diff options
author | Juergen Beisert <j.beisert@pengutronix.de> | 2009-06-23 15:46:15 +0200 |
---|---|---|
committer | Juergen Beisert <j.beisert@pengutronix.de> | 2009-07-01 14:36:40 +0200 |
commit | 5139e618b8d732bfbea69d9a9bdf83832de30472 (patch) | |
tree | 530f01f7b25071d0d8ab1a300060e6f9e15aae1b /arch | |
parent | 5d56a46c0aaaadb7eebc23ef7577a637610926f7 (diff) | |
download | barebox-5139e618b8d732bfbea69d9a9bdf83832de30472.tar.gz barebox-5139e618b8d732bfbea69d9a9bdf83832de30472.tar.xz |
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/Kconfig | 51 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/generic.c | 250 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/lowlevel-init.S | 318 |
6 files changed, 623 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1767f9e3bb..4243b338a1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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 " diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 58ab93a3f4..1b4f52d504 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -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 diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig new file mode 100644 index 0000000000..3d5d359bc5 --- /dev/null +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -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 diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile new file mode 100644 index 0000000000..1cc8a23751 --- /dev/null +++ b/arch/arm/mach-s3c24xx/Makefile @@ -0,0 +1,2 @@ +obj-y += generic.o +obj-$(CONFIG_S3C24XX_LOW_LEVEL_INIT) += lowlevel-init.o diff --git a/arch/arm/mach-s3c24xx/generic.c b/arch/arm/mach-s3c24xx/generic.c new file mode 100644 index 0000000000..864977d7b8 --- /dev/null +++ b/arch/arm/mach-s3c24xx/generic.c @@ -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 +*/ diff --git a/arch/arm/mach-s3c24xx/lowlevel-init.S b/arch/arm/mach-s3c24xx/lowlevel-init.S new file mode 100644 index 0000000000..8c32f50508 --- /dev/null +++ b/arch/arm/mach-s3c24xx/lowlevel-init.S @@ -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. + +*/ |