summaryrefslogtreecommitdiff
path: root/arch/powerpc/cpu/mpc83xx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/cpu/mpc83xx')
-rw-r--r--arch/powerpc/cpu/mpc83xx/Makefile62
-rw-r--r--arch/powerpc/cpu/mpc83xx/config.mk29
-rw-r--r--arch/powerpc/cpu/mpc83xx/cpu.c334
-rw-r--r--arch/powerpc/cpu/mpc83xx/cpu_init.c548
-rw-r--r--arch/powerpc/cpu/mpc83xx/ecc.c390
-rw-r--r--arch/powerpc/cpu/mpc83xx/fdt.c143
-rw-r--r--arch/powerpc/cpu/mpc83xx/interrupts.c97
-rw-r--r--arch/powerpc/cpu/mpc83xx/nand_init.c112
-rw-r--r--arch/powerpc/cpu/mpc83xx/pci.c241
-rw-r--r--arch/powerpc/cpu/mpc83xx/pcie.c317
-rw-r--r--arch/powerpc/cpu/mpc83xx/qe_io.c82
-rw-r--r--arch/powerpc/cpu/mpc83xx/serdes.c145
-rw-r--r--arch/powerpc/cpu/mpc83xx/spd_sdram.c918
-rw-r--r--arch/powerpc/cpu/mpc83xx/speed.c549
-rw-r--r--arch/powerpc/cpu/mpc83xx/start.S1207
-rw-r--r--arch/powerpc/cpu/mpc83xx/traps.c266
-rw-r--r--arch/powerpc/cpu/mpc83xx/u-boot.lds121
17 files changed, 5561 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/mpc83xx/Makefile b/arch/powerpc/cpu/mpc83xx/Makefile
new file mode 100644
index 0000000..15e2c18
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/Makefile
@@ -0,0 +1,62 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright 2004 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).a
+
+START = start.o
+
+COBJS-y += traps.o
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += speed.o
+COBJS-y += interrupts.o
+COBJS-y += spd_sdram.o
+COBJS-y += ecc.o
+COBJS-$(CONFIG_QE) += qe_io.o
+COBJS-$(CONFIG_FSL_SERDES) += serdes.o
+COBJS-$(CONFIG_PCI) += pci.o
+COBJS-$(CONFIG_PCIE) += pcie.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+
+COBJS := $(COBJS-y)
+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) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc83xx/config.mk b/arch/powerpc/cpu/mpc83xx/config.mk
new file mode 100644
index 0000000..8a3a8c1
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/config.mk
@@ -0,0 +1,29 @@
+#
+# Copyright 2004 Freescale Semiconductor, Inc.
+#
+# 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 -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC83xx -DCONFIG_E300 \
+ -ffixed-r2 -msoft-float
+
+# Use default linker script. Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc83xx/u-boot.lds
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c
new file mode 100644
index 0000000..51180d6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/cpu.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC83xx family.
+ *
+ * Derived from the MPC8260 and MPC85xx.
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+#include <libfdt.h>
+#include <tsec.h>
+#include <netdev.h>
+#include <fsl_esdhc.h>
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+#include <asm/immap_qe.h>
+#include <asm/io.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu(void)
+{
+ volatile immap_t *immr;
+ ulong clock = gd->cpu_clk;
+ u32 pvr = get_pvr();
+ u32 spridr;
+ char buf[32];
+ int i;
+
+ const struct cpu_type {
+ char name[15];
+ u32 partid;
+ } cpu_type_list [] = {
+ CPU_TYPE_ENTRY(8311),
+ CPU_TYPE_ENTRY(8313),
+ CPU_TYPE_ENTRY(8314),
+ CPU_TYPE_ENTRY(8315),
+ CPU_TYPE_ENTRY(8321),
+ CPU_TYPE_ENTRY(8323),
+ CPU_TYPE_ENTRY(8343),
+ CPU_TYPE_ENTRY(8347_TBGA_),
+ CPU_TYPE_ENTRY(8347_PBGA_),
+ CPU_TYPE_ENTRY(8349),
+ CPU_TYPE_ENTRY(8358_TBGA_),
+ CPU_TYPE_ENTRY(8358_PBGA_),
+ CPU_TYPE_ENTRY(8360),
+ CPU_TYPE_ENTRY(8377),
+ CPU_TYPE_ENTRY(8378),
+ CPU_TYPE_ENTRY(8379),
+ };
+
+ immr = (immap_t *)CONFIG_SYS_IMMR;
+
+ puts("CPU: ");
+
+ switch (pvr & 0xffff0000) {
+ case PVR_E300C1:
+ printf("e300c1, ");
+ break;
+
+ case PVR_E300C2:
+ printf("e300c2, ");
+ break;
+
+ case PVR_E300C3:
+ printf("e300c3, ");
+ break;
+
+ case PVR_E300C4:
+ printf("e300c4, ");
+ break;
+
+ default:
+ printf("Unknown core, ");
+ }
+
+ spridr = immr->sysconf.spridr;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++)
+ if (cpu_type_list[i].partid == PARTID_NO_E(spridr)) {
+ puts("MPC");
+ puts(cpu_type_list[i].name);
+ if (IS_E_PROCESSOR(spridr))
+ puts("E");
+ if (REVID_MAJOR(spridr) >= 2)
+ puts("A");
+ printf(", Rev: %d.%d", REVID_MAJOR(spridr),
+ REVID_MINOR(spridr));
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cpu_type_list))
+ printf("(SPRIDR %08x unknown), ", spridr);
+
+ printf(" at %s MHz, ", strmhz(buf, clock));
+
+ printf("CSB: %s MHz\n", strmhz(buf, gd->csb_clk));
+
+ return 0;
+}
+
+
+/*
+ * Program a UPM with the code supplied in the table.
+ *
+ * The 'dummy' variable is used to increment the MAD. 'dummy' is
+ * supposed to be a pointer to the memory of the device being
+ * programmed by the UPM. The data in the MDR is written into
+ * memory and the MAD is incremented every time there's a write
+ * to 'dummy'. Unfortunately, the current prototype for this
+ * function doesn't allow for passing the address of this
+ * device, and changing the prototype will break a number lots
+ * of other code, so we need to use a round-about way of finding
+ * the value for 'dummy'.
+ *
+ * The value can be extracted from the base address bits of the
+ * Base Register (BR) associated with the specific UPM. To find
+ * that BR, we need to scan all 8 BRs until we find the one that
+ * has its MSEL bits matching the UPM we want. Once we know the
+ * right BR, we can extract the base address bits from it.
+ *
+ * The MxMR and the BR and OR of the chosen bank should all be
+ * configured before calling this function.
+ *
+ * Parameters:
+ * upm: 0=UPMA, 1=UPMB, 2=UPMC
+ * table: Pointer to an array of values to program
+ * size: Number of elements in the array. Must be 64 or less.
+ */
+void upmconfig (uint upm, uint *table, uint size)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fsl_lbus_t *lbus = &immap->lbus;
+ volatile uchar *dummy = NULL;
+ const u32 msel = (upm + 4) << BR_MSEL_SHIFT; /* What the MSEL field in BRn should be */
+ volatile u32 *mxmr = &lbus->mamr + upm; /* Pointer to mamr, mbmr, or mcmr */
+ uint i;
+
+ /* Scan all the banks to determine the base address of the device */
+ for (i = 0; i < 8; i++) {
+ if ((lbus->bank[i].br & BR_MSEL) == msel) {
+ dummy = (uchar *) (lbus->bank[i].br & BR_BA);
+ break;
+ }
+ }
+
+ if (!dummy) {
+ printf("Error: %s() could not find matching BR\n", __FUNCTION__);
+ hang();
+ }
+
+ /* Set the OP field in the MxMR to "write" and the MAD field to 000000 */
+ *mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000;
+
+ for (i = 0; i < size; i++) {
+ lbus->mdr = table[i];
+ __asm__ __volatile__ ("sync");
+ *dummy = 0; /* Write the value to memory and increment MAD */
+ __asm__ __volatile__ ("sync");
+ while(((*mxmr & 0x3f) != ((i + 1) & 0x3f)));
+ }
+
+ /* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */
+ *mxmr &= 0xCFFFFFC0;
+}
+
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong msr;
+#ifndef MPC83xx_RESET
+ ulong addr;
+#endif
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ puts("Resetting the board.\n");
+
+#ifdef MPC83xx_RESET
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~( MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /* enable Reset Control Reg */
+ immap->reset.rpr = 0x52535445;
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("isync");
+
+ /* confirm Reset Control Reg is enabled */
+ while(!((immap->reset.rcer) & RCER_CRE));
+
+ udelay(200);
+
+ /* perform reset, only one bit */
+ immap->reset.rcr = RCR_SWHR;
+
+#else /* ! MPC83xx_RESET */
+
+ immap->reset.rmr = RMR_CSRE; /* Checkstop Reset enable */
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+ addr = CONFIG_SYS_RESET_ADDRESS;
+
+ ((void (*)(void)) addr) ();
+#endif /* MPC83xx_RESET */
+
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+
+unsigned long get_tbclk(void)
+{
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return tbclk;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts();
+
+ /* Reset the 83xx watchdog */
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ immr->wdt.swsrr = 0x556c;
+ immr->wdt.swsrr = 0xaa39;
+
+ if (re_enable)
+ enable_interrupts ();
+}
+#endif
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_UEC_ETH)
+ uec_standard_init(bis);
+#endif
+
+#if defined(CONFIG_TSEC_ENET)
+ tsec_standard_init(bis);
+#endif
+ return 0;
+}
+
+/*
+ * Initializes on-chip MMC controllers.
+ * to override, implement board_mmc_init()
+ */
+int cpu_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FSL_ESDHC
+ return fsl_esdhc_mmc_init(bis);
+#else
+ return 0;
+#endif
+}
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+#if !defined(CONFIG_MPC8360)
+#error "CONFIG_BOOTCOUNT_LIMIT only for MPC8360 implemented"
+#endif
+
+#if !defined(CONFIG_BOOTCOUNT_ADDR)
+#define CONFIG_BOOTCOUNT_ADDR (0x110000 + QE_MURAM_SIZE - 2 * sizeof(unsigned long))
+#endif
+
+#include <asm/io.h>
+
+void bootcount_store (ulong a)
+{
+ void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR);
+ out_be32 (reg, a);
+ out_be32 (reg + 4, BOOTCOUNT_MAGIC);
+}
+
+ulong bootcount_load (void)
+{
+ void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR);
+
+ if (in_be32 (reg + 4) != BOOTCOUNT_MAGIC)
+ return 0;
+ else
+ return in_be32 (reg);
+}
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c
new file mode 100644
index 0000000..75b4522
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
+ *
+ * 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 <mpc83xx.h>
+#include <ioports.h>
+#include <asm/io.h>
+#ifdef CONFIG_USB_EHCI_FSL
+#include <usb/ehci-fsl.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_QE
+extern qe_iop_conf_t qe_iop_conf_tab[];
+extern void qe_config_iopin(u8 port, u8 pin, int dir,
+ int open_drain, int assign);
+extern void qe_init(uint qe_base);
+extern void qe_reset(void);
+
+static void config_qe_ioports(void)
+{
+ u8 port, pin;
+ int dir, open_drain, assign;
+ int i;
+
+ for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) {
+ port = qe_iop_conf_tab[i].port;
+ pin = qe_iop_conf_tab[i].pin;
+ dir = qe_iop_conf_tab[i].dir;
+ open_drain = qe_iop_conf_tab[i].open_drain;
+ assign = qe_iop_conf_tab[i].assign;
+ qe_config_iopin(port, pin, dir, open_drain, assign);
+ }
+}
+#endif
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+ __be32 acr_mask =
+#ifdef CONFIG_SYS_ACR_PIPE_DEP /* Arbiter pipeline depth */
+ (ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_RPTCNT /* Arbiter repeat count */
+ (ACR_RPTCNT << ACR_RPTCNT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_APARK /* Arbiter address parking mode */
+ (ACR_APARK << ACR_APARK_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_PARKM /* Arbiter parking master */
+ (ACR_PARKM << ACR_PARKM_SHIFT) |
+#endif
+ 0;
+ __be32 acr_val =
+#ifdef CONFIG_SYS_ACR_PIPE_DEP /* Arbiter pipeline depth */
+ (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_RPTCNT /* Arbiter repeat count */
+ (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_APARK /* Arbiter address parking mode */
+ (CONFIG_SYS_ACR_APARK << ACR_APARK_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_PARKM /* Arbiter parking master */
+ (CONFIG_SYS_ACR_PARKM << ACR_PARKM_SHIFT) |
+#endif
+ 0;
+ __be32 spcr_mask =
+#ifdef CONFIG_SYS_SPCR_OPT /* Optimize transactions between CSB and other dev */
+ (SPCR_OPT << SPCR_OPT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSECEP /* all eTSEC's Emergency priority */
+ (SPCR_TSECEP << SPCR_TSECEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC1EP /* TSEC1 Emergency priority */
+ (SPCR_TSEC1EP << SPCR_TSEC1EP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC2EP /* TSEC2 Emergency priority */
+ (SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT) |
+#endif
+ 0;
+ __be32 spcr_val =
+#ifdef CONFIG_SYS_SPCR_OPT
+ (CONFIG_SYS_SPCR_OPT << SPCR_OPT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSECEP /* all eTSEC's Emergency priority */
+ (CONFIG_SYS_SPCR_TSECEP << SPCR_TSECEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC1EP /* TSEC1 Emergency priority */
+ (CONFIG_SYS_SPCR_TSEC1EP << SPCR_TSEC1EP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC2EP /* TSEC2 Emergency priority */
+ (CONFIG_SYS_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT) |
+#endif
+ 0;
+ __be32 sccr_mask =
+#ifdef CONFIG_SYS_SCCR_ENCCM /* Encryption clock mode */
+ (SCCR_ENCCM << SCCR_ENCCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCICM /* PCI & DMA clock mode */
+ (SCCR_PCICM << SCCR_PCICM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSECCM /* all TSEC's clock mode */
+ (SCCR_TSECCM << SCCR_TSECCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1CM /* TSEC1 clock mode */
+ (SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2CM /* TSEC2 clock mode */
+ (SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1ON /* TSEC1 clock switch */
+ (SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2ON /* TSEC2 clock switch */
+ (SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBMPHCM /* USB MPH clock mode */
+ (SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBDRCM /* USB DR clock mode */
+ (SCCR_USBDRCM << SCCR_USBDRCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_SATACM /* SATA controller clock mode */
+ (SCCR_SATACM << SCCR_SATACM_SHIFT) |
+#endif
+ 0;
+ __be32 sccr_val =
+#ifdef CONFIG_SYS_SCCR_ENCCM /* Encryption clock mode */
+ (CONFIG_SYS_SCCR_ENCCM << SCCR_ENCCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCICM /* PCI & DMA clock mode */
+ (CONFIG_SYS_SCCR_PCICM << SCCR_PCICM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSECCM /* all TSEC's clock mode */
+ (CONFIG_SYS_SCCR_TSECCM << SCCR_TSECCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1CM /* TSEC1 clock mode */
+ (CONFIG_SYS_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2CM /* TSEC2 clock mode */
+ (CONFIG_SYS_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1ON /* TSEC1 clock switch */
+ (CONFIG_SYS_SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2ON /* TSEC2 clock switch */
+ (CONFIG_SYS_SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBMPHCM /* USB MPH clock mode */
+ (CONFIG_SYS_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBDRCM /* USB DR clock mode */
+ (CONFIG_SYS_SCCR_USBDRCM << SCCR_USBDRCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_SATACM /* SATA controller clock mode */
+ (CONFIG_SYS_SCCR_SATACM << SCCR_SATACM_SHIFT) |
+#endif
+ 0;
+ __be32 lcrr_mask =
+#ifdef CONFIG_SYS_LCRR_DBYP /* PLL bypass */
+ LCRR_DBYP |
+#endif
+#ifdef CONFIG_SYS_LCRR_EADC /* external address delay */
+ LCRR_EADC |
+#endif
+#ifdef CONFIG_SYS_LCRR_CLKDIV /* system clock divider */
+ LCRR_CLKDIV |
+#endif
+ 0;
+ __be32 lcrr_val =
+#ifdef CONFIG_SYS_LCRR_DBYP /* PLL bypass */
+ CONFIG_SYS_LCRR_DBYP |
+#endif
+#ifdef CONFIG_SYS_LCRR_EADC
+ CONFIG_SYS_LCRR_EADC |
+#endif
+#ifdef CONFIG_SYS_LCRR_CLKDIV /* system clock divider */
+ CONFIG_SYS_LCRR_CLKDIV |
+#endif
+ 0;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* system performance tweaking */
+ clrsetbits_be32(&im->arbiter.acr, acr_mask, acr_val);
+
+ clrsetbits_be32(&im->sysconf.spcr, spcr_mask, spcr_val);
+
+ clrsetbits_be32(&im->clk.sccr, sccr_mask, sccr_val);
+
+ /* RSR - Reset Status Register - clear all status (4.6.1.3) */
+ gd->reset_status = __raw_readl(&im->reset.rsr);
+ __raw_writel(~(RSR_RES), &im->reset.rsr);
+
+ /* AER - Arbiter Event Register - store status */
+ gd->arbiter_event_attributes = __raw_readl(&im->arbiter.aeatr);
+ gd->arbiter_event_address = __raw_readl(&im->arbiter.aeadr);
+
+ /*
+ * RMR - Reset Mode Register
+ * contains checkstop reset enable (4.6.1.4)
+ */
+ __raw_writel(RMR_CSRE & (1<<RMR_CSRE_SHIFT), &im->reset.rmr);
+
+ /* LCRR - Clock Ratio Register (10.3.1.16)
+ * write, read, and isync per MPC8379ERM rev.1 CLKDEV field description
+ */
+ clrsetbits_be32(&im->lbus.lcrr, lcrr_mask, lcrr_val);
+ __raw_readl(&im->lbus.lcrr);
+ isync();
+
+ /* Enable Time Base & Decrementer ( so we will have udelay() )*/
+ setbits_be32(&im->sysconf.spcr, SPCR_TBEN);
+
+ /* System General Purpose Register */
+#ifdef CONFIG_SYS_SICRH
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC8313)
+ /* regarding to MPC34x manual rev.1 bits 28..29 must be preserved */
+ __raw_writel((im->sysconf.sicrh & 0x0000000C) | CONFIG_SYS_SICRH,
+ &im->sysconf.sicrh);
+#else
+ __raw_writel(CONFIG_SYS_SICRH, &im->sysconf.sicrh);
+#endif
+#endif
+#ifdef CONFIG_SYS_SICRL
+ __raw_writel(CONFIG_SYS_SICRL, &im->sysconf.sicrl);
+#endif
+#ifdef CONFIG_SYS_DDRCDR /* DDR control driver register */
+ __raw_writel(CONFIG_SYS_DDRCDR, &im->sysconf.ddrcdr);
+#endif
+#ifdef CONFIG_SYS_OBIR /* Output buffer impedance register */
+ __raw_writel(CONFIG_SYS_OBIR, &im->sysconf.obir);
+#endif
+
+#ifdef CONFIG_QE
+ /* Config QE ioports */
+ config_qe_ioports();
+#endif
+
+ /*
+ * Memory Controller:
+ */
+
+ /* 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(CONFIG_SYS_BR0_PRELIM) \
+ && defined(CONFIG_SYS_OR0_PRELIM) \
+ && defined(CONFIG_SYS_LBLAWBAR0_PRELIM) \
+ && defined(CONFIG_SYS_LBLAWAR0_PRELIM)
+ im->lbus.bank[0].br = CONFIG_SYS_BR0_PRELIM;
+ im->lbus.bank[0].or = CONFIG_SYS_OR0_PRELIM;
+ im->sysconf.lblaw[0].bar = CONFIG_SYS_LBLAWBAR0_PRELIM;
+ im->sysconf.lblaw[0].ar = CONFIG_SYS_LBLAWAR0_PRELIM;
+#else
+#error CONFIG_SYS_BR0_PRELIM, CONFIG_SYS_OR0_PRELIM, CONFIG_SYS_LBLAWBAR0_PRELIM & CONFIG_SYS_LBLAWAR0_PRELIM must be defined
+#endif
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+ im->lbus.bank[1].br = CONFIG_SYS_BR1_PRELIM;
+ im->lbus.bank[1].or = CONFIG_SYS_OR1_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR1_PRELIM) && defined(CONFIG_SYS_LBLAWAR1_PRELIM)
+ im->sysconf.lblaw[1].bar = CONFIG_SYS_LBLAWBAR1_PRELIM;
+ im->sysconf.lblaw[1].ar = CONFIG_SYS_LBLAWAR1_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+ im->lbus.bank[2].br = CONFIG_SYS_BR2_PRELIM;
+ im->lbus.bank[2].or = CONFIG_SYS_OR2_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR2_PRELIM) && defined(CONFIG_SYS_LBLAWAR2_PRELIM)
+ im->sysconf.lblaw[2].bar = CONFIG_SYS_LBLAWBAR2_PRELIM;
+ im->sysconf.lblaw[2].ar = CONFIG_SYS_LBLAWAR2_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+ im->lbus.bank[3].br = CONFIG_SYS_BR3_PRELIM;
+ im->lbus.bank[3].or = CONFIG_SYS_OR3_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR3_PRELIM) && defined(CONFIG_SYS_LBLAWAR3_PRELIM)
+ im->sysconf.lblaw[3].bar = CONFIG_SYS_LBLAWBAR3_PRELIM;
+ im->sysconf.lblaw[3].ar = CONFIG_SYS_LBLAWAR3_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+ im->lbus.bank[4].br = CONFIG_SYS_BR4_PRELIM;
+ im->lbus.bank[4].or = CONFIG_SYS_OR4_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR4_PRELIM) && defined(CONFIG_SYS_LBLAWAR4_PRELIM)
+ im->sysconf.lblaw[4].bar = CONFIG_SYS_LBLAWBAR4_PRELIM;
+ im->sysconf.lblaw[4].ar = CONFIG_SYS_LBLAWAR4_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+ im->lbus.bank[5].br = CONFIG_SYS_BR5_PRELIM;
+ im->lbus.bank[5].or = CONFIG_SYS_OR5_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR5_PRELIM) && defined(CONFIG_SYS_LBLAWAR5_PRELIM)
+ im->sysconf.lblaw[5].bar = CONFIG_SYS_LBLAWBAR5_PRELIM;
+ im->sysconf.lblaw[5].ar = CONFIG_SYS_LBLAWAR5_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+ im->lbus.bank[6].br = CONFIG_SYS_BR6_PRELIM;
+ im->lbus.bank[6].or = CONFIG_SYS_OR6_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR6_PRELIM) && defined(CONFIG_SYS_LBLAWAR6_PRELIM)
+ im->sysconf.lblaw[6].bar = CONFIG_SYS_LBLAWBAR6_PRELIM;
+ im->sysconf.lblaw[6].ar = CONFIG_SYS_LBLAWAR6_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+ im->lbus.bank[7].br = CONFIG_SYS_BR7_PRELIM;
+ im->lbus.bank[7].or = CONFIG_SYS_OR7_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR7_PRELIM) && defined(CONFIG_SYS_LBLAWAR7_PRELIM)
+ im->sysconf.lblaw[7].bar = CONFIG_SYS_LBLAWBAR7_PRELIM;
+ im->sysconf.lblaw[7].ar = CONFIG_SYS_LBLAWAR7_PRELIM;
+#endif
+#ifdef CONFIG_SYS_GPIO1_PRELIM
+ im->gpio[0].dat = CONFIG_SYS_GPIO1_DAT;
+ im->gpio[0].dir = CONFIG_SYS_GPIO1_DIR;
+#endif
+#ifdef CONFIG_SYS_GPIO2_PRELIM
+ im->gpio[1].dat = CONFIG_SYS_GPIO2_DAT;
+ im->gpio[1].dir = CONFIG_SYS_GPIO2_DIR;
+#endif
+#ifdef CONFIG_USB_EHCI_FSL
+#ifndef CONFIG_MPC834x
+ uint32_t temp;
+ struct usb_ehci *ehci = (struct usb_ehci *)CONFIG_SYS_MPC8xxx_USB_ADDR;
+
+ /* Configure interface. */
+ setbits_be32(&ehci->control, REFSEL_16MHZ | UTMI_PHY_EN);
+
+ /* Wait for clock to stabilize */
+ do {
+ temp = __raw_readl(&ehci->control);
+ udelay(1000);
+ } while (!(temp & PHY_CLK_VALID));
+#endif
+#endif
+}
+
+int cpu_init_r (void)
+{
+#ifdef CONFIG_QE
+ uint qe_base = CONFIG_SYS_IMMR + 0x00100000; /* QE immr base */
+
+ qe_init(qe_base);
+ qe_reset();
+#endif
+ return 0;
+}
+
+/*
+ * Print out the bus arbiter event
+ */
+#if defined(CONFIG_DISPLAY_AER_FULL)
+static int print_83xx_arb_event(int force)
+{
+ static char* event[] = {
+ "Address Time Out",
+ "Data Time Out",
+ "Address Only Transfer Type",
+ "External Control Word Transfer Type",
+ "Reserved Transfer Type",
+ "Transfer Error",
+ "reserved",
+ "reserved"
+ };
+ static char* master[] = {
+ "e300 Core Data Transaction",
+ "reserved",
+ "e300 Core Instruction Fetch",
+ "reserved",
+ "TSEC1",
+ "TSEC2",
+ "USB MPH",
+ "USB DR",
+ "Encryption Core",
+ "I2C Boot Sequencer",
+ "JTAG",
+ "reserved",
+ "eSDHC",
+ "PCI1",
+ "PCI2",
+ "DMA",
+ "QUICC Engine 00",
+ "QUICC Engine 01",
+ "QUICC Engine 10",
+ "QUICC Engine 11",
+ "reserved",
+ "reserved",
+ "reserved",
+ "reserved",
+ "SATA1",
+ "SATA2",
+ "SATA3",
+ "SATA4",
+ "reserved",
+ "PCI Express 1",
+ "PCI Express 2",
+ "TDM-DMAC"
+ };
+ static char *transfer[] = {
+ "Address-only, Clean Block",
+ "Address-only, lwarx reservation set",
+ "Single-beat or Burst write",
+ "reserved",
+ "Address-only, Flush Block",
+ "reserved",
+ "Burst write",
+ "reserved",
+ "Address-only, sync",
+ "Address-only, tlbsync",
+ "Single-beat or Burst read",
+ "Single-beat or Burst read",
+ "Address-only, Kill Block",
+ "Address-only, icbi",
+ "Burst read",
+ "reserved",
+ "Address-only, eieio",
+ "reserved",
+ "Single-beat write",
+ "reserved",
+ "ecowx - Illegal single-beat write",
+ "reserved",
+ "reserved",
+ "reserved",
+ "Address-only, TLB Invalidate",
+ "reserved",
+ "Single-beat or Burst read",
+ "reserved",
+ "eciwx - Illegal single-beat read",
+ "reserved",
+ "Burst read",
+ "reserved"
+ };
+
+ int etype = (gd->arbiter_event_attributes & AEATR_EVENT)
+ >> AEATR_EVENT_SHIFT;
+ int mstr_id = (gd->arbiter_event_attributes & AEATR_MSTR_ID)
+ >> AEATR_MSTR_ID_SHIFT;
+ int tbst = (gd->arbiter_event_attributes & AEATR_TBST)
+ >> AEATR_TBST_SHIFT;
+ int tsize = (gd->arbiter_event_attributes & AEATR_TSIZE)
+ >> AEATR_TSIZE_SHIFT;
+ int ttype = (gd->arbiter_event_attributes & AEATR_TTYPE)
+ >> AEATR_TTYPE_SHIFT;
+
+ if (!force && !gd->arbiter_event_address)
+ return 0;
+
+ puts("Arbiter Event Status:\n");
+ printf(" Event Address: 0x%08lX\n", gd->arbiter_event_address);
+ printf(" Event Type: 0x%1x = %s\n", etype, event[etype]);
+ printf(" Master ID: 0x%02x = %s\n", mstr_id, master[mstr_id]);
+ printf(" Transfer Size: 0x%1x = %d bytes\n", (tbst<<3) | tsize,
+ tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize);
+ printf(" Transfer Type: 0x%02x = %s\n", ttype, transfer[ttype]);
+
+ return gd->arbiter_event_address;
+}
+
+#elif defined(CONFIG_DISPLAY_AER_BRIEF)
+
+static int print_83xx_arb_event(int force)
+{
+ if (!force && !gd->arbiter_event_address)
+ return 0;
+
+ printf("Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+ gd->arbiter_event_attributes, gd->arbiter_event_address);
+
+ return gd->arbiter_event_address;
+}
+#endif /* CONFIG_DISPLAY_AER_xxxx */
+
+/*
+ * Figure out the cause of the reset
+ */
+int prt_83xx_rsr(void)
+{
+ static struct {
+ ulong mask;
+ char *desc;
+ } bits[] = {
+ {
+ RSR_SWSR, "Software Soft"}, {
+ RSR_SWHR, "Software Hard"}, {
+ RSR_JSRS, "JTAG Soft"}, {
+ RSR_CSHR, "Check Stop"}, {
+ RSR_SWRS, "Software Watchdog"}, {
+ RSR_BMRS, "Bus Monitor"}, {
+ RSR_SRS, "External/Internal Soft"}, {
+ RSR_HRS, "External/Internal Hard"}
+ };
+ static int n = sizeof bits / sizeof bits[0];
+ ulong rsr = gd->reset_status;
+ int i;
+ char *sep;
+
+ puts("Reset Status:");
+
+ sep = " ";
+ for (i = 0; i < n; i++)
+ if (rsr & bits[i].mask) {
+ printf("%s%s", sep, bits[i].desc);
+ sep = ", ";
+ }
+ puts("\n");
+
+#if defined(CONFIG_DISPLAY_AER_FULL) || defined(CONFIG_DISPLAY_AER_BRIEF)
+ print_83xx_arb_event(rsr & RSR_BMRS);
+#endif
+ puts("\n");
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc83xx/ecc.c b/arch/powerpc/cpu/mpc83xx/ecc.c
new file mode 100644
index 0000000..f3942b4
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/ecc.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on the contribution of Marian Balakowicz <m8@semihalf.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.
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <command.h>
+
+#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD)
+void ecc_print_status(void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+
+ printf("\nECC mode: %s\n\n",
+ (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF");
+
+ /* Interrupts */
+ printf("Memory Error Interrupt Enable:\n");
+ printf(" Multiple-Bit Error Interrupt Enable: %d\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0);
+ printf(" Single-Bit Error Interrupt Enable: %d\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0);
+ printf(" Memory Select Error Interrupt Enable: %d\n\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0);
+
+ /* Error disable */
+ printf("Memory Error Disable:\n");
+ printf(" Multiple-Bit Error Disable: %d\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0);
+ printf(" Sinle-Bit Error Disable: %d\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0);
+ printf(" Memory Select Error Disable: %d\n\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0);
+
+ /* Error injection */
+ printf("Memory Data Path Error Injection Mask High/Low: %08x %08x\n",
+ ddr->data_err_inject_hi, ddr->data_err_inject_lo);
+
+ printf("Memory Data Path Error Injection Mask ECC:\n");
+ printf(" ECC Mirror Byte: %d\n",
+ (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0);
+ printf(" ECC Injection Enable: %d\n",
+ (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0);
+ printf(" ECC Error Injection Mask: 0x%02x\n\n",
+ ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM);
+
+ /* SBE counter/threshold */
+ printf("Memory Single-Bit Error Management (0..255):\n");
+ printf(" Single-Bit Error Threshold: %d\n",
+ (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT);
+ printf(" Single-Bit Error Counter: %d\n\n",
+ (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT);
+
+ /* Error detect */
+ printf("Memory Error Detect:\n");
+ printf(" Multiple Memory Errors: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0);
+ printf(" Multiple-Bit Error: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0);
+ printf(" Single-Bit Error: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0);
+ printf(" Memory Select Error: %d\n\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0);
+
+ /* Capture data */
+ printf("Memory Error Address Capture: 0x%08x\n", ddr->capture_address);
+ printf("Memory Data Path Read Capture High/Low: %08x %08x\n",
+ ddr->capture_data_hi, ddr->capture_data_lo);
+ printf("Memory Data Path Read Capture ECC: 0x%02x\n\n",
+ ddr->capture_ecc & CAPTURE_ECC_ECE);
+
+ printf("Memory Error Attributes Capture:\n");
+ printf(" Data Beat Number: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >>
+ ECC_CAPT_ATTR_BNUM_SHIFT);
+ printf(" Transaction Size: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >>
+ ECC_CAPT_ATTR_TSIZ_SHIFT);
+ printf(" Transaction Source: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >>
+ ECC_CAPT_ATTR_TSRC_SHIFT);
+ printf(" Transaction Type: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >>
+ ECC_CAPT_ATTR_TTYP_SHIFT);
+ printf(" Error Information Valid: %d\n\n",
+ ddr->capture_attributes & ECC_CAPT_ATTR_VLD);
+}
+
+int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ volatile u32 val;
+ u64 *addr;
+ u32 count;
+ register u64 *i;
+ u32 ret[2];
+ u32 pattern[2];
+ u32 writeback[2];
+
+ /* The pattern is written into memory to generate error */
+ pattern[0] = 0xfedcba98UL;
+ pattern[1] = 0x76543210UL;
+
+ /* After injecting error, re-initialize the memory with the value */
+ writeback[0] = 0x01234567UL;
+ writeback[1] = 0x89abcdefUL;
+
+ if (argc > 4) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ if (argc == 2) {
+ if (strcmp(argv[1], "status") == 0) {
+ ecc_print_status();
+ return 0;
+ } else if (strcmp(argv[1], "captureclear") == 0) {
+ ddr->capture_address = 0;
+ ddr->capture_data_hi = 0;
+ ddr->capture_data_lo = 0;
+ ddr->capture_ecc = 0;
+ ddr->capture_attributes = 0;
+ return 0;
+ }
+ }
+ if (argc == 3) {
+ if (strcmp(argv[1], "sbecnt") == 0) {
+ val = simple_strtoul(argv[2], NULL, 10);
+ if (val > 255) {
+ printf("Incorrect Counter value, "
+ "should be 0..255\n");
+ return 1;
+ }
+
+ val = (val << ECC_ERROR_MAN_SBEC_SHIFT);
+ val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET);
+
+ ddr->err_sbe = val;
+ return 0;
+ } else if (strcmp(argv[1], "sbethr") == 0) {
+ val = simple_strtoul(argv[2], NULL, 10);
+ if (val > 255) {
+ printf("Incorrect Counter value, "
+ "should be 0..255\n");
+ return 1;
+ }
+
+ val = (val << ECC_ERROR_MAN_SBET_SHIFT);
+ val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC);
+
+ ddr->err_sbe = val;
+ return 0;
+ } else if (strcmp(argv[1], "errdisable") == 0) {
+ val = ddr->err_disable;
+
+ if (strcmp(argv[2], "+sbe") == 0) {
+ val |= ECC_ERROR_DISABLE_SBED;
+ } else if (strcmp(argv[2], "+mbe") == 0) {
+ val |= ECC_ERROR_DISABLE_MBED;
+ } else if (strcmp(argv[2], "+mse") == 0) {
+ val |= ECC_ERROR_DISABLE_MSED;
+ } else if (strcmp(argv[2], "+all") == 0) {
+ val |= (ECC_ERROR_DISABLE_SBED |
+ ECC_ERROR_DISABLE_MBED |
+ ECC_ERROR_DISABLE_MSED);
+ } else if (strcmp(argv[2], "-sbe") == 0) {
+ val &= ~ECC_ERROR_DISABLE_SBED;
+ } else if (strcmp(argv[2], "-mbe") == 0) {
+ val &= ~ECC_ERROR_DISABLE_MBED;
+ } else if (strcmp(argv[2], "-mse") == 0) {
+ val &= ~ECC_ERROR_DISABLE_MSED;
+ } else if (strcmp(argv[2], "-all") == 0) {
+ val &= ~(ECC_ERROR_DISABLE_SBED |
+ ECC_ERROR_DISABLE_MBED |
+ ECC_ERROR_DISABLE_MSED);
+ } else {
+ printf("Incorrect err_disable field\n");
+ return 1;
+ }
+
+ ddr->err_disable = val;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+ return 0;
+ } else if (strcmp(argv[1], "errdetectclr") == 0) {
+ val = ddr->err_detect;
+
+ if (strcmp(argv[2], "mme") == 0) {
+ val |= ECC_ERROR_DETECT_MME;
+ } else if (strcmp(argv[2], "sbe") == 0) {
+ val |= ECC_ERROR_DETECT_SBE;
+ } else if (strcmp(argv[2], "mbe") == 0) {
+ val |= ECC_ERROR_DETECT_MBE;
+ } else if (strcmp(argv[2], "mse") == 0) {
+ val |= ECC_ERROR_DETECT_MSE;
+ } else if (strcmp(argv[2], "all") == 0) {
+ val |= (ECC_ERROR_DETECT_MME |
+ ECC_ERROR_DETECT_MBE |
+ ECC_ERROR_DETECT_SBE |
+ ECC_ERROR_DETECT_MSE);
+ } else {
+ printf("Incorrect err_detect field\n");
+ return 1;
+ }
+
+ ddr->err_detect = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectdatahi") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ ddr->data_err_inject_hi = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectdatalo") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ ddr->data_err_inject_lo = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectecc") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+ if (val > 0xff) {
+ printf("Incorrect ECC inject mask, "
+ "should be 0x00..0xff\n");
+ return 1;
+ }
+ val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM);
+
+ ddr->ecc_err_inject = val;
+ return 0;
+ } else if (strcmp(argv[1], "inject") == 0) {
+ val = ddr->ecc_err_inject;
+
+ if (strcmp(argv[2], "en") == 0)
+ val |= ECC_ERR_INJECT_EIEN;
+ else if (strcmp(argv[2], "dis") == 0)
+ val &= ~ECC_ERR_INJECT_EIEN;
+ else
+ printf("Incorrect command\n");
+
+ ddr->ecc_err_inject = val;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+ return 0;
+ } else if (strcmp(argv[1], "mirror") == 0) {
+ val = ddr->ecc_err_inject;
+
+ if (strcmp(argv[2], "en") == 0)
+ val |= ECC_ERR_INJECT_EMB;
+ else if (strcmp(argv[2], "dis") == 0)
+ val &= ~ECC_ERR_INJECT_EMB;
+ else
+ printf("Incorrect command\n");
+
+ ddr->ecc_err_inject = val;
+ return 0;
+ }
+ }
+ if (argc == 4) {
+ if (strcmp(argv[1], "testdw") == 0) {
+ addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if ((u32) addr % 8) {
+ printf("Address not alligned on "
+ "double word boundary\n");
+ return 1;
+ }
+ disable_interrupts();
+
+ for (i = addr; i < addr + count; i++) {
+
+ /* enable injects */
+ ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* write memory location injecting errors */
+ ppcDWstore((u32 *) i, pattern);
+ __asm__ __volatile__("sync");
+
+ /* disable injects */
+ ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* read data, this generates ECC error */
+ ppcDWload((u32 *) i, ret);
+ __asm__ __volatile__("sync");
+
+ /* re-initialize memory, double word write the location again,
+ * generates new ECC code this time */
+ ppcDWstore((u32 *) i, writeback);
+ __asm__ __volatile__("sync");
+ }
+ enable_interrupts();
+ return 0;
+ }
+ if (strcmp(argv[1], "testword") == 0) {
+ addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if ((u32) addr % 8) {
+ printf("Address not alligned on "
+ "double word boundary\n");
+ return 1;
+ }
+ disable_interrupts();
+
+ for (i = addr; i < addr + count; i++) {
+
+ /* enable injects */
+ ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* write memory location injecting errors */
+ *(u32 *) i = 0xfedcba98UL;
+ __asm__ __volatile__("sync");
+
+ /* sub double word write,
+ * bus will read-modify-write,
+ * generates ECC error */
+ *((u32 *) i + 1) = 0x76543210UL;
+ __asm__ __volatile__("sync");
+
+ /* disable injects */
+ ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* re-initialize memory,
+ * double word write the location again,
+ * generates new ECC code this time */
+ ppcDWstore((u32 *) i, writeback);
+ __asm__ __volatile__("sync");
+ }
+ enable_interrupts();
+ return 0;
+ }
+ }
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(ecc, 4, 0, do_ecc,
+ "support for DDR ECC features",
+ "status - print out status info\n"
+ "ecc captureclear - clear capture regs data\n"
+ "ecc sbecnt <val> - set Single-Bit Error counter\n"
+ "ecc sbethr <val> - set Single-Bit Threshold\n"
+ "ecc errdisable <flag> - clear/set disable Memory Error Disable, flag:\n"
+ " [-|+]sbe - Single-Bit Error\n"
+ " [-|+]mbe - Multiple-Bit Error\n"
+ " [-|+]mse - Memory Select Error\n"
+ " [-|+]all - all errors\n"
+ "ecc errdetectclr <flag> - clear Memory Error Detect, flag:\n"
+ " mme - Multiple Memory Errors\n"
+ " sbe - Single-Bit Error\n"
+ " mbe - Multiple-Bit Error\n"
+ " mse - Memory Select Error\n"
+ " all - all errors\n"
+ "ecc injectdatahi <hi> - set Memory Data Path Error Injection Mask High\n"
+ "ecc injectdatalo <lo> - set Memory Data Path Error Injection Mask Low\n"
+ "ecc injectecc <ecc> - set ECC Error Injection Mask\n"
+ "ecc inject <en|dis> - enable/disable error injection\n"
+ "ecc mirror <en|dis> - enable/disable mirror byte\n"
+ "ecc testdw <addr> <cnt> - test mem region with double word access:\n"
+ " - enables injects\n"
+ " - writes pattern injecting errors with double word access\n"
+ " - disables injects\n"
+ " - reads pattern back with double word access, generates error\n"
+ " - re-inits memory\n"
+ "ecc testword <addr> <cnt> - test mem region with word access:\n"
+ " - enables injects\n"
+ " - writes pattern injecting errors with word access\n"
+ " - writes pattern with word access, generates error\n"
+ " - disables injects\n" " - re-inits memory");
+#endif
diff --git a/arch/powerpc/cpu/mpc83xx/fdt.c b/arch/powerpc/cpu/mpc83xx/fdt.c
new file mode 100644
index 0000000..daf73a6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/fdt.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ *
+ * (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
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/processor.h>
+
+extern void ft_qe_setup(void *blob);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT) && defined(CONFIG_MPC8360)
+#include <asm/immap_qe.h>
+
+void fdt_fixup_muram (void *blob)
+{
+ ulong data[2];
+
+ data[0] = 0;
+ data[1] = QE_MURAM_SIZE - 2 * sizeof(unsigned long);
+ do_fixup_by_compat(blob, "fsl,qe-muram-data", "reg",
+ data, sizeof (data), 0);
+}
+#endif
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ int spridr = immr->sysconf.spridr;
+
+ /*
+ * delete crypto node if not on an E-processor
+ * initial revisions of the MPC834xE/6xE have the original SEC 2.0.
+ * EA revisions got the SEC uprevved to 2.4 but since the default device
+ * tree contains SEC 2.0 properties we uprev them here.
+ */
+ if (!IS_E_PROCESSOR(spridr))
+ fdt_fixup_crypto_node(blob, 0);
+ else if (IS_E_PROCESSOR(spridr) &&
+ (SPR_FAMILY(spridr) == SPR_834X_FAMILY ||
+ SPR_FAMILY(spridr) == SPR_836X_FAMILY) &&
+ REVID_MAJOR(spridr) >= 2)
+ fdt_fixup_crypto_node(blob, 0x0204);
+
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
+ defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3) ||\
+ defined(CONFIG_HAS_ETH4) || defined(CONFIG_HAS_ETH5)
+ fdt_fixup_ethernet(blob);
+#ifdef CONFIG_MPC8313
+ /*
+ * mpc8313e erratum IPIC1 swapped TSEC interrupt ID numbers on rev. 1
+ * h/w (see AN3545). The base device tree in use has rev. 1 ID numbers,
+ * so if on Rev. 2 (and higher) h/w, we fix them up here
+ */
+ if (REVID_MAJOR(immr->sysconf.spridr) >= 2) {
+ int nodeoffset, path;
+ const char *prop;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+#if defined(CONFIG_HAS_ETH0)
+ prop = fdt_getprop(blob, nodeoffset, "ethernet0", NULL);
+ if (prop) {
+ u32 tmp[] = { 32, 0x8, 33, 0x8, 34, 0x8 };
+
+ path = fdt_path_offset(blob, prop);
+ prop = fdt_getprop(blob, path, "interrupts", 0);
+ if (prop)
+ fdt_setprop(blob, path, "interrupts",
+ &tmp, sizeof(tmp));
+ }
+#endif
+#if defined(CONFIG_HAS_ETH1)
+ prop = fdt_getprop(blob, nodeoffset, "ethernet1", NULL);
+ if (prop) {
+ u32 tmp[] = { 35, 0x8, 36, 0x8, 37, 0x8 };
+
+ path = fdt_path_offset(blob, prop);
+ prop = fdt_getprop(blob, path, "interrupts", 0);
+ if (prop)
+ fdt_setprop(blob, path, "interrupts",
+ &tmp, sizeof(tmp));
+ }
+#endif
+ }
+ }
+#endif
+#endif
+
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", (bd->bi_busfreq / 4), 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "clock-frequency", gd->core_clk, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,soc",
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,soc",
+ "clock-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,immr",
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,immr",
+ "clock-frequency", bd->bi_busfreq, 1);
+#ifdef CONFIG_QE
+ ft_qe_setup(blob);
+#endif
+
+#ifdef CONFIG_SYS_NS16550
+ do_fixup_by_compat_u32(blob, "ns16550",
+ "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT)
+ fdt_fixup_muram (blob);
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc83xx/interrupts.c b/arch/powerpc/cpu/mpc83xx/interrupts.c
new file mode 100644
index 0000000..faffbaf
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/interrupts.c
@@ -0,0 +1,97 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc.
+ *
+ * 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 <mpc83xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ *decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_HZ;
+
+ /* Enable e300 time base */
+
+ immr->sysconf.spcr |= 0x00400000;
+
+ return 0;
+}
+
+
+/*
+ * Handle external interrupts
+ */
+
+void external_interrupt (struct pt_regs *regs)
+{
+}
+
+
+/*
+ * Install and free an interrupt handler.
+ */
+
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+}
+
+
+void irq_free_handler (int irq)
+{
+}
+
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+
+#if defined(CONFIG_CMD_IRQ)
+
+/* ripped this out of ppc4xx/interrupts.c */
+
+/*
+ * irqinfo - print information about PCI devices
+ */
+
+void
+do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc83xx/nand_init.c b/arch/powerpc/cpu/mpc83xx/nand_init.c
new file mode 100644
index 0000000..38e141a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/nand_init.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ *
+ * 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 <mpc83xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+ int i;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ for (i = 0; i < sizeof(gd_t); i++)
+ ((char *)gd)[i] = 0;
+
+ /* system performance tweaking */
+
+#ifdef CONFIG_SYS_ACR_PIPE_DEP
+ /* Arbiter pipeline depth */
+ im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) |
+ (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT);
+#endif
+
+#ifdef CONFIG_SYS_ACR_RPTCNT
+ /* Arbiter repeat count */
+ im->arbiter.acr = (im->arbiter.acr & ~(ACR_RPTCNT)) |
+ (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT);
+#endif
+
+#ifdef CONFIG_SYS_SPCR_OPT
+ /* Optimize transactions between CSB and other devices */
+ im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_OPT) |
+ (CONFIG_SYS_SPCR_OPT << SPCR_OPT_SHIFT);
+#endif
+
+ /* Enable Time Base & Decrimenter (so we will have udelay()) */
+ im->sysconf.spcr |= SPCR_TBEN;
+
+ /* DDR control driver register */
+#ifdef CONFIG_SYS_DDRCDR
+ im->sysconf.ddrcdr = CONFIG_SYS_DDRCDR;
+#endif
+ /* Output buffer impedance register */
+#ifdef CONFIG_SYS_OBIR
+ im->sysconf.obir = CONFIG_SYS_OBIR;
+#endif
+
+ /*
+ * Memory Controller:
+ */
+
+ /* 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(CONFIG_SYS_NAND_BR_PRELIM) \
+ && defined(CONFIG_SYS_NAND_OR_PRELIM) \
+ && defined(CONFIG_SYS_NAND_LBLAWBAR_PRELIM) \
+ && defined(CONFIG_SYS_NAND_LBLAWAR_PRELIM)
+ im->lbus.bank[0].br = CONFIG_SYS_NAND_BR_PRELIM;
+ im->lbus.bank[0].or = CONFIG_SYS_NAND_OR_PRELIM;
+ im->sysconf.lblaw[0].bar = CONFIG_SYS_NAND_LBLAWBAR_PRELIM;
+ im->sysconf.lblaw[0].ar = CONFIG_SYS_NAND_LBLAWAR_PRELIM;
+#else
+#error CONFIG_SYS_NAND_BR_PRELIM, CONFIG_SYS_NAND_OR_PRELIM, CONFIG_SYS_NAND_LBLAWBAR_PRELIM & CONFIG_SYS_NAND_LBLAWAR_PRELIM must be defined
+#endif
+}
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+unsigned long get_tbclk(void)
+{
+ return (gd->bus_clk + 3L) / 4L;
+}
+
+void puts(const char *str)
+{
+ while (*str)
+ putc(*str++);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/pci.c b/arch/powerpc/cpu/mpc83xx/pci.c
new file mode 100644
index 0000000..a42b230
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/pci.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) Freescale Semiconductor, Inc. 2007
+ *
+ * Author: Scott Wood <scottwood@freescale.com>,
+ * with some bits from older board-specific PCI initialization.
+ *
+ * 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 <pci.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#include <asm/mpc8349_pci.h>
+
+#define MAX_BUSES 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct pci_controller pci_hose[MAX_BUSES];
+static int pci_num_buses;
+
+static void pci_init_bus(int bus, struct pci_region *reg)
+{
+ volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+ volatile pot83xx_t *pot = immr->ios.pot;
+ volatile pcictrl83xx_t *pci_ctrl = &immr->pci_ctrl[bus];
+ struct pci_controller *hose = &pci_hose[bus];
+ u32 dev;
+ u16 reg16;
+ int i;
+
+ if (bus == 1)
+ pot += 3;
+
+ /* Setup outbound translation windows */
+ for (i = 0; i < 3; i++, reg++, pot++) {
+ if (reg->size == 0)
+ break;
+
+ hose->regions[i] = *reg;
+ hose->region_count++;
+
+ pot->potar = reg->bus_start >> 12;
+ pot->pobar = reg->phys_start >> 12;
+ pot->pocmr = ~(reg->size - 1) >> 12;
+
+ if (reg->flags & PCI_REGION_IO)
+ pot->pocmr |= POCMR_IO;
+#ifdef CONFIG_83XX_PCI_STREAMING
+ else if (reg->flags & PCI_REGION_PREFETCH)
+ pot->pocmr |= POCMR_SE;
+#endif
+
+ if (bus == 1)
+ pot->pocmr |= POCMR_DST;
+
+ pot->pocmr |= POCMR_EN;
+ }
+
+ /* Point inbound translation at RAM */
+ pci_ctrl->pitar1 = 0;
+ pci_ctrl->pibar1 = 0;
+ pci_ctrl->piebar1 = 0;
+ pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP |
+ PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size - 1));
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = 0;
+ hose->regions[i].phys_start = 0;
+ hose->regions[i].size = gd->ram_size;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+ hose->first_busno = pci_last_busno() + 1;
+ hose->last_busno = 0xff;
+
+ pci_setup_indirect(hose, CONFIG_SYS_IMMR + 0x8300 + bus * 0x80,
+ CONFIG_SYS_IMMR + 0x8304 + bus * 0x80);
+
+ pci_register_hose(hose);
+
+ /*
+ * Write to Command register
+ */
+ reg16 = 0xff;
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+#ifndef CONFIG_PCISLAVE
+ /*
+ * Hose scan.
+ */
+ hose->last_busno = pci_hose_scan(hose);
+#endif
+}
+
+/*
+ * The caller must have already set OCCR, and the PCI_LAW BARs
+ * must have been set to cover all of the requested regions.
+ *
+ * If fewer than three regions are requested, then the region
+ * list is terminated with a region of size 0.
+ */
+void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot)
+{
+ volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+ int i;
+
+ if (num_buses > MAX_BUSES) {
+ printf("%d PCI buses requsted, %d supported\n",
+ num_buses, MAX_BUSES);
+
+ num_buses = MAX_BUSES;
+ }
+
+ pci_num_buses = num_buses;
+
+ /*
+ * Release PCI RST Output signal.
+ * Power on to RST high must be at least 100 ms as per PCI spec.
+ * On warm boots only 1 ms is required.
+ */
+ udelay(warmboot ? 1000 : 100000);
+
+ for (i = 0; i < num_buses; i++)
+ immr->pci_ctrl[i].gcr = 1;
+
+ /*
+ * RST high to first config access must be at least 2^25 cycles
+ * as per PCI spec. This could be cut in half if we know we're
+ * running at 66MHz. This could be insufficiently long if we're
+ * running the PCI bus at significantly less than 33MHz.
+ */
+ udelay(1020000);
+
+ for (i = 0; i < num_buses; i++)
+ pci_init_bus(i, reg[i]);
+}
+
+#ifdef CONFIG_PCISLAVE
+
+#define PCI_FUNCTION_CONFIG 0x44
+#define PCI_FUNCTION_CFG_LOCK 0x20
+
+/*
+ * Unlock the configuration bit so that the host system can begin booting
+ *
+ * This should be used after you have:
+ * 1) Called mpc83xx_pci_init()
+ * 2) Set up your inbound translation windows to the appropriate size
+ */
+void mpc83xx_pcislave_unlock(int bus)
+{
+ struct pci_controller *hose = &pci_hose[bus];
+ u32 dev;
+ u16 reg16;
+
+ /* Unlock configuration lock in PCI function configuration register */
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word (hose, dev, PCI_FUNCTION_CONFIG, &reg16);
+ reg16 &= ~(PCI_FUNCTION_CFG_LOCK);
+ pci_hose_write_config_word (hose, dev, PCI_FUNCTION_CONFIG, reg16);
+
+ /* The configuration bit is now unlocked, so we can scan the bus */
+ hose->last_busno = pci_hose_scan(hose);
+}
+#endif
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ int nodeoffset;
+ int tmp[2];
+ const char *path;
+
+ if (pci_num_buses < 1)
+ return;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+ path = fdt_getprop(blob, nodeoffset, "pci0", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+ tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+
+ tmp[0] = cpu_to_be32(gd->pci_clk);
+ do_fixup_by_path(blob, path, "clock-frequency",
+ &tmp, sizeof(tmp[0]), 1);
+ }
+
+ if (pci_num_buses < 2)
+ return;
+
+ path = fdt_getprop(blob, nodeoffset, "pci1", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(pci_hose[1].first_busno);
+ tmp[1] = cpu_to_be32(pci_hose[1].last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+
+ tmp[0] = cpu_to_be32(gd->pci_clk);
+ do_fixup_by_path(blob, path, "clock-frequency",
+ &tmp, sizeof(tmp[0]), 1);
+ }
+ }
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/arch/powerpc/cpu/mpc83xx/pcie.c b/arch/powerpc/cpu/mpc83xx/pcie.c
new file mode 100644
index 0000000..77f8906
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/pcie.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2007-2009 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008-2009 MontaVista Software, Inc.
+ *
+ * Authors: Tony Li <tony.li@freescale.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <mpc83xx.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PCIE_MAX_BUSES 2
+
+#ifdef CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES
+
+static int mpc83xx_pcie_remap_cfg(struct pci_controller *hose, pci_dev_t dev)
+{
+ int bus = PCI_BUS(dev) - hose->first_busno;
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ pex83xx_t *pex = &immr->pciexp[bus];
+ struct pex_outbound_window *out_win = &pex->bridge.pex_outbound_win[0];
+ u8 devfn = PCI_DEV(dev) << 3 | PCI_FUNC(dev);
+ u32 dev_base = bus << 24 | devfn << 16;
+
+ if (hose->indirect_type == INDIRECT_TYPE_NO_PCIE_LINK)
+ return -1;
+ /*
+ * Workaround for the HW bug: for Type 0 configure transactions the
+ * PCI-E controller does not check the device number bits and just
+ * assumes that the device number bits are 0.
+ */
+ if (devfn & 0xf8)
+ return -1;
+
+ out_le32(&out_win->tarl, dev_base);
+ return 0;
+}
+
+#define cfg_read(val, addr, type, op) \
+ do { *val = op((type)(addr)); } while (0)
+#define cfg_write(val, addr, type, op) \
+ do { op((type *)(addr), (val)); } while (0)
+
+#define cfg_read_err(val) do { *val = -1; } while (0)
+#define cfg_write_err(val) do { } while (0)
+
+#define PCIE_OP(rw, size, type, op) \
+static int pcie_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, \
+ type val) \
+{ \
+ int ret; \
+ \
+ ret = mpc83xx_pcie_remap_cfg(hose, dev); \
+ if (ret) { \
+ cfg_##rw##_err(val); \
+ return ret; \
+ } \
+ cfg_##rw(val, (void *)hose->cfg_addr + offset, type, op); \
+ return 0; \
+}
+
+PCIE_OP(read, byte, u8 *, in_8)
+PCIE_OP(read, word, u16 *, in_le16)
+PCIE_OP(read, dword, u32 *, in_le32)
+PCIE_OP(write, byte, u8, out_8)
+PCIE_OP(write, word, u16, out_le16)
+PCIE_OP(write, dword, u32, out_le32)
+
+static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
+ u8 link)
+{
+ extern void disable_addr_trans(void); /* start.S */
+ static struct pci_controller pcie_hose[PCIE_MAX_BUSES];
+ struct pci_controller *hose = &pcie_hose[bus];
+ int i;
+
+ /*
+ * There are no spare BATs to remap all PCI-E windows for U-Boot, so
+ * disable translations. In general, this is not great solution, and
+ * that's why we don't register PCI-E hoses by default.
+ */
+ disable_addr_trans();
+
+ for (i = 0; i < 2; i++, reg++) {
+ if (reg->size == 0)
+ break;
+
+ hose->regions[i] = *reg;
+ hose->region_count++;
+ }
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = 0;
+ hose->regions[i].phys_start = 0;
+ hose->regions[i].size = gd->ram_size;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = CONFIG_SYS_IMMR;
+ hose->regions[i].phys_start = CONFIG_SYS_IMMR;
+ hose->regions[i].size = 0x100000;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+ hose->first_busno = pci_last_busno() + 1;
+ hose->last_busno = 0xff;
+
+ if (bus == 0)
+ hose->cfg_addr = (unsigned int *)CONFIG_SYS_PCIE1_CFG_BASE;
+ else
+ hose->cfg_addr = (unsigned int *)CONFIG_SYS_PCIE2_CFG_BASE;
+
+ pci_set_ops(hose,
+ pcie_read_config_byte,
+ pcie_read_config_word,
+ pcie_read_config_dword,
+ pcie_write_config_byte,
+ pcie_write_config_word,
+ pcie_write_config_dword);
+
+ if (!link)
+ hose->indirect_type = INDIRECT_TYPE_NO_PCIE_LINK;
+
+ pci_register_hose(hose);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ /*
+ * Hose scan.
+ */
+ hose->last_busno = pci_hose_scan(hose);
+}
+
+#else
+
+static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
+ u8 link) {}
+
+#endif /* CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES */
+
+static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
+{
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ pex83xx_t *pex = &immr->pciexp[bus];
+ struct pex_outbound_window *out_win;
+ struct pex_inbound_window *in_win;
+ void *hose_cfg_base;
+ unsigned int ram_sz;
+ unsigned int barl;
+ unsigned int tar;
+ u16 reg16;
+ int i;
+
+ /* Enable pex csb bridge inbound & outbound transactions */
+ out_le32(&pex->bridge.pex_csb_ctrl,
+ in_le32(&pex->bridge.pex_csb_ctrl) | PEX_CSB_CTRL_OBPIOE |
+ PEX_CSB_CTRL_IBPIOE);
+
+ /* Enable bridge outbound */
+ out_le32(&pex->bridge.pex_csb_obctrl, PEX_CSB_OBCTRL_PIOE |
+ PEX_CSB_OBCTRL_MEMWE | PEX_CSB_OBCTRL_IOWE |
+ PEX_CSB_OBCTRL_CFGWE);
+
+ out_win = &pex->bridge.pex_outbound_win[0];
+ if (bus) {
+ out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+ CONFIG_SYS_PCIE2_CFG_SIZE);
+ out_le32(&out_win->bar, CONFIG_SYS_PCIE2_CFG_BASE);
+ } else {
+ out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+ CONFIG_SYS_PCIE1_CFG_SIZE);
+ out_le32(&out_win->bar, CONFIG_SYS_PCIE1_CFG_BASE);
+ }
+ out_le32(&out_win->tarl, 0);
+ out_le32(&out_win->tarh, 0);
+
+ for (i = 0; i < 2; i++, reg++) {
+ u32 ar;
+
+ if (reg->size == 0)
+ break;
+
+ out_win = &pex->bridge.pex_outbound_win[i + 1];
+ out_le32(&out_win->bar, reg->phys_start);
+ out_le32(&out_win->tarl, reg->bus_start);
+ out_le32(&out_win->tarh, 0);
+ ar = PEX_OWAR_EN | (reg->size & PEX_OWAR_SIZE);
+ if (reg->flags & PCI_REGION_IO)
+ ar |= PEX_OWAR_TYPE_IO;
+ else
+ ar |= PEX_OWAR_TYPE_MEM;
+ out_le32(&out_win->ar, ar);
+ }
+
+ out_le32(&pex->bridge.pex_csb_ibctrl, PEX_CSB_IBCTRL_PIOE);
+
+ ram_sz = gd->ram_size;
+ barl = 0;
+ tar = 0;
+ i = 0;
+ while (ram_sz > 0) {
+ in_win = &pex->bridge.pex_inbound_win[i];
+ out_le32(&in_win->barl, barl);
+ out_le32(&in_win->barh, 0x0);
+ out_le32(&in_win->tar, tar);
+ if (ram_sz >= 0x10000000) {
+ /* The maxium windows size is 256M */
+ out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+ PEX_IWAR_TYPE_PF | 0x0FFFF000);
+ barl += 0x10000000;
+ tar += 0x10000000;
+ ram_sz -= 0x10000000;
+ } else {
+ /* The UM is not clear here.
+ * So, round up to even Mb boundary */
+
+ ram_sz = ram_sz >> (20 +
+ ((ram_sz & 0xFFFFF) ? 1 : 0));
+ if (!(ram_sz % 2))
+ ram_sz -= 1;
+ out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+ PEX_IWAR_TYPE_PF | (ram_sz << 20) | 0xFF000);
+ ram_sz = 0;
+ }
+ i++;
+ }
+
+ in_win = &pex->bridge.pex_inbound_win[i];
+ out_le32(&in_win->barl, CONFIG_SYS_IMMR);
+ out_le32(&in_win->barh, 0);
+ out_le32(&in_win->tar, CONFIG_SYS_IMMR);
+ out_le32(&in_win->ar, PEX_IWAR_EN |
+ PEX_IWAR_TYPE_NO_PF | PEX_IWAR_SIZE_1M);
+
+ /* Enable the host virtual INTX interrupts */
+ out_le32(&pex->bridge.pex_int_axi_misc_enb,
+ in_le32(&pex->bridge.pex_int_axi_misc_enb) | 0x1E0);
+
+ /* Hose configure header is memory-mapped */
+ hose_cfg_base = (void *)pex;
+
+ get_clocks();
+ /* Configure the PCIE controller core clock ratio */
+ out_le32(hose_cfg_base + PEX_GCLK_RATIO,
+ (((bus ? gd->pciexp2_clk : gd->pciexp1_clk) / 1000000) * 16)
+ / 333);
+ udelay(1000000);
+
+ /* Do Type 1 bridge configuration */
+ out_8(hose_cfg_base + PCI_PRIMARY_BUS, 0);
+ out_8(hose_cfg_base + PCI_SECONDARY_BUS, 1);
+ out_8(hose_cfg_base + PCI_SUBORDINATE_BUS, 255);
+
+ /*
+ * Write to Command register
+ */
+ reg16 = in_le16(hose_cfg_base + PCI_COMMAND);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO |
+ PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
+ out_le16(hose_cfg_base + PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ out_le16(hose_cfg_base + PCI_STATUS, 0xffff);
+ out_8(hose_cfg_base + PCI_LATENCY_TIMER, 0x80);
+ out_8(hose_cfg_base + PCI_CACHE_LINE_SIZE, 0x08);
+
+ printf("PCIE%d: ", bus);
+
+ reg16 = in_le16(hose_cfg_base + PCI_LTSSM);
+ if (reg16 >= PCI_LTSSM_L0)
+ printf("link\n");
+ else
+ printf("No link\n");
+
+ mpc83xx_pcie_register_hose(bus, reg, reg16 >= PCI_LTSSM_L0);
+}
+
+/*
+ * The caller must have already set SCCR, SERDES and the PCIE_LAW BARs
+ * must have been set to cover all of the requested regions.
+ */
+void mpc83xx_pcie_init(int num_buses, struct pci_region **reg, int warmboot)
+{
+ int i;
+
+ /*
+ * Release PCI RST Output signal.
+ * Power on to RST high must be at least 100 ms as per PCI spec.
+ * On warm boots only 1 ms is required.
+ */
+ udelay(warmboot ? 1000 : 100000);
+
+ for (i = 0; i < num_buses; i++)
+ mpc83xx_pcie_init_bus(i, reg[i]);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/qe_io.c b/arch/powerpc/cpu/mpc83xx/qe_io.c
new file mode 100644
index 0000000..db94f00
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/qe_io.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ *
+ * 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/immap_83xx.h"
+
+#define NUM_OF_PINS 32
+void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
+{
+ u32 pin_2bit_mask;
+ u32 pin_2bit_dir;
+ u32 pin_2bit_assign;
+ u32 pin_1bit_mask;
+ u32 tmp_val;
+ volatile immap_t *im = (volatile immap_t *)CONFIG_SYS_IMMR;
+ volatile qepio83xx_t *par_io = (volatile qepio83xx_t *)&im->qepio;
+
+ /* Caculate pin location and 2bit mask and dir */
+ pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+ pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+
+ /* Setup the direction */
+ tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \
+ in_be32(&par_io->ioport[port].dir2) :
+ in_be32(&par_io->ioport[port].dir1);
+
+ if (pin > (NUM_OF_PINS/2) -1) {
+ out_be32(&par_io->ioport[port].dir2, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].dir2, pin_2bit_dir | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].dir1, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].dir1, pin_2bit_dir | tmp_val);
+ }
+
+ /* Calculate pin location for 1bit mask */
+ pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1)));
+
+ /* Setup the open drain */
+ tmp_val = in_be32(&par_io->ioport[port].podr);
+ if (open_drain) {
+ out_be32(&par_io->ioport[port].podr, pin_1bit_mask | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].podr, ~pin_1bit_mask & tmp_val);
+ }
+
+ /* Setup the assignment */
+ tmp_val = (pin > (NUM_OF_PINS/2) - 1) ?
+ in_be32(&par_io->ioport[port].ppar2):
+ in_be32(&par_io->ioport[port].ppar1);
+ pin_2bit_assign = (u32)(assign
+ << (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2));
+
+ /* Clear and set 2 bits mask */
+ if (pin > (NUM_OF_PINS/2) - 1) {
+ out_be32(&par_io->ioport[port].ppar2, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].ppar2, pin_2bit_assign | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].ppar1, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].ppar1, pin_2bit_assign | tmp_val);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc83xx/serdes.c b/arch/powerpc/cpu/mpc83xx/serdes.c
new file mode 100644
index 0000000..64033fe
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/serdes.c
@@ -0,0 +1,145 @@
+/*
+ * Freescale SerDes initialization routine
+ *
+ * Copyright (C) 2007 Freescale Semicondutor, Inc.
+ * Copyright (C) 2008 MontaVista Software, Inc.
+ *
+ * Author: Li Yang <leoli@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.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_serdes.h>
+
+/* SerDes registers */
+#define FSL_SRDSCR0_OFFS 0x0
+#define FSL_SRDSCR0_DPP_1V2 0x00008800
+#define FSL_SRDSCR1_OFFS 0x4
+#define FSL_SRDSCR1_PLLBW 0x00000040
+#define FSL_SRDSCR2_OFFS 0x8
+#define FSL_SRDSCR2_VDD_1V2 0x00800000
+#define FSL_SRDSCR2_SEIC_MASK 0x00001c1c
+#define FSL_SRDSCR2_SEIC_SATA 0x00001414
+#define FSL_SRDSCR2_SEIC_PEX 0x00001010
+#define FSL_SRDSCR2_SEIC_SGMII 0x00000101
+#define FSL_SRDSCR3_OFFS 0xc
+#define FSL_SRDSCR3_KFR_SATA 0x10100000
+#define FSL_SRDSCR3_KPH_SATA 0x04040000
+#define FSL_SRDSCR3_SDFM_SATA_PEX 0x01010000
+#define FSL_SRDSCR3_SDTXL_SATA 0x00000505
+#define FSL_SRDSCR4_OFFS 0x10
+#define FSL_SRDSCR4_PROT_SATA 0x00000808
+#define FSL_SRDSCR4_PROT_PEX 0x00000101
+#define FSL_SRDSCR4_PROT_SGMII 0x00000505
+#define FSL_SRDSCR4_PLANE_X2 0x01000000
+#define FSL_SRDSRSTCTL_OFFS 0x20
+#define FSL_SRDSRSTCTL_RST 0x80000000
+#define FSL_SRDSRSTCTL_SATA_RESET 0xf
+
+void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd)
+{
+ void *regs = (void *)CONFIG_SYS_IMMR + offset;
+ u32 tmp;
+
+ /* 1.0V corevdd */
+ if (vdd) {
+ /* DPPE/DPPA = 0 */
+ tmp = in_be32(regs + FSL_SRDSCR0_OFFS);
+ tmp &= ~FSL_SRDSCR0_DPP_1V2;
+ out_be32(regs + FSL_SRDSCR0_OFFS, tmp);
+
+ /* VDD = 0 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_VDD_1V2;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+ }
+
+ /* protocol specific configuration */
+ switch (proto) {
+ case FSL_SERDES_PROTO_SATA:
+ /* Set and clear reset bits */
+ tmp = in_be32(regs + FSL_SRDSRSTCTL_OFFS);
+ tmp |= FSL_SRDSRSTCTL_SATA_RESET;
+ out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+ udelay(1000);
+ tmp &= ~FSL_SRDSRSTCTL_SATA_RESET;
+ out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+
+ /* Configure SRDSCR1 */
+ tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_PLLBW;
+ out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+ /* Configure SRDSCR2 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+ tmp |= FSL_SRDSCR2_SEIC_SATA;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+ /* Configure SRDSCR3 */
+ tmp = FSL_SRDSCR3_KFR_SATA | FSL_SRDSCR3_KPH_SATA |
+ FSL_SRDSCR3_SDFM_SATA_PEX |
+ FSL_SRDSCR3_SDTXL_SATA;
+ out_be32(regs + FSL_SRDSCR3_OFFS, tmp);
+
+ /* Configure SRDSCR4 */
+ tmp = rfcks | FSL_SRDSCR4_PROT_SATA;
+ out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+ break;
+ case FSL_SERDES_PROTO_PEX:
+ case FSL_SERDES_PROTO_PEX_X2:
+ /* Configure SRDSCR1 */
+ tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+ tmp |= FSL_SRDSCR1_PLLBW;
+ out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+ /* Configure SRDSCR2 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+ tmp |= FSL_SRDSCR2_SEIC_PEX;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+ /* Configure SRDSCR3 */
+ tmp = FSL_SRDSCR3_SDFM_SATA_PEX;
+ out_be32(regs + FSL_SRDSCR3_OFFS, tmp);
+
+ /* Configure SRDSCR4 */
+ tmp = rfcks | FSL_SRDSCR4_PROT_PEX;
+ if (proto == FSL_SERDES_PROTO_PEX_X2)
+ tmp |= FSL_SRDSCR4_PLANE_X2;
+ out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+ break;
+ case FSL_SERDES_PROTO_SGMII:
+ /* Configure SRDSCR1 */
+ tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_PLLBW;
+ out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+ /* Configure SRDSCR2 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+ tmp |= FSL_SRDSCR2_SEIC_SGMII;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+ /* Configure SRDSCR3 */
+ out_be32(regs + FSL_SRDSCR3_OFFS, 0);
+
+ /* Configure SRDSCR4 */
+ tmp = rfcks | FSL_SRDSCR4_PROT_SGMII;
+ out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+ break;
+ default:
+ return;
+ }
+
+ /* Do a software reset */
+ tmp = in_be32(regs + FSL_SRDSRSTCTL_OFFS);
+ tmp |= FSL_SRDSRSTCTL_RST;
+ out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
new file mode 100644
index 0000000..44aaa9a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
@@ -0,0 +1,918 @@
+/*
+ * (C) Copyright 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ * (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 <asm/io.h>
+#include <i2c.h>
+#include <spd.h>
+#include <asm/mmu.h>
+#include <spd_sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_add_ram_info(int use_default)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ char buf[32];
+
+ printf(" (DDR%d", ((ddr->sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK)
+ >> SDRAM_CFG_SDRAM_TYPE_SHIFT) - 1);
+
+ if (ddr->sdram_cfg & SDRAM_CFG_32_BE)
+ puts(", 32-bit");
+ else
+ puts(", 64-bit");
+
+ if (ddr->sdram_cfg & SDRAM_CFG_ECC_EN)
+ puts(", ECC on");
+ else
+ puts(", ECC off");
+
+ printf(", %s MHz)", strmhz(buf, gd->mem_clk));
+
+#if defined(CONFIG_SYS_LB_SDRAM) && defined(CONFIG_SYS_LBC_SDRAM_SIZE)
+ puts("\nSDRAM: ");
+ print_size (CONFIG_SYS_LBC_SDRAM_SIZE * 1024 * 1024, " (local bus)");
+#endif
+}
+
+#ifdef CONFIG_SPD_EEPROM
+#ifndef CONFIG_SYS_READ_SPD
+#define CONFIG_SYS_READ_SPD i2c_read
+#endif
+
+/*
+ * Convert picoseconds into clock cycles (rounding up if needed).
+ */
+int
+picos_to_clk(int picos)
+{
+ unsigned int mem_bus_clk;
+ int clks;
+
+ mem_bus_clk = gd->mem_clk >> 1;
+ clks = picos / (1000000000 / (mem_bus_clk / 1000));
+ if (picos % (1000000000 / (mem_bus_clk / 1000)) != 0)
+ clks++;
+
+ return clks;
+}
+
+unsigned int banksize(unsigned char row_dens)
+{
+ return ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24;
+}
+
+int read_spd(uint addr)
+{
+ return ((int) addr);
+}
+
+#undef SPD_DEBUG
+#ifdef SPD_DEBUG
+static void spd_debug(spd_eeprom_t *spd)
+{
+ printf ("\nDIMM type: %-18.18s\n", spd->mpart);
+ printf ("SPD size: %d\n", spd->info_size);
+ printf ("EEPROM size: %d\n", 1 << spd->chip_size);
+ printf ("Memory type: %d\n", spd->mem_type);
+ printf ("Row addr: %d\n", spd->nrow_addr);
+ printf ("Column addr: %d\n", spd->ncol_addr);
+ printf ("# of rows: %d\n", spd->nrows);
+ printf ("Row density: %d\n", spd->row_dens);
+ printf ("# of banks: %d\n", spd->nbanks);
+ printf ("Data width: %d\n",
+ 256 * spd->dataw_msb + spd->dataw_lsb);
+ printf ("Chip width: %d\n", spd->primw);
+ printf ("Refresh rate: %02X\n", spd->refresh);
+ printf ("CAS latencies: %02X\n", spd->cas_lat);
+ printf ("Write latencies: %02X\n", spd->write_lat);
+ printf ("tRP: %d\n", spd->trp);
+ printf ("tRCD: %d\n", spd->trcd);
+ printf ("\n");
+}
+#endif /* SPD_DEBUG */
+
+long int spd_sdram()
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ volatile law83xx_t *ecm = &immap->sysconf.ddrlaw[0];
+ spd_eeprom_t spd;
+ unsigned int n_ranks;
+ unsigned int odt_rd_cfg, odt_wr_cfg;
+ unsigned char twr_clk, twtr_clk;
+ unsigned int sdram_type;
+ unsigned int memsize;
+ unsigned int law_size;
+ unsigned char caslat, caslat_ctrl;
+ unsigned int trfc, trfc_clk, trfc_low, trfc_high;
+ unsigned int trcd_clk, trtp_clk;
+ unsigned char cke_min_clk;
+ unsigned char add_lat, wr_lat;
+ unsigned char wr_data_delay;
+ unsigned char four_act;
+ unsigned char cpo;
+ unsigned char burstlen;
+ unsigned char odt_cfg, mode_odt_enable;
+ unsigned int max_bus_clk;
+ unsigned int max_data_rate, effective_data_rate;
+ unsigned int ddrc_clk;
+ unsigned int refresh_clk;
+ unsigned int sdram_cfg;
+ unsigned int ddrc_ecc_enable;
+ unsigned int pvr = get_pvr();
+
+ /*
+ * First disable the memory controller (could be enabled
+ * by the debugger)
+ */
+ clrsetbits_be32(&ddr->sdram_cfg, SDRAM_CFG_MEM_EN, 0);
+ sync();
+ isync();
+
+ /* Read SPD parameters with I2C */
+ CONFIG_SYS_READ_SPD(SPD_EEPROM_ADDRESS, 0, 1, (uchar *) & spd, sizeof (spd));
+#ifdef SPD_DEBUG
+ spd_debug(&spd);
+#endif
+ /* Check the memory type */
+ if (spd.mem_type != SPD_MEMTYPE_DDR && spd.mem_type != SPD_MEMTYPE_DDR2) {
+ debug("DDR: Module mem type is %02X\n", spd.mem_type);
+ return 0;
+ }
+
+ /* Check the number of physical bank */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ n_ranks = spd.nrows;
+ } else {
+ n_ranks = (spd.nrows & 0x7) + 1;
+ }
+
+ if (n_ranks > 2) {
+ printf("DDR: The number of physical bank is %02X\n", n_ranks);
+ return 0;
+ }
+
+ /* Check if the number of row of the module is in the range of DDRC */
+ if (spd.nrow_addr < 12 || spd.nrow_addr > 15) {
+ printf("DDR: Row number is out of range of DDRC, row=%02X\n",
+ spd.nrow_addr);
+ return 0;
+ }
+
+ /* Check if the number of col of the module is in the range of DDRC */
+ if (spd.ncol_addr < 8 || spd.ncol_addr > 11) {
+ printf("DDR: Col number is out of range of DDRC, col=%02X\n",
+ spd.ncol_addr);
+ return 0;
+ }
+
+#ifdef CONFIG_SYS_DDRCDR_VALUE
+ /*
+ * Adjust DDR II IO voltage biasing. It just makes it work.
+ */
+ if(spd.mem_type == SPD_MEMTYPE_DDR2) {
+ immap->sysconf.ddrcdr = CONFIG_SYS_DDRCDR_VALUE;
+ }
+ udelay(50000);
+#endif
+
+ /*
+ * 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 CSn */
+ }
+
+ /* Setup DDR chip select register */
+#ifdef CONFIG_SYS_83XX_DDR_USES_CS0
+ ddr->csbnds[0].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+ ddr->cs_config[0] = ( 1 << 31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("\n");
+ debug("cs0_bnds = 0x%08x\n",ddr->csbnds[0].csbnds);
+ debug("cs0_config = 0x%08x\n",ddr->cs_config[0]);
+
+ if (n_ranks == 2) {
+ ddr->csbnds[1].csbnds = ( (banksize(spd.row_dens) >> 8)
+ | ((banksize(spd.row_dens) >> 23) - 1) );
+ ddr->cs_config[1] = ( 1<<31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("cs1_bnds = 0x%08x\n",ddr->csbnds[1].csbnds);
+ debug("cs1_config = 0x%08x\n",ddr->cs_config[1]);
+ }
+
+#else
+ ddr->csbnds[2].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+ ddr->cs_config[2] = ( 1 << 31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("\n");
+ debug("cs2_bnds = 0x%08x\n",ddr->csbnds[2].csbnds);
+ debug("cs2_config = 0x%08x\n",ddr->cs_config[2]);
+
+ if (n_ranks == 2) {
+ ddr->csbnds[3].csbnds = ( (banksize(spd.row_dens) >> 8)
+ | ((banksize(spd.row_dens) >> 23) - 1) );
+ ddr->cs_config[3] = ( 1<<31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("cs3_bnds = 0x%08x\n",ddr->csbnds[3].csbnds);
+ debug("cs3_config = 0x%08x\n",ddr->cs_config[3]);
+ }
+#endif
+
+ /*
+ * Figure out memory size in Megabytes.
+ */
+ memsize = n_ranks * banksize(spd.row_dens) / 0x100000;
+
+ /*
+ * First supported LAW size is 16M, at LAWAR_SIZE_16M == 23.
+ */
+ law_size = 19 + __ilog2(memsize);
+
+ /*
+ * Set up LAWBAR for all of DDR.
+ */
+ ecm->bar = CONFIG_SYS_DDR_SDRAM_BASE & 0xfffff000;
+ ecm->ar = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & law_size));
+ debug("DDR:bar=0x%08x\n", ecm->bar);
+ debug("DDR:ar=0x%08x\n", ecm->ar);
+
+ /*
+ * 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 6 4 0111
+ * 4.5 1000
+ * 5.0 5 1001
+ */
+ caslat = __ilog2(spd.cas_lat);
+ if ((spd.mem_type == SPD_MEMTYPE_DDR)
+ && (caslat > 6)) {
+ 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);
+
+ max_bus_clk = 1000 *10 / (((spd.clk_cycle & 0xF0) >> 4) * 10
+ + (spd.clk_cycle & 0x0f));
+ max_data_rate = max_bus_clk * 2;
+
+ debug("DDR:Module maximum data rate is: %d MHz\n", max_data_rate);
+
+ ddrc_clk = gd->mem_clk / 1000000;
+ effective_data_rate = 0;
+
+ if (max_data_rate >= 460) { /* it is DDR2-800, 667, 533 */
+ if (spd.cas_lat & 0x08)
+ caslat = 3;
+ else
+ caslat = 4;
+ if (ddrc_clk <= 460 && ddrc_clk > 350)
+ effective_data_rate = 400;
+ else if (ddrc_clk <=350 && ddrc_clk > 280)
+ effective_data_rate = 333;
+ else if (ddrc_clk <= 280 && ddrc_clk > 230)
+ effective_data_rate = 266;
+ else
+ effective_data_rate = 200;
+ } else if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
+ if (ddrc_clk <= 460 && ddrc_clk > 350) {
+ /* DDR controller clk at 350~460 */
+ effective_data_rate = 400; /* 5ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDR controller clk at 280~350 */
+ effective_data_rate = 333; /* 6ns */
+ if (spd.clk_cycle2 == 0x60)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ if (spd.clk_cycle3 == 0x75)
+ caslat = caslat - 2;
+ else if (spd.clk_cycle2 == 0x75)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ if (spd.clk_cycle3 == 0xa0)
+ caslat = caslat - 2;
+ else if (spd.clk_cycle2 == 0xa0)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ }
+ } else if (max_data_rate >= 323) { /* it is DDR 333 */
+ if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDR controller clk at 280~350 */
+ effective_data_rate = 333; /* 6ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ if (spd.clk_cycle2 == 0x75)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ if (spd.clk_cycle3 == 0xa0)
+ caslat = caslat - 2;
+ else if (spd.clk_cycle2 == 0xa0)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ }
+ } else if (max_data_rate >= 256) { /* it is DDR 266 */
+ if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDR controller clk at 280~350 */
+ printf("DDR: DDR controller freq is more than "
+ "max data rate of the module\n");
+ return 0;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ if (spd.clk_cycle2 == 0xa0)
+ caslat = caslat - 1;
+ }
+ } else if (max_data_rate >= 190) { /* it is DDR 200 */
+ if (ddrc_clk <= 350 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~350 */
+ printf("DDR: DDR controller freq is more than "
+ "max data rate of the module\n");
+ return 0;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ caslat = caslat;
+ }
+ }
+
+ debug("DDR:Effective data rate is: %dMHz\n", effective_data_rate);
+ debug("DDR:The MSB 1 of CAS Latency is: %d\n", caslat);
+
+ /*
+ * Errata DDR6 work around: input enable 2 cycles earlier.
+ * including MPC834x Rev1.0/1.1 and MPC8360 Rev1.1/1.2.
+ */
+ if(PVR_MAJ(pvr) <= 1 && spd.mem_type == SPD_MEMTYPE_DDR){
+ if (caslat == 2)
+ ddr->debug_reg = 0x201c0000; /* CL=2 */
+ else if (caslat == 3)
+ ddr->debug_reg = 0x202c0000; /* CL=2.5 */
+ else if (caslat == 4)
+ ddr->debug_reg = 0x202c0000; /* CL=3.0 */
+
+ __asm__ __volatile__ ("sync");
+
+ debug("Errata DDR6 (debug_reg=0x%08x)\n", ddr->debug_reg);
+ }
+
+ /*
+ * 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: effective data rate is %d MHz\n", effective_data_rate);
+ debug("DDR: caslat SPD bit is %d, controller field is 0x%x\n",
+ caslat, caslat_ctrl);
+
+ /*
+ * Timing Config 0.
+ * Avoid writing for DDR I.
+ */
+ 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);
+ }
+
+ /*
+ * 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);
+ if (twtr_clk < 2)
+ twtr_clk = 2;
+ }
+
+ /*
+ * 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
+ * 83xx 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;
+
+ ddr->timing_cfg_1 =
+ (((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 */
+ );
+
+ /*
+ * 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 + caslat) < 4) {
+ add_lat = 0;
+ }
+ }
+
+ /*
+ * Write Data Delay
+ * Historically 0x2 == 4/8 clock delay.
+ * Empirically, 0x3 == 6/8 clock delay is suggested for DDR I 266.
+ */
+ wr_data_delay = 2;
+
+ /*
+ * 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);
+ if (trtp_clk < 2)
+ trtp_clk = 2;
+ trtp_clk += add_lat;
+
+ cke_min_clk = 3; /* By the book. */
+ four_act = picos_to_clk(37500); /* By the book. 1k pages? */
+ }
+
+ /*
+ * Empirically set ~MCAS-to-preamble override for DDR 2.
+ * Your milage will vary.
+ */
+ cpo = 0;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ if (effective_data_rate == 266) {
+ cpo = 0x4; /* READ_LAT + 1/2 */
+ } else if (effective_data_rate == 333) {
+ cpo = 0x6; /* READ_LAT + 1 */
+ } else if (effective_data_rate == 400) {
+ cpo = 0x7; /* READ_LAT + 5/4 */
+ } else {
+ /* Automatic calibration */
+ cpo = 0x1f;
+ }
+ }
+
+ 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_1=0x%08x\n", ddr->timing_cfg_1);
+ debug("DDR:timing_cfg_2=0x%08x\n", ddr->timing_cfg_2);
+
+ /* Check DIMM data bus width */
+ if (spd.dataw_lsb < 64) {
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
+ else
+ burstlen = 0x02; /* 32 bit data bus, burst len is 4 */
+ debug("\n DDR DIMM: data bus width is 32 bit");
+ } else {
+ burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */
+ debug("\n DDR DIMM: data bus width is 64 bit");
+ }
+
+ /* Is this an ECC DDR chip? */
+ if (spd.config == 0x02)
+ debug(" with ECC\n");
+ else
+ debug(" without ECC\n");
+
+ /* Burst length is always 4 for 64 bit data bus, 8 for 32 bit data bus,
+ Burst type is sequential
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ switch (caslat) {
+ case 1:
+ ddr->sdram_mode = 0x50 | burstlen; /* CL=1.5 */
+ break;
+ case 2:
+ ddr->sdram_mode = 0x20 | burstlen; /* CL=2.0 */
+ break;
+ case 3:
+ ddr->sdram_mode = 0x60 | burstlen; /* CL=2.5 */
+ break;
+ case 4:
+ ddr->sdram_mode = 0x30 | burstlen; /* CL=3.0 */
+ break;
+ default:
+ printf("DDR:only CL 1.5, 2.0, 2.5, 3.0 is supported\n");
+ return 0;
+ }
+ } else {
+ 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 =
+ (0
+ | (1 << (16 + 10)) /* DQS Differential disable */
+ | (add_lat << (16 + 3)) /* Additive Latency in EMRS1 */
+ | (mode_odt_enable << 16) /* ODT Enable in EMRS1 */
+ | ((twr_clk - 1) << 9) /* Write Recovery Autopre */
+ | (caslat << 4) /* caslat */
+ | (burstlen << 0) /* Burst length */
+ );
+ }
+ debug("DDR:sdram_mode=0x%08x\n", ddr->sdram_mode);
+
+ /*
+ * Clear EMRS2 and EMRS3.
+ */
+ ddr->sdram_mode2 = 0;
+ debug("DDR: sdram_mode2 = 0x%08x\n", ddr->sdram_mode2);
+
+ switch (spd.refresh) {
+ case 0x00:
+ case 0x80:
+ refresh_clk = picos_to_clk(15625000);
+ break;
+ case 0x01:
+ case 0x81:
+ refresh_clk = picos_to_clk(3900000);
+ break;
+ case 0x02:
+ case 0x82:
+ refresh_clk = picos_to_clk(7800000);
+ break;
+ case 0x03:
+ case 0x83:
+ refresh_clk = picos_to_clk(31300000);
+ break;
+ case 0x04:
+ case 0x84:
+ refresh_clk = picos_to_clk(62500000);
+ break;
+ case 0x05:
+ case 0x85:
+ refresh_clk = picos_to_clk(125000000);
+ break;
+ default:
+ refresh_clk = 0x512;
+ break;
+ }
+
+ /*
+ * Set BSTOPRE to 0x100 for page mode
+ * If auto-charge is used, set BSTOPRE = 0
+ */
+ ddr->sdram_interval = ((refresh_clk & 0x3fff) << 16) | 0x100;
+ debug("DDR:sdram_interval=0x%08x\n", ddr->sdram_interval);
+
+ /*
+ * SDRAM Cfg 2
+ */
+ odt_cfg = 0;
+#ifndef CONFIG_NEVER_ASSERT_ODT_TO_CPU
+ if (odt_rd_cfg | odt_wr_cfg) {
+ odt_cfg = 0x2; /* ODT to IOs during reads */
+ }
+#endif
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ ddr->sdram_cfg2 = (0
+ | (0 << 26) /* True DQS */
+ | (odt_cfg << 21) /* ODT only read */
+ | (1 << 12) /* 1 refresh at a time */
+ );
+
+ debug("DDR: sdram_cfg2 = 0x%08x\n", ddr->sdram_cfg2);
+ }
+
+#ifdef CONFIG_SYS_DDR_SDRAM_CLK_CNTL /* Optional platform specific value */
+ ddr->sdram_clk_cntl = CONFIG_SYS_DDR_SDRAM_CLK_CNTL;
+#endif
+ debug("DDR:sdram_clk_cntl=0x%08x\n", ddr->sdram_clk_cntl);
+
+ asm("sync;isync");
+
+ udelay(600);
+
+ /*
+ * Figure out the settings for the sdram_cfg register. Build up
+ * the value in 'sdram_cfg' before writing since the write into
+ * the register will actually enable the memory controller, and 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_cfg[12] = 0 (32_BE =0 , 64 bit bus mode)
+ * sdram_cfg[13] = 0 (8_BE =0, 4-beat bursts)
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ sdram_type = SDRAM_CFG_SDRAM_TYPE_DDR1;
+ else
+ sdram_type = SDRAM_CFG_SDRAM_TYPE_DDR2;
+
+ sdram_cfg = (0
+ | SDRAM_CFG_MEM_EN /* DDR enable */
+ | SDRAM_CFG_SREN /* Self refresh */
+ | sdram_type /* SDRAM type */
+ );
+
+ /* sdram_cfg[3] = RD_EN - registered DIMM enable */
+ if (spd.mod_attr & 0x02)
+ sdram_cfg |= SDRAM_CFG_RD_EN;
+
+ /* The DIMM is 32bit width */
+ if (spd.dataw_lsb < 64) {
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ sdram_cfg |= SDRAM_CFG_32_BE | SDRAM_CFG_8_BE;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2)
+ sdram_cfg |= SDRAM_CFG_32_BE;
+ }
+
+ ddrc_ecc_enable = 0;
+
+#if defined(CONFIG_DDR_ECC)
+ /* Enable ECC with sdram_cfg[2] */
+ if (spd.config == 0x02) {
+ sdram_cfg |= 0x20000000;
+ ddrc_ecc_enable = 1;
+ /* disable error detection */
+ ddr->err_disable = ~ECC_ERROR_ENABLE;
+ /* set single bit error threshold to maximum value,
+ * reset counter to zero */
+ ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) |
+ (0 << ECC_ERROR_MAN_SBEC_SHIFT);
+ }
+
+ debug("DDR:err_disable=0x%08x\n", ddr->err_disable);
+ debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe);
+#endif
+ debug(" DDRC ECC mode: %s\n", ddrc_ecc_enable ? "ON":"OFF");
+
+#if defined(CONFIG_DDR_2T_TIMING)
+ /*
+ * Enable 2T timing by setting sdram_cfg[16].
+ */
+ sdram_cfg |= SDRAM_CFG_2T_EN;
+#endif
+ /* Enable controller, and GO! */
+ ddr->sdram_cfg = sdram_cfg;
+ asm("sync;isync");
+ udelay(500);
+
+ debug("DDR:sdram_cfg=0x%08x\n", ddr->sdram_cfg);
+ return memsize; /*in MBytes*/
+}
+#endif /* CONFIG_SPD_EEPROM */
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+/*
+ * Use timebase counter, get_timer() is not availabe
+ * at this point of initialization yet.
+ */
+static __inline__ unsigned long get_tbms (void)
+{
+ unsigned long tbl;
+ unsigned long tbu1, tbu2;
+ unsigned long ms;
+ unsigned long long tmp;
+
+ ulong tbclk = get_tbclk();
+
+ /* get the timebase ticks */
+ do {
+ asm volatile ("mftbu %0":"=r" (tbu1):);
+ asm volatile ("mftb %0":"=r" (tbl):);
+ asm volatile ("mftbu %0":"=r" (tbu2):);
+ } while (tbu1 != tbu2);
+
+ /* convert ticks to ms */
+ tmp = (unsigned long long)(tbu1);
+ tmp = (tmp << 32);
+ tmp += (unsigned long long)(tbl);
+ ms = tmp/(tbclk/1000);
+
+ return ms;
+}
+
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+void ddr_enable_ecc(unsigned int dram_size)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr= &immap->ddr;
+ unsigned long t_start, t_end;
+ register u64 *p;
+ register uint size;
+ unsigned int pattern[2];
+
+ icache_enable();
+ t_start = get_tbms();
+ pattern[0] = 0xdeadbeef;
+ pattern[1] = 0xdeadbeef;
+
+#if defined(CONFIG_DDR_ECC_INIT_VIA_DMA)
+ dma_meminit(pattern[0], dram_size);
+#else
+ debug("ddr init: CPU FP write method\n");
+ size = dram_size;
+ for (p = 0; p < (u64*)(size); p++) {
+ ppcDWstore((u32*)p, pattern);
+ }
+ __asm__ __volatile__ ("sync");
+#endif
+
+ t_end = get_tbms();
+ icache_disable();
+
+ debug("\nREADY!!\n");
+ debug("ddr init duration: %ld ms\n", t_end - t_start);
+
+ /* Clear All ECC Errors */
+ if ((ddr->err_detect & ECC_ERROR_DETECT_MME) == ECC_ERROR_DETECT_MME)
+ ddr->err_detect |= ECC_ERROR_DETECT_MME;
+ if ((ddr->err_detect & ECC_ERROR_DETECT_MBE) == ECC_ERROR_DETECT_MBE)
+ ddr->err_detect |= ECC_ERROR_DETECT_MBE;
+ if ((ddr->err_detect & ECC_ERROR_DETECT_SBE) == ECC_ERROR_DETECT_SBE)
+ ddr->err_detect |= ECC_ERROR_DETECT_SBE;
+ if ((ddr->err_detect & ECC_ERROR_DETECT_MSE) == ECC_ERROR_DETECT_MSE)
+ ddr->err_detect |= ECC_ERROR_DETECT_MSE;
+
+ /* Disable ECC-Interrupts */
+ ddr->err_int_en &= ECC_ERR_INT_DISABLE;
+
+ /* Enable errors for ECC */
+ ddr->err_disable &= ECC_ERROR_ENABLE;
+
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("isync");
+}
+#endif /* CONFIG_DDR_ECC */
diff --git a/arch/powerpc/cpu/mpc83xx/speed.c b/arch/powerpc/cpu/mpc83xx/speed.c
new file mode 100644
index 0000000..bde7e92
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/speed.c
@@ -0,0 +1,549 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ *
+ * 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 <mpc83xx.h>
+#include <command.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ----------------------------------------------------------------- */
+
+typedef enum {
+ _unk,
+ _off,
+ _byp,
+ _x8,
+ _x4,
+ _x2,
+ _x1,
+ _1x,
+ _1_5x,
+ _2x,
+ _2_5x,
+ _3x
+} mult_t;
+
+typedef struct {
+ mult_t core_csb_ratio;
+ mult_t vco_divider;
+} corecnf_t;
+
+corecnf_t corecnf_tab[] = {
+ {_byp, _byp}, /* 0x00 */
+ {_byp, _byp}, /* 0x01 */
+ {_byp, _byp}, /* 0x02 */
+ {_byp, _byp}, /* 0x03 */
+ {_byp, _byp}, /* 0x04 */
+ {_byp, _byp}, /* 0x05 */
+ {_byp, _byp}, /* 0x06 */
+ {_byp, _byp}, /* 0x07 */
+ {_1x, _x2}, /* 0x08 */
+ {_1x, _x4}, /* 0x09 */
+ {_1x, _x8}, /* 0x0A */
+ {_1x, _x8}, /* 0x0B */
+ {_1_5x, _x2}, /* 0x0C */
+ {_1_5x, _x4}, /* 0x0D */
+ {_1_5x, _x8}, /* 0x0E */
+ {_1_5x, _x8}, /* 0x0F */
+ {_2x, _x2}, /* 0x10 */
+ {_2x, _x4}, /* 0x11 */
+ {_2x, _x8}, /* 0x12 */
+ {_2x, _x8}, /* 0x13 */
+ {_2_5x, _x2}, /* 0x14 */
+ {_2_5x, _x4}, /* 0x15 */
+ {_2_5x, _x8}, /* 0x16 */
+ {_2_5x, _x8}, /* 0x17 */
+ {_3x, _x2}, /* 0x18 */
+ {_3x, _x4}, /* 0x19 */
+ {_3x, _x8}, /* 0x1A */
+ {_3x, _x8}, /* 0x1B */
+};
+
+/* ----------------------------------------------------------------- */
+
+/*
+ *
+ */
+int get_clocks(void)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ u32 pci_sync_in;
+ u8 spmf;
+ u8 clkin_div;
+ u32 sccr;
+ u32 corecnf_tab_index;
+ u8 corepll;
+ u32 lcrr;
+
+ u32 csb_clk;
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+ u32 tsec1_clk;
+ u32 tsec2_clk;
+ u32 usbdr_clk;
+#endif
+#ifdef CONFIG_MPC834x
+ u32 usbmph_clk;
+#endif
+ u32 core_clk;
+ u32 i2c1_clk;
+#if !defined(CONFIG_MPC832x)
+ u32 i2c2_clk;
+#endif
+#if defined(CONFIG_MPC8315)
+ u32 tdm_clk;
+#endif
+#if defined(CONFIG_MPC837x)
+ u32 sdhc_clk;
+#endif
+ u32 enc_clk;
+ u32 lbiu_clk;
+ u32 lclk_clk;
+ u32 mem_clk;
+#if defined(CONFIG_MPC8360)
+ u32 mem_sec_clk;
+#endif
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+ u32 qepmf;
+ u32 qepdf;
+ u32 qe_clk;
+ u32 brg_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC831x)
+ u32 pciexp1_clk;
+ u32 pciexp2_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ u32 sata_clk;
+#endif
+
+ if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32) im)
+ return -1;
+
+ clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT);
+
+ if (im->reset.rcwh & HRCWH_PCI_HOST) {
+#if defined(CONFIG_83XX_CLKIN)
+ pci_sync_in = CONFIG_83XX_CLKIN / (1 + clkin_div);
+#else
+ pci_sync_in = 0xDEADBEEF;
+#endif
+ } else {
+#if defined(CONFIG_83XX_PCICLK)
+ pci_sync_in = CONFIG_83XX_PCICLK;
+#else
+ pci_sync_in = 0xDEADBEEF;
+#endif
+ }
+
+ spmf = ((im->reset.rcwl & HRCWL_SPMF) >> HRCWL_SPMF_SHIFT);
+ csb_clk = pci_sync_in * (1 + clkin_div) * spmf;
+
+ sccr = im->clk.sccr;
+
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+ switch ((sccr & SCCR_TSEC1CM) >> SCCR_TSEC1CM_SHIFT) {
+ case 0:
+ tsec1_clk = 0;
+ break;
+ case 1:
+ tsec1_clk = csb_clk;
+ break;
+ case 2:
+ tsec1_clk = csb_clk / 2;
+ break;
+ case 3:
+ tsec1_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_TSEC1CM value */
+ return -2;
+ }
+
+ switch ((sccr & SCCR_USBDRCM) >> SCCR_USBDRCM_SHIFT) {
+ case 0:
+ usbdr_clk = 0;
+ break;
+ case 1:
+ usbdr_clk = csb_clk;
+ break;
+ case 2:
+ usbdr_clk = csb_clk / 2;
+ break;
+ case 3:
+ usbdr_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_USBDRCM value */
+ return -3;
+ }
+#endif
+
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ switch ((sccr & SCCR_TSEC2CM) >> SCCR_TSEC2CM_SHIFT) {
+ case 0:
+ tsec2_clk = 0;
+ break;
+ case 1:
+ tsec2_clk = csb_clk;
+ break;
+ case 2:
+ tsec2_clk = csb_clk / 2;
+ break;
+ case 3:
+ tsec2_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_TSEC2CM value */
+ return -4;
+ }
+#elif defined(CONFIG_MPC8313)
+ tsec2_clk = tsec1_clk;
+
+ if (!(sccr & SCCR_TSEC1ON))
+ tsec1_clk = 0;
+ if (!(sccr & SCCR_TSEC2ON))
+ tsec2_clk = 0;
+#endif
+
+#if defined(CONFIG_MPC834x)
+ switch ((sccr & SCCR_USBMPHCM) >> SCCR_USBMPHCM_SHIFT) {
+ case 0:
+ usbmph_clk = 0;
+ break;
+ case 1:
+ usbmph_clk = csb_clk;
+ break;
+ case 2:
+ usbmph_clk = csb_clk / 2;
+ break;
+ case 3:
+ usbmph_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_USBMPHCM value */
+ return -5;
+ }
+
+ if (usbmph_clk != 0 && usbdr_clk != 0 && usbmph_clk != usbdr_clk) {
+ /* if USB MPH clock is not disabled and
+ * USB DR clock is not disabled then
+ * USB MPH & USB DR must have the same rate
+ */
+ return -6;
+ }
+#endif
+ switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) {
+ case 0:
+ enc_clk = 0;
+ break;
+ case 1:
+ enc_clk = csb_clk;
+ break;
+ case 2:
+ enc_clk = csb_clk / 2;
+ break;
+ case 3:
+ enc_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_ENCCM value */
+ return -7;
+ }
+
+#if defined(CONFIG_MPC837x)
+ switch ((sccr & SCCR_SDHCCM) >> SCCR_SDHCCM_SHIFT) {
+ case 0:
+ sdhc_clk = 0;
+ break;
+ case 1:
+ sdhc_clk = csb_clk;
+ break;
+ case 2:
+ sdhc_clk = csb_clk / 2;
+ break;
+ case 3:
+ sdhc_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_SDHCCM value */
+ return -8;
+ }
+#endif
+#if defined(CONFIG_MPC8315)
+ switch ((sccr & SCCR_TDMCM) >> SCCR_TDMCM_SHIFT) {
+ case 0:
+ tdm_clk = 0;
+ break;
+ case 1:
+ tdm_clk = csb_clk;
+ break;
+ case 2:
+ tdm_clk = csb_clk / 2;
+ break;
+ case 3:
+ tdm_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_TDMCM value */
+ return -8;
+ }
+#endif
+
+#if defined(CONFIG_MPC834x)
+ i2c1_clk = tsec2_clk;
+#elif defined(CONFIG_MPC8360)
+ i2c1_clk = csb_clk;
+#elif defined(CONFIG_MPC832x)
+ i2c1_clk = enc_clk;
+#elif defined(CONFIG_MPC831x)
+ i2c1_clk = enc_clk;
+#elif defined(CONFIG_MPC837x)
+ i2c1_clk = sdhc_clk;
+#endif
+#if !defined(CONFIG_MPC832x)
+ i2c2_clk = csb_clk; /* i2c-2 clk is equal to csb clk */
+#endif
+
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC831x)
+ switch ((sccr & SCCR_PCIEXP1CM) >> SCCR_PCIEXP1CM_SHIFT) {
+ case 0:
+ pciexp1_clk = 0;
+ break;
+ case 1:
+ pciexp1_clk = csb_clk;
+ break;
+ case 2:
+ pciexp1_clk = csb_clk / 2;
+ break;
+ case 3:
+ pciexp1_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_PCIEXP1CM value */
+ return -9;
+ }
+
+ switch ((sccr & SCCR_PCIEXP2CM) >> SCCR_PCIEXP2CM_SHIFT) {
+ case 0:
+ pciexp2_clk = 0;
+ break;
+ case 1:
+ pciexp2_clk = csb_clk;
+ break;
+ case 2:
+ pciexp2_clk = csb_clk / 2;
+ break;
+ case 3:
+ pciexp2_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_PCIEXP2CM value */
+ return -10;
+ }
+#endif
+
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ switch ((sccr & SCCR_SATA1CM) >> SCCR_SATA1CM_SHIFT) {
+ case 0:
+ sata_clk = 0;
+ break;
+ case 1:
+ sata_clk = csb_clk;
+ break;
+ case 2:
+ sata_clk = csb_clk / 2;
+ break;
+ case 3:
+ sata_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_SATACM value */
+ return -11;
+ }
+#endif
+
+ lbiu_clk = csb_clk *
+ (1 + ((im->reset.rcwl & HRCWL_LBIUCM) >> HRCWL_LBIUCM_SHIFT));
+ lcrr = (im->lbus.lcrr & LCRR_CLKDIV) >> LCRR_CLKDIV_SHIFT;
+ switch (lcrr) {
+ case 2:
+ case 4:
+ case 8:
+ lclk_clk = lbiu_clk / lcrr;
+ break;
+ default:
+ /* unknown lcrr */
+ return -12;
+ }
+
+ mem_clk = csb_clk *
+ (1 + ((im->reset.rcwl & HRCWL_DDRCM) >> HRCWL_DDRCM_SHIFT));
+ corepll = (im->reset.rcwl & HRCWL_COREPLL) >> HRCWL_COREPLL_SHIFT;
+#if defined(CONFIG_MPC8360)
+ mem_sec_clk = csb_clk * (1 +
+ ((im->reset.rcwl & HRCWL_LBIUCM) >> HRCWL_LBIUCM_SHIFT));
+#endif
+
+ corecnf_tab_index = ((corepll & 0x1F) << 2) | ((corepll & 0x60) >> 5);
+ if (corecnf_tab_index > (sizeof(corecnf_tab) / sizeof(corecnf_t))) {
+ /* corecnf_tab_index is too high, possibly worng value */
+ return -11;
+ }
+ switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) {
+ case _byp:
+ case _x1:
+ case _1x:
+ core_clk = csb_clk;
+ break;
+ case _1_5x:
+ core_clk = (3 * csb_clk) / 2;
+ break;
+ case _2x:
+ core_clk = 2 * csb_clk;
+ break;
+ case _2_5x:
+ core_clk = (5 * csb_clk) / 2;
+ break;
+ case _3x:
+ core_clk = 3 * csb_clk;
+ break;
+ default:
+ /* unkown core to csb ratio */
+ return -13;
+ }
+
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+ qepmf = (im->reset.rcwl & HRCWL_CEPMF) >> HRCWL_CEPMF_SHIFT;
+ qepdf = (im->reset.rcwl & HRCWL_CEPDF) >> HRCWL_CEPDF_SHIFT;
+ qe_clk = (pci_sync_in * qepmf) / (1 + qepdf);
+ brg_clk = qe_clk / 2;
+#endif
+
+ gd->csb_clk = csb_clk;
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+ gd->tsec1_clk = tsec1_clk;
+ gd->tsec2_clk = tsec2_clk;
+ gd->usbdr_clk = usbdr_clk;
+#endif
+#if defined(CONFIG_MPC834x)
+ gd->usbmph_clk = usbmph_clk;
+#endif
+#if defined(CONFIG_MPC8315)
+ gd->tdm_clk = tdm_clk;
+#endif
+#if defined(CONFIG_MPC837x)
+ gd->sdhc_clk = sdhc_clk;
+#endif
+ gd->core_clk = core_clk;
+ gd->i2c1_clk = i2c1_clk;
+#if !defined(CONFIG_MPC832x)
+ gd->i2c2_clk = i2c2_clk;
+#endif
+ gd->enc_clk = enc_clk;
+ gd->lbiu_clk = lbiu_clk;
+ gd->lclk_clk = lclk_clk;
+ gd->mem_clk = mem_clk;
+#if defined(CONFIG_MPC8360)
+ gd->mem_sec_clk = mem_sec_clk;
+#endif
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+ gd->qe_clk = qe_clk;
+ gd->brg_clk = brg_clk;
+#endif
+#if defined(CONFIG_MPC837x)
+ gd->pciexp1_clk = pciexp1_clk;
+ gd->pciexp2_clk = pciexp2_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ gd->sata_clk = sata_clk;
+#endif
+ gd->pci_clk = pci_sync_in;
+ gd->cpu_clk = gd->core_clk;
+ gd->bus_clk = gd->csb_clk;
+ return 0;
+
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq(ulong dummy)
+{
+ return gd->csb_clk;
+}
+
+int do_clocks (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ char buf[32];
+
+ printf("Clock configuration:\n");
+ printf(" Core: %-4s MHz\n", strmhz(buf, gd->core_clk));
+ printf(" Coherent System Bus: %-4s MHz\n", strmhz(buf, gd->csb_clk));
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+ printf(" QE: %-4s MHz\n", strmhz(buf, gd->qe_clk));
+ printf(" BRG: %-4s MHz\n", strmhz(buf, gd->brg_clk));
+#endif
+ printf(" Local Bus Controller:%-4s MHz\n", strmhz(buf, gd->lbiu_clk));
+ printf(" Local Bus: %-4s MHz\n", strmhz(buf, gd->lclk_clk));
+ printf(" DDR: %-4s MHz\n", strmhz(buf, gd->mem_clk));
+#if defined(CONFIG_MPC8360)
+ printf(" DDR Secondary: %-4s MHz\n", strmhz(buf, gd->mem_sec_clk));
+#endif
+ printf(" SEC: %-4s MHz\n", strmhz(buf, gd->enc_clk));
+ printf(" I2C1: %-4s MHz\n", strmhz(buf, gd->i2c1_clk));
+#if !defined(CONFIG_MPC832x)
+ printf(" I2C2: %-4s MHz\n", strmhz(buf, gd->i2c2_clk));
+#endif
+#if defined(CONFIG_MPC8315)
+ printf(" TDM: %-4s MHz\n", strmhz(buf, gd->tdm_clk));
+#endif
+#if defined(CONFIG_MPC837x)
+ printf(" SDHC: %-4s MHz\n", strmhz(buf, gd->sdhc_clk));
+#endif
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+ printf(" TSEC1: %-4s MHz\n", strmhz(buf, gd->tsec1_clk));
+ printf(" TSEC2: %-4s MHz\n", strmhz(buf, gd->tsec2_clk));
+ printf(" USB DR: %-4s MHz\n", strmhz(buf, gd->usbdr_clk));
+#endif
+#if defined(CONFIG_MPC834x)
+ printf(" USB MPH: %-4s MHz\n", strmhz(buf, gd->usbmph_clk));
+#endif
+#if defined(CONFIG_MPC837x)
+ printf(" PCIEXP1: %-4s MHz\n", strmhz(buf, gd->pciexp1_clk));
+ printf(" PCIEXP2: %-4s MHz\n", strmhz(buf, gd->pciexp2_clk));
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ printf(" SATA: %-4s MHz\n", strmhz(buf, gd->sata_clk));
+#endif
+ return 0;
+}
+
+U_BOOT_CMD(clocks, 1, 0, do_clocks,
+ "print clock configuration",
+ " clocks"
+);
diff --git a/arch/powerpc/cpu/mpc83xx/start.S b/arch/powerpc/cpu/mpc83xx/start.S
new file mode 100644
index 0000000..a7c8079
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/start.S
@@ -0,0 +1,1207 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
+ * Copyright Freescale Semiconductor, Inc. 2004, 2006, 2008.
+ *
+ * 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 MPC83xx PowerPC based Embedded Boards
+ */
+
+#include <config.h>
+#include <mpc83xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_83XX 1 /* needed for Linux kernel header files*/
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING "MPC83XX"
+#endif
+
+/* We don't want the MMU yet.
+ */
+#undef MSR_KERNEL
+
+/*
+ * Floating Point enable, Machine Check and Recoverable Interr.
+ */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SYS_RAMBOOT)
+#define CONFIG_SYS_FLASHBOOT
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(__bss_start)
+ GOT_ENTRY(_end)
+
+#ifndef CONFIG_NAND_SPL
+ GOT_ENTRY(_FIXUP_TABLE_)
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+#endif
+ END_GOT
+
+/*
+ * The Hard Reset Configuration Word (HRCW) table is in the first 64
+ * (0x40) bytes of flash. It has 8 bytes, but each byte is repeated 8
+ * times so the processor can fetch it out of flash whether the flash
+ * is 8, 16, 32, or 64 bits wide (hardware trickery).
+ */
+ .text
+#define _HRCW_TABLE_ENTRY(w) \
+ .fill 8,1,(((w)>>24)&0xff); \
+ .fill 8,1,(((w)>>16)&0xff); \
+ .fill 8,1,(((w)>> 8)&0xff); \
+ .fill 8,1,(((w) )&0xff)
+
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_LOW)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_HIGH)
+
+/*
+ * Magic number and version string - put it after the HRCW since it
+ * cannot be first in flash like it is in many other processors.
+ */
+ .long 0x27051956 /* U-Boot Magic Number */
+
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+ .ascii " ", CONFIG_IDENT_STRING, "\0"
+
+ .align 2
+
+ .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
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+ .globl ppcDWstore
+ppcDWstore:
+ lfd 1, 0(r4)
+ stfd 1, 0(r3)
+ blr
+
+ .globl ppcDWload
+ppcDWload:
+ lfd 1, 0(r3)
+ stfd 1, 0(r4)
+ blr
+
+#ifndef CONFIG_DEFAULT_IMMR
+#error CONFIG_DEFAULT_IMMR must be defined
+#endif /* CONFIG_SYS_DEFAULT_IMMR */
+#ifndef CONFIG_SYS_IMMR
+#define CONFIG_SYS_IMMR CONFIG_DEFAULT_IMMR
+#endif /* CONFIG_SYS_IMMR */
+
+/*
+ * After configuration, a system reset exception is executed using the
+ * vector at offset 0x100 relative to the base set by MSR[IP]. If
+ * MSR[IP] is 0, the base address is 0x00000000. If MSR[IP] is 1, the
+ * base address is 0xfff00000. In the case of a Power On Reset or Hard
+ * Reset, the value of MSR[IP] is determined by the CIP field in the
+ * HRCW.
+ *
+ * Other bits in the HRCW set up the Base Address and Port Size in BR0.
+ * This determines the location of the boot ROM (flash or EPROM) in the
+ * processor's address space at boot time. As long as the HRCW is set up
+ * so that we eventually end up executing the code below when the
+ * processor executes the reset exception, the actual values used should
+ * not matter.
+ *
+ * Once we have got here, the address mask in OR0 is cleared so that the
+ * bottom 32K of the boot ROM is effectively repeated all throughout the
+ * processor's address space, after which we can jump to the absolute
+ * address at which the boot ROM was linked at compile time, and proceed
+ * to initialise the memory controller without worrying if the rug will
+ * be pulled out from under us, so to speak (it will be fine as long as
+ * we configure BR0 with the same boot ROM link address).
+ */
+ . = EXC_OFF_SYS_RESET
+
+ .globl _start
+_start: /* time t 0 */
+ li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH*/
+ nop
+ b boot_cold
+
+ . = EXC_OFF_SYS_RESET + 0x10
+
+ .globl _start_warm
+_start_warm:
+ li r21, BOOTFLAG_WARM /* Software reboot */
+ b boot_warm
+
+
+boot_cold: /* time t 3 */
+ lis r4, CONFIG_DEFAULT_IMMR@h
+ nop
+boot_warm: /* time t 5 */
+ mfmsr r5 /* save msr contents */
+
+ /* 83xx manuals prescribe a specific sequence for updating IMMRBAR. */
+ bl 1f
+1: mflr r7
+
+ lis r3, CONFIG_SYS_IMMR@h
+ ori r3, r3, CONFIG_SYS_IMMR@l
+
+ lwz r6, IMMRBAR(r4)
+ isync
+
+ stw r3, IMMRBAR(r4)
+ lwz r6, 0(r7) /* Arbitrary external load */
+ isync
+
+ lwz r6, IMMRBAR(r3)
+ isync
+
+ /* Initialise the E300 processor core */
+ /*------------------------------------------*/
+
+#ifdef CONFIG_NAND_SPL
+ /* The FCM begins execution after only the first page
+ * is loaded. Wait for the rest before branching
+ * to another flash page.
+ */
+1: lwz r6, 0x50b0(r3)
+ andi. r6, r6, 1
+ beq 1b
+#endif
+
+ bl init_e300_core
+
+#ifdef CONFIG_SYS_FLASHBOOT
+
+ /* Inflate flash location so it appears everywhere, calculate */
+ /* the absolute address in final location of the FLASH, jump */
+ /* there and deflate the flash size back to minimal size */
+ /*------------------------------------------------------------*/
+ bl map_flash_by_law1
+ lis r4, (CONFIG_SYS_MONITOR_BASE)@h
+ ori r4, r4, (CONFIG_SYS_MONITOR_BASE)@l
+ addi r5, r4, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r5
+ blr
+in_flash:
+#if 1 /* Remapping flash with LAW0. */
+ bl remap_flash_by_law0
+#endif
+#endif /* CONFIG_SYS_FLASHBOOT */
+
+ /* setup the bats */
+ bl setup_bats
+ sync
+
+ /*
+ * Cache must be enabled here for stack-in-cache trick.
+ * This means we need to enable the BATS.
+ * This means:
+ * 1) for the EVB, original gt regs need to be mapped
+ * 2) need to have an IBAT for the 0xf region,
+ * we are running there!
+ * Cache should be turned on after BATs, since by default
+ * everything is write-through.
+ * The init-mem BAT can be reused after reloc. The old
+ * gt-regs BAT can be reused after board_init_f calls
+ * board_early_init_f (EVB only).
+ */
+ /* enable address translation */
+ bl enable_addr_trans
+ sync
+
+ /* enable the data cache */
+ bl dcache_enable
+ sync
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+ bl lock_ram_in_cache
+ sync
+#endif
+
+ /* set up the stack pointer in our newly created
+ * cache-ram (r1) */
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_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 */
+
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable & stack humble */
+ /*------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ lis r3, CONFIG_SYS_IMMR@h
+ /* run low-level CPU init code (in Flash)*/
+ bl cpu_init_f
+
+ /* r3: BOOTFLAG */
+ mr r3, r21
+ /* run 1st part of board init code (in Flash)*/
+ bl board_init_f
+
+#ifndef CONFIG_NAND_SPL
+/*
+ * Vector 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. */
+#ifndef FIXME
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+#endif
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ 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, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+ . = 0x1300
+ /*
+ * This exception occurs when the program counter matches the
+ * Instruction Address Breakpoint Register (IABR).
+ *
+ * I want the cpu to halt if this occurs so I can hunt around
+ * with the debugger and look at things.
+ *
+ * When DEBUG is defined, both machine check enable (in the MSR)
+ * and checkstop reset enable (in the reset mode register) are
+ * turned off and so a checkstop condition will result in the cpu
+ * halting.
+ *
+ * I force the cpu into a checkstop condition by putting an illegal
+ * instruction here (at least this is the theory).
+ *
+ * well - that didnt work, so just do an infinite loop!
+ */
+1: b 1b
+#else
+ STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+ STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+ STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x3000
+
+/*
+ * 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)
+ 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
+#endif /* !CONFIG_NAND_SPL */
+
+/*
+ * This code initialises the E300 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+ .globl init_e300_core
+init_e300_core: /* time t 10 */
+ /* Initialize machine status; enable machine check interrupt */
+ /*-----------------------------------------------------------*/
+
+ li r3, MSR_KERNEL /* Set ME and RI flags */
+ rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
+#ifdef DEBUG
+ rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
+#endif
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+
+ lis r3, CONFIG_SYS_IMMR@h
+#if defined(CONFIG_WATCHDOG)
+ /* Initialise the Wathcdog values and reset it (if req) */
+ /*------------------------------------------------------*/
+ lis r4, CONFIG_SYS_WATCHDOG_VALUE
+ ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)
+ stw r4, SWCRR(r3)
+
+ /* and reset it */
+
+ li r4, 0x556C
+ sth r4, SWSRR@l(r3)
+ li r4, -0x55C7
+ sth r4, SWSRR@l(r3)
+#else
+ /* Disable Wathcdog */
+ /*-------------------*/
+ lwz r4, SWCRR(r3)
+ /* Check to see if its enabled for disabling
+ once disabled by SW you can't re-enable */
+ andi. r4, r4, 0x4
+ beq 1f
+ xor r4, r4, r4
+ stw r4, SWCRR(r3)
+1:
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_MASK_AER_AO)
+ /* Write the Arbiter Event Enable to mask Address Only traps. */
+ /* This prevents the dcbz instruction from being trapped when */
+ /* HID0_ABE Address Broadcast Enable is set and the MEMORY */
+ /* COHERENCY bit is set in the WIMG bits, which is often */
+ /* needed for PCI operation. */
+ lwz r4, 0x0808(r3)
+ rlwinm r0, r4, 0, ~AER_AO
+ stw r0, 0x0808(r3)
+#endif /* CONFIG_MASK_AER_AO */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /* - force invalidation of data and instruction caches */
+ /*------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_HID0_INIT@h
+ ori r3, r3, (CONFIG_SYS_HID0_INIT | HID0_ICFI | HID0_DCFI)@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID0_FINAL@h
+ ori r3, r3, (CONFIG_SYS_HID0_FINAL & ~(HID0_ICFI | HID0_DCFI))@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID2@h
+ ori r3, r3, CONFIG_SYS_HID2@l
+ SYNC
+ mtspr HID2, r3
+
+ /* Done! */
+ /*------------------------------*/
+ blr
+
+ /* setup_bats - set them up to some initial state */
+ .globl setup_bats
+setup_bats:
+ addis r0, r0, 0x0000
+
+ /* IBAT 0 */
+ addis r4, r0, CONFIG_SYS_IBAT0L@h
+ ori r4, r4, CONFIG_SYS_IBAT0L@l
+ addis r3, r0, CONFIG_SYS_IBAT0U@h
+ ori r3, r3, CONFIG_SYS_IBAT0U@l
+ mtspr IBAT0L, r4
+ mtspr IBAT0U, r3
+
+ /* DBAT 0 */
+ addis r4, r0, CONFIG_SYS_DBAT0L@h
+ ori r4, r4, CONFIG_SYS_DBAT0L@l
+ addis r3, r0, CONFIG_SYS_DBAT0U@h
+ ori r3, r3, CONFIG_SYS_DBAT0U@l
+ mtspr DBAT0L, r4
+ mtspr DBAT0U, r3
+
+ /* IBAT 1 */
+ addis r4, r0, CONFIG_SYS_IBAT1L@h
+ ori r4, r4, CONFIG_SYS_IBAT1L@l
+ addis r3, r0, CONFIG_SYS_IBAT1U@h
+ ori r3, r3, CONFIG_SYS_IBAT1U@l
+ mtspr IBAT1L, r4
+ mtspr IBAT1U, r3
+
+ /* DBAT 1 */
+ addis r4, r0, CONFIG_SYS_DBAT1L@h
+ ori r4, r4, CONFIG_SYS_DBAT1L@l
+ addis r3, r0, CONFIG_SYS_DBAT1U@h
+ ori r3, r3, CONFIG_SYS_DBAT1U@l
+ mtspr DBAT1L, r4
+ mtspr DBAT1U, r3
+
+ /* IBAT 2 */
+ addis r4, r0, CONFIG_SYS_IBAT2L@h
+ ori r4, r4, CONFIG_SYS_IBAT2L@l
+ addis r3, r0, CONFIG_SYS_IBAT2U@h
+ ori r3, r3, CONFIG_SYS_IBAT2U@l
+ mtspr IBAT2L, r4
+ mtspr IBAT2U, r3
+
+ /* DBAT 2 */
+ addis r4, r0, CONFIG_SYS_DBAT2L@h
+ ori r4, r4, CONFIG_SYS_DBAT2L@l
+ addis r3, r0, CONFIG_SYS_DBAT2U@h
+ ori r3, r3, CONFIG_SYS_DBAT2U@l
+ mtspr DBAT2L, r4
+ mtspr DBAT2U, r3
+
+ /* IBAT 3 */
+ addis r4, r0, CONFIG_SYS_IBAT3L@h
+ ori r4, r4, CONFIG_SYS_IBAT3L@l
+ addis r3, r0, CONFIG_SYS_IBAT3U@h
+ ori r3, r3, CONFIG_SYS_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+
+ /* DBAT 3 */
+ addis r4, r0, CONFIG_SYS_DBAT3L@h
+ ori r4, r4, CONFIG_SYS_DBAT3L@l
+ addis r3, r0, CONFIG_SYS_DBAT3U@h
+ ori r3, r3, CONFIG_SYS_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+
+#ifdef CONFIG_HIGH_BATS
+ /* IBAT 4 */
+ addis r4, r0, CONFIG_SYS_IBAT4L@h
+ ori r4, r4, CONFIG_SYS_IBAT4L@l
+ addis r3, r0, CONFIG_SYS_IBAT4U@h
+ ori r3, r3, CONFIG_SYS_IBAT4U@l
+ mtspr IBAT4L, r4
+ mtspr IBAT4U, r3
+
+ /* DBAT 4 */
+ addis r4, r0, CONFIG_SYS_DBAT4L@h
+ ori r4, r4, CONFIG_SYS_DBAT4L@l
+ addis r3, r0, CONFIG_SYS_DBAT4U@h
+ ori r3, r3, CONFIG_SYS_DBAT4U@l
+ mtspr DBAT4L, r4
+ mtspr DBAT4U, r3
+
+ /* IBAT 5 */
+ addis r4, r0, CONFIG_SYS_IBAT5L@h
+ ori r4, r4, CONFIG_SYS_IBAT5L@l
+ addis r3, r0, CONFIG_SYS_IBAT5U@h
+ ori r3, r3, CONFIG_SYS_IBAT5U@l
+ mtspr IBAT5L, r4
+ mtspr IBAT5U, r3
+
+ /* DBAT 5 */
+ addis r4, r0, CONFIG_SYS_DBAT5L@h
+ ori r4, r4, CONFIG_SYS_DBAT5L@l
+ addis r3, r0, CONFIG_SYS_DBAT5U@h
+ ori r3, r3, CONFIG_SYS_DBAT5U@l
+ mtspr DBAT5L, r4
+ mtspr DBAT5U, r3
+
+ /* IBAT 6 */
+ addis r4, r0, CONFIG_SYS_IBAT6L@h
+ ori r4, r4, CONFIG_SYS_IBAT6L@l
+ addis r3, r0, CONFIG_SYS_IBAT6U@h
+ ori r3, r3, CONFIG_SYS_IBAT6U@l
+ mtspr IBAT6L, r4
+ mtspr IBAT6U, r3
+
+ /* DBAT 6 */
+ addis r4, r0, CONFIG_SYS_DBAT6L@h
+ ori r4, r4, CONFIG_SYS_DBAT6L@l
+ addis r3, r0, CONFIG_SYS_DBAT6U@h
+ ori r3, r3, CONFIG_SYS_DBAT6U@l
+ mtspr DBAT6L, r4
+ mtspr DBAT6U, r3
+
+ /* IBAT 7 */
+ addis r4, r0, CONFIG_SYS_IBAT7L@h
+ ori r4, r4, CONFIG_SYS_IBAT7L@l
+ addis r3, r0, CONFIG_SYS_IBAT7U@h
+ ori r3, r3, CONFIG_SYS_IBAT7U@l
+ mtspr IBAT7L, r4
+ mtspr IBAT7U, r3
+
+ /* DBAT 7 */
+ addis r4, r0, CONFIG_SYS_DBAT7L@h
+ ori r4, r4, CONFIG_SYS_DBAT7L@l
+ addis r3, r0, CONFIG_SYS_DBAT7U@h
+ ori r3, r3, CONFIG_SYS_DBAT7U@l
+ mtspr DBAT7L, r4
+ mtspr DBAT7U, r3
+#endif
+
+ isync
+
+ /* invalidate all tlb's
+ *
+ * From the 603e User Manual: "The 603e provides the ability to
+ * invalidate a TLB entry. The TLB Invalidate Entry (tlbie)
+ * instruction invalidates the TLB entry indexed by the EA, and
+ * operates on both the instruction and data TLBs simultaneously
+ * invalidating four TLB entries (both sets in each TLB). The
+ * index corresponds to bits 15-19 of the EA. To invalidate all
+ * entries within both TLBs, 32 tlbie instructions should be
+ * issued, incrementing this field by one each time."
+ *
+ * "Note that the tlbia instruction is not implemented on the
+ * 603e."
+ *
+ * bits 15-19 correspond to addresses 0x00000000 to 0x0001F000
+ * incrementing by 0x1000 each time. The code below is sort of
+ * based on code in "flush_tlbs" from arch/powerpc/kernel/head.S
+ *
+ */
+ lis r3, 0
+ lis r5, 2
+
+1:
+ tlbie r3
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt 1b
+
+ blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+ .globl icache_enable
+icache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ICE
+ li r4, HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_ICE|HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r4
+ isync
+ mtspr HID0, r3 /* clears invalidate, enable and lock */
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ ori r3, r3, HID0_DCE
+ sync
+ mtspr HID0, r3 /* enable, no invalidate */
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mflr r4
+ bl flush_dcache /* uses r3 and r5 */
+ mfspr r3, HID0
+ li r5, HID0_DCE|HID0_DLOCK
+ andc r3, r3, r5
+ ori r5, r3, HID0_DCFI
+ sync
+ mtspr HID0, r5 /* sets invalidate, clears enable and lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ mtlr r4
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31
+ blr
+
+ .globl flush_dcache
+flush_dcache:
+ lis r3, 0
+ lis r5, CONFIG_SYS_CACHELINE_SIZE
+1: cmp 0, 1, r3, r5
+ bge 2f
+ lwz r5, 0(r3)
+ lis r5, CONFIG_SYS_CACHELINE_SIZE
+ addi r3, r3, 0x4
+ b 1b
+2: 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 r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__bss_start)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE)
+ * + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ 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)
+
+ /* copy */
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+
+ addi r0,r5,3
+ srwi. r0,r0,2
+ mtctr r0
+ la r8,-4(r4)
+ la r7,-4(r3)
+
+ /* and compare */
+20: lwzu r20,4(r8)
+ lwzu r21,4(r7)
+ xor. r22, r20, r21
+ bne 30f
+ bdnz 20b
+ b 4f
+
+ /* compare failed */
+30: li r3, 0
+ blr
+
+2: slwi r0,r0,2 /* re copy in reverse order ... y do we needed it? */
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * 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:
+
+ /*
+ * Relocation Function, r12 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)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+#ifndef CONFIG_NAND_SPL
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ 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:
+#endif
+
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+#if defined(CONFIG_HYMOD)
+ /*
+ * For HYMOD - the environment is the very last item in flash.
+ * The real .bss stops just before environment starts, so only
+ * clear up to that point.
+ *
+ * taken from mods for FADS board
+ */
+ lwz r4,GOT(environment)
+#else
+ lwz r4,GOT(_end)
+#endif
+
+ 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 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+#ifndef CONFIG_NAND_SPL
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ 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 */
+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
+
+ mfmsr r3 /* now that the vectors have */
+ lis r7, MSR_IP@h /* relocated into low memory */
+ ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
+ andc r3, r3, r7 /* (if it was on) */
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+
+ mtlr r4 /* restore link register */
+ blr
+
+#endif /* !CONFIG_NAND_SPL */
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+
+ /* Lock the data cache */
+ mfspr r0, HID0
+ ori r0, r0, HID0_DLOCK
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+
+#ifndef CONFIG_NAND_SPL
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1: icbi r0, r3
+ dcbi r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+ sync /* Wait for all icbi to complete on bus */
+ isync
+
+ /* Unlock the data cache and invalidate it */
+ mfspr r3, HID0
+ li r5, HID0_DLOCK|HID0_DCFI
+ andc r3, r3, r5 /* no invalidate, unlock */
+ ori r5, r3, HID0_DCFI /* invalidate, unlock */
+ sync
+ mtspr HID0, r5 /* invalidate, unlock */
+ sync
+ mtspr HID0, r3 /* no invalidate, unlock */
+ blr
+#endif /* !CONFIG_NAND_SPL */
+#endif /* CONFIG_SYS_INIT_RAM_LOCK */
+
+#ifdef CONFIG_SYS_FLASHBOOT
+map_flash_by_law1:
+ /* When booting from ROM (Flash or EPROM), clear the */
+ /* Address Mask in OR0 so ROM appears everywhere */
+ /*----------------------------------------------------*/
+ lis r3, (CONFIG_SYS_IMMR)@h /* r3 <= CONFIG_SYS_IMMR */
+ lwz r4, OR0@l(r3)
+ li r5, 0x7fff /* r5 <= 0x00007FFFF */
+ and r4, r4, r5
+ stw r4, OR0@l(r3) /* OR0 <= OR0 & 0x00007FFFF */
+
+ /* As MPC8349E User's Manual presented, when RCW[BMS] is set to 0,
+ * system will boot from 0x0000_0100, and the LBLAWBAR0[BASE_ADDR]
+ * reset value is 0x00000; when RCW[BMS] is set to 1, system will boot
+ * from 0xFFF0_0100, and the LBLAWBAR0[BASE_ADDR] reset value is
+ * 0xFF800. From the hard resetting to here, the processor fetched and
+ * executed the instructions one by one. There is not absolutely
+ * jumping happened. Laterly, the u-boot code has to do an absolutely
+ * jumping to tell the CPU instruction fetching component what the
+ * u-boot TEXT base address is. Because the TEXT base resides in the
+ * boot ROM memory space, to garantee the code can run smoothly after
+ * that jumping, we must map in the entire boot ROM by Local Access
+ * Window. Sometimes, we desire an non-0x00000 or non-0xFF800 starting
+ * address for boot ROM, such as 0xFE000000. In this case, the default
+ * LBIU Local Access Widow 0 will not cover this memory space. So, we
+ * need another window to map in it.
+ */
+ lis r4, (CONFIG_SYS_FLASH_BASE)@h
+ ori r4, r4, (CONFIG_SYS_FLASH_BASE)@l
+ stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CONFIG_SYS_FLASH_BASE */
+
+ /* Store 0x80000012 + log2(CONFIG_SYS_FLASH_SIZE) into LBLAWAR1 */
+ lis r4, (0x80000012)@h
+ ori r4, r4, (0x80000012)@l
+ li r5, CONFIG_SYS_FLASH_SIZE
+1: srawi. r5, r5, 1 /* r5 = r5 >> 1 */
+ addi r4, r4, 1
+ bne 1b
+
+ stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 8MB Flash Size */
+ blr
+
+ /* Though all the LBIU Local Access Windows and LBC Banks will be
+ * initialized in the C code, we'd better configure boot ROM's
+ * window 0 and bank 0 correctly at here.
+ */
+remap_flash_by_law0:
+ /* Initialize the BR0 with the boot ROM starting address. */
+ lwz r4, BR0(r3)
+ li r5, 0x7FFF
+ and r4, r4, r5
+ lis r5, (CONFIG_SYS_FLASH_BASE & 0xFFFF8000)@h
+ ori r5, r5, (CONFIG_SYS_FLASH_BASE & 0xFFFF8000)@l
+ or r5, r5, r4
+ stw r5, BR0(r3) /* r5 <= (CONFIG_SYS_FLASH_BASE & 0xFFFF8000) | (BR0 & 0x00007FFF) */
+
+ lwz r4, OR0(r3)
+ lis r5, ~((CONFIG_SYS_FLASH_SIZE << 4) - 1)
+ or r4, r4, r5
+ stw r4, OR0(r3)
+
+ lis r4, (CONFIG_SYS_FLASH_BASE)@h
+ ori r4, r4, (CONFIG_SYS_FLASH_BASE)@l
+ stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CONFIG_SYS_FLASH_BASE */
+
+ /* Store 0x80000012 + log2(CONFIG_SYS_FLASH_SIZE) into LBLAWAR0 */
+ lis r4, (0x80000012)@h
+ ori r4, r4, (0x80000012)@l
+ li r5, CONFIG_SYS_FLASH_SIZE
+1: srawi. r5, r5, 1 /* r5 = r5 >> 1 */
+ addi r4, r4, 1
+ bne 1b
+ stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= Flash Size */
+
+
+ xor r4, r4, r4
+ stw r4, LBLAWBAR1(r3)
+ stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */
+ blr
+#endif /* CONFIG_SYS_FLASHBOOT */
diff --git a/arch/powerpc/cpu/mpc83xx/traps.c b/arch/powerpc/cpu/mpc83xx/traps.c
new file mode 100644
index 0000000..9d71b8b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/traps.c
@@ -0,0 +1,266 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * 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 <kgdb.h>
+#include <asm/processor.h>
+#include <asm/mpc8349_pci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* 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)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ puts ("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ putc ('\n');
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ putc ('\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);
+
+ putc ('\n');
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ putc ('\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);
+}
+
+#ifdef CONFIG_PCI
+void dump_pci (void)
+{
+/*
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ printf ("PCI: err status %x err mask %x err ctrl %x\n",
+ le32_to_cpu (immap->im_pci.pci_esr),
+ le32_to_cpu (immap->im_pci.pci_emr),
+ le32_to_cpu (immap->im_pci.pci_ecr));
+ printf (" error address %x error data %x ctrl %x\n",
+ le32_to_cpu (immap->im_pci.pci_eacr),
+ le32_to_cpu (immap->im_pci.pci_edcr),
+ le32_to_cpu (immap->im_pci.pci_eccr));
+*/
+}
+#endif
+
+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.
+ */
+#ifdef CONFIG_PCI
+#if 0
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+#ifdef DEBUG
+ dump_pci();
+#endif
+ /* clear the error in the error status register */
+ if(immap->im_pci.pci_esr & cpu_to_le32(PCI_ERROR_PCI_NO_RSP)) {
+ immap->im_pci.pci_esr = cpu_to_le32(PCI_ERROR_PCI_NO_RSP);
+ return;
+ }
+#endif
+#endif /* CONFIG_PCI */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ puts ("Machine check in kernel mode.\n"
+ "Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ puts ("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ puts ("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ puts ("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ puts ("Address parity signal\n");
+ break;
+ default:
+ puts ("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_PCI
+ dump_pci();
+#endif
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_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)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_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 defined(CONFIG_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);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc83xx/u-boot.lds b/arch/powerpc/cpu/mpc83xx/u-boot.lds
new file mode 100644
index 0000000..0b74a13
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/u-boot.lds
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) }
+ .plt : { *(.plt) }
+ .text :
+ {
+ arch/powerpc/cpu/mpc83xx/start.o (.text)
+ *(.text)
+ *(.got1)
+ . = ALIGN(16);
+ *(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ *(.got)
+ _GOT2_TABLE_ = .;
+ *(.got2)
+ _FIXUP_TABLE_ = .;
+ *(.fixup)
+ }
+ __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+ __u_boot_cmd_start = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+ENTRY(_start)