summaryrefslogtreecommitdiff
path: root/cpu/mpc83xx
diff options
context:
space:
mode:
authorEran Liberty <liberty@freescale.com>2005-07-28 10:08:46 -0500
committerJon Loeliger <jdl@freescale.com>2005-07-28 10:08:46 -0500
commitf046ccd15c8bc9613bfd72916b761a127d36e5c6 (patch)
tree40b48bdc1fff75c661cab5c4806a322a67e9dc44 /cpu/mpc83xx
parent63be111e72371b6edc6d02134dd785abb6be188c (diff)
downloadu-boot-imx-f046ccd15c8bc9613bfd72916b761a127d36e5c6.zip
u-boot-imx-f046ccd15c8bc9613bfd72916b761a127d36e5c6.tar.gz
u-boot-imx-f046ccd15c8bc9613bfd72916b761a127d36e5c6.tar.bz2
* Patch by Eran Liberty
Add support for the Freescale MPC8349ADS board.
Diffstat (limited to 'cpu/mpc83xx')
-rw-r--r--cpu/mpc83xx/Makefile53
-rw-r--r--cpu/mpc83xx/config.mk26
-rw-r--r--cpu/mpc83xx/cpu.c145
-rw-r--r--cpu/mpc83xx/cpu_init.c164
-rw-r--r--cpu/mpc83xx/i2c.c251
-rw-r--r--cpu/mpc83xx/interrupts.c94
-rw-r--r--cpu/mpc83xx/pci.c253
-rw-r--r--cpu/mpc83xx/resetvec.S6
-rw-r--r--cpu/mpc83xx/spd_sdram.c413
-rw-r--r--cpu/mpc83xx/speed.c424
-rw-r--r--cpu/mpc83xx/start.S1096
-rw-r--r--cpu/mpc83xx/traps.c274
12 files changed, 3199 insertions, 0 deletions
diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile
new file mode 100644
index 0000000..14574f4
--- /dev/null
+++ b/cpu/mpc83xx/Makefile
@@ -0,0 +1,53 @@
+#
+# 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 = lib$(CPU).a
+
+START = start.o \
+ resetvec.o
+
+COBJS = traps.o \
+ cpu.o \
+ cpu_init.o \
+ speed.o \
+ interrupts.o \
+ pci.o \
+ i2c.o \
+ spd_sdram.o
+
+OBJS = $(COBJS)
+
+all: .depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend: Makefile $(START:.o=.S) $(AOBJS:.o=.S) $(COBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(START:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/mpc83xx/config.mk b/cpu/mpc83xx/config.mk
new file mode 100644
index 0000000..8b4ff92
--- /dev/null
+++ b/cpu/mpc83xx/config.mk
@@ -0,0 +1,26 @@
+#
+# 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 -ffixed-r14 -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC83XX -DCONFIG_E300 \
+ -ffixed-r2 -ffixed-r29 -msoft-float
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c
new file mode 100644
index 0000000..73d125a
--- /dev/null
+++ b/cpu/mpc83xx/cpu.c
@@ -0,0 +1,145 @@
+/*
+ * 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
+ *
+ * Change log:
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+/*
+ * 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>
+
+
+int checkcpu(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ ulong clock = gd->cpu_clk;
+ u32 pvr = get_pvr();
+ char buf[32];
+
+ if ((pvr & 0xFFFF0000) != PVR_83xx) {
+ puts("Not MPC83xx Family!!!\n");
+ return -1;
+ }
+
+ puts("CPU: MPC83xx, ");
+ switch(pvr) {
+ case PVR_8349_REV10:
+ break;
+ case PVR_8349_REV11:
+ break;
+ default:
+ puts("Rev: Unknown\n");
+ return -1; /* Not sure what this is */
+ }
+ printf("Rev: %02x at %s MHz\n",pvr & 0x0000FFFF, strmhz(buf, clock));
+ return 0;
+}
+
+
+void upmconfig (uint upm, uint *table, uint size)
+{
+ hang(); /* FIXME: upconfig() needed? */
+}
+
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong msr, addr;
+
+ volatile immap_t *immap = (immap_t *) CFG_IMMRBAR;
+
+#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;
+
+ /* confirm Reset Control Reg is enabled */
+ while(!((immap->reset.rcer) & RCER_CRE));
+
+ printf("Resetting the board.");
+ printf("\n");
+
+ udelay(200);
+
+ /* perform reset, only one bit */
+ immap->reset.rcr = RCR_SWHR;
+#else
+ 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 = CFG_RESET_ADDRESS;
+
+ printf("resetting the board.");
+ printf("\n");
+ ((void (*)(void)) addr) ();
+#endif
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+
+unsigned long get_tbclk(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return tbclk;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ hang(); /* FIXME: implement watchdog_reset()? */
+}
+#endif /* CONFIG_WATCHDOG */
diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c
new file mode 100644
index 0000000..7e80ced
--- /dev/null
+++ b/cpu/mpc83xx/cpu_init.c
@@ -0,0 +1,164 @@
+/*
+ * 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
+ *
+ * Change log:
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <ioports.h>
+
+/*
+ * 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)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* RSR - Reset Status Register - clear all status (4.6.1.3) */
+ gd->reset_status = im->reset.rsr;
+ im->reset.rsr = ~(RSR_RES);
+
+ /*
+ * RMR - Reset Mode Register
+ * contains checkstop reset enable (4.6.1.4)
+ */
+ im->reset.rmr = (RMR_CSRE & (1<<RMR_CSRE_SHIFT));
+
+ /* LCRR - Clock Ratio Register (10.3.1.16) */
+ im->lbus.lcrr = CFG_LCRR;
+
+ /* Enable Time Base & Decrimenter ( so we will have udelay() )*/
+ im->sysconf.spcr |= SPCR_TBEN;
+
+ /* System General Purpose Register */
+ im->sysconf.sicrh = SICRH_TSOBI1;
+ im->sysconf.sicrl = SICRL_LDP_A;
+
+ /*
+ * 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(CFG_BR0_PRELIM) \
+ && defined(CFG_OR0_PRELIM) \
+ && defined(CFG_LBLAWBAR0_PRELIM) \
+ && defined(CFG_LBLAWAR0_PRELIM)
+ im->lbus.bank[0].br = CFG_BR0_PRELIM;
+ im->lbus.bank[0].or = CFG_OR0_PRELIM;
+ im->sysconf.lblaw[0].bar = CFG_LBLAWBAR0_PRELIM;
+ im->sysconf.lblaw[0].ar = CFG_LBLAWAR0_PRELIM;
+#else
+#error CFG_BR0_PRELIM, CFG_OR0_PRELIM, CFG_LBLAWBAR0_PRELIM & CFG_LBLAWAR0_PRELIM must be defined
+#endif
+
+#if defined(CFG_BR1_PRELIM) \
+ && defined(CFG_OR1_PRELIM) \
+ && defined(CFG_LBLAWBAR1_PRELIM) \
+ && defined(CFG_LBLAWAR1_PRELIM)
+ im->lbus.bank[1].br = CFG_BR1_PRELIM;
+ im->lbus.bank[1].or = CFG_OR1_PRELIM;
+ im->sysconf.lblaw[1].bar = CFG_LBLAWBAR1_PRELIM;
+ im->sysconf.lblaw[1].ar = CFG_LBLAWAR1_PRELIM;
+#endif
+#if defined(CFG_BR2_PRELIM) \
+ && defined(CFG_OR2_PRELIM) \
+ && defined(CFG_LBLAWBAR2_PRELIM) \
+ && defined(CFG_LBLAWAR2_PRELIM)
+ im->lbus.bank[2].br = CFG_BR2_PRELIM;
+ im->lbus.bank[2].or = CFG_OR2_PRELIM;
+ im->sysconf.lblaw[2].bar = CFG_LBLAWBAR2_PRELIM;
+ im->sysconf.lblaw[2].ar = CFG_LBLAWAR2_PRELIM;
+#endif
+#if defined(CFG_BR3_PRELIM) \
+ && defined(CFG_OR3_PRELIM) \
+ && defined(CFG_LBLAWBAR3_PRELIM) \
+ && defined(CFG_LBLAWAR3_PRELIM)
+ im->lbus.bank[3].br = CFG_BR3_PRELIM;
+ im->lbus.bank[3].or = CFG_OR3_PRELIM;
+ im->sysconf.lblaw[3].bar = CFG_LBLAWBAR3_PRELIM;
+ im->sysconf.lblaw[3].ar = CFG_LBLAWAR3_PRELIM;
+#endif
+#if defined(CFG_BR4_PRELIM) \
+ && defined(CFG_OR4_PRELIM) \
+ && defined(CFG_LBLAWBAR4_PRELIM) \
+ && defined(CFG_LBLAWAR4_PRELIM)
+ im->lbus.bank[4].br = CFG_BR4_PRELIM;
+ im->lbus.bank[4].or = CFG_OR4_PRELIM;
+ im->sysconf.lblaw[4].bar = CFG_LBLAWBAR4_PRELIM;
+ im->sysconf.lblaw[4].ar = CFG_LBLAWAR4_PRELIM;
+#endif
+#if defined(CFG_BR5_PRELIM) \
+ && defined(CFG_OR5_PRELIM) \
+ && defined(CFG_LBLAWBAR5_PRELIM) \
+ && defined(CFG_LBLAWAR5_PRELIM)
+ im->lbus.bank[5].br = CFG_BR5_PRELIM;
+ im->lbus.bank[5].or = CFG_OR5_PRELIM;
+ im->sysconf.lblaw[5].bar = CFG_LBLAWBAR5_PRELIM;
+ im->sysconf.lblaw[5].ar = CFG_LBLAWAR5_PRELIM;
+#endif
+#if defined(CFG_BR6_PRELIM) \
+ && defined(CFG_OR6_PRELIM) \
+ && defined(CFG_LBLAWBAR6_PRELIM) \
+ && defined(CFG_LBLAWAR6_PRELIM)
+ im->lbus.bank[6].br = CFG_BR6_PRELIM;
+ im->lbus.bank[6].or = CFG_OR6_PRELIM;
+ im->sysconf.lblaw[6].bar = CFG_LBLAWBAR6_PRELIM;
+ im->sysconf.lblaw[6].ar = CFG_LBLAWAR6_PRELIM;
+#endif
+#if defined(CFG_BR7_PRELIM) \
+ && defined(CFG_OR7_PRELIM) \
+ && defined(CFG_LBLAWBAR7_PRELIM) \
+ && defined(CFG_LBLAWAR7_PRELIM)
+ im->lbus.bank[7].br = CFG_BR7_PRELIM;
+ im->lbus.bank[7].or = CFG_OR7_PRELIM;
+ im->sysconf.lblaw[7].bar = CFG_LBLAWBAR7_PRELIM;
+ im->sysconf.lblaw[7].ar = CFG_LBLAWAR7_PRELIM;
+#endif
+}
+
+
+/*
+ * Initialize higher level parts of CPU like time base and timers.
+ */
+
+int cpu_init_r (void)
+{
+ return 0;
+}
+
diff --git a/cpu/mpc83xx/i2c.c b/cpu/mpc83xx/i2c.c
new file mode 100644
index 0000000..3db7d2c
--- /dev/null
+++ b/cpu/mpc83xx/i2c.c
@@ -0,0 +1,251 @@
+/*
+ * (C) Copyright 2003,Motorola Inc.
+ * Xianghua Xiao <x.xiao@motorola.com>
+ * Adapted for Motorola 85xx chip.
+ *
+ * (C) Copyright 2003
+ * Gleb Natapov <gnatapov@mrv.com>
+ * Some bits are taken from linux driver writen by adrian@humboldt.co.uk
+ *
+ * Hardware I2C driver for MPC107 PCI bridge.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Change log:
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_HARD_I2C
+#include <i2c.h>
+#include <asm/i2c.h>
+
+#ifdef CONFIG_MPC8349ADS
+i2c_t * mpc8349_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET);
+#endif
+
+void
+i2c_init(int speed, int slaveadd)
+{
+ /* stop I2C controller */
+ writeb(0x00 , &I2C->cr);
+
+ /* set clock */
+ writeb(0x3f, &I2C->fdr);
+
+ /* set default filter */
+ writeb(0x10,&I2C->dfsrr);
+
+ /* write slave address */
+ writeb(slaveadd, &I2C->adr);
+
+ /* clear status register */
+ writeb(0x00, &I2C->sr);
+
+ /* start I2C controller */
+ writeb(I2C_CR_MEN, &I2C->cr);
+}
+
+static __inline__ int
+i2c_wait4bus (void)
+{
+ ulong timeval = get_timer (0);
+ while (readb(&I2C->sr) & I2C_SR_MBB) {
+ if (get_timer (timeval) > I2C_TIMEOUT) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static __inline__ int
+i2c_wait (int write)
+{
+ u32 csr;
+ ulong timeval = get_timer(0);
+ do {
+ csr = readb(&I2C->sr);
+
+ if (!(csr & I2C_SR_MIF))
+ continue;
+
+ writeb(0x0, &I2C->sr);
+
+ if (csr & I2C_SR_MAL) {
+ debug("i2c_wait: MAL\n");
+ return -1;
+ }
+
+ if (!(csr & I2C_SR_MCF)) {
+ debug("i2c_wait: unfinished\n");
+ return -1;
+ }
+
+ if (write == I2C_WRITE && (csr & I2C_SR_RXAK)) {
+ debug("i2c_wait: No RXACK\n");
+ return -1;
+ }
+
+ return 0;
+ } while (get_timer (timeval) < I2C_TIMEOUT);
+ debug("i2c_wait: timed out\n");
+}
+
+static __inline__ int
+i2c_write_addr (u8 dev, u8 dir, int rsta)
+{
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX |
+ (rsta?I2C_CR_RSTA:0),
+ &I2C->cr);
+
+ writeb((dev << 1) | dir, &I2C->dr);
+
+ if (i2c_wait (I2C_WRITE) < 0)
+ return 0;
+ return 1;
+}
+
+static __inline__ int
+__i2c_write (u8 *data, int length)
+{
+ int i;
+
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
+ &I2C->cr);
+
+ for (i=0; i < length; i++) {
+ writeb(data[i], &I2C->dr);
+
+ if (i2c_wait (I2C_WRITE) < 0)
+ break;
+ }
+ return i;
+}
+
+static __inline__ int
+__i2c_read (u8 *data, int length)
+{
+ int i;
+
+ writeb(I2C_CR_MEN | I2C_CR_MSTA |
+ ((length == 1) ? I2C_CR_TXAK : 0),
+ &I2C->cr);
+
+ /* dummy read */
+ readb(&I2C->dr);
+
+ for (i=0; i < length; i++) {
+ if (i2c_wait (I2C_READ) < 0)
+ break;
+
+ /* Generate ack on last next to last byte */
+ if (i == length - 2)
+ writeb(I2C_CR_MEN | I2C_CR_MSTA |
+ I2C_CR_TXAK,
+ &I2C->cr);
+
+ /* Generate stop on last byte */
+ if (i == length - 1)
+ writeb(I2C_CR_MEN | I2C_CR_TXAK, &I2C->cr);
+
+ data[i] = readb(&I2C->dr);
+ }
+ return i;
+}
+
+int
+i2c_read (u8 dev, uint addr, int alen, u8 *data, int length)
+{
+ int i = 0;
+ u8 *a = (u8*)&addr;
+
+ if (i2c_wait4bus () < 0)
+ goto exit;
+
+ if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
+ goto exit;
+
+ if (__i2c_write (&a[4 - alen], alen) != alen)
+ goto exit;
+
+ if (i2c_write_addr (dev, I2C_READ, 1) == 0)
+ goto exit;
+
+ i = __i2c_read (data, length);
+
+ exit:
+ writeb(I2C_CR_MEN, &I2C->cr);
+ return !(i == length);
+}
+
+int
+i2c_write (u8 dev, uint addr, int alen, u8 *data, int length)
+{
+ int i = 0;
+ u8 *a = (u8*)&addr;
+
+ if (i2c_wait4bus () < 0)
+ goto exit;
+
+ if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
+ goto exit;
+
+ if (__i2c_write (&a[4 - alen], alen) != alen)
+ goto exit;
+
+ i = __i2c_write (data, length);
+
+ exit:
+ writeb(I2C_CR_MEN, &I2C->cr);
+ return !(i == length);
+}
+
+int i2c_probe (uchar chip)
+{
+ int tmp;
+
+ /*
+ * Try to read the first location of the chip. The underlying
+ * driver doesn't appear to support sending just the chip address
+ * and looking for an <ACK> back.
+ */
+ udelay(10000);
+ return i2c_read (chip, 0, 1, (char *)&tmp, 1);
+}
+
+uchar i2c_reg_read (uchar i2c_addr, uchar reg)
+{
+ char buf[1];
+
+ i2c_read (i2c_addr, reg, 1, buf, 1);
+
+ return (buf[0]);
+}
+
+void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
+{
+ i2c_write (i2c_addr, reg, 1, &val, 1);
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/cpu/mpc83xx/interrupts.c b/cpu/mpc83xx/interrupts.c
new file mode 100644
index 0000000..53474f6
--- /dev/null
+++ b/cpu/mpc83xx/interrupts.c
@@ -0,0 +1,94 @@
+/*
+ * (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
+ *
+ * Change log:
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ 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 (CONFIG_COMMANDS & CFG_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 /* CONFIG_COMMANDS & CFG_CMD_IRQ */
diff --git a/cpu/mpc83xx/pci.c b/cpu/mpc83xx/pci.c
new file mode 100644
index 0000000..d9daa3e
--- /dev/null
+++ b/cpu/mpc83xx/pci.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Copyright (C) 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
+ *
+ * Change log:
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+/*
+ * PCI Configuration space access support for MPC85xx PCI Bridge
+ */
+#include <asm/mmu.h>
+#include <asm/io.h>
+#include <common.h>
+#include <pci.h>
+
+#ifdef CONFIG_MPC8349ADS
+#include <asm/i2c.h>
+#endif
+
+#if defined(CONFIG_PCI)
+
+void
+pci_mpc83xx_init(volatile struct pci_controller *hose)
+{
+ volatile immap_t * immr;
+ volatile clk8349_t * clk;
+ volatile law8349_t * pci_law;
+ volatile pot8349_t * pci_pot;
+ volatile pcictrl8349_t * pci_ctrl;
+ volatile pciconf8349_t * pci_conf;
+
+ u8 val8,tmp8,ret;
+ u16 reg16,tmp16;
+ u32 val32,tmp32;
+
+ immr = (immap_t *)CFG_IMMRBAR;
+ clk = (clk8349_t *)&immr->clk;
+ pci_law = immr->sysconf.pcilaw;
+ pci_pot = immr->ios.pot;
+ pci_ctrl = immr->pci_ctrl;
+ pci_conf = immr->pci_conf;
+
+ /*
+ * Configure PCI controller and PCI_CLK_OUTPUT both in 66M mode
+ */
+ val32 = clk->occr;
+ udelay(2000);
+ clk->occr = 0xff000000;
+ udelay(2000);
+
+ /*
+ * Configure PCI Local Access Windows
+ */
+ pci_law[0].bar = CFG_PCI1_MEM_PHYS & LAWBAR_BAR;
+ pci_law[0].ar = LAWAR_EN | LAWAR_SIZE_1G;
+ pci_law[1].bar = CFG_PCI1_IO_PHYS & LAWBAR_BAR;
+ pci_law[1].ar = LAWAR_EN | LAWAR_SIZE_32M;
+
+ /*
+ * Configure PCI Outbound Translation Windows
+ */
+ pci_pot[0].potar = (CFG_PCI1_MEM_BASE >> 12) & POTAR_TA_MASK;
+ pci_pot[0].pobar = (CFG_PCI1_MEM_PHYS >> 12) & POBAR_BA_MASK;
+ pci_pot[0].pocmr = POCMR_EN | (POCMR_CM_512M & POCMR_CM_MASK);
+
+ /* mapped to PCI1 IO space 0x0 to local 0xe2000000 */
+ pci_pot[1].potar = (CFG_PCI1_IO_BASE >> 12) & POTAR_TA_MASK;
+ pci_pot[1].pobar = (CFG_PCI1_IO_PHYS >> 12) & POBAR_BA_MASK;
+ pci_pot[1].pocmr = POCMR_EN | POCMR_IO | (POCMR_CM_16M & POCMR_CM_MASK);
+//#if defined(CONFIG_PCI_2)
+ pci_pot[3].potar = (CFG_PCI2_MEM_BASE >> 12) & POTAR_TA_MASK;
+ pci_pot[3].pobar = (CFG_PCI2_MEM_PHYS >> 12) & POBAR_BA_MASK;
+ pci_pot[3].pocmr = POCMR_EN | POCMR_DST | (POCMR_CM_512M & POCMR_CM_MASK);
+
+ /* mapped to PCI2 IO space 0x0 to local 0xe3000000 */
+ pci_pot[4].potar = (CFG_PCI2_IO_BASE >> 12) & POTAR_TA_MASK;
+ pci_pot[4].pobar = (CFG_PCI2_IO_PHYS >> 12) & POBAR_BA_MASK;
+ pci_pot[4].pocmr = POCMR_EN | POCMR_DST | POCMR_IO | (POCMR_CM_16M & POCMR_CM_MASK);
+//#endif
+
+ /*
+ * Configure PCI Inbound Translation Windows
+ */
+ pci_ctrl[0].pitar1 = 0x0;
+ pci_ctrl[0].pibar1 = 0x0;
+ pci_ctrl[0].piebar1 = 0x0;
+ pci_ctrl[0].piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+
+ pci_ctrl[1].pitar1 = 0x0;
+ pci_ctrl[1].pibar1 = 0x0;
+ pci_ctrl[1].piebar1 = 0x0;
+ pci_ctrl[1].piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+ /*
+ * Assign PIB PMC slot to desired PCI bus
+ */
+#ifdef CONFIG_MPC8349ADS
+ mpc8349_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C2_OFFSET);
+ i2c_init(CFG_I2C_SPEED,CFG_I2C_SLAVE);
+#endif
+ val8 = 0;
+ ret = i2c_write(0x23,0x6,1,&val8,1);
+ ret = i2c_write(0x23,0x7,1,&val8,1);
+ val8 = 0xff;
+ ret = i2c_write(0x23,0x2,1,&val8,1);
+ ret = i2c_write(0x23,0x3,1,&val8,1);
+
+ val8 = 0;
+ ret = i2c_write(0x26,0x6,1,&val8,1);
+ val8 = 0x34;
+ ret = i2c_write(0x26,0x7,1,&val8,1);
+#if defined(PCI_64BIT)
+ val8 = 0xf4; // PMC2<->PCI1 64bit
+#elif defined(PCI_ALL_PCI1)
+ val8 = 0xf3; // PMC1<->PCI1,PMC2<->PCI1,PMC3<->PCI1 32bit
+#elif defined(PCI_ONE_PCI1)
+ val8 = 0xf9; // PMC1<->PCI1,PMC2<->PCI2,PMC3<->PCI2 32bit
+#elif defined(PCI_TWO_PCI1)
+ val8 = 0xf5; // PMC1<->PCI1,PMC2<->PCI1,PMC3<->PCI2 32bit
+#else
+ val8 = 0xf5;
+#endif
+ ret = i2c_write(0x26,0x2,1,&val8,1);
+ val8 = 0xff;
+ ret = i2c_write(0x26,0x3,1,&val8,1);
+ val8 = 0;
+ ret = i2c_write(0x27,0x6,1,&val8,1);
+ ret = i2c_write(0x27,0x7,1,&val8,1);
+ val8 = 0xff;
+ ret = i2c_write(0x27,0x2,1,&val8,1);
+ val8 = 0xef;
+ ret = i2c_write(0x27,0x3,1,&val8,1);
+ asm("eieio");
+
+ /*
+ * Release PCI RST Output signal
+ */
+ udelay(2000);
+ pci_ctrl[0].gcr = 1;
+#ifndef PCI_64BIT
+ pci_ctrl[1].gcr = 1;
+#endif
+ udelay(2000);
+
+ hose[0].first_busno = 0;
+ hose[0].last_busno = 0xff;
+
+ pci_set_region(hose[0].regions + 0,
+ CFG_PCI1_MEM_BASE,
+ CFG_PCI1_MEM_PHYS,
+ CFG_PCI1_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ pci_set_region(hose[0].regions + 1,
+ CFG_PCI1_IO_BASE,
+ CFG_PCI1_IO_PHYS,
+ CFG_PCI1_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose[0].region_count = 2;
+
+ pci_setup_indirect(&hose[0],
+ (CFG_IMMRBAR+0x8300),
+ (CFG_IMMRBAR+0x8304));
+#define PCI_CLASS_BRIDGE 0x06
+ reg16 = 0xff;
+ tmp32 = 0xffff;
+ pci_hose_write_config_byte(&hose[0],PCI_BDF(0,0,0),PCI_CLASS_CODE,PCI_CLASS_BRIDGE);
+
+ pci_hose_read_config_word (&hose[0],PCI_BDF(0,0,0),PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(&hose[0],PCI_BDF(0,0,0), PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(&hose[0],PCI_BDF(0,0,0), PCI_STATUS, 0xffff);
+ pci_hose_write_config_byte(&hose[0],PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80);
+#ifndef PCI_64BIT
+ hose[1].first_busno = 0;
+ hose[1].last_busno = 0xff;
+
+ pci_set_region(hose[1].regions + 0,
+ CFG_PCI2_MEM_BASE,
+ CFG_PCI2_MEM_PHYS,
+ CFG_PCI2_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ pci_set_region(hose[1].regions + 1,
+ CFG_PCI2_IO_BASE,
+ CFG_PCI2_IO_PHYS,
+ CFG_PCI2_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose[1].region_count = 2;
+
+ pci_setup_indirect(&hose[1],
+ (CFG_IMMRBAR+0x8380),
+ (CFG_IMMRBAR+0x8384));
+
+ pci_hose_write_config_byte(&hose[1],PCI_BDF(0,0,0),PCI_CLASS_CODE,PCI_CLASS_BRIDGE);
+ pci_hose_read_config_word (&hose[1],PCI_BDF(0,0,0), PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(&hose[1],PCI_BDF(0,0,0), PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(&hose[1],PCI_BDF(0,0,0), PCI_STATUS, 0xffff);
+ pci_hose_write_config_byte(&hose[1],PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80);
+#endif
+
+#if defined(PCI_64BIT)
+ printf("PCI1 64bit on PMC2\n");
+#elif defined(PCI_ALL_PCI1)
+ printf("PCI1 32bit on PMC1 & PMC2 & PMC3\n");
+#elif defined(PCI_ONE_PCI1)
+ printf("PCI1 32bit on PMC1,PCI2 32bit on PMC2 & PMC3\n");
+#else
+ printf("PCI1 32bit on PMC1 & PMC2 & PMC3 in default\n");
+#endif
+
+#if 1
+ /*
+ * Hose scan.
+ */
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+#endif
+}
+
+#endif /* CONFIG_PCI */
diff --git a/cpu/mpc83xx/resetvec.S b/cpu/mpc83xx/resetvec.S
new file mode 100644
index 0000000..7593e73
--- /dev/null
+++ b/cpu/mpc83xx/resetvec.S
@@ -0,0 +1,6 @@
+ .section .resetvec,"ax"
+#ifndef FIXME
+#if 0
+ b _start_e500
+#endif
+#endif
diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c
new file mode 100644
index 0000000..5bd112c
--- /dev/null
+++ b/cpu/mpc83xx/spd_sdram.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Change log:
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <i2c.h>
+#include <spd.h>
+#include <asm/mmu.h>
+#include <spd_sdram.h>
+
+#ifdef CONFIG_SPD_EEPROM
+
+
+#if defined(CONFIG_DDR_ECC)
+extern void dma_init(void);
+extern uint dma_check(void);
+extern int dma_xfer(void *dest, uint count, void *src);
+#endif
+
+
+#ifndef CFG_READ_SPD
+#define CFG_READ_SPD i2c_read
+#endif
+
+
+
+/*
+ * Convert picoseconds into clock cycles (rounding up if needed).
+ */
+
+int
+picos_to_clk(int picos)
+{
+ int clks;
+
+ clks = picos / (2000000000 / (get_bus_freq(0) / 1000));
+ if (picos % (2000000000 / (get_bus_freq(0) / 1000)) != 0) {
+ clks++;
+ }
+
+ return clks;
+}
+
+
+unsigned int
+banksize(unsigned char row_dens)
+{
+ return ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24;
+}
+
+
+long int spd_sdram(int(read_spd)(uint addr))
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
+ volatile ddr8349_t *ddr = &immap->ddr;
+ volatile law8349_t *ecm = &immap->sysconf.ddrlaw[0];
+ spd_eeprom_t spd;
+ unsigned tmp, tmp1;
+ unsigned int memsize;
+ unsigned int law_size;
+ unsigned char caslat;
+ unsigned int trfc, trfc_clk, trfc_low;
+
+#warning Current spd_sdram does not fit its usage... adjust implementation or API...
+
+ CFG_READ_SPD(SPD_EEPROM_ADDRESS, 0, 1, (uchar *) & spd, sizeof (spd));
+
+ if (spd.nrows > 2) {
+ puts("DDR:Only two chip selects are supported on ADS.\n");
+ return 0;
+ }
+
+ if (spd.nrow_addr < 12
+ || spd.nrow_addr > 14
+ || spd.ncol_addr < 8
+ || spd.ncol_addr > 11) {
+ puts("DDR:Row or Col number unsupported.\n");
+ return 0;
+ }
+
+ ddr->csbnds[2].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+ ddr->cs_config[2] = ( 1 << 31
+ | (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 (spd.nrows == 2) {
+ ddr->csbnds[3].csbnds = ( (banksize(spd.row_dens) >> 8)
+ | ((banksize(spd.row_dens) >> 23) - 1) );
+ ddr->cs_config[3] = ( 1<<31
+ | (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]);
+ }
+
+ if (spd.mem_type != 0x07) {
+ puts("No DDR module found!\n");
+ return 0;
+ }
+
+ /*
+ * Figure out memory size in Megabytes.
+ */
+ memsize = spd.nrows * 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 = ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff);
+ 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
+ */
+ if(spd.cas_lat & 0x40) {
+ caslat = 7;
+ } else if (spd.cas_lat & 0x20) {
+ caslat = 6;
+ } else if (spd.cas_lat & 0x10) {
+ caslat = 5;
+ } else if (spd.cas_lat & 0x08) {
+ caslat = 4;
+ } else if (spd.cas_lat & 0x04) {
+ caslat = 3;
+ } else if (spd.cas_lat & 0x02) {
+ caslat = 2;
+ } else if (spd.cas_lat & 0x01) {
+ caslat = 1;
+ } else {
+ puts("DDR:no valid CAS Latency information.\n");
+ return 0;
+ }
+
+ tmp = 20000 / (((spd.clk_cycle & 0xF0) >> 4) * 10
+ + (spd.clk_cycle & 0x0f));
+ debug("DDR:Module maximum data rate is: %dMhz\n", tmp);
+
+ tmp1 = get_bus_freq(0) / 1000000;
+ if (tmp1 < 230 && tmp1 >= 90 && tmp >= 230) {
+ /* 90~230 range, treated as DDR 200 */
+ if (spd.clk_cycle3 == 0xa0)
+ caslat -= 2;
+ else if(spd.clk_cycle2 == 0xa0)
+ caslat--;
+ } else if (tmp1 < 280 && tmp1 >= 230 && tmp >= 280) {
+ /* 230-280 range, treated as DDR 266 */
+ if (spd.clk_cycle3 == 0x75)
+ caslat -= 2;
+ else if (spd.clk_cycle2 == 0x75)
+ caslat--;
+ } else if (tmp1 < 350 && tmp1 >= 280 && tmp >= 350) {
+ /* 280~350 range, treated as DDR 333 */
+ if (spd.clk_cycle3 == 0x60)
+ caslat -= 2;
+ else if (spd.clk_cycle2 == 0x60)
+ caslat--;
+ } else if (tmp1 < 90 || tmp1 >= 350) {
+ /* DDR rate out-of-range */
+ puts("DDR:platform frequency is not fit for DDR rate\n");
+ return 0;
+ }
+
+ /*
+ * note: caslat must also be programmed into ddr->sdram_mode
+ * register.
+ *
+ * note: WRREC(Twr) and WRTORD(Twtr) are not in SPD,
+ * use conservative value here.
+ */
+ trfc = spd.trfc * 1000; /* up to ps */
+ trfc_clk = picos_to_clk(trfc);
+ trfc_low = (trfc_clk - 8) & 0xf;
+
+ ddr->timing_cfg_1 =
+ (((picos_to_clk(spd.trp * 250) & 0x07) << 28 ) |
+ ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24 ) |
+ ((picos_to_clk(spd.trcd * 250) & 0x07) << 20 ) |
+ ((caslat & 0x07) << 16 ) |
+ (trfc_low << 12 ) |
+ ( 0x300 ) |
+ ((picos_to_clk(spd.trrd * 250) & 0x07) << 4) | 1);
+
+ ddr->timing_cfg_2 = 0x00000800;
+
+ debug("DDR:timing_cfg_1=0x%08x\n", ddr->timing_cfg_1);
+ debug("DDR:timing_cfg_2=0x%08x\n", ddr->timing_cfg_2);
+
+ /*
+ * Only DDR I is supported
+ * DDR I and II have different mode-register-set definition
+ */
+
+ /* burst length is always 4 */
+ switch(caslat) {
+ case 2:
+ ddr->sdram_mode = 0x52; /* 1.5 */
+ break;
+ case 3:
+ ddr->sdram_mode = 0x22; /* 2.0 */
+ break;
+ case 4:
+ ddr->sdram_mode = 0x62; /* 2.5 */
+ break;
+ case 5:
+ ddr->sdram_mode = 0x32; /* 3.0 */
+ break;
+ default:
+ puts("DDR:only CAS Latency 1.5, 2.0, 2.5, 3.0 is supported.\n");
+ return 0;
+ }
+ debug("DDR:sdram_mode=0x%08x\n", ddr->sdram_mode);
+
+ switch(spd.refresh) {
+ case 0x00:
+ case 0x80:
+ tmp = picos_to_clk(15625000);
+ break;
+ case 0x01:
+ case 0x81:
+ tmp = picos_to_clk(3900000);
+ break;
+ case 0x02:
+ case 0x82:
+ tmp = picos_to_clk(7800000);
+ break;
+ case 0x03:
+ case 0x83:
+ tmp = picos_to_clk(31300000);
+ break;
+ case 0x04:
+ case 0x84:
+ tmp = picos_to_clk(62500000);
+ break;
+ case 0x05:
+ case 0x85:
+ tmp = picos_to_clk(125000000);
+ break;
+ default:
+ tmp = 0x512;
+ break;
+ }
+
+ /*
+ * Set BSTOPRE to 0x100 for page mode
+ * If auto-charge is used, set BSTOPRE = 0
+ */
+ ddr->sdram_interval = ((tmp & 0x3fff) << 16) | 0x100;
+ debug("DDR:sdram_interval=0x%08x\n", ddr->sdram_interval);
+
+ /*
+ * Is this an ECC DDR chip?
+ */
+#if defined(CONFIG_DDR_ECC)
+ if (spd.config == 0x02) {
+ ddr->err_disable = 0x0000000d;
+ ddr->err_sbe = 0x00ff0000;
+ }
+ debug("DDR:err_disable=0x%08x\n", ddr->err_disable);
+ debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe);
+#endif
+ asm("sync;isync");
+
+ udelay(500);
+
+
+ ddr->sdram_clk_cntl = 0x82000000;/*SS_EN=1, CLK_ADJST = 2-MCK/MCK_B, is lauched 1/2 of one SDRAM clock cycle after address/command*/
+
+
+ /*
+ * Figure out the settings for the sdram_cfg register. Build up
+ * the entire register in 'tmp' 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[6:7] = 2 (SDRAM type = DDR SDRAM)
+ */
+ tmp = 0xc2000000;
+
+ /*
+ * sdram_cfg[3] = RD_EN - registered DIMM enable
+ * A value of 0x26 indicates micron registered DIMMS (micron.com)
+ */
+ if (spd.mod_attr == 0x26) {
+ tmp |= 0x10000000;
+ }
+
+#if defined(CONFIG_DDR_ECC)
+ /*
+ * If the user wanted ECC (enabled via sdram_cfg[2])
+ */
+ if (spd.config == 0x02) {
+ tmp |= 0x20000000;
+ }
+#endif
+
+#if defined(CONFIG_DDR_2T_TIMING)
+ /*
+ * Enable 2T timing by setting sdram_cfg[16].
+ */
+ tmp |= SDRAM_CFG_2T_EN;
+#endif
+
+ ddr->sdram_cfg = tmp;
+
+ 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)
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+
+void
+ddr_enable_ecc(unsigned int dram_size)
+{
+#ifndef FIXME
+ uint *p = 0;
+ uint i = 0;
+ volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
+ volatile ccsr_ddr_t *ddr= &immap->im_ddr;
+
+ dma_init();
+
+ for (*p = 0; p < (uint *)(8 * 1024); p++) {
+ if (((unsigned int)p & 0x1f) == 0) {
+ ppcDcbz((unsigned long) p);
+ }
+ *p = (unsigned int)0xdeadbeef;
+ if (((unsigned int)p & 0x1c) == 0x1c) {
+ ppcDcbf((unsigned long) p);
+ }
+ }
+
+ /* 8K */
+ dma_xfer((uint *)0x2000, 0x2000, (uint *)0);
+ /* 16K */
+ dma_xfer((uint *)0x4000, 0x4000, (uint *)0);
+ /* 32K */
+ dma_xfer((uint *)0x8000, 0x8000, (uint *)0);
+ /* 64K */
+ dma_xfer((uint *)0x10000, 0x10000, (uint *)0);
+ /* 128k */
+ dma_xfer((uint *)0x20000, 0x20000, (uint *)0);
+ /* 256k */
+ dma_xfer((uint *)0x40000, 0x40000, (uint *)0);
+ /* 512k */
+ dma_xfer((uint *)0x80000, 0x80000, (uint *)0);
+ /* 1M */
+ dma_xfer((uint *)0x100000, 0x100000, (uint *)0);
+ /* 2M */
+ dma_xfer((uint *)0x200000, 0x200000, (uint *)0);
+ /* 4M */
+ dma_xfer((uint *)0x400000, 0x400000, (uint *)0);
+
+ for (i = 1; i < dram_size / 0x800000; i++) {
+ dma_xfer((uint *)(0x800000*i), 0x800000, (uint *)0);
+ }
+
+ /*
+ * Enable errors for ECC.
+ */
+ ddr->err_disable = 0x00000000;
+ asm("sync;isync");
+#endif
+}
+
+#endif /* CONFIG_DDR_ECC */
diff --git a/cpu/mpc83xx/speed.c b/cpu/mpc83xx/speed.c
new file mode 100644
index 0000000..6530fbf
--- /dev/null
+++ b/cpu/mpc83xx/speed.c
@@ -0,0 +1,424 @@
+/*
+ * (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
+ *
+ * Change log:
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+
+/* ----------------------------------------------------------------- */
+
+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)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ volatile immap_t *im = (immap_t *)CFG_IMMRBAR;
+ u32 pci_sync_in;
+ u8 spmf;
+ u8 clkin_div;
+ u32 sccr;
+ u32 corecnf_tab_index;
+ u8 corepll;
+ u32 lcrr;
+
+ u32 csb_clk;
+ u32 tsec1_clk;
+ u32 tsec2_clk;
+ u32 core_clk;
+ u32 usbmph_clk;
+ u32 usbdr_clk;
+ u32 i2c_clk;
+ u32 enc_clk;
+ u32 lbiu_clk;
+ u32 lclk_clk;
+ u32 ddr_clk;
+
+ if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im)
+ return -1;
+
+#ifndef CFG_HRCW_HIGH
+# error "CFG_HRCW_HIGH must be defined in include/configs/MCP83XXADS.h"
+#endif /* CFG_HCWD_HIGH */
+
+#if (CFG_HRCW_HIGH & HRCWH_PCI_HOST)
+# ifndef CONFIG_83XX_CLKIN
+# error "In PCI Host Mode, CONFIG_83XX_CLKIN must be defined in include/configs/MCP83XXADS.h"
+# endif /* CONFIG_83XX_CLKIN */
+# ifdef CONFIG_83XX_PCICLK
+# warning "In PCI Host Mode, CONFIG_83XX_PCICLK in include/configs/MCP83XXADS.h is igonred."
+# endif /* CONFIG_83XX_PCICLK */
+/* PCI Host Mode */
+ if (!(im->reset.rcwh & RCWH_PCIHOST)) {
+ /* though RCWH_PCIHOST is defined in CFG_HRCW_HIGH the im->reset.rcwhr PCI Host Mode is disabled */
+ /* FIXME: findout if there is a way to issue some warning */
+ return -2;
+
+ }
+ if (im->clk.spmr & SPMR_CKID) {
+ pci_sync_in = CONFIG_83XX_CLKIN / 2; /* PCI Clock is half CONFIG_83XX_CLKIN */
+ }
+ else {
+ pci_sync_in = CONFIG_83XX_CLKIN;
+ }
+#else
+# ifdef CONFIG_83XX_CLKIN
+# warning "In PCI Agent Mode, CONFIG_83XX_CLKIN in include/configs/MCP83XXADS.h is igonred."
+# endif /* CONFIG_83XX_CLKIN */
+# ifndef CONFIG_83XX_PCICLK
+# error "In PCI Agent Mode, CONFIG_83XX_PCICLK must be defined in include/configs/MCP83XXADS.h"
+# endif /* CONFIG_83XX_PCICLK */
+/* PCI Agent Mode */
+ if (im->reset.rcwh & RCWH_PCIHOST) {
+ /* though RCWH_PCIHOST is not defined in CFG_HRCW_HIGH the im->reset.rcwhr PCI Host Mode is enabled */
+ return -3;
+ }
+ pci_sync_in = CONFIG_83XX_PCICLK;
+#endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST) */
+
+ /* we have up to date pci_sync_in */
+
+ spmf = ((im->reset.rcwl & RCWL_SPMF) >> RCWL_SPMF_SHIFT);
+ clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT);
+
+ if ((im->reset.rcwl & RCWL_LBIUCM) || (im->reset.rcwl & RCWL_DDRCM)) {
+ csb_clk = (pci_sync_in * spmf * (1 + clkin_div)) / 2;
+ }
+ else {
+ csb_clk = pci_sync_in * spmf * (1 + clkin_div);
+ }
+
+ sccr = im->clk.sccr;
+ 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 -4;
+ }
+
+ 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 -5;
+ }
+ i2c_clk = tsec2_clk;
+
+ 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 -6;
+ }
+
+ 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 -7;
+ }
+
+ 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 -8;
+ }
+
+ 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 than USB MPH & USB DR must have the same rate */
+ return -9;
+ }
+
+ lbiu_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_LBIUCM) >> RCWL_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 -10;
+ }
+
+ ddr_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_DDRCM) >> RCWL_DDRCM_SHIFT));
+
+ corepll = (im->reset.rcwl & RCWL_COREPLL) >> RCWL_COREPLL_SHIFT;
+ 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 -12;
+ }
+
+ gd->csb_clk = csb_clk ;
+ gd->tsec1_clk = tsec1_clk ;
+ gd->tsec2_clk = tsec2_clk ;
+ gd->core_clk = core_clk ;
+ gd->usbmph_clk = usbmph_clk;
+ gd->usbdr_clk = usbdr_clk ;
+ gd->i2c_clk = i2c_clk ;
+ gd->enc_clk = enc_clk ;
+ gd->lbiu_clk = lbiu_clk ;
+ gd->lclk_clk = lclk_clk ;
+ gd->ddr_clk = ddr_clk ;
+
+ gd->cpu_clk = gd->core_clk;
+ gd->bus_clk = gd->lbiu_clk;
+ return 0;
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ return gd->csb_clk;
+}
+
+int print_clock_conf (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ printf("Clock configuration:\n");
+ printf(" Coherent System Bus: %4d MHz\n",gd->csb_clk/1000000);
+ printf(" Core: %4d MHz\n",gd->core_clk/1000000);
+ printf(" Local Bus Controller:%4d MHz\n",gd->lbiu_clk/1000000);
+ printf(" Local Bus: %4d MHz\n",gd->lclk_clk/1000000);
+ printf(" DDR: %4d MHz\n",gd->ddr_clk/1000000);
+ printf(" I2C: %4d MHz\n",gd->i2c_clk/1000000);
+ printf(" TSEC1: %4d MHz\n",gd->tsec1_clk/1000000);
+ printf(" TSEC2: %4d MHz\n",gd->tsec2_clk/1000000);
+ printf(" USB MPH: %4d MHz\n",gd->usbmph_clk/1000000);
+ printf(" USB DR: %4d MHz\n",gd->usbdr_clk/1000000);
+
+#if 0
+ DECLARE_GLOBAL_DATA_PTR;
+
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ ulong sccr, dfbrg;
+ ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf;
+ corecnf_t *cp;
+
+ sccr = immap->im_clkrst.car_sccr;
+ dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+ scmr = immap->im_clkrst.car_scmr;
+ corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+ busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT;
+ cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT;
+ plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+ pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+
+ cp = &corecnf_tab[corecnf];
+
+ puts (CPU_ID_STR " Clock Configuration\n - Bus-to-Core Mult ");
+
+ switch (cp->b2c_mult) {
+ case _byp:
+ puts ("BYPASS");
+ break;
+
+ case _off:
+ puts ("OFF");
+ break;
+
+ case _unk:
+ puts ("UNKNOWN");
+ break;
+
+ default:
+ printf ("%d%sx",
+ cp->b2c_mult / 2,
+ (cp->b2c_mult % 2) ? ".5" : "");
+ break;
+ }
+
+ printf (", VCO Div %d, 60x Bus Freq %s, Core Freq %s\n",
+ cp->vco_div, cp->freq_60x, cp->freq_core);
+
+ printf (" - dfbrg %ld, corecnf 0x%02lx, busdf %ld, cpmdf %ld, "
+ "plldf %ld, pllmf %ld\n", dfbrg, corecnf, busdf, cpmdf, plldf,
+ pllmf);
+
+ printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n",
+ gd->vco_out, gd->scc_clk, gd->brg_clk);
+
+ printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n",
+ gd->cpu_clk, gd->cpm_clk, gd->bus_clk);
+
+ if (sccr & SCCR_PCI_MODE) {
+ uint pci_div;
+
+ pci_div = ( (sccr & SCCR_PCI_MODCK) ? 2 : 1) *
+ ( ( (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT) + 1);
+
+ printf (" - pci_clk %10ld\n", (gd->cpm_clk * 2) / pci_div);
+ }
+ putc ('\n');
+#endif
+ return (0);
+}
+
diff --git a/cpu/mpc83xx/start.S b/cpu/mpc83xx/start.S
new file mode 100644
index 0000000..e9f0790
--- /dev/null
+++ b/cpu/mpc83xx/start.S
@@ -0,0 +1,1096 @@
+/*
+ * 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 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
+ */
+
+/*
+ * U-Boot - Startup Code for MPC83xx PowerPC based Embedded Boards
+ */
+
+#include <config.h>
+#include <mpc83xx.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
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * Version string - must be in data segment because MPC83xx uses the
+ * first 256 bytes for the Hard Reset Configuration Word table (see
+ * below). Similarly, can't have the U-Boot Magic Number as the first
+ * thing in the image - don't know how this will affect the image tools,
+ * but I guess I'll find out soon.
+ */
+ .data
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", __DATE__, " - ", __TIME__, ")"
+ .ascii " ", CONFIG_IDENT_STRING, "\0"
+
+ .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(CFG_HRCW_LOW)
+ _HRCW_TABLE_ENTRY(CFG_HRCW_HIGH)
+
+
+
+#ifndef CONFIG_DEFAULT_IMMR
+#error CONFIG_DEFAULT_IMMR must be defined
+#endif /* CFG_DEFAULT_IMMR */
+#ifndef CFG_IMMRBAR
+#define CFG_IMMRBAR CONFIG_DEFAULT_IMMR
+#endif /* CFG_IMMRBAR */
+
+/*
+ * 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 */
+ lis r3, CFG_IMMRBAR@h
+ ori r3, r3, CFG_IMMRBAR@l
+ stw r3, IMMRBAR(r4)
+
+ /* Initialise the E300 processor core */
+ /*------------------------------------------*/
+
+ bl init_e300_core
+
+#ifndef CFG_RAMBOOT
+
+ /* 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, (CFG_MONITOR_BASE)@h
+ ori r4, r4, (CFG_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 /* CFG_RAMBOOT */
+
+ bl setup_stack_in_data_cache_on_r1
+
+ /* 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, CFG_IMMRBAR@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
+
+/*
+ * 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
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_Alignment:
+ .long AlignmentException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_ProgramCheck:
+ .long ProgramCheckException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(0x1000, 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
+
+/*
+ * 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, CFG_IMMRBAR@h
+#if defined(CONFIG_WATCHDOG)
+ /* Initialise the Wathcdog values and reset it (if req) */
+ /*------------------------------------------------------*/
+ lis r4, CFG_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, 0xAA39
+ sth r4, SWSRR@l(r3)
+#else
+ /* Disable Wathcdog */
+ /*-------------------*/
+ xor r4, r4, r4
+ stw r4, SWCRR(r3)
+#endif /* CONFIG_WATCHDOG */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /*------------------------------------------------------*/
+
+ lis r3, CFG_HID0_INIT@h
+ ori r3, r3, CFG_HID0_INIT@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CFG_HID0_FINAL@h
+ ori r3, r3, CFG_HID0_FINAL@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CFG_HID2@h
+ ori r3, r3, CFG_HID2@l
+ SYNC
+ mtspr HID2, r3
+
+ /* clear all BAT's */
+ /*----------------------------------*/
+
+ xor r0, r0, r0
+ mtspr DBAT0U, r0
+ mtspr DBAT0L, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT1L, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT2L, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT3L, r0
+ mtspr IBAT0U, r0
+ mtspr IBAT0L, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT1L, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT2L, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT3L, r0
+ SYNC
+
+ /* 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/ppc/kernel/head.S
+ *
+ */
+
+ li r3, 32
+ mtctr r3
+ li r3, 0
+1: tlbie r3
+ addi r3, r3, 0x1000
+ bdnz 1b
+ SYNC
+
+ /* Done! */
+ /*------------------------------*/
+ 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
+ lis r4, 0
+ ori r4, r4, 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_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock*/
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_ICE_SHIFT, 31, 31
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ENABLE_DATA_CACHE
+ lis r4, 0
+ ori r4, r4, HID0_LOCK_DATA_CACHE
+ andc r3, r3, r4
+ ori r4, r3, HID0_LOCK_INSTRUCTION_CACHE
+ sync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_ENABLE_DATA_CACHE|HID0_LOCK_DATA_CACHE
+ andc r3, r3, r4
+ ori r4, r3, HID0_INVALIDATE_DATA_CACHE
+ sync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_DCE_SHIFT, 31, 31
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ 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 */
+
+ mr r3, r5 /* Destination Address */
+ lis r4, CFG_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CFG_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE)
+ * + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r14, r14, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ 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:
+ bl un_setup_stack_in_data_cache
+ mr r7, r3
+ mr r8, r4
+ bl dcache_disable
+ mr r3, r7
+ mr r4, r8
+
+ cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mfspr r7,HID0 /* don't do dcbst if dcache is disabled*/
+ rlwinm r7,r7,HID0_DCE_SHIFT,31,31
+ cmpwi r7,0
+ beq 9f
+ 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 */
+9: mfspr r7,HID0 /* don't do icbi if icache is disabled */
+ rlwinm r7,r7,HID0_DCE_SHIFT,31,31
+ cmpwi r7,0
+ beq 7f
+ 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, r14 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ add r0,r0,r11
+ stw r0,0(r3)
+ bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+2: li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ add r0,r0,r11
+ stw r10,0(r3)
+ stw r0,0(r4)
+ bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+#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
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+
+ mflr r4 /* save link register */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ 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
+
+ /*
+ * Function: relocate entries for one exception vector
+ */
+trap_reloc:
+ lwz r0, 0(r7) /* hdlr ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 0(r7)
+
+ lwz r0, 4(r7) /* int_return ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 4(r7)
+
+ blr
+
+#ifdef CFG_INIT_RAM_LOCK
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3, (CFG_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l
+ li r2,512
+ mtctr r2
+1: icbi r0, r3
+ dcbi r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+ sync /* Wait for all icbi to complete on bus */
+ isync
+ blr
+#endif
+
+map_flash_by_law1:
+ /* When booting from ROM (Flash or EPROM), clear the */
+ /* Address Mask in OR0 so ROM appears everywhere */
+ /*----------------------------------------------------*/
+ lis r3, (CFG_IMMRBAR)@h /* r3 <= CFG_IMMRBAR */
+ 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, (CFG_FLASH_BASE)@h
+ ori r4, r4, (CFG_FLASH_BASE)@l
+ stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CFG_FLASH_BASE */
+ lis r4, (0x80000016)@h
+ ori r4, r4, (0x80000016)@l
+ 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, (CFG_FLASH_BASE & 0xFFFF8000)@h
+ ori r5, r5, (CFG_FLASH_BASE & 0xFFFF8000)@l
+ or r5, r5, r4
+ stw r5, BR0(r3) /* r5 <= (CFG_FLASH_BASE & 0xFFFF8000) | (BR0 & 0x00007FFF) */
+
+ lwz r4, OR0(r3)
+ lis r5, 0xFF80 /* 8M */
+ or r4, r4, r5
+ stw r4, OR0(r3) /* OR0 <= OR0 | 0xFF800000 */
+
+ lis r4, (CFG_FLASH_BASE)@h
+ ori r4, r4, (CFG_FLASH_BASE)@l
+ stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CFG_FLASH_BASE */
+
+ lis r4, (0x80000016)@h
+ ori r4, r4, (0x80000016)@l
+ stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= 8MB Flash Size */
+
+ xor r4, r4, r4
+ stw r4, LBLAWBAR1(r3)
+ stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */
+ blr
+
+setup_stack_in_data_cache_on_r1:
+ lis r3, (CFG_IMMRBAR)@h
+
+ /* setup D-BAT for the D-Cache (with out real memory backup) */
+
+ lis r4, (CFG_INIT_RAM_ADDR & 0xFFFE0000)@h
+ mtspr DBAT0U, r4
+ ori r4, r4, 0x0002
+ mtspr DBAT0L, r4
+ isync
+
+#if 0
+ /* Enable MMU */
+ mfmsr r4
+ ori r4, r4, (MSR_DR | MSR_IR)@l
+ mtmsr r4
+#endif
+
+ /* Enable and invalidate data cache. */
+ mfspr r4, HID0
+ mr r5, r4
+ ori r4, r4, HID0_DCE | HID0_DCI
+ ori r5, r5, HID0_DCE
+ sync
+ mtspr HID0, r4
+ mtspr HID0, r5
+ sync
+
+ /* Allocate Initial RAM in data cache.*/
+ li r0, 0
+ lis r4, (CFG_INIT_RAM_ADDR)@h
+ ori r4, r4, (CFG_INIT_RAM_ADDR)@l
+ li r5, 128*8 /* 128*8*32=32Kb */
+ mtctr r5
+1:
+ dcbz r0, r4
+ addi r4, r4, 32
+ bdnz 1b
+ isync
+
+ /* Lock all the D-cache, basically leaving the reset of the program without dcache */
+ mfspr r4, HID0
+ ori r4, r4, (HID0_DLOCK)@l
+ sync
+ mtspr HID0 , r4
+
+ /* setup the stack pointer in r1 */
+ lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l
+ li r0, 0 /* Make room for stack frame header and */
+
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ blr
+
+un_setup_stack_in_data_cache:
+ blr
+ mr r14, r4
+ mr r15, r5
+
+
+ lis r4, (CFG_INIT_RAM_ADDR & 0xFFFE0000)@h
+ mtspr DBAT0U, r4
+ ori r4, r4, 0x0002
+ mtspr DBAT0L, r4
+ isync
+
+ /* un lock all the D-cache */
+ mfspr r4, HID0
+ lis r5, (~(HID0_DLOCK))@h
+ ori r5, r5, (~(HID0_DLOCK))@l
+ and r4, r4, r5
+ sync
+ mtspr HID0 , r4
+
+ /* Re - Allocate Initial RAM in data cache.*/
+ li r0, 0
+ lis r4, (CFG_INIT_RAM_ADDR)@h
+ ori r4, r4, (CFG_INIT_RAM_ADDR)@l
+ li r5, 128*8 /* 128*8*32=32Kb */
+ mtctr r5
+1:
+ dcbz r0, r4
+ addi r4, r4, 32
+ bdnz 1b
+ isync
+
+ mflr r16
+ bl dcache_disable
+ mtlr r16
+
+ blr
+
+#if 0
+#define GREEN_LIGHT 0x2B0D4046
+#define RED_LIGHT 0x250D4046
+#define LIB_CNT 0x4FFF
+
+/*
+ * Lib Light
+ */
+
+ .globl liblight
+liblight:
+ lis r3, CFG_IMMRBAR@h
+ ori r3, r3, CFG_IMMRBAR@l
+ li r4, 0x3002
+ mtmsr r4
+ xor r4, r4, r4
+ mtspr HID0, r4
+ mtspr HID2, r4
+ lis r4, 0xF8000000@h
+ ori r4, r4, 0xF8000000@l
+ stw r4, LBLAWBAR1(r3)
+ lis r4, 0x8000000E@h
+ ori r4, r4, 0x8000000E@l
+ stw r4, LBLAWAR1(r3)
+ lis r4, 0xF8000801@h
+ ori r4, r4, 0xF8000801@l
+ stw r4, BR1(r3)
+ lis r4, 0xFFFFE8f0@h
+ ori r4, r4, 0xFFFFE8f0@l
+ stw r4, OR1(r3)
+
+ lis r4, 0xF8000000@h
+ ori r4, r4, 0xF8000000@l
+ lis r5, GREEN_LIGHT@h
+ ori r5, r5, GREEN_LIGHT@l
+ lis r6, RED_LIGHT@h
+ ori r6, r6, RED_LIGHT@l
+ lis r7, LIB_CNT@h
+ ori r7, r7, LIB_CNT@l
+
+1:
+ stw r5, 0(r4)
+ mtctr r7
+2: bdnz 2b
+ stw r6, 0(r4)
+ mtctr r7
+3: bdnz 3b
+ b 1b
+
+#endif
diff --git a/cpu/mpc83xx/traps.c b/cpu/mpc83xx/traps.c
new file mode 100644
index 0000000..c7a5638
--- /dev/null
+++ b/cpu/mpc83xx/traps.c
@@ -0,0 +1,274 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * 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
+ *
+ * Change log:
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 20050101: Eran Liberty (liberty@freescale.com)
+ * Initial file creating (porting from 85XX & 8260)
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware
+ * exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/mpc8349_pci.h>
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize)
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ int cnt = 0;
+ unsigned long i;
+
+ 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 *) CFG_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 *)CFG_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 (CONFIG_COMMANDS & CFG_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 (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#if (CONFIG_COMMANDS & CFG_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 (CONFIG_COMMANDS & CFG_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;
+}