summaryrefslogtreecommitdiff
path: root/cpu/arm926ejs
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/arm926ejs')
-rw-r--r--cpu/arm926ejs/at91/Makefile8
-rw-r--r--cpu/arm926ejs/at91/at91cap9_devices.c15
-rw-r--r--cpu/arm926ejs/at91/at91sam9263_devices.c15
-rw-r--r--cpu/arm926ejs/at91/lowlevel_init.S278
-rw-r--r--cpu/arm926ejs/kirkwood/Makefile49
-rw-r--r--cpu/arm926ejs/kirkwood/cpu.c311
-rw-r--r--cpu/arm926ejs/kirkwood/dram.c58
-rw-r--r--cpu/arm926ejs/kirkwood/mpp.c80
-rw-r--r--cpu/arm926ejs/kirkwood/timer.c168
-rw-r--r--cpu/arm926ejs/mx27/Makefile44
-rw-r--r--cpu/arm926ejs/mx27/generic.c241
-rw-r--r--cpu/arm926ejs/mx27/reset.c57
-rw-r--r--cpu/arm926ejs/mx27/timer.c191
-rw-r--r--cpu/arm926ejs/nomadik/reset.S13
-rw-r--r--cpu/arm926ejs/nomadik/timer.c166
15 files changed, 1541 insertions, 153 deletions
diff --git a/cpu/arm926ejs/at91/Makefile b/cpu/arm926ejs/at91/Makefile
index 66eec76..3da89f4 100644
--- a/cpu/arm926ejs/at91/Makefile
+++ b/cpu/arm926ejs/at91/Makefile
@@ -37,8 +37,12 @@ COBJS-y += cpu.o
COBJS-y += reset.o
COBJS-y += timer.o
-SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
-OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y))
+ifndef CONFIG_SKIP_LOWLEVEL_INIT
+SOBJS-y := lowlevel_init.o
+endif
+
+SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
all: $(obj).depend $(LIB)
diff --git a/cpu/arm926ejs/at91/at91cap9_devices.c b/cpu/arm926ejs/at91/at91cap9_devices.c
index c0024ac..39e405f 100644
--- a/cpu/arm926ejs/at91/at91cap9_devices.c
+++ b/cpu/arm926ejs/at91/at91cap9_devices.c
@@ -3,6 +3,10 @@
* Stelian Pop <stelian.pop@leadtechdesign.com>
* Lead Tech Design <www.leadtechdesign.com>
*
+ * (C) Copyright 2009
+ * Daniel Gorsulowski <daniel.gorsulowski@esd.eu>
+ * esd electronic system design gmbh <www.esd.eu>
+ *
* See file CREDITS for list of people who contributed to this
* project.
*
@@ -174,3 +178,14 @@ void at91_macb_hw_init(void)
#endif
}
#endif
+
+#ifdef CONFIG_AT91_CAN
+void at91_can_hw_init(void)
+{
+ at91_set_A_periph(AT91_PIN_PA12, 0); /* CAN_TX */
+ at91_set_A_periph(AT91_PIN_PA13, 1); /* CAN_RX */
+
+ /* Enable clock */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91CAP9_ID_CAN);
+}
+#endif
diff --git a/cpu/arm926ejs/at91/at91sam9263_devices.c b/cpu/arm926ejs/at91/at91sam9263_devices.c
index 0f2613e..f72efdf 100644
--- a/cpu/arm926ejs/at91/at91sam9263_devices.c
+++ b/cpu/arm926ejs/at91/at91sam9263_devices.c
@@ -3,6 +3,10 @@
* Stelian Pop <stelian.pop@leadtechdesign.com>
* Lead Tech Design <www.leadtechdesign.com>
*
+ * (C) Copyright 2009
+ * Daniel Gorsulowski <daniel.gorsulowski@esd.eu>
+ * esd electronic system design gmbh <www.esd.eu>
+ *
* See file CREDITS for list of people who contributed to this
* project.
*
@@ -182,3 +186,14 @@ void at91_uhp_hw_init(void)
at91_set_gpio_output(AT91_PIN_PA24, 0);
}
#endif
+
+#ifdef CONFIG_AT91_CAN
+void at91_can_hw_init(void)
+{
+ at91_set_A_periph(AT91_PIN_PA13, 0); /* CAN_TX */
+ at91_set_A_periph(AT91_PIN_PA14, 1); /* CAN_RX */
+
+ /* Enable clock */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_CAN);
+}
+#endif
diff --git a/cpu/arm926ejs/at91/lowlevel_init.S b/cpu/arm926ejs/at91/lowlevel_init.S
new file mode 100644
index 0000000..5ed518c
--- /dev/null
+++ b/cpu/arm926ejs/at91/lowlevel_init.S
@@ -0,0 +1,278 @@
+/*
+ * Memory Setup stuff - taken from blob memsetup.S
+ *
+ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
+ * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
+ *
+ * Copyright (C) 2008 Ronetix Ilko Iliev (www.ronetix.at)
+ * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * 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 <config.h>
+#include <version.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_pio.h>
+#include <asm/arch/at91_rstc.h>
+#include <asm/arch/at91_wdt.h>
+#include <asm/arch/at91sam9_matrix.h>
+#include <asm/arch/at91sam9_sdramc.h>
+#include <asm/arch/at91sam9_smc.h>
+
+_TEXT_BASE:
+ .word TEXT_BASE
+
+.globl lowlevel_init
+.type lowlevel_init,function
+lowlevel_init:
+
+ mov r5, pc /* r5 = POS1 + 4 current */
+POS1:
+ ldr r0, =POS1 /* r0 = POS1 compile */
+ ldr r2, _TEXT_BASE
+ sub r0, r0, r2 /* r0 = POS1-_TEXT_BASE (POS1 relative) */
+ sub r5, r5, r0 /* r0 = TEXT_BASE-1 */
+ sub r5, r5, #4 /* r1 = text base - current */
+
+ /* memory control configuration 1 */
+ ldr r0, =SMRDATA
+ ldr r2, =SMRDATA1
+ ldr r1, _TEXT_BASE
+ sub r0, r0, r1
+ sub r2, r2, r1
+ add r0, r0, r5
+ add r2, r2, r5
+0:
+ /* the address */
+ ldr r1, [r0], #4
+ /* the value */
+ ldr r3, [r0], #4
+ str r3, [r1]
+ cmp r2, r0
+ bne 0b
+
+/* ----------------------------------------------------------------------------
+ * PMC Init Step 1.
+ * ----------------------------------------------------------------------------
+ * - Check if the PLL is already initialized
+ * ----------------------------------------------------------------------------
+ */
+ ldr r1, =(AT91_BASE_SYS + AT91_PMC_MCKR)
+ ldr r0, [r1]
+ and r0, r0, #3
+ cmp r0, #0
+ bne PLL_setup_end
+
+/* ---------------------------------------------------------------------------
+ * - Enable the Main Oscillator
+ * ---------------------------------------------------------------------------
+ */
+ ldr r1, =(AT91_BASE_SYS + AT91_CKGR_MOR)
+ ldr r2, =(AT91_BASE_SYS + AT91_PMC_SR)
+ /* Main oscillator Enable register PMC_MOR: */
+ ldr r0, =CONFIG_SYS_MOR_VAL
+ str r0, [r1]
+
+ /* Reading the PMC Status to detect when the Main Oscillator is enabled */
+ mov r4, #AT91_PMC_MOSCS
+MOSCS_Loop:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_MOSCS
+ bne MOSCS_Loop
+
+/* ----------------------------------------------------------------------------
+ * PMC Init Step 2.
+ * ----------------------------------------------------------------------------
+ * Setup PLLA
+ * ----------------------------------------------------------------------------
+ */
+ ldr r1, =(AT91_BASE_SYS + AT91_CKGR_PLLAR)
+ ldr r0, =CONFIG_SYS_PLLAR_VAL
+ str r0, [r1]
+
+ /* Reading the PMC Status register to detect when the PLLA is locked */
+ mov r4, #AT91_PMC_LOCKA
+MOSCS_Loop1:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_LOCKA
+ bne MOSCS_Loop1
+
+/* ----------------------------------------------------------------------------
+ * PMC Init Step 3.
+ * ----------------------------------------------------------------------------
+ * - Switch on the Main Oscillator
+ * ----------------------------------------------------------------------------
+ */
+ ldr r1, =(AT91_BASE_SYS + AT91_PMC_MCKR)
+
+ /* -Master Clock Controller register PMC_MCKR */
+ ldr r0, =CONFIG_SYS_MCKR1_VAL
+ str r0, [r1]
+
+ /* Reading the PMC Status to detect when the Master clock is ready */
+ mov r4, #AT91_PMC_MCKRDY
+MCKRDY_Loop:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_MCKRDY
+ bne MCKRDY_Loop
+
+ ldr r0, =CONFIG_SYS_MCKR2_VAL
+ str r0, [r1]
+
+ /* Reading the PMC Status to detect when the Master clock is ready */
+ mov r4, #AT91_PMC_MCKRDY
+MCKRDY_Loop1:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_MCKRDY
+ bne MCKRDY_Loop1
+
+PLL_setup_end:
+
+/* ----------------------------------------------------------------------------
+ * - memory control configuration 2
+ * ----------------------------------------------------------------------------
+ */
+ ldr r0, =(AT91_BASE_SYS + AT91_SDRAMC_TR)
+ ldr r1, [r0]
+ cmp r1, #0
+ bne SDRAM_setup_end
+
+ ldr r0, =SMRDATA1
+ ldr r2, =SMRDATA2
+ ldr r1, _TEXT_BASE
+ sub r0, r0, r1
+ sub r2, r2, r1
+ add r0, r0, r5
+ add r2, r2, r5
+
+2:
+ /* the address */
+ ldr r1, [r0], #4
+ /* the value */
+ ldr r3, [r0], #4
+ str r3, [r1]
+ cmp r2, r0
+ bne 2b
+
+SDRAM_setup_end:
+ /* everything is fine now */
+ mov pc, lr
+
+ .ltorg
+
+SMRDATA:
+ .word (AT91_BASE_SYS + AT91_WDT_MR)
+ .word CONFIG_SYS_WDTC_WDMR_VAL
+
+ /* configure PIOx as EBI0 D[16-31] */
+#if defined(CONFIG_AT91SAM9263)
+ .word (AT91_BASE_SYS + AT91_PIOD + PIO_PDR)
+ .word CONFIG_SYS_PIOD_PDR_VAL1
+ .word (AT91_BASE_SYS + AT91_PIOD + PIO_PUDR)
+ .word CONFIG_SYS_PIOD_PPUDR_VAL
+ .word (AT91_BASE_SYS + AT91_PIOD + PIO_ASR)
+ .word CONFIG_SYS_PIOD_PPUDR_VAL
+#elif defined(CONFIG_AT91SAM9261)
+ .word (AT91_BASE_SYS + AT91_PIOC + PIO_PDR)
+ .word CONFIG_SYS_PIOC_PDR_VAL1
+ .word (AT91_BASE_SYS + AT91_PIOC + PIO_PUDR)
+ .word CONFIG_SYS_PIOC_PPUDR_VAL
+#endif
+
+#if defined(AT91_MATRIX_EBI0CSA)
+ .word (AT91_BASE_SYS + AT91_MATRIX_EBI0CSA)
+ .word CONFIG_SYS_MATRIX_EBI0CSA_VAL
+#else /* AT91_MATRIX_EBICSA */
+ .word (AT91_BASE_SYS + AT91_MATRIX_EBICSA)
+ .word CONFIG_SYS_MATRIX_EBICSA_VAL
+#endif
+
+ /* flash */
+ .word (AT91_BASE_SYS + AT91_SMC_MODE(0))
+ .word CONFIG_SYS_SMC0_MODE0_VAL
+
+ .word (AT91_BASE_SYS + AT91_SMC_CYCLE(0))
+ .word CONFIG_SYS_SMC0_CYCLE0_VAL
+
+ .word (AT91_BASE_SYS + AT91_SMC_PULSE(0))
+ .word CONFIG_SYS_SMC0_PULSE0_VAL
+
+ .word (AT91_BASE_SYS + AT91_SMC_SETUP(0))
+ .word CONFIG_SYS_SMC0_SETUP0_VAL
+
+SMRDATA1:
+ .word (AT91_BASE_SYS + AT91_SDRAMC_MR)
+ .word CONFIG_SYS_SDRC_MR_VAL1
+ .word (AT91_BASE_SYS + AT91_SDRAMC_TR)
+ .word CONFIG_SYS_SDRC_TR_VAL1
+ .word (AT91_BASE_SYS + AT91_SDRAMC_CR)
+ .word CONFIG_SYS_SDRC_CR_VAL
+ .word (AT91_BASE_SYS + AT91_SDRAMC_MDR)
+ .word CONFIG_SYS_SDRC_MDR_VAL
+ .word (AT91_BASE_SYS + AT91_SDRAMC_MR)
+ .word CONFIG_SYS_SDRC_MR_VAL2
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL1
+ .word (AT91_BASE_SYS + AT91_SDRAMC_MR)
+ .word CONFIG_SYS_SDRC_MR_VAL3
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL2
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL3
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL4
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL5
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL6
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL7
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL8
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL9
+ .word (AT91_BASE_SYS + AT91_SDRAMC_MR)
+ .word CONFIG_SYS_SDRC_MR_VAL4
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL10
+ .word (AT91_BASE_SYS + AT91_SDRAMC_MR)
+ .word CONFIG_SYS_SDRC_MR_VAL5
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL11
+ .word (AT91_BASE_SYS + AT91_SDRAMC_TR)
+ .word CONFIG_SYS_SDRC_TR_VAL2
+ .word AT91_SDRAM_BASE
+ .word CONFIG_SYS_SDRAM_VAL12
+ /* User reset enable*/
+ .word (AT91_BASE_SYS + AT91_RSTC_MR)
+ .word CONFIG_SYS_RSTC_RMR_VAL
+#ifdef CONFIG_SYS_MATRIX_MCFG_REMAP
+ /* MATRIX_MCFG - REMAP all masters */
+ .word (AT91_BASE_SYS + AT91_MATRIX_MCFG0)
+ .word 0x1FF
+#endif
+
+SMRDATA2:
+ .word 0
diff --git a/cpu/arm926ejs/kirkwood/Makefile b/cpu/arm926ejs/kirkwood/Makefile
new file mode 100644
index 0000000..d73e2104
--- /dev/null
+++ b/cpu/arm926ejs/kirkwood/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2009
+# Marvell Semiconductor <www.marvell.com>
+# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(SOC).a
+
+COBJS-y = dram.o
+COBJS-y += cpu.o
+COBJS-y += mpp.o
+COBJS-y += timer.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/arm926ejs/kirkwood/cpu.c b/cpu/arm926ejs/kirkwood/cpu.c
new file mode 100644
index 0000000..795a739
--- /dev/null
+++ b/cpu/arm926ejs/kirkwood/cpu.c
@@ -0,0 +1,311 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include <asm/cache.h>
+#include <u-boot/md5.h>
+#include <asm/arch/kirkwood.h>
+
+#define BUFLEN 16
+
+void reset_cpu(unsigned long ignored)
+{
+ struct kwcpu_registers *cpureg =
+ (struct kwcpu_registers *)KW_CPU_REG_BASE;
+
+ writel(readl(&cpureg->rstoutn_mask) | (1 << 2),
+ &cpureg->rstoutn_mask);
+ writel(readl(&cpureg->sys_soft_rst) | 1,
+ &cpureg->sys_soft_rst);
+ while (1) ;
+}
+
+/*
+ * Generates Ramdom hex number reading some time varient system registers
+ * and using md5 algorithm
+ */
+unsigned char get_random_hex(void)
+{
+ int i;
+ u32 inbuf[BUFLEN];
+ u8 outbuf[BUFLEN];
+
+ /*
+ * in case of 88F6281/88F6192 A0,
+ * Bit7 need to reset to generate random values in KW_REG_UNDOC_0x1470
+ * Soc reg offsets KW_REG_UNDOC_0x1470 and KW_REG_UNDOC_0x1478 are reserved regs and
+ * Does not have names at this moment (no errata available)
+ */
+ writel(readl(KW_REG_UNDOC_0x1478) & ~(1 << 7), KW_REG_UNDOC_0x1478);
+ for (i = 0; i < BUFLEN; i++) {
+ inbuf[i] = readl(KW_REG_UNDOC_0x1470);
+ }
+ md5((u8 *) inbuf, (BUFLEN * sizeof(u32)), outbuf);
+ return outbuf[outbuf[7] % 0x0f];
+}
+
+/*
+ * Window Size
+ * Used with the Base register to set the address window size and location.
+ * Must be programmed from LSB to MSB as sequence of ones followed by
+ * sequence of zeros. The number of ones specifies the size of the window in
+ * 64 KByte granularity (e.g., a value of 0x00FF specifies 256 = 16 MByte).
+ * NOTE: A value of 0x0 specifies 64-KByte size.
+ */
+unsigned int kw_winctrl_calcsize(unsigned int sizeval)
+{
+ int i;
+ unsigned int j = 0;
+ u32 val = sizeval >> 1;
+
+ for (i = 0; val > 0x10000; i++) {
+ j |= (1 << i);
+ val = val >> 1;
+ }
+ return (0x0000ffff & j);
+}
+
+/*
+ * kw_config_adr_windows - Configure address Windows
+ *
+ * There are 8 address windows supported by Kirkwood Soc to addess different
+ * devices. Each window can be configured for size, BAR and remap addr
+ * Below configuration is standard for most of the cases
+ *
+ * If remap function not used, remap_lo must be set as base
+ *
+ * Reference Documentation:
+ * Mbus-L to Mbus Bridge Registers Configuration.
+ * (Sec 25.1 and 25.3 of Datasheet)
+ */
+int kw_config_adr_windows(void)
+{
+ struct kwwin_registers *winregs =
+ (struct kwwin_registers *)KW_CPU_WIN_BASE;
+
+ /* Window 0: PCIE MEM address space */
+ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 256, KWCPU_TARGET_PCIE,
+ KWCPU_ATTR_PCIE_MEM, KWCPU_WIN_ENABLE), &winregs[0].ctrl);
+
+ writel(KW_DEFADR_PCI_MEM, &winregs[0].base);
+ writel(KW_DEFADR_PCI_MEM, &winregs[0].remap_lo);
+ writel(0x0, &winregs[0].remap_hi);
+
+ /* Window 1: PCIE IO address space */
+ writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_PCIE,
+ KWCPU_ATTR_PCIE_IO, KWCPU_WIN_ENABLE), &winregs[1].ctrl);
+ writel(KW_DEFADR_PCI_IO, &winregs[1].base);
+ writel(KW_DEFADR_PCI_IO_REMAP, &winregs[1].remap_lo);
+ writel(0x0, &winregs[1].remap_hi);
+
+ /* Window 2: NAND Flash address space */
+ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY,
+ KWCPU_ATTR_NANDFLASH, KWCPU_WIN_ENABLE), &winregs[2].ctrl);
+ writel(KW_DEFADR_NANDF, &winregs[2].base);
+ writel(KW_DEFADR_NANDF, &winregs[2].remap_lo);
+ writel(0x0, &winregs[2].remap_hi);
+
+ /* Window 3: SPI Flash address space */
+ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY,
+ KWCPU_ATTR_SPIFLASH, KWCPU_WIN_ENABLE), &winregs[3].ctrl);
+ writel(KW_DEFADR_SPIF, &winregs[3].base);
+ writel(KW_DEFADR_SPIF, &winregs[3].remap_lo);
+ writel(0x0, &winregs[3].remap_hi);
+
+ /* Window 4: BOOT Memory address space */
+ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY,
+ KWCPU_ATTR_BOOTROM, KWCPU_WIN_ENABLE), &winregs[4].ctrl);
+ writel(KW_DEFADR_BOOTROM, &winregs[4].base);
+
+ /* Window 5: Security SRAM address space */
+ writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_SASRAM,
+ KWCPU_ATTR_SASRAM, KWCPU_WIN_ENABLE), &winregs[5].ctrl);
+ writel(KW_DEFADR_SASRAM, &winregs[5].base);
+
+ /* Window 6-7: Disabled */
+ writel(KWCPU_WIN_DISABLE, &winregs[6].ctrl);
+ writel(KWCPU_WIN_DISABLE, &winregs[7].ctrl);
+
+ return 0;
+}
+
+/*
+ * kw_config_gpio - GPIO configuration
+ */
+void kw_config_gpio(u32 gpp0_oe_val, u32 gpp1_oe_val, u32 gpp0_oe, u32 gpp1_oe)
+{
+ struct kwgpio_registers *gpio0reg =
+ (struct kwgpio_registers *)KW_GPIO0_BASE;
+ struct kwgpio_registers *gpio1reg =
+ (struct kwgpio_registers *)KW_GPIO1_BASE;
+
+ /* Init GPIOS to default values as per board requirement */
+ writel(gpp0_oe_val, &gpio0reg->dout);
+ writel(gpp1_oe_val, &gpio1reg->dout);
+ writel(gpp0_oe, &gpio0reg->oe);
+ writel(gpp1_oe, &gpio1reg->oe);
+}
+
+/*
+ * kw_config_mpp - Multi-Purpose Pins Functionality configuration
+ *
+ * Each MPP can be configured to different functionality through
+ * MPP control register, ref (sec 6.1 of kirkwood h/w specification)
+ *
+ * There are maximum 64 Multi-Pourpose Pins on Kirkwood
+ * Each MPP functionality can be configuration by a 4bit value
+ * of MPP control reg, the value and associated functionality depends
+ * upon used SoC varient
+ */
+int kw_config_mpp(u32 mpp0_7, u32 mpp8_15, u32 mpp16_23, u32 mpp24_31,
+ u32 mpp32_39, u32 mpp40_47, u32 mpp48_55)
+{
+ u32 *mppreg = (u32 *) KW_MPP_BASE;
+
+ /* program mpp registers */
+ writel(mpp0_7, &mppreg[0]);
+ writel(mpp8_15, &mppreg[1]);
+ writel(mpp16_23, &mppreg[2]);
+ writel(mpp24_31, &mppreg[3]);
+ writel(mpp32_39, &mppreg[4]);
+ writel(mpp40_47, &mppreg[5]);
+ writel(mpp48_55, &mppreg[6]);
+ return 0;
+}
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+int print_cpuinfo(void)
+{
+ char *name = "Unknown";
+
+ switch (readl(KW_REG_DEVICE_ID) & 0x03) {
+ case 1:
+ name = "88F6192_A0";
+ break;
+ case 2:
+ name = "88F6281_A0";
+ break;
+ default:
+ printf("SoC: Unsupported Kirkwood\n");
+ return -1;
+ }
+ printf("SoC: Kirkwood %s\n", name);
+ return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifdef CONFIG_ARCH_CPU_INIT
+int arch_cpu_init(void)
+{
+ u32 reg;
+ struct kwcpu_registers *cpureg =
+ (struct kwcpu_registers *)KW_CPU_REG_BASE;
+
+ /* Linux expects` the internal registers to be at 0xf1000000 */
+ writel(KW_REGS_PHY_BASE, KW_OFFSET_REG);
+
+ /* Enable and invalidate L2 cache in write through mode */
+ writel(readl(&cpureg->l2_cfg) | 0x18, &cpureg->l2_cfg);
+ invalidate_l2_cache();
+
+ kw_config_adr_windows();
+
+#ifdef CONFIG_KIRKWOOD_RGMII_PAD_1V8
+ /*
+ * Configures the I/O voltage of the pads connected to Egigabit
+ * Ethernet interface to 1.8V
+ * By defult it is set to 3.3V
+ */
+ reg = readl(KW_REG_MPP_OUT_DRV_REG);
+ reg |= (1 << 7);
+ writel(reg, KW_REG_MPP_OUT_DRV_REG);
+#endif
+#ifdef CONFIG_KIRKWOOD_EGIGA_INIT
+ /*
+ * Set egiga port0/1 in normal functional mode
+ * This is required becasue on kirkwood by default ports are in reset mode
+ * OS egiga driver may not have provision to set them in normal mode
+ * and if u-boot is build without network support, network may fail at OS level
+ */
+ reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(0));
+ reg &= ~(1 << 4); /* Clear PortReset Bit */
+ writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(0)));
+ reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(1));
+ reg &= ~(1 << 4); /* Clear PortReset Bit */
+ writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(1)));
+#endif
+#ifdef CONFIG_KIRKWOOD_PCIE_INIT
+ /*
+ * Enable PCI Express Port0
+ */
+ reg = readl(&cpureg->ctrl_stat);
+ reg |= (1 << 0); /* Set PEX0En Bit */
+ writel(reg, &cpureg->ctrl_stat);
+#endif
+ return 0;
+}
+#endif /* CONFIG_ARCH_CPU_INIT */
+
+/*
+ * SOC specific misc init
+ */
+#if defined(CONFIG_ARCH_MISC_INIT)
+int arch_misc_init(void)
+{
+ volatile u32 temp;
+
+ /*CPU streaming & write allocate */
+ temp = readfr_extra_feature_reg();
+ temp &= ~(1 << 28); /* disable wr alloc */
+ writefr_extra_feature_reg(temp);
+
+ temp = readfr_extra_feature_reg();
+ temp &= ~(1 << 29); /* streaming disabled */
+ writefr_extra_feature_reg(temp);
+
+ /* L2Cache settings */
+ temp = readfr_extra_feature_reg();
+ /* Disable L2C pre fetch - Set bit 24 */
+ temp |= (1 << 24);
+ /* enable L2C - Set bit 22 */
+ temp |= (1 << 22);
+ writefr_extra_feature_reg(temp);
+
+ icache_enable();
+ /* Change reset vector to address 0x0 */
+ temp = get_cr();
+ set_cr(temp & ~CR_V);
+
+ return 0;
+}
+#endif /* CONFIG_ARCH_MISC_INIT */
+
+#ifdef CONFIG_KIRKWOOD_EGIGA
+int cpu_eth_init(bd_t *bis)
+{
+ kirkwood_egiga_initialize(bis);
+ return 0;
+}
+#endif
diff --git a/cpu/arm926ejs/kirkwood/dram.c b/cpu/arm926ejs/kirkwood/dram.c
new file mode 100644
index 0000000..8f2a18a
--- /dev/null
+++ b/cpu/arm926ejs/kirkwood/dram.c
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <asm/arch/kirkwood.h>
+
+#define KW_REG_CPUCS_WIN_BAR(x) (KW_REGISTER(0x1500) + (x * 0x08))
+#define KW_REG_CPUCS_WIN_SZ(x) (KW_REGISTER(0x1504) + (x * 0x08))
+/*
+ * kw_sdram_bar - reads SDRAM Base Address Register
+ */
+u32 kw_sdram_bar(enum memory_bank bank)
+{
+ u32 result = 0;
+ u32 enable = 0x01 & readl(KW_REG_CPUCS_WIN_SZ(bank));
+
+ if ((!enable) || (bank > BANK3))
+ return 0;
+
+ result = readl(KW_REG_CPUCS_WIN_BAR(bank));
+ return result;
+}
+
+/*
+ * kw_sdram_bs - reads SDRAM Bank size
+ */
+u32 kw_sdram_bs(enum memory_bank bank)
+{
+ u32 result = 0;
+ u32 enable = 0x01 & readl(KW_REG_CPUCS_WIN_SZ(bank));
+
+ if ((!enable) || (bank > BANK3))
+ return 0;
+ result = 0xff000000 & readl(KW_REG_CPUCS_WIN_SZ(bank));
+ result += 0x01000000;
+ return result;
+}
diff --git a/cpu/arm926ejs/kirkwood/mpp.c b/cpu/arm926ejs/kirkwood/mpp.c
new file mode 100644
index 0000000..b2f0ad5
--- /dev/null
+++ b/cpu/arm926ejs/kirkwood/mpp.c
@@ -0,0 +1,80 @@
+/*
+ * arch/arm/mach-kirkwood/mpp.c
+ *
+ * MPP functions for Marvell Kirkwood SoCs
+ * Referenced from Linux kernel source
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <common.h>
+#include <asm/arch/kirkwood.h>
+#include <asm/arch/mpp.h>
+
+static u32 kirkwood_variant(void)
+{
+ switch (readl(KW_REG_DEVICE_ID) & 0x03) {
+ case 1:
+ return MPP_F6192_MASK;
+ case 2:
+ return MPP_F6281_MASK;
+ default:
+ debug("MPP setup: unknown kirkwood variant\n");
+ return 0;
+ }
+}
+
+#define MPP_CTRL(i) (KW_MPP_BASE + (i* 4))
+#define MPP_NR_REGS (1 + MPP_MAX/8)
+
+void kirkwood_mpp_conf(u32 *mpp_list)
+{
+ u32 mpp_ctrl[MPP_NR_REGS];
+ unsigned int variant_mask;
+ int i;
+
+ variant_mask = kirkwood_variant();
+ if (!variant_mask)
+ return;
+
+ debug( "initial MPP regs:");
+ for (i = 0; i < MPP_NR_REGS; i++) {
+ mpp_ctrl[i] = readl(MPP_CTRL(i));
+ debug(" %08x", mpp_ctrl[i]);
+ }
+ debug("\n");
+
+
+ while (*mpp_list) {
+ unsigned int num = MPP_NUM(*mpp_list);
+ unsigned int sel = MPP_SEL(*mpp_list);
+ int shift;
+
+ if (num > MPP_MAX) {
+ debug("kirkwood_mpp_conf: invalid MPP "
+ "number (%u)\n", num);
+ continue;
+ }
+ if (!(*mpp_list & variant_mask)) {
+ debug("kirkwood_mpp_conf: requested MPP%u config "
+ "unavailable on this hardware\n", num);
+ continue;
+ }
+
+ shift = (num & 7) << 2;
+ mpp_ctrl[num / 8] &= ~(0xf << shift);
+ mpp_ctrl[num / 8] |= sel << shift;
+
+ mpp_list++;
+ }
+
+ debug(" final MPP regs:");
+ for (i = 0; i < MPP_NR_REGS; i++) {
+ writel(mpp_ctrl[i], MPP_CTRL(i));
+ debug(" %08x", mpp_ctrl[i]);
+ }
+ debug("\n");
+
+}
diff --git a/cpu/arm926ejs/kirkwood/timer.c b/cpu/arm926ejs/kirkwood/timer.c
new file mode 100644
index 0000000..817ff42
--- /dev/null
+++ b/cpu/arm926ejs/kirkwood/timer.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <asm/arch/kirkwood.h>
+
+#define UBOOT_CNTR 0 /* counter to use for uboot timer */
+
+/* Timer reload and current value registers */
+struct kwtmr_val {
+ u32 reload; /* Timer reload reg */
+ u32 val; /* Timer value reg */
+};
+
+/* Timer registers */
+struct kwtmr_registers {
+ u32 ctrl; /* Timer control reg */
+ u32 pad[3];
+ struct kwtmr_val tmr[2];
+ u32 wdt_reload;
+ u32 wdt_val;
+};
+
+struct kwtmr_registers *kwtmr_regs = (struct kwtmr_registers *)KW_TIMER_BASE;
+
+/*
+ * ARM Timers Registers Map
+ */
+#define CNTMR_CTRL_REG &kwtmr_regs->ctrl
+#define CNTMR_RELOAD_REG(tmrnum) &kwtmr_regs->tmr[tmrnum].reload
+#define CNTMR_VAL_REG(tmrnum) &kwtmr_regs->tmr[tmrnum].val
+
+/*
+ * ARM Timers Control Register
+ * CPU_TIMERS_CTRL_REG (CTCR)
+ */
+#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2)
+#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS)
+#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr))
+#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr))
+
+#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1)
+#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1)
+#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr))
+#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr))
+
+/*
+ * ARM Timer\Watchdog Reload Register
+ * CNTMR_RELOAD_REG (TRR)
+ */
+#define TRG_ARM_TIMER_REL_OFFS 0
+#define TRG_ARM_TIMER_REL_MASK 0xffffffff
+
+/*
+ * ARM Timer\Watchdog Register
+ * CNTMR_VAL_REG (TVRG)
+ */
+#define TVR_ARM_TIMER_OFFS 0
+#define TVR_ARM_TIMER_MASK 0xffffffff
+#define TVR_ARM_TIMER_MAX 0xffffffff
+#define TIMER_LOAD_VAL 0xffffffff
+
+#define READ_TIMER (readl(CNTMR_VAL_REG(UBOOT_CNTR)) / \
+ (CONFIG_SYS_TCLK / 1000))
+
+static ulong timestamp;
+static ulong lastdec;
+
+void reset_timer_masked(void)
+{
+ /* reset time */
+ lastdec = READ_TIMER;
+ timestamp = 0;
+}
+
+ulong get_timer_masked(void)
+{
+ ulong now = READ_TIMER;
+
+ if (lastdec >= now) {
+ /* normal mode */
+ timestamp += lastdec - now;
+ } else {
+ /* we have an overflow ... */
+ timestamp += lastdec +
+ (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now;
+ }
+ lastdec = now;
+
+ return timestamp;
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+ return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+ timestamp = t;
+}
+
+void udelay(unsigned long usec)
+{
+ uint current;
+ ulong delayticks;
+
+ current = readl(CNTMR_VAL_REG(UBOOT_CNTR));
+ delayticks = (usec * (CONFIG_SYS_TCLK / 1000000));
+
+ if (current < delayticks) {
+ delayticks -= current;
+ while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) < current) ;
+ while ((TIMER_LOAD_VAL - delayticks) <
+ readl(CNTMR_VAL_REG(UBOOT_CNTR))) ;
+ } else {
+ while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) >
+ (current - delayticks)) ;
+ }
+}
+
+/*
+ * init the counter
+ */
+int timer_init(void)
+{
+ unsigned int cntmrctrl;
+
+ /* load value into timer */
+ writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR));
+ writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR));
+
+ /* enable timer in auto reload mode */
+ cntmrctrl = readl(CNTMR_CTRL_REG);
+ cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR);
+ cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR);
+ writel(cntmrctrl, CNTMR_CTRL_REG);
+
+ /* init the timestamp and lastdec value */
+ reset_timer_masked();
+
+ return 0;
+}
diff --git a/cpu/arm926ejs/mx27/Makefile b/cpu/arm926ejs/mx27/Makefile
new file mode 100644
index 0000000..67d1b0e
--- /dev/null
+++ b/cpu/arm926ejs/mx27/Makefile
@@ -0,0 +1,44 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# 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 = generic.o reset.o timer.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/arm926ejs/mx27/generic.c b/cpu/arm926ejs/mx27/generic.c
new file mode 100644
index 0000000..eab54d8
--- /dev/null
+++ b/cpu/arm926ejs/mx27/generic.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org>
+ * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com>
+ *
+ * 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 <div64.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/*
+ * get the system pll clock in Hz
+ *
+ * mfi + mfn / (mfd +1)
+ * f = 2 * f_ref * --------------------
+ * pd + 1
+ */
+unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref)
+{
+ unsigned int mfi = (pll >> 10) & 0xf;
+ unsigned int mfn = pll & 0x3ff;
+ unsigned int mfd = (pll >> 16) & 0x3ff;
+ unsigned int pd = (pll >> 26) & 0xf;
+
+ mfi = mfi <= 5 ? 5 : mfi;
+
+ return lldiv(2 * (u64)f_ref * (mfi * (mfd + 1) + mfn),
+ (mfd + 1) * (pd + 1));
+}
+
+static ulong clk_in_32k(void)
+{
+ return 1024 * CONFIG_MX27_CLK32;
+}
+
+static ulong clk_in_26m(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+
+ if (readl(&pll->cscr) & CSCR_OSC26M_DIV1P5) {
+ /* divide by 1.5 */
+ return 26000000 * 2 / 3;
+ } else {
+ return 26000000;
+ }
+}
+
+ulong imx_get_mpllclk(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+ ulong cscr = readl(&pll->cscr);
+ ulong fref;
+
+ if (cscr & CSCR_MCU_SEL)
+ fref = clk_in_26m();
+ else
+ fref = clk_in_32k();
+
+ return imx_decode_pll(readl(&pll->mpctl0), fref);
+}
+
+ulong imx_get_armclk(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+ ulong cscr = readl(&pll->cscr);
+ ulong fref = imx_get_mpllclk();
+ ulong div;
+
+ if (!(cscr & CSCR_ARM_SRC_MPLL))
+ fref = lldiv((fref * 2), 3);
+
+ div = ((cscr >> 12) & 0x3) + 1;
+
+ return lldiv(fref, div);
+}
+
+ulong imx_get_ahbclk(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+ ulong cscr = readl(&pll->cscr);
+ ulong fref = imx_get_mpllclk();
+ ulong div;
+
+ div = ((cscr >> 8) & 0x3) + 1;
+
+ return lldiv(fref * 2, 3 * div);
+}
+
+ulong imx_get_spllclk(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+ ulong cscr = readl(&pll->cscr);
+ ulong fref;
+
+ if (cscr & CSCR_SP_SEL)
+ fref = clk_in_26m();
+ else
+ fref = clk_in_32k();
+
+ return imx_decode_pll(readl(&pll->spctl0), fref);
+}
+
+static ulong imx_decode_perclk(ulong div)
+{
+ return lldiv((imx_get_mpllclk() * 2), (div * 3));
+}
+
+ulong imx_get_perclk1(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+
+ return imx_decode_perclk((readl(&pll->pcdr1) & 0x3f) + 1);
+}
+
+ulong imx_get_perclk2(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+
+ return imx_decode_perclk(((readl(&pll->pcdr1) >> 8) & 0x3f) + 1);
+}
+
+ulong imx_get_perclk3(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+
+ return imx_decode_perclk(((readl(&pll->pcdr1) >> 16) & 0x3f) + 1);
+}
+
+ulong imx_get_perclk4(void)
+{
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+
+ return imx_decode_perclk(((readl(&pll->pcdr1) >> 24) & 0x3f) + 1);
+}
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+int print_cpuinfo (void)
+{
+ char buf[32];
+
+ printf("CPU: Freescale i.MX27 at %s MHz\n\n",
+ strmhz(buf, imx_get_mpllclk()));
+ return 0;
+}
+#endif
+
+void imx_gpio_mode(int gpio_mode)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;
+ unsigned int pin = gpio_mode & GPIO_PIN_MASK;
+ unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+ unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT;
+ unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT;
+ unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT;
+ unsigned int tmp;
+
+ /* Pullup enable */
+ if (gpio_mode & GPIO_PUEN) {
+ writel(readl(&regs->port[port].puen) | (1 << pin),
+ &regs->port[port].puen);
+ } else {
+ writel(readl(&regs->port[port].puen) & ~(1 << pin),
+ &regs->port[port].puen);
+ }
+
+ /* Data direction */
+ if (gpio_mode & GPIO_OUT) {
+ writel(readl(&regs->port[port].ddir) | 1 << pin,
+ &regs->port[port].ddir);
+ } else {
+ writel(readl(&regs->port[port].ddir) & ~(1 << pin),
+ &regs->port[port].ddir);
+ }
+
+ /* Primary / alternate function */
+ if (gpio_mode & GPIO_AF) {
+ writel(readl(&regs->port[port].gpr) | (1 << pin),
+ &regs->port[port].gpr);
+ } else {
+ writel(readl(&regs->port[port].gpr) & ~(1 << pin),
+ &regs->port[port].gpr);
+ }
+
+ /* use as gpio? */
+ if (!(gpio_mode & (GPIO_PF | GPIO_AF))) {
+ writel(readl(&regs->port[port].gius) | (1 << pin),
+ &regs->port[port].gius);
+ } else {
+ writel(readl(&regs->port[port].gius) & ~(1 << pin),
+ &regs->port[port].gius);
+ }
+
+ /* Output / input configuration */
+ if (pin < 16) {
+ tmp = readl(&regs->port[port].ocr1);
+ tmp &= ~(3 << (pin * 2));
+ tmp |= (ocr << (pin * 2));
+ writel(tmp, &regs->port[port].ocr1);
+
+ writel(readl(&regs->port[port].iconfa1) & ~(3 << (pin * 2)),
+ &regs->port[port].iconfa1);
+ writel(readl(&regs->port[port].iconfa1) | aout << (pin * 2),
+ &regs->port[port].iconfa1);
+ writel(readl(&regs->port[port].iconfb1) & ~(3 << (pin * 2)),
+ &regs->port[port].iconfb1);
+ writel(readl(&regs->port[port].iconfb1) | bout << (pin * 2),
+ &regs->port[port].iconfb1);
+ } else {
+ pin -= 16;
+
+ tmp = readl(&regs->port[port].ocr2);
+ tmp &= ~(3 << (pin * 2));
+ tmp |= (ocr << (pin * 2));
+ writel(tmp, &regs->port[port].ocr2);
+
+ writel(readl(&regs->port[port].iconfa2) & ~(3 << (pin * 2)),
+ &regs->port[port].iconfa2);
+ writel(readl(&regs->port[port].iconfa2) | aout << (pin * 2),
+ &regs->port[port].iconfa2);
+ writel(readl(&regs->port[port].iconfb2) & ~(3 << (pin * 2)),
+ &regs->port[port].iconfb2);
+ writel(readl(&regs->port[port].iconfb2) | bout << (pin * 2),
+ &regs->port[port].iconfb2);
+ }
+}
+
diff --git a/cpu/arm926ejs/mx27/reset.c b/cpu/arm926ejs/mx27/reset.c
new file mode 100644
index 0000000..6c54eaf
--- /dev/null
+++ b/cpu/arm926ejs/mx27/reset.c
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * (C) Copyright 2009
+ * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
+ *
+ * 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 <common.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/*
+ * Reset the cpu by setting up the watchdog timer and let it time out
+ */
+void reset_cpu (ulong ignored)
+{
+ struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE;
+ /* Disable watchdog and set Time-Out field to 0 */
+ writel(0x00000000, &regs->wcr);
+
+ /* Write Service Sequence */
+ writel(0x00005555, &regs->wsr);
+ writel(0x0000AAAA, &regs->wsr);
+
+ /* Enable watchdog */
+ writel(WCR_WDE, &regs->wcr);
+
+ while (1);
+ /*NOTREACHED*/
+}
diff --git a/cpu/arm926ejs/mx27/timer.c b/cpu/arm926ejs/mx27/timer.c
new file mode 100644
index 0000000..d22252e
--- /dev/null
+++ b/cpu/arm926ejs/mx27/timer.c
@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * (C) Copyright 2009
+ * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
+ *
+ * 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 <common.h>
+#include <div64.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/* General purpose timers bitfields */
+#define GPTCR_SWR (1 << 15) /* Software reset */
+#define GPTCR_FRR (1 << 8) /* Freerun / restart */
+#define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */
+#define GPTCR_TEN 1 /* Timer enable */
+
+static ulong timestamp;
+static ulong lastinc;
+
+/*
+ * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
+ * "tick" is internal timer period
+ */
+#ifdef CONFIG_MX27_TIMER_HIGH_PRECISION
+/* ~0.4% error - measured with stop-watch on 100s boot-delay */
+static inline unsigned long long tick_to_time(unsigned long long tick)
+{
+ tick *= CONFIG_SYS_HZ;
+ do_div(tick, CONFIG_MX27_CLK32);
+ return tick;
+}
+
+static inline unsigned long long time_to_tick(unsigned long long time)
+{
+ time *= CONFIG_MX27_CLK32;
+ do_div(time, CONFIG_SYS_HZ);
+ return time;
+}
+
+static inline unsigned long long us_to_tick(unsigned long long us)
+{
+ us = us * CONFIG_MX27_CLK32 + 999999;
+ do_div(us, 1000000);
+ return us;
+}
+#else
+/* ~2% error */
+#define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \
+ CONFIG_SYS_HZ)
+#define US_PER_TICK (1000000 / CONFIG_MX27_CLK32)
+
+static inline unsigned long long tick_to_time(unsigned long long tick)
+{
+ do_div(tick, TICK_PER_TIME);
+ return tick;
+}
+
+static inline unsigned long long time_to_tick(unsigned long long time)
+{
+ return time * TICK_PER_TIME;
+}
+
+static inline unsigned long long us_to_tick(unsigned long long us)
+{
+ us += US_PER_TICK - 1;
+ do_div(us, US_PER_TICK);
+ return us;
+}
+#endif
+
+/* nothing really to do with interrupts, just starts up a counter. */
+/* The 32768Hz 32-bit timer overruns in 131072 seconds */
+int timer_init(void)
+{
+ int i;
+ struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
+ struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+
+ /* setup GP Timer 1 */
+ writel(GPTCR_SWR, &regs->gpt_tctl);
+
+ writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0);
+ writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1);
+
+ for (i = 0; i < 100; i++)
+ writel(0, &regs->gpt_tctl); /* We have no udelay by now */
+ writel(0, &regs->gpt_tprer); /* 32Khz */
+ /* Freerun Mode, PERCLK1 input */
+ writel(readl(&regs->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
+ &regs->gpt_tctl);
+ writel(readl(&regs->gpt_tctl) | GPTCR_TEN, &regs->gpt_tctl);
+
+ return 0;
+}
+
+void reset_timer_masked(void)
+{
+ struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
+ /* reset time */
+ /* capture current incrementer value time */
+ lastinc = readl(&regs->gpt_tcn);
+ timestamp = 0; /* start "advancing" time stamp from 0 */
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+unsigned long long get_ticks (void)
+{
+ struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
+ ulong now = readl(&regs->gpt_tcn); /* current tick value */
+
+ if (now >= lastinc) {
+ /*
+ * normal mode (non roll)
+ * move stamp forward with absolut diff ticks
+ */
+ timestamp += (now - lastinc);
+ } else {
+ /* we have rollover of incrementer */
+ timestamp += (0xFFFFFFFF - lastinc) + now;
+ }
+ lastinc = now;
+ return timestamp;
+}
+
+ulong get_timer_masked (void)
+{
+ /*
+ * get_ticks() returns a long long (64 bit), it wraps in
+ * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
+ * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
+ * 5 * 10^6 days - long enough.
+ */
+ return tick_to_time(get_ticks());
+}
+
+ulong get_timer (ulong base)
+{
+ return get_timer_masked () - base;
+}
+
+void set_timer (ulong t)
+{
+ timestamp = time_to_tick(t);
+}
+
+/* delay x useconds AND perserve advance timstamp value */
+void udelay (unsigned long usec)
+{
+ unsigned long long tmp;
+ ulong tmo;
+
+ tmo = us_to_tick(usec);
+ tmp = get_ticks() + tmo; /* get current timestamp */
+
+ while (get_ticks() < tmp) /* loop till event */
+ /*NOP*/;
+}
+
diff --git a/cpu/arm926ejs/nomadik/reset.S b/cpu/arm926ejs/nomadik/reset.S
index 948996b..ec95472 100644
--- a/cpu/arm926ejs/nomadik/reset.S
+++ b/cpu/arm926ejs/nomadik/reset.S
@@ -6,20 +6,9 @@
.align 5
.globl reset_cpu
reset_cpu:
-#if defined CONFIG_NOMADIK_8815
- ldr r0, =NOMADIK_SRC_BASE
+ ldr r0, =NOMADIK_SRC_BASE /* System and Reset Controller */
ldr r1, =0x1
str r1, [r0, #0x18]
-#else
- ldr r1, rstctl1 /* get clkm1 reset ctl */
- mov r3, #0x0
- strh r3, [r1] /* clear it */
- mov r3, #0x8
- strh r3, [r1] /* force dsp+arm reset */
-#endif
_loop_forever:
b _loop_forever
-
-rstctl1:
- .word 0xfffece10
diff --git a/cpu/arm926ejs/nomadik/timer.c b/cpu/arm926ejs/nomadik/timer.c
index 2870d24..16067c9 100644
--- a/cpu/arm926ejs/nomadik/timer.c
+++ b/cpu/arm926ejs/nomadik/timer.c
@@ -1,20 +1,5 @@
/*
- * (C) Copyright 2003
- * Texas Instruments <www.ti.com>
- *
- * (C) Copyright 2002
- * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
- * Marius Groeger <mgroeger@sysgo.de>
- *
- * (C) Copyright 2002
- * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
- * Alex Zuepke <azu@sysgo.de>
- *
- * (C) Copyright 2002-2004
- * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
- *
- * (C) Copyright 2004
- * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
+ * (C) Copyright 2009 Alessandro Rubini
*
* See file CREDITS for list of people who contributed to this
* project.
@@ -37,146 +22,49 @@
#include <common.h>
#include <asm/io.h>
+#include <asm/arch/mtu.h>
-#define TIMER_LOAD_VAL 0xffffffff
-
-/* macro to read the 32 bit timer */
-#define READ_TIMER readl(CONFIG_SYS_TIMERBASE + 20)
+/*
+ * The timer is a decrementer, we'll left it free running at 2.4MHz.
+ * We have 2.4 ticks per microsecond and an overflow in almost 30min
+ */
+#define TIMER_CLOCK (24 * 100 * 1000)
+#define COUNT_TO_USEC(x) ((x) * 5 / 12) /* overflows at 6min */
+#define USEC_TO_COUNT(x) ((x) * 12 / 5) /* overflows at 6min */
+#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ)
+#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ)
-static ulong timestamp;
-static ulong lastdec;
+/* macro to read the 32 bit timer: since it decrements, we invert read value */
+#define READ_TIMER() (~readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0)))
-/* nothing really to do with interrupts, just starts up a counter. */
+/* Configure a free-running, auto-wrap counter with no prescaler */
int timer_init(void)
{
- /* Load timer with initial value */
- writel(TIMER_LOAD_VAL, CONFIG_SYS_TIMERBASE + 16);
-
- /*
- * Set timer to be enabled, free-running, no interrupts, 256 divider,
- * 32-bit, wrap-mode
- */
- writel(0x8a, CONFIG_SYS_TIMERBASE + 24);
-
- /* init the timestamp and lastdec value */
- reset_timer_masked();
-
+ writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS,
+ CONFIG_SYS_TIMERBASE + MTU_CR(0));
+ reset_timer();
return 0;
}
-/*
- * timer without interrupts
- */
+/* Restart counting from 0 */
void reset_timer(void)
{
- reset_timer_masked();
+ writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0)); /* Immediate effect */
}
+/* Return how many HZ passed since "base" */
ulong get_timer(ulong base)
{
- return get_timer_masked() - base;
+ return TICKS_TO_HZ(READ_TIMER()) - base;
}
-void set_timer(ulong t)
-{
- timestamp = t;
-}
-
-/* delay x useconds AND perserve advance timstamp value */
+/* Delay x useconds */
void udelay(unsigned long usec)
{
- ulong tmo, tmp;
-
- if (usec >= 1000) {
- /* if "big" number, spread normalization to seconds */
- tmo = usec / 1000; /* start to normalize */
- tmo *= CONFIG_SYS_HZ; /* find number of "ticks" */
- tmo /= 1000; /* finish normalize. */
- } else {
- /* small number, don't kill it prior to HZ multiply */
- tmo = usec * CONFIG_SYS_HZ;
- tmo /= (1000 * 1000);
- }
-
- tmp = get_timer(0); /* get current timestamp */
- if ((tmo + tmp + 1) < tmp) /* will roll time stamp? */
- reset_timer_masked(); /* reset to 0, set lastdec value */
- else
- tmo += tmp;
-
- while (get_timer_masked() < tmo)
- /* nothing */ ;
-}
-
-void reset_timer_masked(void)
-{
- /* reset time */
- lastdec = READ_TIMER; /* capure current decrementer value time */
- timestamp = 0; /* start "advancing" time stamp from 0 */
-}
-
-ulong get_timer_masked(void)
-{
- ulong now = READ_TIMER; /* current tick value */
-
- if (lastdec >= now) { /* normal mode (non roll) */
- /* move stamp fordward */
- timestamp += lastdec - now;
- } else {
- /*
- * An overflow is expected.
- * nts = ts + ld + (TLV - now)
- * ts=old stamp, ld=time that passed before passing through -1
- * (TLV-now) amount of time after passing though -1
- * nts = new "advancing time stamp"...it could also roll
- */
- timestamp += lastdec + TIMER_LOAD_VAL - now;
- }
- lastdec = now;
-
- return timestamp;
-}
-
-/* waits specified delay value and resets timestamp */
-void udelay_masked(unsigned long usec)
-{
- ulong tmo;
-
- if (usec >= 1000) {
- /* if "big" number, spread normalization to seconds */
- tmo = usec / 1000; /* start to normalize */
- tmo *= CONFIG_SYS_HZ; /* find number of "ticks" */
- tmo /= 1000; /* finish normalize. */
- } else {
- /* else small number, don't kill it prior to HZ multiply */
- tmo = usec * CONFIG_SYS_HZ;
- tmo /= (1000*1000);
- }
-
- reset_timer_masked();
- /* set "advancing" timestamp to 0, set lastdec vaule */
-
- while (get_timer_masked() < tmo)
- /* nothing */ ;
-}
-
-/*
- * 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)
-{
- return get_timer(0);
-}
-
-/*
- * 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)
-{
- ulong tbclk;
+ ulong ini, end;
- tbclk = CONFIG_SYS_HZ;
- return tbclk;
+ ini = READ_TIMER();
+ end = ini + USEC_TO_COUNT(usec);
+ while ((signed)(end - READ_TIMER()) > 0)
+ ;
}