summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c24xx
diff options
context:
space:
mode:
authorJuergen Beisert <j.beisert@pengutronix.de>2009-06-23 15:46:15 +0200
committerJuergen Beisert <j.beisert@pengutronix.de>2009-07-01 14:36:40 +0200
commit5139e618b8d732bfbea69d9a9bdf83832de30472 (patch)
tree530f01f7b25071d0d8ab1a300060e6f9e15aae1b /arch/arm/mach-s3c24xx
parent5d56a46c0aaaadb7eebc23ef7577a637610926f7 (diff)
downloadbarebox-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/arm/mach-s3c24xx')
-rw-r--r--arch/arm/mach-s3c24xx/Kconfig51
-rw-r--r--arch/arm/mach-s3c24xx/Makefile2
-rw-r--r--arch/arm/mach-s3c24xx/generic.c250
-rw-r--r--arch/arm/mach-s3c24xx/lowlevel-init.S318
4 files changed, 621 insertions, 0 deletions
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.
+
+*/