From 9b07773f8883665b002500c190507e9fd99b7181 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 31 Aug 2008 00:39:46 +0200 Subject: ARM: Add arm1176 core with S3C6400 SoC Based on the original S3C64XX port by Samsung for U-Boot 1.1.6. Signed-off-by: Guennadi Liakhovetski --- cpu/arm1176/Makefile | 50 +++++ cpu/arm1176/config.mk | 35 +++ cpu/arm1176/cpu.c | 188 ++++++++++++++++ cpu/arm1176/s3c64xx/Makefile | 48 ++++ cpu/arm1176/s3c64xx/config.mk | 34 +++ cpu/arm1176/s3c64xx/cpu_init.S | 142 ++++++++++++ cpu/arm1176/s3c64xx/interrupts.c | 174 +++++++++++++++ cpu/arm1176/s3c64xx/speed.c | 145 ++++++++++++ cpu/arm1176/start.S | 469 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 1285 insertions(+) create mode 100644 cpu/arm1176/Makefile create mode 100644 cpu/arm1176/config.mk create mode 100644 cpu/arm1176/cpu.c create mode 100644 cpu/arm1176/s3c64xx/Makefile create mode 100644 cpu/arm1176/s3c64xx/config.mk create mode 100644 cpu/arm1176/s3c64xx/cpu_init.S create mode 100644 cpu/arm1176/s3c64xx/interrupts.c create mode 100644 cpu/arm1176/s3c64xx/speed.c create mode 100644 cpu/arm1176/start.S (limited to 'cpu/arm1176') diff --git a/cpu/arm1176/Makefile b/cpu/arm1176/Makefile new file mode 100644 index 000000000..1ca9199a6 --- /dev/null +++ b/cpu/arm1176/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2008 +# Guennadi Liakhovetki, DENX Software Engineering, +# +# 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 +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o +COBJS = cpu.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm1176/config.mk b/cpu/arm1176/config.mk new file mode 100644 index 000000000..508359425 --- /dev/null +++ b/cpu/arm1176/config.mk @@ -0,0 +1,35 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, +# +# 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 +# +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ + -msoft-float + +# Make ARMv5 to allow more compilers to work, even though its v6. +PLATFORM_CPPFLAGS += -march=armv5t +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) +PLATFORM_CPPFLAGS +=$(call cc-option,-mno-thumb-interwork,) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) diff --git a/cpu/arm1176/cpu.c b/cpu/arm1176/cpu.c new file mode 100644 index 000000000..1e94f7d6d --- /dev/null +++ b/cpu/arm1176/cpu.c @@ -0,0 +1,188 @@ +/* + * (C) Copyright 2004 Texas Insturments + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * 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 + */ + +/* + * CPU specific code + */ + +#include +#include +#include + +static void cache_flush (void); + +/* read co-processor 15, register #1 (control register) */ +static unsigned long read_p15_c1 (void) +{ + unsigned long value; + + __asm__ __volatile__( + "mrc p15, 0, %0, c1, c0, 0 @ read control reg\n" + : "=r" (value) + : + : "memory"); + return value; +} + +/* write to co-processor 15, register #1 (control register) */ +static void write_p15_c1 (unsigned long value) +{ + __asm__ __volatile__( + "mcr p15, 0, %0, c1, c0, 0 @ write it back\n" + : + : "r" (value) + : "memory"); + + read_p15_c1(); +} + +static void cp_delay (void) +{ + volatile int i; + + /* Many OMAP regs need at least 2 nops */ + for (i = 0; i < 100; i++) + __asm__ __volatile__("nop\n"); +} + +/* See also ARM Ref. Man. */ +#define C1_MMU (1 << 0) /* mmu off/on */ +#define C1_ALIGN (1 << 1) /* alignment faults off/on */ +#define C1_DC (1 << 2) /* dcache off/on */ +#define C1_WB (1 << 3) /* merging write buffer on/off */ +#define C1_BIG_ENDIAN (1 << 7) /* big endian off/on */ +#define C1_SYS_PROT (1 << 8) /* system protection */ +#define C1_ROM_PROT (1 << 9) /* ROM protection */ +#define C1_IC (1 << 12) /* icache off/on */ +#define C1_HIGH_VECTORS (1 << 13) /* location of vectors: low/high */ +#define RESERVED_1 (0xf << 3) /* must be 111b for R/W */ + +int cpu_init (void) +{ + return 0; +} + +int cleanup_before_linux (void) +{ + /* + * this function is called just before we call linux + * it prepares the processor for linux + * + * we turn off caches etc ... + */ + + disable_interrupts (); + + /* turn off I/D-cache */ + icache_disable(); + dcache_disable(); + cache_flush(); + + return 0; +} + + +/* * reset the cpu by setting up the watchdog timer and let him time out */ +void reset_cpu (ulong ignored) +{ + printf("reset... \n\n\n"); + SW_RST_REG = 0x6400; + /* loop forever and wait for reset to happen */ + while (1) { + if (serial_tstc()) { + serial_getc(); + break; + } + } + /*NOTREACHED*/ +} + +int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + disable_interrupts (); + reset_cpu (0); + /*NOTREACHED*/ + return 0; +} + +void icache_enable (void) +{ + ulong reg; + + reg = read_p15_c1 (); /* get control reg. */ + cp_delay (); + write_p15_c1 (reg | C1_IC); +} + +void icache_disable (void) +{ + ulong reg; + + reg = read_p15_c1 (); + cp_delay (); + write_p15_c1 (reg & ~C1_IC); +} + +int icache_status (void) +{ + return (read_p15_c1 () & C1_IC) != 0; +} + +/* It makes no sense to use the dcache if the MMU is not enabled */ +void dcache_enable (void) +{ + ulong reg; + + reg = read_p15_c1 (); + cp_delay (); + write_p15_c1 (reg | C1_DC); +} + +void dcache_disable (void) +{ + ulong reg; + + reg = read_p15_c1 (); + cp_delay (); + write_p15_c1 (reg & ~C1_DC); +} + +int dcache_status (void) +{ + return (read_p15_c1 () & C1_DC) != 0; +} + +/* flush I/D-cache */ +static void cache_flush (void) +{ + /* invalidate both caches and flush btb */ + asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (0)); + /* mem barrier to sync things */ + asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (0)); +} diff --git a/cpu/arm1176/s3c64xx/Makefile b/cpu/arm1176/s3c64xx/Makefile new file mode 100644 index 000000000..fa4ee3f24 --- /dev/null +++ b/cpu/arm1176/s3c64xx/Makefile @@ -0,0 +1,48 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2008 +# Guennadi Liakhovetki, DENX Software Engineering, +# +# 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 +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS-y = interrupts.o +COBJS-$(CONFIG_S3C6400) += cpu_init.o speed.o + +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm1176/s3c64xx/config.mk b/cpu/arm1176/s3c64xx/config.mk new file mode 100644 index 000000000..204e880b8 --- /dev/null +++ b/cpu/arm1176/s3c64xx/config.mk @@ -0,0 +1,34 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, +# +# 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 +# +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ + -msoft-float + +# Make ARMv5 to allow more compilers to work, even though its v6. +PLATFORM_CPPFLAGS += -march=armv5t +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +#PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) diff --git a/cpu/arm1176/s3c64xx/cpu_init.S b/cpu/arm1176/s3c64xx/cpu_init.S new file mode 100644 index 000000000..08bda99fd --- /dev/null +++ b/cpu/arm1176/s3c64xx/cpu_init.S @@ -0,0 +1,142 @@ +/* + * Originates from Samsung's u-boot 1.1.6 port to S3C6400 / SMDK6400 + * + * Copyright (C) 2008 + * Guennadi Liakhovetki, DENX Software Engineering, + * + * 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 + */ + +#include +#include + + .globl mem_ctrl_asm_init +mem_ctrl_asm_init: + /* Memory subsystem address 0x7e00f120 */ + ldr r0, =ELFIN_MEM_SYS_CFG + + /* Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1 */ + mov r1, #0xd + str r1, [r0] + + /* DMC1 base address 0x7e001000 */ + ldr r0, =ELFIN_DMC1_BASE + + ldr r1, =0x4 + str r1, [r0, #INDEX_DMC_MEMC_CMD] + + ldr r1, =DMC_DDR_REFRESH_PRD + str r1, [r0, #INDEX_DMC_REFRESH_PRD] + + ldr r1, =DMC_DDR_CAS_LATENCY + str r1, [r0, #INDEX_DMC_CAS_LATENCY] + + ldr r1, =DMC_DDR_t_DQSS + str r1, [r0, #INDEX_DMC_T_DQSS] + + ldr r1, =DMC_DDR_t_MRD + str r1, [r0, #INDEX_DMC_T_MRD] + + ldr r1, =DMC_DDR_t_RAS + str r1, [r0, #INDEX_DMC_T_RAS] + + ldr r1, =DMC_DDR_t_RC + str r1, [r0, #INDEX_DMC_T_RC] + + ldr r1, =DMC_DDR_t_RCD + ldr r2, =DMC_DDR_schedule_RCD + orr r1, r1, r2 + str r1, [r0, #INDEX_DMC_T_RCD] + + ldr r1, =DMC_DDR_t_RFC + ldr r2, =DMC_DDR_schedule_RFC + orr r1, r1, r2 + str r1, [r0, #INDEX_DMC_T_RFC] + + ldr r1, =DMC_DDR_t_RP + ldr r2, =DMC_DDR_schedule_RP + orr r1, r1, r2 + str r1, [r0, #INDEX_DMC_T_RP] + + ldr r1, =DMC_DDR_t_RRD + str r1, [r0, #INDEX_DMC_T_RRD] + + ldr r1, =DMC_DDR_t_WR + str r1, [r0, #INDEX_DMC_T_WR] + + ldr r1, =DMC_DDR_t_WTR + str r1, [r0, #INDEX_DMC_T_WTR] + + ldr r1, =DMC_DDR_t_XP + str r1, [r0, #INDEX_DMC_T_XP] + + ldr r1, =DMC_DDR_t_XSR + str r1, [r0, #INDEX_DMC_T_XSR] + + ldr r1, =DMC_DDR_t_ESR + str r1, [r0, #INDEX_DMC_T_ESR] + + ldr r1, =DMC1_MEM_CFG + str r1, [r0, #INDEX_DMC_MEMORY_CFG] + + ldr r1, =DMC1_MEM_CFG2 + str r1, [r0, #INDEX_DMC_MEMORY_CFG2] + + ldr r1, =DMC1_CHIP0_CFG + str r1, [r0, #INDEX_DMC_CHIP_0_CFG] + + ldr r1, =DMC_DDR_32_CFG + str r1, [r0, #INDEX_DMC_USER_CONFIG] + + /* DMC0 DDR Chip 0 configuration direct command reg */ + ldr r1, =DMC_NOP0 + str r1, [r0, #INDEX_DMC_DIRECT_CMD] + + /* Precharge All */ + ldr r1, =DMC_PA0 + str r1, [r0, #INDEX_DMC_DIRECT_CMD] + + /* Auto Refresh 2 time */ + ldr r1, =DMC_AR0 + str r1, [r0, #INDEX_DMC_DIRECT_CMD] + str r1, [r0, #INDEX_DMC_DIRECT_CMD] + + /* MRS */ + ldr r1, =DMC_mDDR_EMR0 + str r1, [r0, #INDEX_DMC_DIRECT_CMD] + + /* Mode Reg */ + ldr r1, =DMC_mDDR_MR0 + str r1, [r0, #INDEX_DMC_DIRECT_CMD] + + /* Enable DMC1 */ + mov r1, #0x0 + str r1, [r0, #INDEX_DMC_MEMC_CMD] + +check_dmc1_ready: + ldr r1, [r0, #INDEX_DMC_MEMC_STATUS] + mov r2, #0x3 + and r1, r1, r2 + cmp r1, #0x1 + bne check_dmc1_ready + nop + + mov pc, lr + + .ltorg diff --git a/cpu/arm1176/s3c64xx/interrupts.c b/cpu/arm1176/s3c64xx/interrupts.c new file mode 100644 index 000000000..8356ae49e --- /dev/null +++ b/cpu/arm1176/s3c64xx/interrupts.c @@ -0,0 +1,174 @@ +/* + * (C) Copyright 2003 + * Texas Instruments + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Alex Zuepke + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, + * + * 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 + */ + +#include +#include +#include + +static ulong timer_load_val; + +#define PRESCALER 167 + +static s3c64xx_timers *s3c64xx_get_base_timers(void) +{ + return (s3c64xx_timers *)ELFIN_TIMER_BASE; +} + +/* macro to read the 16 bit timer */ +static inline ulong read_timer(void) +{ + s3c64xx_timers *const timers = s3c64xx_get_base_timers(); + + return timers->TCNTO4; +} + +/* Internal tick units */ +/* Last decremneter snapshot */ +static unsigned long lastdec; +/* Monotonic incrementing timer */ +static unsigned long long timestamp; + +int interrupt_init(void) +{ + s3c64xx_timers *const timers = s3c64xx_get_base_timers(); + + /* use PWM Timer 4 because it has no output */ + /* + * We use the following scheme for the timer: + * Prescaler is hard fixed at 167, divider at 1/4. + * This gives at PCLK frequency 66MHz approx. 10us ticks + * The timer is set to wrap after 100s, at 66MHz this obviously + * happens after 10,000,000 ticks. A long variable can thus + * keep values up to 40,000s, i.e., 11 hours. This should be + * enough for most uses:-) Possible optimizations: select a + * binary-friendly frequency, e.g., 1ms / 128. Also calculate + * the prescaler automatically for other PCLK frequencies. + */ + timers->TCFG0 = PRESCALER << 8; + if (timer_load_val == 0) { + timer_load_val = get_PCLK() / PRESCALER * (100 / 4); /* 100s */ + timers->TCFG1 = (timers->TCFG1 & ~0xf0000) | 0x20000; + } + + /* load value for 10 ms timeout */ + lastdec = timers->TCNTB4 = timer_load_val; + /* auto load, manual update of Timer 4 */ + timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | + TCON_4_UPDATE; + + /* auto load, start Timer 4 */ + timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON; + timestamp = 0; + + return 0; +} + +/* + * timer without interrupts + */ + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + ulong now = read_timer(); + + if (lastdec >= now) { + /* normal mode */ + timestamp += lastdec - now; + } else { + /* we have an overflow ... */ + timestamp += lastdec + timer_load_val - now; + } + lastdec = now; + + return timestamp; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + /* We overrun in 100s */ + return (ulong)(timer_load_val / 100); +} + +void reset_timer_masked(void) +{ + /* reset time */ + lastdec = read_timer(); + timestamp = 0; +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer_masked(void) +{ + return get_ticks() / (timer_load_val / (100 * CFG_HZ)); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void set_timer(ulong t) +{ + timestamp = t * (timer_load_val / (100 * CFG_HZ)); +} + +void udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = (usec + 9) / 10; + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp)/* loop till event */ + /*NOP*/; +} diff --git a/cpu/arm1176/s3c64xx/speed.c b/cpu/arm1176/s3c64xx/speed.c new file mode 100644 index 000000000..5c335a55a --- /dev/null +++ b/cpu/arm1176/s3c64xx/speed.c @@ -0,0 +1,145 @@ +/* + * (C) Copyright 2001-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * David Mueller, ELSOFT AG, d.mueller@elsoft.ch + * + * 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 + */ + +/* + * This code should work for both the S3C2400 and the S3C2410 + * as they seem to have the same PLL and clock machinery inside. + * The different address mapping is handled by the s3c24xx.h files below. + */ + +#include +#include + +#define APLL 0 +#define MPLL 1 +#define EPLL 2 + +/* ------------------------------------------------------------------------- */ +/* + * NOTE: This describes the proper use of this file. + * + * CONFIG_SYS_CLK_FREQ should be defined as the input frequency of the PLL. + * + * get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of + * the specified bus in HZ. + */ +/* ------------------------------------------------------------------------- */ + +static ulong get_PLLCLK(int pllreg) +{ + ulong r, m, p, s; + + switch (pllreg) { + case APLL: + r = APLL_CON_REG; + break; + case MPLL: + r = MPLL_CON_REG; + break; + case EPLL: + r = EPLL_CON0_REG; + break; + default: + hang(); + } + + m = (r >> 16) & 0x3ff; + p = (r >> 8) & 0x3f; + s = r & 0x7; + + return m * (CONFIG_SYS_CLK_FREQ / (p * (1 << s))); +} + +/* return ARMCORE frequency */ +ulong get_ARMCLK(void) +{ + ulong div; + + div = CLK_DIV0_REG; + + return get_PLLCLK(APLL) / ((div & 0x7) + 1); +} + +/* return FCLK frequency */ +ulong get_FCLK(void) +{ + return get_PLLCLK(APLL); +} + +/* return HCLK frequency */ +ulong get_HCLK(void) +{ + ulong fclk; + + uint hclkx2_div = ((CLK_DIV0_REG >> 9) & 0x7) + 1; + uint hclk_div = ((CLK_DIV0_REG >> 8) & 0x1) + 1; + + /* + * Bit 7 exists on s3c6410, and not on s3c6400, it is reserved on + * s3c6400 and is always 0, and it is indeed running in ASYNC mode + */ + if (OTHERS_REG & 0x80) + fclk = get_FCLK(); /* SYNC Mode */ + else + fclk = get_PLLCLK(MPLL); /* ASYNC Mode */ + + return fclk / (hclk_div * hclkx2_div); +} + +/* return PCLK frequency */ +ulong get_PCLK(void) +{ + ulong fclk; + uint hclkx2_div = ((CLK_DIV0_REG >> 9) & 0x7) + 1; + uint pre_div = ((CLK_DIV0_REG >> 12) & 0xf) + 1; + + if (OTHERS_REG & 0x80) + fclk = get_FCLK(); /* SYNC Mode */ + else + fclk = get_PLLCLK(MPLL); /* ASYNC Mode */ + + return fclk / (hclkx2_div * pre_div); +} + +/* return UCLK frequency */ +ulong get_UCLK(void) +{ + return get_PLLCLK(EPLL); +} + +int print_cpuinfo(void) +{ + printf("\nCPU: S3C6400@%luMHz\n", get_ARMCLK() / 1000000); + printf(" Fclk = %luMHz, Hclk = %luMHz, Pclk = %luMHz ", + get_FCLK() / 1000000, get_HCLK() / 1000000, + get_PCLK() / 1000000); + + if (OTHERS_REG & 0x80) + printf("(SYNC Mode) \n"); + else + printf("(ASYNC Mode) \n"); + return 0; +} diff --git a/cpu/arm1176/start.S b/cpu/arm1176/start.S new file mode 100644 index 000000000..991277f1c --- /dev/null +++ b/cpu/arm1176/start.S @@ -0,0 +1,469 @@ +/* + * armboot - Startup Code for S3C6400/ARM1176 CPU-core + * + * Copyright (c) 2007 Samsung Electronics + * + * Copyright (C) 2008 + * Guennadi Liakhovetki, DENX Software Engineering, + * + * 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 + * + * 2007-09-21 - Restructured codes by jsgood (jsgood.yang@samsung.com) + * 2007-09-21 - Added MoviNAND and OneNAND boot codes by + * jsgood (jsgood.yang@samsung.com) + * Base codes by scsuh (sc.suh) + */ + +#include +#include +#ifdef CONFIG_ENABLE_MMU +#include +#endif +#include + +#if !defined(CONFIG_ENABLE_MMU) && !defined(CFG_PHY_UBOOT_BASE) +#define CFG_PHY_UBOOT_BASE CFG_UBOOT_BASE +#endif + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + +.globl _start +_start: b reset +#ifndef CONFIG_NAND_SPL + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: + .word undefined_instruction +_software_interrupt: + .word software_interrupt +_prefetch_abort: + .word prefetch_abort +_data_abort: + .word data_abort +_not_used: + .word not_used +_irq: + .word irq +_fiq: + .word fiq +_pad: + .word 0x12345678 /* now 16*4=64 */ +#else + . = _start + 64 +#endif + +.global _end_vect +_end_vect: + .balignl 16,0xdeadbeef +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* + */ + +_TEXT_BASE: + .word TEXT_BASE + +/* + * Below variable is very important because we use MMU in U-Boot. + * Without it, we cannot run code correctly before MMU is ON. + * by scsuh. + */ +_TEXT_PHY_BASE: + .word CFG_PHY_UBOOT_BASE + +.globl _armboot_start +_armboot_start: + .word _start + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +/* + * the actual reset code + */ + +reset: + /* + * set the cpu to SVC32 mode + */ + mrs r0, cpsr + bic r0, r0, #0x3f + orr r0, r0, #0xd3 + msr cpsr, r0 + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + /* + * we do sys-critical inits only at reboot, + * not when booting from ram! + */ +cpu_init_crit: + /* + * When booting from NAND - it has definitely been a reset, so, no need + * to flush caches and disable the MMU + */ +#ifndef CONFIG_NAND_SPL + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + /* Prepare to disable the MMU */ + adr r1, mmu_disable_phys + /* We presume we're within the first 1024 bytes */ + and r1, r1, #0x3fc + ldr r2, _TEXT_PHY_BASE + ldr r3, =0xfff00000 + and r2, r2, r3 + orr r2, r2, r1 + b mmu_disable + + .align 5 + /* Run in a single cache-line */ +mmu_disable: + mcr p15, 0, r0, c1, c0, 0 + nop + nop + mov pc, r2 +#endif + +mmu_disable_phys: + /* Peri port setup */ + ldr r0, =0x70000000 + orr r0, r0, #0x13 + mcr p15,0,r0,c15,c2,4 @ 256M (0x70000000 - 0x7fffffff) + + /* + * Go setup Memory and board specific bits prior to relocation. + */ + bl lowlevel_init /* go setup pll,mux,memory */ + +after_copy: +#ifdef CONFIG_ENABLE_MMU +enable_mmu: + /* enable domain access */ + ldr r5, =0x0000ffff + mcr p15, 0, r5, c3, c0, 0 /* load domain access register */ + + /* Set the TTB register */ + ldr r0, _mmu_table_base + ldr r1, =CFG_PHY_UBOOT_BASE + ldr r2, =0xfff00000 + bic r0, r0, r2 + orr r1, r0, r1 + mcr p15, 0, r1, c2, c0, 0 + + /* Enable the MMU */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #1 /* Set CR_M to enable MMU */ + + /* Prepare to enable the MMU */ + adr r1, skip_hw_init + and r1, r1, #0x3fc + ldr r2, _TEXT_BASE + ldr r3, =0xfff00000 + and r2, r2, r3 + orr r2, r2, r1 + b mmu_enable + + .align 5 + /* Run in a single cache-line */ +mmu_enable: + + mcr p15, 0, r0, c1, c0, 0 + nop + nop + mov pc, r2 +#endif + +skip_hw_init: + /* Set up the stack */ +stack_setup: +#ifdef CONFIG_MEMORY_UPPER_CODE + ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc) +#else + ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CFG_MALLOC_LEN /* malloc area */ + sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ + +#endif + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0 /* clear */ + +clbss_l: + str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + +#ifndef CONFIG_NAND_SPL + ldr pc, _start_armboot + +_start_armboot: + .word start_armboot +#else + b nand_boot +/* .word nand_boot*/ +#endif + +#ifdef CONFIG_ENABLE_MMU +_mmu_table_base: + .word mmu_table +#endif + +#ifndef CONFIG_NAND_SPL +/* + * we assume that cache operation is done before. (eg. cleanup_before_linux()) + * actually, we don't need to do anything about cache if not use d-cache in + * U-Boot. So, in this function we clean only MMU. by scsuh + * + * void theLastJump(void *kernel, int arch_num, uint boot_params); + */ +#ifdef CONFIG_ENABLE_MMU + .globl theLastJump +theLastJump: + mov r9, r0 + ldr r3, =0xfff00000 + ldr r4, _TEXT_PHY_BASE + adr r5, phy_last_jump + bic r5, r5, r3 + orr r5, r5, r4 + mov pc, r5 +phy_last_jump: + /* + * disable MMU stuff + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */ + bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */ + orr r0, r0, #0x00000002 /* set bit 2 (A) Align */ + orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ + mcr p15, 0, r0, c1, c0, 0 + + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + mov r0, #0 + mov pc, r9 +#endif +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + */ + + .macro bad_save_user_regs + /* carve out a frame on current user stack */ + sub sp, sp, #S_FRAME_SIZE + /* Save user registers (now in svc mode) r0-r12 */ + stmia sp, {r0 - r12} + + ldr r2, _armboot_start + sub r2, r2, #(CFG_MALLOC_LEN) + /* set base 2 words into abort stack */ + sub r2, r2, #(CFG_GBL_DATA_SIZE+8) + /* get values for "aborted" pc and cpsr (into parm regs) */ + ldmia r2, {r2 - r3} + /* grab pointer to old stack */ + add r0, sp, #S_FRAME_SIZE + + add r5, sp, #S_SP + mov r1, lr + /* save sp_SVC, lr_SVC, pc, cpsr */ + stmia r5, {r0 - r3} + /* save current stack into r0 (param register) */ + mov r0, sp + .endm + + .macro get_bad_stack + /* setup our mode stack (enter in banked mode) */ + ldr r13, _armboot_start + /* move past malloc pool */ + sub r13, r13, #(CFG_MALLOC_LEN) + /* move to reserved a couple spots for abort stack */ + sub r13, r13, #(CFG_GBL_DATA_SIZE + 8) + + /* save caller lr in position 0 of saved stack */ + str lr, [r13] + /* get the spsr */ + mrs lr, spsr + /* save spsr in position 1 of saved stack */ + str lr, [r13, #4] + + /* prepare SVC-Mode */ + mov r13, #MODE_SVC + @ msr spsr_c, r13 + /* switch modes, make sure moves will execute */ + msr spsr, r13 + /* capture return pc */ + mov lr, pc + /* jump to next instruction & switch modes. */ + movs pc, lr + .endm + + .macro get_bad_stack_swi + /* space on current stack for scratch reg. */ + sub r13, r13, #4 + /* save R0's value. */ + str r0, [r13] + /* get data regions start */ + ldr r0, _armboot_start + /* move past malloc pool */ + sub r0, r0, #(CFG_MALLOC_LEN) + /* move past gbl and a couple spots for abort stack */ + sub r0, r0, #(CFG_GBL_DATA_SIZE + 8) + /* save caller lr in position 0 of saved stack */ + str lr, [r0] + /* get the spsr */ + mrs r0, spsr + /* save spsr in position 1 of saved stack */ + str lr, [r0, #4] + /* restore r0 */ + ldr r0, [r13] + /* pop stack entry */ + add r13, r13, #4 + .endm + +/* + * exception handlers + */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack_swi + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq +#endif /* CONFIG_NAND_SPL */ -- cgit v1.2.3