Initial revision
diff --git a/cpu/arm720t/Makefile b/cpu/arm720t/Makefile
new file mode 100644
index 0000000..8c950da
--- /dev/null
+++ b/cpu/arm720t/Makefile
@@ -0,0 +1,43 @@
+#
+# (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 $(TOPDIR)/config.mk
+
+LIB	= lib$(CPU).a
+
+START	= start.o
+OBJS	= serial.o interrupts.o cpu.o
+
+all:	.depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/arm720t/interrupts.c b/cpu/arm720t/interrupts.c
new file mode 100644
index 0000000..52787fe
--- /dev/null
+++ b/cpu/arm720t/interrupts.c
@@ -0,0 +1,265 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * 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 <clps7111.h>
+
+#include <asm/proc-armv/ptrace.h>
+
+extern void reset_cpu(ulong addr);
+
+/* we always count down the max. */
+#define TIMER_LOAD_VAL 0xffff
+
+/* macro to read the 16 bit timer */
+#define READ_TIMER (IO_TC1D & 0xffff)
+
+#ifdef CONFIG_USE_IRQ
+/* enable IRQ/FIQ interrupts */
+void enable_interrupts (void)
+{
+	unsigned long temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "bic %0, %0, #0x80\n"
+			     "msr cpsr_c, %0"
+			     : "=r" (temp)
+			     :
+			     : "memory");
+}
+
+
+/*
+ * disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them
+ */
+int disable_interrupts (void)
+{
+	unsigned long old,temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "orr %1, %0, #0x80\n"
+			     "msr cpsr_c, %1"
+			     : "=r" (old), "=r" (temp)
+			     :
+			     : "memory");
+	return (old & 0x80) == 0;
+}
+#else
+void enable_interrupts (void)
+{
+	return;
+}
+int disable_interrupts (void)
+{
+	return 0;
+}
+#endif
+
+
+
+void bad_mode (void)
+{
+	panic ("Resetting CPU ...\n");
+	reset_cpu (0);
+}
+
+void show_regs (struct pt_regs *regs)
+{
+	unsigned long flags;
+	const char *processor_modes[] =
+			{ "USER_26", "FIQ_26", "IRQ_26", "SVC_26", "UK4_26", "UK5_26",
+"UK6_26", "UK7_26",
+		"UK8_26", "UK9_26", "UK10_26", "UK11_26", "UK12_26", "UK13_26",
+				"UK14_26", "UK15_26",
+		"USER_32", "FIQ_32", "IRQ_32", "SVC_32", "UK4_32", "UK5_32",
+				"UK6_32", "ABT_32",
+		"UK8_32", "UK9_32", "UK10_32", "UND_32", "UK12_32", "UK13_32",
+				"UK14_32", "SYS_32"
+	};
+
+	flags = condition_codes (regs);
+
+	printf ("pc : [<%08lx>]    lr : [<%08lx>]\n"
+			"sp : %08lx  ip : %08lx  fp : %08lx\n",
+			instruction_pointer (regs),
+			regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
+	printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
+			regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
+	printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+			regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
+	printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+			regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
+	printf ("Flags: %c%c%c%c",
+			flags & CC_N_BIT ? 'N' : 'n',
+			flags & CC_Z_BIT ? 'Z' : 'z',
+			flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
+	printf ("  IRQs %s  FIQs %s  Mode %s%s\n",
+			interrupts_enabled (regs) ? "on" : "off",
+			fast_interrupts_enabled (regs) ? "on" : "off",
+			processor_modes[processor_mode (regs)],
+			thumb_mode (regs) ? " (T)" : "");
+}
+
+void do_undefined_instruction (struct pt_regs *pt_regs)
+{
+	printf ("undefined instruction\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_software_interrupt (struct pt_regs *pt_regs)
+{
+	printf ("software interrupt\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_prefetch_abort (struct pt_regs *pt_regs)
+{
+	printf ("prefetch abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_data_abort (struct pt_regs *pt_regs)
+{
+	printf ("data abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_not_used (struct pt_regs *pt_regs)
+{
+	printf ("not used\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_fiq (struct pt_regs *pt_regs)
+{
+	printf ("fast interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_irq (struct pt_regs *pt_regs)
+{
+	printf ("interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+static ulong timestamp;
+static ulong lastdec;
+
+int interrupt_init (void)
+{
+	/* disable all interrupts */
+	IO_INTMR1 = 0;
+
+	/* operate timer 1 in prescale mode */
+	IO_SYSCON1 |= SYSCON1_TC1M;
+
+	/* select 2kHz clock source for timer 1 */
+	IO_SYSCON1 &= ~SYSCON1_TC1S;
+
+	/* set timer 1 counter */
+	lastdec = IO_TC1D = TIMER_LOAD_VAL;
+	timestamp = 0;
+
+	return (0);
+}
+
+/*
+ * timer without interrupts
+ */
+
+void reset_timer (void)
+{
+	reset_timer_masked ();
+}
+
+ulong get_timer (ulong base)
+{
+	return get_timer_masked () - base;
+}
+
+void set_timer (ulong t)
+{
+	timestamp = t;
+}
+
+void udelay (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= CFG_HZ;
+	tmo /= 1000;
+
+	tmo += get_timer (0);
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
+
+void reset_timer_masked (void)
+{
+	/* reset time */
+	lastdec = READ_TIMER;
+	timestamp = 0;
+}
+
+ulong get_timer_masked (void)
+{
+	ulong now = READ_TIMER;
+
+	if (lastdec >= now) {
+		/* normal mode */
+		timestamp += lastdec - now;
+	} else {
+		/* we have an overflow ... */
+		timestamp += lastdec + TIMER_LOAD_VAL - now;
+	}
+	lastdec = now;
+
+	return timestamp;
+}
+
+void udelay_masked (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= CFG_HZ;
+	tmo /= 1000;
+
+	reset_timer_masked ();
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
diff --git a/cpu/arm920t/Makefile b/cpu/arm920t/Makefile
new file mode 100644
index 0000000..e5ec81d
--- /dev/null
+++ b/cpu/arm920t/Makefile
@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2000, 2001, 2002
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= lib$(CPU).a
+
+START	= start.o
+OBJS	= serial.o interrupts.o cpu.o speed.o
+
+all:	.depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/arm920t/interrupts.c b/cpu/arm920t/interrupts.c
new file mode 100644
index 0000000..963ccbd
--- /dev/null
+++ b/cpu/arm920t/interrupts.c
@@ -0,0 +1,304 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * 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 <arm920t.h>
+#if defined(CONFIG_S3C2400)
+#include <s3c2400.h>
+#elif defined(CONFIG_S3C2410)
+#include <s3c2410.h>
+#endif
+
+#include <asm/proc-armv/ptrace.h>
+
+extern void reset_cpu(ulong addr);
+int timer_load_val = 0;
+
+/* macro to read the 16 bit timer */
+#define READ_TIMER (rTCNTO4 & 0xffff)
+
+#ifdef CONFIG_USE_IRQ
+/* enable IRQ interrupts */
+void enable_interrupts (void)
+{
+	unsigned long temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "bic %0, %0, #0x80\n"
+			     "msr cpsr_c, %0"
+			     : "=r" (temp)
+			     :
+			     : "memory");
+}
+
+
+/*
+ * disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them
+ */
+int disable_interrupts (void)
+{
+	unsigned long old,temp;
+	__asm__ __volatile__("mrs %0, cpsr\n"
+			     "orr %1, %0, #0xc0\n"
+			     "msr cpsr_c, %1"
+			     : "=r" (old), "=r" (temp)
+			     :
+			     : "memory");
+	return (old & 0x80) == 0;
+}
+#else
+void enable_interrupts (void)
+{
+	return;
+}
+int disable_interrupts (void)
+{
+	return 0;
+}
+#endif
+
+
+
+void bad_mode (void)
+{
+	panic ("Resetting CPU ...\n");
+	reset_cpu (0);
+}
+
+void show_regs (struct pt_regs *regs)
+{
+	unsigned long flags;
+	const char *processor_modes[] = {
+	"USER_26",	"FIQ_26",	"IRQ_26",	"SVC_26",
+	"UK4_26",	"UK5_26",	"UK6_26",	"UK7_26",
+	"UK8_26",	"UK9_26",	"UK10_26",	"UK11_26",
+	"UK12_26",	"UK13_26",	"UK14_26",	"UK15_26",
+	"USER_32",	"FIQ_32",	"IRQ_32",	"SVC_32",
+	"UK4_32",	"UK5_32",	"UK6_32",	"ABT_32",
+	"UK8_32",	"UK9_32",	"UK10_32",	"UND_32",
+	"UK12_32",	"UK13_32",	"UK14_32",	"SYS_32",
+	};
+
+	flags = condition_codes (regs);
+
+	printf ("pc : [<%08lx>]    lr : [<%08lx>]\n"
+		"sp : %08lx  ip : %08lx  fp : %08lx\n",
+		instruction_pointer (regs),
+		regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
+	printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
+		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
+	printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
+	printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
+	printf ("Flags: %c%c%c%c",
+		flags & CC_N_BIT ? 'N' : 'n',
+		flags & CC_Z_BIT ? 'Z' : 'z',
+		flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
+	printf ("  IRQs %s  FIQs %s  Mode %s%s\n",
+		interrupts_enabled (regs) ? "on" : "off",
+		fast_interrupts_enabled (regs) ? "on" : "off",
+		processor_modes[processor_mode (regs)],
+		thumb_mode (regs) ? " (T)" : "");
+}
+
+void do_undefined_instruction (struct pt_regs *pt_regs)
+{
+	printf ("undefined instruction\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_software_interrupt (struct pt_regs *pt_regs)
+{
+	printf ("software interrupt\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_prefetch_abort (struct pt_regs *pt_regs)
+{
+	printf ("prefetch abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_data_abort (struct pt_regs *pt_regs)
+{
+	printf ("data abort\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_not_used (struct pt_regs *pt_regs)
+{
+	printf ("not used\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_fiq (struct pt_regs *pt_regs)
+{
+	printf ("fast interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+void do_irq (struct pt_regs *pt_regs)
+{
+	printf ("interrupt request\n");
+	show_regs (pt_regs);
+	bad_mode ();
+}
+
+static ulong timestamp;
+static ulong lastdec;
+
+int interrupt_init (void)
+{
+	/* use PWM Timer 4 because it has no output */
+	/* prescaler for Timer 4 is 16 */
+	rTCFG0 = 0x0f00;
+	if (timer_load_val == 0)
+	{
+		/*
+		 * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
+		 * (default) and prescaler = 16. Should be 10390
+		 * @33.25MHz and 15625 @ 50 MHz
+		 */
+		timer_load_val = get_PCLK()/(2 * 16 * 100);
+	}
+	/* load value for 10 ms timeout */
+	lastdec = rTCNTB4 = timer_load_val;
+	/* auto load, manual update of Timer 4 */
+	rTCON = 0x600000;
+	/* auto load, start Timer 4 */
+	rTCON = 0x500000;
+	timestamp = 0;
+
+	return (0);
+}
+
+/*
+ * timer without interrupts
+ */
+
+void reset_timer (void)
+{
+	reset_timer_masked ();
+}
+
+ulong get_timer (ulong base)
+{
+	return get_timer_masked () - base;
+}
+
+void set_timer (ulong t)
+{
+	timestamp = t;
+}
+
+void udelay (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= (timer_load_val * 100);
+	tmo /= 1000;
+
+	tmo += get_timer (0);
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
+
+void reset_timer_masked (void)
+{
+	/* reset time */
+	lastdec = READ_TIMER;
+	timestamp = 0;
+}
+
+ulong get_timer_masked (void)
+{
+	ulong now = READ_TIMER;
+
+	if (lastdec >= now) {
+		/* normal mode */
+		timestamp += lastdec - now;
+	} else {
+		/* we have an overflow ... */
+		timestamp += lastdec + timer_load_val - now;
+	}
+	lastdec = now;
+
+	return timestamp;
+}
+
+void udelay_masked (unsigned long usec)
+{
+	ulong tmo;
+
+	tmo = usec / 1000;
+	tmo *= (timer_load_val * 100);
+	tmo /= 1000;
+
+	reset_timer_masked ();
+
+	while (get_timer_masked () < tmo)
+		/*NOP*/;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk (void)
+{
+	ulong tbclk;
+
+#if defined(CONFIG_SMDK2400) || defined(CONFIG_TRAB)
+	tbclk = timer_load_val * 100;
+#elif defined(CONFIG_SMDK2410)
+	tbclk = CFG_HZ;
+#endif
+
+	return tbclk;
+}
diff --git a/cpu/arm920t/serial.c b/cpu/arm920t/serial.c
new file mode 100644
index 0000000..c32e73b
--- /dev/null
+++ b/cpu/arm920t/serial.c
@@ -0,0 +1,200 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * 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>
+#if defined(CONFIG_S3C2400) || defined(CONFIG_TRAB)
+#include <s3c2400.h>
+#elif defined(CONFIG_S3C2410)
+#include <s3c2410.h>
+#endif
+
+
+void serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int i;
+	unsigned int reg = 0;
+
+	/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
+	reg = get_PCLK() / (16 * gd->baudrate) - 1;
+
+#ifdef CONFIG_SERIAL1
+	/* FIFO enable, Tx/Rx FIFO clear */
+	rUFCON0 = 0x07;
+	rUMCON0 = 0x0;
+	/* Normal,No parity,1 stop,8 bit */
+	rULCON0 = 0x3;
+	/*
+	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
+	 * normal,interrupt or polling
+	 */
+	rUCON0 = 0x245;
+	rUBRDIV0 = reg;
+
+#ifdef CONFIG_HWFLOW
+	rUMCON0 = 0x1; /* RTS up */
+#endif
+	for (i = 0; i < 100; i++);
+#elif CONFIG_SERIAL2
+# if defined(CONFIG_TRAB)
+#  #error "TRAB supports only CONFIG_SERIAL1"
+# endif
+	/* FIFO enable, Tx/Rx FIFO clear */
+	rUFCON1 = 0x06;
+	rUMCON1 = 0x0;
+	/* Normal,No parity,1 stop,8 bit */
+	rULCON1 = 0x3;
+	/*
+	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
+	 * normal,interrupt or polling
+	 */
+	rUCON1 = 0x245;
+	rUBRDIV1 = reg;
+
+#ifdef CONFIG_HWFLOW
+	rUMCON1 = 0x1; /* RTS up */
+#endif
+	for (i = 0; i < 100; i++);
+#else
+#error "Bad: you didn't configure serial ..."
+#endif
+}
+
+/*
+ * Initialise the serial port with the given baudrate. The settings
+ * are always 8 data bits, no parity, 1 stop bit, no start bits.
+ *
+ */
+int serial_init (void)
+{
+	serial_setbrg ();
+
+	return (0);
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+int serial_getc (void)
+{
+#ifdef CONFIG_SERIAL1
+	while (!(rUTRSTAT0 & 0x1));
+
+	return rURXH0 & 0xff;
+#elif CONFIG_SERIAL2
+	while (!(rUTRSTAT1 & 0x1));
+
+	return rURXH1 & 0xff;
+#endif
+}
+
+#ifdef CONFIG_HWFLOW
+static int hwflow = 0; /* turned off by default */
+int hwflow_onoff(int on)
+{
+	switch(on) {
+	case 0:
+	default:
+		break; /* return current */
+	case 1:
+		hwflow = 1; /* turn on */
+		break;
+	case -1:
+		hwflow = 0; /* turn off */
+		break;
+	}
+	return hwflow;
+}
+#endif
+
+#ifdef CONFIG_MODEM_SUPPORT
+static int be_quiet = 0;
+void disable_putc(void)
+{
+	be_quiet = 1;
+}
+
+void enable_putc(void)
+{
+	be_quiet = 0;
+}
+#endif
+
+
+/*
+ * Output a single byte to the serial port.
+ */
+void serial_putc (const char c)
+{
+#ifdef CONFIG_MODEM_SUPPORT
+	if (be_quiet)
+		return;
+#endif
+
+#ifdef CONFIG_SERIAL1
+	/* wait for room in the tx FIFO on SERIAL1 */
+	while (!(rUTRSTAT0 & 0x2));
+
+#ifdef CONFIG_HWFLOW
+	/* Wait for CTS up */
+	while(hwflow && !(rUMSTAT0 & 0x1))
+		;
+#endif
+
+	rUTXH0 = c;
+#elif CONFIG_SERIAL2
+	/* wait for room in the tx FIFO on SERIAL2 */
+	while (!(rUTRSTAT1 & 0x2));
+
+#ifdef CONFIG_HWFLOW
+	/* Wait for CTS up */
+	while(hwflow && !(rUMSTAT1 & 0x1))
+		;
+#endif
+	rUTXH1 = c;
+#endif
+
+	/* If \n, also do \r */
+	if (c == '\n')
+		serial_putc ('\r');
+}
+
+/*
+ * Test whether a character is in the RX buffer
+ */
+int serial_tstc (void)
+{
+#ifdef CONFIG_SERIAL1
+	return rUTRSTAT0 & 0x1;
+#elif CONFIG_SERIAL2
+	return rUTRSTAT1 & 0x1;
+#endif
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
diff --git a/cpu/arm920t/speed.c b/cpu/arm920t/speed.c
new file mode 100644
index 0000000..1ee0c1a
--- /dev/null
+++ b/cpu/arm920t/speed.c
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 2001-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* This code should work for both the S3C2400 and the S3C2410
+ * as they seem to have the same PLL and clock machinery inside.
+ * The different address mapping is handled by the s3c24xx.h files below.
+ */
+
+#include <common.h>
+#if defined(CONFIG_S3C2400)
+#include <s3c2400.h>
+#elif defined(CONFIG_S3C2410)
+#include <s3c2410.h>
+#endif
+
+#define MPLL 0
+#define UPLL 1
+
+/* ------------------------------------------------------------------------- */
+/* NOTE: This describes the proper use of this file.
+ *
+ * CONFIG_PLL_INPUT_FREQ should be defined as the input frequency of the PLL.
+ *
+ * get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of
+ * the specified bus in HZ.
+ */
+/* ------------------------------------------------------------------------- */
+
+static ulong get_PLLCLK(int pllreg)
+{
+    ulong r, m, p, s;
+
+    if (pllreg == MPLL)
+	r = rMPLLCON;
+    else if (pllreg == UPLL)
+	r = rUPLLCON;
+    else
+	hang();
+
+    m = ((r & 0xFF000) >> 12) + 8;
+    p = ((r & 0x003F0) >> 4) + 2;
+    s = r & 0x3;
+
+    return((CONFIG_PLL_INPUT_FREQ * m) / (p << s));
+}
+
+/* return FCLK frequency */
+ulong get_FCLK(void)
+{
+    return(get_PLLCLK(MPLL));
+}
+
+/* return HCLK frequency */
+ulong get_HCLK(void)
+{
+    ulong clkdiv = rCLKDIVN;
+
+    return((clkdiv & 0x2) ? get_FCLK()/2 : get_FCLK());
+}
+
+/* return PCLK frequency */
+ulong get_PCLK(void)
+{
+    ulong clkdiv = rCLKDIVN;
+
+    return((clkdiv & 0x1) ? get_HCLK()/2 : get_HCLK());
+}
+
+/* return UCLK frequency */
+ulong get_UCLK(void)
+{
+    return(get_PLLCLK(UPLL));
+}
diff --git a/cpu/mpc824x/cpu_init.c b/cpu/mpc824x/cpu_init.c
new file mode 100644
index 0000000..602f65d
--- /dev/null
+++ b/cpu/mpc824x/cpu_init.c
@@ -0,0 +1,383 @@
+/*
+ * (C) Copyright 2000
+ * Rob Taylor. Flying Pig Systems. robt@flyingpig.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 <mpc824x.h>
+
+#ifndef CFG_BANK0_ROW
+#define CFG_BANK0_ROW 0
+#endif
+#ifndef CFG_BANK1_ROW
+#define CFG_BANK1_ROW 0
+#endif
+#ifndef CFG_BANK2_ROW
+#define CFG_BANK2_ROW 0
+#endif
+#ifndef CFG_BANK3_ROW
+#define CFG_BANK3_ROW 0
+#endif
+#ifndef CFG_BANK4_ROW
+#define CFG_BANK4_ROW 0
+#endif
+#ifndef CFG_BANK5_ROW
+#define CFG_BANK5_ROW 0
+#endif
+#ifndef CFG_BANK6_ROW
+#define CFG_BANK6_ROW 0
+#endif
+#ifndef CFG_BANK7_ROW
+#define CFG_BANK7_ROW 0
+#endif
+#ifndef CFG_DBUS_SIZE2
+#define CFG_DBUS_SIZE2 0
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ */
+void
+cpu_init_f (void)
+{
+/* MOUSSE board is initialized in asm */
+#if !defined(CONFIG_MOUSSE) && !defined(CONFIG_BMW)
+    register unsigned long val;
+    CONFIG_WRITE_HALFWORD(PCICR, 0x06); /* Bus Master, respond to PCI memory space acesses*/
+/*    CONFIG_WRITE_HALFWORD(PCISR, 0xffff); */ /*reset PCISR*/
+
+#if defined(CONFIG_MUSENKI) || defined(CONFIG_PN62)
+/* Why is this here, you ask?  Try, just try setting 0x8000
+ * in PCIACR with CONFIG_WRITE_HALFWORD()
+ * this one was a stumper, and we are annoyed
+ */
+
+#define M_CONFIG_WRITE_HALFWORD( addr, data ) \
+    __asm__ __volatile__(     \
+      "                       \
+      stw  %2,0(%0)\n         \
+      sync\n                  \
+      sth  %3,2(%1)\n         \
+      sync\n                  \
+      "                       \
+      : /* no output */       \
+      : "r" (CONFIG_ADDR), "r" (CONFIG_DATA),                 \
+        "r" (PCISWAP(addr & ~3)), "r" (PCISWAP(data << 16))   \
+      );
+
+    M_CONFIG_WRITE_HALFWORD(PCIACR, 0x8000);
+#endif
+
+    CONFIG_WRITE_BYTE(PCLSR, 0x8);	/* set PCI cache line size */
+
+    /*
+     * Note that although this bit is cleared after a hard reset, it
+     * must be explicitly set and then cleared by software during
+     * initialization in order to guarantee correct operation of the
+     * DLL and the SDRAM_CLK[0:3] signals (if they are used).
+     */
+    CONFIG_READ_BYTE (AMBOR, val);
+    CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
+    CONFIG_WRITE_BYTE(AMBOR, val | 0x20);
+    CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
+
+    CONFIG_READ_WORD(PICR1, val);
+#if defined(CONFIG_MPC8240)
+    CONFIG_WRITE_WORD( PICR1,
+       (val & (PICR1_ADDRESS_MAP | PICR1_RCS0)) |
+	       PIRC1_MSK | PICR1_PROC_TYPE_603E |
+	       PICR1_FLASH_WR_EN | PICR1_MCP_EN |
+	       PICR1_CF_DPARK | PICR1_EN_PCS |
+	       PICR1_CF_APARK );
+#elif defined(CONFIG_MPC8245)
+    CONFIG_WRITE_WORD( PICR1,
+       (val & (PICR1_RCS0)) |
+	       PICR1_PROC_TYPE_603E |
+	       PICR1_FLASH_WR_EN | PICR1_MCP_EN |
+	       PICR1_CF_DPARK | PICR1_NO_BUSW_CK |
+	       PICR1_DEC| PICR1_CF_APARK | 0x10);	/* 8245 UM says bit 4 must be set */
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+    CONFIG_READ_WORD(PICR2, val);
+    val= val & ~ (PICR2_CF_SNOOP_WS_MASK | PICR2_CF_APHASE_WS_MASK); /*mask off waitstate bits*/
+#ifndef CONFIG_PN62
+    val |= PICR2_CF_SNOOP_WS_1WS | PICR2_CF_APHASE_WS_1WS; /*1 wait state*/
+#endif
+    CONFIG_WRITE_WORD(PICR2, val);
+
+    CONFIG_WRITE_WORD(EUMBBAR, CFG_EUMB_ADDR);
+#ifndef CFG_RAMBOOT
+    CONFIG_WRITE_WORD(MCCR1, (CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) |
+				 (CFG_BANK0_ROW) |
+				 (CFG_BANK1_ROW << MCCR1_BANK1ROW_SHIFT) |
+				 (CFG_BANK2_ROW << MCCR1_BANK2ROW_SHIFT) |
+				 (CFG_BANK3_ROW << MCCR1_BANK3ROW_SHIFT) |
+				 (CFG_BANK4_ROW << MCCR1_BANK4ROW_SHIFT) |
+				 (CFG_BANK5_ROW << MCCR1_BANK5ROW_SHIFT) |
+				 (CFG_BANK6_ROW << MCCR1_BANK6ROW_SHIFT) |
+				 (CFG_BANK7_ROW << MCCR1_BANK7ROW_SHIFT) |
+			     (CFG_ROMFAL << MCCR1_ROMFAL_SHIFT));
+#endif
+
+#if defined(CFG_ASRISE) && defined(CFG_ASFALL)
+    CONFIG_WRITE_WORD(MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT |
+    			     CFG_ASRISE << MCCR2_ASRISE_SHIFT |
+    			     CFG_ASFALL << MCCR2_ASFALL_SHIFT);
+#else
+    CONFIG_WRITE_WORD(MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT);
+#endif
+
+#if defined(CONFIG_MPC8240)
+    CONFIG_WRITE_WORD(MCCR3,
+	(((CFG_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+	(CFG_REFREC << MCCR3_REFREC_SHIFT) |
+	(CFG_RDLAT  << MCCR3_RDLAT_SHIFT));
+#elif defined(CONFIG_MPC8245)
+    CONFIG_WRITE_WORD(MCCR3,
+	(((CFG_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+	(CFG_REFREC << MCCR3_REFREC_SHIFT));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+/* this is gross.  We think these should all be the same, and various boards
+ *  should define CFG_ACTORW to 0 if they don't want to set it, or even, if
+ *  its not set, we define it to zero in this file
+ */
+#if defined(CONFIG_CU824) || defined(CONFIG_PN62)
+	CONFIG_WRITE_WORD(MCCR4,
+	(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+	(CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+	MCCR4_BIT21 |
+	(CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+	((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+	(((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
+		  CFG_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) |
+	(CFG_ACTORW << MCCR4_ACTTORW_SHIFT) |
+	(((CFG_BSTOPRE & 0x03c0) >> 6) << MCCR4_BSTOPRE6TO9_SHIFT));
+#elif defined(CONFIG_MPC8240)
+	CONFIG_WRITE_WORD(MCCR4,
+	(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+	(CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+	MCCR4_BIT21 |
+	(CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+	((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+	(((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
+		  (CFG_SDMODE_BURSTLEN)) <<MCCR4_SDMODE_SHIFT) |
+	(((CFG_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#elif defined(CONFIG_MPC8245)
+    CONFIG_READ_WORD(MCCR1, val);
+    val &= MCCR1_DBUS_SIZE0;    /* test for 64-bit mem bus */
+
+    CONFIG_WRITE_WORD(MCCR4,
+	(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+	(CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+        (CFG_EXTROM ? MCCR4_EXTROM : 0) |
+        (CFG_REGDIMM ? MCCR4_REGDIMM : 0) |
+	(CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+	((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+	(CFG_DBUS_SIZE2 << MCCR4_DBUS_SIZE2_SHIFT) |
+	(((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
+              (val ? 2 : 3)) << MCCR4_SDMODE_SHIFT)  |
+	(CFG_ACTORW << MCCR4_ACTTORW_SHIFT) |
+	(((CFG_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+    CONFIG_WRITE_WORD(MSAR1,
+	( (CFG_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+	(((CFG_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+	(((CFG_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+	(((CFG_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(EMSAR1,
+	( (CFG_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+	(((CFG_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+	(((CFG_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+	(((CFG_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(MSAR2,
+	( (CFG_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+	(((CFG_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+	(((CFG_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+	(((CFG_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(EMSAR2,
+	( (CFG_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+	(((CFG_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+	(((CFG_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+	(((CFG_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(MEAR1,
+	( (CFG_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+	(((CFG_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+	(((CFG_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+	(((CFG_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(EMEAR1,
+	( (CFG_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+	(((CFG_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+	(((CFG_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+	(((CFG_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(MEAR2,
+	( (CFG_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+	(((CFG_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+	(((CFG_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+	(((CFG_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+    CONFIG_WRITE_WORD(EMEAR2,
+	( (CFG_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+	(((CFG_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+	(((CFG_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+	(((CFG_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+
+    CONFIG_WRITE_BYTE(ODCR, CFG_ODCR);
+#ifdef CFG_DLL_MAX_DELAY
+	CONFIG_WRITE_BYTE(MIOCR1, CFG_DLL_MAX_DELAY);	/* needed to make DLL lock */
+#endif
+#if defined(CFG_DLL_EXTEND) && defined(CFG_PCI_HOLD_DEL)
+	CONFIG_WRITE_BYTE(PMCR2, CFG_DLL_EXTEND | CFG_PCI_HOLD_DEL);
+#endif
+#if defined(MIOCR2) && defined(CFG_SDRAM_DSCD)
+	CONFIG_WRITE_BYTE(MIOCR2, CFG_SDRAM_DSCD);	/* change memory input */
+#endif /* setup & hold time */
+
+    CONFIG_WRITE_BYTE(MBER,
+	 CFG_BANK0_ENABLE |
+	(CFG_BANK1_ENABLE << 1) |
+	(CFG_BANK2_ENABLE << 2) |
+	(CFG_BANK3_ENABLE << 3) |
+	(CFG_BANK4_ENABLE << 4) |
+	(CFG_BANK5_ENABLE << 5) |
+	(CFG_BANK6_ENABLE << 6) |
+	(CFG_BANK7_ENABLE << 7));
+
+#ifdef CFG_PGMAX
+    CONFIG_WRITE_BYTE(MPMR, CFG_PGMAX);
+#endif
+
+    /* ! Wait 200us before initialize other registers */
+    /*FIXME: write a decent udelay wait */
+    __asm__ __volatile__(
+      " mtctr	%0 \n \
+       0: bdnz	 0b\n"
+      :
+      : "r" (0x10000));
+
+   CONFIG_READ_WORD(MCCR1, val);
+   CONFIG_WRITE_WORD(MCCR1, val | MCCR1_MEMGO); /* set memory access going */
+   __asm__ __volatile__("eieio");
+
+#endif /* !CONFIG_MOUSSE && !CONFIG_BMW */
+}
+
+
+#ifdef CONFIG_MOUSSE
+#ifdef INCLUDE_MPC107_REPORT
+struct MPC107_s{
+    unsigned int iobase;
+    char desc[120];
+} MPC107Regs[] ={
+    {BMC_BASE+0x0,  "MPC107 Vendor/Device ID"},
+    {BMC_BASE+0x4,  "MPC107 PCI Command/Status Register"},
+    {BMC_BASE+0x8,  "MPC107 Revision"},
+    {BMC_BASE+0xC,  "MPC107 Cache Line Size"},
+    {BMC_BASE+0x10, "MPC107 LMBAR"},
+    {BMC_BASE+0x14, "MPC824x PCSR"},
+    {BMC_BASE+0xA8, "MPC824x PICR1"},
+    {BMC_BASE+0xAC, "MPC824x PICR2"},
+    {BMC_BASE+0x46, "MPC824x PACR"},
+    {BMC_BASE+0x310, "MPC824x ITWR"},
+    {BMC_BASE+0x300, "MPC824x OMBAR"},
+    {BMC_BASE+0x308, "MPC824x OTWR"},
+    {BMC_BASE+0x14, "MPC107 Peripheral Control and Status Register"},
+    {BMC_BASE+0x78, "MPC107 EUMBAR"},
+    {BMC_BASE+0xC0, "MPC107 Processor Bus Error Status"},
+    {BMC_BASE+0xC4, "MPC107 PCI Bus Error Status"},
+    {BMC_BASE+0xC8, "MPC107 Processor/PCI Error Address"},
+    {BMC_BASE+0xE0, "MPC107 AMBOR Register"},
+    {BMC_BASE+0xF0, "MPC107 MCCR1 Register"},
+    {BMC_BASE+0xF4, "MPC107 MCCR2 Register"},
+    {BMC_BASE+0xF8, "MPC107 MCCR3 Register"},
+    {BMC_BASE+0xFC, "MPC107 MCCR4 Register"}
+};
+#define N_MPC107_Regs	(sizeof(MPC107Regs)/sizeof(MPC107Regs[0]))
+#endif /* INCLUDE_MPC107_REPORT */
+#endif /* CONFIG_MOUSSE */
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#ifdef CONFIG_MOUSSE
+#ifdef INCLUDE_MPC107_REPORT
+	unsigned int tmp = 0, i;
+#endif
+	/*
+	 * Initialize the EUMBBAR (Embedded Util Mem Block Base Addr Reg).
+	 * This is necessary before the EPIC, DMA ctlr, I2C ctlr, etc. can
+	 * be accessed.
+	 */
+
+#ifdef CONFIG_MPC8240			/* only on MPC8240 */
+	mpc824x_mpc107_setreg (EUMBBAR, EUMBBAR_VAL);
+	/* MOT/SPS: Issue #10002, PCI (FD Alias enable) */
+	mpc824x_mpc107_setreg (AMBOR, 0x000000C0);
+#endif
+
+
+#ifdef INCLUDE_MPC107_REPORT
+	/* Check MPC824x PCI Device and Vendor ID */
+	while ((tmp = mpc824x_mpc107_getreg (BMC_BASE)) != 0x31057) {
+		printf ("	MPC107: offset=0x%x, val = 0x%x\n",
+			BMC_BASE,
+			tmp);
+	}
+
+	for (i = 0; i < N_MPC107_Regs; i++) {
+		printf ("	0x%x/%s = 0x%x\n",
+			MPC107Regs[i].iobase,
+			MPC107Regs[i].desc,
+			mpc824x_mpc107_getreg (MPC107Regs[i].iobase));
+	}
+
+	printf ("IBAT0L = 0x%08X\n", mfspr (IBAT0L));
+	printf ("IBAT0U = 0x%08X\n", mfspr (IBAT0U));
+	printf ("IBAT1L = 0x%08X\n", mfspr (IBAT1L));
+	printf ("IBAT1U = 0x%08X\n", mfspr (IBAT1U));
+	printf ("IBAT2L = 0x%08X\n", mfspr (IBAT2L));
+	printf ("IBAT2U = 0x%08X\n", mfspr (IBAT2U));
+	printf ("IBAT3L = 0x%08X\n", mfspr (IBAT3L));
+	printf ("IBAT3U = 0x%08X\n", mfspr (IBAT3U));
+	printf ("DBAT0L = 0x%08X\n", mfspr (DBAT0L));
+	printf ("DBAT0U = 0x%08X\n", mfspr (DBAT0U));
+	printf ("DBAT1L = 0x%08X\n", mfspr (DBAT1L));
+	printf ("DBAT1U = 0x%08X\n", mfspr (DBAT1U));
+	printf ("DBAT2L = 0x%08X\n", mfspr (DBAT2L));
+	printf ("DBAT2U = 0x%08X\n", mfspr (DBAT2U));
+	printf ("DBAT3L = 0x%08X\n", mfspr (DBAT3L));
+	printf ("DBAT3U = 0x%08X\n", mfspr (DBAT3U));
+#endif /* INCLUDE_MPC107_REPORT */
+#endif /* CONFIG_MOUSSE */
+	return (0);
+}
diff --git a/cpu/mpc824x/drivers/i2c/i2c1.c b/cpu/mpc824x/drivers/i2c/i2c1.c
new file mode 100644
index 0000000..be6ec60
--- /dev/null
+++ b/cpu/mpc824x/drivers/i2c/i2c1.c
@@ -0,0 +1,1228 @@
+/*************************************************************
+ *
+ * Copyright @ Motorola, 1999
+ *
+ ************************************************************/
+#include <common.h>
+
+#ifdef CONFIG_HARD_I2C
+#include <i2c.h>
+#include "i2c_export.h"
+#include "i2c.h"
+
+#undef  I2CDBG0
+#undef  DEBUG
+
+/* Define a macro to use an optional application-layer print function, if
+ * one was passed to the I2C library during initialization.  If there was
+ * no function pointer passed, this protects against calling it.  Also define
+ * the global variable that holds the passed pointer.
+ */
+#define TIMEOUT (CFG_HZ/4)
+#define PRINT if ( app_print ) app_print
+static int (*app_print) (char *, ...);
+
+/******************* Internal to I2C Driver *****************/
+static unsigned int ByteToXmit = 0;
+static unsigned int XmitByte = 0;
+static unsigned char *XmitBuf = 0;
+static unsigned int XmitBufEmptyStop = 0;
+static unsigned int ByteToRcv = 0;
+static unsigned int RcvByte = 0;
+static unsigned char *RcvBuf = 0;
+static unsigned int RcvBufFulStop = 0;
+static unsigned int MasterRcvAddress = 0;
+
+/* Set by call to get_eumbbar during I2C_Initialize.
+ * This could be globally available to the I2C library, but there is
+ * an advantage to passing it as a parameter: it is already in a register
+ * and doesn't have to be loaded from memory.  Also, that is the way the
+ * I2C library was already implemented and I don't want to change it without
+ * a more detailed analysis.
+ * It is being set as a global variable in I2C_Initialize to hide it from
+ * the DINK application layer, because it is Kahlua-specific.  I think that
+ * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in
+ * a Kahlua-specific library dealing with the embedded utilities memory block.
+ * Right now, get_eumbbar is defined in dink32/kahlua.s.  The other two are
+ * defined in dink32/drivers/i2c/i2c2.s.
+ */
+static unsigned int Global_eumbbar = 0;
+
+extern unsigned int load_runtime_reg (unsigned int eumbbar,
+				      unsigned int reg);
+
+extern unsigned int store_runtime_reg (unsigned int eumbbar,
+				       unsigned int reg, unsigned int val);
+
+/************************** API *****************/
+
+/* Application Program Interface (API) are the calls provided by the I2C
+ * library to upper layer applications (i.e., DINK) to access the Kahlua
+ * I2C bus interface.  The functions and values that are part of this API
+ * are declared in i2c_export.h.
+ */
+
+/*  Initialize I2C unit with the following:
+ *  driver's slave address
+ *  interrupt enabled
+ *  optional pointer to application layer print function
+ *
+ *  These parameters may be added:
+ *  desired clock rate
+ *  digital filter frequency sampling rate
+ *
+ *  This function must be called before I2C unit can be used.
+ */
+I2C_Status I2C_Initialize (unsigned char addr,
+			   I2C_INTERRUPT_MODE en_int,
+			   int (*p) (char *, ...))
+{
+	I2CStatus status;
+
+	/* establish the pointer, if there is one, to the application's "printf" */
+	app_print = p;
+
+	/* If this is the first call, get the embedded utilities memory block
+	 * base address.  I'm not sure what to do about error handling here:
+	 * if a non-zero value is returned, accept it.
+	 */
+	if (Global_eumbbar == 0)
+		Global_eumbbar = get_eumbbar ();
+	if (Global_eumbbar == 0) {
+		PRINT ("I2C_Initialize: can't find EUMBBAR\n");
+		return I2C_ERROR;
+	}
+
+	/* validate the I2C address */
+	if (addr & 0x80) {
+		PRINT ("I2C_Initialize, I2C address invalid:  %d 0x%x\n",
+			   (unsigned int) addr, (unsigned int) addr);
+		return I2C_ERROR;
+	}
+
+	/* Call the internal I2C library function to perform work.
+	 * Accept the default frequency sampling rate (no way to set it currently,
+	 * via I2C_Init) and set the clock frequency to something reasonable.
+	 */
+	status = I2C_Init (Global_eumbbar, (unsigned char) 0x31, addr, en_int);
+	if (status != I2CSUCCESS) {
+		PRINT ("I2C_Initialize: error in initiation\n");
+		return I2C_ERROR;
+	}
+
+	/* all is well */
+	return I2C_SUCCESS;
+}
+
+
+/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV
+ * are implemented.  Both are only in polling mode.
+ *
+ * en_int controls interrupt/polling mode
+ * act is the type of transaction
+ * i2c_addr is the I2C address of the slave device
+ * data_addr is the address of the data on the slave device
+ * len is the length of data to send or receive
+ * buffer is the address of the data buffer
+ * stop = I2C_NO_STOP, don't signal STOP at end of transaction
+ *        I2C_STOP, signal STOP at end of transaction
+ * retry is the timeout retry value, currently ignored
+ * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
+ *        I2C_RESTART, this is a continuation of existing transaction
+ */
+I2C_Status I2C_do_transaction ( I2C_INTERRUPT_MODE en_int,
+				I2C_TRANSACTION_MODE act,
+				unsigned char i2c_addr,
+				unsigned char data_addr,
+				int len,
+				char *buffer,
+				I2C_STOP_MODE stop,
+				int retry, I2C_RESTART_MODE rsta)
+{
+	I2C_Status status;
+	unsigned char data_addr_buffer[1];
+
+#if 1
+/* This is a temporary work-around.  The I2C library breaks the protocol
+ * if it attempts to handle a data transmission in more than one
+ * transaction, so the data address and the actual data bytes are put
+ * into a single buffer before sending it to the library internal functions.
+ * The problem is related to being able to restart a transaction without
+ * sending the I2C device address or repeating the data address.  It may take
+ * a day or two to sort it all out, so I'll have to get back to it later.
+ * Look at I2C_Start to see about using some status flags (I'm not sure that
+ * "stop" and "rsta" are enough to reflect the states, maybe so; but the logic
+ * in the library is insufficient) to control correct handling of the protocol.
+ */
+	unsigned char dummy_buffer[257];
+
+	if (act == I2C_MASTER_XMIT) {
+		int i;
+
+		if (len > 256)
+			return I2C_ERROR;
+		for (i = 1; i <= len; i++)
+			dummy_buffer[i] = buffer[i - 1];
+		dummy_buffer[0] = data_addr;
+		status = I2C_do_buffer (en_int, act, i2c_addr, 1 + len,
+					dummy_buffer, stop, retry, rsta);
+		if (status != I2C_SUCCESS) {
+			PRINT ("I2C_do_transaction: can't perform data transfer\n");
+			return I2C_ERROR;
+		}
+		return I2C_SUCCESS;
+	}
+#endif	/* end of temp work-around */
+
+	/* validate requested transaction type */
+	if ((act != I2C_MASTER_XMIT) && (act != I2C_MASTER_RCV)) {
+		PRINT ("I2C_do_transaction, invalid transaction request:  %d\n",
+			act);
+		return I2C_ERROR;
+	}
+
+	/* range check the I2C address */
+	if (i2c_addr & 0x80) {
+		PRINT ("I2C_do_transaction, I2C address out of range:  %d 0x%x\n",
+			(unsigned int) i2c_addr, (unsigned int) i2c_addr);
+		return I2C_ERROR;
+	} else {
+		data_addr_buffer[0] = data_addr;
+	}
+
+	/*
+         * We first have to contact the slave device and transmit the
+         * data address. Be careful about the STOP and restart stuff.
+         * We don't want to signal STOP after sending the data
+         * address, but this could be a continuation if the
+         * application didn't release the bus after the previous
+         * transaction, by not sending a STOP after it.
+	 */
+	status = I2C_do_buffer (en_int, I2C_MASTER_XMIT, i2c_addr, 1,
+				data_addr_buffer, I2C_NO_STOP, retry, rsta);
+	if (status != I2C_SUCCESS) {
+		PRINT ("I2C_do_transaction: can't send data address for read\n");
+		return I2C_ERROR;
+	}
+
+	/* The data transfer will be a continuation. */
+	rsta = I2C_RESTART;
+
+	/* now handle the user data */
+	status = I2C_do_buffer (en_int, act, i2c_addr, len,
+				buffer, stop, retry, rsta);
+	if (status != I2C_SUCCESS) {
+		PRINT ("I2C_do_transaction: can't perform data transfer\n");
+		return I2C_ERROR;
+	}
+
+	/* all is well */
+	return I2C_SUCCESS;
+}
+
+/* This function performs the work for I2C_do_transaction.  The work is
+ * split into this function to enable I2C_do_transaction to first transmit
+ * the data address to the I2C slave device without putting the data address
+ * into the first byte of the buffer.
+ *
+ * en_int controls interrupt/polling mode
+ * act is the type of transaction
+ * i2c_addr is the I2C address of the slave device
+ * len is the length of data to send or receive
+ * buffer is the address of the data buffer
+ * stop = I2C_NO_STOP, don't signal STOP at end of transaction
+ *        I2C_STOP, signal STOP at end of transaction
+ * retry is the timeout retry value, currently ignored
+ * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
+ *        I2C_RESTART, this is a continuation of existing transaction
+ */
+static I2C_Status I2C_do_buffer (I2C_INTERRUPT_MODE en_int,
+				 I2C_TRANSACTION_MODE act,
+				 unsigned char i2c_addr,
+				 int len,
+				 unsigned char *buffer,
+				 I2C_STOP_MODE stop,
+				 int retry, I2C_RESTART_MODE rsta)
+{
+	I2CStatus rval;
+	unsigned int dev_stat;
+
+	if (act == I2C_MASTER_RCV) {
+		/* set up for master-receive transaction */
+		rval = I2C_get (Global_eumbbar, i2c_addr, buffer, len, stop, rsta);
+	} else {
+		/* set up for master-transmit transaction */
+		rval = I2C_put (Global_eumbbar, i2c_addr, buffer, len, stop, rsta);
+	}
+
+	/* validate the setup */
+	if (rval != I2CSUCCESS) {
+		dev_stat = load_runtime_reg (Global_eumbbar, I2CSR);
+		PRINT ("Error(I2C_do_buffer): control phase, code(0x%08x), status(0x%08x)\n", rval, dev_stat);
+		I2C_Stop (Global_eumbbar);
+		return I2C_ERROR;
+	}
+
+	if (en_int == 1) {
+		/* this should not happen, no interrupt handling yet */
+		return I2C_SUCCESS;
+	}
+
+	/* this performs the polling action, when the transfer is completed,
+	 * the status returned from I2C_Timer_Event will be I2CBUFFFULL or
+	 * I2CBUFFEMPTY (rcv or xmit), I2CSUCCESS or I2CADDRESS indicates the
+	 * transaction is not yet complete, anything else is an error.
+	 */
+	while (rval == I2CSUCCESS || rval == I2CADDRESS) {
+		int timeval = get_timer (0);
+
+		/* poll the device until something happens */
+		do {
+			rval = I2C_Timer_Event (Global_eumbbar, 0);
+		}
+		while (rval == I2CNOEVENT && get_timer (timeval) < TIMEOUT);
+
+		/* check for error condition */
+		if (rval == I2CSUCCESS   ||
+		    rval == I2CBUFFFULL  ||
+		    rval == I2CBUFFEMPTY ||
+		    rval == I2CADDRESS) {
+			;	/* do nothing */
+		} else {
+			/* report the error condition */
+			dev_stat = load_runtime_reg (Global_eumbbar, I2CSR);
+			PRINT ("Error(I2C_do_buffer):  code(0x%08x), status(0x%08x)\n",
+				   rval, dev_stat);
+			return I2C_ERROR;
+		}
+	}
+
+	/* all is well */
+	return I2C_SUCCESS;
+}
+
+/**
+ * Note:
+ *
+ * In all following functions,
+ * the caller shall pass the configured embedded utility memory
+ * block base, EUMBBAR.
+ **/
+
+/***********************************************************
+ * function: I2C_put
+ *
+ * description:
+   Send a buffer of data to the intended rcv_addr.
+ * If stop_flag is set, after the whole buffer
+ * is sent, generate a STOP signal provided that the
+ * receiver doesn't signal the STOP in the middle.
+ * I2C is the master performing transmitting. If
+ * no STOP signal is generated at the end of current
+ * transaction, the master can generate a START signal
+ * to another slave addr.
+ *
+ * note: this is master xmit API
+ *********************************************************/
+static I2CStatus I2C_put (unsigned int eumbbar, unsigned char rcv_addr,	/* receiver's address */
+	  unsigned char *buffer_ptr,	/* pointer of data to be sent */
+	  unsigned int length,	/* number of byte of in the buffer */
+	  unsigned int stop_flag,	/* 1 - signal STOP when buffer is empty
+					 * 0 - no STOP signal when buffer is empty
+					 */
+	  unsigned int is_cnt)
+{					/* 1 - this is a restart, don't check MBB
+					 * 0 - this is a new start, check MBB
+					 */
+	if (buffer_ptr == 0 || length == 0) {
+		return I2CERROR;
+	}
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_put\n", __FILE__, __LINE__);
+#endif
+
+	XmitByte = 0;
+	ByteToXmit = length;
+	XmitBuf = buffer_ptr;
+	XmitBufEmptyStop = stop_flag;
+
+	RcvByte = 0;
+	ByteToRcv = 0;
+	RcvBuf = 0;
+
+	/* we are the master, start transaction */
+	return I2C_Start (eumbbar, rcv_addr, XMIT, is_cnt);
+}
+
+/***********************************************************
+ * function: I2C_get
+ *
+ * description:
+ * Receive a buffer of data from the desired sender_addr
+ * If stop_flag is set, when the buffer is full and the
+ * sender does not signal STOP, generate a STOP signal.
+ * I2C is the master performing receiving. If no STOP signal
+ * is generated, the master can generate a START signal
+ * to another slave addr.
+ *
+ * note: this is master receive API
+ **********************************************************/
+static I2CStatus I2C_get (unsigned int eumbbar, unsigned char rcv_from,	/* sender's address */
+		  unsigned char *buffer_ptr,	/* pointer of receiving buffer */
+		  unsigned int length,	/* length of the receiving buffer */
+		  unsigned int stop_flag,	/* 1 - signal STOP when buffer is full
+						 * 0 - no STOP signal when buffer is full
+						 */
+		  unsigned int is_cnt)
+{						/* 1 - this is a restart, don't check MBB
+						 * 0 - this is a new start, check MBB
+						 */
+	if (buffer_ptr == 0 || length == 0) {
+		return I2CERROR;
+	}
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_get\n", __FILE__, __LINE__);
+#endif
+
+	RcvByte = 0;
+	ByteToRcv = length;
+	RcvBuf = buffer_ptr;
+	RcvBufFulStop = stop_flag;
+
+	XmitByte = 0;
+	ByteToXmit = 0;
+	XmitBuf = 0;
+
+	/* we are the master, start the transaction */
+	return I2C_Start (eumbbar, rcv_from, RCV, is_cnt);
+
+}
+
+#if 0	/* turn off dead code */
+/*********************************************************
+ * function: I2C_write
+ *
+ * description:
+ * Send a buffer of data to the requiring master.
+ * If stop_flag is set, after the whole buffer is sent,
+ * generate a STOP signal provided that the requiring
+ * receiver doesn't signal the STOP in the middle.
+ * I2C is the slave performing transmitting.
+ *
+ * Note: this is slave xmit API.
+ *
+ *       due to the current Kahlua design, slave transmitter
+ *       shall not signal STOP since there is no way
+ *       for master to detect it, causing I2C bus hung.
+ *
+ *       For the above reason, the stop_flag is always
+ *       set, i.e., 0.
+ *
+ *       programmer shall use the timer on Kahlua to
+ *       control the interval of data byte at the
+ *       master side.
+ *******************************************************/
+static I2CStatus I2C_write (unsigned int eumbbar, unsigned char *buffer_ptr,	/* pointer of data to be sent */
+		unsigned int length,	/* number of byte of in the buffer */
+		unsigned int stop_flag)
+{					/* 1 - signal STOP when buffer is empty
+					 * 0 - no STOP signal when buffer is empty
+					 */
+	if (buffer_ptr == 0 || length == 0) {
+		return I2CERROR;
+	}
+
+	XmitByte = 0;
+	ByteToXmit = length;
+	XmitBuf = buffer_ptr;
+	XmitBufEmptyStop = 0;	/* in order to avoid bus hung, ignored the user's stop_flag */
+
+	RcvByte = 0;
+	ByteToRcv = 0;
+	RcvBuf = 0;
+
+	/* we are the slave, just wait for being called, or pull */
+	/* I2C_Timer_Event( eumbbar ); */
+}
+
+/******************************************************
+ * function: I2C_read
+ *
+ * description:
+ * Receive a buffer of data from the sending master.
+ * If stop_flag is set, when the buffer is full and the
+ * sender does not signal STOP, generate a STOP signal.
+ * I2C is the slave performing receiving.
+ *
+ * note: this is slave receive API
+ ****************************************************/
+static I2CStatus I2C_read (unsigned int eumbbar, unsigned char *buffer_ptr,	/* pointer of receiving buffer */
+		   unsigned int length,	/* length of the receiving buffer */
+		   unsigned int stop_flag)
+{					/* 1 - signal STOP when buffer is full
+					 * 0 - no STOP signal when buffer is full
+					 */
+	if (buffer_ptr == 0 || length == 0) {
+		return I2CERROR;
+	}
+
+	RcvByte = 0;
+	ByteToRcv = length;
+	RcvBuf = buffer_ptr;
+	RcvBufFulStop = stop_flag;
+
+	XmitByte = 0;
+	ByteToXmit = 0;
+	XmitBuf = 0;
+
+	/* wait for master to call us, or poll */
+	/* I2C_Timer_Event( eumbbar ); */
+}
+#endif	/* turn off dead code */
+
+/*********************************************************
+ * function: I2c_Timer_Event
+ *
+ * description:
+ * if interrupt is not used, this is the timer event handler.
+ * After each fixed time interval, this function can be called
+ * to check the I2C status and call appropriate function to
+ * handle the status event.
+ ********************************************************/
+static I2CStatus I2C_Timer_Event (unsigned int eumbbar,
+				  I2CStatus (*handler) (unsigned int))
+{
+	I2C_STAT stat;
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Timer_Event\n", __FILE__, __LINE__);
+#endif
+
+	stat = I2C_Get_Stat (eumbbar);
+
+	if (stat.mif == 1) {
+		if (handler == 0) {
+			return I2C_ISR (eumbbar);
+		} else {
+			return (*handler) (eumbbar);
+		}
+	}
+
+	return I2CNOEVENT;
+}
+
+
+/****************** Device I/O function *****************/
+
+/******************************************************
+ * function: I2C_Start
+ *
+ * description: Generate a START signal in the desired mode.
+ *              I2C is the master.
+ *
+ *              Return I2CSUCCESS if no error.
+ *
+ * note:
+ ****************************************************/
+static I2CStatus I2C_Start (unsigned int eumbbar, unsigned char slave_addr,	/* address of the receiver */
+			I2C_MODE mode,	/* XMIT(1) - put (write)
+					 * RCV(0)  - get (read)
+					 */
+			unsigned int is_cnt)
+{					/* 1 - this is a restart, don't check MBB
+					 * 0 - this is a new start
+					 */
+	unsigned int tmp = 0;
+	I2C_STAT stat;
+	I2C_CTRL ctrl;
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Start addr 0x%x mode %d cnt %d\n", __FILE__,
+		   __LINE__, slave_addr, mode, is_cnt);
+#endif
+
+	ctrl = I2C_Get_Ctrl (eumbbar);
+
+	/* first make sure I2C has been initialized */
+	if (ctrl.men == 0) {
+		return I2CERROR;
+	}
+
+	/* next make sure bus is idle */
+	stat = I2C_Get_Stat (eumbbar);
+
+	if (is_cnt == 0 && stat.mbb == 1) {
+		/* sorry, we lost */
+		return I2CBUSBUSY;
+	} else if (is_cnt == 1 && stat.mif == 1 && stat.mal == 0) {
+		/* sorry, we lost the bus */
+		return I2CALOSS;
+	}
+
+
+	/* OK, I2C is enabled and we have the bus */
+
+	/* prepare to write the slave address */
+	ctrl.msta = 1;
+	ctrl.mtx = 1;
+	ctrl.txak = 0;
+	ctrl.rsta = is_cnt;		/* set the repeat start bit */
+	I2C_Set_Ctrl (eumbbar, ctrl);
+
+	/* write the slave address and xmit/rcv mode bit */
+	tmp = load_runtime_reg (eumbbar, I2CDR);
+	tmp = (tmp & 0xffffff00) |
+	      ((slave_addr & 0x007f) << 1) |
+	      (mode == XMIT ? 0x0 : 0x1);
+	store_runtime_reg (eumbbar, I2CDR, tmp);
+
+	if (mode == RCV) {
+		MasterRcvAddress = 1;
+	} else {
+		MasterRcvAddress = 0;
+	}
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Start exit\n", __FILE__, __LINE__);
+#endif
+
+	/* wait for the interrupt or poll  */
+	return I2CSUCCESS;
+}
+
+/***********************************************************
+ * function: I2c_Stop
+ *
+ * description: Generate a STOP signal to terminate the master
+ *              transaction.
+ *              return I2CSUCCESS
+ *
+ **********************************************************/
+static I2CStatus I2C_Stop (unsigned int eumbbar)
+{
+	I2C_CTRL ctrl;
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Stop enter\n", __FILE__, __LINE__);
+#endif
+
+	ctrl = I2C_Get_Ctrl (eumbbar);
+	ctrl.msta = 0;
+	I2C_Set_Ctrl (eumbbar, ctrl);
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Stop exit\n", __FILE__, __LINE__);
+#endif
+
+	return I2CSUCCESS;
+}
+
+/****************************************************
+ * function: I2C_Master_Xmit
+ *
+ * description: Master sends one byte of data to
+ *              slave target
+ *
+ *              return I2CSUCCESS if the byte transmitted.
+ *              Otherwise no-zero
+ *
+ * Note: condition must meet when this function is called:
+ *       I2CSR(MIF) == 1 && I2CSR(MCF)  == 1  && I2CSR(RXAK) == 0
+ *       I2CCR(MSTA) == 1  && I2CCR(MTX) == 1
+ *
+ ***************************************************/
+static I2CStatus I2C_Master_Xmit (unsigned int eumbbar)
+{
+	unsigned int val;
+
+	if (ByteToXmit > 0) {
+
+		if (ByteToXmit == XmitByte) {
+			/* all xmitted */
+			ByteToXmit = 0;
+
+			if (XmitBufEmptyStop == 1) {
+				I2C_Stop (eumbbar);
+			}
+
+			return I2CBUFFEMPTY;
+
+		}
+#ifdef I2CDBG0
+		PRINT ("%s(%d): xmit 0x%02x\n", __FILE__, __LINE__,
+			   *(XmitBuf + XmitByte));
+#endif
+
+		val = *(XmitBuf + XmitByte);
+		val &= 0x000000ff;
+		store_runtime_reg (eumbbar, I2CDR, val);
+		XmitByte++;
+
+		return I2CSUCCESS;
+
+	}
+
+	return I2CBUFFEMPTY;
+}
+
+/***********************************************
+ * function: I2C_Master_Rcv
+ *
+ * description: master reads one byte data
+ *              from slave source
+ *
+ *              return I2CSUCCESS if no error
+ *
+ * Note: condition must meet when this function is called:
+ *       I2CSR(MIF) == 1 && I2CSR(MCF) == 1 &&
+ *       I2CCR(MSTA) == 1 && I2CCR(MTX) == 0
+ *
+ ***********************************************/
+static I2CStatus I2C_Master_Rcv (unsigned int eumbbar)
+{
+	I2C_CTRL ctrl;
+	unsigned int val;
+
+	if (ByteToRcv > 0) {
+
+		if (ByteToRcv - RcvByte == 2 && RcvBufFulStop == 1) {
+			/* master requests more than or equal to 2 bytes
+			 * we are reading 2nd to last byte
+			 */
+
+			/* we need to set I2CCR(TXAK) to generate a STOP */
+			ctrl = I2C_Get_Ctrl (eumbbar);
+			ctrl.txak = 1;
+			I2C_Set_Ctrl (eumbbar, ctrl);
+
+			/* Kahlua will automatically generate a STOP
+			 * next time a transaction happens
+			 */
+
+			/* note: the case of master requesting one byte is
+			 *       handled in I2C_ISR
+			 */
+		}
+
+		/* generat a STOP before reading the last byte */
+		if (RcvByte + 1 == ByteToRcv && RcvBufFulStop == 1) {
+			I2C_Stop (eumbbar);
+		}
+
+		val = load_runtime_reg (eumbbar, I2CDR);
+		*(RcvBuf + RcvByte) = val & 0xFF;
+
+#ifdef I2CDBG0
+		PRINT ("%s(%d): rcv 0x%02x\n", __FILE__, __LINE__,
+			   *(RcvBuf + RcvByte));
+#endif
+
+		RcvByte++;
+
+		if (ByteToRcv == RcvByte) {
+			ByteToRcv = 0;
+
+			return I2CBUFFFULL;
+		}
+
+		return I2CSUCCESS;
+	}
+
+	return I2CBUFFFULL;
+
+}
+
+/****************************************************
+ * function: I2C_Slave_Xmit
+ *
+ * description: Slave sends one byte of data to
+ *              requesting destination
+ *
+ *        return SUCCESS if the byte transmitted. Otherwise
+ *        No-zero
+ *
+ * Note: condition must meet when this function is called:
+ *       I2CSR(MIF) == 1 && I2CSR(MCF) == 1 &&  I2CSR(RXAK) = 0
+ *       I2CCR(MSTA) == 0  && I2CCR(MTX) == 1
+ *
+ ***************************************************/
+static I2CStatus I2C_Slave_Xmit (unsigned int eumbbar)
+{
+	unsigned int val;
+
+	if (ByteToXmit > 0) {
+
+		if (ByteToXmit == XmitByte) {
+			/* no more data to send */
+			ByteToXmit = 0;
+
+			/*
+                         * do not toggle I2CCR(MTX). Doing so will
+                         * cause bus-hung since current Kahlua design
+                         * does not give master a way to detect slave
+                         * stop. It is always a good idea for master
+                         * to use timer to prevent the long long
+                         * delays
+			 */
+
+			return I2CBUFFEMPTY;
+		}
+#ifdef I2CDBG
+		PRINT ("%s(%d): xmit 0x%02x\n", __FILE__, __LINE__,
+			   *(XmitBuf + XmitByte));
+#endif
+
+		val = *(XmitBuf + XmitByte);
+		val &= 0x000000ff;
+		store_runtime_reg (eumbbar, I2CDR, val);
+		XmitByte++;
+
+		return I2CSUCCESS;
+	}
+
+	return I2CBUFFEMPTY;
+}
+
+/***********************************************
+ * function: I2C_Slave_Rcv
+ *
+ * description: slave reads one byte data
+ *              from master source
+ *
+ *              return I2CSUCCESS if no error otherwise non-zero
+ *
+ * Note: condition must meet when this function is called:
+ *       I2CSR(MIF) == 1 && I2CSR(MCF) == 1 &&
+ *       I2CCR(MSTA) == 0 && I2CCR(MTX)  = 0
+ *
+ ***********************************************/
+static I2CStatus I2C_Slave_Rcv (unsigned int eumbbar)
+{
+	unsigned int val;
+	I2C_CTRL ctrl;
+
+	if (ByteToRcv > 0) {
+		val = load_runtime_reg (eumbbar, I2CDR);
+		*(RcvBuf + RcvByte) = val & 0xff;
+#ifdef I2CDBG
+		PRINT ("%s(%d): rcv 0x%02x\n", __FILE__, __LINE__,
+			   *(RcvBuf + RcvByte));
+#endif
+		RcvByte++;
+
+		if (ByteToRcv == RcvByte) {
+			if (RcvBufFulStop == 1) {
+				/* all done */
+				ctrl = I2C_Get_Ctrl (eumbbar);
+				ctrl.txak = 1;
+				I2C_Set_Ctrl (eumbbar, ctrl);
+			}
+
+			ByteToRcv = 0;
+			return I2CBUFFFULL;
+		}
+
+		return I2CSUCCESS;
+	}
+
+	return I2CBUFFFULL;
+}
+
+/****************** Device Control Function *************/
+
+/*********************************************************
+ * function: I2C_Init
+ *
+ * description: Initialize I2C unit with desired frequency divider,
+ *              master's listening address, with interrupt enabled
+ *              or disabled.
+ *
+ * note:
+ ********************************************************/
+static I2CStatus I2C_Init (unsigned int eumbbar, unsigned char fdr,	/* frequency divider */
+		   unsigned char slave_addr,	/* driver's address used for receiving */
+		   unsigned int en_int)
+{						/* 1 - enable I2C interrupt
+						 * 0 - disable I2C interrup
+						 */
+	I2C_CTRL ctrl;
+	unsigned int tmp;
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Init enter\n", __FILE__, __LINE__);
+#endif
+
+	ctrl = I2C_Get_Ctrl (eumbbar);
+	/* disable the I2C module before we change everything */
+	ctrl.men = 0;
+	I2C_Set_Ctrl (eumbbar, ctrl);
+
+	/* set the frequency diver */
+	tmp = load_runtime_reg (eumbbar, I2CFDR);
+	tmp = (tmp & 0xffffffc0) | (fdr & 0x3f);
+	store_runtime_reg (eumbbar, I2CFDR, tmp);
+
+	/* Set our listening (slave) address */
+	tmp = load_runtime_reg (eumbbar, I2CADR);
+	tmp = (tmp & 0xffffff01) | ((slave_addr & 0x7f) << 1);
+	store_runtime_reg (eumbbar, I2CADR, tmp);
+
+	/* enable I2C with desired interrupt setting */
+	ctrl.men = 1;
+	ctrl.mien = en_int & 0x1;
+	I2C_Set_Ctrl (eumbbar, ctrl);
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_Init exit\n", __FILE__, __LINE__);
+#endif
+
+	return I2CSUCCESS;
+
+}
+
+/*****************************************
+ * function I2c_Get_Stat
+ *
+ * description: Query I2C Status, i.e., read I2CSR
+ *
+ ****************************************/
+static I2C_STAT I2C_Get_Stat (unsigned int eumbbar)
+{
+	unsigned int temp;
+	I2C_STAT stat;
+
+	temp = load_runtime_reg (eumbbar, I2CSR);
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): get stat = 0x%08x\n", __FILE__, __LINE__, temp);
+#endif
+
+	stat.rsrv0 = (temp & 0xffffff00) >> 8;
+	stat.mcf   = (temp & 0x00000080) >> 7;
+	stat.maas  = (temp & 0x00000040) >> 6;
+	stat.mbb   = (temp & 0x00000020) >> 5;
+	stat.mal   = (temp & 0x00000010) >> 4;
+	stat.rsrv1 = (temp & 0x00000008) >> 3;
+	stat.srw   = (temp & 0x00000004) >> 2;
+	stat.mif   = (temp & 0x00000002) >> 1;
+	stat.rxak  = (temp & 0x00000001);
+	return stat;
+}
+
+/*********************************************
+ * function: I2c_Set_Ctrl
+ *
+ * description: Change I2C Control bits,
+ *              i.e., write to I2CCR
+ *
+ ********************************************/
+static void I2C_Set_Ctrl (unsigned int eumbbar, I2C_CTRL ctrl)
+{						/* new control value */
+	unsigned int temp = load_runtime_reg (eumbbar, I2CCR);
+
+	temp &= 0xffffff03;
+	temp |= ((ctrl.men  & 0x1) << 7);
+	temp |= ((ctrl.mien & 0x1) << 6);
+	temp |= ((ctrl.msta & 0x1) << 5);
+	temp |= ((ctrl.mtx  & 0x1) << 4);
+	temp |= ((ctrl.txak & 0x1) << 3);
+	temp |= ((ctrl.rsta & 0x1) << 2);
+#ifdef I2CDBG0
+	PRINT ("%s(%d): set ctrl = 0x%08x\n", __FILE__, __LINE__, temp);
+#endif
+	store_runtime_reg (eumbbar, I2CCR, temp);
+
+}
+
+/*****************************************
+ * function: I2C_Get_Ctrl
+ *
+ * description: Query I2C Control bits,
+ *              i.e., read I2CCR
+ *****************************************/
+static I2C_CTRL I2C_Get_Ctrl (unsigned int eumbbar)
+{
+	union {
+		I2C_CTRL ctrl;
+		unsigned int temp;
+	} s;
+
+	s.temp = load_runtime_reg (eumbbar, I2CCR);
+#ifdef I2CDBG0
+	PRINT ("%s(%d): get ctrl = 0x%08x\n", __FILE__, __LINE__, s.temp);
+#endif
+
+	return s.ctrl;
+}
+
+
+/****************************************
+ * function: I2C_Slave_Addr
+ *
+ * description: Process slave address phase.
+ *              return I2CSUCCESS if no error
+ *
+ * note: Precondition for calling this function:
+ *       I2CSR(MIF) == 1 &&
+ *       I2CSR(MAAS) == 1
+ ****************************************/
+static I2CStatus I2C_Slave_Addr (unsigned int eumbbar)
+{
+	I2C_STAT stat = I2C_Get_Stat (eumbbar);
+	I2C_CTRL ctrl = I2C_Get_Ctrl (eumbbar);
+
+	if (stat.srw == 1) {
+		/* we are asked to xmit */
+		ctrl.mtx = 1;
+		I2C_Set_Ctrl (eumbbar, ctrl);	/* set MTX */
+		return I2C_Slave_Xmit (eumbbar);
+	}
+
+	/* we are asked to receive data */
+	ctrl.mtx = 0;
+	I2C_Set_Ctrl (eumbbar, ctrl);
+	(void) load_runtime_reg (eumbbar, I2CDR);	/* do a fake read to start */
+
+	return I2CADDRESS;
+}
+
+/***********************************************
+ * function: I2C_ISR
+ *
+ * description: I2C Interrupt service routine
+ *
+ * note: Precondition:
+ *      I2CSR(MIF) == 1
+ **********************************************/
+static I2CStatus I2C_ISR (unsigned int eumbbar)
+{
+	I2C_STAT stat;
+	I2C_CTRL ctrl;
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): I2C_ISR\n", __FILE__, __LINE__);
+#endif
+
+	stat = I2C_Get_Stat (eumbbar);
+	ctrl = I2C_Get_Ctrl (eumbbar);
+
+	/* clear MIF */
+	stat.mif = 0;
+
+	/* Now let see what kind of event this is */
+	if (stat.mcf == 1) {
+		/* transfer compete */
+
+		/* clear the MIF bit */
+		I2C_Set_Stat (eumbbar, stat);
+
+		if (ctrl.msta == 1) {
+			/* master */
+			if (ctrl.mtx == 1) {
+				/* check if this is the address phase for master receive */
+				if (MasterRcvAddress == 1) {
+					/* Yes, it is the address phase of master receive */
+					ctrl.mtx = 0;
+					/* now check how much we want to receive */
+					if (ByteToRcv == 1 && RcvBufFulStop == 1) {
+						ctrl.txak = 1;
+					}
+
+					I2C_Set_Ctrl (eumbbar, ctrl);
+					(void) load_runtime_reg (eumbbar, I2CDR);	/* fake read first */
+
+					MasterRcvAddress = 0;
+					return I2CADDRESS;
+
+				}
+
+				/* master xmit */
+				if (stat.rxak == 0) {
+					/* slave has acknowledged */
+					return I2C_Master_Xmit (eumbbar);
+				}
+
+				/* slave has not acknowledged yet, generate a STOP */
+				if (XmitBufEmptyStop == 1) {
+					ctrl.msta = 0;
+					I2C_Set_Ctrl (eumbbar, ctrl);
+				}
+
+				return I2CSUCCESS;
+			}
+
+			/* master receive */
+			return I2C_Master_Rcv (eumbbar);
+		}
+
+		/* slave */
+		if (ctrl.mtx == 1) {
+			/* slave xmit */
+			if (stat.rxak == 0) {
+				/* master has acknowledged */
+				return I2C_Slave_Xmit (eumbbar);
+			}
+
+			/* master has not acknowledged, wait for STOP */
+			/* do nothing for preventing bus from hung */
+			return I2CSUCCESS;
+		}
+
+		/* slave rcv */
+		return I2C_Slave_Rcv (eumbbar);
+
+	} else if (stat.maas == 1) {
+		/* received a call from master */
+
+		/* clear the MIF bit */
+		I2C_Set_Stat (eumbbar, stat);
+
+		/* master is calling us, process the address phase */
+		return I2C_Slave_Addr (eumbbar);
+	} else {
+		/* has to be arbitration lost */
+		stat.mal = 0;
+		I2C_Set_Stat (eumbbar, stat);
+
+		ctrl.msta = 0;			/* return to receive mode */
+		I2C_Set_Ctrl (eumbbar, ctrl);
+	}
+
+	return I2CSUCCESS;
+
+}
+
+/******************************************************
+ * function: I2C_Set_Stat
+ *
+ * description: modify the I2CSR
+ *
+ *****************************************************/
+static void I2C_Set_Stat (unsigned int eumbbar, I2C_STAT stat)
+{
+	union {
+		unsigned int val;
+		I2C_STAT stat;
+	} s_tmp;
+	union {
+		unsigned int val;
+		I2C_STAT stat;
+	} s;
+
+	s.val = load_runtime_reg (eumbbar, I2CSR);
+	s.val &= 0xffffff08;
+	s_tmp.stat = stat;
+	s.val |= (s_tmp.val & 0xf7);
+
+#ifdef I2CDBG0
+	PRINT ("%s(%d): set stat = 0x%08x\n", __FILE__, __LINE__, s.val);
+#endif
+
+	store_runtime_reg (eumbbar, I2CSR, s.val);
+
+}
+
+/******************************************************
+ * The following are routines to glue the rest of
+ * U-Boot to the Sandpoint I2C driver.
+ *****************************************************/
+
+void i2c_init (int speed, int slaveadd)
+{
+#ifdef DEBUG
+	I2C_Initialize (0x7f, 0, (void *) printf);
+#else
+	I2C_Initialize (0x7f, 0, 0);
+#endif
+}
+
+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);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+	I2CStatus status;
+	uchar xaddr[4];
+
+	if (alen > 0) {
+		xaddr[0] = (addr >> 24) & 0xFF;
+		xaddr[1] = (addr >> 16) & 0xFF;
+		xaddr[2] = (addr >> 8) & 0xFF;
+		xaddr[3] = addr & 0xFF;
+
+		status = I2C_do_buffer (0, I2C_MASTER_XMIT, chip, alen,
+					&xaddr[4 - alen], I2C_NO_STOP, 1,
+					I2C_NO_RESTART);
+		if (status != I2C_SUCCESS) {
+			PRINT ("i2c_read: can't send data address for read\n");
+			return 1;
+		}
+	}
+
+	/* The data transfer will be a continuation. */
+	status = I2C_do_buffer (0, I2C_MASTER_RCV, chip, len,
+				buffer, I2C_STOP, 1, (alen > 0 ? I2C_RESTART :
+				I2C_NO_RESTART));
+
+	if (status != I2C_SUCCESS) {
+		PRINT ("i2c_read: can't perform data transfer\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+	I2CStatus status;
+	unsigned char dummy_buffer[I2C_RXTX_LEN + 2];
+	int i;
+
+	dummy_buffer[0] = addr & 0xFF;
+	if (alen == 2)
+		dummy_buffer[1] = (addr >> 8) & 0xFF;
+	for (i = 0; i < len; i++)
+		dummy_buffer[i + alen] = buffer[i];
+
+	status = I2C_do_buffer (0, I2C_MASTER_XMIT, chip, alen + len,
+				dummy_buffer, I2C_STOP, 1, I2C_NO_RESTART);
+
+#ifdef CFG_EEPROM_PAGE_WRITE_DELAY_MS
+	udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+#endif
+	if (status != I2C_SUCCESS) {
+		PRINT ("i2c_write: can't perform data transfer\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+uchar i2c_reg_read (uchar i2c_addr, uchar reg)
+{
+	char buf[1];
+
+	i2c_init (0, 0);
+
+	i2c_read (i2c_addr, reg, 1, buf, 1);
+
+	return (buf[0]);
+}
+
+void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
+{
+	i2c_init (0, 0);
+
+	i2c_write (i2c_addr, reg, 1, &val, 1);
+}
+
+#endif	/* CONFIG_HARD_I2C */
diff --git a/cpu/mpc824x/pci.c b/cpu/mpc824x/pci.c
new file mode 100644
index 0000000..7e3c4c3
--- /dev/null
+++ b/cpu/mpc824x/pci.c
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/kernel/mpc10x_common.c
+ *
+ * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
+ * Mem ctlr, EPIC, etc.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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>
+
+#ifdef CONFIG_PCI
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <mpc824x.h>
+
+void pci_mpc824x_init (struct pci_controller *hose)
+{
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	/* System memory space */
+	pci_set_region(hose->regions + 0,
+		       CHRP_PCI_MEMORY_BUS,
+		       CHRP_PCI_MEMORY_PHYS,
+		       CHRP_PCI_MEMORY_SIZE,
+		       PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+	/* PCI memory space */
+	pci_set_region(hose->regions + 1,
+		       CHRP_PCI_MEM_BUS,
+		       CHRP_PCI_MEM_PHYS,
+		       CHRP_PCI_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	/* ISA/PCI memory space */
+	pci_set_region(hose->regions + 2,
+		       CHRP_ISA_MEM_BUS,
+		       CHRP_ISA_MEM_PHYS,
+		       CHRP_ISA_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	/* PCI I/O space */
+	pci_set_region(hose->regions + 3,
+		       CHRP_PCI_IO_BUS,
+		       CHRP_PCI_IO_PHYS,
+		       CHRP_PCI_IO_SIZE,
+		       PCI_REGION_IO);
+
+	/* ISA/PCI I/O space */
+	pci_set_region(hose->regions + 4,
+		       CHRP_ISA_IO_BUS,
+		       CHRP_ISA_IO_PHYS,
+		       CHRP_ISA_IO_SIZE,
+		       PCI_REGION_IO);
+
+	hose->region_count = 5;
+
+	pci_setup_indirect(hose,
+			   CHRP_REG_ADDR,
+			   CHRP_REG_DATA);
+
+	pci_register_hose(hose);
+
+	hose->last_busno = pci_hose_scan(hose);
+}
+
+#endif
diff --git a/cpu/mpc824x/start.S b/cpu/mpc824x/start.S
new file mode 100644
index 0000000..bd9706d
--- /dev/null
+++ b/cpu/mpc824x/start.S
@@ -0,0 +1,835 @@
+/*
+ *  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>
+ *
+ * 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 PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0x00000100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ * This works because the cpu gives the FLASH (CS0) the whole
+ * address space at startup, and board_init lies as a echo of
+ * the flash somewhere up there in the memorymap.
+ *
+ * board_init will change CS0 to be positioned at the correct
+ * address and (s)dram will be positioned at address 0
+ */
+#include <config.h>
+#include <mpc824x.h>
+#include <version.h>
+
+#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 ""
+#endif
+
+/* We don't want the MMU yet.
+*/
+#undef	MSR_KERNEL
+/* FP, Machine Check and Recoverable Interr. */
+#define MSR_KERNEL ( MSR_FP | MSR_ME | MSR_RI )
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(_end)
+	GOT_ENTRY(.bss)
+#if defined(CONFIG_FADS)
+	GOT_ENTRY(environment)
+#endif
+	END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+	.text
+	.long	0x27051956		/* U-Boot Magic Number			*/
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", __DATE__, " - ", __TIME__, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH	*/
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM	/* Software reboot			*/
+	b	boot_warm
+
+boot_cold:
+boot_warm:
+
+	/* Initialize machine status; enable machine check interrupt		*/
+	/*----------------------------------------------------------------------*/
+	li	r3, MSR_KERNEL		/* Set FP, ME, RI flags */
+	mtmsr	r3
+	mtspr	SRR1, r3		/* Make SRR1 match MSR */
+
+	addis	r0,0,0x0000		/* lets make sure that r0 is really 0 */
+	mtspr   HID0, r0		/* disable I and D caches */
+
+	mfspr	r3, ICR			/* clear Interrupt Cause Register */
+
+	mfmsr	r3			/* turn off address translation */
+	addis	r4,0,0xffff
+	ori	r4,r4,0xffcf
+	and	r3,r3,r4
+	mtmsr	r3
+	isync
+	sync				/* the MMU should be off... */
+
+
+in_flash:
+#if defined(CONFIG_BMW)
+	bl early_init_f /* Must be ASM: no stack yet! */
+#endif
+	/*
+	 * Setup BATs - cannot be done in C since we don't have a stack yet
+	 */
+	bl	setup_bats
+
+	/* Enable MMU.
+	 */
+	mfmsr	r3
+	ori	r3, r3, (MSR_IR | MSR_DR)
+	mtmsr	r3
+#if !defined(CONFIG_BMW)
+	/* Enable and invalidate data cache.
+	 */
+	mfspr	r3, HID0
+	mr	r2, r3
+	ori	r3, r3, HID0_DCE | HID0_DCI
+	ori	r2, r2, HID0_DCE
+	sync
+	mtspr	HID0, r3
+	mtspr	HID0, r2
+	sync
+
+	/* Allocate Initial RAM in data cache.
+	 */
+	lis	r3, CFG_INIT_RAM_ADDR@h
+	ori	r3, r3, CFG_INIT_RAM_ADDR@l
+	li	r2, 128
+	mtctr	r2
+1:
+	dcbz	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+
+	/* Lock way0 in data cache.
+	 */
+	mfspr	r3, 1011
+	lis	r2, 0xffff
+	ori	r2, r2, 0xff1f
+	and	r3, r3, r2
+	ori	r3, r3, 0x0080
+	sync
+	mtspr	1011, r3
+#endif /* !CONFIG_BMW */
+	/*
+	 * Thisk the stack pointer *somewhere* sensible. Doesnt
+	 * matter much where as we'll move it when we relocate
+	 */
+	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	*/
+
+	/* let the C-code set up the rest					*/
+	/*									*/
+	/* Be careful to keep code relocatable !				*/
+	/*----------------------------------------------------------------------*/
+
+	GET_GOT			/* initialize GOT access			*/
+
+	/* r3: IMMR */
+	bl	cpu_init_f	/* run low-level CPU init code     (from Flash)	*/
+
+	mr	r3, r21
+	/* r3: BOOTFLAG */
+	bl	board_init_f	/* run 1st part of board init code (from Flash) */
+
+
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(EXC_OFF_MACH_CHCK, MachineCheck, MachineCheckException)
+
+/* Data Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(EXC_OFF_DATA_STOR, DataStorage, UnknownException)
+
+/* Instruction Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(EXC_OFF_INS_STOR, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(EXC_OFF_EXTERNAL, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = EXC_OFF_ALIGN
+Alignment:
+	EXCEPTION_PROLOG
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	lwz	r6,GOT(transfer_to_handler)
+	mtlr	r6
+	blrl
+.L_Alignment:
+	.long	AlignmentException - _start + EXC_OFF_SYS_RESET
+	.long	int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+	. = EXC_OFF_PROGRAM
+ProgramCheck:
+	EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	lwz	r6,GOT(transfer_to_handler)
+	mtlr	r6
+	blrl
+.L_ProgramCheck:
+	.long	ProgramCheckException - _start + EXC_OFF_SYS_RESET
+	.long	int_return - _start + EXC_OFF_SYS_RESET
+
+	/* No FPU on MPC8xx. This exception is not supposed to happen.
+	*/
+	STD_EXCEPTION(EXC_OFF_FPUNAVAIL, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(EXC_OFF_DECR, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+
+	. = 0xc00
+/*
+ * r0 - SYSCALL number
+ * r3-... arguments
+ */
+SystemCall:
+	addis	r11,r0,0		/* get functions table addr */
+	ori	r11,r11,0		/* Note: this code is patched in trap_init */
+	addis	r12,r0,0		/* get number of functions */
+	ori	r12,r12,0
+
+	cmplw	0, r0, r12
+	bge	1f
+
+	rlwinm	r0,r0,2,0,31		/* fn_addr = fn_tbl[r0] */
+	add	r11,r11,r0
+	lwz	r11,0(r11)
+
+	li	r12,0xd00-4*3		/* save LR & SRRx */
+	mflr	r0
+	stw	r0,0(r12)
+	mfspr	r0,SRR0
+	stw	r0,4(r12)
+	mfspr	r0,SRR1
+	stw	r0,8(r12)
+
+	li	r12,0xc00+_back-SystemCall
+	mtlr	r12
+	mtspr	SRR0,r11
+
+1:	SYNC
+	rfi
+
+_back:
+
+	mfmsr	r11			/* Disable interrupts */
+	li	r12,0
+	ori	r12,r12,MSR_EE
+	andc	r11,r11,r12
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r11
+	SYNC
+
+	li	r12,0xd00-4*3		/* restore regs */
+	lwz	r11,0(r12)
+	mtlr	r11
+	lwz	r11,4(r12)
+	mtspr	SRR0,r11
+	lwz	r11,8(r12)
+	mtspr	SRR1,r11
+
+	SYNC
+	rfi
+
+	STD_EXCEPTION(EXC_OFF_TRACE, SingleStep, UnknownException)
+
+	STD_EXCEPTION(EXC_OFF_FPUNASSIST, Trap_0e, UnknownException)
+	STD_EXCEPTION(EXC_OFF_PMI, Trap_0f, UnknownException)
+
+	STD_EXCEPTION(EXC_OFF_ITME, InstructionTransMiss, UnknownException)
+	STD_EXCEPTION(EXC_OFF_DLTME, DataLoadTransMiss, UnknownException)
+	STD_EXCEPTION(EXC_OFF_DSTME, DataStoreTransMiss, UnknownException)
+	STD_EXCEPTION(EXC_OFF_IABE, InstructionBreakpoint, UnknownException)
+	STD_EXCEPTION(EXC_OFF_SMIE, SysManageInt, UnknownException)
+	STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+	STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+	STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+	STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+	STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+	STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+	STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+	STD_EXCEPTION(0x1c00, ReservedC, UnknownException)
+	STD_EXCEPTION(0x1d00, ReservedD, UnknownException)
+	STD_EXCEPTION(0x1e00, ReservedE, UnknownException)
+	STD_EXCEPTION(0x1f00, ReservedF, UnknownException)
+
+	STD_EXCEPTION(EXC_OFF_RMTE, RunModeTrace, 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)
+#if 0
+	andi.	r23,r23,MSR_PR
+	mfspr	r23,SPRG3		/* if from user, fix up tss.regs */
+	beq	2f
+	addi	r24,r1,STACK_FRAME_OVERHEAD
+	stw	r24,PT_REGS(r23)
+2:	addi	r2,r23,-TSS		/* set r2 to current */
+	tovirt(r2,r2,r23)
+#endif
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+#if 0
+	addi	r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */
+	cmplw	0,r1,r2
+	cmplw	1,r1,r24
+	crand	1,1,4
+	bgt	stack_ovf		/* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+#endif
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	ori	r20,r20,0x30		/* enable IR, DR */
+	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
+
+/* Cache functions.
+*/
+	.globl	icache_enable
+icache_enable:
+	mfspr	r5,HID0		/* turn on the I cache. */
+	ori	r5,r5,0x8800	/* Instruction cache only! */
+	addis	r6,0,0xFFFF
+	ori	r6,r6,0xF7FF
+	and	r6,r5,r6	/* clear the invalidate bit */
+	sync
+	mtspr	HID0,r5
+	mtspr	HID0,r6
+	isync
+	sync
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r5,HID0
+	addis	r6,0,0xFFFF
+	ori	r6,r6,0x7FFF
+	and	r5,r5,r6
+	sync
+	mtspr	HID0,r5
+	isync
+	sync
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	srwi	r3, r3, 15	/* >>15 & 1=> select bit 16 */
+	andi.	r3, r3, 1
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mfspr	r5,HID0		/* turn on the D cache. */
+	ori	r5,r5,0x4400	/* Data cache only! */
+	mfspr	r4, PVR		/* read PVR */
+	srawi	r3, r4, 16	/* shift off the least 16 bits */
+	cmpi	0, 0, r3, 0xC	/* Check for Max pvr */
+	bne	NotMax
+	ori	r5,r5,0x0040	/* setting the DCFA bit, for Max rev 1 errata */
+NotMax:
+	addis	r6,0,0xFFFF
+	ori	r6,r6,0xFBFF
+	and	r6,r5,r6	/* clear the invalidate bit */
+	sync
+	mtspr	HID0,r5
+	mtspr	HID0,r6
+	isync
+	sync
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r5,HID0
+	addis	r6,0,0xFFFF
+	ori	r6,r6,0xBFFF
+	and	r5,r5,r6
+	sync
+	mtspr	HID0,r5
+	isync
+	sync
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	srwi	r3, r3, 14	/* >>14 & 1=> select bit 17 */
+	andi.	r3, r3, 1
+	blr
+
+	.globl	dc_read
+dc_read:
+/*TODO : who uses this, what should it do?
+*/
+	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	*/
+#ifdef DEBUG
+	lis	r4, CFG_SDRAM_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CFG_SDRAM_BASE@l
+#else
+	lis	r4, CFG_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CFG_MONITOR_BASE@l
+#endif
+	lis	r5, CFG_MONITOR_LEN@h		/* Length in Bytes	*/
+	ori	r5, r5, CFG_MONITOR_LEN@l
+	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
+	/* the 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)
+1:	lwzu	r0,4(r8)
+	stwu	r0,4(r7)
+	bdnz	1b
+	b	4f
+
+2:	slwi	r0,r0,2
+	add	r8,r4,r0
+	add	r7,r3,r0
+3:	lwzu	r0,-4(r8)
+	stwu	r0,-4(r7)
+	bdnz	3b
+
+/*
+ * 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, 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)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	blt	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/* Problems accessing "end" in C, so do it here */
+	.globl	get_endaddr
+get_endaddr:
+	lwz	r3,GOT(_end)
+	blr
+
+	/*
+	 * 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)
+
+	rlwinm	r9, r7, 0, 18, 31	/* _start & 0x3FFF	*/
+
+	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
+
+	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
+
+	/* Setup the BAT registers.
+	 */
+setup_bats:
+	lis	r4, CFG_IBAT0L@h
+	ori	r4, r4, CFG_IBAT0L@l
+	lis	r3, CFG_IBAT0U@h
+	ori	r3, r3, CFG_IBAT0U@l
+	mtspr	IBAT0L, r4
+	mtspr	IBAT0U, r3
+	isync
+
+	lis	r4, CFG_DBAT0L@h
+	ori	r4, r4, CFG_DBAT0L@l
+	lis	r3, CFG_DBAT0U@h
+	ori	r3, r3, CFG_DBAT0U@l
+	mtspr	DBAT0L, r4
+	mtspr	DBAT0U, r3
+	isync
+
+	lis	r4, CFG_IBAT1L@h
+	ori	r4, r4, CFG_IBAT1L@l
+	lis	r3, CFG_IBAT1U@h
+	ori	r3, r3, CFG_IBAT1U@l
+	mtspr	IBAT1L, r4
+	mtspr	IBAT1U, r3
+	isync
+
+	lis	r4, CFG_DBAT1L@h
+	ori	r4, r4, CFG_DBAT1L@l
+	lis	r3, CFG_DBAT1U@h
+	ori	r3, r3, CFG_DBAT1U@l
+	mtspr	DBAT1L, r4
+	mtspr	DBAT1U, r3
+	isync
+
+	lis	r4, CFG_IBAT2L@h
+	ori	r4, r4, CFG_IBAT2L@l
+	lis	r3, CFG_IBAT2U@h
+	ori	r3, r3, CFG_IBAT2U@l
+	mtspr	IBAT2L, r4
+	mtspr	IBAT2U, r3
+	isync
+
+	lis	r4, CFG_DBAT2L@h
+	ori	r4, r4, CFG_DBAT2L@l
+	lis	r3, CFG_DBAT2U@h
+	ori	r3, r3, CFG_DBAT2U@l
+	mtspr	DBAT2L, r4
+	mtspr	DBAT2U, r3
+	isync
+
+	lis	r4, CFG_IBAT3L@h
+	ori	r4, r4, CFG_IBAT3L@l
+	lis	r3, CFG_IBAT3U@h
+	ori	r3, r3, CFG_IBAT3U@l
+	mtspr	IBAT3L, r4
+	mtspr	IBAT3U, r3
+	isync
+
+	lis	r4, CFG_DBAT3L@h
+	ori	r4, r4, CFG_DBAT3L@l
+	lis	r3, CFG_DBAT3U@h
+	ori	r3, r3, CFG_DBAT3U@l
+	mtspr	DBAT3L, r4
+	mtspr	DBAT3U, r3
+	isync
+
+	/* Invalidate TLBs.
+	 * -> for (val = 0; val < 0x20000; val+=0x1000)
+	 * ->   tlbie(val);
+	 */
+	lis	r3, 0
+	lis	r5, 2
+
+1:
+	tlbie	r3
+	addi	r3, r3, 0x1000
+	cmp	0, 0, r3, r5
+	blt	1b
+
+	blr
+
+
diff --git a/cpu/mpc8260/cpu_init.c b/cpu/mpc8260/cpu_init.c
new file mode 100644
index 0000000..9f9369a
--- /dev/null
+++ b/cpu/mpc8260/cpu_init.c
@@ -0,0 +1,264 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+#include <ioports.h>
+
+static void config_8260_ioports (volatile immap_t * immr)
+{
+	int portnum;
+
+	for (portnum = 0; portnum < 4; portnum++) {
+		uint pmsk = 0,
+		     ppar = 0,
+		     psor = 0,
+		     pdir = 0,
+		     podr = 0,
+		     pdat = 0;
+		iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0];
+		iop_conf_t *eiopc = iopc + 32;
+		uint msk = 1;
+
+		/*
+		 * NOTE:
+		 * index 0 refers to pin 31,
+		 * index 31 refers to pin 0
+		 */
+		while (iopc < eiopc) {
+			if (iopc->conf) {
+				pmsk |= msk;
+				if (iopc->ppar)
+					ppar |= msk;
+				if (iopc->psor)
+					psor |= msk;
+				if (iopc->pdir)
+					pdir |= msk;
+				if (iopc->podr)
+					podr |= msk;
+				if (iopc->pdat)
+					pdat |= msk;
+			}
+
+			msk <<= 1;
+			iopc++;
+		}
+
+		if (pmsk != 0) {
+			volatile ioport_t *iop = ioport_addr (immr, portnum);
+			uint tpmsk = ~pmsk;
+
+			/*
+                         * the (somewhat confused) paragraph at the
+                         * bottom of page 35-5 warns that there might
+                         * be "unknown behaviour" when programming
+                         * PSORx and PDIRx, if PPARx = 1, so I
+                         * decided this meant I had to disable the
+                         * dedicated function first, and enable it
+                         * last.
+			 */
+			iop->ppar &= tpmsk;
+			iop->psor = (iop->psor & tpmsk) | psor;
+			iop->pdat = (iop->pdat & tpmsk) | pdat;
+			iop->pdir = (iop->pdir & tpmsk) | pdir;
+			iop->podr = (iop->podr & tpmsk) | podr;
+			iop->ppar |= ppar;
+		}
+	}
+}
+
+/*
+ * Breath 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 * immr)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile memctl8260_t *memctl = &immr->im_memctl;
+	extern void m8260_cpm_reset (void);
+
+	/* 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 (5-4) */
+	gd->reset_status = immr->im_clkrst.car_rsr;
+	immr->im_clkrst.car_rsr = RSR_ALLBITS;
+
+	/* RMR - Reset Mode Register - contains checkstop reset enable (5-5) */
+	immr->im_clkrst.car_rmr = CFG_RMR;
+
+	/* BCR - Bus Configuration Register (4-25) */
+	immr->im_siu_conf.sc_bcr = CFG_BCR;
+
+	/* SIUMCR - contains debug pin configuration (4-31) */
+	immr->im_siu_conf.sc_siumcr = CFG_SIUMCR;
+
+	config_8260_ioports (immr);
+
+	/* initialize time counter status and control register (4-40) */
+	immr->im_sit.sit_tmcntsc = CFG_TMCNTSC;
+
+	/* initialize the PIT (4-42) */
+	immr->im_sit.sit_piscr = CFG_PISCR;
+
+#if !defined(CONFIG_COGENT)		/* done in start.S for the cogent */
+	/* System clock control register (9-8) */
+	immr->im_clkrst.car_sccr = CFG_SCCR;
+#endif /* !CONFIG_COGENT */
+
+	/*
+	 * 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_OR0_REMAP)
+	memctl->memc_or0 = CFG_OR0_REMAP;
+#endif
+#if defined(CFG_OR1_REMAP)
+	memctl->memc_or1 = CFG_OR1_REMAP;
+#endif
+
+	/* now restrict to preliminary range */
+	memctl->memc_br0 = CFG_BR0_PRELIM;
+	memctl->memc_or0 = CFG_OR0_PRELIM;
+
+#if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM)
+	memctl->memc_or1 = CFG_OR1_PRELIM;
+	memctl->memc_br1 = CFG_BR1_PRELIM;
+#endif
+
+#if defined(CFG_BR2_PRELIM) && defined(CFG_OR2_PRELIM)
+	memctl->memc_or2 = CFG_OR2_PRELIM;
+	memctl->memc_br2 = CFG_BR2_PRELIM;
+#endif
+
+#if defined(CFG_BR3_PRELIM) && defined(CFG_OR3_PRELIM)
+	memctl->memc_or3 = CFG_OR3_PRELIM;
+	memctl->memc_br3 = CFG_BR3_PRELIM;
+#endif
+
+#if defined(CFG_BR4_PRELIM) && defined(CFG_OR4_PRELIM)
+	memctl->memc_or4 = CFG_OR4_PRELIM;
+	memctl->memc_br4 = CFG_BR4_PRELIM;
+#endif
+
+#if defined(CFG_BR5_PRELIM) && defined(CFG_OR5_PRELIM)
+	memctl->memc_or5 = CFG_OR5_PRELIM;
+	memctl->memc_br5 = CFG_BR5_PRELIM;
+#endif
+
+#if defined(CFG_BR6_PRELIM) && defined(CFG_OR6_PRELIM)
+	memctl->memc_or6 = CFG_OR6_PRELIM;
+	memctl->memc_br6 = CFG_BR6_PRELIM;
+#endif
+
+#if defined(CFG_BR7_PRELIM) && defined(CFG_OR7_PRELIM)
+	memctl->memc_or7 = CFG_OR7_PRELIM;
+	memctl->memc_br7 = CFG_BR7_PRELIM;
+#endif
+
+#if defined(CFG_BR8_PRELIM) && defined(CFG_OR8_PRELIM)
+	memctl->memc_or8 = CFG_OR8_PRELIM;
+	memctl->memc_br8 = CFG_BR8_PRELIM;
+#endif
+
+#if defined(CFG_BR9_PRELIM) && defined(CFG_OR9_PRELIM)
+	memctl->memc_or9 = CFG_OR9_PRELIM;
+	memctl->memc_br9 = CFG_BR9_PRELIM;
+#endif
+
+#if defined(CFG_BR10_PRELIM) && defined(CFG_OR10_PRELIM)
+	memctl->memc_or10 = CFG_OR10_PRELIM;
+	memctl->memc_br10 = CFG_BR10_PRELIM;
+#endif
+
+#if defined(CFG_BR11_PRELIM) && defined(CFG_OR11_PRELIM)
+	memctl->memc_or11 = CFG_OR11_PRELIM;
+	memctl->memc_br11 = CFG_BR11_PRELIM;
+#endif
+
+	m8260_cpm_reset ();
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile immap_t *immr = (immap_t *) gd->bd->bi_immr_base;
+
+	immr->im_cpm.cp_rccr = CFG_RCCR;
+
+	return (0);
+}
+
+/*
+ * print out the reason for the reset
+ */
+int prt_8260_rsr (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	static struct {
+		ulong mask;
+		char *desc;
+	} bits[] = {
+		{
+		RSR_JTRS, "JTAG"}, {
+		RSR_CSRS, "Check Stop"}, {
+		RSR_SWRS, "Software Watchdog"}, {
+		RSR_BMRS, "Bus Monitor"}, {
+		RSR_ESRS, "External Soft"}, {
+		RSR_EHRS, "External Hard"}
+	};
+	static int n = sizeof bits / sizeof bits[0];
+	ulong rsr = gd->reset_status;
+	int i;
+	char *sep;
+
+	puts ("MPC8260 Reset Status:");
+
+	sep = " ";
+	for (i = 0; i < n; i++)
+		if (rsr & bits[i].mask) {
+			printf ("%s%s", sep, bits[i].desc);
+			sep = ", ";
+		}
+
+	puts ("\n\n");
+	return (0);
+}
diff --git a/cpu/mpc8260/i2c.c b/cpu/mpc8260/i2c.c
new file mode 100644
index 0000000..8bfa2e8
--- /dev/null
+++ b/cpu/mpc8260/i2c.c
@@ -0,0 +1,733 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.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>
+
+#if defined(CONFIG_HARD_I2C)
+
+#include <asm/cpm_8260.h>
+#include <i2c.h>
+
+/* define to enable debug messages */
+#undef  DEBUG_I2C
+
+/* uSec to wait between polls of the i2c */
+#define DELAY_US	100
+/* uSec to wait for the CPM to start processing the buffer */
+#define START_DELAY_US	1000
+
+/*
+ * tx/rx per-byte timeout: we delay DELAY_US uSec between polls so the
+ * timeout will be (tx_length + rx_length) * DELAY_US * TOUT_LOOP
+ */
+#define TOUT_LOOP 5
+
+/*-----------------------------------------------------------------------
+ * Set default values
+ */
+#ifndef	CFG_I2C_SPEED
+#define	CFG_I2C_SPEED	50000
+#endif
+
+#ifndef	CFG_I2C_SLAVE
+#define	CFG_I2C_SLAVE	0xFE
+#endif
+/*-----------------------------------------------------------------------
+ */
+
+typedef void (*i2c_ecb_t)(int, int);    /* error callback function */
+
+/* This structure keeps track of the bd and buffer space usage. */
+typedef struct i2c_state {
+	int		rx_idx;		/* index   to next free Rx BD */
+	int		tx_idx;		/* index   to next free Tx BD */
+	void		*rxbd;		/* pointer to next free Rx BD */
+	void		*txbd;		/* pointer to next free Tx BD */
+	int		tx_space;	/* number  of Tx bytes left   */
+	unsigned char	*tx_buf;	/* pointer to free Tx area    */
+	i2c_ecb_t	err_cb;		/* error callback function    */
+} i2c_state_t;
+
+/* flags for i2c_send() and i2c_receive() */
+#define	I2CF_ENABLE_SECONDARY	0x01	/* secondary_address is valid	*/
+#define	I2CF_START_COND		0x02	/* tx: generate start condition	*/
+#define I2CF_STOP_COND		0x04	/* tx: generate stop  condition	*/
+
+/* return codes */
+#define I2CERR_NO_BUFFERS	0x01	/* no more BDs or buffer space	*/
+#define I2CERR_MSG_TOO_LONG	0x02	/* tried to send/receive to much data   */
+#define I2CERR_TIMEOUT		0x03	/* timeout in i2c_doio()	*/
+#define I2CERR_QUEUE_EMPTY	0x04	/* i2c_doio called without send/receive */
+
+/* error callback flags */
+#define I2CECB_RX_ERR		0x10	/* this is a receive error	*/
+#define     I2CECB_RX_ERR_OV	0x02	/* receive overrun error	*/
+#define     I2CECB_RX_MASK	0x0f	/* mask for error bits		*/
+#define I2CECB_TX_ERR		0x20	/* this is a transmit error	*/
+#define     I2CECB_TX_CL	0x01	/* transmit collision error	*/
+#define     I2CECB_TX_UN	0x02	/* transmit underflow error	*/
+#define     I2CECB_TX_NAK	0x04	/* transmit no ack error	*/
+#define     I2CECB_TX_MASK	0x0f	/* mask for error bits		*/
+#define I2CECB_TIMEOUT		0x40	/* this is a timeout error	*/
+
+#define ERROR_I2C_NONE		0
+#define ERROR_I2C_LENGTH	1
+
+#define I2C_WRITE_BIT		0x00
+#define I2C_READ_BIT		0x01
+
+#define I2C_RXTX_LEN	128	/* maximum tx/rx buffer length */
+
+
+#define NUM_RX_BDS 4
+#define NUM_TX_BDS 4
+#define MAX_TX_SPACE 256
+
+typedef struct I2C_BD
+{
+  unsigned short status;
+  unsigned short length;
+  unsigned char *addr;
+} I2C_BD;
+#define BD_I2C_TX_START 0x0400  /* special status for i2c: Start condition */
+
+#define BD_I2C_TX_CL	0x0001	/* collision error */
+#define BD_I2C_TX_UN	0x0002	/* underflow error */
+#define BD_I2C_TX_NAK	0x0004	/* no acknowledge error */
+#define BD_I2C_TX_ERR	(BD_I2C_TX_NAK|BD_I2C_TX_UN|BD_I2C_TX_CL)
+
+#define BD_I2C_RX_ERR	BD_SC_OV
+
+#ifdef DEBUG_I2C
+#define PRINTD(x) printf x
+#else
+#define PRINTD(x)
+#endif
+
+/*
+ * Returns the best value of I2BRG to meet desired clock speed of I2C with
+ * input parameters (clock speed, filter, and predivider value).
+ * It returns computer speed value and the difference between it and desired
+ * speed.
+ */
+static inline int
+i2c_roundrate(int hz, int speed, int filter, int modval,
+		int *brgval, int *totspeed)
+{
+    int moddiv = 1 << (5-(modval & 3)), brgdiv, div;
+
+    PRINTD(("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n",
+	hz, speed, filter, modval));
+
+    div = moddiv * speed;
+    brgdiv = (hz + div - 1) / div;
+
+    PRINTD(("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv));
+
+    *brgval = (brgdiv / 2) - 3 - (2*filter);
+
+    if ((*brgval < 0) || (*brgval > 255)) {
+	  PRINTD(("\t\trejected brgval=%d\n", *brgval));
+	  return -1;
+    }
+
+    brgdiv = 2 * (*brgval + 3 + (2 * filter));
+    div = moddiv * brgdiv ;
+    *totspeed = (hz + div - 1) / div;
+
+    PRINTD(("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed));
+
+    return  0;
+}
+
+/*
+ * Sets the I2C clock predivider and divider to meet required clock speed.
+ */
+static int i2c_setrate(int hz, int speed)
+{
+    immap_t	*immap = (immap_t *)CFG_IMMR ;
+    volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
+    int brgval,
+	  modval,	/* 0-3 */
+	  bestspeed_diff = speed,
+	  bestspeed_brgval=0,
+	  bestspeed_modval=0,
+	  bestspeed_filter=0,
+	  totspeed,
+	  filter = 0; /* Use this fixed value */
+
+	for (modval = 0; modval < 4; modval++)
+	{
+		if (i2c_roundrate (hz, speed, filter, modval, &brgval, &totspeed) == 0)
+		{
+			int diff = speed - totspeed ;
+
+			if ((diff >= 0) && (diff < bestspeed_diff))
+			{
+				bestspeed_diff 	= diff ;
+				bestspeed_modval 	= modval;
+				bestspeed_brgval 	= brgval;
+				bestspeed_filter 	= filter;
+			}
+		}
+	}
+
+    PRINTD(("[I2C] Best is:\n"));
+    PRINTD(("[I2C] CPU=%dhz RATE=%d F=%d I2MOD=%08x I2BRG=%08x DIFF=%dhz\n",
+		   hz, speed,
+		   bestspeed_filter, bestspeed_modval, bestspeed_brgval,
+		   bestspeed_diff));
+
+    i2c->i2c_i2mod |= ((bestspeed_modval & 3) << 1) | (bestspeed_filter << 3);
+    i2c->i2c_i2brg = bestspeed_brgval & 0xff;
+
+    PRINTD(("[I2C] i2mod=%08x i2brg=%08x\n", i2c->i2c_i2mod, i2c->i2c_i2brg));
+
+    return 1 ;
+}
+
+void i2c_init(int speed, int slaveadd)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile immap_t *immap = (immap_t *)CFG_IMMR ;
+	volatile cpm8260_t *cp = (cpm8260_t *)&immap->im_cpm;
+	volatile i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
+	volatile iic_t *iip;
+	ulong rbase, tbase;
+	volatile I2C_BD *rxbd, *txbd;
+	uint dpaddr;
+
+	dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE]));
+	if (dpaddr == 0) {
+	    /* need to allocate dual port ram */
+	    dpaddr = m8260_cpm_dpalloc(64 +
+		(NUM_RX_BDS * sizeof(I2C_BD)) + (NUM_TX_BDS * sizeof(I2C_BD)) +
+		MAX_TX_SPACE, 64);
+	    *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE])) = dpaddr;
+	}
+
+	/*
+	 * initialise data in dual port ram:
+	 *
+	 * 	  dpaddr -> parameter ram (64 bytes)
+	 *         rbase -> rx BD         (NUM_RX_BDS * sizeof(I2C_BD) bytes)
+	 *         tbase -> tx BD         (NUM_TX_BDS * sizeof(I2C_BD) bytes)
+	 *                  tx buffer     (MAX_TX_SPACE bytes)
+	 */
+
+	iip = (iic_t *)&immap->im_dprambase[dpaddr];
+	memset((void*)iip, 0, sizeof(iic_t));
+
+	rbase = dpaddr + 64;
+	tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
+
+	/* Disable interrupts */
+	i2c->i2c_i2mod = 0x00;
+	i2c->i2c_i2cmr = 0x00;
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2add = slaveadd;
+
+	/*
+	 * Set the I2C BRG Clock division factor from desired i2c rate
+	 * and current CPU rate (we assume sccr dfbgr field is 0;
+	 * divide BRGCLK by 1)
+	 */
+	PRINTD(("[I2C] Setting rate...\n"));
+	i2c_setrate (gd->brg_clk, CFG_I2C_SPEED) ;
+
+	/* Set I2C controller in master mode */
+	i2c->i2c_i2com = 0x01;
+
+	/* Initialize Tx/Rx parameters */
+	iip->iic_rbase = rbase;
+	iip->iic_tbase = tbase;
+	rxbd = (I2C_BD *)((unsigned char *)&immap->im_dprambase[iip->iic_rbase]);
+	txbd = (I2C_BD *)((unsigned char *)&immap->im_dprambase[iip->iic_tbase]);
+
+	PRINTD(("[I2C] rbase = %04x\n", iip->iic_rbase));
+	PRINTD(("[I2C] tbase = %04x\n", iip->iic_tbase));
+	PRINTD(("[I2C] rxbd = %08x\n", (int)rxbd));
+	PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
+
+	/* Set big endian byte order */
+	iip->iic_tfcr = 0x10;
+	iip->iic_rfcr = 0x10;
+
+	/* Set maximum receive size. */
+	iip->iic_mrblr = I2C_RXTX_LEN;
+
+    cp->cp_cpcr = mk_cr_cmd(CPM_CR_I2C_PAGE,
+							CPM_CR_I2C_SBLOCK,
+							0x00,
+							CPM_CR_INIT_TRX) | CPM_CR_FLG;
+    do {
+		__asm__ __volatile__ ("eieio");
+    } while (cp->cp_cpcr & CPM_CR_FLG);
+
+	/* Clear events and interrupts */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2cmr = 0x00;
+}
+
+static
+void i2c_newio(i2c_state_t *state)
+{
+	volatile immap_t *immap = (immap_t *)CFG_IMMR ;
+	volatile iic_t *iip;
+	uint dpaddr;
+
+	PRINTD(("[I2C] i2c_newio\n"));
+
+	dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE]));
+	iip = (iic_t *)&immap->im_dprambase[dpaddr];
+	state->rx_idx = 0;
+	state->tx_idx = 0;
+	state->rxbd = (void*)&immap->im_dprambase[iip->iic_rbase];
+	state->txbd = (void*)&immap->im_dprambase[iip->iic_tbase];
+	state->tx_space = MAX_TX_SPACE;
+	state->tx_buf = (uchar*)state->txbd + NUM_TX_BDS * sizeof(I2C_BD);
+	state->err_cb = NULL;
+
+	PRINTD(("[I2C] rxbd = %08x\n", (int)state->rxbd));
+	PRINTD(("[I2C] txbd = %08x\n", (int)state->txbd));
+	PRINTD(("[I2C] tx_buf = %08x\n", (int)state->tx_buf));
+
+	/* clear the buffer memory */
+	memset((char *)state->tx_buf, 0, MAX_TX_SPACE);
+}
+
+static
+int i2c_send(i2c_state_t *state,
+			 unsigned char address,
+			 unsigned char secondary_address,
+			 unsigned int flags,
+			 unsigned short size,
+			 unsigned char *dataout)
+{
+	volatile I2C_BD *txbd;
+	int i,j;
+
+	PRINTD(("[I2C] i2c_send add=%02d sec=%02d flag=%02d size=%d\n",
+			address, secondary_address, flags, size));
+
+	/* trying to send message larger than BD */
+	if (size > I2C_RXTX_LEN)
+	  return I2CERR_MSG_TOO_LONG;
+
+	/* no more free bds */
+	if (state->tx_idx >= NUM_TX_BDS || state->tx_space < (2 + size))
+	  return I2CERR_NO_BUFFERS;
+
+	txbd = (I2C_BD *)state->txbd;
+	txbd->addr = state->tx_buf;
+
+	PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
+
+    if (flags & I2CF_START_COND)
+    {
+	PRINTD(("[I2C] Formatting addresses...\n"));
+	if (flags & I2CF_ENABLE_SECONDARY)
+	{
+		txbd->length = size + 2;  /* Length of message plus dest addresses */
+		txbd->addr[0] = address << 1;
+		txbd->addr[1] = secondary_address;
+		i = 2;
+	}
+	else
+	{
+		txbd->length = size + 1;  /* Length of message plus dest address */
+		txbd->addr[0] = address << 1;  /* Write destination address to BD */
+		i = 1;
+	}
+    }
+    else
+    {
+	txbd->length = size;  /* Length of message */
+	i = 0;
+    }
+
+	/* set up txbd */
+	txbd->status = BD_SC_READY;
+	if (flags & I2CF_START_COND)
+	  txbd->status |= BD_I2C_TX_START;
+	if (flags & I2CF_STOP_COND)
+	  txbd->status |= BD_SC_LAST | BD_SC_WRAP;
+
+	/* Copy data to send into buffer */
+	PRINTD(("[I2C] copy data...\n"));
+	for(j = 0; j < size; i++, j++)
+	  txbd->addr[i] = dataout[j];
+
+	PRINTD(("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+		   txbd->length,
+		   txbd->status,
+		   txbd->addr[0],
+		   txbd->addr[1]));
+
+	/* advance state */
+	state->tx_buf += txbd->length;
+	state->tx_space -= txbd->length;
+	state->tx_idx++;
+	state->txbd = (void*)(txbd + 1);
+
+	return 0;
+}
+
+static
+int i2c_receive(i2c_state_t *state,
+				unsigned char address,
+				unsigned char secondary_address,
+				unsigned int flags,
+				unsigned short size_to_expect,
+				unsigned char *datain)
+{
+	volatile I2C_BD *rxbd, *txbd;
+
+	PRINTD(("[I2C] i2c_receive %02d %02d %02d\n", address, secondary_address, flags));
+
+	/* Expected to receive too much */
+	if (size_to_expect > I2C_RXTX_LEN)
+	  return I2CERR_MSG_TOO_LONG;
+
+	/* no more free bds */
+	if (state->tx_idx >= NUM_TX_BDS || state->rx_idx >= NUM_RX_BDS
+		 || state->tx_space < 2)
+	  return I2CERR_NO_BUFFERS;
+
+	rxbd = (I2C_BD *)state->rxbd;
+	txbd = (I2C_BD *)state->txbd;
+
+	PRINTD(("[I2C] rxbd = %08x\n", (int)rxbd));
+	PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
+
+	txbd->addr = state->tx_buf;
+
+	/* set up TXBD for destination address */
+	if (flags & I2CF_ENABLE_SECONDARY)
+	{
+		txbd->length = 2;
+		txbd->addr[0] = address << 1;   /* Write data */
+		txbd->addr[1] = secondary_address;  /* Internal address */
+		txbd->status = BD_SC_READY;
+	}
+	else
+	{
+		txbd->length = 1 + size_to_expect;
+		txbd->addr[0] = (address << 1) | 0x01;
+		txbd->status = BD_SC_READY;
+		memset(&txbd->addr[1], 0, txbd->length);
+	}
+
+	/* set up rxbd for reception */
+	rxbd->status = BD_SC_EMPTY;
+	rxbd->length = size_to_expect;
+	rxbd->addr = datain;
+
+	txbd->status |= BD_I2C_TX_START;
+	if (flags & I2CF_STOP_COND)
+	{
+		txbd->status |= BD_SC_LAST | BD_SC_WRAP;
+		rxbd->status |= BD_SC_WRAP;
+	}
+
+	PRINTD(("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+		   txbd->length,
+		   txbd->status,
+		   txbd->addr[0],
+		   txbd->addr[1]));
+	PRINTD(("[I2C] rxbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+		   rxbd->length,
+		   rxbd->status,
+		   rxbd->addr[0],
+		   rxbd->addr[1]));
+
+	/* advance state */
+	state->tx_buf += txbd->length;
+	state->tx_space -= txbd->length;
+	state->tx_idx++;
+	state->txbd = (void*)(txbd + 1);
+	state->rx_idx++;
+	state->rxbd = (void*)(rxbd + 1);
+
+	return 0;
+}
+
+
+static
+int i2c_doio(i2c_state_t *state)
+{
+	volatile immap_t *immap = (immap_t *)CFG_IMMR ;
+	volatile iic_t *iip;
+	volatile i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
+	volatile I2C_BD *txbd, *rxbd;
+	int  j;
+        int  timeout;
+	uint dpaddr;
+
+	PRINTD(("[I2C] i2c_doio\n"));
+
+        timeout = TOUT_LOOP * 256;	/* arbitrarily long */
+
+	if (state->tx_idx <= 0 && state->rx_idx <= 0) {
+		PRINTD(("[I2C] No I/O is queued\n"));
+		return I2CERR_QUEUE_EMPTY;
+	}
+
+	dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE]));
+	iip = (iic_t *)&immap->im_dprambase[dpaddr];
+	iip->iic_rbptr = iip->iic_rbase;
+	iip->iic_tbptr = iip->iic_tbase;
+
+	/* Enable I2C */
+	PRINTD(("[I2C] Enabling I2C...\n"));
+	i2c->i2c_i2mod |= 0x01;
+
+	/* Begin transmission */
+	i2c->i2c_i2com |= 0x80;
+
+	/* Loop until transmit & receive completed */
+
+	txbd = ((I2C_BD*)state->txbd) - 1;
+	j = 0;
+	if (state->tx_idx > 0) {
+        	timeout = TOUT_LOOP * txbd->length;
+
+		PRINTD(("[I2C] Transmitting...(txbd=0x%08lx)\n", (ulong)txbd));
+		udelay(START_DELAY_US);	/* give it time to start */
+		while((txbd->status & BD_SC_READY) && (j++ < timeout)) {
+			udelay(DELAY_US);
+			if (ctrlc())
+				return (-1);
+			__asm__ __volatile__ ("eieio");
+		}
+	}
+
+	rxbd = ((I2C_BD*)state->rxbd) - 1;
+	j = 0;
+	if ((state->rx_idx > 0) && (j < timeout)) {
+        	timeout = TOUT_LOOP * rxbd->length;
+		PRINTD(("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong)rxbd));
+		udelay(START_DELAY_US);	/* give it time to start */
+		while((rxbd->status & BD_SC_EMPTY) && (j++ < timeout)) {
+			udelay(DELAY_US);
+			if (ctrlc())
+				return (-1);
+			__asm__ __volatile__ ("eieio");
+		}
+	}
+
+	/* Turn off I2C */
+	i2c->i2c_i2mod &= ~0x01;
+
+	if (state->err_cb != NULL) {
+		int n, i, b;
+
+		/*
+		 * if we have an error callback function, look at the
+		 * error bits in the bd status and pass them back
+		 */
+
+		if ((n = state->tx_idx) > 0) {
+			for (i = 0; i < n; i++) {
+				txbd = ((I2C_BD*)state->txbd) - (n - i);
+				if ((b = txbd->status & BD_I2C_TX_ERR) != 0)
+					(*state->err_cb)(I2CECB_TX_ERR|b, i);
+			}
+		}
+
+		if ((n = state->rx_idx) > 0) {
+			for (i = 0; i < n; i++) {
+				rxbd = ((I2C_BD*)state->rxbd) - (n - i);
+				if ((b = rxbd->status & BD_I2C_RX_ERR) != 0)
+					(*state->err_cb)(I2CECB_RX_ERR|b, i);
+			}
+		}
+
+		if (j >= timeout)
+			(*state->err_cb)(I2CECB_TIMEOUT, 0);
+	}
+
+	/* sort out errors and return appropriate good/error status */
+	if(j >= timeout)
+		return(I2CERR_TIMEOUT);
+	if((txbd->status & BD_I2C_TX_ERR) != 0)
+		return(I2CECB_TX_ERR | (txbd->status & I2CECB_TX_MASK));
+	if((rxbd->status & BD_I2C_RX_ERR) != 0)
+		return(I2CECB_RX_ERR | (rxbd->status & I2CECB_RX_MASK));
+
+	return(0);
+}
+
+static int had_tx_nak;
+
+static void
+i2c_test_callback(int flags, int xnum)
+{
+	if ((flags & I2CECB_TX_ERR) && (flags & I2CECB_TX_NAK))
+		had_tx_nak = 1;
+}
+
+int i2c_probe(uchar chip)
+{
+	i2c_state_t state;
+	int rc;
+	uchar buf[1];
+
+	i2c_newio(&state);
+
+	state.err_cb = i2c_test_callback;
+	had_tx_nak = 0;
+
+	rc = i2c_receive(&state, chip, 0, I2CF_START_COND|I2CF_STOP_COND, 1, buf);
+
+	if (rc != 0)
+		return (rc);
+
+	rc = i2c_doio(&state);
+
+	if ((rc != 0) && (rc != I2CERR_TIMEOUT))
+		return (rc);
+
+	return (had_tx_nak);
+}
+
+
+int
+i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	i2c_state_t state;
+	uchar xaddr[4];
+	int rc;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr        & 0xFF;
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+	 /*
+	  * EEPROM chips that implement "address overflow" are ones
+	  * like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
+	  * and the extra bits end up in the "chip address" bit slots.
+	  * This makes a 24WC08 (1Kbyte) chip look like four 256 byte
+	  * chips.
+  	  *
+	  * Note that we consider the length of the address field to still
+	  * be one byte because the extra address bits are hidden in the
+	  * chip address.
+	  */
+	chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+	i2c_newio(&state);
+
+	rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, &xaddr[4-alen]);
+	if (rc != 0) {
+		printf("i2c_read: i2c_send failed (%d)\n", rc);
+		return 1;
+	}
+
+	rc = i2c_receive(&state, chip, 0, I2CF_STOP_COND, len, buffer);
+	if (rc != 0) {
+		printf("i2c_read: i2c_receive failed (%d)\n", rc);
+		return 1;
+	}
+
+	rc = i2c_doio(&state);
+	if (rc != 0) {
+		printf("i2c_read: i2c_doio failed (%d)\n", rc);
+		return 1;
+	}
+	return 0;
+}
+
+int
+i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	i2c_state_t state;
+	uchar xaddr[4];
+	int rc;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr        & 0xFF;
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+	 /*
+	  * EEPROM chips that implement "address overflow" are ones
+	  * like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
+	  * and the extra bits end up in the "chip address" bit slots.
+	  * This makes a 24WC08 (1Kbyte) chip look like four 256 byte
+	  * chips.
+  	  *
+	  * Note that we consider the length of the address field to still
+	  * be one byte because the extra address bits are hidden in the
+	  * chip address.
+	  */
+	chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+	i2c_newio(&state);
+
+	rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, &xaddr[4-alen]);
+	if (rc != 0) {
+		printf("i2c_write: first i2c_send failed (%d)\n", rc);
+		return 1;
+	}
+
+	rc = i2c_send(&state, 0, 0, I2CF_STOP_COND, len, buffer);
+	if (rc != 0) {
+		printf("i2c_write: second i2c_send failed (%d)\n", rc);
+		return 1;
+	}
+
+	rc = i2c_doio(&state);
+	if (rc != 0) {
+		printf("i2c_write: i2c_doio failed (%d)\n", rc);
+		return 1;
+	}
+	return 0;
+}
+
+uchar
+i2c_reg_read(uchar chip, uchar reg)
+{
+	char buf;
+
+	i2c_read(chip, reg, 1, &buf, 1);
+
+	return (buf);
+}
+
+void
+i2c_reg_write(uchar chip, uchar reg, uchar val)
+{
+	i2c_write(chip, reg, 1, &val, 1);
+}
+
+#endif	/* CONFIG_HARD_I2C */
diff --git a/cpu/mpc8xx/cpu.c b/cpu/mpc8xx/cpu.c
new file mode 100644
index 0000000..b1b58b0
--- /dev/null
+++ b/cpu/mpc8xx/cpu.c
@@ -0,0 +1,516 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * m8xx.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8xx.h>
+#include <asm/cache.h>
+
+static char *cpu_warning = "\n         " \
+	"*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***";
+
+#if ((defined(CONFIG_MPC860) || defined(CONFIG_MPC855)) && \
+     !defined(CONFIG_MPC862))
+# ifdef	CONFIG_MPC855
+#  define	ID_STR	"PC855"
+# else
+#  define	ID_STR	"PC860"
+# endif
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint k, m;
+	char buf[32];
+	char pre = 'X';
+	char *mid = "xx";
+	char *suf;
+
+	/* the highest 16 bits should be 0x0050 for a 860 */
+
+	if ((pvr >> 16) != 0x0050)
+		return -1;
+
+	k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+	m = 0;
+
+	switch (k) {
+	case 0x00020001: pre = 'p'; suf = ""; break;
+	case 0x00030001: suf = ""; break;
+	case 0x00120003: suf = "A"; break;
+	case 0x00130003: suf = "A3"; break;
+
+	case 0x00200004: suf = "B"; break;
+
+	case 0x00300004: suf = "C"; break;
+	case 0x00310004: suf = "C1"; m = 1;
+		break;
+
+	case 0x00200064: mid = "SR"; suf = "B"; break;
+	case 0x00300065: mid = "SR"; suf = "C"; break;
+	case 0x00310065: mid = "SR"; suf = "C1"; m = 1; break;
+	case 0x05010000: suf = "D3"; m = 1; break;
+	case 0x05020000: suf = "D4"; m = 1; break;
+
+		/* this value is not documented anywhere */
+	case 0x40000000: pre = 'P'; suf = "D"; m = 1; break;
+
+	default: suf = NULL; break;
+	}
+
+	if (suf)
+		printf ("%c" ID_STR "%sZPnn%s", pre, mid, suf);
+	else
+		printf ("unknown M" ID_STR " (0x%08x)", k);
+
+	printf (" at %s MHz:", strmhz (buf, clock));
+
+	printf (" %u kB I-Cache", checkicache () >> 10);
+	printf (" %u kB D-Cache", checkdcache () >> 10);
+
+	/* lets check and see if we're running on a 860T (or P?) */
+
+	immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+	if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+		printf (" FEC present");
+	}
+
+	if (!m) {
+		puts (cpu_warning);
+	}
+
+	putc ('\n');
+
+	return 0;
+}
+
+#elif defined(CONFIG_MPC862)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint k, m;
+	char buf[32];
+	char pre = 'X';
+	char *mid = "xx";
+	char *suf;
+
+	/* the highest 16 bits should be 0x0050 for a 8xx */
+
+	if ((pvr >> 16) != 0x0050)
+		return -1;
+
+	k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+	m = 0;
+
+	switch (k) {
+
+		/* this value is not documented anywhere */
+	case 0x06000000: mid = "P"; suf = "0"; break;
+	case 0x06010001: mid = "P"; suf = "A"; m = 1; break;
+	case 0x07000003: mid = "P"; suf = "B"; m = 1; break;
+	default: suf = NULL; break;
+	}
+
+	if (suf)
+		printf ("%cPC862%sZPnn%s", pre, mid, suf);
+	else
+		printf ("unknown MPC862 (0x%08x)", k);
+
+	printf (" at %s MHz:", strmhz (buf, clock));
+
+	printf (" %u kB I-Cache", checkicache () >> 10);
+	printf (" %u kB D-Cache", checkdcache () >> 10);
+
+	/* lets check and see if we're running on a 862T (or P?) */
+
+	immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+	if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+		printf (" FEC present");
+	}
+
+	if (!m) {
+		puts (cpu_warning);
+	}
+
+	putc ('\n');
+
+	return 0;
+}
+
+#elif defined(CONFIG_MPC823)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint k, m;
+	char buf[32];
+	char *suf;
+
+	/* the highest 16 bits should be 0x0050 for a 8xx */
+
+	if ((pvr >> 16) != 0x0050)
+		return -1;
+
+	k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+	m = 0;
+
+	switch (k) {
+		/* MPC823 */
+	case 0x20000000: suf = "0"; break;
+	case 0x20010000: suf = "0.1"; break;
+	case 0x20020000: suf = "Z2/3"; break;
+	case 0x20020001: suf = "Z3"; break;
+	case 0x21000000: suf = "A"; break;
+	case 0x21010000: suf = "B"; m = 1; break;
+	case 0x21010001: suf = "B2"; m = 1; break;
+		/* MPC823E */
+	case 0x24010000: suf = NULL;
+			puts ("PPC823EZTnnB2");
+			m = 1;
+			break;
+	default:
+			suf = NULL;
+			printf ("unknown MPC823 (0x%08x)", k);
+			break;
+	}
+	if (suf)
+		printf ("PPC823ZTnn%s", suf);
+
+	printf (" at %s MHz:", strmhz (buf, clock));
+
+	printf (" %u kB I-Cache", checkicache () >> 10);
+	printf (" %u kB D-Cache", checkdcache () >> 10);
+
+	/* lets check and see if we're running on a 860T (or P?) */
+
+	immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+	if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+		puts (" FEC present");
+	}
+
+	if (!m) {
+		puts (cpu_warning);
+	}
+
+	putc ('\n');
+
+	return 0;
+}
+
+#elif defined(CONFIG_MPC850)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint k, m;
+	char buf[32];
+
+	/* the highest 16 bits should be 0x0050 for a 8xx */
+
+	if ((pvr >> 16) != 0x0050)
+		return -1;
+
+	k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+	m = 0;
+
+	switch (k) {
+	case 0x20020001:
+		printf ("XPC850xxZT");
+		break;
+	case 0x21000065:
+		printf ("XPC850xxZTA");
+		break;
+	case 0x21010067:
+		printf ("XPC850xxZTB");
+		m = 1;
+		break;
+	case 0x21020068:
+		printf ("XPC850xxZTC");
+		m = 1;
+		break;
+	default:
+		printf ("unknown MPC850 (0x%08x)", k);
+	}
+	printf (" at %s MHz:", strmhz (buf, clock));
+
+	printf (" %u kB I-Cache", checkicache () >> 10);
+	printf (" %u kB D-Cache", checkdcache () >> 10);
+
+	/* lets check and see if we're running on a 850T (or P?) */
+
+	immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+	if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+		printf (" FEC present");
+	}
+
+	if (!m) {
+		puts (cpu_warning);
+	}
+
+	putc ('\n');
+
+	return 0;
+}
+#else
+#error CPU undefined
+#endif
+/* ------------------------------------------------------------------------- */
+
+int checkcpu (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	ulong clock = gd->cpu_clk;
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	uint pvr = get_pvr ();
+
+	puts ("CPU:   ");
+
+	/* 850 has PARTNUM 20 */
+	/* 801 has PARTNUM 10 */
+	return check_CPU (clock, pvr, immr);
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache                                                                */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB)              */
+/* the 860 P (plus) has 256 sets of 16 bytes in 4 ways (= 16 kB)             */
+
+int checkicache (void)
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	u32 cacheon = rd_ic_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP860
+	u32 k = memctl->memc_br1 & ~0x00007fff;	/* probe in flash memoryarea */
+#else
+	u32 k = memctl->memc_br0 & ~0x00007fff;	/* probe in flash memoryarea */
+#endif
+	u32 m;
+	u32 lines = -1;
+
+	wr_ic_cst (IDC_UNALL);
+	wr_ic_cst (IDC_INVALL);
+	wr_ic_cst (IDC_DISABLE);
+	__asm__ volatile ("isync");
+
+	while (!((m = rd_ic_cst ()) & IDC_CERR2)) {
+		wr_ic_adr (k);
+		wr_ic_cst (IDC_LDLCK);
+		__asm__ volatile ("isync");
+
+		lines++;
+		k += 0x10;				/* the number of bytes in a cacheline */
+	}
+
+	wr_ic_cst (IDC_UNALL);
+	wr_ic_cst (IDC_INVALL);
+
+	if (cacheon)
+		wr_ic_cst (IDC_ENABLE);
+	else
+		wr_ic_cst (IDC_DISABLE);
+
+	__asm__ volatile ("isync");
+
+	return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache                                                                */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB)              */
+/* the 860 P (plus) has 256 sets of 16 bytes in 2 ways (= 8 kB)              */
+/* call with cache disabled                                                  */
+
+int checkdcache (void)
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	u32 cacheon = rd_dc_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP860
+	u32 k = memctl->memc_br1 & ~0x00007fff;	/* probe in flash memoryarea */
+#else
+	u32 k = memctl->memc_br0 & ~0x00007fff;	/* probe in flash memoryarea */
+#endif
+	u32 m;
+	u32 lines = -1;
+
+	wr_dc_cst (IDC_UNALL);
+	wr_dc_cst (IDC_INVALL);
+	wr_dc_cst (IDC_DISABLE);
+
+	while (!((m = rd_dc_cst ()) & IDC_CERR2)) {
+		wr_dc_adr (k);
+		wr_dc_cst (IDC_LDLCK);
+		lines++;
+		k += 0x10;	/* the number of bytes in a cacheline */
+	}
+
+	wr_dc_cst (IDC_UNALL);
+	wr_dc_cst (IDC_INVALL);
+
+	if (cacheon)
+		wr_dc_cst (IDC_ENABLE);
+	else
+		wr_dc_cst (IDC_DISABLE);
+
+	return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+	uint i;
+	uint addr = 0;
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+	for (i = 0; i < size; i++) {
+		memctl->memc_mdr = table[i];	/* (16-15) */
+		memctl->memc_mcr = addr | upm;	/* (16-16) */
+		addr++;
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc,
+			  char *argv[])
+{
+	ulong msr, addr;
+
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+	immap->im_clkrst.car_plprcr |= PLPRCR_CSR;	/* Checkstop Reset enable */
+
+	/* Interrupts and MMU off */
+	__asm__ volatile ("mtspr    81, 0");
+	__asm__ volatile ("mfmsr    %0":"=r" (msr));
+
+	msr &= ~0x1030;
+	__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
+	 */
+#ifdef CFG_RESET_ADDRESS
+	addr = CFG_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CFG_MONITOR_BASE points to a RAM address, CFG_MONITOR_BASE
+	 * - sizeof (ulong) is usually a valid address. Better pick an address
+	 * known to be invalid on your system and assign it to CFG_RESET_ADDRESS.
+	 * "(ulong)-1" used to be a good choice for many systems...
+	 */
+	addr = CFG_MONITOR_BASE - sizeof (ulong);
+#endif
+	((void (*)(void)) addr) ();
+	return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ * See table 15-5 pp. 15-16, and SCCR[RTSEL] pp. 15-27.
+ */
+unsigned long get_tbclk (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile immap_t *immr = (volatile immap_t *) CFG_IMMR;
+	ulong oscclk, factor;
+
+	if (immr->im_clkrst.car_sccr & SCCR_TBS) {
+		return (gd->cpu_clk / 16);
+	}
+
+	factor = (((CFG_PLPRCR) & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT) + 1;
+
+	oscclk = gd->cpu_clk / factor;
+
+	if ((immr->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
+		return (oscclk / 4);
+	}
+	return (oscclk / 16);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts ();
+
+	reset_8xx_watchdog ((immap_t *) CFG_IMMR);
+	if (re_enable)
+		enable_interrupts ();
+}
+
+void reset_8xx_watchdog (volatile immap_t * immr)
+{
+# if defined(CONFIG_LWMON)
+	/*
+	 * The LWMON board uses a MAX6301 Watchdog
+	 * with the trigger pin connected to port PA.7
+	 *
+	 * (The old board version used a MAX706TESA Watchdog, which
+	 * had to be handled exactly the same.)
+	 */
+# define WATCHDOG_BIT	0x0100
+	immr->im_ioport.iop_papar &= ~(WATCHDOG_BIT);	/* GPIO     */
+	immr->im_ioport.iop_padir |= WATCHDOG_BIT;	/* Output   */
+	immr->im_ioport.iop_paodr &= ~(WATCHDOG_BIT);	/* active output */
+
+	immr->im_ioport.iop_padat ^= WATCHDOG_BIT;	/* Toggle WDI   */
+# else
+	/*
+	 * All other boards use the MPC8xx Internal Watchdog
+	 */
+	immr->im_siu_conf.sc_swsr = 0x556c;	/* write magic1 */
+	immr->im_siu_conf.sc_swsr = 0xaa39;	/* write magic2 */
+# endif /* CONFIG_LWMON */
+}
+
+#endif /* CONFIG_WATCHDOG */
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc8xx/fec.c b/cpu/mpc8xx/fec.c
new file mode 100644
index 0000000..d43dcaa
--- /dev/null
+++ b/cpu/mpc8xx/fec.c
@@ -0,0 +1,710 @@
+/*
+ * (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 <malloc.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+#undef	ET_DEBUG
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET)
+
+#ifdef CFG_DISCOVER_PHY
+#include <miiphy.h>
+static void mii_discover_phy(void);
+#endif
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH  1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 100
+
+#define PKT_MAXBUF_SIZE		1518
+#define PKT_MINBUF_SIZE		64
+#define PKT_MAXBLR_SIZE		1520
+
+
+static char txbuf[DBUF_LENGTH];
+
+static uint rxIdx;	/* index of the current RX buffer */
+static uint txIdx;	/* index of the current TX buffer */
+
+/*
+  * FEC Ethernet Tx and Rx buffer descriptors allocated at the
+  *  immr->udata_bd address on Dual-Port RAM
+  * Provide for Double Buffering
+  */
+
+typedef volatile struct CommonBufferDescriptor {
+    cbd_t rxbd[PKTBUFSRX];		/* Rx BD */
+    cbd_t txbd[TX_BUF_CNT];		/* Tx BD */
+} RTXBD;
+
+static RTXBD *rtx = NULL;
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length);
+static int fec_recv(struct eth_device* dev);
+static int fec_init(struct eth_device* dev, bd_t * bd);
+static void fec_halt(struct eth_device* dev);
+
+int fec_initialize(bd_t *bis)
+{
+	struct eth_device* dev;
+
+	dev = (struct eth_device*) malloc(sizeof *dev);
+
+	sprintf(dev->name, "FEC ETHERNET");
+	dev->iobase = 0;
+	dev->priv   = 0;
+	dev->init   = fec_init;
+	dev->halt   = fec_halt;
+	dev->send   = fec_send;
+	dev->recv   = fec_recv;
+
+	eth_register(dev);
+
+	return 1;
+}
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length)
+{
+	int j, rc;
+	volatile immap_t *immr = (immap_t *) CFG_IMMR;
+	volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+	/* section 16.9.23.3
+	 * Wait for ready
+	 */
+	j = 0;
+	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+		udelay(1);
+		j++;
+	}
+	if (j>=TOUT_LOOP) {
+		printf("TX not ready\n");
+	}
+
+	rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
+	rtx->txbd[txIdx].cbd_datlen  = length;
+	rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST;
+	__asm__ ("eieio");
+
+	/* Activate transmit Buffer Descriptor polling */
+	fecp->fec_x_des_active = 0x01000000;	/* Descriptor polling active	*/
+
+	j = 0;
+	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+#if defined(CONFIG_ICU862)
+		udelay(10);
+#else
+		udelay(1);
+#endif
+		j++;
+	}
+	if (j>=TOUT_LOOP) {
+		printf("TX timeout\n");
+	}
+#ifdef ET_DEBUG
+	printf("%s[%d] %s: cycles: %d    status: %x  retry cnt: %d\n",
+	__FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc,
+	(rtx->txbd[txIdx].cbd_sc & 0x003C)>>2);
+#endif
+	/* return only status bits */;
+	rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS);
+
+	txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+	return rc;
+}
+
+static int fec_recv(struct eth_device* dev)
+{
+	int length;
+	volatile immap_t *immr = (immap_t *) CFG_IMMR;
+	volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+   for (;;) {
+	/* section 16.9.23.2 */
+	if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+		length = -1;
+		break;     /* nothing received - leave for() loop */
+	}
+
+	length = rtx->rxbd[rxIdx].cbd_datlen;
+
+	if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
+#ifdef ET_DEBUG
+		printf("%s[%d] err: %x\n",
+		__FUNCTION__,__LINE__,rtx->rxbd[rxIdx].cbd_sc);
+#endif
+	} else {
+		/* Pass the packet up to the protocol layers. */
+		NetReceive(NetRxPackets[rxIdx], length - 4);
+	}
+
+	/* Give the buffer back to the FEC. */
+	rtx->rxbd[rxIdx].cbd_datlen = 0;
+
+	/* wrap around buffer index when necessary */
+	if ((rxIdx + 1) >= PKTBUFSRX) {
+		rtx->rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+		rxIdx = 0;
+	} else {
+		rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+		rxIdx++;
+	}
+
+	__asm__ ("eieio");
+
+	/* Try to fill Buffer Descriptors */
+	fecp->fec_r_des_active = 0x01000000;	/* Descriptor polling active	*/
+   }
+
+   return length;
+}
+
+/**************************************************************
+ *
+ * FEC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+#define	FEC_ECNTRL_PINMUX	0x00000004
+#define FEC_ECNTRL_ETHER_EN	0x00000002
+#define FEC_ECNTRL_RESET	0x00000001
+
+#define FEC_RCNTRL_BC_REJ	0x00000010
+#define FEC_RCNTRL_PROM		0x00000008
+#define FEC_RCNTRL_MII_MODE	0x00000004
+#define FEC_RCNTRL_DRT		0x00000002
+#define FEC_RCNTRL_LOOP		0x00000001
+
+#define FEC_TCNTRL_FDEN		0x00000004
+#define FEC_TCNTRL_HBC		0x00000002
+#define FEC_TCNTRL_GTS		0x00000001
+
+#define	FEC_RESET_DELAY		50
+
+static int fec_init(struct eth_device* dev, bd_t * bd)
+{
+
+	int i;
+	volatile immap_t *immr = (immap_t *) CFG_IMMR;
+	volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+#if defined(CONFIG_FADS) && defined(CONFIG_MPC860T)
+	/* configure FADS for fast (FEC) ethernet, half-duplex */
+	/* The LXT970 needs about 50ms to recover from reset, so
+	 * wait for it by discovering the PHY before leaving eth_init().
+	 */
+	{
+		volatile uint *bcsr4 = (volatile uint *) BCSR4;
+		*bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1))
+			| (BCSR4_FETHCFG0 | BCSR4_FETHFDE | BCSR4_FETHRST);
+
+		/* reset the LXT970 PHY */
+		*bcsr4 &= ~BCSR4_FETHRST;
+		udelay (10);
+		*bcsr4 |= BCSR4_FETHRST;
+		udelay (10);
+	}
+#endif
+	/* Whack a reset.
+	 * A delay is required between a reset of the FEC block and
+	 * initialization of other FEC registers because the reset takes
+	 * some time to complete. If you don't delay, subsequent writes
+	 * to FEC registers might get killed by the reset routine which is
+	 * still in progress.
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay (1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printf ("FEC_RESET_DELAY timeout\n");
+		return 0;
+	}
+
+	/* We use strictly polling mode only
+	 */
+	fecp->fec_imask = 0;
+
+	/* Clear any pending interrupt
+	 */
+	fecp->fec_ievent = 0xffc0;
+
+	/* No need to set the IVEC register */
+
+	/* Set station address
+	 */
+#define ea eth_get_dev()->enetaddr
+	fecp->fec_addr_low   =	(ea[0] << 24) | (ea[1] << 16) |
+				(ea[2] <<  8) | (ea[3]      ) ;
+	fecp->fec_addr_high  =	(ea[4] <<  8) | (ea[5]	    ) ;
+#undef ea
+
+	/* Clear multicast address hash table
+	 */
+	fecp->fec_hash_table_high = 0;
+	fecp->fec_hash_table_low  = 0;
+
+	/* Set maximum receive buffer size.
+	 */
+	fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+
+	/* Set maximum frame length
+	 */
+	fecp->fec_r_hash = PKT_MAXBUF_SIZE;
+
+	/*
+	 * Setup Buffers and Buffer Desriptors
+	 */
+	rxIdx = 0;
+	txIdx = 0;
+
+	if (!rtx) {
+#ifdef CFG_ALLOC_DPRAM
+	    rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + dpram_alloc_align(sizeof(RTXBD),8));
+#else
+	    rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
+#endif
+	}
+	/*
+	 * Setup Receiver Buffer Descriptors (13.14.24.18)
+	 * Settings:
+	 *     Empty, Wrap
+	 */
+	for (i = 0; i < PKTBUFSRX; i++) {
+		rtx->rxbd[i].cbd_sc      = BD_ENET_RX_EMPTY;
+		rtx->rxbd[i].cbd_datlen  = 0;	/* Reset */
+		rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+	}
+	rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+	/*
+	 * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+	 * Settings:
+	 *    Last, Tx CRC
+	 */
+	for (i = 0; i < TX_BUF_CNT; i++) {
+		rtx->txbd[i].cbd_sc      = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+		rtx->txbd[i].cbd_datlen  = 0;	/* Reset */
+		rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
+	}
+	rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+	/* Set receive and transmit descriptor base
+	 */
+	fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]);
+	fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]);
+
+	/* Enable MII mode
+	 */
+#if 0	/* Full duplex mode */
+	fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;
+	fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;
+#else	/* Half duplex mode */
+	fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
+	fecp->fec_x_cntrl = 0;
+#endif
+
+	/* Enable big endian and don't care about SDMA FC.
+	 */
+	fecp->fec_fun_code = 0x78000000;
+
+	/* Set MII speed to 2.5 MHz or slightly below.
+	 * According to the MPC860T (Rev. D) Fast ethernet controller user
+	 * manual (6.2.14),
+	 * the MII management interface clock must be less than or equal
+	 * to 2.5 MHz.
+	 * This MDC frequency is equal to system clock / (2 * MII_SPEED).
+	 * Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
+	 */
+	fecp->fec_mii_speed = ((bd->bi_busfreq + 4999999) / 5000000) << 1;
+
+#if !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
+	/* Configure all of port D for MII.
+	 */
+	immr->im_ioport.iop_pdpar = 0x1fff;
+
+	/* Bits moved from Rev. D onward */
+	if ((get_immr (0) & 0xffff) < 0x0501) {
+		immr->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
+	} else {
+		immr->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
+	}
+#else
+	/* Configure port A for MII.
+	*/
+
+#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY)
+
+	/* On the ICU862 board the MII-MDC pin is routed to PD8 pin
+	 * of CPU, so for this board we need to configure Utopia and
+	 * enable PD8 to MII-MDC function */
+	immr->im_ioport.iop_pdpar |= 0x4080;
+#endif
+
+	/* Has Utopia been configured? */
+	if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
+		/*
+		 * YES - Use MUXED mode for UTOPIA bus.
+		 * This frees Port A for use by MII (see 862UM table 41-6).
+		 */
+		immr->im_ioport.utmode &= ~0x80;
+	} else {
+		/*
+		 * NO - set SPLIT mode for UTOPIA bus.
+		 *
+		 * This doesn't really effect UTOPIA (which isn't
+		 * enabled anyway) but just tells the 862
+		 * to use port A for MII (see 862UM table 41-6).
+		 */
+		immr->im_ioport.utmode |= 0x80;
+	}
+#endif	/* !defined(CONFIG_ICU862) */
+
+	rxIdx = 0;
+	txIdx = 0;
+
+	/* Now enable the transmit and receive processing
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+
+#ifdef CFG_DISCOVER_PHY
+	/* wait for the PHY to wake up after reset
+	 */
+	mii_discover_phy();
+#endif
+
+	/* And last, try to fill Rx Buffer Descriptors */
+	fecp->fec_r_des_active = 0x01000000;	/* Descriptor polling active	*/
+
+	return 1;
+}
+
+
+
+static void fec_halt(struct eth_device* dev)
+{
+#if 0
+    volatile immap_t *immr = (immap_t *)CFG_IMMR;
+    immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+}
+
+#if 0
+void restart(void)
+{
+   volatile immap_t *immr = (immap_t *)CFG_IMMR;
+   immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+#endif
+
+#if defined(CFG_DISCOVER_PHY) || (CONFIG_COMMANDS & CFG_CMD_MII)
+
+static	int	phyaddr = -1;	/* didn't find a PHY yet */
+static	uint	phytype;
+
+/* Make MII read/write commands for the FEC.
+*/
+
+#define mk_mii_read(ADDR, REG)	(0x60020000 | ((ADDR << 23) | \
+						(REG & 0x1f) << 18))
+
+#define mk_mii_write(ADDR, REG, VAL)	(0x50020000 | ((ADDR << 23) | \
+						(REG & 0x1f) << 18) | \
+						(VAL & 0xffff))
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
+#define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
+#define FEC_ENET_BABT	((uint)0x20000000)	/* Babbling transmitter */
+#define FEC_ENET_GRA	((uint)0x10000000)	/* Graceful stop complete */
+#define FEC_ENET_TXF	((uint)0x08000000)	/* Full frame transmitted */
+#define FEC_ENET_TXB	((uint)0x04000000)	/* A buffer was transmitted */
+#define FEC_ENET_RXF	((uint)0x02000000)	/* Full frame received */
+#define FEC_ENET_RXB	((uint)0x01000000)	/* A buffer was received */
+#define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
+#define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
+
+/* PHY identification
+ */
+#define PHY_ID_LXT970		0x78100000	/* LXT970 */
+#define PHY_ID_LXT971		0x001378e0	/* LXT971 and 972 */
+#define PHY_ID_82555		0x02a80150	/* Intel 82555 */
+#define PHY_ID_QS6612		0x01814400	/* QS6612 */
+#define PHY_ID_AMD79C784	0x00225610	/* AMD 79C784 */
+#define PHY_ID_LSI80225		0x0016f870	/* LSI 80225 */
+#define PHY_ID_LSI80225B	0x0016f880	/* LSI 80225/B */
+
+
+/* send command to phy using mii, wait for result */
+static uint
+mii_send(uint mii_cmd)
+{
+	uint mii_reply;
+	volatile fec_t	*ep;
+
+	ep = &(((immap_t *)CFG_IMMR)->im_cpm.cp_fec);
+
+	ep->fec_mii_data = mii_cmd;	/* command to phy */
+
+	/* wait for mii complete */
+	while (!(ep->fec_ievent & FEC_ENET_MII))
+		;	/* spin until done */
+	mii_reply = ep->fec_mii_data;		/* result from phy */
+	ep->fec_ievent = FEC_ENET_MII;		/* clear MII complete */
+#if 0
+	printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
+		__FILE__,__LINE__,__FUNCTION__,mii_cmd,mii_reply);
+#endif
+	return (mii_reply & 0xffff);		/* data read from phy */
+}
+#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */
+
+#if defined(CFG_DISCOVER_PHY)
+static void
+mii_discover_phy(void)
+{
+#define MAX_PHY_PASSES 11
+	uint phyno;
+	int  pass;
+
+	phyaddr = -1;	/* didn't find a PHY yet */
+	for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
+		if (pass > 1) {
+			/* PHY may need more time to recover from reset.
+			 * The LXT970 needs 50ms typical, no maximum is
+			 * specified, so wait 10ms before try again.
+			 * With 11 passes this gives it 100ms to wake up.
+			 */
+			udelay(10000);	/* wait 10ms */
+		}
+		for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
+			phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1));
+#ifdef ET_DEBUG
+			printf("PHY type 0x%x pass %d type ", phytype, pass);
+#endif
+			if (phytype != 0xffff) {
+				phyaddr = phyno;
+				phytype <<= 16;
+				phytype |= mii_send(mk_mii_read(phyno,
+								PHY_PHYIDR2));
+
+#ifdef ET_DEBUG
+				printf("PHY @ 0x%x pass %d type ",phyno,pass);
+				switch (phytype & 0xfffffff0) {
+				case PHY_ID_LXT970:
+					printf("LXT970\n");
+					break;
+				case PHY_ID_LXT971:
+					printf("LXT971\n");
+					break;
+				case PHY_ID_82555:
+					printf("82555\n");
+					break;
+				case PHY_ID_QS6612:
+					printf("QS6612\n");
+					break;
+				case PHY_ID_AMD79C784:
+					printf("AMD79C784\n");
+					break;
+				case PHY_ID_LSI80225B:
+					printf("LSI L80225/B\n");
+					break;
+				default:
+					printf("0x%08x\n", phytype);
+					break;
+				}
+#endif
+			}
+		}
+	}
+	if (phyaddr < 0) {
+		printf("No PHY device found.\n");
+	}
+}
+#endif	/* CFG_DISCOVER_PHY */
+
+#if (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)
+
+static int mii_init_done = 0;
+
+/****************************************************************************
+ * mii_init -- Initialize the MII for MII command without ethernet
+ * This function is a subset of eth_init
+ ****************************************************************************
+ */
+void mii_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	bd_t *bd = gd->bd;
+
+	volatile immap_t *immr = (immap_t *) CFG_IMMR;
+	volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+	int i;
+
+	if (mii_init_done != 0) {
+		return;
+	}
+
+	/* Whack a reset.
+	 * A delay is required between a reset of the FEC block and
+	 * initialization of other FEC registers because the reset takes
+	 * some time to complete. If you don't delay, subsequent writes
+	 * to FEC registers might get killed by the reset routine which is
+	 * still in progress.
+	 */
+
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay (1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printf ("FEC_RESET_DELAY timeout\n");
+		return;
+	}
+
+	/* We use strictly polling mode only
+	 */
+	fecp->fec_imask = 0;
+
+	/* Clear any pending interrupt
+	 */
+	fecp->fec_ievent = 0xffc0;
+
+	/* Set MII speed to 2.5 MHz or slightly below.
+	 * According to the MPC860T (Rev. D) Fast ethernet controller user
+	 * manual (6.2.14),
+	 * the MII management interface clock must be less than or equal
+	 * to 2.5 MHz.
+	 * This MDC frequency is equal to system clock / (2 * MII_SPEED).
+	 * Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
+	 */
+	fecp->fec_mii_speed = ((bd->bi_busfreq + 4999999) / 5000000) << 1;
+
+#if !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
+	/* Configure all of port D for MII.
+	 */
+	immr->im_ioport.iop_pdpar = 0x1fff;
+
+	/* Bits moved from Rev. D onward */
+	if ((get_immr (0) & 0xffff) < 0x0501) {
+		immr->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
+	} else {
+		immr->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
+	}
+#else
+	/* Configure port A for MII.
+	*/
+
+#if defined(CONFIG_ICU862)
+
+	/* On the ICU862 board the MII-MDC pin is routed to PD8 pin
+	 * of CPU, so for this board we need to configure Utopia and
+	 * enable PD8 to MII-MDC function */
+	immr->im_ioport.iop_pdpar |= 0x4080;
+#endif
+
+	/* Has Utopia been configured? */
+	if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
+		/*
+		 * YES - Use MUXED mode for UTOPIA bus.
+		 * This frees Port A for use by MII (see 862UM table 41-6).
+		 */
+		immr->im_ioport.utmode &= ~0x80;
+	} else {
+		/*
+		 * NO - set SPLIT mode for UTOPIA bus.
+		 *
+		 * This doesn't really effect UTOPIA (which isn't
+		 * enabled anyway) but just tells the 862
+		 * to use port A for MII (see 862UM table 41-6).
+		 */
+		immr->im_ioport.utmode |= 0x80;
+	}
+#endif	/* !defined(CONFIG_ICU862) */
+	/* Now enable the transmit and receive processing
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+
+	mii_init_done = 1;
+}
+/*****************************************************************************
+ * Read and write a MII PHY register, routines used by MII Utilities
+ *
+ * FIXME: These routines are expected to return 0 on success, but mii_send
+ *	  does _not_ return an error code. Maybe 0xFFFF means error, i.e.
+ *	  no PHY connected...
+ *	  For now always return 0.
+ * FIXME: These routines only work after calling eth_init() at least once!
+ *	  Otherwise they hang in mii_send() !!! Sorry!
+ *****************************************************************************/
+
+int miiphy_read(unsigned char addr, unsigned char  reg, unsigned short *value)
+{
+	short rdreg;    /* register working value */
+
+#ifdef MII_DEBUG
+	printf ("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
+#endif
+	rdreg = mii_send(mk_mii_read(addr, reg));
+
+	*value = rdreg;
+
+#ifdef MII_DEBUG
+	printf ("0x%04x\n", *value);
+#endif
+
+	return 0;
+}
+
+int miiphy_write(unsigned char  addr, unsigned char  reg, unsigned short value)
+{
+	short rdreg;    /* register working value */
+
+#ifdef MII_DEBUG
+	printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+#endif
+
+	rdreg = mii_send(mk_mii_write(addr, reg, value));
+
+#ifdef MII_DEBUG
+	printf ("0x%04x\n", value);
+#endif
+
+	return 0;
+}
+#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)*/
+
+#endif	/* CFG_CMD_NET, FEC_ENET */
diff --git a/cpu/mpc8xx/spi.c b/cpu/mpc8xx/spi.c
new file mode 100644
index 0000000..f04d88e
--- /dev/null
+++ b/cpu/mpc8xx/spi.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2001 Navin Boppuri / Prashant Patel
+ *	<nboppuri@trinetcommunication.com>,
+ *	<pmpatel@trinetcommunication.com>
+ * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
+ * Copyright (c) 2001 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
+ */
+
+/*
+ * MPC8xx CPM SPI interface.
+ *
+ * Parts of this code are probably not portable and/or specific to
+ * the board which I used for the tests. Please send fixes/complaints
+ * to wd@denx.de
+ *
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <net.h>
+
+#if (defined(CONFIG_SPI)) || (CONFIG_POST & CFG_POST_SPI)
+
+/* Warning:
+ * You cannot enable DEBUG for early system initalization, i. e. when
+ * this driver is used to read environment parameters like "baudrate"
+ * from EEPROM which are used to initialize the serial port which is
+ * needed to print the debug messages...
+ */
+#undef	DEBUG
+
+#define SPI_EEPROM_WREN		0x06
+#define SPI_EEPROM_RDSR		0x05
+#define SPI_EEPROM_READ		0x03
+#define SPI_EEPROM_WRITE	0x02
+
+/* ---------------------------------------------------------------
+ * Offset for initial SPI buffers in DPRAM:
+ * We need a 520 byte scratch DPRAM area to use at an early stage.
+ * It is used between the two initialization calls (spi_init_f()
+ * and spi_init_r()).
+ * The value 0xb00 makes it far enough from the start of the data
+ * area (as well as from the stack pointer).
+ * --------------------------------------------------------------- */
+#ifndef	CFG_SPI_INIT_OFFSET
+#define	CFG_SPI_INIT_OFFSET	0xB00
+#endif
+
+#ifdef	DEBUG
+
+#define	DPRINT(a)	printf a;
+/* -----------------------------------------------
+ * Helper functions to peek into tx and rx buffers
+ * ----------------------------------------------- */
+static const char * const hex_digit = "0123456789ABCDEF";
+
+static char quickhex (int i)
+{
+	return hex_digit[i];
+}
+
+static void memdump (void *pv, int num)
+{
+	int i;
+	unsigned char *pc = (unsigned char *) pv;
+
+	for (i = 0; i < num; i++)
+		printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
+	printf ("\t");
+	for (i = 0; i < num; i++)
+		printf ("%c", isprint (pc[i]) ? pc[i] : '.');
+	printf ("\n");
+}
+#else	/* !DEBUG */
+
+#define	DPRINT(a)
+
+#endif	/* DEBUG */
+
+/* -------------------
+ * Function prototypes
+ * ------------------- */
+void spi_init (void);
+
+ssize_t spi_read (uchar *, int, uchar *, int);
+ssize_t spi_write (uchar *, int, uchar *, int);
+ssize_t spi_xfer (size_t);
+
+/* -------------------
+ * Variables
+ * ------------------- */
+
+#define MAX_BUFFER	0x104
+
+/* ----------------------------------------------------------------------
+ * Initially we place the RX and TX buffers at a fixed location in DPRAM!
+ * ---------------------------------------------------------------------- */
+static uchar *rxbuf =
+  (uchar *)&((cpm8xx_t *)&((immap_t *)CFG_IMMR)->im_cpm)->cp_dpmem
+			[CFG_SPI_INIT_OFFSET];
+static uchar *txbuf =
+  (uchar *)&((cpm8xx_t *)&((immap_t *)CFG_IMMR)->im_cpm)->cp_dpmem
+			[CFG_SPI_INIT_OFFSET+MAX_BUFFER];
+
+/* **************************************************************************
+ *
+ *  Function:    spi_init_f
+ *
+ *  Description: Init SPI-Controller (ROM part)
+ *
+ *  return:      ---
+ *
+ * *********************************************************************** */
+void spi_init_f (void)
+{
+	unsigned int dpaddr;
+
+	volatile spi_t *spi;
+	volatile immap_t *immr;
+	volatile cpic8xx_t *cpi;
+	volatile cpm8xx_t *cp;
+	volatile iop8xx_t *iop;
+	volatile cbd_t *tbdf, *rbdf;
+
+	immr = (immap_t *)  CFG_IMMR;
+	cpi  = (cpic8xx_t *)&immr->im_cpic;
+	iop  = (iop8xx_t *) &immr->im_ioport;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CFG_SPI_UCODE_PATCH
+	spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+	spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+	/* Disable relocation */
+	spi->spi_rpbase = 0;
+#endif
+
+/* 1 */
+	/* ------------------------------------------------
+	 * Initialize Port B SPI pins -> page 34-8 MPC860UM
+	 * (we are only in Master Mode !)
+	 * ------------------------------------------------ */
+
+	/* --------------------------------------------
+	 * GPIO or per. Function
+	 * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
+	 * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
+	 * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
+	 * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
+	 * -------------------------------------------- */
+	cp->cp_pbpar |=  0x0000000E;	/* set  bits	*/
+	cp->cp_pbpar &= ~0x00000001;	/* reset bit	*/
+
+	/* ----------------------------------------------
+	 * In/Out or per. Function 0/1
+	 * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
+	 * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
+	 * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
+	 * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
+	 * ---------------------------------------------- */
+	cp->cp_pbdir |= 0x0000000F;
+
+	/* ----------------------------------------------
+	 * open drain or active output
+	 * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
+	 * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
+	 * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
+	 * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
+	 * ---------------------------------------------- */
+
+	cp->cp_pbodr |=  0x00000008;
+	cp->cp_pbodr &= ~0x00000007;
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero
+	 */
+	spi->spi_rstate	= 0;
+	spi->spi_rdp	= 0;
+	spi->spi_rbptr	= 0;
+	spi->spi_rbc	= 0;
+	spi->spi_rxtmp	= 0;
+	spi->spi_tstate	= 0;
+	spi->spi_tdp	= 0;
+	spi->spi_tbptr	= 0;
+	spi->spi_tbc	= 0;
+	spi->spi_txtmp	= 0;
+
+	/* Allocate space for one transmit and one receive buffer
+	 * descriptor in the DP ram
+	 */
+#ifdef CFG_ALLOC_DPRAM
+	dpaddr = dpram_alloc_align (sizeof(cbd_t)*2, 8);
+#else
+	dpaddr = CPM_SPI_BASE;
+#endif
+
+/* 3 */
+	/* Set up the SPI parameters in the parameter ram */
+	spi->spi_rbase = dpaddr;
+	spi->spi_tbase = dpaddr + sizeof (cbd_t);
+
+	/***********IMPORTANT******************/
+
+        /*
+         * Setting transmit and receive buffer descriptor pointers
+         * initially to rbase and tbase. Only the microcode patches
+         * documentation talks about initializing this pointer. This
+         * is missing from the sample I2C driver. If you dont
+         * initialize these pointers, the kernel hangs.
+	 */
+	spi->spi_rbptr = spi->spi_rbase;
+	spi->spi_tbptr = spi->spi_tbase;
+
+/* 4 */
+#ifdef CFG_SPI_UCODE_PATCH
+	/*
+	 *  Initialize required parameters if using microcode patch.
+	 */
+	spi->spi_rstate = 0;
+	spi->spi_tstate = 0;
+#else
+	/* Init SPI Tx + Rx Parameters */
+	while (cp->cp_cpcr & CPM_CR_FLG)
+		;
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG)
+		;
+#endif	/* CFG_SPI_UCODE_PATCH */
+
+/* 5 */
+	/* Set SDMA configuration register */
+	immr->im_siu_conf.sc_sdcr = 0x0001;
+
+/* 6 */
+	/* Set to big endian. */
+	spi->spi_tfcr = SMC_EB;
+	spi->spi_rfcr = SMC_EB;
+
+/* 7 */
+	/* Set maximum receive size. */
+	spi->spi_mrblr = MAX_BUFFER;
+
+/* 8 + 9 */
+	/* tx and rx buffer descriptors */
+	tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+	rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+	tbdf->cbd_sc &= ~BD_SC_READY;
+	rbdf->cbd_sc &= ~BD_SC_EMPTY;
+
+	/* Set the bd's rx and tx buffer address pointers */
+	rbdf->cbd_bufaddr = (ulong) rxbuf;
+	tbdf->cbd_bufaddr = (ulong) txbuf;
+
+/* 10 + 11 */
+	cp->cp_spim = 0;			/* Mask  all SPI events */
+	cp->cp_spie = SPI_EMASK;		/* Clear all SPI events	*/
+
+	return;
+}
+
+/* **************************************************************************
+ *
+ *  Function:    spi_init_r
+ *
+ *  Description: Init SPI-Controller (RAM part) -
+ *		 The malloc engine is ready and we can move our buffers to
+ *		 normal RAM
+ *
+ *  return:      ---
+ *
+ * *********************************************************************** */
+void spi_init_r (void)
+{
+	volatile cpm8xx_t *cp;
+	volatile spi_t *spi;
+	volatile immap_t *immr;
+	volatile cbd_t *tbdf, *rbdf;
+
+	immr = (immap_t *)  CFG_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CFG_SPI_UCODE_PATCH
+	spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+	spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+	/* Disable relocation */
+	spi->spi_rpbase = 0;
+#endif
+
+	/* tx and rx buffer descriptors */
+	tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+	rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+	/* Allocate memory for RX and TX buffers */
+	rxbuf = (uchar *) malloc (MAX_BUFFER);
+	txbuf = (uchar *) malloc (MAX_BUFFER);
+
+	rbdf->cbd_bufaddr = (ulong) rxbuf;
+	tbdf->cbd_bufaddr = (ulong) txbuf;
+
+	return;
+}
+
+/****************************************************************************
+ *  Function:    spi_write
+ **************************************************************************** */
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+	int i;
+
+	memset(rxbuf, 0, MAX_BUFFER);
+	memset(txbuf, 0, MAX_BUFFER);
+	*txbuf = SPI_EEPROM_WREN;		/* write enable		*/
+	spi_xfer(1);
+	memcpy(txbuf, addr, alen);
+	*txbuf = SPI_EEPROM_WRITE;		/* WRITE memory array	*/
+	memcpy(alen + txbuf, buffer, len);
+	spi_xfer(alen + len);
+						/* ignore received data	*/
+	for (i = 0; i < 1000; i++) {
+		*txbuf = SPI_EEPROM_RDSR;	/* read status		*/
+		txbuf[1] = 0;
+		spi_xfer(2);
+		if (!(rxbuf[1] & 1)) {
+			break;
+		}
+		udelay(1000);
+	}
+	if (i >= 1000) {
+		printf ("*** spi_write: Time out while writing!\n");
+	}
+
+	return len;
+}
+
+/****************************************************************************
+ *  Function:    spi_read
+ **************************************************************************** */
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+	memset(rxbuf, 0, MAX_BUFFER);
+	memset(txbuf, 0, MAX_BUFFER);
+	memcpy(txbuf, addr, alen);
+	*txbuf = SPI_EEPROM_READ;		/* READ memory array	*/
+
+	/*
+	 * There is a bug in 860T (?) that cuts the last byte of input
+	 * if we're reading into DPRAM. The solution we choose here is
+	 * to always read len+1 bytes (we have one extra byte at the
+	 * end of the buffer).
+	 */
+	spi_xfer(alen + len + 1);
+	memcpy(buffer, alen + rxbuf, len);
+
+	return len;
+}
+
+/****************************************************************************
+ *  Function:    spi_xfer
+ **************************************************************************** */
+ssize_t spi_xfer (size_t count)
+{
+	volatile immap_t *immr;
+	volatile cpm8xx_t *cp;
+	volatile spi_t *spi;
+	cbd_t *tbdf, *rbdf;
+	ushort loop;
+	int tm;
+
+	DPRINT (("*** spi_xfer entered ***\n"));
+
+	immr = (immap_t *) CFG_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CFG_SPI_UCODE_PATCH
+	spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+	spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+	/* Disable relocation */
+	spi->spi_rpbase = 0;
+#endif
+
+	tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+	rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+	/* Set CS for device */
+	cp->cp_pbdat &= ~0x0001;
+
+	/* Setting tx bd status and data length */
+	tbdf->cbd_sc  = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
+	tbdf->cbd_datlen = count;
+
+	DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
+							tbdf->cbd_datlen));
+
+	/* Setting rx bd status and data length */
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	rbdf->cbd_datlen = 0;	 /* rx length has no significance */
+
+	loop = cp->cp_spmode & SPMODE_LOOP;
+	cp->cp_spmode = /*SPMODE_DIV16	|*/	/* BRG/16 mode not used here */
+			loop		|
+			SPMODE_REV	|
+			SPMODE_MSTR	|
+			SPMODE_EN	|
+			SPMODE_LEN(8)	|	/* 8 Bits per char */
+			SPMODE_PM(0x8) ;	/* medium speed */
+	cp->cp_spim = 0;			/* Mask  all SPI events */
+	cp->cp_spie = SPI_EMASK;		/* Clear all SPI events	*/
+
+	/* start spi transfer */
+	DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+	cp->cp_spcom |= SPI_STR;		/* Start transmit */
+
+	/* --------------------------------
+	 * Wait for SPI transmit to get out
+	 * or time out (1 second = 1000 ms)
+	 * -------------------------------- */
+	for (tm=0; tm<1000; ++tm) {
+		if (cp->cp_spie & SPI_TXB) {	/* Tx Buffer Empty */
+			DPRINT (("*** spi_xfer: Tx buffer empty\n"));
+			break;
+		}
+		if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
+			DPRINT (("*** spi_xfer: Tx BD done\n"));
+			break;
+		}
+		udelay (1000);
+	}
+	if (tm >= 1000) {
+		printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
+	}
+	DPRINT (("*** spi_xfer: ... transfer ended\n"));
+
+#ifdef	DEBUG
+	printf ("\nspi_xfer: txbuf after xfer\n");
+	memdump ((void *) txbuf, 16);	/* dump of txbuf before transmit */
+	printf ("spi_xfer: rxbuf after xfer\n");
+	memdump ((void *) rxbuf, 16);	/* dump of rxbuf after transmit */
+	printf ("\n");
+#endif
+
+	/* Clear CS for device */
+	cp->cp_pbdat |= 0x0001;
+
+	return count;
+}
+#endif	/* CONFIG_SPI || (CONFIG_POST & CFG_POST_SPI) */
+
+/*
+ * SPI test
+ *
+ * The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
+ * The interface is configured accordingly and several packets
+ * are transfered. The configurable test parameters are:
+ *   TEST_MIN_LENGTH - minimum size of packet to transfer
+ *   TEST_MAX_LENGTH - maximum size of packet to transfer
+ *   TEST_NUM - number of tests
+ */
+
+#if CONFIG_POST & CFG_POST_SPI
+
+#define TEST_MIN_LENGTH		1
+#define TEST_MAX_LENGTH		MAX_BUFFER
+#define TEST_NUM		1
+
+static void packet_fill (char * packet, int length)
+{
+	char c = (char) length;
+	int i;
+
+	for (i = 0; i < length; i++)
+	{
+	    packet[i] = c++;
+	}
+}
+
+static int packet_check (char * packet, int length)
+{
+	char c = (char) length;
+	int i;
+
+	for (i = 0; i < length; i++)
+	{
+	    if (packet[i] != c++) return -1;
+	}
+
+	return 0;
+}
+
+int spi_post_test (int flags)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int res = -1;
+	volatile immap_t *immr = (immap_t *) CFG_IMMR;
+	volatile cpm8xx_t *cp = (cpm8xx_t *) &immr->im_cpm;
+	int i;
+	int l;
+
+	spi_init_f();
+	spi_init_r();
+
+	cp->cp_spmode |= SPMODE_LOOP;
+
+	for (i = 0; i < TEST_NUM; i++)
+	{
+	    for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8)
+	    {
+		packet_fill(txbuf, l);
+
+		spi_xfer(l);
+
+		if (packet_check(rxbuf, l) < 0)
+		{
+		    goto Done;
+		}
+	    }
+	}
+
+	res = 0;
+
+	Done:
+
+	cp->cp_spmode &= ~SPMODE_LOOP;
+
+	/*
+	 * SCC2 Ethernet parameter RAM space overlaps
+	 * the SPI parameter RAM space. So we need to restore
+	 * the SCC2 configuration if it is used by UART or Ethernet.
+	 */
+
+#if defined(CONFIG_8xx_CONS_SCC2)
+	serial_init();
+#endif
+
+#if defined(SCC_ENET) && (SCC_ENET == 1)
+	eth_init(gd->bd);
+#endif
+
+	if (res != 0)
+	{
+		post_log("SPI test failed\n");
+	}
+
+	return res;
+}
+#endif	/* CONFIG_POST & CFG_POST_SPI */
diff --git a/cpu/ppc4xx/405gp_enet.c b/cpu/ppc4xx/405gp_enet.c
new file mode 100644
index 0000000..49e9e42
--- /dev/null
+++ b/cpu/ppc4xx/405gp_enet.c
@@ -0,0 +1,867 @@
+/*-----------------------------------------------------------------------------+
+ *
+ *       This source code has been made available to you by IBM on an AS-IS
+ *       basis.  Anyone receiving this source is licensed under IBM
+ *       copyrights to use it in any way he or she deems fit, including
+ *       copying it, modifying it, compiling it, and redistributing it either
+ *       with or without modifications.  No license under IBM patents or
+ *       patent applications is to be implied by the copyright license.
+ *
+ *       Any user of this software should understand that IBM cannot provide
+ *       technical support for this software and will not be responsible for
+ *       any consequences resulting from the use of this software.
+ *
+ *       Any person who transfers this source code or any derivative work
+ *       must include the IBM copyright notice, this paragraph, and the
+ *       preceding two paragraphs in the transferred software.
+ *
+ *       COPYRIGHT   I B M   CORPORATION 1995
+ *       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+ *
+ *  File Name:  enetemac.c
+ *
+ *  Function:   Device driver for the ethernet EMAC3 macro on the 405GP.
+ *
+ *  Author:     Mark Wisner
+ *
+ *  Change Activity-
+ *
+ *  Date        Description of Change                                       BY
+ *  ---------   ---------------------                                       ---
+ *  05-May-99   Created                                                     MKW
+ *  27-Jun-99   Clean up                                                    JWB
+ *  16-Jul-99   Added MAL error recovery and better IP packet handling      MKW
+ *  29-Jul-99   Added Full duplex support                                   MKW
+ *  06-Aug-99   Changed names for Mal CR reg                                MKW
+ *  23-Aug-99   Turned off SYE when running at 10Mbs                        MKW
+ *  24-Aug-99   Marked descriptor empty after call_xlc                      MKW
+ *  07-Sep-99   Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16     MCG
+ *              to avoid chaining maximum sized packets. Push starting
+ *              RX descriptor address up to the next cache line boundary.
+ *  16-Jan-00   Added support for booting with IP of 0x0                    MKW
+ *  15-Mar-00   Updated enetInit() to enable broadcast addresses in the
+ *	        EMAC_RXM register.                                          JWB
+ *  12-Mar-01   anne-sophie.harnois@nextream.fr
+ *               - Variables are compatible with those already defined in
+ *                include/net.h
+ *              - Receive buffer descriptor ring is used to send buffers
+ *                to the user
+ *              - Info print about send/received/handled packet number if
+ *                INFO_405_ENET is set
+ *  17-Apr-01   stefan.roese@esd-electronics.com
+ *              - MAL reset in "eth_halt" included
+ *              - Enet speed and duplex output now in one line
+ *  08-May-01   stefan.roese@esd-electronics.com
+ *              - MAL error handling added (eth_init called again)
+ *  13-Nov-01   stefan.roese@esd-electronics.com
+ *              - Set IST bit in EMAC_M1 reg upon 100MBit or full duplex
+ *  04-Jan-02   stefan.roese@esd-electronics.com
+ *              - Wait for PHY auto negotiation to complete added
+ *  06-Feb-02   stefan.roese@esd-electronics.com
+ *              - Bug fixed in waiting for auto negotiation to complete
+ *  26-Feb-02   stefan.roese@esd-electronics.com
+ *              - rx and tx buffer descriptors now allocated (no fixed address
+ *                used anymore)
+ *  17-Jun-02   stefan.roese@esd-electronics.com
+ *              - MAL error debug printf 'M' removed (rx de interrupt may
+ *                occur upon many incoming packets with only 4 rx buffers).
+ *-----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ppc4xx.h>
+#include <commproc.h>
+#include <405gp_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+#include <net.h>
+#include <malloc.h>
+#include "vecnum.h"
+
+#if defined(CONFIG_405GP) || defined(CONFIG_440)
+
+#define EMAC_RESET_TIMEOUT 1000	/* 1000 ms reset timeout */
+#define PHY_AUTONEGOTIATE_TIMEOUT 2000	/* 2000 ms autonegotiate timeout */
+
+#define NUM_TX_BUFF 1
+/* AS.HARNOIS
+ * Use PKTBUFSRX (include/net.h) instead of setting NUM_RX_BUFF again
+ * These both variables are used to define the same thing!
+ * #define NUM_RX_BUFF 4
+ */
+#define NUM_RX_BUFF PKTBUFSRX
+
+/* Ethernet Transmit and Receive Buffers */
+/* AS.HARNOIS
+ * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from
+ * PKTSIZE and PKTSIZE_ALIGN (include/net.h)
+ */
+#define ENET_MAX_MTU           PKTSIZE
+#define ENET_MAX_MTU_ALIGNED   PKTSIZE_ALIGN
+
+static char *txbuf_ptr;
+
+/* define the number of channels implemented */
+#define EMAC_RXCHL      1
+#define EMAC_TXCHL      1
+
+/*-----------------------------------------------------------------------------+
+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
+ * Interrupt Controller).
+ *-----------------------------------------------------------------------------*/
+#define MAL_UIC_ERR ( UIC_MAL_SERR | UIC_MAL_TXDE  | UIC_MAL_RXDE)
+#define MAL_UIC_DEF  (UIC_MAL_RXEOB | MAL_UIC_ERR)
+#define EMAC_UIC_DEF UIC_ENET
+
+/*-----------------------------------------------------------------------------+
+ * Global variables. TX and RX descriptors and buffers.
+ *-----------------------------------------------------------------------------*/
+static volatile mal_desc_t *tx;
+static volatile mal_desc_t *rx;
+static mal_desc_t *alloc_tx_buf = NULL;
+static mal_desc_t *alloc_rx_buf = NULL;
+
+/* IER globals */
+static unsigned long emac_ier;
+static unsigned long mal_ier;
+
+
+/* Statistic Areas */
+#define MAX_ERR_LOG 10
+struct emac_stats {
+	int data_len_err;
+	int rx_frames;
+	int rx;
+	int rx_prot_err;
+};
+
+static struct stats {			/* Statistic Block */
+	struct emac_stats emac;
+	int int_err;
+	short tx_err_log[MAX_ERR_LOG];
+	short rx_err_log[MAX_ERR_LOG];
+} stats;
+
+static int first_init = 0;
+
+static int tx_err_index = 0;	/* Transmit Error Index for tx_err_log */
+static int rx_err_index = 0;	/* Receive Error Index for rx_err_log */
+
+static int rx_slot = 0;			/* MAL Receive Slot */
+static int rx_i_index = 0;		/* Receive Interrupt Queue Index */
+static int rx_u_index = 0;		/* Receive User Queue Index */
+static int rx_ready[NUM_RX_BUFF];	/* Receive Ready Queue */
+
+static int tx_slot = 0;			/* MAL Transmit Slot */
+static int tx_i_index = 0;		/* Transmit Interrupt Queue Index */
+static int tx_u_index = 0;		/* Transmit User Queue Index */
+static int tx_run[NUM_TX_BUFF];	/* Transmit Running Queue */
+
+#undef INFO_405_ENET 1
+#ifdef INFO_405_ENET
+static int packetSent = 0;
+static int packetReceived = 0;
+static int packetHandled = 0;
+#endif
+
+static char emac_hwd_addr[ENET_ADDR_LENGTH];
+
+static bd_t *bis_save = NULL;	/* for eth_init upon mal error */
+
+static int is_receiving = 0;	/* sync with eth interrupt */
+static int print_speed = 1;	/* print speed message upon start */
+
+static void enet_rcv (unsigned long malisr);
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes and externals.
+ *-----------------------------------------------------------------------------*/
+void mal_err (unsigned long isr, unsigned long uic, unsigned long mal_def,
+	      unsigned long mal_errr);
+void emac_err (unsigned long isr);
+
+
+void eth_halt (void)
+{
+	mtdcr (malier, 0x00000000);	/* disable mal interrupts */
+	out32 (EMAC_IER, 0x00000000);	/* disable emac interrupts */
+
+	/* 1st reset MAL */
+	mtdcr (malmcr, MAL_CR_MMSR);
+
+	/* wait for reset */
+	while (mfdcr (malmcr) & MAL_CR_MMSR) {
+	};
+
+	/* EMAC RESET */
+	out32 (EMAC_M0, EMAC_M0_SRST);
+
+	print_speed = 1;		/* print speed message again next time */
+}
+
+
+int eth_init (bd_t * bis)
+{
+	int i;
+	unsigned long reg;
+	unsigned long msr;
+	unsigned long speed;
+	unsigned long duplex;
+	unsigned mode_reg;
+	unsigned short reg_short;
+
+	msr = mfmsr ();
+	mtmsr (msr & ~(MSR_EE));	/* disable interrupts */
+
+#ifdef INFO_405_ENET
+	/* AS.HARNOIS
+	 * We should have :
+	 * packetHandled <=  packetReceived <= packetHandled+PKTBUFSRX
+         * In the most cases packetHandled = packetReceived, but it
+         * is possible that new packets (without relationship with
+         * current transfer) have got the time to arrived before
+         * netloop calls eth_halt
+	 */
+	printf ("About preceeding transfer:\n"
+		"- Sent packet number %d\n"
+		"- Received packet number %d\n"
+		"- Handled packet number %d\n",
+		packetSent, packetReceived, packetHandled);
+	packetSent = 0;
+	packetReceived = 0;
+	packetHandled = 0;
+#endif
+
+	/* MAL RESET */
+	mtdcr (malmcr, MAL_CR_MMSR);
+	/* wait for reset */
+	while (mfdcr (malmcr) & MAL_CR_MMSR) {
+	};
+
+	tx_err_index = 0;		/* Transmit Error Index for tx_err_log */
+	rx_err_index = 0;		/* Receive Error Index for rx_err_log */
+
+	rx_slot = 0;			/* MAL Receive Slot */
+	rx_i_index = 0;			/* Receive Interrupt Queue Index */
+	rx_u_index = 0;			/* Receive User Queue Index */
+
+	tx_slot = 0;			/* MAL Transmit Slot */
+	tx_i_index = 0;			/* Transmit Interrupt Queue Index */
+	tx_u_index = 0;			/* Transmit User Queue Index */
+
+#if defined(CONFIG_440)
+        /* set RMII mode */
+        out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0);
+#endif /* CONFIG_440 */
+
+	/* EMAC RESET */
+	out32 (EMAC_M0, EMAC_M0_SRST);
+
+	/* wait for PHY to complete auto negotiation */
+	reg_short = 0;
+#ifndef CONFIG_CS8952_PHY
+	miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, &reg_short);
+
+	/*
+	 * Wait if PHY is able of autonegotiation and autonegotiation is not complete
+	 */
+	if ((reg_short & PHY_BMSR_AUTN_ABLE)
+	    && !(reg_short & PHY_BMSR_AUTN_COMP)) {
+		puts ("Waiting for PHY auto negotiation to complete");
+		i = 0;
+		while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
+			if ((i++ % 100) == 0)
+				putc ('.');
+			udelay (10000);		/* 10 ms */
+			miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, &reg_short);
+
+			/*
+			 * Timeout reached ?
+			 */
+			if (i * 10 > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts (" TIMEOUT !\n");
+				break;
+			}
+		}
+		puts (" done\n");
+		udelay (500000);	/* another 500 ms (results in faster booting) */
+	}
+#endif
+	speed = miiphy_speed (CONFIG_PHY_ADDR);
+	duplex = miiphy_duplex (CONFIG_PHY_ADDR);
+	if (print_speed) {
+		print_speed = 0;
+		printf ("ENET Speed is %d Mbps - %s duplex connection\n",
+			(int) speed, (duplex == HALF) ? "HALF" : "FULL");
+	}
+
+	/* set the Mal configuration reg */
+#if defined(CONFIG_440)
+	/* Errata 1.12: MAL_1 -- Disable MAL bursting */
+	if( get_pvr() == PVR_440GP_RB )
+	    mtdcr (malmcr, MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+	else
+#else
+	mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+#endif
+
+	/* Free "old" buffers */
+	if (alloc_tx_buf) free(alloc_tx_buf);
+	if (alloc_rx_buf) free(alloc_rx_buf);
+
+	/*
+	 * Malloc MAL buffer desciptors, make sure they are
+	 * aligned on cache line boundary size
+	 * (401/403/IOP480 = 16, 405 = 32)
+	 * and doesn't cross cache block boundaries.
+	 */
+	alloc_tx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_TX_BUFF) +
+					    ((2 * CFG_CACHELINE_SIZE) - 2));
+	if (((int)alloc_tx_buf & CACHELINE_MASK) != 0) {
+		tx = (mal_desc_t *)((int)alloc_tx_buf + CFG_CACHELINE_SIZE -
+				    ((int)alloc_tx_buf & CACHELINE_MASK));
+	} else {
+		tx = alloc_tx_buf;
+	}
+
+	alloc_rx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_RX_BUFF) +
+					    ((2 * CFG_CACHELINE_SIZE) - 2));
+	if (((int)alloc_rx_buf & CACHELINE_MASK) != 0) {
+		rx = (mal_desc_t *)((int)alloc_rx_buf + CFG_CACHELINE_SIZE -
+				    ((int)alloc_rx_buf & CACHELINE_MASK));
+	} else {
+		rx = alloc_rx_buf;
+	}
+
+	for (i = 0; i < NUM_TX_BUFF; i++) {
+		tx[i].ctrl = 0;
+		tx[i].data_len = 0;
+		if (first_init == 0)
+			txbuf_ptr = (char *) malloc (ENET_MAX_MTU_ALIGNED);
+		tx[i].data_ptr = txbuf_ptr;
+		if ((NUM_TX_BUFF - 1) == i)
+			tx[i].ctrl |= MAL_TX_CTRL_WRAP;
+		tx_run[i] = -1;
+#if 0
+		printf ("TX_BUFF %d @ 0x%08lx\n", i, (ulong) tx[i].data_ptr);
+#endif
+	}
+
+	for (i = 0; i < NUM_RX_BUFF; i++) {
+		rx[i].ctrl = 0;
+		rx[i].data_len = 0;
+		/*       rx[i].data_ptr = (char *) &rx_buff[i]; */
+		rx[i].data_ptr = (char *) NetRxPackets[i];
+		if ((NUM_RX_BUFF - 1) == i)
+			rx[i].ctrl |= MAL_RX_CTRL_WRAP;
+		rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
+		rx_ready[i] = -1;
+#if 0
+		printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
+#endif
+	}
+
+	memcpy (emac_hwd_addr, bis->bi_enetaddr, ENET_ADDR_LENGTH);
+
+	reg = 0x00000000;
+
+	reg |= emac_hwd_addr[0];	/* set high address */
+	reg = reg << 8;
+	reg |= emac_hwd_addr[1];
+
+	out32 (EMAC_IAH, reg);
+
+	reg = 0x00000000;
+	reg |= emac_hwd_addr[2];	/* set low address  */
+	reg = reg << 8;
+	reg |= emac_hwd_addr[3];
+	reg = reg << 8;
+	reg |= emac_hwd_addr[4];
+	reg = reg << 8;
+	reg |= emac_hwd_addr[5];
+
+	out32 (EMAC_IAL, reg);
+
+	/* setup MAL tx & rx channel pointers */
+	mtdcr (maltxctp0r, tx);
+	mtdcr (malrxctp0r, rx);
+
+	/* Reset transmit and receive channels */
+	mtdcr (malrxcarr, 0x80000000);	/* 2 channels */
+	mtdcr (maltxcarr, 0x80000000);	/* 2 channels */
+
+	/* Enable MAL transmit and receive channels */
+	mtdcr (maltxcasr, 0x80000000);	/* 1 channel */
+	mtdcr (malrxcasr, 0x80000000);	/* 1 channel */
+
+	/* set RX buffer size */
+	mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16);
+
+	/* set transmit enable & receive enable */
+	out32 (EMAC_M0, EMAC_M0_TXE | EMAC_M0_RXE);
+
+	/* set receive fifo to 4k and tx fifo to 2k */
+	mode_reg = EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
+
+	/* set speed */
+	if (speed == _100BASET)
+		mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
+	else
+		mode_reg = mode_reg & ~0x00C00000;	/* 10 MBPS */
+	if (duplex == FULL)
+		mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
+
+	out32 (EMAC_M1, mode_reg);
+
+	/* Enable broadcast and indvidual address */
+	out32 (EMAC_RXM, EMAC_RMR_BAE | EMAC_RMR_IAE
+	       /*| EMAC_RMR_ARRP| EMAC_RMR_SFCS | EMAC_RMR_SP */ );
+
+	/* we probably need to set the tx mode1 reg? maybe at tx time */
+
+	/* set transmit request threshold register */
+	out32 (EMAC_TRTR, 0x18000000);	/* 256 byte threshold */
+
+	/* set receive  low/high water mark register */
+#if defined(CONFIG_440)
+	/* 440GP has a 64 byte burst length */
+        out32 (EMAC_RX_HI_LO_WMARK, 0x80009000);
+        out32 (EMAC_TXM1,           0xf8640000);
+#else /* CONFIG_440 */
+	/* 405s have a 16 byte burst length */
+	out32 (EMAC_RX_HI_LO_WMARK, 0x0f002000);
+#endif /* CONFIG_440 */
+
+	/* Frame gap set */
+	out32 (EMAC_I_FRAME_GAP_REG, 0x00000008);
+
+	if (first_init == 0) {
+		/*
+		 * Connect interrupt service routines
+		 */
+		irq_install_handler (VECNUM_EWU0, (interrupt_handler_t *) enetInt, NULL);
+		irq_install_handler (VECNUM_MS, (interrupt_handler_t *) enetInt, NULL);
+		irq_install_handler (VECNUM_MTE, (interrupt_handler_t *) enetInt, NULL);
+		irq_install_handler (VECNUM_MRE, (interrupt_handler_t *) enetInt, NULL);
+		irq_install_handler (VECNUM_TXDE, (interrupt_handler_t *) enetInt, NULL);
+		irq_install_handler (VECNUM_RXDE, (interrupt_handler_t *) enetInt, NULL);
+		irq_install_handler (VECNUM_ETH0, (interrupt_handler_t *) enetInt, NULL);
+	}
+
+	/* set up interrupt handler */
+	/* setup interrupt controler to take interrupts from the MAL &
+	   EMAC */
+	mtdcr (uicsr, 0xffffffff);	/* clear pending interrupts */
+	mtdcr (uicer, mfdcr (uicer) | MAL_UIC_DEF | EMAC_UIC_DEF);
+
+	/* set the MAL IER ??? names may change with new spec ??? */
+	mal_ier = MAL_IER_DE | MAL_IER_NE | MAL_IER_TE | MAL_IER_OPBE |
+		MAL_IER_PLBE;
+	mtdcr (malesr, 0xffffffff);	/* clear pending interrupts */
+	mtdcr (maltxdeir, 0xffffffff);	/* clear pending interrupts */
+	mtdcr (malrxdeir, 0xffffffff);	/* clear pending interrupts */
+	mtdcr (malier, mal_ier);
+
+	/* Set EMAC IER */
+	emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS |
+		EMAC_ISR_PTLE | EMAC_ISR_ORE  | EMAC_ISR_IRE;
+	if (speed == _100BASET)
+		emac_ier = emac_ier | EMAC_ISR_SYE;
+
+	out32 (EMAC_ISR, 0xffffffff);	/* clear pending interrupts */
+	out32 (EMAC_IER, emac_ier);
+
+	mtmsr (msr);				/* enable interrupts again */
+
+	bis_save = bis;
+	first_init = 1;
+
+	return (0);
+}
+
+
+int eth_send (volatile void *ptr, int len)
+{
+	struct enet_frame *ef_ptr;
+	ulong time_start, time_now;
+	unsigned long temp_txm0;
+
+	ef_ptr = (struct enet_frame *) ptr;
+
+	/*-----------------------------------------------------------------------+
+	 *  Copy in our address into the frame.
+	 *-----------------------------------------------------------------------*/
+	(void) memcpy (ef_ptr->source_addr, emac_hwd_addr, ENET_ADDR_LENGTH);
+
+	/*-----------------------------------------------------------------------+
+	 * If frame is too long or too short, modify length.
+	 *-----------------------------------------------------------------------*/
+	if (len > ENET_MAX_MTU)
+		len = ENET_MAX_MTU;
+
+	/*   memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
+	memcpy ((void *) txbuf_ptr, (const void *) ptr, len);
+
+	/*-----------------------------------------------------------------------+
+	 * set TX Buffer busy, and send it
+	 *-----------------------------------------------------------------------*/
+	tx[tx_slot].ctrl = (MAL_TX_CTRL_LAST |
+			    EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) &
+		~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA);
+	if ((NUM_TX_BUFF - 1) == tx_slot)
+		tx[tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
+
+	tx[tx_slot].data_len = (short) len;
+	tx[tx_slot].ctrl |= MAL_TX_CTRL_READY;
+
+    __asm__ volatile ("eieio");
+	out32 (EMAC_TXM0, in32 (EMAC_TXM0) | EMAC_TXM0_GNP0);
+#ifdef INFO_405_ENET
+	packetSent++;
+#endif
+
+	/*-----------------------------------------------------------------------+
+	 * poll unitl the packet is sent and then make sure it is OK
+	 *-----------------------------------------------------------------------*/
+	time_start = get_timer (0);
+	while (1) {
+		temp_txm0 = in32 (EMAC_TXM0);
+		/* loop until either TINT turns on or 3 seconds elapse */
+		if ((temp_txm0 & EMAC_TXM0_GNP0) != 0) {
+			/* transmit is done, so now check for errors
+                         * If there is an error, an interrupt should
+                         * happen when we return
+			 */
+			time_now = get_timer (0);
+			if ((time_now - time_start) > 3000) {
+				return (-1);
+			}
+		} else {
+			return (0);
+		}
+	}
+}
+
+
+#if defined(CONFIG_440)
+/*-----------------------------------------------------------------------------+
+| EnetInt.
+| EnetInt is the interrupt handler.  It will determine the
+| cause of the interrupt and call the apporpriate servive
+| routine.
++-----------------------------------------------------------------------------*/
+int enetInt ()
+{
+	int serviced;
+	int rc = -1;				/* default to not us */
+	unsigned long mal_isr;
+	unsigned long emac_isr = 0;
+	unsigned long mal_rx_eob;
+	unsigned long my_uic0msr, my_uic1msr;
+
+	/* enter loop that stays in interrupt code until nothing to service */
+	do {
+		serviced = 0;
+
+		my_uic0msr = mfdcr (uic0msr);
+		my_uic1msr = mfdcr (uic1msr);
+
+		if (!(my_uic0msr & UIC_MRE)
+                    && !(my_uic1msr & (UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE))) {
+                        /* not for us */
+			return (rc);
+		}
+
+		/* get and clear controller status interrupts */
+		/* look at Mal and EMAC interrupts */
+		if ((my_uic0msr & UIC_MRE)
+                    || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+                        /* we have a MAL interrupt */
+			mal_isr = mfdcr (malesr);
+			/* look for mal error */
+			if (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE)) {
+				mal_err (mal_isr, my_uic0msr, MAL_UIC_DEF, MAL_UIC_ERR);
+				serviced = 1;
+				rc = 0;
+			}
+		}
+		if (UIC_ETH0 & my_uic1msr) {	/* look for EMAC errors */
+			emac_isr = in32 (EMAC_ISR);
+			if ((emac_ier & emac_isr) != 0) {
+				emac_err (emac_isr);
+				serviced = 1;
+				rc = 0;
+			}
+		}
+		if ((emac_ier & emac_isr)
+                    || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
+			mtdcr (uic0sr, UIC_MRE); /* Clear */
+			mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+			return (rc);		/* we had errors so get out */
+		}
+
+		/* handle MAL RX EOB  interupt from a receive */
+		/* check for EOB on valid channels            */
+		if (my_uic0msr & UIC_MRE) {
+			mal_rx_eob = mfdcr (malrxeobisr);
+			if ((mal_rx_eob & 0x80000000) != 0) {	/* call emac routine for channel 0 */
+				/* clear EOB
+				   mtdcr(malrxeobisr, mal_rx_eob); */
+				enet_rcv (emac_isr);
+				/* indicate that we serviced an interrupt */
+				serviced = 1;
+				rc = 0;
+			}
+		}
+                mtdcr (uic0sr, UIC_MRE); /* Clear */
+                mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+	} while (serviced);
+
+	return (rc);
+}
+#else /* CONFIG_440 */
+/*-----------------------------------------------------------------------------+
+ * EnetInt.
+ * EnetInt is the interrupt handler.  It will determine the
+ * cause of the interrupt and call the apporpriate servive
+ * routine.
+ *-----------------------------------------------------------------------------*/
+int enetInt ()
+{
+	int serviced;
+	int rc = -1;				/* default to not us */
+	unsigned long mal_isr;
+	unsigned long emac_isr = 0;
+	unsigned long mal_rx_eob;
+	unsigned long my_uicmsr;
+
+	/* enter loop that stays in interrupt code until nothing to service */
+	do {
+		serviced = 0;
+
+		my_uicmsr = mfdcr (uicmsr);
+		if ((my_uicmsr & (MAL_UIC_DEF | EMAC_UIC_DEF)) == 0) {	/* not for us */
+			return (rc);
+		}
+
+
+		/* get and clear controller status interrupts */
+		/* look at Mal and EMAC interrupts */
+		if ((MAL_UIC_DEF & my_uicmsr) != 0) {	/* we have a MAL interrupt */
+			mal_isr = mfdcr (malesr);
+			/* look for mal error */
+			if ((my_uicmsr & MAL_UIC_ERR) != 0) {
+				mal_err (mal_isr, my_uicmsr, MAL_UIC_DEF, MAL_UIC_ERR);
+				serviced = 1;
+				rc = 0;
+			}
+		}
+		if ((EMAC_UIC_DEF & my_uicmsr) != 0) {	/* look for EMAC errors */
+			emac_isr = in32 (EMAC_ISR);
+			if ((emac_ier & emac_isr) != 0) {
+				emac_err (emac_isr);
+				serviced = 1;
+				rc = 0;
+			}
+		}
+		if (((emac_ier & emac_isr) != 0) | ((MAL_UIC_ERR & my_uicmsr) != 0)) {
+			mtdcr (uicsr, MAL_UIC_DEF | EMAC_UIC_DEF); /* Clear */
+			return (rc);		/* we had errors so get out */
+		}
+
+
+		/* handle MAL RX EOB  interupt from a receive */
+		/* check for EOB on valid channels            */
+		if ((my_uicmsr & UIC_MAL_RXEOB) != 0) {
+			mal_rx_eob = mfdcr (malrxeobisr);
+			if ((mal_rx_eob & 0x80000000) != 0) {	/* call emac routine for channel 0 */
+				/* clear EOB
+				   mtdcr(malrxeobisr, mal_rx_eob); */
+				enet_rcv (emac_isr);
+				/* indicate that we serviced an interrupt */
+				serviced = 1;
+				rc = 0;
+			}
+		}
+		mtdcr (uicsr, MAL_UIC_DEF | EMAC_UIC_DEF);	/* Clear */
+	}
+	while (serviced);
+
+	return (rc);
+}
+#endif /* CONFIG_440 */
+
+/*-----------------------------------------------------------------------------+
+ *  MAL Error Routine
+ *-----------------------------------------------------------------------------*/
+void mal_err (unsigned long isr, unsigned long uic, unsigned long maldef,
+	      unsigned long mal_errr)
+{
+	mtdcr (malesr, isr);		/* clear interrupt */
+
+	/* clear DE interrupt */
+	mtdcr (maltxdeir, 0xC0000000);
+	mtdcr (malrxdeir, 0x80000000);
+
+#if 1	/*sr */
+	printf ("\nMAL error occured.... ISR = %lx UIC = = %lx  MAL_DEF = %lx  MAL_ERR= %lx \n",
+		isr, uic, maldef, mal_errr);
+#else
+#if 0
+	/*
+	 * MAL error is RX DE error (out of rx buffers)! This is OK here, upon
+	 * many incoming packets with only 4 rx buffers.
+	 */
+	printf ("M");			/* just to see something upon mal error */
+#endif
+#endif	/*sr */
+
+	eth_init (bis_save);		/* start again... */
+}
+
+/*-----------------------------------------------------------------------------+
+ *  EMAC Error Routine
+ *-----------------------------------------------------------------------------*/
+void emac_err (unsigned long isr)
+{
+	printf ("EMAC error occured.... ISR = %lx\n", isr);
+	out32 (EMAC_ISR, isr);
+}
+
+/*-----------------------------------------------------------------------------+
+ *  enet_rcv() handles the ethernet receive data
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (unsigned long malisr)
+{
+	struct enet_frame *ef_ptr;
+	unsigned long data_len;
+	unsigned long rx_eob_isr;
+
+	int handled = 0;
+	int i;
+	int loop_count = 0;
+
+	rx_eob_isr = mfdcr (malrxeobisr);
+	if ((0x80000000 >> (EMAC_RXCHL - 1)) & rx_eob_isr) {
+		/* clear EOB */
+		mtdcr (malrxeobisr, rx_eob_isr);
+
+		/* EMAC RX done */
+		while (1) {				/* do all */
+			i = rx_slot;
+
+			if ((MAL_RX_CTRL_EMPTY & rx[i].ctrl)
+			    || (loop_count >= NUM_RX_BUFF))
+				break;
+			loop_count++;
+			rx_slot++;
+			if (NUM_RX_BUFF == rx_slot)
+				rx_slot = 0;
+			handled++;
+			data_len = (unsigned long) rx[i].data_len;	/* Get len */
+			if (data_len) {
+				if (data_len > ENET_MAX_MTU)	/* Check len */
+					data_len = 0;
+				else {
+					if (EMAC_RX_ERRORS & rx[i].ctrl) {	/* Check Errors */
+						data_len = 0;
+						stats.rx_err_log[rx_err_index] = rx[i].ctrl;
+						rx_err_index++;
+						if (rx_err_index == MAX_ERR_LOG)
+							rx_err_index = 0;
+					}	/* emac_erros         */
+				}		/* data_len < max mtu */
+			}			/* if data_len        */
+			if (!data_len) {	/* no data */
+				rx[i].ctrl |= MAL_RX_CTRL_EMPTY;	/* Free Recv Buffer */
+
+				stats.emac.data_len_err++;	/* Error at Rx */
+			}
+
+			/* !data_len */
+			/* AS.HARNOIS */
+			/* Check if user has already eaten buffer */
+			/* if not => ERROR */
+			else if (rx_ready[rx_i_index] != -1) {
+				if (is_receiving)
+					printf ("ERROR : Receive buffers are full!\n");
+				break;
+			} else {
+				stats.emac.rx_frames++;
+				stats.emac.rx += data_len;
+				ef_ptr = (struct enet_frame *) rx[i].data_ptr;
+#ifdef INFO_405_ENET
+				packetReceived++;
+#endif
+				/* AS.HARNOIS
+				 * use ring buffer
+				 */
+				rx_ready[rx_i_index] = i;
+				rx_i_index++;
+				if (NUM_RX_BUFF == rx_i_index)
+					rx_i_index = 0;
+
+				/* printf("X");  /|* test-only *|/ */
+
+				/*  AS.HARNOIS
+				 * free receive buffer only when
+				 * buffer has been handled (eth_rx)
+				 rx[i].ctrl |= MAL_RX_CTRL_EMPTY;
+				*/
+			}			/* if data_len */
+		}				/* while */
+	}					/* if EMACK_RXCHL */
+}
+
+
+int eth_rx (void)
+{
+	int length;
+	int user_index;
+	unsigned long msr;
+
+	is_receiving = 1;			/* tell driver */
+
+	for (;;) {
+		/* AS.HARNOIS
+		 * use ring buffer and
+		 * get index from rx buffer desciptor queue
+		 */
+		user_index = rx_ready[rx_u_index];
+		if (user_index == -1) {
+			length = -1;
+			break;	/* nothing received - leave for() loop */
+		}
+
+		msr = mfmsr ();
+		mtmsr (msr & ~(MSR_EE));
+
+		length = rx[user_index].data_len;
+
+		/* Pass the packet up to the protocol layers. */
+		/*       NetReceive(NetRxPackets[rxIdx], length - 4); */
+		/*       NetReceive(NetRxPackets[i], length); */
+		NetReceive (NetRxPackets[user_index], length - 4);
+		/* Free Recv Buffer */
+		rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
+		/* Free rx buffer descriptor queue */
+		rx_ready[rx_u_index] = -1;
+		rx_u_index++;
+		if (NUM_RX_BUFF == rx_u_index)
+			rx_u_index = 0;
+
+#ifdef INFO_405_ENET
+		packetHandled++;
+#endif
+
+		mtmsr (msr);			/* Enable IRQ's */
+	}
+
+	is_receiving = 0;			/* tell driver */
+
+	return length;
+}
+
+#endif	/* CONFIG_405GP */
diff --git a/cpu/ppc4xx/405gp_pci.c b/cpu/ppc4xx/405gp_pci.c
new file mode 100644
index 0000000..1c2c59b
--- /dev/null
+++ b/cpu/ppc4xx/405gp_pci.c
@@ -0,0 +1,502 @@
+/*-----------------------------------------------------------------------------+
+ *
+ *       This source code has been made available to you by IBM on an AS-IS
+ *       basis.  Anyone receiving this source is licensed under IBM
+ *       copyrights to use it in any way he or she deems fit, including
+ *       copying it, modifying it, compiling it, and redistributing it either
+ *       with or without modifications.  No license under IBM patents or
+ *       patent applications is to be implied by the copyright license.
+ *
+ *       Any user of this software should understand that IBM cannot provide
+ *       technical support for this software and will not be responsible for
+ *       any consequences resulting from the use of this software.
+ *
+ *       Any person who transfers this source code or any derivative work
+ *       must include the IBM copyright notice, this paragraph, and the
+ *       preceding two paragraphs in the transferred software.
+ *
+ *       COPYRIGHT   I B M   CORPORATION 1995
+ *       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
+ *-----------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------+
+ *
+ *  File Name:   405gp_pci.c
+ *
+ *  Function:    Initialization code for the 405GP PCI Configuration regs.
+ *
+ *  Author:      Mark Game
+ *
+ *  Change Activity-
+ *
+ *  Date        Description of Change                                       BY
+ *  ---------   ---------------------                                       ---
+ *  09-Sep-98   Created                                                     MCG
+ *  02-Nov-98   Removed External arbiter selected message                   JWB
+ *  27-Nov-98   Zero out PTMBAR2 and disable in PTM2MS                      JWB
+ *  04-Jan-99   Zero out other unused PMM and PTM regs. Change bus scan     MCG
+ *              from (0 to n) to (1 to n).
+ *  17-May-99   Port to Walnut                                              JWB
+ *  17-Jun-99   Updated for VGA support                                     JWB
+ *  21-Jun-99   Updated to allow SRAM region to be a target from PCI bus    JWB
+ *  19-Jul-99   Updated for 405GP pass 1 errata #26 (Low PCI subsequent     MCG
+ *              target latency timer values are not supported).
+ *              Should be fixed in pass 2.
+ *  09-Sep-99   Removed use of PTM2 since the SRAM region no longer needs   JWB
+ *              to be a PCI target. Zero out PTMBAR2 and disable in PTM2MS.
+ *  10-Dec-99   Updated PCI_Write_CFG_Reg for pass2 errata #6               JWB
+ *  11-Jan-00   Ensure PMMxMAs disabled before setting PMMxLAs. This is not
+ *              really required after a reset since PMMxMAs are already
+ * 	        disabled but is a good practice nonetheless.                JWB
+ *  12-Jun-01   stefan.roese@esd-electronics.com
+ *              - PCI host/adapter handling reworked
+ *  09-Jul-01   stefan.roese@esd-electronics.com
+ *              - PCI host now configures from device 0 (not 1) to max_dev,
+ *                (host configures itself)
+ *              - On CPCI-405 pci base address and size is generated from
+ *                SDRAM and FLASH size (CFG regs not used anymore)
+ *              - Some minor changes for CPCI-405-A (adapter version)
+ *  14-Sep-01   stefan.roese@esd-electronics.com
+ *              - CONFIG_PCI_SCAN_SHOW added to print pci devices upon startup
+ *  28-Sep-01   stefan.roese@esd-electronics.com
+ *              - Changed pci master configuration for linux compatibility
+ *                (no need for bios_fixup() anymore)
+ *  26-Feb-02   stefan.roese@esd-electronics.com
+ *              - Bug fixed in pci configuration (Andrew May)
+ *              - Removed pci class code init for CPCI405 board
+ *  15-May-02   stefan.roese@esd-electronics.com
+ *              - New vga device handling
+ *  29-May-02   stefan.roese@esd-electronics.com
+ *              - PCI class code init added (if defined)
+ *----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <command.h>
+#include <cmd_boot.h>
+#if !defined(CONFIG_440)
+#include <405gp_pci.h>
+#endif
+#include <asm/processor.h>
+#include <pci.h>
+
+#if defined(CONFIG_405GP)
+
+#ifdef CONFIG_PCI
+
+/*#define DEBUG*/
+
+/*-----------------------------------------------------------------------------+
+ * pci_init.  Initializes the 405GP PCI Configuration regs.
+ *-----------------------------------------------------------------------------*/
+void pci_405gp_init(struct pci_controller *hose)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int i, reg_num = 0;
+	bd_t *bd = gd->bd;
+
+	unsigned short temp_short;
+	unsigned long ptmpcila[2] = {CFG_PCI_PTM1PCI, CFG_PCI_PTM2PCI};
+#if defined(CONFIG_CPCI405)
+	unsigned long ptmla[2]    = {bd->bi_memstart, bd->bi_flashstart};
+	unsigned long ptmms[2]    = {~(bd->bi_memsize - 1) | 1, ~(bd->bi_flashsize - 1) | 1};
+#else
+	unsigned long ptmla[2]    = {CFG_PCI_PTM1LA, CFG_PCI_PTM2LA};
+	unsigned long ptmms[2]    = {CFG_PCI_PTM1MS, CFG_PCI_PTM2MS};
+#endif
+#if defined(CONFIG_PIP405) || defined (CONFIG_MIP405)
+	unsigned long pmmla[3]    = {0x80000000, 0xA0000000, 0};
+	unsigned long pmmma[3]    = {0xE0000001, 0xE0000001, 0};
+	unsigned long pmmpcila[3] = {0x80000000, 0x00000000, 0};
+	unsigned long pmmpciha[3] = {0x00000000, 0x00000000, 0};
+#else
+	unsigned long pmmla[3]    = {0x80000000, 0,0};
+	unsigned long pmmma[3]    = {0xC0000001, 0,0};
+	unsigned long pmmpcila[3] = {0x80000000, 0,0};
+	unsigned long pmmpciha[3] = {0x00000000, 0,0};
+#endif
+
+	/*
+	 * Register the hose
+	 */
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	/* ISA/PCI I/O space */
+	pci_set_region(hose->regions + reg_num++,
+		       MIN_PCI_PCI_IOADDR,
+		       MIN_PLB_PCI_IOADDR,
+		       0x10000,
+		       PCI_REGION_IO);
+
+	/* PCI I/O space */
+	pci_set_region(hose->regions + reg_num++,
+		       0x00800000,
+		       0xe8800000,
+		       0x03800000,
+		       PCI_REGION_IO);
+
+	reg_num = 2;
+
+	/* Memory spaces */
+	for (i=0; i<2; i++)
+		if (ptmms[i] & 1)
+		{
+			if (!i) hose->pci_fb = hose->regions + reg_num;
+
+			pci_set_region(hose->regions + reg_num++,
+				       ptmpcila[i], ptmla[i],
+				       ~(ptmms[i] & 0xfffff000) + 1,
+				       PCI_REGION_MEM |
+				       PCI_REGION_MEMORY);
+		}
+
+	/* PCI memory spaces */
+	for (i=0; i<3; i++)
+		if (pmmma[i] & 1)
+		{
+			pci_set_region(hose->regions + reg_num++,
+				       pmmpcila[i], pmmla[i],
+				       ~(pmmma[i] & 0xfffff000) + 1,
+				       PCI_REGION_MEM);
+		}
+
+	hose->region_count = reg_num;
+
+	pci_setup_indirect(hose,
+			   PCICFGADR,
+			   PCICFGDATA);
+
+	if (hose->pci_fb)
+		pciauto_region_init(hose->pci_fb);
+
+	pci_register_hose(hose);
+
+	/*--------------------------------------------------------------------------+
+	 * 405GP PCI Master configuration.
+	 * Map one 512 MB range of PLB/processor addresses to PCI memory space.
+	 * PLB address 0x80000000-0xBFFFFFFF ==> PCI address 0x80000000-0xBFFFFFFF
+	 * Use byte reversed out routines to handle endianess.
+	 *--------------------------------------------------------------------------*/
+	out32r(PMM0MA,    pmmma[0]);          /* ensure disabled b4 setting PMM0LA */
+	out32r(PMM0LA,    pmmla[0]);
+	out32r(PMM0PCILA, pmmpcila[0]);
+	out32r(PMM0PCIHA, pmmpciha[0]);
+	out32r(PMM0MA,    pmmma[0]);
+
+	/*--------------------------------------------------------------------------+
+	 * PMM1 is not used.  Initialize them to zero.
+	 *--------------------------------------------------------------------------*/
+	out32r(PMM1MA,    pmmma[1]);          /* ensure disabled b4 setting PMM2LA */
+	out32r(PMM1LA,    pmmla[1]);
+	out32r(PMM1PCILA, pmmpcila[1]);
+	out32r(PMM1PCIHA, pmmpciha[1]);
+	out32r(PMM1MA,    pmmma[1]);
+
+	/*--------------------------------------------------------------------------+
+	 * PMM2 is not used.  Initialize them to zero.
+	 *--------------------------------------------------------------------------*/
+	out32r(PMM2MA,    pmmma[2]);          /* ensure disabled b4 setting PMM2LA */
+	out32r(PMM2LA,    pmmla[2]);
+	out32r(PMM2PCILA, pmmpcila[2]);
+	out32r(PMM2PCIHA, pmmpciha[2]);
+	out32r(PMM2MA,    pmmma[2]);
+
+	/*--------------------------------------------------------------------------+
+	 * 405GP PCI Target configuration.  (PTM1)
+	 * Note: PTM1MS is hardwire enabled but we set the enable bit anyway.
+	 *--------------------------------------------------------------------------*/
+	out32r(PTM1LA,    ptmla[0]);         /* insert address                     */
+	out32r(PTM1MS,    ptmms[0]);         /* insert size, enable bit is 1       */
+
+	/*--------------------------------------------------------------------------+
+	 * 405GP PCI Target configuration.  (PTM2)
+	 *--------------------------------------------------------------------------*/
+	out32r(PTM2LA, ptmla[1]);            /* insert address                     */
+	if (ptmms[1] == 0)
+	{
+		out32r(PTM2MS,    0x00000001);   /* set enable bit                     */
+		pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, 0x00000000);
+		out32r(PTM2MS,    0x00000000);   /* disable                            */
+	}
+	else
+	{
+		out32r(PTM2MS, ptmms[1]);        /* insert size, enable bit is 1       */
+	}
+
+	/*
+	 * Insert Subsystem Vendor and Device ID
+	 */
+	pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_VENDOR_ID, CFG_PCI_SUBSYS_VENDORID);
+#ifdef CONFIG_CPCI405
+	if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+		pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID);
+	else
+		pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID2);
+#else
+	pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID);
+#endif
+
+	/*
+	 * Insert Class-code
+	 */
+#ifdef CFG_PCI_CLASSCODE
+	pci_write_config_word(PCIDEVID_405GP, PCI_CLASS_SUB_CODE, CFG_PCI_CLASSCODE);
+#endif /* CFG_PCI_CLASSCODE */
+
+	/*--------------------------------------------------------------------------+
+	 * If PCI speed = 66Mhz, set 66Mhz capable bit.
+	 *--------------------------------------------------------------------------*/
+	if (bd->bi_pci_busfreq >= 66000000) {
+		pci_read_config_word(PCIDEVID_405GP, PCI_STATUS, &temp_short);
+		pci_write_config_word(PCIDEVID_405GP,PCI_STATUS,(temp_short|PCI_STATUS_66MHZ));
+	}
+
+#if (CONFIG_PCI_HOST != PCI_HOST_ADAPTER)
+#if (CONFIG_PCI_HOSE == PCI_HOST_AUTO)
+	if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+#endif
+	{
+		/*--------------------------------------------------------------------------+
+		 * Write the 405GP PCI Configuration regs.
+		 * Enable 405GP to be a master on the PCI bus (PMM).
+		 * Enable 405GP to act as a PCI memory target (PTM).
+		 *--------------------------------------------------------------------------*/
+		pci_read_config_word(PCIDEVID_405GP, PCI_COMMAND, &temp_short);
+		pci_write_config_word(PCIDEVID_405GP, PCI_COMMAND, temp_short |
+				      PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	}
+#endif
+
+	/*
+	 * Set HCE bit (Host Configuration Enabled)
+	 */
+	pci_read_config_word(PCIDEVID_405GP, PCIBRDGOPT2, &temp_short);
+	pci_write_config_word(PCIDEVID_405GP, PCIBRDGOPT2, (temp_short | 0x0001));
+
+#ifdef CONFIG_PCI_PNP
+	/*--------------------------------------------------------------------------+
+	 * Scan the PCI bus and configure devices found.
+	 *--------------------------------------------------------------------------*/
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+	if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+#endif
+	{
+#ifdef CONFIG_PCI_SCAN_SHOW
+		printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
+
+		hose->last_busno = pci_hose_scan(hose);
+	}
+#endif  /* CONFIG_PCI_PNP */
+
+}
+
+/*
+ * drivers/pci.c skips every host bridge but the 405GP since it could
+ * be set as an Adapter.
+ *
+ * I (Andrew May) don't know what we should do here, but I don't want
+ * the auto setup of a PCI device disabling what is done pci_405gp_init
+ * as has happened before.
+ */
+void pci_405gp_setup_bridge(struct pci_controller *hose, pci_dev_t dev,
+			    struct pci_config_table *entry)
+{
+#ifdef DEBUG
+        printf("405gp_setup_bridge\n");
+#endif
+}
+
+/*
+ *
+ */
+
+void pci_405gp_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+	unsigned char int_line = 0xff;
+
+	/*
+	 * Write pci interrupt line register (cpci405 specific)
+	 */
+	switch (PCI_DEV(dev) & 0x03)
+	{
+	case 0:
+		int_line = 27 + 2;
+		break;
+	case 1:
+		int_line = 27 + 3;
+		break;
+	case 2:
+		int_line = 27 + 0;
+		break;
+	case 3:
+		int_line = 27 + 1;
+		break;
+	}
+
+	pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
+}
+
+void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
+			 struct pci_config_table *entry)
+{
+	unsigned int cmdstat = 0;
+
+	pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io);
+
+	/* always enable io space on vga boards */
+	pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+	cmdstat |= PCI_COMMAND_IO;
+	pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
+}
+
+#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405))
+
+/*
+ *As is these functs get called out of flash Not a horrible
+ *thing, but something to keep in mind. (no statics?)
+ */
+static struct pci_config_table pci_405gp_config_table[] = {
+/*if VendID is 0 it terminates the table search (ie Walnut)*/
+#if CFG_PCI_SUBSYS_VENDORID
+	{CFG_PCI_SUBSYS_VENDORID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_bridge},
+#endif
+	{PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
+
+	{PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
+
+	{ }
+};
+
+static struct pci_controller hose = {
+	fixup_irq: pci_405gp_fixup_irq,
+	config_table: pci_405gp_config_table,
+};
+
+void pci_init(void)
+{
+	/*we want the ptrs to RAM not flash (ie don't use init list)*/
+	hose.fixup_irq    = pci_405gp_fixup_irq;
+	hose.config_table = pci_405gp_config_table;
+	pci_405gp_init(&hose);
+}
+
+#endif
+
+#endif /* CONFIG_PCI */
+
+#endif /* CONFIG_405GP */
+
+/*-----------------------------------------------------------------------------+
+ * CONFIG_440
+ *-----------------------------------------------------------------------------*/
+#if defined(CONFIG_440) && defined(CONFIG_PCI)
+
+static struct pci_controller ppc440_hose = {0};
+
+
+void pci_440_init (struct pci_controller *hose)
+{
+	int reg_num = 0;
+	unsigned long strap;
+
+	/*--------------------------------------------------------------------------+
+	 * The PCI initialization sequence enable bit must be set ... if not abort
+     * pci setup since updating the bit requires chip reset.
+	 *--------------------------------------------------------------------------*/
+    strap = mfdcr(cpc0_strp1);
+    if( (strap & 0x00040000) == 0 ){
+        printf("PCI: CPC0_STRP1[PISE] not set.\n");
+        printf("PCI: Configuration aborted.\n");
+        return;
+    }
+
+	/*--------------------------------------------------------------------------+
+	 * PCI controller init
+	 *--------------------------------------------------------------------------*/
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_set_region(hose->regions + reg_num++,
+		       0x00000000,
+			   PCIX0_IOBASE,
+			   0x10000,
+			   PCI_REGION_IO);
+
+	pci_set_region(hose->regions + reg_num++,
+		       CFG_PCI_TARGBASE,
+			   CFG_PCI_MEMBASE,
+			   0x10000000,
+			   PCI_REGION_MEM );
+	hose->region_count = reg_num;
+
+	pci_setup_indirect(hose, PCIX0_CFGADR, PCIX0_CFGDATA);
+
+#if defined(CFG_PCI_PRE_INIT)
+    /* Let board change/modify hose & do initial checks */
+    if( pci_pre_init (hose) == 0 ){
+        printf("PCI: Board-specific initialization failed.\n");
+        printf("PCI: Configuration aborted.\n");
+        return;
+    }
+#endif
+
+	pci_register_hose( hose );
+
+	/*--------------------------------------------------------------------------+
+	 * PCI target init
+	 *--------------------------------------------------------------------------*/
+#if defined(CFG_PCI_TARGET_INIT)
+	pci_target_init(hose);                /* Let board setup pci target */
+#else
+    out16r( PCIX0_SBSYSVID, CFG_PCI_SUBSYS_VENDORID );
+    out16r( PCIX0_SBSYSID, CFG_PCI_SUBSYS_ID );
+    out16r( PCIX0_CLS, 0x00060000 ); /* Bridge, host bridge */
+#endif
+
+    out32r( PCIX0_BRDGOPT1, 0x10000060 );               /* PLB Rq pri highest   */
+    out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 1 ); /* Enable host config   */
+
+	/*--------------------------------------------------------------------------+
+	 * PCI master init: default is one 256MB region for PCI memory:
+	 * 0x3_00000000 - 0x3_0FFFFFFF  ==> CFG_PCI_MEMBASE
+	 *--------------------------------------------------------------------------*/
+#if defined(CFG_PCI_MASTER_INIT)
+	pci_master_init(hose);          /* Let board setup pci master */
+#else
+	out32r( PCIX0_POM0SA, 0 ); /* disable */
+	out32r( PCIX0_POM1SA, 0 ); /* disable */
+	out32r( PCIX0_POM2SA, 0 ); /* disable */
+	out32r( PCIX0_POM0LAL, 0x00000000 );
+	out32r( PCIX0_POM0LAH, 0x00000003 );
+	out32r( PCIX0_POM0PCIAL, CFG_PCI_MEMBASE );
+	out32r( PCIX0_POM0PCIAH, 0x00000000 );
+	out32r( PCIX0_POM0SA, 0xf0000001 ); /* 256MB, enabled */
+    out32r( PCIX0_STS, in32r( PCIX0_STS ) & ~0x0000fff8 );
+#endif
+
+	/*--------------------------------------------------------------------------+
+	 * PCI host configuration -- we don't make any assumptions here ... the
+     * _board_must_indicate_ what to do -- there's just too many runtime
+     * scenarios in environments like cPCI, PPMC, etc. to make a determination
+     * based on hard-coded values or state of arbiter enable.
+	 *--------------------------------------------------------------------------*/
+    if( is_pci_host(hose) ){
+#ifdef CONFIG_PCI_SCAN_SHOW
+        printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
+        out16r( PCIX0_CMD, in16r( PCIX0_CMD ) | PCI_COMMAND_MASTER);
+        hose->last_busno = pci_hose_scan(hose);
+    }
+}
+
+
+void pci_init(void)
+{
+	pci_440_init (&ppc440_hose);
+}
+
+#endif /* CONFIG_440 & CONFIG_PCI */
diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c
new file mode 100644
index 0000000..8aaffb1
--- /dev/null
+++ b/cpu/ppc4xx/cpu.c
@@ -0,0 +1,253 @@
+/*
+ * (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
+ */
+
+/*
+ * m8xx.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <ppc4xx.h>
+
+
+#if defined(CONFIG_440)
+static int do_chip_reset( unsigned long sys0, unsigned long sys1 );
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+int checkcpu (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_IOP480) || defined(CONFIG_440)
+	uint pvr = get_pvr();
+#endif
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_IOP480)
+	DECLARE_GLOBAL_DATA_PTR;
+
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+#endif
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
+	PPC405_SYS_INFO sys_info;
+
+	puts ("CPU:   ");
+
+	get_sys_info(&sys_info);
+
+#if CONFIG_405GP
+	puts("IBM PowerPC 405GP");
+	if (pvr == PVR_405GPR_RA) {
+		putc('r');
+	}
+	puts(" Rev. ");
+#endif
+#if CONFIG_405CR
+	puts("IBM PowerPC 405CR Rev. ");
+#endif
+	switch (pvr) {
+	case PVR_405GP_RB:
+		putc('B');
+		break;
+	case PVR_405GP_RC:
+#if CONFIG_405CR
+	case PVR_405CR_RC:
+#endif
+		putc('C');
+		break;
+	case PVR_405GP_RD:
+		putc('D');
+		break;
+#if CONFIG_405GP
+	case PVR_405GP_RE:
+		putc('E');
+		break;
+#endif
+	case PVR_405CR_RA:
+	case PVR_405GPR_RA:
+		putc('A');
+		break;
+	case PVR_405CR_RB:
+		putc('B');
+		break;
+	default:
+		printf("? (PVR=%08x)", pvr);
+		break;
+	}
+
+	printf(" at %s MHz (PLB=%lu, OPB=%lu, EBC=%lu MHz)\n", strmhz(buf, clock),
+	       sys_info.freqPLB / 1000000,
+	       sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
+	       sys_info.freqPLB / sys_info.pllExtBusDiv / 1000000);
+
+#if CONFIG_405GP
+	if (mfdcr(strap) & PSR_PCI_ASYNC_EN)
+		printf("           PCI async ext clock used, ");
+	else
+		printf("           PCI sync clock at %lu MHz, ",
+		       sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
+	if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
+		printf("internal PCI arbiter enabled\n");
+	else
+		printf("external PCI arbiter enabled\n");
+#endif
+
+	if ((pvr | 0x00000001) == PVR_405GPR_RA) {
+		printf("           16 kB I-Cache 16 kB D-Cache");
+	} else {
+		printf("           16 kB I-Cache 8 kB D-Cache");
+	}
+
+
+#endif  /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
+
+#ifdef CONFIG_IOP480
+	printf("PLX IOP480 (PVR=%08x)", pvr);
+	printf(" at %s MHz:", strmhz(buf, clock));
+	printf(" %u kB I-Cache", 4);
+	printf(" %u kB D-Cache", 2);
+#endif
+
+#if defined(CONFIG_440)
+	puts("IBM PowerPC 440 Rev. ");
+	switch(pvr)
+	{
+        case PVR_440GP_RB:
+		putc('B');
+        /* See errata 1.12: CHIP_4 */
+        if(   ( mfdcr(cpc0_sys0) != mfdcr(cpc0_strp0) )
+            ||( mfdcr(cpc0_sys1) != mfdcr(cpc0_strp1) ) ){
+            puts("\n\t CPC0_SYSx DCRs corrupted. Resetting chip ...\n");
+            udelay( 1000 * 1000 ); /* Give time for serial buf to clear */
+            do_chip_reset( mfdcr(cpc0_strp0), mfdcr(cpc0_strp1) );
+        }
+		break;
+        case PVR_440GP_RC:
+		putc('C');
+		break;
+        default:
+		printf("UNKNOWN (PVR=%08x)", pvr);
+		break;
+	}
+#endif
+
+	printf("\n");
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+        /*
+         * Initiate system reset in debug control register DBCR
+         */
+	__asm__ __volatile__("lis   3, 0x3000" ::: "r3");
+#if defined(CONFIG_440)
+	__asm__ __volatile__("mtspr 0x134, 3");
+#else
+	__asm__ __volatile__("mtspr 0x3f2, 3");
+#endif
+	return 1;
+}
+
+#if defined(CONFIG_440)
+static
+int do_chip_reset( unsigned long sys0, unsigned long sys1 )
+{
+    /* Changes to cpc0_sys0 and cpc0_sys1 require chip
+     * reset.
+     */
+    mtdcr( cntrl0, mfdcr(cntrl0) | 0x80000000 ); /* Set SWE */
+    mtdcr( cpc0_sys0, sys0 );
+    mtdcr( cpc0_sys1, sys1 );
+    mtdcr( cntrl0, mfdcr(cntrl0) & ~0x80000000 ); /* Clr SWE */
+    mtspr( dbcr0, 0x20000000);  /* Reset the chip */
+
+    return 1;
+}
+#endif
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+#if defined(CONFIG_440)
+
+	sys_info_t  sys_info;
+
+	get_sys_info(&sys_info);
+	return (sys_info.freqProcessor);
+
+#elif defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405)
+
+	PPC405_SYS_INFO sys_info;
+
+	get_sys_info(&sys_info);
+	return (sys_info.freqProcessor);
+
+#elif defined(CONFIG_IOP480)
+
+	return (66000000);
+
+#else
+
+# error get_tbclk() not implemented
+
+#endif
+
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+watchdog_reset(void)
+{
+	int re_enable = disable_interrupts();
+	reset_4xx_watchdog();
+	if (re_enable) enable_interrupts();
+}
+
+void
+reset_4xx_watchdog(void)
+{
+	/*
+	 * Clear TSR(WIS) bit
+	 */
+	mtspr(tsr, 0x40000000);
+}
+#endif	/* CONFIG_WATCHDOG */
diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c
new file mode 100644
index 0000000..68af057
--- /dev/null
+++ b/cpu/ppc4xx/i2c.c
@@ -0,0 +1,417 @@
+/*****************************************************************************/
+/* I2C Bus interface initialisation and I2C Commands                         */
+/* for PPC405GP		                                                     */
+/* Author : AS HARNOIS                                                       */
+/* Date   : 13.Dec.00                                                        */
+/*****************************************************************************/
+
+#include <common.h>
+#include <ppc4xx.h>
+#if defined(CONFIG_440)
+#   include <440_i2c.h>
+#else
+#   include <405gp_i2c.h>
+#endif
+#include <i2c.h>
+
+#ifdef CONFIG_HARD_I2C
+
+#define IIC_OK		0
+#define IIC_NOK		1
+#define IIC_NOK_LA	2		/* Lost arbitration */
+#define IIC_NOK_ICT	3		/* Incomplete transfer */
+#define IIC_NOK_XFRA	4		/* Transfer aborted */
+#define IIC_NOK_DATA	5		/* No data in buffer */
+#define IIC_NOK_TOUT	6		/* Transfer timeout */
+
+#define IIC_TIMEOUT 1			/* 1 seconde */
+
+
+static void _i2c_bus_reset (void)
+{
+	int i, status;
+
+	/* Reset status register */
+	/* write 1 in SCMP and IRQA to clear these fields */
+	out8 (IIC_STS, 0x0A);
+
+	/* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
+	out8 (IIC_EXTSTS, 0x8F);
+	__asm__ volatile ("eieio");
+
+	/*
+	 * Get current state, reset bus
+	 * only if no transfers are pending.
+	 */
+	i = 10;
+	do {
+		/* Get status */
+		status = in8 (IIC_STS);
+		udelay (500);			/* 500us */
+		i--;
+	} while ((status & IIC_STS_PT) && (i > 0));
+	/* Soft reset controller */
+	status = in8 (IIC_XTCNTLSS);
+	out8 (IIC_XTCNTLSS, (status | IIC_XTCNTLSS_SRST));
+	__asm__ volatile ("eieio");
+
+	/* make sure where in initial state, data hi, clock hi */
+	out8 (IIC_DIRECTCNTL, 0xC);
+	for (i = 0; i < 10; i++) {
+		if ((in8 (IIC_DIRECTCNTL) & 0x3) != 0x3) {
+			/* clock until we get to known state */
+			out8 (IIC_DIRECTCNTL, 0x8);	/* clock lo */
+			udelay (100);		/* 100us */
+			out8 (IIC_DIRECTCNTL, 0xC);	/* clock hi */
+			udelay (100);		/* 100us */
+		} else {
+			break;
+		}
+	}
+	/* send start condition */
+	out8 (IIC_DIRECTCNTL, 0x4);
+	udelay (1000);				/* 1ms */
+	/* send stop condition */
+	out8 (IIC_DIRECTCNTL, 0xC);
+	udelay (1000);				/* 1ms */
+	/* Unreset controller */
+	out8 (IIC_XTCNTLSS, (status & ~IIC_XTCNTLSS_SRST));
+	udelay (1000);				/* 1ms */
+}
+
+void i2c_init (int speed, int slaveadd)
+{
+	sys_info_t sysInfo;
+	unsigned long freqOPB;
+	int val, divisor;
+
+	/* Handle possible failed I2C state */
+	_i2c_bus_reset ();
+
+	/* clear lo master address */
+	out8 (IIC_LMADR, 0);
+
+	/* clear hi master address */
+	out8 (IIC_HMADR, 0);
+
+	/* clear lo slave address */
+	out8 (IIC_LSADR, 0);
+
+	/* clear hi slave address */
+	out8 (IIC_HSADR, 0);
+
+	/* Clock divide Register */
+	/* get OPB frequency */
+	get_sys_info (&sysInfo);
+	freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv;
+	/* set divisor according to freqOPB */
+	divisor = (freqOPB - 1) / 10000000;
+	if (divisor == 0)
+		divisor = 1;
+	out8 (IIC_CLKDIV, divisor);
+
+	/* no interrupts */
+	out8 (IIC_INTRMSK, 0);
+
+	/* clear transfer count */
+	out8 (IIC_XFRCNT, 0);
+
+	/* clear extended control & stat */
+	/* write 1 in SRC SRS SWC SWS to clear these fields */
+	out8 (IIC_XTCNTLSS, 0xF0);
+
+	/* Mode Control Register
+	   Flush Slave/Master data buffer */
+	out8 (IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
+	__asm__ volatile ("eieio");
+
+
+        val = in8(IIC_MDCNTL);
+        __asm__ volatile ("eieio");
+
+        /* Ignore General Call, slave transfers are ignored,
+           disable interrupts, exit unknown bus state, enable hold
+           SCL
+           100kHz normaly or FastMode for 400kHz and above
+        */
+
+        val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL;
+        if( speed >= 400000 ){
+                val |= IIC_MDCNTL_FSM;
+        }
+	out8 (IIC_MDCNTL, val);
+
+	/* clear control reg */
+	out8 (IIC_CNTL, 0x00);
+	__asm__ volatile ("eieio");
+
+}
+
+/*
+  This code tries to use the features of the 405GP i2c
+  controller. It will transfer up to 4 bytes in one pass
+  on the loop. It only does out8(lbz) to the buffer when it
+  is possible to do out16(lhz) transfers.
+
+  cmd_type is 0 for write 1 for read.
+
+  addr_len can take any value from 0-255, it is only limited
+  by the char, we could make it larger if needed. If it is
+  0 we skip the address write cycle.
+
+  Typical case is a Write of an addr followd by a Read. The
+  IBM FAQ does not cover this. On the last byte of the write
+  we don't set the creg CHT bit, and on the first bytes of the
+  read we set the RPST bit.
+
+  It does not support address only transfers, there must be
+  a data part. If you want to write the address yourself, put
+  it in the data pointer.
+
+  It does not support transfer to/from address 0.
+
+  It does not check XFRCNT.
+*/
+static
+int i2c_transfer(unsigned char cmd_type,
+                 unsigned char chip,
+                 unsigned char addr[],
+                 unsigned char addr_len,
+                 unsigned char data[],
+		 unsigned short data_len )
+{
+        unsigned char* ptr;
+        int reading;
+        int tran,cnt;
+        int result;
+        int status;
+        int i;
+        uchar creg;
+
+        if( data == 0 || data_len == 0 ){
+                /*Don't support data transfer of no length or to address 0*/
+                printf( "i2c_transfer: bad call\n" );
+                return IIC_NOK;
+        }
+        if( addr && addr_len ){
+                ptr = addr;
+                cnt = addr_len;
+                reading = 0;
+        }else{
+                ptr = data;
+                cnt = data_len;
+                reading = cmd_type;
+        }
+
+        /*Clear Stop Complete Bit*/
+        out8(IIC_STS,IIC_STS_SCMP);
+        /* Check init */
+        i=10;
+        do {
+                /* Get status */
+                status = in8(IIC_STS);
+                __asm__ volatile("eieio");
+                i--;
+        } while ((status & IIC_STS_PT) && (i>0));
+
+        if (status & IIC_STS_PT) {
+                result = IIC_NOK_TOUT;
+                return(result);
+        }
+        /*flush the Master/Slave Databuffers*/
+        out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB));
+        /*need to wait 4 OPB clocks? code below should take that long*/
+
+        /* 7-bit adressing */
+        out8(IIC_HMADR,0);
+        out8(IIC_LMADR, chip);
+        __asm__ volatile("eieio");
+
+        tran = 0;
+        result = IIC_OK;
+        creg = 0;
+
+        while ( tran != cnt && (result == IIC_OK)) {
+                int  bc,j;
+
+                /* Control register =
+                   Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start,
+                   Transfer is a sequence of transfers
+                */
+                creg |= IIC_CNTL_PT;
+
+                bc = (cnt - tran) > 4 ? 4 :
+                        cnt - tran;
+                creg |= (bc-1)<<4;
+                /* if the real cmd type is write continue trans*/
+                if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) )
+                        creg |= IIC_CNTL_CHT;
+
+                if (reading)
+                        creg |= IIC_CNTL_READ;
+                else {
+                        for(j=0; j<bc; j++) {
+                                /* Set buffer */
+                                out8(IIC_MDBUF,ptr[tran+j]);
+                                __asm__ volatile("eieio");
+                        }
+                }
+                out8(IIC_CNTL, creg );
+                __asm__ volatile("eieio");
+
+                /* Transfer is in progress
+                   we have to wait for upto 5 bytes of data
+                   1 byte chip address+r/w bit then bc bytes
+                   of data.
+                   udelay(10) is 1 bit time at 100khz
+                   Doubled for slop. 20 is too small.
+		*/
+                i=2*5*8;
+                do {
+                        /* Get status */
+                        status = in8(IIC_STS);
+                        __asm__ volatile("eieio");
+                        udelay (10);
+                        i--;
+                } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR)
+			 && (i>0));
+
+                if (status & IIC_STS_ERR) {
+                        result = IIC_NOK;
+                        status = in8 (IIC_EXTSTS);
+                        /* Lost arbitration? */
+                        if (status & IIC_EXTSTS_LA)
+                                result = IIC_NOK_LA;
+                        /* Incomplete transfer? */
+                        if (status & IIC_EXTSTS_ICT)
+                                result = IIC_NOK_ICT;
+                        /* Transfer aborted? */
+                        if (status & IIC_EXTSTS_XFRA)
+                                result = IIC_NOK_XFRA;
+                } else if ( status & IIC_STS_PT) {
+                        result = IIC_NOK_TOUT;
+                }
+                /* Command is reading => get buffer */
+                if ((reading) && (result == IIC_OK)) {
+                        /* Are there data in buffer */
+                        if (status & IIC_STS_MDBS) {
+                                /*
+                                  even if we have data we have to wait 4OPB clocks
+                                  for it to hit the front of the FIFO, after that
+                                  we can just read. We should check XFCNT here and
+                                  if the FIFO is full there is no need to wait.
+				*/
+                                udelay (1);
+                                for(j=0;j<bc;j++) {
+                                        ptr[tran+j] = in8(IIC_MDBUF);
+                                        __asm__ volatile("eieio");
+                                }
+                        } else
+                                result = IIC_NOK_DATA;
+                }
+                creg = 0;
+                tran+=bc;
+                if( ptr == addr && tran == cnt ) {
+                        ptr = data;
+                        cnt = data_len;
+                        tran = 0;
+                        reading = cmd_type;
+                        if( reading )
+                                creg = IIC_CNTL_RPST;
+                }
+        }
+        return (result);
+}
+
+int i2c_probe (uchar chip)
+{
+	uchar buf[1];
+
+	buf[0] = 0;
+
+        /*
+         * What is needed is to send the chip address and verify that the
+         * address was <ACK>ed (i.e. there was a chip at that address which
+         * drove the data line low).
+         */
+        return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0);
+}
+
+
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+        uchar xaddr[4];
+        int ret;
+
+	if ( alen > 4 ) {
+		printf ("I2C read: addr len %d not supported\n", alen);
+		return 1;
+	}
+
+        if ( alen > 0 ) {
+                xaddr[0] = (addr >> 24) & 0xFF;
+                xaddr[1] = (addr >> 16) & 0xFF;
+                xaddr[2] = (addr >> 8) & 0xFF;
+                xaddr[3] = addr & 0xFF;
+        }
+
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+	/*
+         * EEPROM chips that implement "address overflow" are ones
+         * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+         * address and the extra bits end up in the "chip address"
+         * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+         * four 256 byte chips.
+	 *
+         * Note that we consider the length of the address field to
+         * still be one byte because the extra address bits are
+         * hidden in the chip address.
+	 */
+        if( alen > 0 )
+                chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+        if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) {
+                printf( "I2c read: failed %d\n", ret);
+                return 1;
+        }
+        return 0;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+        uchar xaddr[4];
+
+	if ( alen > 4 ) {
+		printf ("I2C write: addr len %d not supported\n", alen);
+		return 1;
+
+	}
+        if ( alen > 0 ) {
+                xaddr[0] = (addr >> 24) & 0xFF;
+                xaddr[1] = (addr >> 16) & 0xFF;
+                xaddr[2] = (addr >> 8) & 0xFF;
+                xaddr[3] = addr & 0xFF;
+        }
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+	/*
+         * EEPROM chips that implement "address overflow" are ones
+         * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+         * address and the extra bits end up in the "chip address"
+         * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+         * four 256 byte chips.
+	 *
+         * Note that we consider the length of the address field to
+         * still be one byte because the extra address bits are
+         * hidden in the chip address.
+	 */
+        if( alen > 0 )
+                chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+        return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0);
+}
+
+#endif	/* CONFIG_HARD_I2C */
diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c
new file mode 100644
index 0000000..d64bf96
--- /dev/null
+++ b/cpu/ppc4xx/sdram.c
@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2002
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.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 <ppc4xx.h>
+#include <asm/processor.h>
+#include <pci.h>
+
+
+#ifdef CONFIG_SDRAM_BANK0
+
+
+#define MAGIC0 0x00000000
+#define MAGIC1 0x11111111
+#define MAGIC2 0x22222222
+#define MAGIC3 0x33333333
+#define MAGIC4 0x44444444
+
+#define ADDR_ZERO 0x00000000
+#define ADDR_400  0x00000400
+#define ADDR_08MB 0x00800000
+#define ADDR_16MB 0x01000000
+#define ADDR_32MB 0x02000000
+#define ADDR_64MB 0x04000000
+
+#define mtsdram0(reg, data)  mtdcr(memcfga,reg);mtdcr(memcfgd,data)
+
+
+/*-----------------------------------------------------------------------
+ */
+void sdram_init(void)
+{
+	ulong speed;
+	ulong sdtr1;
+	ulong rtr;
+
+	/*
+	 * Determine SDRAM speed
+	 */
+	speed = get_bus_freq(0); /* parameter not used on ppc4xx */
+
+	/*
+	 * Support for 100MHz and 133MHz SDRAM
+	 */
+	if (speed > 100000000) {
+		/*
+		 * 133 MHz SDRAM
+		 */
+		sdtr1 = 0x01074015;
+		rtr = 0x07f00000;
+	} else {
+		/*
+		 * default: 100 MHz SDRAM
+		 */
+		sdtr1 = 0x0086400d;
+		rtr = 0x05f00000;
+	}
+
+	/*
+	 * Set MB0CF for bank 0. (0-64MB) Address Mode 3 since 13x9(4)
+	 */
+	mtsdram0(mem_mb0cf, 0x00084001);
+
+	mtsdram0(mem_sdtr1, sdtr1);
+	mtsdram0(mem_rtr, rtr);
+
+	/*
+	 * Wait for 200us
+	 */
+	udelay(200);
+
+	/*
+	 * Set memory controller options reg, MCOPT1.
+	 * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
+	 * read/prefetch.
+	 */
+	mtsdram0(mem_mcopt1, 0x80800000);
+
+	/*
+	 * Wait for 10ms
+	 */
+	udelay(10000);
+
+	/*
+	 * Test if 64 MByte are equipped (mirror test)
+	 */
+	*(volatile ulong *)ADDR_ZERO = MAGIC0;
+	*(volatile ulong *)ADDR_08MB = MAGIC1;
+	*(volatile ulong *)ADDR_16MB = MAGIC2;
+	*(volatile ulong *)ADDR_32MB = MAGIC3;
+
+	if ((*(volatile ulong *)ADDR_ZERO == MAGIC0) &&
+	    (*(volatile ulong *)ADDR_08MB == MAGIC1) &&
+	    (*(volatile ulong *)ADDR_16MB == MAGIC2)) {
+		/*
+		 * OK, 64MB detected -> all done
+		 */
+		return;
+	}
+
+	/*
+	 * Now test for 32 MByte...
+	 */
+
+        /*
+	 * Disable memory controller.
+	 */
+	mtsdram0(mem_mcopt1, 0x00000000);
+
+	/*
+	 * Set MB0CF for bank 0. (0-32MB) Address Mode 2 since 12x9(4)
+	 */
+	mtsdram0(mem_mb0cf, 0x00062001);
+
+	/*
+	 * Set memory controller options reg, MCOPT1.
+	 * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
+	 * read/prefetch.
+	 */
+	mtsdram0(mem_mcopt1, 0x80800000);
+
+	/*
+	 * Wait for 10ms
+	 */
+	udelay(10000);
+
+	/*
+	 * Test if 32 MByte are equipped (mirror test)
+	 */
+	*(volatile ulong *)ADDR_ZERO = MAGIC0;
+	*(volatile ulong *)ADDR_400  = MAGIC1;
+	*(volatile ulong *)ADDR_08MB = MAGIC2;
+	*(volatile ulong *)ADDR_16MB = MAGIC3;
+
+	if ((*(volatile ulong *)ADDR_ZERO == MAGIC0) &&
+	    (*(volatile ulong *)ADDR_400  == MAGIC1) &&
+	    (*(volatile ulong *)ADDR_08MB == MAGIC2)) {
+		/*
+		 * OK, 32MB detected -> all done
+		 */
+		return;
+	}
+
+	/*
+	 * Setup for 16 MByte...
+	 */
+
+        /*
+	 * Disable memory controller.
+	 */
+	mtsdram0(mem_mcopt1, 0x00000000);
+
+	/*
+	 * Set MB0CF for bank 0. (0-16MB) Address Mode 4 since 12x8(4)
+	 */
+	mtsdram0(mem_mb0cf, 0x00046001);
+
+	/*
+	 * Set memory controller options reg, MCOPT1.
+	 * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
+	 * read/prefetch.
+	 */
+	mtsdram0(mem_mcopt1, 0x80800000);
+
+	/*
+	 * Wait for 10ms
+	 */
+	udelay(10000);
+}
+
+#endif /* CONFIG_SDRAM_BANK0 */
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
new file mode 100644
index 0000000..4541529
--- /dev/null
+++ b/cpu/ppc4xx/speed.c
@@ -0,0 +1,308 @@
+/*
+ * (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 <ppc_asm.tmpl>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/* ------------------------------------------------------------------------- */
+
+#define ONE_BILLION        1000000000
+
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
+
+void get_sys_info (PPC405_SYS_INFO * sysInfo)
+{
+	unsigned long pllmr;
+	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+	uint pvr = get_pvr();
+	unsigned long psr;
+	unsigned long m;
+
+	/*
+	 * Read PLL Mode register
+	 */
+	pllmr = mfdcr (pllmd);
+
+	/*
+	 * Read Pin Strapping register
+	 */
+	psr = mfdcr (strap);
+
+	/*
+	 * Determine FWD_DIV.
+	 */
+	sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
+
+	/*
+	 * Determine FBK_DIV.
+	 */
+	sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
+	if (sysInfo->pllFbkDiv == 0) {
+		sysInfo->pllFbkDiv = 16;
+	}
+
+	/*
+	 * Determine PLB_DIV.
+	 */
+	sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
+
+	/*
+	 * Determine PCI_DIV.
+	 */
+	sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
+
+	/*
+	 * Determine EXTBUS_DIV.
+	 */
+	sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
+
+	/*
+	 * Determine OPB_DIV.
+	 */
+	sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
+
+	/*
+	 * Check if PPC405GPr used (mask minor revision field)
+	 */
+	if ((pvr & 0xfffffff0) == (PVR_405GPR_RA & 0xfffffff0)) {
+		/*
+		 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
+		 */
+		sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
+
+		/*
+		 * Determine factor m depending on PLL feedback clock source
+		 */
+		if (!(psr & PSR_PCI_ASYNC_EN)) {
+			if (psr & PSR_NEW_MODE_EN) {
+				/*
+				 * sync pci clock used as feedback (new mode)
+				 */
+				m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
+			} else {
+				/*
+				 * sync pci clock used as feedback (legacy mode)
+				 */
+				m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
+			}
+		} else if (psr & PSR_NEW_MODE_EN) {
+			if (psr & PSR_PERCLK_SYNC_MODE_EN) {
+				/*
+				 * PerClk used as feedback (new mode)
+				 */
+				m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
+			} else {
+				/*
+				 * CPU clock used as feedback (new mode)
+				 */
+				m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
+			}
+		} else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
+			/*
+			 * PerClk used as feedback (legacy mode)
+			 */
+			m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
+		} else {
+			/*
+			 * PLB clock used as feedback (legacy mode)
+			 */
+			m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
+		}
+
+		sysInfo->freqVCOMhz = (1000000 * m) / sysClkPeriodPs;
+		sysInfo->freqProcessor = (sysInfo->freqVCOMhz * 1000000) / sysInfo->pllFwdDiv;
+		sysInfo->freqPLB = (sysInfo->freqVCOMhz * 1000000) /
+			(sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
+	} else {
+		/*
+		 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
+		 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
+		 * to make sure it is within the proper range.
+		 *    spec:    VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
+		 * Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
+		 */
+		if (sysInfo->pllFwdDiv == 1) {
+			sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
+			sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
+		} else {
+			sysInfo->freqVCOMhz = ( 1000000 *
+						sysInfo->pllFwdDiv *
+						sysInfo->pllFbkDiv *
+						sysInfo->pllPlbDiv
+				) / sysClkPeriodPs;
+			if (sysInfo->freqVCOMhz >= VCO_MIN
+			    && sysInfo->freqVCOMhz <= VCO_MAX) {
+				sysInfo->freqPLB = (ONE_BILLION /
+						    ((sysClkPeriodPs * 10) /
+						     sysInfo->pllFbkDiv)) * 10000;
+				sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
+			} else {
+				printf ("\nInvalid VCO frequency calculated :  %ld MHz \a\n",
+					sysInfo->freqVCOMhz);
+				printf ("It must be between %d-%d MHz \a\n",
+					VCO_MIN, VCO_MAX);
+				printf ("PLL Mode reg           :  %8.8lx\a\n",
+					pllmr);
+				hang ();
+			}
+		}
+	}
+}
+
+
+/********************************************
+ * get_OPB_freq
+ * return OPB bus freq in Hz
+ *********************************************/
+ulong get_OPB_freq (void)
+{
+	ulong val = 0;
+
+	PPC405_SYS_INFO sys_info;
+
+	get_sys_info (&sys_info);
+	val = sys_info.freqPLB / sys_info.pllOpbDiv;
+
+	return val;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+	ulong val;
+	PPC405_SYS_INFO sys_info;
+
+	get_sys_info (&sys_info);
+	val = sys_info.freqPLB / sys_info.pllPciDiv;
+	return val;
+}
+
+
+#elif defined(CONFIG_440)
+void get_sys_info (sys_info_t * sysInfo)
+{
+	unsigned long strp0;
+	unsigned long temp;
+	unsigned long m;
+
+	/* Extract configured divisors */
+	strp0 = mfdcr( cpc0_strp0 );
+	sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
+	sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
+	temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
+	sysInfo->pllFbkDiv = temp ? temp : 16;
+	sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
+	sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
+
+	/* Calculate 'M' based on feedback source */
+	if( strp0 & PLLSYS0_EXTSL_MASK )
+		m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+	else
+		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+
+	/* Now calculate the individual clocks */
+	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
+    if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
+        sysInfo->freqPLB >>= 1;
+	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+	sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+
+}
+
+ulong get_OPB_freq (void)
+{
+
+	sys_info_t sys_info;
+	get_sys_info (&sys_info);
+	return sys_info.freqOPB;
+}
+
+#elif defined(CONFIG_405)
+
+void get_sys_info (sys_info_t * sysInfo) {
+
+	sysInfo->freqVCOMhz=3125000;
+	sysInfo->freqProcessor=12*1000*1000;
+	sysInfo->freqPLB=50*1000*1000;
+	sysInfo->freqPCI=66*1000*1000;
+
+}
+
+#endif
+
+int get_clocks (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405)
+	DECLARE_GLOBAL_DATA_PTR;
+
+	sys_info_t sys_info;
+
+	get_sys_info (&sys_info);
+	gd->cpu_clk = sys_info.freqProcessor;
+	gd->bus_clk = sys_info.freqPLB;
+
+#endif	/* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
+
+#ifdef CONFIG_IOP480
+	DECLARE_GLOBAL_DATA_PTR;
+
+	gd->cpu_clk = 66000000;
+	gd->bus_clk = 66000000;
+#endif
+	return (0);
+}
+
+
+/********************************************
+ * get_bus_freq
+ * return PLB bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+	ulong val;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_440)
+	sys_info_t sys_info;
+
+	get_sys_info (&sys_info);
+	val = sys_info.freqPLB;
+
+#elif defined(CONFIG_IOP480)
+
+	val = 66;
+
+#else
+# error get_bus_freq() not implemented
+#endif
+
+	return val;
+}
diff --git a/cpu/ppc4xx/vecnum.h b/cpu/ppc4xx/vecnum.h
new file mode 100644
index 0000000..d493a5d
--- /dev/null
+++ b/cpu/ppc4xx/vecnum.h
@@ -0,0 +1,100 @@
+/*
+*  Copyright (C) 2002 Scott McNutt <smcnutt@artesyncp.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
+*/
+
+/*
+ * Interrupt vector number definitions to ease the
+ * 405 -- 440 porting pain ;-)
+ *
+ * NOTE: They're not all here yet ... update as needed.
+ *
+ */
+
+#ifndef _VECNUMS_H_
+#define _VECNUMS_H_
+
+#if defined(CONFIG_440)
+
+/* UIC 0 */
+#define VECNUM_U0           0           /* UART0                        */
+#define VECNUM_U1           1           /* UART1                        */
+#define VECNUM_IIC0         2           /* IIC0                         */
+#define VECNUM_IIC1         3           /* IIC1                         */
+#define VECNUM_PIM          4           /* PCI inbound message          */
+#define VECNUM_PCRW         5           /* PCI command reg write        */
+#define VECNUM_PPM          6           /* PCI power management         */
+#define VECNUM_MSI0         7           /* PCI MSI level 0              */
+#define VECNUM_MSI1         8           /* PCI MSI level 0              */
+#define VECNUM_MSI2         9           /* PCI MSI level 0              */
+#define VECNUM_MTE          10          /* MAL TXEOB                    */
+#define VECNUM_MRE          11          /* MAL RXEOB                    */
+#define VECNUM_D0           12          /* DMA channel 0                */
+#define VECNUM_D1           13          /* DMA channel 1                */
+#define VECNUM_D2           14          /* DMA channel 2                */
+#define VECNUM_D3           15          /* DMA channel 3                */
+#define VECNUM_CT0          18          /* GPT compare timer 0          */
+#define VECNUM_CT1          19          /* GPT compare timer 1          */
+#define VECNUM_CT2          20          /* GPT compare timer 2          */
+#define VECNUM_CT3          21          /* GPT compare timer 3          */
+#define VECNUM_CT4          22          /* GPT compare timer 4          */
+#define VECNUM_EIR0         23          /* External interrupt 0         */
+#define VECNUM_EIR1         24          /* External interrupt 1         */
+#define VECNUM_EIR2         25          /* External interrupt 2         */
+#define VECNUM_EIR3         26          /* External interrupt 3         */
+#define VECNUM_EIR4         27          /* External interrupt 4         */
+#define VECNUM_EIR5         28          /* External interrupt 5         */
+#define VECNUM_EIR6         29          /* External interrupt 6         */
+#define VECNUM_UIC1NC       30          /* UIC1 non-critical interrupt  */
+#define VECNUM_UIC1C        31          /* UIC1 critical interrupt      */
+
+/* UIC 1 */
+#define VECNUM_MS           (32 + 0 )   /* MAL SERR                     */
+#define VECNUM_TXDE         (32 + 1 )   /* MAL TXDE                     */
+#define VECNUM_RXDE         (32 + 2 )   /* MAL RXDE                     */
+#define VECNUM_ETH0         (32 + 28)   /* Ethernet 0 interrupt status  */
+#define VECNUM_EWU0         (32 + 29)   /* Ethernet 0 wakeup            */
+
+#else /* !defined(CONFIG_440) */
+
+#define VECNUM_U0           0           /* UART0                        */
+#define VECNUM_U1           1           /* UART1                        */
+#define VECNUM_D0           5           /* DMA channel 0                */
+#define VECNUM_D1           6           /* DMA channel 1                */
+#define VECNUM_D2           7           /* DMA channel 2                */
+#define VECNUM_D3           8           /* DMA channel 3                */
+#define VECNUM_EWU0         9           /* Ethernet wakeup              */
+#define VECNUM_MS           10          /* MAL SERR                     */
+#define VECNUM_MTE          11          /* MAL TXEOB                    */
+#define VECNUM_MRE          12          /* MAL RXEOB                    */
+#define VECNUM_TXDE         13          /* MAL TXDE                     */
+#define VECNUM_RXDE         14          /* MAL RXDE                     */
+#define VECNUM_ETH0         15          /* Ethernet interrupt status    */
+#define VECNUM_EIR0         25          /* External interrupt 0         */
+#define VECNUM_EIR1         26          /* External interrupt 1         */
+#define VECNUM_EIR2         27          /* External interrupt 2         */
+#define VECNUM_EIR3         28          /* External interrupt 3         */
+#define VECNUM_EIR4         29          /* External interrupt 4         */
+#define VECNUM_EIR5         30          /* External interrupt 5         */
+#define VECNUM_EIR6         31          /* External interrupt 6         */
+
+#endif /* defined(CONFIG_440) */
+
+#endif /* _VECNUMS_H_ */
diff --git a/cpu/sa1100/Makefile b/cpu/sa1100/Makefile
new file mode 100644
index 0000000..8c950da
--- /dev/null
+++ b/cpu/sa1100/Makefile
@@ -0,0 +1,43 @@
+#
+# (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 $(TOPDIR)/config.mk
+
+LIB	= lib$(CPU).a
+
+START	= start.o
+OBJS	= serial.o interrupts.o cpu.o
+
+all:	.depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/xscale/serial.c b/cpu/xscale/serial.c
new file mode 100644
index 0000000..35302a7
--- /dev/null
+++ b/cpu/xscale/serial.c
@@ -0,0 +1,143 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <common.h>
+#include <asm/arch/pxa-regs.h>
+
+void serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	unsigned int quot = 0;
+
+	if (gd->baudrate == 1200)
+		quot = 192;
+	else if (gd->baudrate == 9600)
+		quot = 96;
+	else if (gd->baudrate == 19200)
+		quot = 48;
+	else if (gd->baudrate == 38400)
+		quot = 24;
+	else if (gd->baudrate == 57600)
+		quot = 16;
+	else if (gd->baudrate == 115200)
+		quot = 8;
+	else
+		hang ();
+
+#ifdef CONFIG_FFUART
+
+	CKEN |= CKEN6_FFUART;
+
+	FFIER = 0;					/* Disable for now */
+	FFFCR = 0;					/* No fifos enabled */
+
+	/* set baud rate */
+	FFLCR = LCR_WLS0 | LCR_WLS1 | LCR_DLAB;
+	FFDLL = quot & 0xff;
+	FFDLH = quot >> 8;
+	FFLCR = LCR_WLS0 | LCR_WLS1;
+
+	FFIER = IER_UUE;			/* Enable FFUART */
+
+#elif CONFIG_STUART
+#error "Bad: not implemented yet!"
+#else
+#error "Bad: you didn't configured serial ..."
+#endif
+}
+
+
+/*
+ * Initialise the serial port with the given baudrate. The settings
+ * are always 8 data bits, no parity, 1 stop bit, no start bits.
+ *
+ */
+int serial_init (void)
+{
+	serial_setbrg ();
+
+	return (0);
+}
+
+
+/*
+ * Output a single byte to the serial port.
+ */
+void serial_putc (const char c)
+{
+#ifdef CONFIG_FFUART
+	/* wait for room in the tx FIFO on FFUART */
+	while ((FFLSR & LSR_TEMT) == 0);
+
+	FFTHR = c;
+#elif CONFIG_STUART
+#endif
+
+	/* If \n, also do \r */
+	if (c == '\n')
+		serial_putc ('\r');
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+int serial_tstc (void)
+{
+#ifdef CONFIG_FFUART
+	return FFLSR & LSR_DR;
+#elif CONFIG_STUART
+#endif
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+int serial_getc (void)
+{
+#ifdef CONFIG_FFUART
+	while (!(FFLSR & LSR_DR));
+
+	return (char) FFRBR & 0xff;
+#elif CONFIG_STUART
+#endif
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
diff --git a/cpu/xscale/start.S b/cpu/xscale/start.S
new file mode 100644
index 0000000..f1049a8
--- /dev/null
+++ b/cpu/xscale/start.S
@@ -0,0 +1,412 @@
+/*
+ *  armboot - Startup Code for XScale
+ *
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000	Wolfgang Denk <wd@denx.de>
+ *  Copyright (c) 2001	Alex Züpke <azu@sysgo.de>
+ *  Copyright (c) 2002	Kyle Harris <kharris@nexus-tech.net>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+
+#include <config.h>
+#include <version.h>
+
+.globl _start
+_start:	b       reset
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:	.word undefined_instruction
+_software_interrupt:	.word software_interrupt
+_prefetch_abort:	.word prefetch_abort
+_data_abort:		.word data_abort
+_not_used:		.word not_used
+_irq:			.word irq
+_fiq:			.word fiq
+
+	.balignl 16,0xdeadbeef
+
+
+/*
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * - relocate armboot to ram
+ * - setup stack
+ * - jump to second stage
+ */
+
+/*
+ * CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h)
+ */
+_TEXT_BASE:
+	.word	TEXT_BASE
+
+.globl _armboot_start
+_armboot_start:
+	.word _start
+
+/*
+ * Note: _armboot_end_data and _armboot_end are defined
+ * by the (board-dependent) linker script.
+ * _armboot_end_data is the first usable FLASH address after armboot
+ */
+.globl _armboot_end_data
+_armboot_end_data:
+	.word armboot_end_data
+.globl _armboot_end
+_armboot_end:
+	.word armboot_end
+
+/*
+ * _armboot_real_end is the first usable RAM address behind armboot
+ * and the various stacks
+ */
+.globl _armboot_real_end
+_armboot_real_end:
+	.word 0x0badc0de
+
+/*
+ * We relocate uboot to this address (end of RAM - 128 KiB)
+ */
+.globl _uboot_reloc
+_uboot_reloc:
+	.word CFG_DRAM_BASE + CFG_DRAM_SIZE - CFG_MONITOR_LEN
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+
+/****************************************************************************/
+/*                                                                          */
+/* the actual reset code                                                    */
+/*                                                                          */
+/****************************************************************************/
+
+reset:
+	mrs	r0,cpsr			/* set the cpu to SVC32 mode        */
+	bic	r0,r0,#0x1f		/* (superviser mode, M=10011)       */
+	orr	r0,r0,#0x13
+	msr	cpsr,r0
+
+	bl	cpu_init_crit		/* we do sys-critical inits         */
+
+relocate:				/* relocate U-Boot to RAM          */
+	adr	r0, _start		/* r0 <- current position of code */
+	ldr	r2, _armboot_start
+	ldr	r3, _armboot_end
+	sub	r2, r3, r2		/* r2 <- size of armboot */
+/*	ldr	r1, _uboot_reloc	/ * r1 <- destination address        */
+	ldr	r1, _TEXT_BASE
+	add	r2, r0, r2		/* r2 <- source end address */
+
+copy_loop:
+	ldmia	r0!, {r3-r10}		/* copy from source address [r0]    */
+	stmia	r1!, {r3-r10}		/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end addreee [r2]    */
+	ble	copy_loop
+
+	/* Set up the stack                                                 */
+	ldr	r0, _uboot_reloc	/* upper 128 KiB: relocated uboot   */
+	sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
+					/* FIXME: bdinfo should be here     */
+	sub	sp, r0, #12		/* leave 3 words for abort-stack */
+
+	ldr	pc, _start_armboot
+
+_start_armboot:	.word start_armboot
+
+
+/****************************************************************************/
+/*                                                                          */
+/* CPU_init_critical registers                                              */
+/*                                                                          */
+/* - setup important registers                                              */
+/* - setup memory timing                                                    */
+/*                                                                          */
+/****************************************************************************/
+
+	/* Interrupt-Controller base address                                */
+IC_BASE:	   .word	   0x40d00000
+#define ICMR	0x04
+
+/* Reset-Controller */
+RST_BASE:	.word   0x40f00030
+#define RCSR	0x00
+
+
+	/* Clock Manager Registers                                          */
+CC_BASE:		.word	0x41300000
+#define CCCR    0x00
+cpuspeed:	.word   CFG_CPUSPEED
+
+	/* RS: ???                                                          */
+	.macro CPWAIT
+    mrc  p15,0,r0,c2,c0,0
+	mov  r0,r0
+	sub  pc,pc,#4
+	.endm
+
+
+cpu_init_crit:
+
+	/* mask all IRQs                                                    */
+	ldr	r0, IC_BASE
+	mov	r1, #0x00
+	str	r1, [r0, #ICMR]
+
+	/* set clock speed */
+	ldr	r0, CC_BASE
+	ldr	r1, cpuspeed
+	str	r1, [r0, #CCCR]
+
+	/*
+	 * before relocating, we have to setup RAM timing
+	 * because memory timing is board-dependend, you will
+	 * find a memsetup.S in your board directory.
+	 */
+	mov	ip,	lr
+	bl	memsetup
+	mov	lr,	ip
+
+	/* Memory interfaces are working. Disable MMU and enable I-cache.   */
+
+	ldr	r0, =0x2001		/* enable access to all coproc.     */
+	mcr	p15, 0, r0, c15, c1, 0
+    CPWAIT
+
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write & fill buffers   */
+    CPWAIT
+
+	mcr	p15, 0, r0, c7, c7, 0	/* flush Icache, Dcache and BTB     */
+    CPWAIT
+
+	mcr	p15, 0, r0, c8, c7, 0	/* flush instuction and data TLBs   */
+    CPWAIT
+
+	/* Enable the Icache                                                */
+/*
+	mrc	p15, 0, r0, c1, c0, 0
+	orr	r0, r0, #0x1800
+	mcr	p15, 0, r0, c1, c0, 0
+    CPWAIT
+*/
+	mov	pc, lr
+
+
+/****************************************************************************/
+/*                                                                          */
+/* Interrupt handling                                                       */
+/*                                                                          */
+/****************************************************************************/
+
+/* IRQ stack frame                                                          */
+
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+
+	/* use bad_save_user_regs for abort/prefetch/undef/swi ...          */
+
+	.macro	bad_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			/* Calling r0-r12           */
+	add     r8, sp, #S_PC
+
+	ldr	r2, _armboot_end
+	add	r2, r2, #CONFIG_STACKSIZE
+	sub	r2, r2, #8
+	ldmia	r2, {r2 - r4}                   /* get pc, cpsr, old_r0     */
+	add	r0, sp, #S_FRAME_SIZE		/* restore sp_SVC           */
+
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r4}                   /* save sp_SVC, lr_SVC, pc, cpsr, old_r */
+	mov	r0, sp
+	.endm
+
+
+	/* use irq_save_user_regs / irq_restore_user_regs for                */
+	/* IRQ/FIQ handling                                                  */
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			/* Calling r0-r12            */
+	add     r8, sp, #S_PC
+	stmdb   r8, {sp, lr}^                   /* Calling SP, LR            */
+	str     lr, [r8, #0]                    /* Save calling PC           */
+	mrs     r6, spsr
+	str     r6, [r8, #4]                    /* Save CPSR                 */
+	str     r0, [r8, #8]                    /* Save OLD_R0               */
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4			@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, _armboot_end		@ setup our mode stack
+	add	r13, r13, #CONFIG_STACKSIZE	@ resides at top of normal stack
+	sub	r13, r13, #8
+
+	str	lr, [r13]			@ save caller lr / spsr
+	mrs	lr, spsr
+	str     lr, [r13, #4]
+
+	mov	r13, #MODE_SVC			@ prepare SVC-Mode
+	msr	spsr_c, r13
+	mov	lr, pc
+	movs	pc, lr
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+
+
+/****************************************************************************/
+/*                                                                          */
+/* exception handlers                                                       */
+/*                                                                          */
+/****************************************************************************/
+
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl 	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	irq_save_user_regs		/* someone ought to write a more    */
+	bl 	do_fiq			/* effiction fiq_save_user_regs     */
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl 	do_fiq
+
+#endif
+
+/*
+ * FIXME How do we reset??? Watchdog timeout??
+ */
+	.align	5
+.globl reset_cpu
+reset_cpu:
+	/*
+	ldr	r0, RST_BASE
+	mov	r1, #0x0			@ set bit 3-0 ...
+	str	r1, [r0, #RCSR]			@ ... to clear in RCSR
+	mov	r1, #0x1
+	str	r1, [r0, #RCSR]			@ and perform reset
+	*/
+	b	reset_cpu			@ silly, but repeat endlessly
+