summaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'cpu')
-rw-r--r--cpu/at32ap/Makefile50
-rw-r--r--cpu/at32ap/at32ap7000/Makefile43
-rw-r--r--cpu/at32ap/at32ap7000/devices.c448
-rw-r--r--cpu/at32ap/at32ap7000/hebi.c38
-rw-r--r--cpu/at32ap/cache.c97
-rw-r--r--cpu/at32ap/config.mk22
-rw-r--r--cpu/at32ap/cpu.c83
-rw-r--r--cpu/at32ap/device.c126
-rw-r--r--cpu/at32ap/entry.S65
-rw-r--r--cpu/at32ap/exception.c119
-rw-r--r--cpu/at32ap/hsdramc.c155
-rw-r--r--cpu/at32ap/hsdramc1.h143
-rw-r--r--cpu/at32ap/hsmc3.h126
-rw-r--r--cpu/at32ap/interrupts.c154
-rw-r--r--cpu/at32ap/pio.c94
-rw-r--r--cpu/at32ap/pio2.h44
-rw-r--r--cpu/at32ap/pm.c163
-rw-r--r--cpu/at32ap/sm.h204
-rw-r--r--cpu/at32ap/start.S113
-rw-r--r--cpu/mpc85xx/Makefile2
-rw-r--r--cpu/mpc85xx/i2c.c265
-rw-r--r--cpu/mpc85xx/spd_sdram.c132
-rw-r--r--cpu/mpc86xx/Makefile51
-rw-r--r--cpu/mpc86xx/cache.S374
-rw-r--r--cpu/mpc86xx/config.mk26
-rw-r--r--cpu/mpc86xx/cpu.c308
-rw-r--r--cpu/mpc86xx/cpu_init.c117
-rw-r--r--cpu/mpc86xx/interrupts.c204
-rw-r--r--cpu/mpc86xx/pci.c146
-rw-r--r--cpu/mpc86xx/pcie_indirect.c199
-rw-r--r--cpu/mpc86xx/resetvec.S2
-rw-r--r--cpu/mpc86xx/spd_sdram.c1324
-rw-r--r--cpu/mpc86xx/speed.c127
-rw-r--r--cpu/mpc86xx/start.S1226
-rw-r--r--cpu/mpc86xx/traps.c226
35 files changed, 6681 insertions, 335 deletions
diff --git a/cpu/at32ap/Makefile b/cpu/at32ap/Makefile
new file mode 100644
index 0000000..8ce79e9
--- /dev/null
+++ b/cpu/at32ap/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright (C) 2005-2006 Atmel Corporation.
+#
+# 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
+SOBJS := entry.o
+COBJS := cpu.o hsdramc.o exception.o cache.o
+COBJS += interrupts.o device.o pm.o pio.o
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $^
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/at32ap/at32ap7000/Makefile b/cpu/at32ap/at32ap7000/Makefile
new file mode 100644
index 0000000..1cd9444
--- /dev/null
+++ b/cpu/at32ap/at32ap7000/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2005-2006 Atmel Corporation
+#
+# 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 := hebi.o devices.o
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $^
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/at32ap/at32ap7000/devices.c b/cpu/at32ap/at32ap7000/devices.c
new file mode 100644
index 0000000..8b216e9
--- /dev/null
+++ b/cpu/at32ap/at32ap7000/devices.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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/arch/memory-map.h>
+#include <asm/arch/platform.h>
+
+#include "../sm.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+const struct clock_domain chip_clock[] = {
+ [CLOCK_CPU] = {
+ .reg = SM_PM_CPU_MASK,
+ .id = CLOCK_CPU,
+ .bridge = NO_DEVICE,
+ },
+ [CLOCK_HSB] = {
+ .reg = SM_PM_HSB_MASK,
+ .id = CLOCK_HSB,
+ .bridge = NO_DEVICE,
+ },
+ [CLOCK_PBA] = {
+ .reg = SM_PM_PBA_MASK,
+ .id = CLOCK_PBA,
+ .bridge = DEVICE_PBA_BRIDGE,
+ },
+ [CLOCK_PBB] = {
+ .reg = SM_PM_PBB_MASK,
+ .id = CLOCK_PBB,
+ .bridge = DEVICE_PBB_BRIDGE,
+ },
+};
+
+static const struct resource hebi_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 0 },
+ },
+ }, {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 13 },
+ },
+ }, {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 14 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 27, DEVICE_PIOE, GPIO_FUNC_A, 0 },
+ },
+ },
+};
+static const struct resource pba_bridge_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 1 },
+ }
+ }, {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ /* HSB-HSB Bridge */
+ .clock = { CLOCK_HSB, 4 },
+ },
+ },
+};
+static const struct resource pbb_bridge_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 2 },
+ },
+ },
+};
+static const struct resource hramc_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 3 },
+ },
+ },
+};
+static const struct resource pioa_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 10 },
+ },
+ },
+};
+static const struct resource piob_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 11 },
+ },
+ },
+};
+static const struct resource pioc_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 12 },
+ },
+ },
+};
+static const struct resource piod_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 13 },
+ },
+ },
+};
+static const struct resource pioe_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 14 },
+ },
+ },
+};
+static const struct resource sm_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 0 },
+ },
+ },
+};
+static const struct resource intc_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 1 },
+ },
+ },
+};
+static const struct resource hmatrix_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 2 },
+ },
+ },
+};
+#if defined(CFG_HPDC)
+static const struct resource hpdc_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 16 },
+ },
+ },
+};
+#endif
+#if defined(CFG_MACB0)
+static const struct resource macb0_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 8 },
+ },
+ }, {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 6 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 19, DEVICE_PIOC, GPIO_FUNC_A, 0 },
+ },
+ },
+};
+#endif
+#if defined(CFG_MACB1)
+static const struct resource macb1_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 9 },
+ },
+ }, {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 7 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 12, DEVICE_PIOC, GPIO_FUNC_B, 19 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 14, DEVICE_PIOD, GPIO_FUNC_B, 2 },
+ },
+ },
+};
+#endif
+#if defined(CFG_LCDC)
+static const struct resource lcdc_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 7 },
+ },
+ },
+};
+#endif
+#if defined(CFG_USART0)
+static const struct resource usart0_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 3 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 2, DEVICE_PIOA, GPIO_FUNC_B, 8 },
+ },
+ },
+};
+#endif
+#if defined(CFG_USART1)
+static const struct resource usart1_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 4 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 2, DEVICE_PIOA, GPIO_FUNC_A, 17 },
+ },
+ },
+};
+#endif
+#if defined(CFG_USART2)
+static const struct resource usart2_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 5 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 2, DEVICE_PIOB, GPIO_FUNC_B, 26 },
+ },
+ },
+};
+#endif
+#if defined(CFG_USART3)
+static const struct resource usart3_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBA, 6 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 2, DEVICE_PIOB, GPIO_FUNC_B, 17 },
+ },
+ },
+};
+#endif
+#if defined(CFG_MMCI)
+static const struct resource mmci_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_PBB, 9 },
+ },
+ }, {
+ .type = RESOURCE_GPIO,
+ .u = {
+ .gpio = { 6, DEVICE_PIOA, GPIO_FUNC_A, 10 },
+ },
+ },
+};
+#endif
+#if defined(CFG_DMAC)
+static const struct resource dmac_resource[] = {
+ {
+ .type = RESOURCE_CLOCK,
+ .u = {
+ .clock = { CLOCK_HSB, 10 },
+ },
+ },
+};
+#endif
+
+const struct device chip_device[] = {
+ [DEVICE_HEBI] = {
+ .regs = (void *)HSMC_BASE,
+ .nr_resources = ARRAY_SIZE(hebi_resource),
+ .resource = hebi_resource,
+ },
+ [DEVICE_PBA_BRIDGE] = {
+ .nr_resources = ARRAY_SIZE(pba_bridge_resource),
+ .resource = pba_bridge_resource,
+ },
+ [DEVICE_PBB_BRIDGE] = {
+ .nr_resources = ARRAY_SIZE(pbb_bridge_resource),
+ .resource = pbb_bridge_resource,
+ },
+ [DEVICE_HRAMC] = {
+ .nr_resources = ARRAY_SIZE(hramc_resource),
+ .resource = hramc_resource,
+ },
+ [DEVICE_PIOA] = {
+ .regs = (void *)PIOA_BASE,
+ .nr_resources = ARRAY_SIZE(pioa_resource),
+ .resource = pioa_resource,
+ },
+ [DEVICE_PIOB] = {
+ .regs = (void *)PIOB_BASE,
+ .nr_resources = ARRAY_SIZE(piob_resource),
+ .resource = piob_resource,
+ },
+ [DEVICE_PIOC] = {
+ .regs = (void *)PIOC_BASE,
+ .nr_resources = ARRAY_SIZE(pioc_resource),
+ .resource = pioc_resource,
+ },
+ [DEVICE_PIOD] = {
+ .regs = (void *)PIOD_BASE,
+ .nr_resources = ARRAY_SIZE(piod_resource),
+ .resource = piod_resource,
+ },
+ [DEVICE_PIOE] = {
+ .regs = (void *)PIOE_BASE,
+ .nr_resources = ARRAY_SIZE(pioe_resource),
+ .resource = pioe_resource,
+ },
+ [DEVICE_SM] = {
+ .regs = (void *)SM_BASE,
+ .nr_resources = ARRAY_SIZE(sm_resource),
+ .resource = sm_resource,
+ },
+ [DEVICE_INTC] = {
+ .regs = (void *)INTC_BASE,
+ .nr_resources = ARRAY_SIZE(intc_resource),
+ .resource = intc_resource,
+ },
+ [DEVICE_HMATRIX] = {
+ .regs = (void *)HMATRIX_BASE,
+ .nr_resources = ARRAY_SIZE(hmatrix_resource),
+ .resource = hmatrix_resource,
+ },
+#if defined(CFG_HPDC)
+ [DEVICE_HPDC] = {
+ .nr_resources = ARRAY_SIZE(hpdc_resource),
+ .resource = hpdc_resource,
+ },
+#endif
+#if defined(CFG_MACB0)
+ [DEVICE_MACB0] = {
+ .regs = (void *)MACB0_BASE,
+ .nr_resources = ARRAY_SIZE(macb0_resource),
+ .resource = macb0_resource,
+ },
+#endif
+#if defined(CFG_MACB1)
+ [DEVICE_MACB1] = {
+ .regs = (void *)MACB1_BASE,
+ .nr_resources = ARRAY_SIZE(macb1_resource),
+ .resource = macb1_resource,
+ },
+#endif
+#if defined(CFG_LCDC)
+ [DEVICE_LCDC] = {
+ .nr_resources = ARRAY_SIZE(lcdc_resource),
+ .resource = lcdc_resource,
+ },
+#endif
+#if defined(CFG_USART0)
+ [DEVICE_USART0] = {
+ .regs = (void *)USART0_BASE,
+ .nr_resources = ARRAY_SIZE(usart0_resource),
+ .resource = usart0_resource,
+ },
+#endif
+#if defined(CFG_USART1)
+ [DEVICE_USART1] = {
+ .regs = (void *)USART1_BASE,
+ .nr_resources = ARRAY_SIZE(usart1_resource),
+ .resource = usart1_resource,
+ },
+#endif
+#if defined(CFG_USART2)
+ [DEVICE_USART2] = {
+ .regs = (void *)USART2_BASE,
+ .nr_resources = ARRAY_SIZE(usart2_resource),
+ .resource = usart2_resource,
+ },
+#endif
+#if defined(CFG_USART3)
+ [DEVICE_USART3] = {
+ .regs = (void *)USART3_BASE,
+ .nr_resources = ARRAY_SIZE(usart3_resource),
+ .resource = usart3_resource,
+ },
+#endif
+#if defined(CFG_MMCI)
+ [DEVICE_MMCI] = {
+ .regs = (void *)MMCI_BASE,
+ .nr_resources = ARRAY_SIZE(mmci_resource),
+ .resource = mmci_resource,
+ },
+#endif
+#if defined(CFG_DMAC)
+ [DEVICE_DMAC] = {
+ .regs = (void *)DMAC_BASE,
+ .nr_resources = ARRAY_SIZE(dmac_resource),
+ .resource = dmac_resource,
+ },
+#endif
+};
diff --git a/cpu/at32ap/at32ap7000/hebi.c b/cpu/at32ap/at32ap7000/hebi.c
new file mode 100644
index 0000000..3b32adf
--- /dev/null
+++ b/cpu/at32ap/at32ap7000/hebi.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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/hmatrix2.h>
+#include <asm/arch/memory-map.h>
+#include <asm/arch/platform.h>
+
+void cpu_enable_sdram(void)
+{
+ const struct device *hmatrix;
+
+ hmatrix = get_device(DEVICE_HMATRIX);
+
+ /* Set the SDRAM_ENABLE bit in the HEBI SFR */
+ hmatrix2_writel(hmatrix, SFR4, 1 << 1);
+}
diff --git a/cpu/at32ap/cache.c b/cpu/at32ap/cache.c
new file mode 100644
index 0000000..41fb5aa
--- /dev/null
+++ b/cpu/at32ap/cache.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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/cacheflush.h>
+
+void dcache_clean_range(volatile void *start, size_t size)
+{
+ unsigned long v, begin, end, linesz;
+
+ linesz = CFG_DCACHE_LINESZ;
+
+ /* You asked for it, you got it */
+ begin = (unsigned long)start & ~(linesz - 1);
+ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
+
+ for (v = begin; v < end; v += linesz)
+ dcache_clean_line((void *)v);
+
+ sync_write_buffer();
+}
+
+void dcache_invalidate_range(volatile void *start, size_t size)
+{
+ unsigned long v, begin, end, linesz;
+
+ linesz = CFG_DCACHE_LINESZ;
+
+ /* You asked for it, you got it */
+ begin = (unsigned long)start & ~(linesz - 1);
+ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
+
+ for (v = begin; v < end; v += linesz)
+ dcache_invalidate_line((void *)v);
+}
+
+void dcache_flush_range(volatile void *start, size_t size)
+{
+ unsigned long v, begin, end, linesz;
+
+ linesz = CFG_DCACHE_LINESZ;
+
+ /* You asked for it, you got it */
+ begin = (unsigned long)start & ~(linesz - 1);
+ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
+
+ for (v = begin; v < end; v += linesz)
+ dcache_flush_line((void *)v);
+
+ sync_write_buffer();
+}
+
+void icache_invalidate_range(volatile void *start, size_t size)
+{
+ unsigned long v, begin, end, linesz;
+
+ linesz = CFG_ICACHE_LINESZ;
+
+ /* You asked for it, you got it */
+ begin = (unsigned long)start & ~(linesz - 1);
+ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
+
+ for (v = begin; v < end; v += linesz)
+ icache_invalidate_line((void *)v);
+}
+
+/*
+ * This is called after loading something into memory. We need to
+ * make sure that everything that was loaded is actually written to
+ * RAM, and that the icache will look for it. Cleaning the dcache and
+ * invalidating the icache will do the trick.
+ */
+void flush_cache (unsigned long start_addr, unsigned long size)
+{
+ dcache_clean_range((void *)start_addr, size);
+ icache_invalidate_range((void *)start_addr, size);
+}
diff --git a/cpu/at32ap/config.mk b/cpu/at32ap/config.mk
new file mode 100644
index 0000000..1c12169
--- /dev/null
+++ b/cpu/at32ap/config.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2005-2006 Atmel Corporation
+#
+# 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 += -mcpu=ap7000
diff --git a/cpu/at32ap/cpu.c b/cpu/at32ap/cpu.c
new file mode 100644
index 0000000..37e3ea0
--- /dev/null
+++ b/cpu/at32ap/cpu.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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 <command.h>
+
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <asm/sysreg.h>
+
+#include <asm/arch/memory-map.h>
+#include <asm/arch/platform.h>
+
+#include "hsmc3.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cpu_init(void)
+{
+ const struct device *hebi;
+ extern void _evba(void);
+ char *p;
+
+ gd->cpu_hz = CFG_OSC0_HZ;
+
+ /* fff03400: 00010001 04030402 00050005 10011103 */
+ hebi = get_device(DEVICE_HEBI);
+ hsmc3_writel(hebi, MODE0, 0x00031103);
+ hsmc3_writel(hebi, CYCLE0, 0x000c000d);
+ hsmc3_writel(hebi, PULSE0, 0x0b0a0906);
+ hsmc3_writel(hebi, SETUP0, 0x00010002);
+
+ pm_init();
+
+ sysreg_write(EVBA, (unsigned long)&_evba);
+ asm volatile("csrf %0" : : "i"(SYSREG_EM_OFFSET));
+ gd->console_uart = get_device(CFG_CONSOLE_UART_DEV);
+
+ /* Lock everything that mess with the flash in the icache */
+ for (p = __flashprog_start; p <= (__flashprog_end + CFG_ICACHE_LINESZ);
+ p += CFG_ICACHE_LINESZ)
+ asm volatile("cache %0, 0x02" : "=m"(*p) :: "memory");
+
+ return 0;
+}
+
+void prepare_to_boot(void)
+{
+ /* Flush both caches and the write buffer */
+ asm volatile("cache %0[4], 010\n\t"
+ "cache %0[0], 000\n\t"
+ "sync 0" : : "r"(0) : "memory");
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ /* This will reset the CPU core, caches, MMU and all internal busses */
+ __builtin_mtdr(8, 1 << 13); /* set DC:DBE */
+ __builtin_mtdr(8, 1 << 30); /* set DC:RES */
+
+ /* Flush the pipeline before we declare it a failure */
+ asm volatile("sub pc, pc, -4");
+
+ return -1;
+}
diff --git a/cpu/at32ap/device.c b/cpu/at32ap/device.c
new file mode 100644
index 0000000..89914b6
--- /dev/null
+++ b/cpu/at32ap/device.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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/arch/platform.h>
+
+#include "sm.h"
+
+struct device_state {
+ int refcount;
+};
+
+static struct device_state device_state[NR_DEVICES];
+
+static int claim_resource(const struct resource *res)
+{
+ int ret = 0;
+
+ switch (res->type) {
+ case RESOURCE_GPIO:
+ ret = gpio_set_func(res->u.gpio.gpio_dev,
+ res->u.gpio.start,
+ res->u.gpio.nr_pins,
+ res->u.gpio.func);
+ break;
+ case RESOURCE_CLOCK:
+ ret = pm_enable_clock(res->u.clock.id, res->u.clock.index);
+ break;
+ }
+
+ return ret;
+}
+
+static void free_resource(const struct resource *res)
+{
+ switch (res->type) {
+ case RESOURCE_GPIO:
+ gpio_free(res->u.gpio.gpio_dev, res->u.gpio.start,
+ res->u.gpio.nr_pins);
+ break;
+ case RESOURCE_CLOCK:
+ pm_disable_clock(res->u.clock.id, res->u.clock.index);
+ break;
+ }
+}
+
+static int init_dev(const struct device *dev)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < dev->nr_resources; i++) {
+ ret = claim_resource(&dev->resource[i]);
+ if (ret)
+ goto cleanup;
+ }
+
+ return 0;
+
+cleanup:
+ while (i--)
+ free_resource(&dev->resource[i]);
+
+ return ret;
+}
+
+const struct device *get_device(enum device_id devid)
+{
+ struct device_state *devstate;
+ const struct device *dev;
+ unsigned long flags;
+ int initialized = 0;
+ int ret = 0;
+
+ devstate = &device_state[devid];
+ dev = &chip_device[devid];
+
+ flags = disable_interrupts();
+ if (devstate->refcount++)
+ initialized = 1;
+ if (flags)
+ enable_interrupts();
+
+ if (!initialized)
+ ret = init_dev(dev);
+
+ return ret ? NULL : dev;
+}
+
+void put_device(const struct device *dev)
+{
+ struct device_state *devstate;
+ unsigned long devid, flags;
+
+ devid = (unsigned long)(dev - chip_device) / sizeof(struct device);
+ devstate = &device_state[devid];
+
+ flags = disable_interrupts();
+ devstate--;
+ if (!devstate) {
+ unsigned int i;
+ for (i = 0; i < dev->nr_resources; i++)
+ free_resource(&dev->resource[i]);
+ }
+ if (flags)
+ enable_interrupts();
+}
diff --git a/cpu/at32ap/entry.S b/cpu/at32ap/entry.S
new file mode 100644
index 0000000..b52d798
--- /dev/null
+++ b/cpu/at32ap/entry.S
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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 <asm/sysreg.h>
+#include <asm/ptrace.h>
+
+ .section .text.exception,"ax"
+ .global _evba
+ .type _evba,@function
+ .align 10
+_evba:
+ .irp x,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
+ .align 2
+ rjmp unknown_exception
+ .endr
+
+ .global timer_interrupt_handler
+ .type timer_interrupt_handler,@function
+ .align 2
+timer_interrupt_handler:
+ /*
+ * Increment timer_overflow and re-write COMPARE with 0xffffffff.
+ *
+ * We're running at interrupt level 3, so we don't need to save
+ * r8-r12 or lr to the stack.
+ */
+ mov r8, lo(timer_overflow)
+ orh r8, hi(timer_overflow)
+ ld.w r9, r8[0]
+ mov r10, -1
+ mtsr SYSREG_COMPARE, r10
+ sub r9, -1
+ st.w r8[0], r9
+ rete
+
+ .type unknown_exception, @function
+unknown_exception:
+ pushm r0-r12
+ sub r8, sp, REG_R12 - REG_R0 - 4
+ mov r9, lr
+ mfsr r10, SYSREG_RAR_EX
+ mfsr r11, SYSREG_RSR_EX
+ pushm r8-r11
+ mfsr r12, SYSREG_ECR
+ mov r11, sp
+ rcall do_unknown_exception
+1: rjmp 1b
diff --git a/cpu/at32ap/exception.c b/cpu/at32ap/exception.c
new file mode 100644
index 0000000..4123c44
--- /dev/null
+++ b/cpu/at32ap/exception.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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/sysreg.h>
+#include <asm/ptrace.h>
+
+static const char * const cpu_modes[8] = {
+ "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
+ "Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
+};
+
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+{
+ unsigned long p;
+ int i;
+
+ printf("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+
+ for (p = bottom & ~31; p < top; ) {
+ printf("%04lx: ", p & 0xffff);
+
+ for (i = 0; i < 8; i++, p += 4) {
+ unsigned int val;
+
+ if (p < bottom || p >= top)
+ printf(" ");
+ else {
+ val = *(unsigned long *)p;
+ printf("%08x ", val);
+ }
+ }
+ printf("\n");
+ }
+}
+
+void do_unknown_exception(unsigned int ecr, struct pt_regs *regs)
+{
+ unsigned int mode;
+
+ printf("\n *** Unhandled exception %u at PC=0x%08lx\n", ecr, regs->pc);
+
+ switch (ecr) {
+ case ECR_BUS_ERROR_WRITE:
+ case ECR_BUS_ERROR_READ:
+ printf("Bus error at address 0x%08lx\n",
+ sysreg_read(BEAR));
+ break;
+ case ECR_TLB_MULTIPLE:
+ case ECR_ADDR_ALIGN_X:
+ case ECR_PROTECTION_X:
+ case ECR_ADDR_ALIGN_R:
+ case ECR_ADDR_ALIGN_W:
+ case ECR_PROTECTION_R:
+ case ECR_PROTECTION_W:
+ case ECR_DTLB_MODIFIED:
+ case ECR_TLB_MISS_X:
+ case ECR_TLB_MISS_R:
+ case ECR_TLB_MISS_W:
+ printf("MMU exception at address 0x%08lx\n",
+ sysreg_read(TLBEAR));
+ break;
+ }
+
+ printf(" pc: %08lx lr: %08lx sp: %08lx r12: %08lx\n",
+ regs->pc, regs->lr, regs->sp, regs->r12);
+ printf(" r11: %08lx r10: %08lx r9: %08lx r8: %08lx\n",
+ regs->r11, regs->r10, regs->r9, regs->r8);
+ printf(" r7: %08lx r6: %08lx r5: %08lx r4: %08lx\n",
+ regs->r7, regs->r6, regs->r5, regs->r4);
+ printf(" r3: %08lx r2: %08lx r1: %08lx r0: %08lx\n",
+ regs->r3, regs->r2, regs->r1, regs->r0);
+ printf("Flags: %c%c%c%c%c\n",
+ regs->sr & SR_Q ? 'Q' : 'q',
+ regs->sr & SR_V ? 'V' : 'v',
+ regs->sr & SR_N ? 'N' : 'n',
+ regs->sr & SR_Z ? 'Z' : 'z',
+ regs->sr & SR_C ? 'C' : 'c');
+ printf("Mode bits: %c%c%c%c%c%c%c%c%c\n",
+ regs->sr & SR_H ? 'H' : 'h',
+ regs->sr & SR_R ? 'R' : 'r',
+ regs->sr & SR_J ? 'J' : 'j',
+ regs->sr & SR_EM ? 'E' : 'e',
+ regs->sr & SR_I3M ? '3' : '.',
+ regs->sr & SR_I2M ? '2' : '.',
+ regs->sr & SR_I1M ? '1' : '.',
+ regs->sr & SR_I0M ? '0' : '.',
+ regs->sr & SR_GM ? 'G' : 'g');
+ mode = (regs->sr >> SYSREG_M0_OFFSET) & 7;
+ printf("CPU Mode: %s\n", cpu_modes[mode]);
+
+ /* Avoid exception loops */
+ if (regs->sp >= CFG_INIT_SP_ADDR
+ || regs->sp < (CFG_INIT_SP_ADDR - CONFIG_STACKSIZE))
+ printf("\nStack pointer seems bogus, won't do stack dump\n");
+ else
+ dump_mem("\nStack: ", regs->sp, CFG_INIT_SP_ADDR);
+
+ panic("Unhandled exception\n");
+}
diff --git a/cpu/at32ap/hsdramc.c b/cpu/at32ap/hsdramc.c
new file mode 100644
index 0000000..f36da35
--- /dev/null
+++ b/cpu/at32ap/hsdramc.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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>
+
+#ifdef CFG_HSDRAMC
+#include <asm/io.h>
+#include <asm/sdram.h>
+
+#include <asm/arch/platform.h>
+
+#include "hsdramc1.h"
+
+struct hsdramc {
+ const struct device *hebi;
+ void *regs;
+};
+
+static struct hsdramc hsdramc;
+
+unsigned long sdram_init(const struct sdram_info *info)
+{
+ unsigned long *sdram = (unsigned long *)uncached(info->phys_addr);
+ unsigned long sdram_size;
+ unsigned long tmp;
+ unsigned long bus_hz;
+ unsigned int i;
+
+ hsdramc.hebi = get_device(DEVICE_HEBI);
+ if (!hsdramc.hebi)
+ return 0;
+
+ /* FIXME: Both of these lines are complete hacks */
+ hsdramc.regs = hsdramc.hebi->regs + 0x400;
+ bus_hz = pm_get_clock_freq(hsdramc.hebi->resource[0].u.clock.id);
+
+ cpu_enable_sdram();
+
+ tmp = (HSDRAMC1_BF(NC, info->col_bits - 8)
+ | HSDRAMC1_BF(NR, info->row_bits - 11)
+ | HSDRAMC1_BF(NB, info->bank_bits - 1)
+ | HSDRAMC1_BF(CAS, info->cas)
+ | HSDRAMC1_BF(TWR, info->twr)
+ | HSDRAMC1_BF(TRC, info->trc)
+ | HSDRAMC1_BF(TRP, info->trp)
+ | HSDRAMC1_BF(TRCD, info->trcd)
+ | HSDRAMC1_BF(TRAS, info->tras)
+ | HSDRAMC1_BF(TXSR, info->txsr));
+
+#ifdef CFG_SDRAM_16BIT
+ tmp |= HSDRAMC1_BIT(DBW);
+ sdram_size = 1 << (info->row_bits + info->col_bits
+ + info->bank_bits + 1);
+#else
+ sdram_size = 1 << (info->row_bits + info->col_bits
+ + info->bank_bits + 2);
+#endif
+
+ hsdramc1_writel(&hsdramc, CR, tmp);
+
+ /*
+ * Initialization sequence for SDRAM, from the data sheet:
+ *
+ * 1. A minimum pause of 200 us is provided to precede any
+ * signal toggle.
+ */
+ udelay(200);
+
+ /*
+ * 2. A Precharge All command is issued to the SDRAM
+ */
+ hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_BANKS_PRECHARGE);
+ hsdramc1_readl(&hsdramc, MR);
+ writel(0, sdram);
+
+ /*
+ * 3. Eight auto-refresh (CBR) cycles are provided
+ */
+ hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_AUTO_REFRESH);
+ hsdramc1_readl(&hsdramc, MR);
+ for (i = 0; i < 8; i++)
+ writel(0, sdram);
+
+ /*
+ * 4. A mode register set (MRS) cycle is issued to program
+ * SDRAM parameters, in particular CAS latency and burst
+ * length.
+ *
+ * CAS from info struct, burst length 1, serial burst type
+ */
+ hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_LOAD_MODE);
+ hsdramc1_readl(&hsdramc, MR);
+ writel(0, sdram + (info->cas << 4));
+
+ /*
+ * 5. A Normal Mode command is provided, 3 clocks after tMRD
+ * is met.
+ *
+ * From the timing diagram, it looks like tMRD is 3
+ * cycles...try a dummy read from the peripheral bus.
+ */
+ hsdramc1_readl(&hsdramc, MR);
+ hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_NORMAL);
+ hsdramc1_readl(&hsdramc, MR);
+ writel(0, sdram);
+
+ /*
+ * 6. Write refresh rate into SDRAMC refresh timer count
+ * register (refresh rate = timing between refresh cycles).
+ *
+ * 15.6 us is a typical value for a burst of length one
+ */
+ hsdramc1_writel(&hsdramc, TR, (156 * (bus_hz / 1000)) / 10000);
+
+ printf("SDRAM: %u MB at address 0x%08lx\n",
+ sdram_size >> 20, info->phys_addr);
+
+ printf("Testing SDRAM...");
+ for (i = 0; i < sdram_size / 4; i++)
+ sdram[i] = i;
+
+ for (i = 0; i < sdram_size / 4; i++) {
+ tmp = sdram[i];
+ if (tmp != i) {
+ printf("FAILED at address 0x%08lx\n",
+ info->phys_addr + i * 4);
+ printf("SDRAM: read 0x%lx, expected 0x%lx\n", tmp, i);
+ return 0;
+ }
+ }
+
+ puts("OK\n");
+
+ return sdram_size;
+}
+
+#endif /* CFG_HSDRAMC */
diff --git a/cpu/at32ap/hsdramc1.h b/cpu/at32ap/hsdramc1.h
new file mode 100644
index 0000000..ce229bc
--- /dev/null
+++ b/cpu/at32ap/hsdramc1.h
@@ -0,0 +1,143 @@
+/*
+ * Register definitions for SDRAM Controller
+ */
+#ifndef __ASM_AVR32_HSDRAMC1_H__
+#define __ASM_AVR32_HSDRAMC1_H__
+
+/* HSDRAMC1 register offsets */
+#define HSDRAMC1_MR 0x0000
+#define HSDRAMC1_TR 0x0004
+#define HSDRAMC1_CR 0x0008
+#define HSDRAMC1_HSR 0x000c
+#define HSDRAMC1_LPR 0x0010
+#define HSDRAMC1_IER 0x0014
+#define HSDRAMC1_IDR 0x0018
+#define HSDRAMC1_IMR 0x001c
+#define HSDRAMC1_ISR 0x0020
+#define HSDRAMC1_MDR 0x0024
+#define HSDRAMC1_VERSION 0x00fc
+
+/* Bitfields in MR */
+#define HSDRAMC1_MODE_OFFSET 0
+#define HSDRAMC1_MODE_SIZE 3
+
+/* Bitfields in TR */
+#define HSDRAMC1_COUNT_OFFSET 0
+#define HSDRAMC1_COUNT_SIZE 12
+
+/* Bitfields in CR */
+#define HSDRAMC1_NC_OFFSET 0
+#define HSDRAMC1_NC_SIZE 2
+#define HSDRAMC1_NR_OFFSET 2
+#define HSDRAMC1_NR_SIZE 2
+#define HSDRAMC1_NB_OFFSET 4
+#define HSDRAMC1_NB_SIZE 1
+#define HSDRAMC1_CAS_OFFSET 5
+#define HSDRAMC1_CAS_SIZE 2
+#define HSDRAMC1_DBW_OFFSET 7
+#define HSDRAMC1_DBW_SIZE 1
+#define HSDRAMC1_TWR_OFFSET 8
+#define HSDRAMC1_TWR_SIZE 4
+#define HSDRAMC1_TRC_OFFSET 12
+#define HSDRAMC1_TRC_SIZE 4
+#define HSDRAMC1_TRP_OFFSET 16
+#define HSDRAMC1_TRP_SIZE 4
+#define HSDRAMC1_TRCD_OFFSET 20
+#define HSDRAMC1_TRCD_SIZE 4
+#define HSDRAMC1_TRAS_OFFSET 24
+#define HSDRAMC1_TRAS_SIZE 4
+#define HSDRAMC1_TXSR_OFFSET 28
+#define HSDRAMC1_TXSR_SIZE 4
+
+/* Bitfields in HSR */
+#define HSDRAMC1_DA_OFFSET 0
+#define HSDRAMC1_DA_SIZE 1
+
+/* Bitfields in LPR */
+#define HSDRAMC1_LPCB_OFFSET 0
+#define HSDRAMC1_LPCB_SIZE 2
+#define HSDRAMC1_PASR_OFFSET 4
+#define HSDRAMC1_PASR_SIZE 3
+#define HSDRAMC1_TCSR_OFFSET 8
+#define HSDRAMC1_TCSR_SIZE 2
+#define HSDRAMC1_DS_OFFSET 10
+#define HSDRAMC1_DS_SIZE 2
+#define HSDRAMC1_TIMEOUT_OFFSET 12
+#define HSDRAMC1_TIMEOUT_SIZE 2
+
+/* Bitfields in IDR */
+#define HSDRAMC1_RES_OFFSET 0
+#define HSDRAMC1_RES_SIZE 1
+
+/* Bitfields in MDR */
+#define HSDRAMC1_MD_OFFSET 0
+#define HSDRAMC1_MD_SIZE 2
+
+/* Bitfields in VERSION */
+#define HSDRAMC1_VERSION_OFFSET 0
+#define HSDRAMC1_VERSION_SIZE 12
+#define HSDRAMC1_MFN_OFFSET 16
+#define HSDRAMC1_MFN_SIZE 3
+
+/* Constants for MODE */
+#define HSDRAMC1_MODE_NORMAL 0
+#define HSDRAMC1_MODE_NOP 1
+#define HSDRAMC1_MODE_BANKS_PRECHARGE 2
+#define HSDRAMC1_MODE_LOAD_MODE 3
+#define HSDRAMC1_MODE_AUTO_REFRESH 4
+#define HSDRAMC1_MODE_EXT_LOAD_MODE 5
+#define HSDRAMC1_MODE_POWER_DOWN 6
+
+/* Constants for NC */
+#define HSDRAMC1_NC_8_COLUMN_BITS 0
+#define HSDRAMC1_NC_9_COLUMN_BITS 1
+#define HSDRAMC1_NC_10_COLUMN_BITS 2
+#define HSDRAMC1_NC_11_COLUMN_BITS 3
+
+/* Constants for NR */
+#define HSDRAMC1_NR_11_ROW_BITS 0
+#define HSDRAMC1_NR_12_ROW_BITS 1
+#define HSDRAMC1_NR_13_ROW_BITS 2
+
+/* Constants for NB */
+#define HSDRAMC1_NB_TWO_BANKS 0
+#define HSDRAMC1_NB_FOUR_BANKS 1
+
+/* Constants for CAS */
+#define HSDRAMC1_CAS_ONE_CYCLE 1
+#define HSDRAMC1_CAS_TWO_CYCLES 2
+
+/* Constants for DBW */
+#define HSDRAMC1_DBW_32_BITS 0
+#define HSDRAMC1_DBW_16_BITS 1
+
+/* Constants for TIMEOUT */
+#define HSDRAMC1_TIMEOUT_AFTER_END 0
+#define HSDRAMC1_TIMEOUT_64_CYC_AFTER_END 1
+#define HSDRAMC1_TIMEOUT_128_CYC_AFTER_END 2
+
+/* Constants for MD */
+#define HSDRAMC1_MD_SDRAM 0
+#define HSDRAMC1_MD_LOW_POWER_SDRAM 1
+
+/* Bit manipulation macros */
+#define HSDRAMC1_BIT(name) \
+ (1 << HSDRAMC1_##name##_OFFSET)
+#define HSDRAMC1_BF(name,value) \
+ (((value) & ((1 << HSDRAMC1_##name##_SIZE) - 1)) \
+ << HSDRAMC1_##name##_OFFSET)
+#define HSDRAMC1_BFEXT(name,value) \
+ (((value) >> HSDRAMC1_##name##_OFFSET) \
+ & ((1 << HSDRAMC1_##name##_SIZE) - 1))
+#define HSDRAMC1_BFINS(name,value,old) \
+ (((old) & ~(((1 << HSDRAMC1_##name##_SIZE) - 1) \
+ << HSDRAMC1_##name##_OFFSET)) \
+ | HSDRAMC1_BF(name,value))
+
+/* Register access macros */
+#define hsdramc1_readl(port,reg) \
+ readl((port)->regs + HSDRAMC1_##reg)
+#define hsdramc1_writel(port,reg,value) \
+ writel((value), (port)->regs + HSDRAMC1_##reg)
+
+#endif /* __ASM_AVR32_HSDRAMC1_H__ */
diff --git a/cpu/at32ap/hsmc3.h b/cpu/at32ap/hsmc3.h
new file mode 100644
index 0000000..ec78cee
--- /dev/null
+++ b/cpu/at32ap/hsmc3.h
@@ -0,0 +1,126 @@
+/*
+ * Register definitions for Static Memory Controller
+ */
+#ifndef __CPU_AT32AP_HSMC3_H__
+#define __CPU_AT32AP_HSMC3_H__
+
+/* HSMC3 register offsets */
+#define HSMC3_SETUP0 0x0000
+#define HSMC3_PULSE0 0x0004
+#define HSMC3_CYCLE0 0x0008
+#define HSMC3_MODE0 0x000c
+#define HSMC3_SETUP1 0x0010
+#define HSMC3_PULSE1 0x0014
+#define HSMC3_CYCLE1 0x0018
+#define HSMC3_MODE1 0x001c
+#define HSMC3_SETUP2 0x0020
+#define HSMC3_PULSE2 0x0024
+#define HSMC3_CYCLE2 0x0028
+#define HSMC3_MODE2 0x002c
+#define HSMC3_SETUP3 0x0030
+#define HSMC3_PULSE3 0x0034
+#define HSMC3_CYCLE3 0x0038
+#define HSMC3_MODE3 0x003c
+#define HSMC3_SETUP4 0x0040
+#define HSMC3_PULSE4 0x0044
+#define HSMC3_CYCLE4 0x0048
+#define HSMC3_MODE4 0x004c
+#define HSMC3_SETUP5 0x0050
+#define HSMC3_PULSE5 0x0054
+#define HSMC3_CYCLE5 0x0058
+#define HSMC3_MODE5 0x005c
+
+/* Bitfields in SETUP0 */
+#define HSMC3_NWE_SETUP_OFFSET 0
+#define HSMC3_NWE_SETUP_SIZE 6
+#define HSMC3_NCS_WR_SETUP_OFFSET 8
+#define HSMC3_NCS_WR_SETUP_SIZE 6
+#define HSMC3_NRD_SETUP_OFFSET 16
+#define HSMC3_NRD_SETUP_SIZE 6
+#define HSMC3_NCS_RD_SETUP_OFFSET 24
+#define HSMC3_NCS_RD_SETUP_SIZE 6
+
+/* Bitfields in PULSE0 */
+#define HSMC3_NWE_PULSE_OFFSET 0
+#define HSMC3_NWE_PULSE_SIZE 7
+#define HSMC3_NCS_WR_PULSE_OFFSET 8
+#define HSMC3_NCS_WR_PULSE_SIZE 7
+#define HSMC3_NRD_PULSE_OFFSET 16
+#define HSMC3_NRD_PULSE_SIZE 7
+#define HSMC3_NCS_RD_PULSE_OFFSET 24
+#define HSMC3_NCS_RD_PULSE_SIZE 7
+
+/* Bitfields in CYCLE0 */
+#define HSMC3_NWE_CYCLE_OFFSET 0
+#define HSMC3_NWE_CYCLE_SIZE 9
+#define HSMC3_NRD_CYCLE_OFFSET 16
+#define HSMC3_NRD_CYCLE_SIZE 9
+
+/* Bitfields in MODE0 */
+#define HSMC3_READ_MODE_OFFSET 0
+#define HSMC3_READ_MODE_SIZE 1
+#define HSMC3_WRITE_MODE_OFFSET 1
+#define HSMC3_WRITE_MODE_SIZE 1
+#define HSMC3_EXNW_MODE_OFFSET 4
+#define HSMC3_EXNW_MODE_SIZE 2
+#define HSMC3_BAT_OFFSET 8
+#define HSMC3_BAT_SIZE 1
+#define HSMC3_DBW_OFFSET 12
+#define HSMC3_DBW_SIZE 2
+#define HSMC3_TDF_CYCLES_OFFSET 16
+#define HSMC3_TDF_CYCLES_SIZE 4
+#define HSMC3_TDF_MODE_OFFSET 20
+#define HSMC3_TDF_MODE_SIZE 1
+#define HSMC3_PMEN_OFFSET 24
+#define HSMC3_PMEN_SIZE 1
+#define HSMC3_PS_OFFSET 28
+#define HSMC3_PS_SIZE 2
+
+/* Bitfields in MODE1 */
+#define HSMC3_PD_OFFSET 28
+#define HSMC3_PD_SIZE 2
+
+/* Constants for READ_MODE */
+#define HSMC3_READ_MODE_NCS_CONTROLLED 0
+#define HSMC3_READ_MODE_NRD_CONTROLLED 1
+
+/* Constants for WRITE_MODE */
+#define HSMC3_WRITE_MODE_NCS_CONTROLLED 0
+#define HSMC3_WRITE_MODE_NWE_CONTROLLED 1
+
+/* Constants for EXNW_MODE */
+#define HSMC3_EXNW_MODE_DISABLED 0
+#define HSMC3_EXNW_MODE_RESERVED 1
+#define HSMC3_EXNW_MODE_FROZEN 2
+#define HSMC3_EXNW_MODE_READY 3
+
+/* Constants for BAT */
+#define HSMC3_BAT_BYTE_SELECT 0
+#define HSMC3_BAT_BYTE_WRITE 1
+
+/* Constants for DBW */
+#define HSMC3_DBW_8_BITS 0
+#define HSMC3_DBW_16_BITS 1
+#define HSMC3_DBW_32_BITS 2
+
+/* Bit manipulation macros */
+#define HSMC3_BIT(name) \
+ (1 << HSMC3_##name##_OFFSET)
+#define HSMC3_BF(name,value) \
+ (((value) & ((1 << HSMC3_##name##_SIZE) - 1)) \
+ << HSMC3_##name##_OFFSET)
+#define HSMC3_BFEXT(name,value) \
+ (((value) >> HSMC3_##name##_OFFSET) \
+ & ((1 << HSMC3_##name##_SIZE) - 1))
+#define HSMC3_BFINS(name,value,old)\
+ (((old) & ~(((1 << HSMC3_##name##_SIZE) - 1) \
+ << HSMC3_##name##_OFFSET)) \
+ | HSMC3_BF(name,value))
+
+/* Register access macros */
+#define hsmc3_readl(port,reg) \
+ readl((port)->regs + HSMC3_##reg)
+#define hsmc3_writel(port,reg,value) \
+ writel((value), (port)->regs + HSMC3_##reg)
+
+#endif /* __CPU_AT32AP_HSMC3_H__ */
diff --git a/cpu/at32ap/interrupts.c b/cpu/at32ap/interrupts.c
new file mode 100644
index 0000000..d720cfa
--- /dev/null
+++ b/cpu/at32ap/interrupts.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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/div64.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/sysreg.h>
+
+#include <asm/arch/platform.h>
+
+#define HANDLER_MASK 0x00ffffff
+#define INTLEV_SHIFT 30
+#define INTLEV_MASK 0x00000003
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Incremented whenever COUNT reaches 0xffffffff by timer_interrupt_handler */
+volatile unsigned long timer_overflow;
+
+/*
+ * Instead of dividing by get_tbclk(), multiply by this constant and
+ * right-shift the result by 32 bits.
+ */
+static unsigned long tb_factor;
+
+static const struct device *intc_dev;
+
+unsigned long get_tbclk(void)
+{
+ return gd->cpu_hz;
+}
+
+unsigned long long get_ticks(void)
+{
+ unsigned long lo, hi_now, hi_prev;
+
+ do {
+ hi_prev = timer_overflow;
+ lo = sysreg_read(COUNT);
+ hi_now = timer_overflow;
+ } while (hi_prev != hi_now);
+
+ return ((unsigned long long)hi_now << 32) | lo;
+}
+
+void reset_timer(void)
+{
+ sysreg_write(COUNT, 0);
+ cpu_sync_pipeline(); /* process any pending interrupts */
+ timer_overflow = 0;
+}
+
+unsigned long get_timer(unsigned long base)
+{
+ u64 now = get_ticks();
+
+ now *= tb_factor;
+ return (unsigned long)(now >> 32) - base;
+}
+
+void set_timer(unsigned long t)
+{
+ unsigned long long ticks = t;
+ unsigned long lo, hi, hi_new;
+
+ ticks = (ticks * get_tbclk()) / CFG_HZ;
+ hi = ticks >> 32;
+ lo = ticks & 0xffffffffUL;
+
+ do {
+ timer_overflow = hi;
+ sysreg_write(COUNT, lo);
+ hi_new = timer_overflow;
+ } while (hi_new != hi);
+}
+
+/*
+ * For short delays only. It will overflow after a few seconds.
+ */
+void udelay(unsigned long usec)
+{
+ unsigned long now, end;
+
+ now = sysreg_read(COUNT);
+
+ end = ((usec * (get_tbclk() / 10000)) + 50) / 100;
+ end += now;
+
+ while (now > end)
+ now = sysreg_read(COUNT);
+
+ while (now < end)
+ now = sysreg_read(COUNT);
+}
+
+static int set_interrupt_handler(unsigned int nr, void (*handler)(void),
+ unsigned int priority)
+{
+ unsigned long intpr;
+ unsigned long handler_addr = (unsigned long)handler;
+
+ if ((handler_addr & HANDLER_MASK) != handler_addr
+ || (priority & INTLEV_MASK) != priority)
+ return -EINVAL;
+
+ intpr = (handler_addr & HANDLER_MASK);
+ intpr |= (priority & INTLEV_MASK) << INTLEV_SHIFT;
+ writel(intpr, intc_dev->regs + 4 * nr);
+
+ return 0;
+}
+
+void timer_init(void)
+{
+ extern void timer_interrupt_handler(void);
+ u64 tmp;
+
+ sysreg_write(COUNT, 0);
+
+ tmp = (u64)CFG_HZ << 32;
+ tmp += gd->cpu_hz / 2;
+ do_div(tmp, gd->cpu_hz);
+ tb_factor = (u32)tmp;
+
+ intc_dev = get_device(DEVICE_INTC);
+
+ if (!intc_dev
+ || set_interrupt_handler(0, &timer_interrupt_handler, 3))
+ return;
+
+ /* For all practical purposes, this gives us an overflow interrupt */
+ sysreg_write(COMPARE, 0xffffffff);
+}
diff --git a/cpu/at32ap/pio.c b/cpu/at32ap/pio.c
new file mode 100644
index 0000000..8b6c3a3
--- /dev/null
+++ b/cpu/at32ap/pio.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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/errno.h>
+#include <asm/io.h>
+#include <asm/arch/platform.h>
+
+#include "pio2.h"
+
+struct pio_state {
+ const struct device *dev;
+ u32 alloc_mask;
+};
+
+static struct pio_state pio_state[CFG_NR_PIOS];
+
+int gpio_set_func(enum device_id gpio_devid, unsigned int start,
+ unsigned int nr_pins, enum gpio_func func)
+{
+ const struct device *gpio;
+ struct pio_state *state;
+ u32 mask;
+
+ state = &pio_state[gpio_devid - DEVICE_PIOA];
+
+ gpio = get_device(gpio_devid);
+ if (!gpio)
+ return -EBUSY;
+
+ state->dev = gpio;
+ mask = ((1 << nr_pins) - 1) << start;
+
+ if (mask & state->alloc_mask) {
+ put_device(gpio);
+ return -EBUSY;
+ }
+ state->alloc_mask |= mask;
+
+ switch (func) {
+ case GPIO_FUNC_GPIO:
+ /* TODO */
+ return -EINVAL;
+ case GPIO_FUNC_A:
+ pio2_writel(gpio, ASR, mask);
+ pio2_writel(gpio, PDR, mask);
+ pio2_writel(gpio, PUDR, mask);
+ break;
+ case GPIO_FUNC_B:
+ pio2_writel(gpio, BSR, mask);
+ pio2_writel(gpio, PDR, mask);
+ pio2_writel(gpio, PUDR, mask);
+ break;
+ }
+
+ return 0;
+}
+
+void gpio_free(enum device_id gpio_devid, unsigned int start,
+ unsigned int nr_pins)
+{
+ const struct device *gpio;
+ struct pio_state *state;
+ u32 mask;
+
+ state = &pio_state[gpio_devid - DEVICE_PIOA];
+ gpio = state->dev;
+ mask = ((1 << nr_pins) - 1) << start;
+
+ pio2_writel(gpio, ODR, mask);
+ pio2_writel(gpio, PER, mask);
+
+ state->alloc_mask &= ~mask;
+ put_device(gpio);
+}
diff --git a/cpu/at32ap/pio2.h b/cpu/at32ap/pio2.h
new file mode 100644
index 0000000..6b79de3
--- /dev/null
+++ b/cpu/at32ap/pio2.h
@@ -0,0 +1,44 @@
+/*
+ * Register definitions for Parallel Input/Output Controller
+ */
+#ifndef __CPU_AT32AP_PIO2_H__
+#define __CPU_AT32AP_PIO2_H__
+
+/* PIO2 register offsets */
+#define PIO2_PER 0x0000
+#define PIO2_PDR 0x0004
+#define PIO2_PSR 0x0008
+#define PIO2_OER 0x0010
+#define PIO2_ODR 0x0014
+#define PIO2_OSR 0x0018
+#define PIO2_IFER 0x0020
+#define PIO2_IFDR 0x0024
+#define PIO2_ISFR 0x0028
+#define PIO2_SODR 0x0030
+#define PIO2_CODR 0x0034
+#define PIO2_ODSR 0x0038
+#define PIO2_PDSR 0x003c
+#define PIO2_IER 0x0040
+#define PIO2_IDR 0x0044
+#define PIO2_IMR 0x0048
+#define PIO2_ISR 0x004c
+#define PIO2_MDER 0x0050
+#define PIO2_MDDR 0x0054
+#define PIO2_MDSR 0x0058
+#define PIO2_PUDR 0x0060
+#define PIO2_PUER 0x0064
+#define PIO2_PUSR 0x0068
+#define PIO2_ASR 0x0070
+#define PIO2_BSR 0x0074
+#define PIO2_ABSR 0x0078
+#define PIO2_OWER 0x00a0
+#define PIO2_OWDR 0x00a4
+#define PIO2_OWSR 0x00a8
+
+/* Register access macros */
+#define pio2_readl(port,reg) \
+ readl((port)->regs + PIO2_##reg)
+#define pio2_writel(port,reg,value) \
+ writel((value), (port)->regs + PIO2_##reg)
+
+#endif /* __CPU_AT32AP_PIO2_H__ */
diff --git a/cpu/at32ap/pm.c b/cpu/at32ap/pm.c
new file mode 100644
index 0000000..01ac325
--- /dev/null
+++ b/cpu/at32ap/pm.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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>
+
+#ifdef CFG_POWER_MANAGER
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include <asm/arch/memory-map.h>
+#include <asm/arch/platform.h>
+
+#include "sm.h"
+
+/* Sanity checks */
+#if (CFG_CLKDIV_CPU > CFG_CLKDIV_HSB) \
+ || (CFG_CLKDIV_HSB > CFG_CLKDIV_PBA) \
+ || (CFG_CLKDIV_HSB > CFG_CLKDIV_PBB)
+# error Constraint fCPU >= fHSB >= fPB{A,B} violated
+#endif
+#if defined(CONFIG_PLL) && ((CFG_PLL0_MUL < 1) || (CFG_PLL0_DIV < 1))
+# error Invalid PLL multiplier and/or divider
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct clock_domain_state {
+ const struct device *bridge;
+ unsigned long freq;
+ u32 mask;
+};
+static struct clock_domain_state ckd_state[NR_CLOCK_DOMAINS];
+
+int pm_enable_clock(enum clock_domain_id id, unsigned int index)
+{
+ const struct clock_domain *ckd = &chip_clock[id];
+ struct clock_domain_state *state = &ckd_state[id];
+
+ if (ckd->bridge != NO_DEVICE) {
+ state->bridge = get_device(ckd->bridge);
+ if (!state->bridge)
+ return -EBUSY;
+ }
+
+ state->mask |= 1 << index;
+ if (gd->sm)
+ writel(state->mask, gd->sm->regs + ckd->reg);
+
+ return 0;
+}
+
+void pm_disable_clock(enum clock_domain_id id, unsigned int index)
+{
+ const struct clock_domain *ckd = &chip_clock[id];
+ struct clock_domain_state *state = &ckd_state[id];
+
+ state->mask &= ~(1 << index);
+ if (gd->sm)
+ writel(state->mask, gd->sm->regs + ckd->reg);
+
+ if (ckd->bridge)
+ put_device(state->bridge);
+}
+
+unsigned long pm_get_clock_freq(enum clock_domain_id domain)
+{
+ return ckd_state[domain].freq;
+}
+
+void pm_init(void)
+{
+ uint32_t cksel = 0;
+ unsigned long main_clock;
+
+ /* Make sure we don't disable any device we're already using */
+ get_device(DEVICE_HRAMC);
+ get_device(DEVICE_HEBI);
+
+ /* Enable the PICO as well */
+ ckd_state[CLOCK_CPU].mask |= 1;
+
+ gd->sm = get_device(DEVICE_SM);
+ if (!gd->sm)
+ panic("Unable to claim system manager device!\n");
+
+ /* Disable any devices that haven't been explicitly claimed */
+ sm_writel(gd->sm, PM_PBB_MASK, ckd_state[CLOCK_PBB].mask);
+ sm_writel(gd->sm, PM_PBA_MASK, ckd_state[CLOCK_PBA].mask);
+ sm_writel(gd->sm, PM_HSB_MASK, ckd_state[CLOCK_HSB].mask);
+ sm_writel(gd->sm, PM_CPU_MASK, ckd_state[CLOCK_CPU].mask);
+
+#ifdef CONFIG_PLL
+ /* Initialize the PLL */
+ main_clock = (CFG_OSC0_HZ / CFG_PLL0_DIV) * CFG_PLL0_MUL;
+
+ sm_writel(gd->sm, PM_PLL0, (SM_BF(PLLCOUNT, CFG_PLL0_SUPPRESS_CYCLES)
+ | SM_BF(PLLMUL, CFG_PLL0_MUL - 1)
+ | SM_BF(PLLDIV, CFG_PLL0_DIV - 1)
+ | SM_BF(PLLOPT, CFG_PLL0_OPT)
+ | SM_BF(PLLOSC, 0)
+ | SM_BIT(PLLEN)));
+
+ /* Wait for lock */
+ while (!(sm_readl(gd->sm, PM_ISR) & SM_BIT(LOCK0))) ;
+#else
+ main_clock = CFG_OSC0_HZ;
+#endif
+
+ /* Set up clocks for the CPU and all peripheral buses */
+ if (CFG_CLKDIV_CPU) {
+ cksel |= SM_BIT(CPUDIV) | SM_BF(CPUSEL, CFG_CLKDIV_CPU - 1);
+ ckd_state[CLOCK_CPU].freq = main_clock / (1 << CFG_CLKDIV_CPU);
+ } else {
+ ckd_state[CLOCK_CPU].freq = main_clock;
+ }
+ if (CFG_CLKDIV_HSB) {
+ cksel |= SM_BIT(HSBDIV) | SM_BF(HSBSEL, CFG_CLKDIV_HSB - 1);
+ ckd_state[CLOCK_HSB].freq = main_clock / (1 << CFG_CLKDIV_HSB);
+ } else {
+ ckd_state[CLOCK_HSB].freq = main_clock;
+ }
+ if (CFG_CLKDIV_PBA) {
+ cksel |= SM_BIT(PBADIV) | SM_BF(PBASEL, CFG_CLKDIV_PBA - 1);
+ ckd_state[CLOCK_PBA].freq = main_clock / (1 << CFG_CLKDIV_PBA);
+ } else {
+ ckd_state[CLOCK_PBA].freq = main_clock;
+ }
+ if (CFG_CLKDIV_PBB) {
+ cksel |= SM_BIT(PBBDIV) | SM_BF(PBBSEL, CFG_CLKDIV_PBB - 1);
+ ckd_state[CLOCK_PBB].freq = main_clock / (1 << CFG_CLKDIV_PBB);
+ } else {
+ ckd_state[CLOCK_PBB].freq = main_clock;
+ }
+ sm_writel(gd->sm, PM_CKSEL, cksel);
+
+ /* CFG_HZ currently depends on cpu_hz */
+ gd->cpu_hz = ckd_state[CLOCK_CPU].freq;
+
+#ifdef CONFIG_PLL
+ /* Use PLL0 as main clock */
+ sm_writel(gd->sm, PM_MCCTRL, SM_BIT(PLLSEL));
+#endif
+}
+
+#endif /* CFG_POWER_MANAGER */
diff --git a/cpu/at32ap/sm.h b/cpu/at32ap/sm.h
new file mode 100644
index 0000000..ce81ef0
--- /dev/null
+++ b/cpu/at32ap/sm.h
@@ -0,0 +1,204 @@
+/*
+ * Register definitions for System Manager
+ */
+#ifndef __CPU_AT32AP_SM_H__
+#define __CPU_AT32AP_SM_H__
+
+/* SM register offsets */
+#define SM_PM_MCCTRL 0x0000
+#define SM_PM_CKSEL 0x0004
+#define SM_PM_CPU_MASK 0x0008
+#define SM_PM_HSB_MASK 0x000c
+#define SM_PM_PBA_MASK 0x0010
+#define SM_PM_PBB_MASK 0x0014
+#define SM_PM_PLL0 0x0020
+#define SM_PM_PLL1 0x0024
+#define SM_PM_VCTRL 0x0030
+#define SM_PM_VMREF 0x0034
+#define SM_PM_VMV 0x0038
+#define SM_PM_IER 0x0040
+#define SM_PM_IDR 0x0044
+#define SM_PM_IMR 0x0048
+#define SM_PM_ISR 0x004c
+#define SM_PM_ICR 0x0050
+#define SM_PM_GCCTRL 0x0060
+#define SM_RTC_CTRL 0x0080
+#define SM_RTC_VAL 0x0084
+#define SM_RTC_TOP 0x0088
+#define SM_RTC_IER 0x0090
+#define SM_RTC_IDR 0x0094
+#define SM_RTC_IMR 0x0098
+#define SM_RTC_ISR 0x009c
+#define SM_RTC_ICR 0x00a0
+#define SM_WDT_CTRL 0x00b0
+#define SM_WDT_CLR 0x00b4
+#define SM_WDT_EXT 0x00b8
+#define SM_RC_RCAUSE 0x00c0
+#define SM_EIM_IER 0x0100
+#define SM_EIM_IDR 0x0104
+#define SM_EIM_IMR 0x0108
+#define SM_EIM_ISR 0x010c
+#define SM_EIM_ICR 0x0110
+#define SM_EIM_MODE 0x0114
+#define SM_EIM_EDGE 0x0118
+#define SM_EIM_LEVEL 0x011c
+#define SM_EIM_TEST 0x0120
+#define SM_EIM_NMIC 0x0124
+
+/* Bitfields in PM_CKSEL */
+#define SM_CPUSEL_OFFSET 0
+#define SM_CPUSEL_SIZE 3
+#define SM_CPUDIV_OFFSET 7
+#define SM_CPUDIV_SIZE 1
+#define SM_HSBSEL_OFFSET 8
+#define SM_HSBSEL_SIZE 3
+#define SM_HSBDIV_OFFSET 15
+#define SM_HSBDIV_SIZE 1
+#define SM_PBASEL_OFFSET 16
+#define SM_PBASEL_SIZE 3
+#define SM_PBADIV_OFFSET 23
+#define SM_PBADIV_SIZE 1
+#define SM_PBBSEL_OFFSET 24
+#define SM_PBBSEL_SIZE 3
+#define SM_PBBDIV_OFFSET 31
+#define SM_PBBDIV_SIZE 1
+
+/* Bitfields in PM_PLL0 */
+#define SM_PLLEN_OFFSET 0
+#define SM_PLLEN_SIZE 1
+#define SM_PLLOSC_OFFSET 1
+#define SM_PLLOSC_SIZE 1
+#define SM_PLLOPT_OFFSET 2
+#define SM_PLLOPT_SIZE 3
+#define SM_PLLDIV_OFFSET 8
+#define SM_PLLDIV_SIZE 8
+#define SM_PLLMUL_OFFSET 16
+#define SM_PLLMUL_SIZE 8
+#define SM_PLLCOUNT_OFFSET 24
+#define SM_PLLCOUNT_SIZE 6
+#define SM_PLLTEST_OFFSET 31
+#define SM_PLLTEST_SIZE 1
+
+/* Bitfields in PM_VCTRL */
+#define SM_VAUTO_OFFSET 0
+#define SM_VAUTO_SIZE 1
+#define SM_PM_VCTRL_VAL_OFFSET 8
+#define SM_PM_VCTRL_VAL_SIZE 7
+
+/* Bitfields in PM_VMREF */
+#define SM_REFSEL_OFFSET 0
+#define SM_REFSEL_SIZE 4
+
+/* Bitfields in PM_VMV */
+#define SM_PM_VMV_VAL_OFFSET 0
+#define SM_PM_VMV_VAL_SIZE 8
+
+/* Bitfields in PM_ICR */
+#define SM_LOCK0_OFFSET 0
+#define SM_LOCK0_SIZE 1
+#define SM_LOCK1_OFFSET 1
+#define SM_LOCK1_SIZE 1
+#define SM_WAKE_OFFSET 2
+#define SM_WAKE_SIZE 1
+#define SM_VOK_OFFSET 3
+#define SM_VOK_SIZE 1
+#define SM_VMRDY_OFFSET 4
+#define SM_VMRDY_SIZE 1
+#define SM_CKRDY_OFFSET 5
+#define SM_CKRDY_SIZE 1
+
+/* Bitfields in PM_GCCTRL */
+#define SM_OSCSEL_OFFSET 0
+#define SM_OSCSEL_SIZE 1
+#define SM_PLLSEL_OFFSET 1
+#define SM_PLLSEL_SIZE 1
+#define SM_CEN_OFFSET 2
+#define SM_CEN_SIZE 1
+#define SM_CPC_OFFSET 3
+#define SM_CPC_SIZE 1
+#define SM_DIVEN_OFFSET 4
+#define SM_DIVEN_SIZE 1
+#define SM_DIV_OFFSET 8
+#define SM_DIV_SIZE 8
+
+/* Bitfields in RTC_CTRL */
+#define SM_PCLR_OFFSET 1
+#define SM_PCLR_SIZE 1
+#define SM_TOPEN_OFFSET 2
+#define SM_TOPEN_SIZE 1
+#define SM_CLKEN_OFFSET 3
+#define SM_CLKEN_SIZE 1
+#define SM_PSEL_OFFSET 8
+#define SM_PSEL_SIZE 16
+
+/* Bitfields in RTC_VAL */
+#define SM_RTC_VAL_VAL_OFFSET 0
+#define SM_RTC_VAL_VAL_SIZE 31
+
+/* Bitfields in RTC_TOP */
+#define SM_RTC_TOP_VAL_OFFSET 0
+#define SM_RTC_TOP_VAL_SIZE 32
+
+/* Bitfields in RTC_ICR */
+#define SM_TOPI_OFFSET 0
+#define SM_TOPI_SIZE 1
+
+/* Bitfields in WDT_CTRL */
+#define SM_KEY_OFFSET 24
+#define SM_KEY_SIZE 8
+
+/* Bitfields in RC_RCAUSE */
+#define SM_POR_OFFSET 0
+#define SM_POR_SIZE 1
+#define SM_BOD_OFFSET 1
+#define SM_BOD_SIZE 1
+#define SM_EXT_OFFSET 2
+#define SM_EXT_SIZE 1
+#define SM_WDT_OFFSET 3
+#define SM_WDT_SIZE 1
+#define SM_NTAE_OFFSET 4
+#define SM_NTAE_SIZE 1
+#define SM_SERP_OFFSET 5
+#define SM_SERP_SIZE 1
+
+/* Bitfields in EIM_EDGE */
+#define SM_INT0_OFFSET 0
+#define SM_INT0_SIZE 1
+#define SM_INT1_OFFSET 1
+#define SM_INT1_SIZE 1
+#define SM_INT2_OFFSET 2
+#define SM_INT2_SIZE 1
+#define SM_INT3_OFFSET 3
+#define SM_INT3_SIZE 1
+
+/* Bitfields in EIM_LEVEL */
+
+/* Bitfields in EIM_TEST */
+#define SM_TESTEN_OFFSET 31
+#define SM_TESTEN_SIZE 1
+
+/* Bitfields in EIM_NMIC */
+#define SM_EN_OFFSET 0
+#define SM_EN_SIZE 1
+
+/* Bit manipulation macros */
+#define SM_BIT(name) \
+ (1 << SM_##name##_OFFSET)
+#define SM_BF(name,value) \
+ (((value) & ((1 << SM_##name##_SIZE) - 1)) \
+ << SM_##name##_OFFSET)
+#define SM_BFEXT(name,value) \
+ (((value) >> SM_##name##_OFFSET) \
+ & ((1 << SM_##name##_SIZE) - 1))
+#define SM_BFINS(name,value,old) \
+ (((old) & ~(((1 << SM_##name##_SIZE) - 1) \
+ << SM_##name##_OFFSET)) \
+ | SM_BF(name,value))
+
+/* Register access macros */
+#define sm_readl(port,reg) \
+ readl((port)->regs + SM_##reg)
+#define sm_writel(port,reg,value) \
+ writel((value), (port)->regs + SM_##reg)
+
+#endif /* __CPU_AT32AP_SM_H__ */
diff --git a/cpu/at32ap/start.S b/cpu/at32ap/start.S
new file mode 100644
index 0000000..79ee33b
--- /dev/null
+++ b/cpu/at32ap/start.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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 <asm/sysreg.h>
+
+#ifndef PART_SPECIFIC_BOOTSTRAP
+# define PART_SPECIFIC_BOOTSTRAP
+#endif
+
+#define SYSREG_MMUCR_I_OFFSET 2
+#define SYSREG_MMUCR_S_OFFSET 4
+
+#define SR_INIT (SYSREG_BIT(GM) | SYSREG_BIT(EM) | SYSREG_BIT(M0))
+#define CPUCR_INIT (SYSREG_BIT(BI) | SYSREG_BIT(BE) \
+ | SYSREG_BIT(FE) | SYSREG_BIT(RE) \
+ | SYSREG_BIT(IBE) | SYSREG_BIT(IEE))
+
+ .text
+ .global _start
+_start:
+ PART_SPECIFIC_BOOTSTRAP
+
+ /* Reset the Status Register */
+ mov r0, lo(SR_INIT)
+ orh r0, hi(SR_INIT)
+ mtsr SYSREG_SR, r0
+
+ /* Reset CPUCR and invalidate the BTB */
+ mov r2, CPUCR_INIT
+ mtsr SYSREG_CPUCR, r2
+
+ /* Flush the caches */
+ mov r1, 0
+ cache r1[4], 8
+ cache r1[0], 0
+ sync 0
+
+ /* Reset the MMU to default settings */
+ mov r0, SYSREG_BIT(MMUCR_S) | SYSREG_BIT(MMUCR_I)
+ mtsr SYSREG_MMUCR, r0
+
+ /* Internal RAM should not need any initialization. We might
+ have to initialize external RAM here if the part doesn't
+ have internal RAM (or we may use the data cache) */
+
+ /* Jump to cacheable segment */
+ lddpc pc, 1f
+
+ .align 2
+1: .long 2f
+
+2: lddpc sp, sp_init
+
+ /*
+ * Relocate the data section and initialize .bss. Everything
+ * is guaranteed to be at least doubleword aligned by the
+ * linker script.
+ */
+ lddpc r12, .Ldata_vma
+ lddpc r11, .Ldata_lma
+ lddpc r10, .Ldata_end
+ sub r10, r12
+4: ld.d r8, r11++
+ sub r10, 8
+ st.d r12++, r8
+ brne 4b
+
+ mov r8, 0
+ mov r9, 0
+ lddpc r10, .Lbss_end
+ sub r10, r12
+4: sub r10, 8
+ st.d r12++, r8
+ brne 4b
+
+ /* Initialize the GOT pointer */
+ lddpc r6, got_init
+3: rsub r6, pc
+ ld.w pc, r6[start_u_boot@got]
+
+ .align 2
+ .type sp_init,@object
+sp_init:
+ .long CFG_INIT_SP_ADDR
+got_init:
+ .long 3b - _GLOBAL_OFFSET_TABLE_
+.Ldata_lma:
+ .long __data_lma
+.Ldata_vma:
+ .long _data
+.Ldata_end:
+ .long _edata
+.Lbss_end:
+ .long _end
diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile
index 7b32305..ff67dcd 100644
--- a/cpu/mpc85xx/Makefile
+++ b/cpu/mpc85xx/Makefile
@@ -30,7 +30,7 @@ LIB = $(obj)lib$(CPU).a
START = start.o resetvec.o
COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \
- pci.o serial_scc.o commproc.o ether_fcc.o i2c.o spd_sdram.o
+ pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/mpc85xx/i2c.c b/cpu/mpc85xx/i2c.c
deleted file mode 100644
index 32dcf5d..0000000
--- a/cpu/mpc85xx/i2c.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * (C) Copyright 2003,Motorola Inc.
- * Xianghua Xiao <x.xiao@motorola.com>
- * Adapted for Motorola 85xx chip.
- *
- * (C) Copyright 2003
- * Gleb Natapov <gnatapov@mrv.com>
- * Some bits are taken from linux driver writen by adrian@humboldt.co.uk
- *
- * Hardware I2C driver for MPC107 PCI bridge.
- *
- * 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 <command.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_HARD_I2C
-#include <i2c.h>
-
-#define TIMEOUT (CFG_HZ/4)
-
-#define I2C_Addr ((u8 *)(CFG_CCSRBAR + 0x3000))
-
-#define I2CADR &I2C_Addr[0]
-#define I2CFDR &I2C_Addr[4]
-#define I2CCCR &I2C_Addr[8]
-#define I2CCSR &I2C_Addr[12]
-#define I2CCDR &I2C_Addr[16]
-#define I2CDFSRR &I2C_Addr[20]
-
-#define I2C_READ 1
-#define I2C_WRITE 0
-
-void
-i2c_init(int speed, int slaveadd)
-{
- /* stop I2C controller */
- writeb(0x0, I2CCCR);
-
- /* set clock */
- writeb(0x3f, I2CFDR);
-
- /* set default filter */
- writeb(0x10,I2CDFSRR);
-
- /* write slave address */
- writeb(slaveadd, I2CADR);
-
- /* clear status register */
- writeb(0x0, I2CCSR);
-
- /* start I2C controller */
- writeb(MPC85xx_I2CCR_MEN, I2CCCR);
-}
-
-static __inline__ int
-i2c_wait4bus (void)
-{
- ulong timeval = get_timer (0);
-
- while (readb(I2CCSR) & MPC85xx_I2CSR_MBB) {
- if (get_timer (timeval) > TIMEOUT) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static __inline__ int
-i2c_wait (int write)
-{
- u32 csr;
- ulong timeval = get_timer (0);
-
- do {
- csr = readb(I2CCSR);
-
- if (!(csr & MPC85xx_I2CSR_MIF))
- continue;
-
- writeb(0x0, I2CCSR);
-
- if (csr & MPC85xx_I2CSR_MAL) {
- debug("i2c_wait: MAL\n");
- return -1;
- }
-
- if (!(csr & MPC85xx_I2CSR_MCF)) {
- debug("i2c_wait: unfinished\n");
- return -1;
- }
-
- if (write == I2C_WRITE && (csr & MPC85xx_I2CSR_RXAK)) {
- debug("i2c_wait: No RXACK\n");
- return -1;
- }
-
- return 0;
- } while (get_timer (timeval) < TIMEOUT);
-
- debug("i2c_wait: timed out\n");
- return -1;
-}
-
-static __inline__ int
-i2c_write_addr (u8 dev, u8 dir, int rsta)
-{
- writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX |
- (rsta?MPC85xx_I2CCR_RSTA:0),
- I2CCCR);
-
- writeb((dev << 1) | dir, I2CCDR);
-
- if (i2c_wait (I2C_WRITE) < 0)
- return 0;
-
- return 1;
-}
-
-static __inline__ int
-__i2c_write (u8 *data, int length)
-{
- int i;
-
- writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX,
- I2CCCR);
-
- for (i=0; i < length; i++) {
- writeb(data[i], I2CCDR);
-
- if (i2c_wait (I2C_WRITE) < 0)
- break;
- }
-
- return i;
-}
-
-static __inline__ int
-__i2c_read (u8 *data, int length)
-{
- int i;
-
- writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA |
- ((length == 1) ? MPC85xx_I2CCR_TXAK : 0),
- I2CCCR);
-
- /* dummy read */
- readb(I2CCDR);
-
- for (i=0; i < length; i++) {
- if (i2c_wait (I2C_READ) < 0)
- break;
-
- /* Generate ack on last next to last byte */
- if (i == length - 2)
- writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA |
- MPC85xx_I2CCR_TXAK,
- I2CCCR);
-
- /* Generate stop on last byte */
- if (i == length - 1)
- writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_TXAK, I2CCCR);
-
- data[i] = readb(I2CCDR);
- }
-
- return i;
-}
-
-int
-i2c_read (u8 dev, uint addr, int alen, u8 *data, int length)
-{
- int i = 0;
- u8 *a = (u8*)&addr;
-
- if (i2c_wait4bus () < 0)
- goto exit;
-
- if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
- goto exit;
-
- if (__i2c_write (&a[4 - alen], alen) != alen)
- goto exit;
-
- if (i2c_write_addr (dev, I2C_READ, 1) == 0)
- goto exit;
-
- i = __i2c_read (data, length);
-
- exit:
- writeb(MPC85xx_I2CCR_MEN, I2CCCR);
-
- return !(i == length);
-}
-
-int
-i2c_write (u8 dev, uint addr, int alen, u8 *data, int length)
-{
- int i = 0;
- u8 *a = (u8*)&addr;
-
- if (i2c_wait4bus () < 0)
- goto exit;
-
- if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
- goto exit;
-
- if (__i2c_write (&a[4 - alen], alen) != alen)
- goto exit;
-
- i = __i2c_write (data, length);
-
- exit:
- writeb(MPC85xx_I2CCR_MEN, I2CCCR);
-
- return !(i == length);
-}
-
-int i2c_probe (uchar chip)
-{
- int tmp;
-
- /*
- * Try to read the first location of the chip. The underlying
- * driver doesn't appear to support sending just the chip address
- * and looking for an <ACK> back.
- */
- udelay(10000);
- return i2c_read (chip, 0, 1, (uchar *)&tmp, 1);
-}
-
-uchar i2c_reg_read (uchar i2c_addr, uchar reg)
-{
- uchar buf[1];
-
- i2c_read (i2c_addr, reg, 1, buf, 1);
-
- return (buf[0]);
-}
-
-void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
-{
- i2c_write (i2c_addr, reg, 1, &val, 1);
-}
-
-#endif /* CONFIG_HARD_I2C */
diff --git a/cpu/mpc85xx/spd_sdram.c b/cpu/mpc85xx/spd_sdram.c
index af99282..6da5367 100644
--- a/cpu/mpc85xx/spd_sdram.c
+++ b/cpu/mpc85xx/spd_sdram.c
@@ -131,8 +131,8 @@ convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
800,
900,
250,
- 330, /* FIXME: Is 333 better/valid? */
- 660, /* FIXME: Is 667 better/valid? */
+ 330,
+ 660,
750,
0, /* undefined */
0 /* undefined */
@@ -146,6 +146,28 @@ convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
}
+/*
+ * Determine Refresh Rate. Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+unsigned int determine_refresh_rate(unsigned int spd_refresh)
+{
+ unsigned int refresh_time_ns[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return picos_to_clk(refresh_time_ns[spd_refresh & 0x7]);
+}
+
+
long int
spd_sdram(void)
{
@@ -157,6 +179,10 @@ spd_sdram(void)
unsigned int rank_density;
unsigned int odt_rd_cfg, odt_wr_cfg;
unsigned int odt_cfg, mode_odt_enable;
+ unsigned int refresh_clk;
+#ifdef MPC85xx_DDR_SDRAM_CLK_CNTL
+ unsigned char clk_adjust;
+#endif
unsigned int dqs_cfg;
unsigned char twr_clk, twtr_clk, twr_auto_clk;
unsigned int tCKmin_ps, tCKmax_ps;
@@ -740,38 +766,21 @@ spd_sdram(void)
ddr->sdram_mode_2 = 0;
debug("DDR: sdram_mode_2 = 0x%08x\n", ddr->sdram_mode_2);
-
/*
- * Determine Refresh Rate. Ignore self refresh bit on DDR I.
- * Table from SPD Spec, Byte 12, converted to picoseconds and
- * filled in with "default" normal values.
+ * Determine Refresh Rate.
*/
- {
- unsigned int refresh_clk;
- unsigned int refresh_time_ns[8] = {
- 15625000, /* 0 Normal 1.00x */
- 3900000, /* 1 Reduced .25x */
- 7800000, /* 2 Extended .50x */
- 31300000, /* 3 Extended 2.00x */
- 62500000, /* 4 Extended 4.00x */
- 125000000, /* 5 Extended 8.00x */
- 15625000, /* 6 Normal 1.00x filler */
- 15625000, /* 7 Normal 1.00x filler */
- };
-
- refresh_clk = picos_to_clk(refresh_time_ns[spd.refresh & 0x7]);
+ refresh_clk = determine_refresh_rate(spd.refresh & 0x7);
- /*
- * Set BSTOPRE to 0x100 for page mode
- * If auto-charge is used, set BSTOPRE = 0
- */
- ddr->sdram_interval =
- (0
- | (refresh_clk & 0x3fff) << 16
- | 0x100
- );
- debug("DDR: sdram_interval = 0x%08x\n", ddr->sdram_interval);
- }
+ /*
+ * Set BSTOPRE to 0x100 for page mode
+ * If auto-charge is used, set BSTOPRE = 0
+ */
+ ddr->sdram_interval =
+ (0
+ | (refresh_clk & 0x3fff) << 16
+ | 0x100
+ );
+ debug("DDR: sdram_interval = 0x%08x\n", ddr->sdram_interval);
/*
* Is this an ECC DDR chip?
@@ -835,28 +844,23 @@ spd_sdram(void)
#ifdef MPC85xx_DDR_SDRAM_CLK_CNTL
- {
- unsigned char clk_adjust;
-
- /*
- * Setup the clock control.
- * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1
- * SDRAM_CLK_CNTL[5-7] = Clock Adjust
- * 0110 3/4 cycle late
- * 0111 7/8 cycle late
- */
- if (spd.mem_type == SPD_MEMTYPE_DDR) {
- clk_adjust = 0x6;
- } else {
- clk_adjust = 0x7;
- }
+ /*
+ * Setup the clock control.
+ * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1
+ * SDRAM_CLK_CNTL[5-7] = Clock Adjust
+ * 0110 3/4 cycle late
+ * 0111 7/8 cycle late
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ clk_adjust = 0x6;
+ else
+ clk_adjust = 0x7;
- ddr->sdram_clk_cntl = (0
+ ddr->sdram_clk_cntl = (0
| 0x80000000
| (clk_adjust << 23)
);
- debug("DDR: sdram_clk_cntl = 0x%08x\n", ddr->sdram_clk_cntl);
- }
+ debug("DDR: sdram_clk_cntl = 0x%08x\n", ddr->sdram_clk_cntl);
#endif
/*
@@ -1081,26 +1085,16 @@ ddr_enable_ecc(unsigned int dram_size)
}
}
- /* 8K */
- dma_xfer((uint *)0x2000, 0x2000, (uint *)0);
- /* 16K */
- dma_xfer((uint *)0x4000, 0x4000, (uint *)0);
- /* 32K */
- dma_xfer((uint *)0x8000, 0x8000, (uint *)0);
- /* 64K */
- dma_xfer((uint *)0x10000, 0x10000, (uint *)0);
- /* 128k */
- dma_xfer((uint *)0x20000, 0x20000, (uint *)0);
- /* 256k */
- dma_xfer((uint *)0x40000, 0x40000, (uint *)0);
- /* 512k */
- dma_xfer((uint *)0x80000, 0x80000, (uint *)0);
- /* 1M */
- dma_xfer((uint *)0x100000, 0x100000, (uint *)0);
- /* 2M */
- dma_xfer((uint *)0x200000, 0x200000, (uint *)0);
- /* 4M */
- dma_xfer((uint *)0x400000, 0x400000, (uint *)0);
+ dma_xfer((uint *)0x002000, 0x002000, (uint *)0); /* 8K */
+ dma_xfer((uint *)0x004000, 0x004000, (uint *)0); /* 16K */
+ dma_xfer((uint *)0x008000, 0x008000, (uint *)0); /* 32K */
+ dma_xfer((uint *)0x010000, 0x010000, (uint *)0); /* 64K */
+ dma_xfer((uint *)0x020000, 0x020000, (uint *)0); /* 128k */
+ dma_xfer((uint *)0x040000, 0x040000, (uint *)0); /* 256k */
+ dma_xfer((uint *)0x080000, 0x080000, (uint *)0); /* 512k */
+ dma_xfer((uint *)0x100000, 0x100000, (uint *)0); /* 1M */
+ dma_xfer((uint *)0x200000, 0x200000, (uint *)0); /* 2M */
+ dma_xfer((uint *)0x400000, 0x400000, (uint *)0); /* 4M */
for (i = 1; i < dram_size / 0x800000; i++) {
dma_xfer((uint *)(0x800000*i), 0x800000, (uint *)0);
diff --git a/cpu/mpc86xx/Makefile b/cpu/mpc86xx/Makefile
new file mode 100644
index 0000000..de5561e
--- /dev/null
+++ b/cpu/mpc86xx/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao,X.Xiao@motorola.com
+#
+# (C) Copyright 2004 Freescale Semiconductor. (MC86xx Port)
+# Jeff Brown
+# 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 #resetvec.o
+SOBJS = cache.o
+COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \
+ pci.o pcie_indirect.o spd_sdram.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $(ASOBJS) $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/mpc86xx/cache.S b/cpu/mpc86xx/cache.S
new file mode 100644
index 0000000..f316b3e
--- /dev/null
+++ b/cpu/mpc86xx/cache.S
@@ -0,0 +1,374 @@
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE L1_CACHE_BYTES
+#endif
+
+#if CACHE_LINE_SIZE == 128
+#define LG_CACHE_LINE_SIZE 7
+#elif CACHE_LINE_SIZE == 32
+#define LG_CACHE_LINE_SIZE 5
+#elif CACHE_LINE_SIZE == 16
+#define LG_CACHE_LINE_SIZE 4
+#elif CACHE_LINE_SIZE == 8
+#define LG_CACHE_LINE_SIZE 3
+#else
+# error "Invalid cache line size!"
+#endif
+
+/*
+ * Most of this code is taken from 74xx_7xx/cache.S
+ * and then cleaned up a bit
+ */
+
+/*
+ * Invalidate L1 instruction cache.
+ */
+_GLOBAL(invalidate_l1_instruction_cache)
+ /* use invalidate-all bit in HID0 */
+ mfspr r3,HID0
+ ori r3,r3,HID0_ICFI
+ mtspr HID0,r3
+ isync
+ blr
+
+/*
+ * Invalidate L1 data cache.
+ */
+_GLOBAL(invalidate_l1_data_cache)
+ mfspr r3,HID0
+ ori r3,r3,HID0_DCFI
+ mtspr HID0,r3
+ isync
+ blr
+
+/*
+ * Flush data cache.
+ */
+_GLOBAL(flush_data_cache)
+ lis r3,0
+ lis r5,CACHE_LINE_SIZE
+flush:
+ cmp 0,1,r3,r5
+ bge done
+ lwz r5,0(r3)
+ lis r5,CACHE_LINE_SIZE
+ addi r3,r3,0x4
+ b flush
+done:
+ blr
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync /* additional sync needed on g4 */
+ isync
+ blr
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5 /* align r3 down to cache line */
+ subf r4,r3,r4 /* r4 = offset of stop from start of cache line */
+ add r4,r4,r5 /* r4 += cache_line_size-1 */
+ srwi. r4,r4,LG_CACHE_LINE_SIZE /* r4 = number of cache lines to flush */
+ beqlr /* if r4 == 0 return */
+ mtctr r4 /* ctr = r4 */
+
+ sync
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+ sync
+1: dcbf 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbf's to get to ram */
+ blr
+
+/*
+ * Like above, but invalidate the D-cache. This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+ sync
+1: dcbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbi's to get to ram */
+ blr
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ * void __flush_page_to_ram(void *page)
+ */
+_GLOBAL(__flush_page_to_ram)
+ rlwinm r3,r3,0,0,19 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+ mr r6,r3
+0: dcbst 0,r3 /* Write line to ram */
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 0b
+ sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Flush a particular page from the instruction cache.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ * void __flush_icache_page(void *page)
+ */
+_GLOBAL(__flush_icache_page)
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+1: icbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced). This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+1: dcbz 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ blr
+
+/*
+ * Enable L1 Instruction cache
+ */
+_GLOBAL(icache_enable)
+ mfspr r3, HID0
+ li r5, HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r5
+ ori r3, r3, HID0_ICE
+ ori r5, r3, HID0_ICFI
+ mtspr HID0, r5
+ mtspr HID0, r3
+ isync
+ blr
+
+/*
+ * Disable L1 Instruction cache
+ */
+_GLOBAL(icache_disable)
+ mfspr r3, HID0
+ li r5, 0
+ ori r5, r5, HID0_ICE
+ andc r3, r3, r5
+ mtspr HID0, r3
+ isync
+ blr
+
+/*
+ * Is instruction cache enabled?
+ */
+_GLOBAL(icache_status)
+ mfspr r3, HID0
+ andi. r3, r3, HID0_ICE
+ blr
+
+
+_GLOBAL(l1dcache_enable)
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+ blr
+
+/*
+ * Enable data cache(s) - L1 and optionally L2
+ * Calls l2cache_enable. LR saved in r5
+ */
+_GLOBAL(dcache_enable)
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+#ifdef CFG_L2
+ mflr r5
+ bl l2cache_enable /* uses r3 and r4 */
+ sync
+ mtlr r5
+#endif
+ blr
+
+
+/*
+ * Disable data cache(s) - L1 and optionally L2
+ * Calls flush_data_cache and l2cache_disable_no_flush.
+ * LR saved in r4
+ */
+_GLOBAL(dcache_disable)
+ mflr r4 /* save link register */
+ bl flush_data_cache /* uses r3 and r5 */
+ sync
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ li r5, HID0_DCE|HID0_DCFI
+ andc r3, r3, r5 /* no enable, no invalidate */
+ mtspr HID0, r3
+ sync
+#ifdef CFG_L2
+ bl l2cache_disable_no_flush /* uses r3 */
+#endif
+ mtlr r4 /* restore link register */
+ blr
+
+/*
+ * Is data cache enabled?
+ */
+_GLOBAL(dcache_status)
+ mfspr r3, HID0
+ andi. r3, r3, HID0_DCE
+ blr
+
+/*
+ * Invalidate L2 cache using L2I, assume L2 is enabled
+ */
+_GLOBAL(l2cache_invalidate)
+ mfspr r3, l2cr
+ rlwinm. r3, r3, 0, 0, 0
+ beq 1f
+
+ mfspr r3, l2cr
+ rlwinm r3, r3, 0, 1, 31
+
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ sync
+ mtspr l2cr, r3
+ sync
+1: mfspr r3, l2cr
+ oris r3, r3, L2CR_L2I@h
+ mtspr l2cr, r3
+
+invl2:
+ mfspr r3, l2cr
+ andi. r3, r3, L2CR_L2I@h
+ bne invl2
+ blr
+
+/*
+ * Enable L2 cache
+ * Calls l2cache_invalidate. LR is saved in r4
+ */
+_GLOBAL(l2cache_enable)
+ mflr r4 /* save link register */
+ bl l2cache_invalidate /* uses r3 */
+ sync
+ lis r3, L2_ENABLE@h
+ ori r3, r3, L2_ENABLE@l
+ mtspr l2cr, r3
+ isync
+ mtlr r4 /* restore link register */
+ blr
+
+/*
+ * Disable L2 cache
+ * Calls flush_data_cache. LR is saved in r4
+ */
+_GLOBAL(l2cache_disable)
+ mflr r4 /* save link register */
+ bl flush_data_cache /* uses r3 and r5 */
+ sync
+ mtlr r4 /* restore link register */
+l2cache_disable_no_flush: /* provide way to disable L2 w/o flushing */
+ lis r3, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ mtspr l2cr, r3
+ isync
+ blr
diff --git a/cpu/mpc86xx/config.mk b/cpu/mpc86xx/config.mk
new file mode 100644
index 0000000..3c54f4a
--- /dev/null
+++ b/cpu/mpc86xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2004 Freescale Semiconductor.
+# Jeff Brown
+#
+# 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 += -fPIC -ffixed-r14 -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC86xx -ffixed-r2 -ffixed-r29 -mstring
diff --git a/cpu/mpc86xx/cpu.c b/cpu/mpc86xx/cpu.c
new file mode 100644
index 0000000..551b243
--- /dev/null
+++ b/cpu/mpc86xx/cpu.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2006 Freescale Semiconductor
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.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 <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <mpc86xx.h>
+
+#if defined(CONFIG_OF_FLAT_TREE)
+#include <ft_build.h>
+#endif
+
+#ifdef CONFIG_MPC8641HPCN
+extern void mpc8641_reset_board(cmd_tbl_t *cmdtp, int flag,
+ int argc, char *argv[]);
+#endif
+
+
+int
+checkcpu(void)
+{
+ sys_info_t sysinfo;
+ uint pvr, svr;
+ uint ver;
+ uint major, minor;
+ uint lcrr; /* local bus clock ratio register */
+ uint clkdiv; /* clock divider portion of lcrr */
+
+ puts("Freescale PowerPC\n");
+
+ pvr = get_pvr();
+ ver = PVR_VER(pvr);
+ major = PVR_MAJ(pvr);
+ minor = PVR_MIN(pvr);
+
+ puts("CPU:\n");
+ puts(" Core: ");
+
+ switch (ver) {
+ case PVR_VER(PVR_86xx):
+ puts("E600");
+ break;
+ default:
+ puts("Unknown");
+ break;
+ }
+ printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr);
+
+ svr = get_svr();
+ ver = SVR_VER(svr);
+ major = SVR_MAJ(svr);
+ minor = SVR_MIN(svr);
+
+ puts(" System: ");
+ switch (ver) {
+ case SVR_8641:
+ if (SVR_SUBVER(svr) == 1) {
+ puts("8641D");
+ } else {
+ puts("8641");
+ }
+ break;
+ default:
+ puts("Unknown");
+ break;
+ }
+ printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
+
+ get_sys_info(&sysinfo);
+
+ puts(" Clocks: ");
+ printf("CPU:%4lu MHz, ", sysinfo.freqProcessor / 1000000);
+ printf("MPX:%4lu MHz, ", sysinfo.freqSystemBus / 1000000);
+ printf("DDR:%4lu MHz, ", sysinfo.freqSystemBus / 2000000);
+
+#if defined(CFG_LBC_LCRR)
+ lcrr = CFG_LBC_LCRR;
+#else
+ {
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ccsr_lbc_t *lbc = &immap->im_lbc;
+
+ lcrr = lbc->lcrr;
+ }
+#endif
+ clkdiv = lcrr & 0x0f;
+ if (clkdiv == 2 || clkdiv == 4 || clkdiv == 8) {
+ printf("LBC:%4lu MHz\n",
+ sysinfo.freqSystemBus / 1000000 / clkdiv);
+ } else {
+ printf(" LBC: unknown (lcrr: 0x%08x)\n", lcrr);
+ }
+
+ puts(" L2: ");
+ if (get_l2cr() & 0x80000000)
+ puts("Enabled\n");
+ else
+ puts("Disabled\n");
+
+ return 0;
+}
+
+
+static inline void
+soft_restart(unsigned long addr)
+{
+#ifndef CONFIG_MPC8641HPCN
+
+ /*
+ * SRR0 has system reset vector, SRR1 has default MSR value
+ * rfi restores MSR from SRR1 and sets the PC to the SRR0 value
+ */
+
+ __asm__ __volatile__ ("mtspr 26, %0" :: "r" (addr));
+ __asm__ __volatile__ ("li 4, (1 << 6)" ::: "r4");
+ __asm__ __volatile__ ("mtspr 27, 4");
+ __asm__ __volatile__ ("rfi");
+
+#else /* CONFIG_MPC8641HPCN */
+
+ out8(PIXIS_BASE + PIXIS_RST, 0);
+
+#endif /* !CONFIG_MPC8641HPCN */
+
+ while (1) ; /* not reached */
+}
+
+
+/*
+ * No generic way to do board reset. Simply call soft_reset.
+ */
+void
+do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#ifndef CONFIG_MPC8641HPCN
+
+#ifdef CFG_RESET_ADDRESS
+ ulong addr = CFG_RESET_ADDRESS;
+#else
+ /*
+ * note: when CFG_MONITOR_BASE points to a RAM address,
+ * CFG_MONITOR_BASE - sizeof (ulong) is usually a valid
+ * address. Better pick an address known to be invalid on your
+ * system and assign it to CFG_RESET_ADDRESS.
+ */
+ ulong addr = CFG_MONITOR_BASE - sizeof(ulong);
+#endif
+
+ /* flush and disable I/D cache */
+ __asm__ __volatile__ ("mfspr 3, 1008" ::: "r3");
+ __asm__ __volatile__ ("ori 5, 5, 0xcc00" ::: "r5");
+ __asm__ __volatile__ ("ori 4, 3, 0xc00" ::: "r4");
+ __asm__ __volatile__ ("andc 5, 3, 5" ::: "r5");
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("mtspr 1008, 4");
+ __asm__ __volatile__ ("isync");
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("mtspr 1008, 5");
+ __asm__ __volatile__ ("isync");
+ __asm__ __volatile__ ("sync");
+
+ soft_restart(addr);
+
+#else /* CONFIG_MPC8641HPCN */
+
+ mpc8641_reset_board(cmdtp, flag, argc, argv);
+
+#endif /* !CONFIG_MPC8641HPCN */
+
+ while (1) ; /* not reached */
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long
+get_tbclk(void)
+{
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ return (sys_info.freqSystemBus + 3L) / 4L;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+watchdog_reset(void)
+{
+}
+#endif /* CONFIG_WATCHDOG */
+
+
+#if defined(CONFIG_DDR_ECC)
+void
+dma_init(void)
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ccsr_dma_t *dma = &immap->im_dma;
+
+ dma->satr0 = 0x00040000;
+ dma->datr0 = 0x00040000;
+ asm("sync; isync");
+}
+
+uint
+dma_check(void)
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ccsr_dma_t *dma = &immap->im_dma;
+ volatile uint status = dma->sr0;
+
+ /* While the channel is busy, spin */
+ while ((status & 4) == 4) {
+ status = dma->sr0;
+ }
+
+ if (status != 0) {
+ printf("DMA Error: status = %x\n", status);
+ }
+ return status;
+}
+
+int
+dma_xfer(void *dest, uint count, void *src)
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ccsr_dma_t *dma = &immap->im_dma;
+
+ dma->dar0 = (uint) dest;
+ dma->sar0 = (uint) src;
+ dma->bcr0 = count;
+ dma->mr0 = 0xf000004;
+ asm("sync;isync");
+ dma->mr0 = 0xf000005;
+ asm("sync;isync");
+ return dma_check();
+}
+
+#endif /* CONFIG_DDR_ECC */
+
+
+#ifdef CONFIG_OF_FLAT_TREE
+void
+ft_cpu_setup(void *blob, bd_t *bd)
+{
+ u32 *p;
+ ulong clock;
+ int len;
+
+ clock = bd->bi_busfreq;
+ p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len);
+ if (p != NULL)
+ *p = cpu_to_be32(clock);
+
+ p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len);
+ if (p != NULL)
+ *p = cpu_to_be32(clock);
+
+ p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len);
+ if (p != NULL)
+ *p = cpu_to_be32(clock);
+
+#if defined(CONFIG_MPC86XX_TSEC1)
+ p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len);
+ memcpy(p, bd->bi_enetaddr, 6);
+#endif
+
+#if defined(CONFIG_MPC86XX_TSEC2)
+ p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len);
+ memcpy(p, bd->bi_enet1addr, 6);
+#endif
+
+#if defined(CONFIG_MPC86XX_TSEC3)
+ p = ft_get_prop(blob, "/" OF_SOC "/ethernet@26000/mac-address", &len);
+ memcpy(p, bd->bi_enet2addr, 6);
+#endif
+
+#if defined(CONFIG_MPC86XX_TSEC4)
+ p = ft_get_prop(blob, "/" OF_SOC "/ethernet@27000/mac-address", &len);
+ memcpy(p, bd->bi_enet3addr, 6);
+#endif
+
+}
+#endif
diff --git a/cpu/mpc86xx/cpu_init.c b/cpu/mpc86xx/cpu_init.c
new file mode 100644
index 0000000..4673d05
--- /dev/null
+++ b/cpu/mpc86xx/cpu_init.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.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
+ */
+
+/*
+ * cpu_init.c - low level cpu init
+ */
+
+#include <common.h>
+#include <mpc86xx.h>
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map
+ * initialize a bunch of registers
+ */
+
+void cpu_init_f(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile ccsr_lbc_t *memctl = &immap->im_lbc;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+ * addresses - these have to be modified later when FLASH size
+ * has been determined
+ */
+
+#if defined(CFG_OR0_REMAP)
+ memctl->or0 = CFG_OR0_REMAP;
+#endif
+#if defined(CFG_OR1_REMAP)
+ memctl->or1 = CFG_OR1_REMAP;
+#endif
+
+ /* now restrict to preliminary range */
+#if defined(CFG_BR0_PRELIM) && defined(CFG_OR0_PRELIM)
+ memctl->br0 = CFG_BR0_PRELIM;
+ memctl->or0 = CFG_OR0_PRELIM;
+#endif
+
+#if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM)
+ memctl->or1 = CFG_OR1_PRELIM;
+ memctl->br1 = CFG_BR1_PRELIM;
+#endif
+
+#if defined(CFG_BR2_PRELIM) && defined(CFG_OR2_PRELIM)
+ memctl->or2 = CFG_OR2_PRELIM;
+ memctl->br2 = CFG_BR2_PRELIM;
+#endif
+
+#if defined(CFG_BR3_PRELIM) && defined(CFG_OR3_PRELIM)
+ memctl->or3 = CFG_OR3_PRELIM;
+ memctl->br3 = CFG_BR3_PRELIM;
+#endif
+
+#if defined(CFG_BR4_PRELIM) && defined(CFG_OR4_PRELIM)
+ memctl->or4 = CFG_OR4_PRELIM;
+ memctl->br4 = CFG_BR4_PRELIM;
+#endif
+
+#if defined(CFG_BR5_PRELIM) && defined(CFG_OR5_PRELIM)
+ memctl->or5 = CFG_OR5_PRELIM;
+ memctl->br5 = CFG_BR5_PRELIM;
+#endif
+
+#if defined(CFG_BR6_PRELIM) && defined(CFG_OR6_PRELIM)
+ memctl->or6 = CFG_OR6_PRELIM;
+ memctl->br6 = CFG_BR6_PRELIM;
+#endif
+
+#if defined(CFG_BR7_PRELIM) && defined(CFG_OR7_PRELIM)
+ memctl->or7 = CFG_OR7_PRELIM;
+ memctl->br7 = CFG_BR7_PRELIM;
+#endif
+
+ /* enable the timebase bit in HID0 */
+ set_hid0(get_hid0() | 0x4000000);
+
+ /* enable SYNCBE | ABE bits in HID1 */
+ set_hid1(get_hid1() | 0x00000C00);
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r(void)
+{
+ return 0;
+}
diff --git a/cpu/mpc86xx/interrupts.c b/cpu/mpc86xx/interrupts.c
new file mode 100644
index 0000000..1df6cdc
--- /dev/null
+++ b/cpu/mpc86xx/interrupts.c
@@ -0,0 +1,204 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 Motorola Inc. (MPC85xx port)
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * (C) Copyright 2004 Freescale Semiconductor. (MPC86xx Port)
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.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 <mpc86xx.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <ppc_asm.tmpl>
+
+unsigned long decrementer_count; /* count value for 1e6/HZ microseconds */
+unsigned long timestamp;
+
+
+static __inline__ unsigned long get_msr(void)
+{
+ unsigned long msr;
+
+ asm volatile ("mfmsr %0":"=r" (msr):);
+
+ return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+ asm volatile ("mtmsr %0"::"r" (msr));
+}
+
+static __inline__ unsigned long get_dec(void)
+{
+ unsigned long val;
+
+ asm volatile ("mfdec %0":"=r" (val):);
+
+ return val;
+}
+
+static __inline__ void set_dec(unsigned long val)
+{
+ if (val)
+ asm volatile ("mtdec %0"::"r" (val));
+}
+
+/* interrupt is not supported yet */
+int interrupt_init_cpu(unsigned *decrementer_count)
+{
+ return 0;
+}
+
+int interrupt_init(void)
+{
+ int ret;
+
+ /* call cpu specific function from $(CPU)/interrupts.c */
+ ret = interrupt_init_cpu(&decrementer_count);
+
+ if (ret)
+ return ret;
+
+ decrementer_count = get_tbclk() / CFG_HZ;
+ debug("interrupt init: tbclk() = %d MHz, decrementer_count = %d\n",
+ (get_tbclk() / 1000000),
+ decrementer_count);
+
+ set_dec(decrementer_count);
+
+ set_msr(get_msr() | MSR_EE);
+
+ debug("MSR = 0x%08lx, Decrementer reg = 0x%08lx\n",
+ get_msr(),
+ get_dec());
+
+ return 0;
+}
+
+void enable_interrupts(void)
+{
+ set_msr(get_msr() | MSR_EE);
+}
+
+/* returns flag if MSR_EE was set before */
+int disable_interrupts(void)
+{
+ ulong msr = get_msr();
+
+ set_msr(msr & ~MSR_EE);
+ return (msr & MSR_EE) != 0;
+}
+
+void increment_timestamp(void)
+{
+ timestamp++;
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+ /* nothing to do here */
+}
+
+void timer_interrupt(struct pt_regs *regs)
+{
+ /* call cpu specific function from $(CPU)/interrupts.c */
+ timer_interrupt_cpu(regs);
+
+ timestamp++;
+
+ ppcDcbf(&timestamp);
+
+ /* Restore Decrementer Count */
+ set_dec(decrementer_count);
+
+#if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG)
+ if ((timestamp % (CFG_WATCHDOG_FREQ)) == 0)
+ WATCHDOG_RESET();
+#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
+
+#ifdef CONFIG_STATUS_LED
+ status_led_tick(timestamp);
+#endif /* CONFIG_STATUS_LED */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+ board_show_activity(timestamp);
+#endif /* CONFIG_SHOW_ACTIVITY */
+
+}
+
+void reset_timer(void)
+{
+ timestamp = 0;
+}
+
+ulong get_timer(ulong base)
+{
+ return timestamp - base;
+}
+
+void set_timer(ulong t)
+{
+ timestamp = t;
+}
+
+/*
+ * Install and free a interrupt handler. Not implemented yet.
+ */
+
+void irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+}
+
+void irq_free_handler(int vec)
+{
+}
+
+/*
+ * irqinfo - print information about PCI devices,not implemented.
+ */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ printf("\nInterrupt-unsupported:\n");
+
+ return 0;
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+ puts("external_interrupt (oops!)\n");
+}
diff --git a/cpu/mpc86xx/pci.c b/cpu/mpc86xx/pci.c
new file mode 100644
index 0000000..b86548d
--- /dev/null
+++ b/cpu/mpc86xx/pci.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) Freescale Semiconductor,Inc.
+ * 2005, 2006. All rights reserved.
+ *
+ * Ed Swarthout (ed.swarthout@freescale.com)
+ * Jason Jin (Jason.jin@freescale.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
+ */
+
+/*
+ * PCIE Configuration space access support for PCIE Bridge
+ */
+#include <common.h>
+#include <pci.h>
+
+#if defined(CONFIG_PCI)
+void
+pci_mpc86xx_init(struct pci_controller *hose)
+{
+ volatile immap_t *immap = (immap_t *) CFG_CCSRBAR;
+ volatile ccsr_pex_t *pcie1 = &immap->im_pex1;
+ u16 temp16;
+ u32 temp32;
+
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+ uint host1_agent = (gur->porbmsr & MPC86xx_PORBMSR_HA) >> 17;
+ uint pcie1_host = (host1_agent == 2) || (host1_agent == 3);
+ uint pcie1_agent = (host1_agent == 0) || (host1_agent == 1);
+ uint devdisr = gur->devdisr;
+ uint io_sel = (gur->pordevsr & MPC86xx_PORDEVSR_IO_SEL) >> 16;
+
+ if ((io_sel == 2 || io_sel == 3 || io_sel == 5 || io_sel == 6 ||
+ io_sel == 7 || io_sel == 0xf)
+ && !(devdisr & MPC86xx_DEVDISR_PCIEX1)) {
+ printf("PCI-EXPRESS 1: Configured as %s \n",
+ pcie1_agent ? "Agent" : "Host");
+ if (pcie1_agent)
+ return; /*Don't scan bus when configured as agent */
+ printf(" Scanning PCIE bus");
+ debug("0x%08x=0x%08x ",
+ &pcie1->pme_msg_det,
+ pcie1->pme_msg_det);
+ if (pcie1->pme_msg_det) {
+ pcie1->pme_msg_det = 0xffffffff;
+ debug(" with errors. Clearing. Now 0x%08x",
+ pcie1->pme_msg_det);
+ }
+ debug("\n");
+ } else {
+ printf("PCI-EXPRESS 1 disabled!\n");
+ return;
+ }
+
+ /*
+ * Set first_bus=0 only skipped B0:D0:F0 which is
+ * a reserved device in M1575, but make it easy for
+ * most of the scan process.
+ */
+ hose->first_busno = 0x00;
+ hose->last_busno = 0xfe;
+
+ pcie_setup_indirect(hose, (CFG_IMMR + 0x8000), (CFG_IMMR + 0x8004));
+
+ pci_hose_read_config_word(hose,
+ PCI_BDF(0, 0, 0), PCI_COMMAND, &temp16);
+ temp16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ pci_hose_write_config_word(hose,
+ PCI_BDF(0, 0, 0), PCI_COMMAND, temp16);
+
+ pci_hose_write_config_word(hose, PCI_BDF(0, 0, 0), PCI_STATUS, 0xffff);
+ pci_hose_write_config_byte(hose,
+ PCI_BDF(0, 0, 0), PCI_LATENCY_TIMER, 0x80);
+
+ pci_hose_read_config_dword(hose, PCI_BDF(0, 0, 0), PCI_PRIMARY_BUS,
+ &temp32);
+ temp32 = (temp32 & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16);
+ pci_hose_write_config_dword(hose, PCI_BDF(0, 0, 0), PCI_PRIMARY_BUS,
+ temp32);
+
+ pcie1->powar1 = 0;
+ pcie1->powar2 = 0;
+ pcie1->piwar1 = 0;
+ pcie1->piwar1 = 0;
+
+ pcie1->powbar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff;
+ pcie1->powar1 = 0x8004401c; /* 512M MEM space */
+ pcie1->potar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff;
+ pcie1->potear1 = 0x00000000;
+
+ pcie1->powbar2 = (CFG_PCI1_IO_BASE >> 12) & 0x000fffff;
+ pcie1->powar2 = 0x80088017; /* 16M IO space */
+ pcie1->potar2 = 0x00000000;
+ pcie1->potear2 = 0x00000000;
+
+ pcie1->pitar1 = 0x00000000;
+ pcie1->piwbar1 = 0x00000000;
+ /* Enable, Prefetch, Local Mem, * Snoop R/W, 2G */
+ pcie1->piwar1 = 0xa0f5501e;
+
+ pci_set_region(hose->regions + 0,
+ CFG_PCI_MEMORY_BUS,
+ CFG_PCI_MEMORY_PHYS,
+ CFG_PCI_MEMORY_SIZE,
+ PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+ pci_set_region(hose->regions + 1,
+ CFG_PCI1_MEM_BASE,
+ CFG_PCI1_MEM_PHYS,
+ CFG_PCI1_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ pci_set_region(hose->regions + 2,
+ CFG_PCI1_IO_BASE,
+ CFG_PCI1_IO_PHYS,
+ CFG_PCI1_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_register_hose(hose);
+
+ hose->last_busno = pci_hose_scan(hose);
+ debug("pcie_mpc86xx_init: last_busno %x\n", hose->last_busno);
+ debug("pcie_mpc86xx init: current_busno %x\n ", hose->current_busno);
+
+ printf("....PCIE1 scan & enumeration done\n");
+}
+#endif /* CONFIG_PCI */
diff --git a/cpu/mpc86xx/pcie_indirect.c b/cpu/mpc86xx/pcie_indirect.c
new file mode 100644
index 0000000..b00ad76
--- /dev/null
+++ b/cpu/mpc86xx/pcie_indirect.c
@@ -0,0 +1,199 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (c) Freescale Semiconductor, Inc.
+ * 2006. All rights reserved.
+ *
+ * Jason Jin <Jason.jin@freescale.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.
+ *
+ * partly derived from
+ * arch/powerpc/platforms/86xx/mpc86xx_pcie.c
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define PCI_CFG_OUT out_be32
+#define PEX_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff)
+
+static int
+indirect_read_config_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ int len,
+ u32 *val)
+{
+ int bus = PCI_BUS(dev);
+
+ volatile unsigned char *cfg_data;
+ u32 temp;
+
+ PEX_FIX;
+ if (bus == 0xff) {
+ PCI_CFG_OUT(hose->cfg_addr,
+ dev | (offset & 0xfc) | 0x80000001);
+ } else {
+ PCI_CFG_OUT(hose->cfg_addr,
+ dev | (offset & 0xfc) | 0x80000000);
+ }
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
+ cfg_data = hose->cfg_data;
+ PEX_FIX;
+ temp = in_le32((u32 *) cfg_data);
+ switch (len) {
+ case 1:
+ *val = (temp >> (((offset & 3)) * 8)) & 0xff;
+ break;
+ case 2:
+ *val = (temp >> (((offset & 3)) * 8)) & 0xffff;
+ break;
+ default:
+ *val = temp;
+ break;
+ }
+
+ return 0;
+}
+
+static int
+indirect_write_config_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ int len,
+ u32 val)
+{
+ int bus = PCI_BUS(dev);
+ volatile unsigned char *cfg_data;
+ u32 temp;
+
+ PEX_FIX;
+ if (bus == 0xff) {
+ PCI_CFG_OUT(hose->cfg_addr,
+ dev | (offset & 0xfc) | 0x80000001);
+ } else {
+ PCI_CFG_OUT(hose->cfg_addr,
+ dev | (offset & 0xfc) | 0x80000000);
+ }
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
+ cfg_data = hose->cfg_data;
+ switch (len) {
+ case 1:
+ PEX_FIX;
+ temp = in_le32((u32 *) cfg_data);
+ temp = (temp & ~(0xff << ((offset & 3) * 8))) |
+ (val << ((offset & 3) * 8));
+ PEX_FIX;
+ out_le32((u32 *) cfg_data, temp);
+ break;
+ case 2:
+ PEX_FIX;
+ temp = in_le32((u32 *) cfg_data);
+ temp = (temp & ~(0xffff << ((offset & 3) * 8)));
+ temp |= (val << ((offset & 3) * 8));
+ PEX_FIX;
+ out_le32((u32 *) cfg_data, temp);
+ break;
+ default:
+ PEX_FIX;
+ out_le32((u32 *) cfg_data, val);
+ break;
+ }
+ PEX_FIX;
+ return 0;
+}
+
+static int
+indirect_read_config_byte_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ u8 *val)
+{
+ u32 val32;
+ indirect_read_config_pcie(hose, dev, offset, 1, &val32);
+ *val = (u8) val32;
+ return 0;
+}
+
+static int
+indirect_read_config_word_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ u16 *val)
+{
+ u32 val32;
+ indirect_read_config_pcie(hose, dev, offset, 2, &val32);
+ *val = (u16) val32;
+ return 0;
+}
+
+static int
+indirect_read_config_dword_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ u32 *val)
+{
+ return indirect_read_config_pcie(hose, dev, offset, 4, val);
+}
+
+static int
+indirect_write_config_byte_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ u8 val)
+{
+ return indirect_write_config_pcie(hose, dev, offset, 1, (u32) val);
+}
+
+static int
+indirect_write_config_word_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ unsigned short val)
+{
+ return indirect_write_config_pcie(hose, dev, offset, 2, (u32) val);
+}
+
+static int
+indirect_write_config_dword_pcie(struct pci_controller *hose,
+ pci_dev_t dev,
+ int offset,
+ u32 val)
+{
+ return indirect_write_config_pcie(hose, dev, offset, 4, val);
+}
+
+void
+pcie_setup_indirect(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
+{
+ pci_set_ops(hose,
+ indirect_read_config_byte_pcie,
+ indirect_read_config_word_pcie,
+ indirect_read_config_dword_pcie,
+ indirect_write_config_byte_pcie,
+ indirect_write_config_word_pcie,
+ indirect_write_config_dword_pcie);
+
+ hose->cfg_addr = (unsigned int *)cfg_addr;
+ hose->cfg_data = (unsigned char *)cfg_data;
+}
+
+#endif /* CONFIG_PCI */
diff --git a/cpu/mpc86xx/resetvec.S b/cpu/mpc86xx/resetvec.S
new file mode 100644
index 0000000..9a552f6
--- /dev/null
+++ b/cpu/mpc86xx/resetvec.S
@@ -0,0 +1,2 @@
+ .section .resetvec,"ax"
+ b _start
diff --git a/cpu/mpc86xx/spd_sdram.c b/cpu/mpc86xx/spd_sdram.c
new file mode 100644
index 0000000..97bbf43
--- /dev/null
+++ b/cpu/mpc86xx/spd_sdram.c
@@ -0,0 +1,1324 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.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/processor.h>
+#include <i2c.h>
+#include <spd.h>
+#include <asm/mmu.h>
+
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+extern void dma_init(void);
+extern uint dma_check(void);
+extern int dma_xfer(void *dest, uint count, void *src);
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+
+#ifndef CFG_READ_SPD
+#define CFG_READ_SPD i2c_read
+#endif
+
+/*
+ * Only one of the following three should be 1; others should be 0
+ * By default the cache line interleaving is selected if
+ * the CONFIG_DDR_INTERLEAVE flag is defined
+ */
+#define CFG_PAGE_INTERLEAVING 0
+#define CFG_BANK_INTERLEAVING 0
+#define CFG_SUPER_BANK_INTERLEAVING 0
+
+/*
+ * Convert picoseconds into clock cycles (rounding up if needed).
+ */
+
+int
+picos_to_clk(int picos)
+{
+ int clks;
+
+ clks = picos / (2000000000 / (get_bus_freq(0) / 1000));
+ if (picos % (2000000000 / (get_bus_freq(0) / 1000)) != 0) {
+ clks++;
+ }
+
+ return clks;
+}
+
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ * DDR I DDR II
+ * Bit Size Size
+ * --- ----- ------
+ * 7 high 512MB 512MB
+ * 6 256MB 256MB
+ * 5 128MB 128MB
+ * 4 64MB 16GB
+ * 3 32MB 8GB
+ * 2 16MB 4GB
+ * 1 2GB 2GB
+ * 0 low 1GB 1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ */
+
+unsigned int
+compute_banksize(unsigned int mem_type, unsigned char row_dens)
+{
+ unsigned int bsize;
+
+ if (mem_type == SPD_MEMTYPE_DDR) {
+ /* Bottom 2 bits up to the top. */
+ bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24;
+ debug("DDR: DDR I rank density = 0x%08x\n", bsize);
+ } else {
+ /* Bottom 5 bits up to the top. */
+ bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)) << 27;
+ debug("DDR: DDR II rank density = 0x%08x\n", bsize);
+ }
+ return bsize;
+}
+
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II. No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+
+unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+ /*
+ * Table look up the lower nibble, allow DDR I & II.
+ */
+ unsigned int tenths_ps[16] = {
+ 0,
+ 100,
+ 200,
+ 300,
+ 400,
+ 500,
+ 600,
+ 700,
+ 800,
+ 900,
+ 250,
+ 330,
+ 660,
+ 750,
+ 0, /* undefined */
+ 0 /* undefined */
+ };
+
+ unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+ unsigned int tenth_ns = spd_val & 0x0F;
+ unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+ return ps;
+}
+
+
+/*
+ * Determine Refresh Rate. Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+unsigned int determine_refresh_rate(unsigned int spd_refresh)
+{
+ unsigned int refresh_time_ns[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return picos_to_clk(refresh_time_ns[spd_refresh & 0x7]);
+}
+
+
+long int
+spd_init(unsigned char i2c_address, unsigned int ddr_num,
+ unsigned int dimm_num, unsigned int start_addr)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile ccsr_ddr_t *ddr;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+ spd_eeprom_t spd;
+ unsigned int n_ranks;
+ unsigned int rank_density;
+ unsigned int odt_rd_cfg, odt_wr_cfg;
+ unsigned int odt_cfg, mode_odt_enable;
+ unsigned int refresh_clk;
+#ifdef MPC86xx_DDR_SDRAM_CLK_CNTL
+ unsigned char clk_adjust;
+#endif
+ unsigned int dqs_cfg;
+ unsigned char twr_clk, twtr_clk, twr_auto_clk;
+ unsigned int tCKmin_ps, tCKmax_ps;
+ unsigned int max_data_rate;
+ unsigned int busfreq;
+ unsigned sdram_cfg_1;
+ unsigned int memsize;
+ unsigned char caslat, caslat_ctrl;
+ unsigned int trfc, trfc_clk, trfc_low, trfc_high;
+ unsigned int trcd_clk;
+ unsigned int trtp_clk;
+ unsigned char cke_min_clk;
+ unsigned char add_lat;
+ unsigned char wr_lat;
+ unsigned char wr_data_delay;
+ unsigned char four_act;
+ unsigned char cpo;
+ unsigned char burst_len;
+ unsigned int mode_caslat;
+ unsigned char sdram_type;
+ unsigned char d_init;
+ unsigned int law_size;
+ volatile ccsr_local_mcm_t *mcm = &immap->im_local_mcm;
+ unsigned int tCycle_ps, modfreq;
+
+ if (ddr_num == 1)
+ ddr = &immap->im_ddr1;
+ else
+ ddr = &immap->im_ddr2;
+
+ /*
+ * Read SPD information.
+ */
+ debug("Performing SPD read at I2C address 0x%02lx\n",i2c_address);
+ memset((void *)&spd, 0, sizeof(spd));
+ CFG_READ_SPD(i2c_address, 0, 1, (uchar *) &spd, sizeof(spd));
+
+ /*
+ * Check for supported memory module types.
+ */
+ if (spd.mem_type != SPD_MEMTYPE_DDR &&
+ spd.mem_type != SPD_MEMTYPE_DDR2) {
+ debug("Warning: Unable to locate DDR I or DDR II module for DIMM %d of DDR controller %d.\n"
+ " Fundamental memory type is 0x%0x\n",
+ dimm_num,
+ ddr_num,
+ spd.mem_type);
+ return 0;
+ }
+
+ debug("\nFound memory of type 0x%02lx ", spd.mem_type);
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ debug("DDR I\n");
+ else
+ debug("DDR II\n");
+
+ /*
+ * These test gloss over DDR I and II differences in interpretation
+ * of bytes 3 and 4, but irrelevantly. Multiple asymmetric banks
+ * are not supported on DDR I; and not encoded on DDR II.
+ *
+ * Also note that the 8548 controller can support:
+ * 12 <= nrow <= 16
+ * and
+ * 8 <= ncol <= 11 (still, for DDR)
+ * 6 <= ncol <= 9 (for FCRAM)
+ */
+ if (spd.nrow_addr < 12 || spd.nrow_addr > 14) {
+ printf("DDR: Unsupported number of Row Addr lines: %d.\n",
+ spd.nrow_addr);
+ return 0;
+ }
+ if (spd.ncol_addr < 8 || spd.ncol_addr > 11) {
+ printf("DDR: Unsupported number of Column Addr lines: %d.\n",
+ spd.ncol_addr);
+ return 0;
+ }
+
+ /*
+ * Determine the number of physical banks controlled by
+ * different Chip Select signals. This is not quite the
+ * same as the number of DIMM modules on the board. Feh.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ n_ranks = spd.nrows;
+ } else {
+ n_ranks = (spd.nrows & 0x7) + 1;
+ }
+
+ debug("DDR: number of ranks = %d\n", n_ranks);
+
+ if (n_ranks > 2) {
+ printf("DDR: Only 2 chip selects are supported: %d\n",
+ n_ranks);
+ return 0;
+ }
+
+ /*
+ * Adjust DDR II IO voltage biasing. It just makes it work.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ gur->ddrioovcr = (0
+ | 0x80000000 /* Enable */
+ | 0x10000000 /* VSEL to 1.8V */
+ );
+ }
+
+ /*
+ * Determine the size of each Rank in bytes.
+ */
+ rank_density = compute_banksize(spd.mem_type, spd.row_dens);
+
+ debug("Start address for this controller is 0x%08lx\n", start_addr);
+
+ /*
+ * ODT configuration recommendation from DDR Controller Chapter.
+ */
+ odt_rd_cfg = 0; /* Never assert ODT */
+ odt_wr_cfg = 0; /* Never assert ODT */
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ odt_wr_cfg = 1; /* Assert ODT on writes to CS0 */
+ }
+
+#ifdef CONFIG_DDR_INTERLEAVE
+
+ if (dimm_num != 1) {
+ printf("For interleaving memory on HPCN, need to use DIMM 1 for DDR Controller %d !\n", ddr_num);
+ return 0;
+ } else {
+ /*
+ * Since interleaved memory only uses CS0, the
+ * memory sticks have to be identical in size and quantity
+ * of ranks. That essentially gives double the size on
+ * one rank, i.e on CS0 for both controllers put together.
+ * Confirm this???
+ */
+ rank_density *= 2;
+
+ /*
+ * Eg: Bounds: 0x0000_0000 to 0x0f000_0000 first 256 Meg
+ */
+ start_addr = 0;
+ ddr->cs0_bnds = (start_addr >> 8)
+ | (((start_addr + rank_density - 1) >> 24));
+ /*
+ * Default interleaving mode to cache-line interleaving.
+ */
+ ddr->cs0_config = ( 1 << 31
+#if (CFG_PAGE_INTERLEAVING == 1)
+ | (PAGE_INTERLEAVING)
+#elif (CFG_BANK_INTERLEAVING == 1)
+ | (BANK_INTERLEAVING)
+#elif (CFG_SUPER_BANK_INTERLEAVING == 1)
+ | (SUPER_BANK_INTERLEAVING)
+#else
+ | (CACHE_LINE_INTERLEAVING)
+#endif
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | (spd.nrow_addr - 12) << 8
+ | (spd.ncol_addr - 8) );
+
+ debug("DDR: cs0_bnds = 0x%08x\n", ddr->cs0_bnds);
+ debug("DDR: cs0_config = 0x%08x\n", ddr->cs0_config);
+
+ /*
+ * Adjustment for dual rank memory to get correct memory
+ * size (return value of this function).
+ */
+ if (n_ranks == 2) {
+ n_ranks = 1;
+ rank_density /= 2;
+ } else {
+ rank_density /= 2;
+ }
+ }
+#else /* CONFIG_DDR_INTERLEAVE */
+
+ if (dimm_num == 1) {
+ /*
+ * Eg: Bounds: 0x0000_0000 to 0x0f000_0000 first 256 Meg
+ */
+ ddr->cs0_bnds = (start_addr >> 8)
+ | (((start_addr + rank_density - 1) >> 24));
+
+ ddr->cs0_config = ( 1 << 31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | (spd.nrow_addr - 12) << 8
+ | (spd.ncol_addr - 8) );
+
+ debug("DDR: cs0_bnds = 0x%08x\n", ddr->cs0_bnds);
+ debug("DDR: cs0_config = 0x%08x\n", ddr->cs0_config);
+
+ if (n_ranks == 2) {
+ /*
+ * Eg: Bounds: 0x1000_0000 to 0x1f00_0000,
+ * second 256 Meg
+ */
+ ddr->cs1_bnds = (((start_addr + rank_density) >> 8)
+ | (( start_addr + 2*rank_density - 1)
+ >> 24));
+ ddr->cs1_config = ( 1<<31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | (spd.nrow_addr - 12) << 8
+ | (spd.ncol_addr - 8) );
+ debug("DDR: cs1_bnds = 0x%08x\n", ddr->cs1_bnds);
+ debug("DDR: cs1_config = 0x%08x\n", ddr->cs1_config);
+ }
+
+ } else {
+ /*
+ * This is the 2nd DIMM slot for this controller
+ */
+ /*
+ * Eg: Bounds: 0x0000_0000 to 0x0f000_0000 first 256 Meg
+ */
+ ddr->cs2_bnds = (start_addr >> 8)
+ | (((start_addr + rank_density - 1) >> 24));
+
+ ddr->cs2_config = ( 1 << 31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | (spd.nrow_addr - 12) << 8
+ | (spd.ncol_addr - 8) );
+
+ debug("DDR: cs2_bnds = 0x%08x\n", ddr->cs2_bnds);
+ debug("DDR: cs2_config = 0x%08x\n", ddr->cs2_config);
+
+ if (n_ranks == 2) {
+ /*
+ * Eg: Bounds: 0x1000_0000 to 0x1f00_0000,
+ * second 256 Meg
+ */
+ ddr->cs3_bnds = (((start_addr + rank_density) >> 8)
+ | (( start_addr + 2*rank_density - 1)
+ >> 24));
+ ddr->cs3_config = ( 1<<31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | (spd.nrow_addr - 12) << 8
+ | (spd.ncol_addr - 8) );
+ debug("DDR: cs3_bnds = 0x%08x\n", ddr->cs3_bnds);
+ debug("DDR: cs3_config = 0x%08x\n", ddr->cs3_config);
+ }
+ }
+#endif /* CONFIG_DDR_INTERLEAVE */
+
+ /*
+ * Find the largest CAS by locating the highest 1 bit
+ * in the spd.cas_lat field. Translate it to a DDR
+ * controller field value:
+ *
+ * CAS Lat DDR I DDR II Ctrl
+ * Clocks SPD Bit SPD Bit Value
+ * ------- ------- ------- -----
+ * 1.0 0 0001
+ * 1.5 1 0010
+ * 2.0 2 2 0011
+ * 2.5 3 0100
+ * 3.0 4 3 0101
+ * 3.5 5 0110
+ * 4.0 4 0111
+ * 4.5 1000
+ * 5.0 5 1001
+ */
+ caslat = __ilog2(spd.cas_lat);
+ if ((spd.mem_type == SPD_MEMTYPE_DDR)
+ && (caslat > 5)) {
+ printf("DDR I: Invalid SPD CAS Latency: 0x%x.\n", spd.cas_lat);
+ return 0;
+
+ } else if (spd.mem_type == SPD_MEMTYPE_DDR2
+ && (caslat < 2 || caslat > 5)) {
+ printf("DDR II: Invalid SPD CAS Latency: 0x%x.\n",
+ spd.cas_lat);
+ return 0;
+ }
+ debug("DDR: caslat SPD bit is %d\n", caslat);
+
+ /*
+ * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+ * The SPD clk_cycle field (tCKmin) is measured in tenths of
+ * nanoseconds and represented as BCD.
+ */
+ tCKmin_ps = convert_bcd_tenths_to_cycle_time_ps(spd.clk_cycle);
+ debug("DDR: tCKmin = %d ps\n", tCKmin_ps);
+
+ /*
+ * Double-data rate, scaled 1000 to picoseconds, and back down to MHz.
+ */
+ max_data_rate = 2 * 1000 * 1000 / tCKmin_ps;
+ debug("DDR: Module max data rate = %d Mhz\n", max_data_rate);
+
+
+ /*
+ * Adjust the CAS Latency to allow for bus speeds that
+ * are slower than the DDR module.
+ */
+ busfreq = get_bus_freq(0) / 1000000; /* MHz */
+ tCycle_ps = convert_bcd_tenths_to_cycle_time_ps(spd.clk_cycle3);
+ modfreq = 2 * 1000 * 1000 / tCycle_ps;
+
+ if ((spd.mem_type == SPD_MEMTYPE_DDR2) && (busfreq < 266)) {
+ printf("DDR: platform frequency too low for correct DDR2 controller operation\n");
+ return 0;
+ } else if (busfreq < 90) {
+ printf("DDR: platform frequency too low for correct DDR1 operation\n");
+ return 0;
+ }
+
+ if ((busfreq <= modfreq) && (spd.cas_lat & (1 << (caslat - 2)))) {
+ caslat -= 2;
+ } else {
+ tCycle_ps = convert_bcd_tenths_to_cycle_time_ps(spd.clk_cycle2);
+ modfreq = 2 * 1000 * 1000 / tCycle_ps;
+ if ((busfreq <= modfreq) && (spd.cas_lat & (1 << (caslat - 1))))
+ caslat -= 1;
+ else if (busfreq > max_data_rate) {
+ printf("DDR: Bus freq %d MHz is not fit for DDR rate %d MHz\n",
+ busfreq, max_data_rate);
+ return 0;
+ }
+ }
+
+ /*
+ * Empirically set ~MCAS-to-preamble override for DDR 2.
+ * Your milage will vary.
+ */
+ cpo = 0;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ if (busfreq <= 333) {
+ cpo = 0x7;
+ } else if (busfreq <= 400) {
+ cpo = 0x9;
+ } else {
+ cpo = 0xa;
+ }
+ }
+
+ /*
+ * Convert caslat clocks to DDR controller value.
+ * Force caslat_ctrl to be DDR Controller field-sized.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ caslat_ctrl = (caslat + 1) & 0x07;
+ } else {
+ caslat_ctrl = (2 * caslat - 1) & 0x0f;
+ }
+
+ debug("DDR: caslat SPD bit is %d, controller field is 0x%x\n",
+ caslat, caslat_ctrl);
+
+ /*
+ * Timing Config 0.
+ * Avoid writing for DDR I. The new PQ38 DDR controller
+ * dreams up non-zero default values to be backwards compatible.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ unsigned char taxpd_clk = 8; /* By the book. */
+ unsigned char tmrd_clk = 2; /* By the book. */
+ unsigned char act_pd_exit = 2; /* Empirical? */
+ unsigned char pre_pd_exit = 6; /* Empirical? */
+
+ ddr->timing_cfg_0 = (0
+ | ((act_pd_exit & 0x7) << 20) /* ACT_PD_EXIT */
+ | ((pre_pd_exit & 0x7) << 16) /* PRE_PD_EXIT */
+ | ((taxpd_clk & 0xf) << 8) /* ODT_PD_EXIT */
+ | ((tmrd_clk & 0xf) << 0) /* MRS_CYC */
+ );
+ debug("DDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
+
+ }
+
+
+ /*
+ * Some Timing Config 1 values now.
+ * Sneak Extended Refresh Recovery in here too.
+ */
+
+ /*
+ * For DDR I, WRREC(Twr) and WRTORD(Twtr) are not in SPD,
+ * use conservative value.
+ * For DDR II, they are bytes 36 and 37, in quarter nanos.
+ */
+
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ twr_clk = 3; /* Clocks */
+ twtr_clk = 1; /* Clocks */
+ } else {
+ twr_clk = picos_to_clk(spd.twr * 250);
+ twtr_clk = picos_to_clk(spd.twtr * 250);
+ }
+
+ /*
+ * Calculate Trfc, in picos.
+ * DDR I: Byte 42 straight up in ns.
+ * DDR II: Byte 40 and 42 swizzled some, in ns.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ trfc = spd.trfc * 1000; /* up to ps */
+ } else {
+ unsigned int byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0,
+ 0
+ };
+
+ trfc = (((spd.trctrfc_ext & 0x1) * 256) + spd.trfc) * 1000
+ + byte40_table_ps[(spd.trctrfc_ext >> 1) & 0x7];
+ }
+ trfc_clk = picos_to_clk(trfc);
+
+ /*
+ * Trcd, Byte 29, from quarter nanos to ps and clocks.
+ */
+ trcd_clk = picos_to_clk(spd.trcd * 250) & 0x7;
+
+ /*
+ * Convert trfc_clk to DDR controller fields. DDR I should
+ * fit in the REFREC field (16-19) of TIMING_CFG_1, but the
+ * 8548 controller has an extended REFREC field of three bits.
+ * The controller automatically adds 8 clocks to this value,
+ * so preadjust it down 8 first before splitting it up.
+ */
+ trfc_low = (trfc_clk - 8) & 0xf;
+ trfc_high = ((trfc_clk - 8) >> 4) & 0x3;
+
+ /*
+ * Sneak in some Extended Refresh Recovery.
+ */
+ ddr->ext_refrec = (trfc_high << 16);
+ debug("DDR: ext_refrec = 0x%08x\n", ddr->ext_refrec);
+
+ ddr->timing_cfg_1 =
+ (0
+ | ((picos_to_clk(spd.trp * 250) & 0x07) << 28) /* PRETOACT */
+ | ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24) /* ACTTOPRE */
+ | (trcd_clk << 20) /* ACTTORW */
+ | (caslat_ctrl << 16) /* CASLAT */
+ | (trfc_low << 12) /* REFEC */
+ | ((twr_clk & 0x07) << 8) /* WRRREC */
+ | ((picos_to_clk(spd.trrd * 250) & 0x07) << 4) /* ACTTOACT */
+ | ((twtr_clk & 0x07) << 0) /* WRTORD */
+ );
+
+ debug("DDR: timing_cfg_1 = 0x%08x\n", ddr->timing_cfg_1);
+
+
+ /*
+ * Timing_Config_2
+ * Was: 0x00000800;
+ */
+
+ /*
+ * Additive Latency
+ * For DDR I, 0.
+ * For DDR II, with ODT enabled, use "a value" less than ACTTORW,
+ * which comes from Trcd, and also note that:
+ * add_lat + caslat must be >= 4
+ */
+ add_lat = 0;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2
+ && (odt_wr_cfg || odt_rd_cfg)
+ && (caslat < 4)) {
+ add_lat = 4 - caslat;
+ if (add_lat >= trcd_clk) {
+ add_lat = trcd_clk - 1;
+ }
+ }
+
+ /*
+ * Write Data Delay
+ * Historically 0x2 == 4/8 clock delay.
+ * Empirically, 0x3 == 6/8 clock delay is suggested for DDR I 266.
+ */
+ wr_data_delay = 3;
+
+ /*
+ * Write Latency
+ * Read to Precharge
+ * Minimum CKE Pulse Width.
+ * Four Activate Window
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ /*
+ * This is a lie. It should really be 1, but if it is
+ * set to 1, bits overlap into the old controller's
+ * otherwise unused ACSM field. If we leave it 0, then
+ * the HW will magically treat it as 1 for DDR 1. Oh Yea.
+ */
+ wr_lat = 0;
+
+ trtp_clk = 2; /* By the book. */
+ cke_min_clk = 1; /* By the book. */
+ four_act = 1; /* By the book. */
+
+ } else {
+ wr_lat = caslat - 1;
+
+ /* Convert SPD value from quarter nanos to picos. */
+ trtp_clk = picos_to_clk(spd.trtp * 250);
+
+ cke_min_clk = 3; /* By the book. */
+ four_act = picos_to_clk(37500); /* By the book. 1k pages? */
+ }
+
+ ddr->timing_cfg_2 = (0
+ | ((add_lat & 0x7) << 28) /* ADD_LAT */
+ | ((cpo & 0x1f) << 23) /* CPO */
+ | ((wr_lat & 0x7) << 19) /* WR_LAT */
+ | ((trtp_clk & 0x7) << 13) /* RD_TO_PRE */
+ | ((wr_data_delay & 0x7) << 10) /* WR_DATA_DELAY */
+ | ((cke_min_clk & 0x7) << 6) /* CKE_PLS */
+ | ((four_act & 0x1f) << 0) /* FOUR_ACT */
+ );
+
+ debug("DDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2);
+
+
+ /*
+ * Determine the Mode Register Set.
+ *
+ * This is nominally part specific, but it appears to be
+ * consistent for all DDR I devices, and for all DDR II devices.
+ *
+ * caslat must be programmed
+ * burst length is always 4
+ * burst type is sequential
+ *
+ * For DDR I:
+ * operating mode is "normal"
+ *
+ * For DDR II:
+ * other stuff
+ */
+
+ mode_caslat = 0;
+
+ /*
+ * Table lookup from DDR I or II Device Operation Specs.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ if (1 <= caslat && caslat <= 4) {
+ unsigned char mode_caslat_table[4] = {
+ 0x5, /* 1.5 clocks */
+ 0x2, /* 2.0 clocks */
+ 0x6, /* 2.5 clocks */
+ 0x3 /* 3.0 clocks */
+ };
+ mode_caslat = mode_caslat_table[caslat - 1];
+ } else {
+ puts("DDR I: Only CAS Latencies of 1.5, 2.0, "
+ "2.5 and 3.0 clocks are supported.\n");
+ return 0;
+ }
+
+ } else {
+ if (2 <= caslat && caslat <= 5) {
+ mode_caslat = caslat;
+ } else {
+ puts("DDR II: Only CAS Latencies of 2.0, 3.0, "
+ "4.0 and 5.0 clocks are supported.\n");
+ return 0;
+ }
+ }
+
+ /*
+ * Encoded Burst Length of 4.
+ */
+ burst_len = 2; /* Fiat. */
+
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ twr_auto_clk = 0; /* Historical */
+ } else {
+ /*
+ * Determine tCK max in picos. Grab tWR and convert to picos.
+ * Auto-precharge write recovery is:
+ * WR = roundup(tWR_ns/tCKmax_ns).
+ *
+ * Ponder: Is twr_auto_clk different than twr_clk?
+ */
+ tCKmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd.tckmax);
+ twr_auto_clk = (spd.twr * 250 + tCKmax_ps - 1) / tCKmax_ps;
+ }
+
+ /*
+ * Mode Reg in bits 16 ~ 31,
+ * Extended Mode Reg 1 in bits 0 ~ 15.
+ */
+ mode_odt_enable = 0x0; /* Default disabled */
+ if (odt_wr_cfg || odt_rd_cfg) {
+ /*
+ * Bits 6 and 2 in Extended MRS(1)
+ * Bit 2 == 0x04 == 75 Ohm, with 2 DIMM modules.
+ * Bit 6 == 0x40 == 150 Ohm, with 1 DIMM module.
+ */
+ mode_odt_enable = 0x40; /* 150 Ohm */
+ }
+
+ ddr->sdram_mode_1 =
+ (0
+ | (add_lat << (16 + 3)) /* Additive Latency in EMRS1 */
+ | (mode_odt_enable << 16) /* ODT Enable in EMRS1 */
+ | (twr_auto_clk << 9) /* Write Recovery Autopre */
+ | (mode_caslat << 4) /* caslat */
+ | (burst_len << 0) /* Burst length */
+ );
+
+ debug("DDR: sdram_mode = 0x%08x\n", ddr->sdram_mode_1);
+
+ /*
+ * Clear EMRS2 and EMRS3.
+ */
+ ddr->sdram_mode_2 = 0;
+ debug("DDR: sdram_mode_2 = 0x%08x\n", ddr->sdram_mode_2);
+
+ /*
+ * Determine Refresh Rate.
+ */
+ refresh_clk = determine_refresh_rate(spd.refresh & 0x7);
+
+ /*
+ * Set BSTOPRE to 0x100 for page mode
+ * If auto-charge is used, set BSTOPRE = 0
+ */
+ ddr->sdram_interval =
+ (0
+ | (refresh_clk & 0x3fff) << 16
+ | 0x100
+ );
+ debug("DDR: sdram_interval = 0x%08x\n", ddr->sdram_interval);
+
+
+ /*
+ * Is this an ECC DDR chip?
+ * But don't mess with it if the DDR controller will init mem.
+ */
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+ if (spd.config == 0x02) {
+ ddr->err_disable = 0x0000000d;
+ ddr->err_sbe = 0x00ff0000;
+ }
+ debug("DDR: err_disable = 0x%08x\n", ddr->err_disable);
+ debug("DDR: err_sbe = 0x%08x\n", ddr->err_sbe);
+#endif
+
+ asm volatile("sync;isync");
+ udelay(500);
+
+ /*
+ * SDRAM Cfg 2
+ */
+
+ /*
+ * When ODT is enabled, Chap 9 suggests asserting ODT to
+ * internal IOs only during reads.
+ */
+ odt_cfg = 0;
+ if (odt_rd_cfg | odt_wr_cfg) {
+ odt_cfg = 0x2; /* ODT to IOs during reads */
+ }
+
+ /*
+ * Try to use differential DQS with DDR II.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ dqs_cfg = 0; /* No Differential DQS for DDR I */
+ } else {
+ dqs_cfg = 0x1; /* Differential DQS for DDR II */
+ }
+
+#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+ /*
+ * Use the DDR controller to auto initialize memory.
+ */
+ d_init = 1;
+ ddr->sdram_data_init = CONFIG_MEM_INIT_VALUE;
+ debug("DDR: ddr_data_init = 0x%08x\n", ddr->sdram_data_init);
+#else
+ /*
+ * Memory will be initialized via DMA, or not at all.
+ */
+ d_init = 0;
+#endif
+
+ ddr->sdram_cfg_2 = (0
+ | (dqs_cfg << 26) /* Differential DQS */
+ | (odt_cfg << 21) /* ODT */
+ | (d_init << 4) /* D_INIT auto init DDR */
+ );
+
+ debug("DDR: sdram_cfg_2 = 0x%08x\n", ddr->sdram_cfg_2);
+
+
+#ifdef MPC86xx_DDR_SDRAM_CLK_CNTL
+ /*
+ * Setup the clock control.
+ * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1
+ * SDRAM_CLK_CNTL[5-7] = Clock Adjust
+ * 0110 3/4 cycle late
+ * 0111 7/8 cycle late
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ clk_adjust = 0x6;
+ else
+ clk_adjust = 0x7;
+
+ ddr->sdram_clk_cntl = (0
+ | 0x80000000
+ | (clk_adjust << 23)
+ );
+ debug("DDR: sdram_clk_cntl = 0x%08x\n", ddr->sdram_clk_cntl);
+#endif
+
+ /*
+ * Figure out memory size in Megabytes.
+ */
+ debug("# ranks = %d, rank_density = 0x%08lx\n", n_ranks, rank_density);
+ memsize = n_ranks * rank_density / 0x100000;
+ return memsize;
+}
+
+
+unsigned int enable_ddr(unsigned int ddr_num)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ spd_eeprom_t spd1,spd2;
+ volatile ccsr_ddr_t *ddr;
+ unsigned sdram_cfg_1;
+ unsigned char sdram_type, mem_type, config, mod_attr;
+ unsigned char d_init;
+ unsigned int no_dimm1=0, no_dimm2=0;
+
+ /* Set up pointer to enable the current ddr controller */
+ if (ddr_num == 1)
+ ddr = &immap->im_ddr1;
+ else
+ ddr = &immap->im_ddr2;
+
+ /*
+ * Read both dimm slots and decide whether
+ * or not to enable this controller.
+ */
+ memset((void *)&spd1,0,sizeof(spd1));
+ memset((void *)&spd2,0,sizeof(spd2));
+
+ if (ddr_num == 1) {
+ CFG_READ_SPD(SPD_EEPROM_ADDRESS1,
+ 0, 1, (uchar *) &spd1, sizeof(spd1));
+ CFG_READ_SPD(SPD_EEPROM_ADDRESS2,
+ 0, 1, (uchar *) &spd2, sizeof(spd2));
+ } else {
+ CFG_READ_SPD(SPD_EEPROM_ADDRESS3,
+ 0, 1, (uchar *) &spd1, sizeof(spd1));
+ CFG_READ_SPD(SPD_EEPROM_ADDRESS4,
+ 0, 1, (uchar *) &spd2, sizeof(spd2));
+ }
+
+ /*
+ * Check for supported memory module types.
+ */
+ if (spd1.mem_type != SPD_MEMTYPE_DDR
+ && spd1.mem_type != SPD_MEMTYPE_DDR2) {
+ no_dimm1 = 1;
+ } else {
+ debug("\nFound memory of type 0x%02lx ",spd1.mem_type );
+ if (spd1.mem_type == SPD_MEMTYPE_DDR)
+ debug("DDR I\n");
+ else
+ debug("DDR II\n");
+ }
+
+ if (spd2.mem_type != SPD_MEMTYPE_DDR &&
+ spd2.mem_type != SPD_MEMTYPE_DDR2) {
+ no_dimm2 = 1;
+ } else {
+ debug("\nFound memory of type 0x%02lx ",spd2.mem_type );
+ if (spd2.mem_type == SPD_MEMTYPE_DDR)
+ debug("DDR I\n");
+ else
+ debug("DDR II\n");
+ }
+
+#ifdef CONFIG_DDR_INTERLEAVE
+ if (no_dimm1) {
+ printf("For interleaved operation memory modules need to be present in CS0 DIMM slots of both DDR controllers!\n");
+ return 0;
+ }
+#endif
+
+ /*
+ * Memory is not present in DIMM1 and DIMM2 - so do not enable DDRn
+ */
+ if (no_dimm1 && no_dimm2) {
+ printf("No memory modules found for DDR controller %d!!\n", ddr_num);
+ return 0;
+ } else {
+ mem_type = no_dimm2 ? spd1.mem_type : spd2.mem_type;
+
+ /*
+ * Figure out the settings for the sdram_cfg register.
+ * Build up the entire register in 'sdram_cfg' before
+ * writing since the write into the register will
+ * actually enable the memory controller; all settings
+ * must be done before enabling.
+ *
+ * sdram_cfg[0] = 1 (ddr sdram logic enable)
+ * sdram_cfg[1] = 1 (self-refresh-enable)
+ * sdram_cfg[5:7] = (SDRAM type = DDR SDRAM)
+ * 010 DDR 1 SDRAM
+ * 011 DDR 2 SDRAM
+ */
+ sdram_type = (mem_type == SPD_MEMTYPE_DDR) ? 2 : 3;
+ sdram_cfg_1 = (0
+ | (1 << 31) /* Enable */
+ | (1 << 30) /* Self refresh */
+ | (sdram_type << 24) /* SDRAM type */
+ );
+
+ /*
+ * sdram_cfg[3] = RD_EN - registered DIMM enable
+ * A value of 0x26 indicates micron registered
+ * DIMMS (micron.com)
+ */
+ mod_attr = no_dimm2 ? spd1.mod_attr : spd2.mod_attr;
+ if (mem_type == SPD_MEMTYPE_DDR && mod_attr == 0x26) {
+ sdram_cfg_1 |= 0x10000000; /* RD_EN */
+ }
+
+#if defined(CONFIG_DDR_ECC)
+
+ config = no_dimm2 ? spd1.config : spd2.config;
+
+ /*
+ * If the user wanted ECC (enabled via sdram_cfg[2])
+ */
+ if (config == 0x02) {
+ ddr->err_disable = 0x00000000;
+ asm volatile("sync;isync;");
+ ddr->err_sbe = 0x00ff0000;
+ ddr->err_int_en = 0x0000000d;
+ sdram_cfg_1 |= 0x20000000; /* ECC_EN */
+ }
+#endif
+
+ /*
+ * Set 1T or 2T timing based on 1 or 2 modules
+ */
+ {
+ if (!(no_dimm1 || no_dimm2)) {
+ /*
+ * 2T timing,because both DIMMS are present.
+ * Enable 2T timing by setting sdram_cfg[16].
+ */
+ sdram_cfg_1 |= 0x8000; /* 2T_EN */
+ }
+ }
+
+ /*
+ * 200 painful micro-seconds must elapse between
+ * the DDR clock setup and the DDR config enable.
+ */
+ udelay(200);
+
+ /*
+ * Go!
+ */
+ ddr->sdram_cfg_1 = sdram_cfg_1;
+
+ asm volatile("sync;isync");
+ udelay(500);
+
+ debug("DDR: sdram_cfg = 0x%08x\n", ddr->sdram_cfg_1);
+
+
+#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+ d_init = 1;
+ debug("DDR: memory initializing\n");
+
+ /*
+ * Poll until memory is initialized.
+ * 512 Meg at 400 might hit this 200 times or so.
+ */
+ while ((ddr->sdram_cfg_2 & (d_init << 4)) != 0) {
+ udelay(1000);
+ }
+ debug("DDR: memory initialized\n\n");
+#endif
+
+ debug("Enabled DDR Controller %d\n", ddr_num);
+ return 1;
+ }
+}
+
+
+long int
+spd_sdram(void)
+{
+ int memsize_ddr1_dimm1 = 0;
+ int memsize_ddr1_dimm2 = 0;
+ int memsize_ddr2_dimm1 = 0;
+ int memsize_ddr2_dimm2 = 0;
+ int memsize_total = 0;
+ int memsize_ddr1 = 0;
+ int memsize_ddr2 = 0;
+ unsigned int ddr1_enabled = 0;
+ unsigned int ddr2_enabled = 0;
+ unsigned int law_size_ddr1;
+ unsigned int law_size_ddr2;
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile ccsr_ddr_t *ddr1 = &immap->im_ddr1;
+ volatile ccsr_ddr_t *ddr2 = &immap->im_ddr2;
+ volatile ccsr_local_mcm_t *mcm = &immap->im_local_mcm;
+
+#ifdef CONFIG_DDR_INTERLEAVE
+ unsigned int law_size_interleaved;
+
+ memsize_ddr1_dimm1 = spd_init(SPD_EEPROM_ADDRESS1,
+ 1, 1,
+ (unsigned int)memsize_total * 1024*1024);
+ memsize_total += memsize_ddr1_dimm1;
+
+ memsize_ddr2_dimm1 = spd_init(SPD_EEPROM_ADDRESS3,
+ 2, 1,
+ (unsigned int)memsize_total * 1024*1024);
+ memsize_total += memsize_ddr2_dimm1;
+
+ if (memsize_ddr1_dimm1 != memsize_ddr2_dimm1) {
+ if (memsize_ddr1_dimm1 < memsize_ddr2_dimm1)
+ memsize_total -= memsize_ddr1_dimm1;
+ else
+ memsize_total -= memsize_ddr2_dimm1;
+ debug("Total memory available for interleaving 0x%08lx\n",
+ memsize_total * 1024 * 1024);
+ debug("Adjusting CS0_BNDS to account for unequal DIMM sizes in interleaved memory\n");
+ ddr1->cs0_bnds = ((memsize_total * 1024 * 1024) - 1) >> 24;
+ ddr2->cs0_bnds = ((memsize_total * 1024 * 1024) - 1) >> 24;
+ debug("DDR1: cs0_bnds = 0x%08x\n", ddr1->cs0_bnds);
+ debug("DDR2: cs0_bnds = 0x%08x\n", ddr2->cs0_bnds);
+ }
+
+ ddr1_enabled = enable_ddr(1);
+ ddr2_enabled = enable_ddr(2);
+
+ /*
+ * Both controllers need to be enabled for interleaving.
+ */
+ if (ddr1_enabled && ddr2_enabled) {
+ law_size_interleaved = 19 + __ilog2(memsize_total);
+
+ /*
+ * Set up LAWBAR for DDR 1 space.
+ */
+ mcm->lawbar1 = ((CFG_DDR_SDRAM_BASE >> 12) & 0xfffff);
+ mcm->lawar1 = (LAWAR_EN
+ | LAWAR_TRGT_IF_DDR_INTERLEAVED
+ | (LAWAR_SIZE & law_size_interleaved));
+ debug("DDR: LAWBAR1=0x%08x\n", mcm->lawbar1);
+ debug("DDR: LAWAR1=0x%08x\n", mcm->lawar1);
+ debug("Interleaved memory size is 0x%08lx\n", memsize_total);
+
+#ifdef CONFIG_DDR_INTERLEAVE
+#if (CFG_PAGE_INTERLEAVING == 1)
+ printf("Page ");
+#elif (CFG_BANK_INTERLEAVING == 1)
+ printf("Bank ");
+#elif (CFG_SUPER_BANK_INTERLEAVING == 1)
+ printf("Super-bank ");
+#else
+ printf("Cache-line ");
+#endif
+#endif
+ printf("Interleaved");
+ return memsize_total * 1024 * 1024;
+ } else {
+ printf("Interleaved memory not enabled - check CS0 DIMM slots for both controllers.\n");
+ return 0;
+ }
+
+#else
+ /*
+ * Call spd_sdram() routine to init ddr1 - pass I2c address,
+ * controller number, dimm number, and starting address.
+ */
+ memsize_ddr1_dimm1 = spd_init(SPD_EEPROM_ADDRESS1,
+ 1, 1,
+ (unsigned int)memsize_total * 1024*1024);
+ memsize_total += memsize_ddr1_dimm1;
+
+ memsize_ddr1_dimm2 = spd_init(SPD_EEPROM_ADDRESS2,
+ 1, 2,
+ (unsigned int)memsize_total * 1024*1024);
+ memsize_total += memsize_ddr1_dimm2;
+
+ /*
+ * Enable the DDR controller - pass ddr controller number.
+ */
+ ddr1_enabled = enable_ddr(1);
+
+ /* Keep track of memory to be addressed by DDR1 */
+ memsize_ddr1 = memsize_ddr1_dimm1 + memsize_ddr1_dimm2;
+
+ /*
+ * First supported LAW size is 16M, at LAWAR_SIZE_16M == 23. Fnord.
+ */
+ if (ddr1_enabled) {
+ law_size_ddr1 = 19 + __ilog2(memsize_ddr1);
+
+ /*
+ * Set up LAWBAR for DDR 1 space.
+ */
+ mcm->lawbar1 = ((CFG_DDR_SDRAM_BASE >> 12) & 0xfffff);
+ mcm->lawar1 = (LAWAR_EN
+ | LAWAR_TRGT_IF_DDR1
+ | (LAWAR_SIZE & law_size_ddr1));
+ debug("DDR: LAWBAR1=0x%08x\n", mcm->lawbar1);
+ debug("DDR: LAWAR1=0x%08x\n", mcm->lawar1);
+ }
+
+#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+ memsize_ddr2_dimm1 = spd_init(SPD_EEPROM_ADDRESS3,
+ 2, 1,
+ (unsigned int)memsize_total * 1024*1024);
+ memsize_total += memsize_ddr2_dimm1;
+
+ memsize_ddr2_dimm2 = spd_init(SPD_EEPROM_ADDRESS4,
+ 2, 2,
+ (unsigned int)memsize_total * 1024*1024);
+ memsize_total += memsize_ddr2_dimm2;
+
+ ddr2_enabled = enable_ddr(2);
+
+ /* Keep track of memory to be addressed by DDR2 */
+ memsize_ddr2 = memsize_ddr2_dimm1 + memsize_ddr2_dimm2;
+
+ if (ddr2_enabled) {
+ law_size_ddr2 = 19 + __ilog2(memsize_ddr2);
+
+ /*
+ * Set up LAWBAR for DDR 2 space.
+ */
+ if (ddr1_enabled)
+ mcm->lawbar8 = (((memsize_ddr1 * 1024 * 1024) >> 12)
+ & 0xfffff);
+ else
+ mcm->lawbar8 = ((CFG_DDR_SDRAM_BASE >> 12) & 0xfffff);
+
+ mcm->lawar8 = (LAWAR_EN
+ | LAWAR_TRGT_IF_DDR2
+ | (LAWAR_SIZE & law_size_ddr2));
+ debug("\nDDR: LAWBAR8=0x%08x\n", mcm->lawbar8);
+ debug("DDR: LAWAR8=0x%08x\n", mcm->lawar8);
+ }
+#endif /* CONFIG_NUM_DDR_CONTROLLERS > 1 */
+
+ debug("\nMemory sizes are DDR1 = 0x%08lx, DDR2 = 0x%08lx\n",
+ memsize_ddr1, memsize_ddr2);
+
+ /*
+ * If neither DDR controller is enabled return 0.
+ */
+ if (!ddr1_enabled && !ddr2_enabled)
+ return 0;
+
+ printf("Non-interleaved");
+ return memsize_total * 1024 * 1024;
+
+#endif /* CONFIG_DDR_INTERLEAVE */
+}
+
+
+#endif /* CONFIG_SPD_EEPROM */
+
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+
+void
+ddr_enable_ecc(unsigned int dram_size)
+{
+ uint *p = 0;
+ uint i = 0;
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile ccsr_ddr_t *ddr1= &immap->im_ddr1;
+
+ dma_init();
+
+ for (*p = 0; p < (uint *)(8 * 1024); p++) {
+ if (((unsigned int)p & 0x1f) == 0) {
+ ppcDcbz((unsigned long) p);
+ }
+ *p = (unsigned int)CONFIG_MEM_INIT_VALUE;
+ if (((unsigned int)p & 0x1c) == 0x1c) {
+ ppcDcbf((unsigned long) p);
+ }
+ }
+
+ dma_xfer((uint *)0x002000, 0x002000, (uint *)0); /* 8K */
+ dma_xfer((uint *)0x004000, 0x004000, (uint *)0); /* 16K */
+ dma_xfer((uint *)0x008000, 0x008000, (uint *)0); /* 32K */
+ dma_xfer((uint *)0x010000, 0x010000, (uint *)0); /* 64K */
+ dma_xfer((uint *)0x020000, 0x020000, (uint *)0); /* 128k */
+ dma_xfer((uint *)0x040000, 0x040000, (uint *)0); /* 256k */
+ dma_xfer((uint *)0x080000, 0x080000, (uint *)0); /* 512k */
+ dma_xfer((uint *)0x100000, 0x100000, (uint *)0); /* 1M */
+ dma_xfer((uint *)0x200000, 0x200000, (uint *)0); /* 2M */
+ dma_xfer((uint *)0x400000, 0x400000, (uint *)0); /* 4M */
+
+ for (i = 1; i < dram_size / 0x800000; i++) {
+ dma_xfer((uint *)(0x800000*i), 0x800000, (uint *)0);
+ }
+
+ /*
+ * Enable errors for ECC.
+ */
+ debug("DMA DDR: err_disable = 0x%08x\n", ddr1->err_disable);
+ ddr1->err_disable = 0x00000000;
+ asm volatile("sync;isync");
+ debug("DMA DDR: err_disable = 0x%08x\n", ddr1->err_disable);
+}
+
+#endif /* CONFIG_DDR_ECC && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */
diff --git a/cpu/mpc86xx/speed.c b/cpu/mpc86xx/speed.c
new file mode 100644
index 0000000..312ca12
--- /dev/null
+++ b/cpu/mpc86xx/speed.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * (C) Copyright 2000-2002
+ * 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 <common.h>
+#include <mpc86xx.h>
+#include <asm/processor.h>
+
+
+void get_sys_info(sys_info_t *sysInfo)
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+ uint plat_ratio, e600_ratio;
+
+ plat_ratio = (gur->porpllsr) & 0x0000003e;
+ plat_ratio >>= 1;
+
+ switch (plat_ratio) {
+ case 0x0:
+ sysInfo->freqSystemBus = 16 * CONFIG_SYS_CLK_FREQ;
+ break;
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0c:
+ case 0x10:
+ sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ;
+ break;
+ default:
+ sysInfo->freqSystemBus = 0;
+ break;
+ }
+
+ e600_ratio = (gur->porpllsr) & 0x003f0000;
+ e600_ratio >>= 16;
+
+ switch (e600_ratio) {
+ case 0x10:
+ sysInfo->freqProcessor = 2 * sysInfo->freqSystemBus;
+ break;
+ case 0x19:
+ sysInfo->freqProcessor = 5 * sysInfo->freqSystemBus / 2;
+ break;
+ case 0x20:
+ sysInfo->freqProcessor = 3 * sysInfo->freqSystemBus;
+ break;
+ case 0x39:
+ sysInfo->freqProcessor = 7 * sysInfo->freqSystemBus / 2;
+ break;
+ case 0x28:
+ sysInfo->freqProcessor = 4 * sysInfo->freqSystemBus;
+ break;
+ case 0x1d:
+ sysInfo->freqProcessor = 9 * sysInfo->freqSystemBus / 2;
+ break;
+ default:
+ sysInfo->freqProcessor = e600_ratio + sysInfo->freqSystemBus;
+ break;
+ }
+}
+
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ * (Approx. GCLK frequency in Hz)
+ */
+
+int get_clocks(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ gd->cpu_clk = sys_info.freqProcessor;
+ gd->bus_clk = sys_info.freqSystemBus;
+
+ if (gd->cpu_clk != 0)
+ return 0;
+ else
+ return 1;
+}
+
+
+/*
+ * get_bus_freq
+ * Return system bus freq in Hz
+ */
+
+ulong get_bus_freq(ulong dummy)
+{
+ ulong val;
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ val = sys_info.freqSystemBus;
+
+ return val;
+}
diff --git a/cpu/mpc86xx/start.S b/cpu/mpc86xx/start.S
new file mode 100644
index 0000000..7406fe2
--- /dev/null
+++ b/cpu/mpc86xx/start.S
@@ -0,0 +1,1226 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Srikanth Srinivasan <srikanth.srinivaan@freescale.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
+ */
+
+/* U-Boot - Startup Code for 86xx PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0xfff00100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ */
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+/* Machine Check and Recoverable Interr. */
+#define MSR_KERNEL ( MSR_ME | MSR_RI )
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", __DATE__, " - ", __TIME__, ")"
+ .ascii CONFIG_IDENT_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */
+ b boot_cold
+ sync
+
+ . = EXC_OFF_SYS_RESET + 0x10
+
+ .globl _start_warm
+_start_warm:
+ li r21, BOOTFLAG_WARM /* Software reboot */
+ b boot_warm
+ sync
+
+ /* the boot code is located below the exception table */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_Alignment:
+ .long AlignmentException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_ProgramCheck:
+ .long ProgramCheckException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+ STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x2000
+
+boot_cold:
+boot_warm:
+
+ /* if this is a multi-core system we need to check which cpu
+ * this is, if it is not cpu 0 send the cpu to the linux reset
+ * vector */
+#if (CONFIG_NUM_CPUS > 1)
+ mfspr r0, MSSCR0
+ andi. r0, r0, 0x0020
+ rlwinm r0,r0,27,31,31
+ mtspr PIR, r0
+ beq 1f
+
+ bl secondary_cpu_setup
+#endif
+
+ /* disable everything */
+1: li r0, 0
+ mtspr HID0, r0
+ sync
+ mtmsr 0
+ bl invalidate_bats
+ sync
+
+#ifdef CFG_L2
+ /* init the L2 cache */
+ addis r3, r0, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ mtspr l2cr, r3
+ /* invalidate the L2 cache */
+ bl l2cache_invalidate
+ sync
+#endif
+
+ /*
+ * Calculate absolute address in FLASH and jump there
+ *------------------------------------------------------*/
+ lis r3, CFG_MONITOR_BASE@h
+ ori r3, r3, CFG_MONITOR_BASE@l
+ addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r3
+ blr
+
+in_flash:
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*------------------------------------------------------*/
+ /* perform low-level init */
+
+ /* enable extended addressing */
+ bl enable_ext_addr
+
+ /* setup the bats */
+ bl setup_bats
+ sync
+
+#if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR)
+ /* setup ccsrbar */
+ bl setup_ccsrbar
+#endif
+
+ /* Fix for SMP linux - Changing arbitration to round-robin */
+ lis r3, CFG_CCSRBAR@h
+ ori r3, r3, 0x1000
+ xor r4, r4, r4
+ li r4, 0x1000
+ stw r4, 0(r3)
+
+ /* setup the law entries */
+ bl law_entry
+ sync
+
+ /* Don't use this feature due to bug in 8641D PD4 */
+ /* Disable ERD_DIS */
+ lis r3, CFG_CCSRBAR@h
+ ori r3, r3, 0x1008
+ lwz r4, 0(r3)
+ oris r4, r4, 0x4000
+ stw r4, 0(r3)
+ sync
+
+#if (EMULATOR_RUN == 1)
+ /* On the emulator we want to adjust these ASAP */
+ /* otherwise things are sloooow */
+ /* Setup OR0 (LALE FIX)*/
+ lis r3, CFG_CCSRBAR@h
+ ori r3, r3, 0x5004
+ li r4, 0x0FF3
+ stw r4, 0(r3)
+ sync
+
+ /* Setup LCRR */
+ lis r3, CFG_CCSRBAR@h
+ ori r3, r3, 0x50D4
+ lis r4, 0x8000
+ ori r4, r4, 0x0002
+ stw r4, 0(r3)
+ sync
+#endif
+#if 1
+ /* make sure timer enabled in guts register too */
+ lis r3, CFG_CCSRBAR@h
+ oris r3,r3, 0xE
+ ori r3,r3,0x0070
+ lwz r4, 0(r3)
+ lis r5,0xFFFC
+ ori r5,r5,0x5FFF
+ and r4,r4,r5
+ stw r4,0(r3)
+#endif
+ /*
+ * Cache must be enabled here for stack-in-cache trick.
+ * This means we need to enable the BATS.
+ * Cache should be turned on after BATs, since by default
+ * everything is write-through.
+ */
+
+ /* enable address translation */
+ bl enable_addr_trans
+ sync
+
+ /* enable and invalidate the data cache */
+/* bl l1dcache_enable */
+ bl dcache_enable
+ sync
+
+#if 1
+ bl icache_enable
+#endif
+
+#ifdef CFG_INIT_RAM_LOCK
+ bl lock_ram_in_cache
+ sync
+#endif
+
+ /* set up the stack pointer in our newly created
+ * cache-ram (r1) */
+ lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ GET_GOT /* initialize GOT access */
+
+ /* run low-level CPU init code (from Flash) */
+ bl cpu_init_f
+ sync
+
+#ifdef RUN_DIAG
+
+ /* Sri: Code to run the diagnostic automatically */
+
+ /* Load PX_AUX register address in r4 */
+ lis r4, 0xf810
+ ori r4, r4, 0x6
+ /* Load contents of PX_AUX in r3 bits 24 to 31*/
+ lbz r3, 0(r4)
+
+ /* Mask and obtain the bit in r3 */
+ rlwinm. r3, r3, 0, 24, 24
+ /* If not zero, jump and continue with u-boot */
+ bne diag_done
+
+ /* Load back contents of PX_AUX in r3 bits 24 to 31 */
+ lbz r3, 0(r4)
+ /* Set the MSB of the register value */
+ ori r3, r3, 0x80
+ /* Write value in r3 back to PX_AUX */
+ stb r3, 0(r4)
+
+ /* Get the address to jump to in r3*/
+ lis r3, CFG_DIAG_ADDR@h
+ ori r3, r3, CFG_DIAG_ADDR@l
+
+ /* Load the LR with the branch address */
+ mtlr r3
+
+ /* Branch to diagnostic */
+ blr
+
+diag_done:
+#endif
+
+/* bl l2cache_enable */
+ mr r3, r21
+
+ /* r3: BOOTFLAG */
+ /* run 1st part of board init code (from Flash) */
+ bl board_init_f
+ sync
+
+ /* NOTREACHED */
+
+ .globl invalidate_bats
+invalidate_bats:
+
+ /* invalidate BATs */
+ mtspr IBAT0U, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT4U, r0
+ mtspr IBAT5U, r0
+ mtspr IBAT6U, r0
+ mtspr IBAT7U, r0
+
+ isync
+ mtspr DBAT0U, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT4U, r0
+ mtspr DBAT5U, r0
+ mtspr DBAT6U, r0
+ mtspr DBAT7U, r0
+
+ isync
+ sync
+ blr
+
+
+ /* setup_bats - set them up to some initial state */
+ .globl setup_bats
+setup_bats:
+
+ addis r0, r0, 0x0000
+
+ /* IBAT 0 */
+ addis r4, r0, CFG_IBAT0L@h
+ ori r4, r4, CFG_IBAT0L@l
+ addis r3, r0, CFG_IBAT0U@h
+ ori r3, r3, CFG_IBAT0U@l
+ mtspr IBAT0L, r4
+ mtspr IBAT0U, r3
+ isync
+
+ /* DBAT 0 */
+ addis r4, r0, CFG_DBAT0L@h
+ ori r4, r4, CFG_DBAT0L@l
+ addis r3, r0, CFG_DBAT0U@h
+ ori r3, r3, CFG_DBAT0U@l
+ mtspr DBAT0L, r4
+ mtspr DBAT0U, r3
+ isync
+
+ /* IBAT 1 */
+ addis r4, r0, CFG_IBAT1L@h
+ ori r4, r4, CFG_IBAT1L@l
+ addis r3, r0, CFG_IBAT1U@h
+ ori r3, r3, CFG_IBAT1U@l
+ mtspr IBAT1L, r4
+ mtspr IBAT1U, r3
+ isync
+
+ /* DBAT 1 */
+ addis r4, r0, CFG_DBAT1L@h
+ ori r4, r4, CFG_DBAT1L@l
+ addis r3, r0, CFG_DBAT1U@h
+ ori r3, r3, CFG_DBAT1U@l
+ mtspr DBAT1L, r4
+ mtspr DBAT1U, r3
+ isync
+
+ /* IBAT 2 */
+ addis r4, r0, CFG_IBAT2L@h
+ ori r4, r4, CFG_IBAT2L@l
+ addis r3, r0, CFG_IBAT2U@h
+ ori r3, r3, CFG_IBAT2U@l
+ mtspr IBAT2L, r4
+ mtspr IBAT2U, r3
+ isync
+
+ /* DBAT 2 */
+ addis r4, r0, CFG_DBAT2L@h
+ ori r4, r4, CFG_DBAT2L@l
+ addis r3, r0, CFG_DBAT2U@h
+ ori r3, r3, CFG_DBAT2U@l
+ mtspr DBAT2L, r4
+ mtspr DBAT2U, r3
+ isync
+
+ /* IBAT 3 */
+ addis r4, r0, CFG_IBAT3L@h
+ ori r4, r4, CFG_IBAT3L@l
+ addis r3, r0, CFG_IBAT3U@h
+ ori r3, r3, CFG_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+ isync
+
+ /* DBAT 3 */
+ addis r4, r0, CFG_DBAT3L@h
+ ori r4, r4, CFG_DBAT3L@l
+ addis r3, r0, CFG_DBAT3U@h
+ ori r3, r3, CFG_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+ isync
+
+ /* IBAT 4 */
+ addis r4, r0, CFG_IBAT4L@h
+ ori r4, r4, CFG_IBAT4L@l
+ addis r3, r0, CFG_IBAT4U@h
+ ori r3, r3, CFG_IBAT4U@l
+ mtspr IBAT4L, r4
+ mtspr IBAT4U, r3
+ isync
+
+ /* DBAT 4 */
+ addis r4, r0, CFG_DBAT4L@h
+ ori r4, r4, CFG_DBAT4L@l
+ addis r3, r0, CFG_DBAT4U@h
+ ori r3, r3, CFG_DBAT4U@l
+ mtspr DBAT4L, r4
+ mtspr DBAT4U, r3
+ isync
+
+ /* IBAT 5 */
+ addis r4, r0, CFG_IBAT5L@h
+ ori r4, r4, CFG_IBAT5L@l
+ addis r3, r0, CFG_IBAT5U@h
+ ori r3, r3, CFG_IBAT5U@l
+ mtspr IBAT5L, r4
+ mtspr IBAT5U, r3
+ isync
+
+ /* DBAT 5 */
+ addis r4, r0, CFG_DBAT5L@h
+ ori r4, r4, CFG_DBAT5L@l
+ addis r3, r0, CFG_DBAT5U@h
+ ori r3, r3, CFG_DBAT5U@l
+ mtspr DBAT5L, r4
+ mtspr DBAT5U, r3
+ isync
+
+ /* IBAT 6 */
+ addis r4, r0, CFG_IBAT6L@h
+ ori r4, r4, CFG_IBAT6L@l
+ addis r3, r0, CFG_IBAT6U@h
+ ori r3, r3, CFG_IBAT6U@l
+ mtspr IBAT6L, r4
+ mtspr IBAT6U, r3
+ isync
+
+ /* DBAT 6 */
+ addis r4, r0, CFG_DBAT6L@h
+ ori r4, r4, CFG_DBAT6L@l
+ addis r3, r0, CFG_DBAT6U@h
+ ori r3, r3, CFG_DBAT6U@l
+ mtspr DBAT6L, r4
+ mtspr DBAT6U, r3
+ isync
+
+ /* IBAT 7 */
+ addis r4, r0, CFG_IBAT7L@h
+ ori r4, r4, CFG_IBAT7L@l
+ addis r3, r0, CFG_IBAT7U@h
+ ori r3, r3, CFG_IBAT7U@l
+ mtspr IBAT7L, r4
+ mtspr IBAT7U, r3
+ isync
+
+ /* DBAT 7 */
+ addis r4, r0, CFG_DBAT7L@h
+ ori r4, r4, CFG_DBAT7L@l
+ addis r3, r0, CFG_DBAT7U@h
+ ori r3, r3, CFG_DBAT7U@l
+ mtspr DBAT7L, r4
+ mtspr DBAT7U, r3
+ isync
+
+1:
+ addis r3, 0, 0x0000
+ addis r5, 0, 0x4 /* upper bound of 0x00040000 for 7400/750 */
+ isync
+
+tlblp:
+ tlbie r3
+ sync
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt tlblp
+
+ blr
+
+ .globl enable_addr_trans
+enable_addr_trans:
+ /* enable address translation */
+ mfmsr r5
+ ori r5, r5, (MSR_IR | MSR_DR)
+ mtmsr r5
+ isync
+ blr
+
+ .globl disable_addr_trans
+disable_addr_trans:
+ /* disable address translation */
+ mflr r4
+ mfmsr r3
+ andi. r0, r3, (MSR_IR | MSR_DR)
+ beqlr
+ andc r3, r3, r0
+ mtspr SRR0, r4
+ mtspr SRR1, r3
+ rfi
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+ .globl dc_read
+dc_read:
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+ .globl get_svr
+get_svr:
+ mfspr r3, SVR
+ blr
+
+
+/*
+ * Function: in8
+ * Description: Input 8 bits
+ */
+ .globl in8
+in8:
+ lbz r3,0x0000(r3)
+ blr
+
+/*
+ * Function: out8
+ * Description: Output 8 bits
+ */
+ .globl out8
+out8:
+ stb r4,0x0000(r3)
+ blr
+
+/*
+ * Function: out16
+ * Description: Output 16 bits
+ */
+ .globl out16
+out16:
+ sth r4,0x0000(r3)
+ blr
+
+/*
+ * Function: out16r
+ * Description: Byte reverse and output 16 bits
+ */
+ .globl out16r
+out16r:
+ sthbrx r4,r0,r3
+ blr
+
+/*
+ * Function: out32
+ * Description: Output 32 bits
+ */
+ .globl out32
+out32:
+ stw r4,0x0000(r3)
+ blr
+
+/*
+ * Function: out32r
+ * Description: Byte reverse and output 32 bits
+ */
+ .globl out32r
+out32r:
+ stwbrx r4,r0,r3
+ blr
+
+/*
+ * Function: in16
+ * Description: Input 16 bits
+ */
+ .globl in16
+in16:
+ lhz r3,0x0000(r3)
+ blr
+
+/*
+ * Function: in16r
+ * Description: Input 16 bits and byte reverse
+ */
+ .globl in16r
+in16r:
+ lhbrx r3,r0,r3
+ blr
+
+/*
+ * Function: in32
+ * Description: Input 32 bits
+ */
+ .globl in32
+in32:
+ lwz 3,0x0000(3)
+ blr
+
+/*
+ * Function: in32r
+ * Description: Input 32 bits and byte reverse
+ */
+ .globl in32r
+in32r:
+ lwbrx r3,r0,r3
+ blr
+
+/*
+ * Function: ppcDcbf
+ * Description: Data Cache block flush
+ * Input: r3 = effective address
+ * Output: none.
+ */
+ .globl ppcDcbf
+ppcDcbf:
+ dcbf r0,r3
+ blr
+
+/*
+ * Function: ppcDcbi
+ * Description: Data Cache block Invalidate
+ * Input: r3 = effective address
+ * Output: none.
+ */
+ .globl ppcDcbi
+ppcDcbi:
+ dcbi r0,r3
+ blr
+
+/*
+ * Function: ppcDcbz
+ * Description: Data Cache block zero.
+ * Input: r3 = effective address
+ * Output: none.
+ */
+ .globl ppcDcbz
+ppcDcbz:
+ dcbz r0,r3
+ blr
+
+/*
+ * Function: ppcSync
+ * Description: Processor Synchronize
+ * Input: none.
+ * Output: none.
+ */
+ .globl ppcSync
+ppcSync:
+ sync
+ blr
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r29, r9 /* Save for DECLARE_GLOBAL_DATA_PTR */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ mr r3, r5 /* Destination Address */
+ lis r4, CFG_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CFG_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r14, r14, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+#ifdef CONFIG_ECC
+ bl board_relocate_rom
+ sync
+ mr r3, r10 /* Destination Address */
+ lis r4, CFG_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CFG_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
+#else
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+#endif
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+#ifdef CONFIG_ECC
+ bl board_init_ecc
+#endif
+ /*
+ * Relocation Function, r14 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ add r0,r0,r11
+ stw r0,0(r3)
+ bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+2: li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ add r0,r0,r11
+ stw r10,0(r3)
+ stw r0,0(r4)
+ bdnz 3b
+4:
+/* clear_bss: */
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+ mr r3, r9 /* Init Date pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /* not reached - end relocate_code */
+/*-----------------------------------------------------------------------*/
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+
+ mflr r4 /* save link register */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ /* enable execptions from RAM vectors */
+ mfmsr r7
+ li r8,MSR_IP
+ andc r7,r7,r8
+ mtmsr r7
+
+ mtlr r4 /* restore link register */
+ blr
+
+ /*
+ * Function: relocate entries for one exception vector
+ */
+trap_reloc:
+ lwz r0, 0(r7) /* hdlr ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 0(r7)
+
+ lwz r0, 4(r7) /* int_return ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 4(r7)
+
+ sync
+ isync
+
+ blr
+
+.globl enable_ext_addr
+enable_ext_addr:
+ mfspr r0, HID0
+ lis r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h
+ ori r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l
+ mtspr HID0, r0
+ sync
+ isync
+ blr
+
+#if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR)
+.globl setup_ccsrbar
+setup_ccsrbar:
+ /* Special sequence needed to update CCSRBAR itself */
+ lis r4, CFG_CCSRBAR_DEFAULT@h
+ ori r4, r4, CFG_CCSRBAR_DEFAULT@l
+
+ lis r5, CFG_CCSRBAR@h
+ ori r5, r5, CFG_CCSRBAR@l
+ srwi r6,r5,12
+ stw r6, 0(r4)
+ isync
+
+ lis r5, 0xffff
+ ori r5,r5,0xf000
+ lwz r5, 0(r5)
+ isync
+
+ lis r3, CFG_CCSRBAR@h
+ lwz r5, CFG_CCSRBAR@l(r3)
+ isync
+
+ blr
+#endif
+
+#ifdef CFG_INIT_RAM_LOCK
+lock_ram_in_cache:
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, (CFG_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l
+ li r2, ((CFG_INIT_RAM_END & ~31) + \
+ (CFG_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r2
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+#if 1
+/* Lock the data cache */
+ mfspr r0, HID0
+ ori r0, r0, 0x1000
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
+#if 0
+ /* Lock the first way of the data cache */
+ mfspr r0, LDSTCR
+ ori r0, r0, 0x0080
+#if defined(CONFIG_ALTIVEC)
+ dssall
+#endif
+ sync
+ mtspr LDSTCR, r0
+ sync
+ isync
+ blr
+#endif
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3, (CFG_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l
+ li r2, ((CFG_INIT_RAM_END & ~31) + \
+ (CFG_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r2
+1: icbi r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+ sync /* Wait for all icbi to complete on bus */
+ isync
+#if 1
+/* Unlock the data cache and invalidate it */
+ mfspr r0, HID0
+ li r3,0x1000
+ andc r0,r0,r3
+ li r3,0x0400
+ or r0,r0,r3
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
+#if 0
+ /* Unlock the first way of the data cache */
+ mfspr r0, LDSTCR
+ li r3,0x0080
+ andc r0,r0,r3
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ sync
+ mtspr LDSTCR, r0
+ sync
+ isync
+ li r3,0x0400
+ or r0,r0,r3
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
+#endif
+
+/* If this is a multi-cpu system then we need to handle the
+ * 2nd cpu. The assumption is that the 2nd cpu is being
+ * held in boot holdoff mode until the 1st cpu unlocks it
+ * from Linux. We'll do some basic cpu init and then pass
+ * it to the Linux Reset Vector.
+ * Sri: Much of this initialization is not required. Linux
+ * rewrites the bats, and the sprs and also enables the L1 cache.
+ */
+#if (CONFIG_NUM_CPUS > 1)
+.globl secondary_cpu_setup
+secondary_cpu_setup:
+ /* Do only core setup on all cores except cpu0 */
+ bl invalidate_bats
+ sync
+ bl enable_ext_addr
+
+#ifdef CFG_L2
+ /* init the L2 cache */
+ addis r3, r0, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ sync
+ mtspr l2cr, r3
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ /* invalidate the L2 cache */
+ bl l2cache_invalidate
+ sync
+#endif
+
+ /* enable and invalidate the data cache */
+ bl dcache_enable
+ sync
+
+ /* enable and invalidate the instruction cache*/
+ bl icache_enable
+ sync
+
+ /* TBEN in HID0 */
+ mfspr r4, HID0
+ oris r4, r4, 0x0400
+ mtspr HID0, r4
+ sync
+ isync
+
+ /*SYNCBE|ABE in HID1*/
+ mfspr r4, HID1
+ ori r4, r4, 0x0C00
+ mtspr HID1, r4
+ sync
+ isync
+
+ lis r3, CONFIG_LINUX_RESET_VEC@h
+ ori r3, r3, CONFIG_LINUX_RESET_VEC@l
+ mtlr r3
+ blr
+
+ /* Never Returns, Running in Linux Now */
+#endif
diff --git a/cpu/mpc86xx/traps.c b/cpu/mpc86xx/traps.c
new file mode 100644
index 0000000..8ea14e5
--- /dev/null
+++ b/cpu/mpc86xx/traps.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * 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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize)
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint) sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32)
+ break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void
+show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+ " %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP:"
+ " %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr & MSR_EE ? 1 : 0,
+ regs->msr & MSR_PR ? 1 : 0, regs->msr & MSR_FP ? 1 : 0,
+ regs->msr & MSR_ME ? 1 : 0, regs->msr & MSR_IR ? 1 : 0,
+ regs->msr & MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d", regs->nip, signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ", regs);
+ switch (regs->msr & 0x000F0000) {
+ case (0x80000000 >> 12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000 >> 13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000 >> 14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000 >> 15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+ unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL;
+ int i, j;
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ show_regs(regs);
+
+ p = (unsigned char *)((unsigned long)p & 0xFFFFFFE0);
+ p -= 32;
+ for (i = 0; i < 256; i += 16) {
+ printf("%08x: ", (unsigned int)p + i);
+ for (j = 0; j < 16; j++) {
+ printf("%02x ", p[i + j]);
+ }
+ printf("\n");
+ }
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+/*
+ * Probe an address by reading.
+ * If not present, return -1,
+ * otherwise return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+ return 0;
+}