9
0
Fork 0

Add basic architecture support for Samsung's S3C2410 and S3C2440 CPU.

It includes a
 - driver for the internal UART
 - driver for the internal NAND controller
 - support to boot from NAND
 - PLL handling
 - SDRAM initialisation

Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de>
This commit is contained in:
Juergen Beisert 2009-06-23 15:46:15 +02:00
parent 5d56a46c0a
commit 5139e618b8
15 changed files with 1602 additions and 0 deletions

View File

@ -213,6 +213,7 @@ endchoice
source arch/arm/mach-imx/Kconfig
source arch/arm/mach-netx/Kconfig
source arch/arm/mach-omap/Kconfig
source arch/arm/mach-s3c24xx/Kconfig
menu "Arm specific settings "

View File

@ -7,6 +7,7 @@ machine-$(CONFIG_ARCH_NETX) := netx
machine-$(CONFIG_ARCH_AT91RM9200) := at91rm9200
machine-$(CONFIG_ARCH_OMAP) := omap
machine-$(CONFIG_ARCH_AT91SAM9) := at91sam9
machine-$(CONFIG_ARCH_S3C24xx) := s3c24xx
board-$(CONFIG_MACH_MX1ADS) := mx1ads
board-$(CONFIG_MACH_ECO920) := eco920
board-$(CONFIG_MACH_SCB9328) := scb9328

View File

@ -0,0 +1,51 @@
config ARCH_S3C24xx
bool
select ARM920T
config CPU_S3C2410
select ARCH_S3C24xx
bool
config CPU_S3C2440
select ARCH_S3C24xx
bool
if ARCH_S3C24xx
menu "Board specific settings "
endmenu
menu "S3C24X0 Features "
config S3C24XX_LOW_LEVEL_INIT
bool
config S3C24XX_PLL_INIT
bool
prompt "Reconfigure PLL"
select S3C24XX_LOW_LEVEL_INIT
help
This adds generic code to reconfigure the internal PLL very early
after reset.
config S3C24XX_SDRAM_INIT
bool
prompt "Initialize SDRAM"
select S3C24XX_LOW_LEVEL_INIT
help
This adds generic code to configure the SDRAM controller after reset.
The initialisation will be skipped if the code is already running
from SDRAM.
config S3C24XX_NAND_BOOT
bool
prompt "Booting from NAND"
select NAND_S3C24X0
help
Add generic support to boot from NAND flash. Image loading will be
skipped if the code is running from NOR or already from SDRAM.
endmenu
endif

View File

@ -0,0 +1,2 @@
obj-y += generic.o
obj-$(CONFIG_S3C24XX_LOW_LEVEL_INIT) += lowlevel-init.o

View File

@ -0,0 +1,250 @@
/*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/**
* @file
* @brief Basic clock and timer handling for S3C24xx CPUs
*/
#include <config.h>
#include <common.h>
#include <init.h>
#include <clock.h>
#include <asm/io.h>
#include <asm/arch/s3c24x0-iomap.h>
/**
* Calculate the current M-PLL clock.
* @return Current frequency in Hz
*/
uint32_t s3c24xx_get_mpllclk(void)
{
uint32_t m, p, s, reg_val;
reg_val = readl(MPLLCON);
m = ((reg_val & 0xFF000) >> 12) + 8;
p = ((reg_val & 0x003F0) >> 4) + 2;
s = reg_val & 0x3;
#ifdef CONFIG_CPU_S3C2410
return (S3C24XX_CLOCK_REFERENCE * m) / (p << s);
#endif
#ifdef CONFIG_CPU_S3C2440
return 2 * m * (S3C24XX_CLOCK_REFERENCE / (p << s));
#endif
}
/**
* Calculate the current U-PLL clock
* @return Current frequency in Hz
*/
uint32_t s3c24xx_get_upllclk(void)
{
uint32_t m, p, s, reg_val;
reg_val = readl(UPLLCON);
m = ((reg_val & 0xFF000) >> 12) + 8;
p = ((reg_val & 0x003F0) >> 4) + 2;
s = reg_val & 0x3;
return (S3C24XX_CLOCK_REFERENCE * m) / (p << s);
}
/**
* Calculate the FCLK frequency used for the ARM CPU core
* @return Current frequency in Hz
*/
uint32_t s3c24xx_get_fclk(void)
{
return s3c24xx_get_mpllclk();
}
/**
* Calculate the HCLK frequency used for the AHB bus (CPU to main peripheral)
* @return Current frequency in Hz
*/
uint32_t s3c24xx_get_hclk(void)
{
uint32_t f_clk;
f_clk = s3c24xx_get_fclk();
#ifdef CONFIG_CPU_S3C2410
if (readl(CLKDIVN) & 0x02)
return f_clk >> 1;
#endif
#ifdef CONFIG_CPU_S3C2440
switch(readl(CLKDIVN) & 0x06) {
case 2:
return f_clk >> 1;
case 4:
return f_clk >> 2; /* TODO consider CAMDIVN */
case 6:
return f_clk / 3; /* TODO consider CAMDIVN */
}
#endif
return f_clk;
}
/**
* Calculate the PCLK frequency used for the slower peripherals
* @return Current frequency in Hz
*/
uint32_t s3c24xx_get_pclk(void)
{
uint32_t p_clk;
p_clk = s3c24xx_get_hclk();
if (readl(CLKDIVN) & 0x01)
return p_clk >> 1;
return p_clk;
}
/**
* Calculate the UCLK frequency used by the USB host device
* @return Current frequency in Hz
*/
uint32_t s3c24xx_get_uclk(void)
{
return s3c24xx_get_upllclk();
}
/**
* Show the user the current clock settings
*/
int s3c24xx_dump_clocks(void)
{
printf("refclk: %7d kHz\n", S3C24XX_CLOCK_REFERENCE / 1000);
printf("mpll: %7d kHz\n", s3c24xx_get_mpllclk() / 1000);
printf("upll: %7d kHz\n", s3c24xx_get_upllclk() / 1000);
printf("fclk: %7d kHz\n", s3c24xx_get_fclk() / 1000);
printf("hclk: %7d kHz\n", s3c24xx_get_hclk() / 1000);
printf("pclk: %7d kHz\n", s3c24xx_get_pclk() / 1000);
printf("SDRAM1: CL%d@%dMHz\n", ((readl(BANKCON6) & 0xc) >> 2) + 2, s3c24xx_get_hclk() / 1000000);
if (!(readl(MISCCR) & (1 << 18)))
printf("SDRAM2: CL%d@%dMHz\n", ((readl(BANKCON7) & 0xc) >> 2) + 2, s3c24xx_get_hclk() / 1000000);
return 0;
}
late_initcall(s3c24xx_dump_clocks);
static uint64_t s3c24xx_clocksource_read(void)
{
/* note: its a down counter */
return 0xFFFF - readw(TCNTO4);
}
static struct clocksource cs = {
.read = s3c24xx_clocksource_read,
.mask = 0x0000ffff,
.shift = 10,
};
static int clocksource_init (void)
{
uint32_t p_clk = s3c24xx_get_pclk();
writel(0x00000000, TCON); /* stop all timers */
writel(0x00ffffff, TCFG0); /* PCLK / (255 + 1) for timer 4 */
writel(0x00030000, TCFG1); /* /16 */
writew(0xffff, TCNTB4); /* reload value is TOP */
writel(0x00600000, TCON); /* force a first reload */
writel(0x00400000, TCON);
writel(0x00500000, TCON); /* enable timer 4 with auto reload */
cs.mult = clocksource_hz2mult(p_clk / ((255 + 1) * 16), cs.shift);
init_clock(&cs);
return 0;
}
core_initcall(clocksource_init);
void reset_cpu(ulong addr)
{
/* Disable watchdog */
writew(0x0000, WTCON);
/* Initialize watchdog timer count register */
writew(0x0001, WTCNT);
/* Enable watchdog timer; assert reset at timer timeout */
writew(0x0021, WTCON);
/* loop forever and wait for reset to happen */
while(1)
;
}
EXPORT_SYMBOL(reset_cpu);
/**
@page dev_s3c24xx_arch Samsung's S3C24xx Platforms in U-Boot-v2
@section s3c24xx_boards Boards using S3C24xx Processors
@li @subpage board/a9m2410/a9m2410.c
@li @subpage board/a9m2440/a9m2440.c
@section s3c24xx_arch Documentation for S3C24xx Architectures Files
@li @subpage arch/arm/mach-s3c24xx/generic.c
@section s3c24xx_mem_map SDRAM Memory Map
SDRAM starts at address 0x3000.0000 up to the available amount of connected
SDRAM memory. Physically this CPU can handle up to 256MiB (two areas with
up to 128MiB each).
@subsection s3c24xx_mem_generic_map Generic Map
- 0x0000.0000 Start of the internal SRAM when booting from NAND flash memory or CS signal to a NOR flash memory.
- 0x0800.0000 Start of I/O space.
- 0x3000.0000 Start of SDRAM area.
- 0x3000.0100 Start of the TAG list area.
- 0x3000.8000 Start of the linux kernel (physical address).
- 0x4000.0000 Start of internal SRAM, when booting from NOR flash memory
- 0x4800.0000 Start of the internal I/O area
@section s3c24xx_asm_arm include/asm-arm/arch-s3c24xx directory guidelines
All S3C24xx common headers are located here.
@note Do not add board specific header files/information here.
*/
/** @page dev_s3c24xx_mach Samsung's S3C24xx based platforms
@par U-Boot-v2 Map
The location of the U-Boot-v2 itself depends on the available amount of
installed SDRAM memory:
- 0x30fc.0000 Start of U-Boot-v2 when 16MiB SDRAM is available
- 0x31fc.0000 Start of U-Boot-v2 when 32MiB SDRAM is available
- 0x33fc.0000 Start of U-Boot-v2 when 64MiB SDRAM is available
Adjust the CONFIG_TEXT_BASE/CONFIG_ARCH_TEXT_BASE symbol in accordance to
the available memory.
@note The RAM based filesystem and the stack resides always below the
U-Boot-v2 start address.
@li @subpage dev_s3c24xx_wd_handling
@li @subpage dev_s3c24xx_pll_handling
@li @subpage dev_s3c24xx_sdram_handling
@li @subpage dev_s3c24xx_nandboot_handling
*/

View File

@ -0,0 +1,318 @@
/*
* (C) Copyright 2009
* Juergen Beisert <kernel@pengutronix.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <asm/arch/s3c24x0-iomap.h>
.section ".text_bare_init.s3c24x0_disable_wd","ax"
/*
* Disable the watchdog, else it continues to bark
*/
.globl s3c24x0_disable_wd
s3c24x0_disable_wd:
ldr r0, =S3C24X0_WATCHDOG_BASE
mov r1, #0x0
str r1, [r0]
mov pc, lr
/**
@page dev_s3c24xx_wd_handling Watchdog handling
The watchdog must be disabled very early, because if it resets the system
it is still active and will continue to reset the system. So, call this
routine very early in your board_init_lowlevel routine.
*/
/*
* S3C2410 PLL configuration
* -------------------------
*
* Basic frequency calculation
*
* m * REFclk s = SDIV
* PLLclk = ------------ p = PDIV + 2
* p * 2^s m = MDIV + 8
*
* After reset the PLL of the s3c2410 processor uses:
*
* MPLL UPLL
* MDIV 0x5c 0x28
* PDIV 0x08 0x08
* SDIV 0x0 0x0
*
* 100 * 12MHz 1200MHz
* MPLLclk = ------------- = -------- = 120MHz
* 10 * 2^0 10
*
* 48 * 12MHz 576MHz
* UPLLclk = ------------- = -------- = 57,6MHz
* 10 * 2^0 10
*
* Note: Do not use "r10" here in this code
*/
#ifdef CONFIG_S3C24XX_PLL_INIT
.section ".text_bare_init.s3c24x0_pll_init","ax"
.globl s3c24x0_pll_init
s3c24x0_pll_init:
mov r0, #S3C24X0_CLOCK_POWER_BASE
/* configure internal clock ratio */
mov r1, #BOARD_SPECIFIC_CLKDIVN
str r1, [r0, #20]
/* enable all devices on this chip */
mov r1, #0xFFFFFFF0
str r1, [r0, #12]
/* ??????? */
#ifdef CONFIG_CPU_S3C2440
mov r1, #0xFFFFFFFF
#endif
#ifdef CONFIG_CPU_S3C2410
mov r1, #0x00FFFFFF
#endif
str r1, [r0, #0]
#ifdef CONFIG_CPU_S3C2440
/*
* Most of the time HDIVN is not 0, so we must use the
* asynchronous bus mode (refer datasheet "Clock and Power Management")
*/
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
#endif
/* configure UPLL */
ldr r1, =BOARD_SPECIFIC_UPLL
str r1, [r0, #8]
nop
nop
nop
nop
nop
nop
nop
nop
/* configure MPLL */
ldr r1, =BOARD_SPECIFIC_MPLL
str r1, [r0, #4]
nop
nop
nop
nop
nop
nop
nop
nop
mov pc, lr
#endif
/**
@page dev_s3c24xx_pll_handling PLL clock handling
To control the speed of your machine the PLLs must be reconfigured after reset.
For example the S3C2410 CPU wakes up after reset at 120MHz main PLL speed,
shared with all other system on chip components. Most of the time this
configuration is to slow for the CPU and to fast for the other components.
PLL reprogramming can be done in the machine specific manner very early when
the CONFIG_S3C24XX_PLL_INIT and CONFIG_MACH_HAS_LOWLEVEL_INIT symbols are
defined. The board must provide a board_init_lowlevel() assembler function in
this case and calling the s3c24x0_pll_init() assembler function.
If the s3c24x0_pll_init() is called a few further symbols must be defined to
setup the correct values for the machine.
Define in the machine specific config.h the following symbols:
- S3C24XX_CLOCK_REFERENCE with the frequency in Hz of your reference crystal.
- BOARD_SPECIFIC_CLKDIVN with the value for the main clock ratio register (CLKDIVN)
- BOARD_SPECIFIC_MPLL with the value for the main PLL setup register
- BOARD_SPECIFIC_UPLL with the value for the USB PLL setup register
@note Valid values for the PLL settings can be found in the CPU manual.
@par Background: PLL frequency calculation for the S3C2410 CPU (both PLLs)
and S3C2440 (UPLL only)
@f[
f_{PLL} = \frac{m * f_{Ref}}{p * 2^s}
@f]
With m = MDIV + 8, p = PDIV + 2 and s = SDIV.
@par Background: PLL frequency calculation for the S3C2440 CPU (MPLL only)
@f[
f_{PLL} = \frac{2 * m * f_{Ref}}{p * 2^s}
@f]
With m = MDIV + 8, p = PDIV + 2 and s = SDIV.
@note This routine can be used for the S3C2410 and the S3C2440 CPU.
*/
/* ----------------------------------------------------------------------- */
#ifdef CONFIG_S3C24XX_SDRAM_INIT
.section ".text_bare_init.s3c24x0_sdram_init","ax"
.globl s3c24x0_sdram_init
s3c24x0_sdram_init:
adr r0, SDRAMDATA /* get the current relative address of the table */
mov r1, #S3C24X0_MEMCTL_BASE
mov r2, #6 /* we *know* it contains 6 entries */
ldr r3, [r0], #4 /* write BSWCON first */
str r3, [r1], #0x1c /* post add register offset for bank6 */
/*
* Initializing the SDRAM controller is very simple:
* Just write some useful values into the SDRAM controller.
*/
0: ldr r3, [r0], #4
str r3, [r1], #4
subs r2, r2, #1
bne 0b
mov pc, lr
SDRAMDATA:
.word BOARD_SPECIFIC_BWSCON
.word BOARD_SPECIFIC_BANKCON6
.word BOARD_SPECIFIC_BANKCON7
.word BOARD_SPECIFIC_REFRESH
.word BOARD_SPECIFIC_BANKSIZE
.word BOARD_SPECIFIC_MRSRB6
.word BOARD_SPECIFIC_MRSRB7
#endif
/**
@page dev_s3c24xx_sdram_handling SDRAM controller initialisation
The SDRAM controller is very simple and its initialisation requires only a
few steps. U-Boot-v2 provides a generic routine to do this step.
Enable CONFIG_S3C24XX_SDRAM_INIT and CONFIG_MACH_HAS_LOWLEVEL_INIT to be able
to call the generic s3c24x0_sdram_init() assembler function from within the
machine specific board_init_lowlevel() assembler function.
To use the s3c24x0_sdram_init() assembler function a few symbols must be
defined to setup correct values for the machine.
Define in the machine specific config.h the following list of symbols:
- BOARD_SPECIFIC_BWSCON with the values for SDRAM banks 6 and 7
- BOARD_SPECIFIC_BANKCON6 with the value for the BANKCON6 register
- BOARD_SPECIFIC_BANKCON7 with the value for the BANKCON7 register
- BOARD_SPECIFIC_REFRESH with the value for the REFRESH register
- BOARD_SPECIFIC_BANKSIZE with the value for the BANKSIZE register
- BOARD_SPECIFIC_MRSRB6 with the value for the MRSRB6 register
- BOARD_SPECIFIC_MRSRB7 with the value for the MRSRB7 register
*/
/* ----------------------------------------------------------------------- */
#ifdef CONFIG_S3C24XX_NAND_BOOT
.section ".text_bare_init.s3c24x0_nand_boot","ax"
.globl s3c24x0_nand_boot
s3c24x0_nand_boot:
/*
* In the case of NOR boot we are running from the same address space.
* Detect this case to handle it correctly.
*/
mov r1, #S3C24X0_MEMCTL_BASE
ldr r3, [r1]
and r3, r3, #0x6
cmp r3, #0x0 /* check for NAND case */
beq 2f
mov pc, lr /* NOR case: nothing to do here */
2: ldr sp, =TEXT_BASE /* Setup a temporary stack in SDRAM */
/*
* We still run at a location we are not linked to. But lets still running
* from the internal SRAM, this may speed up the boot
*/
push {lr}
bl nand_boot
pop {lr}
/*
* Adjust the return address to the correct address in SDRAM
*/
ldr r1, =TEXT_BASE
add lr, lr, r1
mov pc, lr
#endif
/**
@page dev_s3c24xx_nandboot_handling Booting from NAND
To be able to boot from NAND memory only, enable the S3C24x0 NAND driver. Also
enable CONFIG_S3C24XX_NAND_BOOT and CONFIG_MACH_HAS_LOWLEVEL_INIT to be
able to call the s3c24x0_nand_boot() assembler routine from within the
machine specific board_init_lowlevel() assembler function.
@note This routine assumes an already working SDRAM controller and
an initialized stack pointer.
@note Basicly this routine runs from inside the internal SRAM. After load of
the whole U-Boot-v2 image from the NAND flash memory into the SDRAM it adjusts
the link register to the final SDRAM adress and returns.
@note In the NAND boot mode, ECC is not checked. So, the first x KBytes used
by U-Boot-v2 should have no bit error.
Due to the fact the code to load the whole U-Boot-v2 from NAND must fit into
the first 4kiB of the U-Boot-v2 image, the shrinked NAND driver is very
minimalistic. Setup the NAND access timing is done in a safe manner, what
means: Slowest possible values are used. If you want to increase the speed you
should define the BOARD_DEFAULT_NAND_TIMING to a valid setting into the
NFCONF register and add it to your board specific config.h. Refer S3C24x0's
datasheet for further details. The macro #CALC_NFCONF_TIMING could help to
calculate the register setting in a hardware independent manner.
@note The regular NAND driver uses a platform data structure to define the
NAND access timings.
@note Its still possible to boot this image from NOR memory. If this routine
detects it is running from NOR instead of the internal SRAM it skips any
loading and returns immediately.
*/

View File

@ -38,6 +38,13 @@ config NAND_ATMEL
prompt "Atmel (AT91SAM9xxx) NAND driver"
depends on ARCH_AT91SAM9
config NAND_S3C24X0
bool
prompt "Samsung S3C24X0 NAND driver"
depends on ARCH_S3C24xx
help
Add support for processor's NAND device controller.
config MTD_NAND_VERIFY_WRITE
bool "Verify NAND page writes"
help

View File

@ -8,4 +8,5 @@ obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_NAND_IMX) += nand_imx.o
obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o
obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_NAND_S3C24X0) += nand_s3c2410.o
#obj-$(CONFIG_NAND) += nand_util.o

528
drivers/nand/nand_s3c2410.c Normal file
View File

@ -0,0 +1,528 @@
/* linux/drivers/mtd/nand/s3c2410.c
*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* Copyright © 2004-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* Samsung S3C2410 NAND driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <config.h>
#include <common.h>
#include <driver.h>
#include <malloc.h>
#include <init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <asm/arch/s3c24xx-generic.h>
#include <asm/arch/s3c24x0-iomap.h>
#include <asm/arch/s3c24x0-nand.h>
#include <asm/io.h>
#include <asm-generic/errno.h>
#ifdef CONFIG_S3C24XX_NAND_BOOT
# define __nand_boot_init __bare_init
# ifndef BOARD_DEFAULT_NAND_TIMING
# define BOARD_DEFAULT_NAND_TIMING 0x0737
# endif
#else
# define __nand_boot_init
#endif
/**
* Define this symbol for testing purpose. It will add a command to read an
* image from the NAND like it the boot strap code will do.
*/
#define CONFIG_NAND_S3C24XX_BOOT_DEBUG
/* NAND controller's register */
#define NFCONF 0x00
#ifdef CONFIG_CPU_S3C2410
#define NFCMD 0x04
#define NFADDR 0x08
#define NFDATA 0x0c
#define NFSTAT 0x10
#define NFECC 0x14
/* S3C2410 specific bits */
#define NFSTAT_BUSY (1)
#define NFCONF_nFCE (1 << 11)
#define NFCONF_INITECC (1 << 12)
#define NFCONF_EN (1 << 15)
#endif /* CONFIG_CPU_S3C2410 */
#ifdef CONFIG_CPU_S3C2440
#define NFCONT 0x04
#define NFCMD 0x08
#define NFADDR 0x0C
#define NFDATA 0x10
#define NFECC 0x1C
#define NFSTAT 0x20
/* S3C2440 specific bits */
#define NFSTAT_BUSY (1)
#define NFCONT_nFCE (1 << 1)
#define NFCONF_INITECC (1 << 12)
#define NFCONT_EN (1)
#endif /* CONFIG_CPU_S3C2440 */
struct s3c24x0_nand_host {
struct mtd_info mtd;
struct nand_chip nand;
struct mtd_partition *parts;
struct device_d *dev;
unsigned long base;
};
/**
* oob placement block for use with hardware ecc generation
*/
static struct nand_ecclayout nand_hw_eccoob = {
.eccbytes = 3,
.eccpos = { 0, 1, 2},
.oobfree = {
{
.offset = 8,
.length = 8
}
}
};
/* - Functions shared between the boot strap code and the regular driver - */
/**
* Issue the specified command to the NAND device
* @param[in] host Base address of the NAND controller
* @param[in] cmd Command for NAND flash
*/
static void __nand_boot_init send_cmd(unsigned long host, uint8_t cmd)
{
writeb(cmd, host + NFCMD);
}
/**
* Issue the specified address to the NAND device
* @param[in] host Base address of the NAND controller
* @param[in] addr Address for the NAND flash
*/
static void __nand_boot_init send_addr(unsigned long host, uint8_t addr)
{
writeb(addr, host + NFADDR);
}
/**
* Enable the NAND flash access
* @param[in] host Base address of the NAND controller
*/
static void __nand_boot_init enable_cs(unsigned long host)
{
#ifdef CONFIG_CPU_S3C2410
writew(readw(host + NFCONF) & ~NFCONF_nFCE, host + NFCONF);
#endif
#ifdef CONFIG_CPU_S3C2440
writew(readw(host + NFCONT) & ~NFCONT_nFCE, host + NFCONT);
#endif
}
/**
* Disable the NAND flash access
* @param[in] host Base address of the NAND controller
*/
static void __nand_boot_init disable_cs(unsigned long host)
{
#ifdef CONFIG_CPU_S3C2410
writew(readw(host + NFCONF) | NFCONF_nFCE, host + NFCONF);
#endif
#ifdef CONFIG_CPU_S3C2440
writew(readw(host + NFCONT) | NFCONT_nFCE, host + NFCONT);
#endif
}
/**
* Enable the NAND flash controller
* @param[in] host Base address of the NAND controller
* @param[in] timing Timing to access the NAND memory
*/
static void __nand_boot_init enable_nand_controller(unsigned long host, uint32_t timing)
{
#ifdef CONFIG_CPU_S3C2410
writew(timing + NFCONF_EN + NFCONF_nFCE, host + NFCONF);
#endif
#ifdef CONFIG_CPU_S3C2440
writew(NFCONT_EN + NFCONT_nFCE, host + NFCONT);
writew(timing, host + NFCONF);
#endif
}
/**
* Diable the NAND flash controller
* @param[in] host Base address of the NAND controller
*/
static void __nand_boot_init disable_nand_controller(unsigned long host)
{
#ifdef CONFIG_CPU_S3C2410
writew(NFCONF_nFCE, host + NFCONF);
#endif
#ifdef CONFIG_CPU_S3C2440
writew(NFCONT_nFCE, host + NFCONT);
#endif
}
/* ----------------------------------------------------------------------- */
/**
* Check the ECC and try to repair the data if possible
* @param[in] mtd_info FIXME
* @param[inout] dat Pointer to the data buffer that might contain a bit error
* @param[in] read_ecc ECC data from the OOB space
* @param[in] calc_ecc ECC data calculated from the data
* @return 0 no error, 1 repaired error, -1 no way...
*
* @note: Alsways 512 byte of data
*/
static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc, uint8_t *calc_ecc)
{
unsigned int diff0, diff1, diff2;
unsigned int bit, byte;
diff0 = read_ecc[0] ^ calc_ecc[0];
diff1 = read_ecc[1] ^ calc_ecc[1];
diff2 = read_ecc[2] ^ calc_ecc[2];
if (diff0 == 0 && diff1 == 0 && diff2 == 0)
return 0; /* ECC is ok */
/* sometimes people do not think about using the ECC, so check
* to see if we have an 0xff,0xff,0xff read ECC and then ignore
* the error, on the assumption that this is an un-eccd page.
*/
if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
/* && info->platform->ignore_unset_ecc */)
return 0;
/* Can we correct this ECC (ie, one row and column change).
* Note, this is similar to the 256 error code on smartmedia */
if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
/* calculate the bit position of the error */
bit = ((diff2 >> 3) & 1) |
((diff2 >> 4) & 2) |
((diff2 >> 5) & 4);
/* calculate the byte position of the error */
byte = ((diff2 << 7) & 0x100) |
((diff1 << 0) & 0x80) |
((diff1 << 1) & 0x40) |
((diff1 << 2) & 0x20) |
((diff1 << 3) & 0x10) |
((diff0 >> 4) & 0x08) |
((diff0 >> 3) & 0x04) |
((diff0 >> 2) & 0x02) |
((diff0 >> 1) & 0x01);
dat[byte] ^= (1 << bit);
return 1;
}
/* if there is only one bit difference in the ECC, then
* one of only a row or column parity has changed, which
* means the error is most probably in the ECC itself */
diff0 |= (diff1 << 8);
diff0 |= (diff2 << 16);
if ((diff0 & ~(1<<fls(diff0))) == 0)
return 1;
return -1;
}
static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct nand_chip *nand_chip = mtd->priv;
struct s3c24x0_nand_host *host = nand_chip->priv;
writel(readl(host->base + NFCONF) | NFCONF_INITECC , host->base + NFCONF);
}
static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code)
{
struct nand_chip *nand_chip = mtd->priv;
struct s3c24x0_nand_host *host = nand_chip->priv;
ecc_code[0] = readb(host->base + NFECC);
ecc_code[1] = readb(host->base + NFECC + 1);
ecc_code[2] = readb(host->base + NFECC + 2);
return 0;
}
static void s3c24x0_nand_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *nand_chip = mtd->priv;
struct s3c24x0_nand_host *host = nand_chip->priv;
if (chip == -1)
disable_cs(host->base);
else
enable_cs(host->base);
}
static int s3c24x0_nand_devready(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd->priv;
struct s3c24x0_nand_host *host = nand_chip->priv;
return readw(host->base + NFSTAT) & NFSTAT_BUSY;
}
static void s3c24x0_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *nand_chip = mtd->priv;
struct s3c24x0_nand_host *host = nand_chip->priv;
if (cmd == NAND_CMD_NONE)
return;
/*
* If the CLE should be active, this call is a NAND command
*/
if (ctrl & NAND_CLE)
send_cmd(host->base, cmd);
/*
* If the ALE should be active, this call is a NAND address
*/
if (ctrl & NAND_ALE)
send_addr(host->base, cmd);
}
static int s3c24x0_nand_inithw(struct s3c24x0_nand_host *host)
{
struct s3c24x0_nand_platform_data *pdata = host->dev->platform_data;
uint32_t tmp;
/* reset the NAND controller */
disable_nand_controller(host->base);
if (pdata != NULL)
tmp = pdata->nand_timing;
else
/* else slowest possible timing */
tmp = CALC_NFCONF_TIMING(4, 8, 8);
/* reenable the NAND controller */
enable_nand_controller(host->base, tmp);
return 0;
}
static int s3c24x0_nand_probe(struct device_d *dev)
{
struct nand_chip *chip;
struct mtd_info *mtd;
struct s3c24x0_nand_host *host;
int ret;
/* Allocate memory for MTD device structure and private data */
host = kzalloc(sizeof(struct s3c24x0_nand_host), GFP_KERNEL);
if (!host)
return -ENOMEM;
host->dev = dev;
host->base = dev->map_base;
/* structures must be linked */
chip = &host->nand;
mtd = &host->mtd;
mtd->priv = chip;
/* init the default settings */
#if 0
/* TODO: Will follow later */
init_nand_chip_bw8(chip);
#endif
/* 50 us command delay time */
chip->chip_delay = 50;
chip->priv = host;
chip->IO_ADDR_R = chip->IO_ADDR_W = (void*)(dev->map_base + NFDATA);
chip->cmd_ctrl = s3c24x0_nand_hwcontrol;
chip->dev_ready = s3c24x0_nand_devready;
chip->select_chip = s3c24x0_nand_select_chip;
/* we are using the hardware ECC feature of this device */
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
/* our hardware capabilities */
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.layout = &nand_hw_eccoob;
ret = s3c24x0_nand_inithw(host);
if (ret != 0)
goto on_error;
/* Scan to find existence of the device */
ret = nand_scan(mtd, 1);
if (ret != 0) {
ret = -ENXIO;
goto on_error;
}
return add_mtd_device(mtd);
on_error:
free(host);
return ret;
}
static struct driver_d s3c24x0_nand_driver = {
.name = "s3c24x0_nand",
.probe = s3c24x0_nand_probe,
};
#ifdef CONFIG_S3C24XX_NAND_BOOT
static void __nand_boot_init wait_for_completion(unsigned long host)
{
while (!(readw(host + NFSTAT) & NFSTAT_BUSY))
;
}
static void __nand_boot_init nfc_addr(unsigned long host, uint32_t offs)
{
send_addr(host, offs & 0xff);
send_addr(host, (offs >> 9) & 0xff);
send_addr(host, (offs >> 17) & 0xff);
send_addr(host, (offs >> 25) & 0xff);
}
/**
* Load a sequential count of blocks from the NAND into memory
* @param[out] dest Pointer to target area (in SDRAM)
* @param[in] size Bytes to read from NAND device
* @param[in] page Start page to read from
* @param[in] pagesize Size of each page in the NAND
*
* This function must be located in the first 4kiB of the U-Boot-v2 image
* (guess why). When this routine is running the SDRAM is up and running
* and it runs from the correct address (physical=linked address).
* TODO Could we access the platform data from the boardfile?
* Due to it makes no sense this function does not return in case of failure.
*/
void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page, int pagesize)
{
unsigned long host = S3C24X0_NAND_BASE;
int i;
/*
* Reenable the NFC and use the default (but slow) access
* timing or the board specific setting if provided.
*/
enable_nand_controller(host, BOARD_DEFAULT_NAND_TIMING);
enable_cs(host);
/* Reset the NAND device */
send_cmd(host, NAND_CMD_RESET);
wait_for_completion(host);
disable_cs(host);
do {
enable_cs(host);
send_cmd(host, NAND_CMD_READ0);
nfc_addr(host, page * pagesize);
wait_for_completion(host);
/* copy one page (do *not* use readsb() here!)*/
for (i = 0; i < pagesize; i++)
writeb(readb(host + NFDATA), (unsigned long)(dest + i));
disable_cs(host);
page++;
dest += pagesize;
size -= pagesize;
} while (size >= 0);
/* disable the controller again */
disable_nand_controller(host);
}
#ifdef CONFIG_NAND_S3C24XX_BOOT_DEBUG
#include <command.h>
static int do_nand_boot_test(cmd_tbl_t *cmdtp, int argc, char *argv[])
{
void *dest;
int size, pagesize;
if (argc < 3) {
u_boot_cmd_usage(cmdtp);
return 1;
}
dest = (void *)strtoul_suffix(argv[1], NULL, 0);
size = strtoul_suffix(argv[2], NULL, 0);
pagesize = strtoul_suffix(argv[3], NULL, 0);
s3c24x0_nand_load_image(dest, size, 0, pagesize);
return 0;
}
static const __maybe_unused char cmd_nand_boot_test_help[] =
"Usage: nand_boot_test <dest> <size> <pagesize>\n";
U_BOOT_CMD_START(nand_boot_test)
.maxargs = CONFIG_MAXARGS,
.cmd = do_nand_boot_test,
.usage = "load an image from NAND",
U_BOOT_CMD_HELP(cmd_nand_boot_test_help)
U_BOOT_CMD_END
#endif
#endif /* CONFIG_S3C24XX_NAND_BOOT */
/*
* Main initialization routine
* @return 0 if successful; non-zero otherwise
*/
static int __init s3c24x0_nand_init(void)
{
return register_driver(&s3c24x0_nand_driver);
}
device_initcall(s3c24x0_nand_init);

View File

@ -42,4 +42,19 @@ config DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
depends on ARCH_OMAP
help
Say Y here if you are using OMAP extensions to NS16550
config DRIVER_SERIAL_S3C24X0
bool "Samsung S3C24X0 serial driver"
depends on ARCH_S3C24xx
default y
help
Say Y here if you want to use the CONS on a S3C24X0 CPU
config DRIVER_SERIAL_S3C24X0_AUTOSYNC
bool "Enable auto flow"
depends on DRIVER_SERIAL_S3C24X0
help
Say Y here if you want to use the auto flow feature of this
UART. RTS and CTS will be handled by the hardware when enabled.
endmenu

View File

@ -12,3 +12,4 @@ obj-$(CONFIG_DRIVER_SERIAL_LINUX_COMSOLE) += linux_console.o
obj-$(CONFIG_DRIVER_SERIAL_MPC5XXX) += serial_mpc5xxx.o
obj-$(CONFIG_DRIVER_SERIAL_BLACKFIN) += serial_blackfin.o
obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial_ns16550.o
obj-$(CONFIG_DRIVER_SERIAL_S3C24X0) += serial_s3c24x0.o

View File

@ -0,0 +1,165 @@
/*
* (c) 2009 Juergen Beisert <j.beisert@saschahauer.de>
*
* Based on code from:
* (c) 2004 Sascha Hauer <sascha@saschahauer.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <common.h>
#include <driver.h>
#include <init.h>
#include <malloc.h>
#include <asm/io.h>
#include <asm/arch/s3c24xx-generic.h>
#include <asm/arch/s3c24x0-iomap.h>
/* Note: Offsets are for little endian access */
#define ULCON 0x00 /* line control */
#define UCON 0x04 /* UART control */
#define UFCON 0x08 /* FIFO control */
#define UMCON 0x0c /* modem control */
#define UTRSTAT 0x10 /* Rx/Tx status */
#define UERSTAT 0x14 /* error status */
#define UFSTAT 0x18 /* FIFO status */
#define UMSTAT 0x1c /* modem status */
#define UTXH 0x20 /* transmitt */
#define URXH 0x24 /* receive */
#define UBRDIV 0x28 /* baudrate generator */
static int s3c24x0_serial_setbaudrate(struct console_device *cdev, int baudrate)
{
struct device_d *dev = cdev->dev;
unsigned val;
/* value is calculated so : PCLK / (16 * baudrate) -1 */
val = s3c24xx_get_pclk() / (16 * baudrate) - 1;
writew(val, dev->map_base + UBRDIV);
return 0;
}
static int s3c24x0_serial_init_port(struct console_device *cdev)
{
struct device_d *dev = cdev->dev;
/* FIFO enable, Tx/Rx FIFO clear */
writeb(0x07, dev->map_base + UFCON);
writeb(0x00, dev->map_base + UMCON);
/* Normal,No parity,1 stop,8 bit */
writeb(0x03, dev->map_base + ULCON);
/*
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
* normal,interrupt or polling
*/
writew(0x0245, dev->map_base + UCON);
#ifdef CONFIG_DRIVER_SERIAL_S3C24X0_AUTOSYNC
writeb(0x01, dev->map_base + UMCON); /* RTS up */
#endif
return 0;
}
static void s3c24x0_serial_putc(struct console_device *cdev, char c)
{
struct device_d *dev = cdev->dev;
/* Wait for Tx FIFO not full */
while (!(readb(dev->map_base + UTRSTAT) & 0x2))
;
writeb(c, dev->map_base + UTXH);
}
static int s3c24x0_serial_tstc(struct console_device *cdev)
{
struct device_d *dev = cdev->dev;
/* If receive fifo is empty, return false */
if (readb(dev->map_base + UTRSTAT) & 0x1)
return 1;
return 0;
}
static int s3c24x0_serial_getc(struct console_device *cdev)
{
struct device_d *dev = cdev->dev;
/* wait for a character */
while (!(readb(dev->map_base + UTRSTAT) & 0x1))
;
return readb(dev->map_base + URXH);
}
static void s3c24x0_serial_flush(struct console_device *cdev)
{
struct device_d *dev = cdev->dev;
while (!readb(dev->map_base + UTRSTAT) & 0x4)
;
}
static int s3c24x0_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
cdev = malloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
cdev->tstc = s3c24x0_serial_tstc;
cdev->putc = s3c24x0_serial_putc;
cdev->getc = s3c24x0_serial_getc;
cdev->flush = s3c24x0_serial_flush;
cdev->setbrg = s3c24x0_serial_setbaudrate;
s3c24x0_serial_init_port(cdev);
/* Enable UART */
console_register(cdev);
return 0;
}
static void s3c24x0_serial_remove(struct device_d *dev)
{
struct console_device *cdev = dev->type_data;
s3c24x0_serial_flush(cdev);
free(cdev);
dev->type_data = NULL;
}
static struct driver_d s3c24x0_serial_driver = {
.name = "s3c24x0_serial",
.probe = s3c24x0_serial_probe,
.remove = s3c24x0_serial_remove,
.type = DEVICE_TYPE_CONSOLE,
};
static int s3c24x0_serial_init(void)
{
register_driver(&s3c24x0_serial_driver);
return 0;
}
console_initcall(s3c24x0_serial_init);

View File

@ -0,0 +1,177 @@
/*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/* S3C2410 device base addresses */
#define S3C24X0_SDRAM_BASE 0x30000000
#define S3C24X0_SDRAM_END 0x40000000
#define S3C24X0_MEMCTL_BASE 0x48000000
#define S3C2410_USB_HOST_BASE 0x49000000
#define S3C2410_INTERRUPT_BASE 0x4A000000
#define S3C2410_DMA_BASE 0x4B000000
#define S3C24X0_CLOCK_POWER_BASE 0x4C000000
#define S3C2410_LCD_BASE 0x4D000000
#define S3C24X0_NAND_BASE 0x4E000000
#define S3C24X0_UART_BASE 0x50000000
#define S3C24X0_TIMER_BASE 0x51000000
#define S3C2410_USB_DEVICE_BASE 0x52000140
#define S3C24X0_WATCHDOG_BASE 0x53000000
#define S3C2410_I2C_BASE 0x54000000
#define S3C2410_I2S_BASE 0x55000000
#define S3C24X0_GPIO_BASE 0x56000000
#define S3C2410_RTC_BASE 0x57000000
#define S3C2410_ADC_BASE 0x58000000
#define S3C2410_SPI_BASE 0x59000000
#define S3C2410_SDI_BASE 0x5A000000
/* Clock control (direct access) */
#define LOCKTIME (S3C24X0_CLOCK_POWER_BASE)
#define MPLLCON (S3C24X0_CLOCK_POWER_BASE + 0x4)
#define UPLLCON (S3C24X0_CLOCK_POWER_BASE + 0x8)
#define CLKCON (S3C24X0_CLOCK_POWER_BASE + 0xc)
#define CLKSLOW (S3C24X0_CLOCK_POWER_BASE + 0x10)
#define CLKDIVN (S3C24X0_CLOCK_POWER_BASE + 0x14)
/* Timer (direct access) */
#define TCFG0 (S3C24X0_TIMER_BASE + 0x00)
#define TCFG1 (S3C24X0_TIMER_BASE + 0x04)
#define TCON (S3C24X0_TIMER_BASE + 0x08)
#define TCNTB0 (S3C24X0_TIMER_BASE + 0x0c)
#define TCMPB0 (S3C24X0_TIMER_BASE + 0x10)
#define TCNTO0 (S3C24X0_TIMER_BASE + 0x14)
#define TCNTB1 (S3C24X0_TIMER_BASE + 0x18)
#define TCMPB1 (S3C24X0_TIMER_BASE + 0x1c)
#define TCNTO1 (S3C24X0_TIMER_BASE + 0x20)
#define TCNTB2 (S3C24X0_TIMER_BASE + 0x24)
#define TCMPB2 (S3C24X0_TIMER_BASE + 0x28)
#define TCNTO2 (S3C24X0_TIMER_BASE + 0x2c)
#define TCNTB3 (S3C24X0_TIMER_BASE + 0x30)
#define TCMPB3 (S3C24X0_TIMER_BASE + 0x34)
#define TCNTO3 (S3C24X0_TIMER_BASE + 0x38)
#define TCNTB4 (S3C24X0_TIMER_BASE + 0x3c)
#define TCNTO4 (S3C24X0_TIMER_BASE + 0x40)
/* Watchdog (direct access) */
#define WTCON (S3C24X0_WATCHDOG_BASE)
#define WTDAT (S3C24X0_WATCHDOG_BASE + 0x04)
#define WTCNT (S3C24X0_WATCHDOG_BASE + 0x08)
/*
* if we are booting from NAND, its internal SRAM occures at
* a different address than without this feature
*/
#ifdef CONFIG_S3C24XX_NAND_BOOT
# define NFC_RAM_AREA 0x00000000
#else
# define NFC_RAM_AREA 0x40000000
#endif
#define NFC_RAM_SIZE 4096
/* internal UARTs (driver based) */
#define UART1_BASE (S3C24X0_UART_BASE)
#define UART1_SIZE 0x4000
#define UART2_BASE (S3C24X0_UART_BASE + 0x4000)
#define UART3_SIZE 0x4000
#define UART3_BASE (S3C24X0_UART_BASE + 0x8000)
#define UART3_SIZE 0x4000
/* CS configuration (direct access) */
#define BWSCON (S3C24X0_MEMCTL_BASE)
#define BANKCON0 (S3C24X0_MEMCTL_BASE + 0x04)
#define BANKCON1 (S3C24X0_MEMCTL_BASE + 0x08)
#define BANKCON2 (S3C24X0_MEMCTL_BASE + 0x0c)
#define BANKCON3 (S3C24X0_MEMCTL_BASE + 0x10)
#define BANKCON4 (S3C24X0_MEMCTL_BASE + 0x14)
#define BANKCON5 (S3C24X0_MEMCTL_BASE + 0x18)
#define BANKCON6 (S3C24X0_MEMCTL_BASE + 0x1c)
#define BANKCON7 (S3C24X0_MEMCTL_BASE + 0x20)
#define REFRESH (S3C24X0_MEMCTL_BASE + 0x24)
#define BANKSIZE (S3C24X0_MEMCTL_BASE + 0x28)
#define MRSRB6 (S3C24X0_MEMCTL_BASE + 0x2c)
#define MRSRB7 (S3C24X0_MEMCTL_BASE + 0x30)
/* GPIO registers (direct access) */
#define GPACON (S3C24X0_GPIO_BASE)
#define GPADAT (S3C24X0_GPIO_BASE + 0x04)
#define GPBCON (S3C24X0_GPIO_BASE + 0x10)
#define GPBDAT (S3C24X0_GPIO_BASE + 0x14)
#define GPBUP (S3C24X0_GPIO_BASE + 0x18)
#define GPCCON (S3C24X0_GPIO_BASE + 0x20)
#define GPCDAT (S3C24X0_GPIO_BASE + 0x24)
#define GPCUP (S3C24X0_GPIO_BASE + 0x28)
#define GPDCON (S3C24X0_GPIO_BASE + 0x30)
#define GPDDAT (S3C24X0_GPIO_BASE + 0x34)
#define GPDUP (S3C24X0_GPIO_BASE + 0x38)
#define GPECON (S3C24X0_GPIO_BASE + 0x40)
#define GPEDAT (S3C24X0_GPIO_BASE + 0x44)
#define GPEUP (S3C24X0_GPIO_BASE + 0x48)
#define GPFCON (S3C24X0_GPIO_BASE + 0x50)
#define GPFDAT (S3C24X0_GPIO_BASE + 0x54)
#define GPFUP (S3C24X0_GPIO_BASE + 0x58)
#define GPGCON (S3C24X0_GPIO_BASE + 0x60)
#define GPGDAT (S3C24X0_GPIO_BASE + 0x64)
#define GPGUP (S3C24X0_GPIO_BASE + 0x68)
#define GPHCON (S3C24X0_GPIO_BASE + 0x70)
#define GPHDAT (S3C24X0_GPIO_BASE + 0x74)
#define GPHUP (S3C24X0_GPIO_BASE + 0x78)
#ifdef CONFIG_CPU_S3C2440
# define GPJCON (S3C24X0_GPIO_BASE + 0xd0)
# define GPJDAT (S3C24X0_GPIO_BASE + 0xd4)
# define GPJUP (S3C24X0_GPIO_BASE + 0xd8)
#endif
#define MISCCR (S3C24X0_GPIO_BASE + 0x80)
#define DCLKCON (S3C24X0_GPIO_BASE + 0x84)
#define EXTINT0 (S3C24X0_GPIO_BASE + 0x88)
#define EXTINT1 (S3C24X0_GPIO_BASE + 0x8c)
#define EXTINT2 (S3C24X0_GPIO_BASE + 0x90)
#define EINTFLT0 (S3C24X0_GPIO_BASE + 0x94)
#define EINTFLT1 (S3C24X0_GPIO_BASE + 0x98)
#define EINTFLT2 (S3C24X0_GPIO_BASE + 0x9c)
#define EINTFLT3 (S3C24X0_GPIO_BASE + 0xa0)
#define EINTMASK (S3C24X0_GPIO_BASE + 0xa4)
#define EINTPEND (S3C24X0_GPIO_BASE + 0xa8)
#define GSTATUS0 (S3C24X0_GPIO_BASE + 0xac)
#define GSTATUS1 (S3C24X0_GPIO_BASE + 0xb0)
#define GSTATUS2 (S3C24X0_GPIO_BASE + 0xb4)
#define GSTATUS3 (S3C24X0_GPIO_BASE + 0xb8)
#define GSTATUS4 (S3C24X0_GPIO_BASE + 0xbc)
#ifdef CONFIG_CPU_S3C2440
# define DSC0 (S3C24X0_GPIO_BASE + 0xc4)
# define DSC1 (S3C24X0_GPIO_BASE + 0xc8)
#endif
/* external IO space */
#define CS0_BASE 0x00000000
#define CS1_BASE 0x08000000
#define CS2_BASE 0x10000000
#define CS3_BASE 0x18000000
#define CS4_BASE 0x20000000
#define CS5_BASE 0x28000000
#define CS6_BASE 0x30000000

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
#ifdef CONFIG_S3C24XX_NAND_BOOT
extern void s3c24x0_nand_load_image(void*, int, int, int);
#endif
/**
* Locate the timing bits for the NFCONF register
* @param setup is the TACLS clock count
* @param access is the TWRPH0 clock count
* @param hold is the TWRPH1 clock count
*
* @note A clock count of 0 means always 1 HCLK clock.
* @note Clock count settings depend on the NAND flash requirements and the current HCLK speed
*/
#ifdef CONFIG_CPU_S3C2410
# define CALC_NFCONF_TIMING(setup, access, hold) \
((setup << 8) + (access << 4) + (hold << 0))
#endif
#ifdef CONFIG_CPU_S3C2440
# define CALC_NFCONF_TIMING(setup, access, hold) \
((setup << 12) + (access << 8) + (hold << 4))
#endif
/**
* Define platform specific data for the NAND controller and its device
*/
struct s3c24x0_nand_platform_data {
uint32_t nand_timing; /**< value for the NFCONF register (timing bits only) */
};
/**
* @file
* @brief Basic declaration to use the s3c24x0 NAND driver
*/

View File

@ -0,0 +1,32 @@
/*
* (C) Copyright 2009
* Juergen Beisert, Pengutronix
*
* (C) Copyright 2001-2004
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2002
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
uint32_t s3c24xx_get_mpllclk(void);
uint32_t s3c24xx_get_upllclk(void);
uint32_t s3c24xx_get_fclk(void);
uint32_t s3c24xx_get_hclk(void);
uint32_t s3c24xx_get_pclk(void);
uint32_t s3c24xx_get_uclk(void);