ppc: Move cpu/$CPU to arch/ppc/cpu/$CPU

Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
diff --git a/arch/ppc/cpu/74xx_7xx/Makefile b/arch/ppc/cpu/74xx_7xx/Makefile
new file mode 100644
index 0000000..fe905f3
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2001
+# Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+SOBJS	= cache.o kgdb.o io.o
+COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/74xx_7xx/cache.S b/arch/ppc/cpu/74xx_7xx/cache.S
new file mode 100644
index 0000000..66c7298
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/cache.S
@@ -0,0 +1,404 @@
+#include <config.h>
+#include <74xx_7xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE L1_CACHE_BYTES
+#endif
+
+#if CACHE_LINE_SIZE == 128
+#define LG_CACHE_LINE_SIZE 7
+#elif CACHE_LINE_SIZE == 32
+#define LG_CACHE_LINE_SIZE 5
+#elif CACHE_LINE_SIZE == 16
+#define LG_CACHE_LINE_SIZE 4
+#elif CACHE_LINE_SIZE == 8
+#define LG_CACHE_LINE_SIZE 3
+#else
+# error "Invalid cache line size!"
+#endif
+
+/*
+ * Invalidate L1 instruction cache.
+ */
+_GLOBAL(invalidate_l1_instruction_cache)
+	mfspr	r3,PVR
+	rlwinm	r3,r3,16,16,31
+	cmpi	0,r3,1
+	beqlr			/* for 601, do nothing */
+	/* 603/604 processor - use invalidate-all bit in HID0 */
+	mfspr	r3,HID0
+	ori	r3,r3,HID0_ICFI
+	mtspr	HID0,r3
+	isync
+	blr
+
+/*
+ * Invalidate L1 data cache.
+ */
+_GLOBAL(invalidate_l1_data_cache)
+	mfspr	r3,HID0
+	ori	r3,r3,HID0_DCFI
+	mtspr	HID0,r3
+	isync
+	blr
+
+/*
+ * Flush data cache.
+ */
+_GLOBAL(flush_dcache)
+	lis	r3,0
+	lis	r5,CACHE_LINE_SIZE
+flush:
+	cmp	0,1,r3,r5
+	bge	done
+	lwz	r5,0(r3)
+	lis	r5,CACHE_LINE_SIZE
+	addi	r3,r3,0x4
+	b	flush
+done:
+	blr
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+	mfspr	r5,PVR
+	rlwinm	r5,r5,16,16,31
+	cmpi	0,r5,1
+	beqlr				/* for 601, do nothing */
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,CACHE_LINE_SIZE
+	bdnz	2b
+	sync				/* additional sync needed on g4 */
+	isync
+	blr
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5	/* align r3 down to cache line */
+	subf	r4,r3,r4	/* r4 = offset of stop from start of cache line */
+	add	r4,r4,r5	/* r4 += cache_line_size-1 */
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE  /* r4 = number of cache lines to flush */
+	beqlr				  /* if r4 == 0 return */
+	mtctr	r4			  /* ctr = r4 */
+
+	sync
+1:	dcbst	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+	sync
+1:	dcbf	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbf's to get to ram */
+	blr
+
+/*
+ * Like above, but invalidate the D-cache.  This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+	sync
+1:	dcbi	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbi's to get to ram */
+	blr
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ *	void __flush_page_to_ram(void *page)
+ */
+_GLOBAL(__flush_page_to_ram)
+	mfspr	r5,PVR
+	rlwinm	r5,r5,16,16,31
+	cmpi	0,r5,1
+	beqlr				/* for 601, do nothing */
+	rlwinm	r3,r3,0,0,19		/* Get page base address */
+	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
+	mtctr	r4
+	mr	r6,r3
+0:	dcbst	0,r3			/* Write line to ram */
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	0b
+	sync
+	mtctr	r4
+1:	icbi	0,r6
+	addi	r6,r6,CACHE_LINE_SIZE
+	bdnz	1b
+	sync
+	isync
+	blr
+
+/*
+ * Flush a particular page from the instruction cache.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ *	void __flush_icache_page(void *page)
+ */
+_GLOBAL(__flush_icache_page)
+	mfspr	r5,PVR
+	rlwinm	r5,r5,16,16,31
+	cmpi	0,r5,1
+	beqlr				/* for 601, do nothing */
+	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
+	mtctr	r4
+1:	icbi	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync
+	isync
+	blr
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced).  This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+1:	dcbz	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	blr
+
+/*
+ * Enable L1 Instruction cache
+ */
+_GLOBAL(icache_enable)
+	mfspr	r3, HID0
+	li	r5, HID0_ICFI|HID0_ILOCK
+	andc	r3, r3, r5
+	ori	r3, r3, HID0_ICE
+	ori	r5, r3, HID0_ICFI
+	mtspr	HID0, r5
+	mtspr	HID0, r3
+	isync
+	blr
+
+/*
+ * Disable L1 Instruction cache
+ */
+_GLOBAL(icache_disable)
+	mflr	r4
+	bl	invalidate_l1_instruction_cache		/* uses r3 */
+	sync
+	mtlr	r4
+	mfspr	r3, HID0
+	li	r5, 0
+	ori	r5, r5, HID0_ICE
+	andc	r3, r3, r5
+	mtspr	HID0, r3
+	isync
+	blr
+
+/*
+ * Is instruction cache enabled?
+ */
+_GLOBAL(icache_status)
+	mfspr	r3, HID0
+	andi.	r3, r3, HID0_ICE
+	blr
+
+
+_GLOBAL(l1dcache_enable)
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	ori	r3, r3, HID0_DCE
+	ori	r5, r3, HID0_DCFI
+	mtspr	HID0, r5		/* enable + invalidate */
+	mtspr	HID0, r3		/* enable */
+	sync
+	blr
+
+/*
+ * Enable data cache(s) - L1 and optionally L2
+ * Calls l2cache_enable. LR saved in r5
+ */
+_GLOBAL(dcache_enable)
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	ori	r3, r3, HID0_DCE
+	ori	r5, r3, HID0_DCFI
+	mtspr	HID0, r5		/* enable + invalidate */
+	mtspr	HID0, r3		/* enable */
+	sync
+#ifdef CONFIG_SYS_L2
+	mflr	r5
+	bl	l2cache_enable		/* uses r3 and r4 */
+	sync
+	mtlr	r5
+#endif
+	blr
+
+
+/*
+ * Disable data cache(s) - L1 and optionally L2
+ * Calls flush_dcache and l2cache_disable_no_flush.
+ * LR saved in r4
+ */
+_GLOBAL(dcache_disable)
+	mflr	r4			/* save link register */
+	bl	flush_dcache	/* uses r3 and r5 */
+	sync
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	li	r5, HID0_DCE|HID0_DCFI
+	andc	r3, r3, r5		/* no enable, no invalidate */
+	mtspr	HID0, r3
+	sync
+#ifdef CONFIG_SYS_L2
+	bl	l2cache_disable_no_flush /* uses r3 */
+#endif
+	mtlr	r4			/* restore link register */
+	blr
+
+/*
+ * Is data cache enabled?
+ */
+_GLOBAL(dcache_status)
+	mfspr	r3, HID0
+	andi.	r3, r3, HID0_DCE
+	blr
+
+/*
+ * Invalidate L2 cache using L2I and polling L2IP or L2I
+ */
+_GLOBAL(l2cache_invalidate)
+	sync
+	mfspr r3, l2cr
+	oris	r3, r3, L2CR_L2I@h
+	sync
+	mtspr	l2cr, r3
+	sync
+	mfspr r3, PVR
+	sync
+	rlwinm r3, r3, 16,16,31
+	cmpli 0,r3,0x8000  /* 7451, 7441 */
+	beq 0,inv_7450
+	cmpli 0,r3,0x8001  /* 7455, 7445 */
+	beq 0,inv_7450
+	cmpli 0,r3,0x8002  /* 7457, 7447 */
+	beq 0,inv_7450
+	cmpli 0,r3,0x8003  /* 7447A */
+	beq 0,inv_7450
+	cmpli 0,r3,0x8004  /* 7448 */
+	beq 0,inv_7450
+invl2:
+	mfspr	r3, l2cr
+	andi.	r3, r3, L2CR_L2IP
+	bne	invl2
+	/* turn off the global invalidate bit */
+	mfspr	r3, l2cr
+	rlwinm	r3, r3, 0, 11, 9
+	sync
+	mtspr	l2cr, r3
+	sync
+	blr
+inv_7450:
+	mfspr	r3, l2cr
+	andis. r3, r3, L2CR_L2I@h
+	bne inv_7450
+	blr
+
+/*
+ * Enable L2 cache
+ * Calls l2cache_invalidate. LR is saved in r4
+ */
+_GLOBAL(l2cache_enable)
+	mflr	r4			/* save link register */
+	bl	l2cache_invalidate	/* uses r3 */
+	sync
+	lis	r3, L2_ENABLE@h
+	ori	r3, r3, L2_ENABLE@l
+	mtspr	l2cr, r3
+	isync
+	mtlr	r4			/* restore link register */
+	blr
+
+/*
+ * Disable L2 cache
+ * Calls flush_dcache. LR is saved in r4
+ */
+_GLOBAL(l2cache_disable)
+	mflr	r4			/* save link register */
+	bl	flush_dcache		/* uses r3 and r5 */
+	sync
+	mtlr	r4			/* restore link register */
+l2cache_disable_no_flush:		/* provide way to disable L2 w/o flushing */
+	lis	r3, L2_INIT@h
+	ori	r3, r3, L2_INIT@l
+	mtspr	l2cr, r3
+	isync
+	blr
diff --git a/arch/ppc/cpu/74xx_7xx/config.mk b/arch/ppc/cpu/74xx_7xx/config.mk
new file mode 100644
index 0000000..df1f6ac
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2001
+# Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_74xx_7xx -ffixed-r2 -mstring
diff --git a/arch/ppc/cpu/74xx_7xx/cpu.c b/arch/ppc/cpu/74xx_7xx/cpu.c
new file mode 100644
index 0000000..3c17277
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/cpu.c
@@ -0,0 +1,320 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cpu.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * more modifications by
+ * Josh Huber <huber@mclx.com>
+ * added support for the 74xx series of cpus
+ * added support for the 7xx series of cpus
+ * made the code a little less hard-coded, and more auto-detectish
+ */
+
+#include <common.h>
+#include <command.h>
+#include <74xx_7xx.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#ifdef CONFIG_AMIGAONEG3SE
+#include "../board/MAI/AmigaOneG3SE/via686.h"
+#include "../board/MAI/AmigaOneG3SE/memio.h"
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+cpu_t
+get_cpu_type(void)
+{
+	uint pvr = get_pvr();
+	cpu_t type;
+
+	type = CPU_UNKNOWN;
+
+	switch (PVR_VER(pvr)) {
+	case 0x000c:
+		type = CPU_7400;
+		break;
+	case 0x0008:
+		type = CPU_750;
+
+		if (((pvr >> 8) & 0xff) == 0x01) {
+			type = CPU_750CX;	/* old CX (80100 and 8010x?)*/
+		} else if (((pvr >> 8) & 0xff) == 0x22) {
+			type = CPU_750CX;	/* CX (82201,82202) and CXe (82214) */
+		} else if (((pvr >> 8) & 0xff) == 0x33) {
+			type = CPU_750CX;	/* CXe (83311) */
+		} else if (((pvr >> 12) & 0xF) == 0x3) {
+			type = CPU_755;
+		}
+		break;
+
+	case 0x7000:
+		type = CPU_750FX;
+		break;
+
+	case 0x7002:
+		type = CPU_750GX;
+		break;
+
+	case 0x800C:
+		type = CPU_7410;
+		break;
+
+	case 0x8000:
+		type = CPU_7450;
+		break;
+
+	case 0x8001:
+		type = CPU_7455;
+		break;
+
+	case 0x8002:
+		type = CPU_7457;
+		break;
+
+	case 0x8003:
+		type = CPU_7447A;
+		break;
+
+	case 0x8004:
+		type = CPU_7448;
+		break;
+
+	default:
+		break;
+	}
+
+	return type;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if !defined(CONFIG_BAB7xx)
+int checkcpu (void)
+{
+	uint type   = get_cpu_type();
+	uint pvr    = get_pvr();
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+	char *str;
+
+	puts ("CPU:   ");
+
+	switch (type) {
+	case CPU_750CX:
+		printf ("750CX%s v%d.%d", (pvr&0xf0)?"e":"",
+			(pvr>>8) & 0xf,
+			pvr & 0xf);
+		goto	PR_CLK;
+
+	case CPU_750:
+		str = "750";
+		break;
+
+	case CPU_750FX:
+		str = "750FX";
+		break;
+
+	case CPU_750GX:
+		str = "750GX";
+		break;
+
+	case CPU_755:
+		str = "755";
+		break;
+
+	case CPU_7400:
+		str = "MPC7400";
+		break;
+
+	case CPU_7410:
+		str = "MPC7410";
+		break;
+
+	case CPU_7447A:
+		str = "MPC7447A";
+		break;
+
+	case CPU_7448:
+		str = "MPC7448";
+		break;
+
+	case CPU_7450:
+		str = "MPC7450";
+		break;
+
+	case CPU_7455:
+		str = "MPC7455";
+		break;
+
+	case CPU_7457:
+		str = "MPC7457";
+		break;
+
+	default:
+		printf("Unknown CPU -- PVR: 0x%08x\n", pvr);
+		return -1;
+	}
+
+	printf ("%s v%d.%d", str, (pvr >> 8) & 0xFF, pvr & 0xFF);
+PR_CLK:
+	printf (" @ %s MHz\n", strmhz(buf, clock));
+
+	return (0);
+}
+#endif
+/* these two functions are unimplemented currently [josh] */
+
+/* -------------------------------------------------------------------- */
+/* L1 i-cache								*/
+
+int
+checkicache(void)
+{
+	return 0; /* XXX */
+}
+
+/* -------------------------------------------------------------------- */
+/* L1 d-cache								*/
+
+int
+checkdcache(void)
+{
+	return 0; /* XXX */
+}
+
+/* -------------------------------------------------------------------- */
+
+static inline void
+soft_restart(unsigned long addr)
+{
+	/* SRR0 has system reset vector, SRR1 has default MSR value */
+	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+
+	__asm__ __volatile__ ("mtspr	26, %0"		:: "r" (addr));
+	__asm__ __volatile__ ("li	4, (1 << 6)"	::: "r4");
+	__asm__ __volatile__ ("mtspr	27, 4");
+	__asm__ __volatile__ ("rfi");
+
+	while(1);	/* not reached */
+}
+
+
+#if !defined(CONFIG_PCIPPC2) && \
+    !defined(CONFIG_BAB7xx)  && \
+    !defined(CONFIG_ELPPC)   && \
+    !defined(CONFIG_PPMC7XX)
+/* no generic way to do board reset. simply call soft_reset. */
+void
+do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	ulong addr;
+	/* flush and disable I/D cache */
+	__asm__ __volatile__ ("mfspr	3, 1008"	::: "r3");
+	__asm__ __volatile__ ("ori	5, 5, 0xcc00"	::: "r5");
+	__asm__ __volatile__ ("ori	4, 3, 0xc00"	::: "r4");
+	__asm__ __volatile__ ("andc	5, 3, 5"	::: "r5");
+	__asm__ __volatile__ ("sync");
+	__asm__ __volatile__ ("mtspr	1008, 4");
+	__asm__ __volatile__ ("isync");
+	__asm__ __volatile__ ("sync");
+	__asm__ __volatile__ ("mtspr	1008, 5");
+	__asm__ __volatile__ ("isync");
+	__asm__ __volatile__ ("sync");
+
+#ifdef CONFIG_SYS_RESET_ADDRESS
+	addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address,
+	 * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid
+	 * address. Better pick an address known to be invalid on your
+	 * system and assign it to CONFIG_SYS_RESET_ADDRESS.
+	 */
+	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+	soft_restart(addr);
+	while(1);	/* not reached */
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * For the 7400 the TB clock runs at 1/4 the cpu bus speed.
+ */
+#if defined(CONFIG_AMIGAONEG3SE) || defined(CONFIG_SYS_CONFIG_BUS_CLK)
+unsigned long get_tbclk(void)
+{
+	return (gd->bus_clk / 4);
+}
+#else	/* ! CONFIG_AMIGAONEG3SE and !CONFIG_SYS_CONFIG_BUS_CLK*/
+
+unsigned long get_tbclk (void)
+{
+	return CONFIG_SYS_BUS_HZ / 4;
+}
+#endif	/* CONFIG_AMIGAONEG3SE or CONFIG_SYS_CONFIG_BUS_CLK*/
+/* ------------------------------------------------------------------------- */
+#if defined(CONFIG_WATCHDOG)
+#if !defined(CONFIG_PCIPPC2) && !defined(CONFIG_BAB7xx)
+void
+watchdog_reset(void)
+{
+
+}
+#endif  /* !CONFIG_PCIPPC2 && !CONFIG_BAB7xx */
+#endif	/* CONFIG_WATCHDOG */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_OF_LIBFDT
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+			     "timebase-frequency", bd->bi_busfreq / 4, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+			     "bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+			     "clock-frequency", bd->bi_intfreq, 1);
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+	fdt_fixup_ethernet(blob);
+}
+#endif
+/* ------------------------------------------------------------------------- */
diff --git a/arch/ppc/cpu/74xx_7xx/cpu_init.c b/arch/ppc/cpu/74xx_7xx/cpu_init.c
new file mode 100644
index 0000000..1dd1b2c
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/cpu_init.c
@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cpu_init.c - low level cpu init
+ *
+ * there's really nothing going on here yet.  future work area?
+ */
+
+#include <common.h>
+#include <74xx_7xx.h>
+
+/*
+ * Breath some life into the CPU...
+ *
+ * there's basically nothing to do here since the memory controller
+ * isn't on the CPU in this case.
+ */
+void
+cpu_init_f (void)
+{
+	switch (get_cpu_type()) {
+	case CPU_7450:
+	case CPU_7455:
+	case CPU_7457:
+	case CPU_7447A:
+	case CPU_7448:
+		/* enable the timebase bit in HID0 */
+		set_hid0(get_hid0() | 0x4000000);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+	return (0);
+}
diff --git a/arch/ppc/cpu/74xx_7xx/interrupts.c b/arch/ppc/cpu/74xx_7xx/interrupts.c
new file mode 100644
index 0000000..0ea1aec
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/interrupts.c
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * interrupts.c - just enough support for the decrementer/timer
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <asm/processor.h>
+#include <commproc.h>
+#include <command.h>
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+#if defined(DEBUG) && !defined(CONFIG_AMIGAONEG3SE)
+	printf("interrupt_init: GT main cause reg: %08x:%08x\n",
+	       GTREGREAD(LOW_INTERRUPT_CAUSE_REGISTER),
+	       GTREGREAD(HIGH_INTERRUPT_CAUSE_REGISTER));
+	printf("interrupt_init: ethernet cause regs: %08x %08x %08x\n",
+	       GTREGREAD(ETHERNET0_INTERRUPT_CAUSE_REGISTER),
+	       GTREGREAD(ETHERNET1_INTERRUPT_CAUSE_REGISTER),
+	       GTREGREAD(ETHERNET2_INTERRUPT_CAUSE_REGISTER));
+	printf("interrupt_init: ethernet mask regs:  %08x %08x %08x\n",
+	       GTREGREAD(ETHERNET0_INTERRUPT_MASK_REGISTER),
+	       GTREGREAD(ETHERNET1_INTERRUPT_MASK_REGISTER),
+	       GTREGREAD(ETHERNET2_INTERRUPT_MASK_REGISTER));
+	puts("interrupt_init: setting decrementer_count\n");
+#endif
+	*decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+
+	return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void
+external_interrupt(struct pt_regs *regs)
+{
+	puts("external_interrupt (oops!)\n");
+}
+
+volatile ulong timestamp = 0;
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void
+timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void
+irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+
+}
+
+void
+irq_free_handler(int vec)
+{
+
+}
+
+/****************************************************************************/
+
+void
+do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+	puts("IRQ related functions are unimplemented currently.\n");
+}
diff --git a/arch/ppc/cpu/74xx_7xx/io.S b/arch/ppc/cpu/74xx_7xx/io.S
new file mode 100644
index 0000000..af2e6d1
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/io.S
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2001	Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *			Andreas Heppel <aheppel@sysgo.de>
+ *  Copyright (C) 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
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in8 */
+/*  Description:  Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  in8
+in8:
+	lbz     r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in16 */
+/*  Description:  Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  in16
+in16:
+	lhz     r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in16r */
+/*  Description:  Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+	.globl  in16r
+in16r:
+	lhbrx   r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in32 */
+/*  Description:  Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  in32
+in32:
+	lwz     3,0(3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in32r */
+/*  Description:  Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+    .globl  in32r
+in32r:
+	lwbrx   r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out8 */
+/*  Description:  Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out8
+out8:
+	stb     r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out16 */
+/*  Description:  Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out16
+out16:
+	sth     r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out16r */
+/*  Description:  Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out16r
+out16r:
+	sthbrx  r4,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out32 */
+/*  Description:  Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out32
+out32:
+	stw     r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out32r */
+/*  Description:  Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out32r
+out32r:
+	stwbrx  r4,0,r3
+	sync
+	blr
diff --git a/arch/ppc/cpu/74xx_7xx/kgdb.S b/arch/ppc/cpu/74xx_7xx/kgdb.S
new file mode 100644
index 0000000..ad487cd
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/kgdb.S
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (C) 2000	Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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-1307USA
+ */
+
+#include <config.h>
+#include <command.h>
+#include <74xx_7xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+
+ /*
+ * cache flushing routines for kgdb
+ */
+
+	.globl	kgdb_flush_cache_all
+kgdb_flush_cache_all:
+	lis	r3,0
+	addis	r4,r0,0x0040
+kgdb_flush_loop:
+	lwz	r5,0(r3)
+	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE
+	cmp	0,0,r3,r4
+	bne	kgdb_flush_loop
+	SYNC
+	mfspr	r3,1008
+	ori	r3,r3,0x8800
+	mtspr	1008,r3
+	sync
+	blr
+
+	.globl	kgdb_flush_cache_range
+kgdb_flush_cache_range:
+	li	r5,CONFIG_SYS_CACHELINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,CONFIG_SYS_CACHELINE_SHIFT
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	2b
+	SYNC
+	blr
+
+#endif
diff --git a/arch/ppc/cpu/74xx_7xx/speed.c b/arch/ppc/cpu/74xx_7xx/speed.c
new file mode 100644
index 0000000..f2fdcd5
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/speed.c
@@ -0,0 +1,185 @@
+/*
+ * (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 <74xx_7xx.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_AMIGAONEG3SE
+#include "../board/MAI/AmigaOneG3SE/via686.h"
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern unsigned long get_board_bus_clk (void);
+
+static const int hid1_multipliers_x_10[] = {
+	25,	/* 0000 - 2.5x */
+	75,	/* 0001 - 7.5x */
+	70,	/* 0010 - 7x */
+	10,	/* 0011 - bypass */
+	20,	/* 0100 - 2x */
+	65,	/* 0101 - 6.5x */
+	100,	/* 0110 - 10x */
+	45,	/* 0111 - 4.5x */
+	30,	/* 1000 - 3x */
+	55,	/* 1001 - 5.5x */
+	40,	/* 1010 - 4x */
+	50,	/* 1011 - 5x */
+	80,	/* 1100 - 8x */
+	60,	/* 1101 - 6x */
+	35,	/* 1110 - 3.5x */
+	0	/* 1111 - off */
+};
+
+/* PLL_CFG[0:4] table for cpu 7448/7447A/7455/7457 */
+static const int hid1_74xx_multipliers_x_10[] = {
+	115,	/* 00000 - 11.5x  */
+	170,	/* 00001 - 17x    */
+	75,	/* 00010 -  7.5x  */
+	150,	/* 00011 - 15x    */
+	70,	/* 00100 -  7x    */
+	180,	/* 00101 - 18x    */
+	10,	/* 00110 - bypass */
+	200,	/* 00111 - 20x    */
+	20,	/* 01000 -  2x    */
+	210,	/* 01001 - 21x    */
+	65,	/* 01010 -  6.5x  */
+	130,	/* 01011 - 13x    */
+	85,	/* 01100 -  8.5x  */
+	240,	/* 01101 - 24x    */
+	95,	/* 01110 -  9.5x  */
+	90,	/* 01111 -  9x    */
+	30,	/* 10000 -  3x    */
+	105,	/* 10001 - 10.5x  */
+	55,	/* 10010 -  5.5x  */
+	110,	/* 10011 - 11x    */
+	40,	/* 10100 -  4x    */
+	100,	/* 10101 - 10x    */
+	50,	/* 10110 -  5x    */
+	120,	/* 10111 - 12x    */
+	80,	/* 11000 -  8x    */
+	140,	/* 11001 - 14x    */
+	60,	/* 11010 -  6x    */
+	160,	/* 11011 - 16x    */
+	135,	/* 11100 - 13.5x  */
+	280,	/* 11101 - 28x    */
+	0,	/* 11110 - off    */
+	125	/* 11111 - 12.5x  */
+};
+
+static const int hid1_fx_multipliers_x_10[] = {
+	00,	/* 0000 - off */
+	00,	/* 0001 - off */
+	10,	/* 0010 - bypass */
+	10,	/* 0011 - bypass */
+	20,	/* 0100 - 2x */
+	25,	/* 0101 - 2.5x */
+	30,	/* 0110 - 3x */
+	35,	/* 0111 - 3.5x */
+	40,	/* 1000 - 4x */
+	45,	/* 1001 - 4.5x */
+	50,	/* 1010 - 5x */
+	55,	/* 1011 - 5.5x */
+	60,	/* 1100 - 6x */
+	65,	/* 1101 - 6.5x */
+	70,	/* 1110 - 7x */
+	75,	/* 1111 - 7.5 */
+	80,	/* 10000 - 8x */
+	85,	/* 10001 - 8.5x */
+	90,	/* 10010 - 9x */
+	95,	/* 10011 - 9.5x */
+	100,	/* 10100 - 10x */
+	110,	/* 10101 - 11x */
+	120,	/* 10110 - 12x */
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ *
+ * (Approx. GCLK frequency in Hz)
+ */
+
+int get_clocks (void)
+{
+	ulong clock = 0;
+
+#ifdef CONFIG_SYS_BUS_CLK
+	gd->bus_clk = CONFIG_SYS_BUS_CLK;	/* bus clock is a fixed frequency */
+#else
+	gd->bus_clk = get_board_bus_clk ();	/* bus clock is configurable */
+#endif
+
+	/* calculate the clock frequency based upon the CPU type */
+	switch (get_cpu_type()) {
+	case CPU_7447A:
+	case CPU_7448:
+	case CPU_7455:
+	case CPU_7457:
+		/*
+		 * Make sure division is done before multiplication to prevent 32-bit
+		 * arithmetic overflows which will cause a negative number
+		 */
+		clock = (gd->bus_clk / 10) *
+			hid1_74xx_multipliers_x_10[(get_hid1 () >> 12) & 0x1F];
+		break;
+
+	case CPU_750GX:
+	case CPU_750FX:
+		clock = (gd->bus_clk / 10) *
+			hid1_fx_multipliers_x_10[get_hid1 () >> 27];
+		break;
+
+	case CPU_7450:
+	case CPU_740:
+	case CPU_740P:
+	case CPU_745:
+	case CPU_750CX:
+	case CPU_750:
+	case CPU_750P:
+	case CPU_755:
+	case CPU_7400:
+	case CPU_7410:
+		/*
+		 * Make sure division is done before multiplication to prevent 32-bit
+		 * arithmetic overflows which will cause a negative number
+		 */
+		clock = (gd->bus_clk / 10) *
+			hid1_multipliers_x_10[get_hid1 () >> 28];
+		break;
+
+	case CPU_UNKNOWN:
+	       printf ("get_gclk_freq(): unknown CPU type\n");
+	       clock = 0;
+	       return (1);
+	}
+
+	gd->cpu_clk = clock;
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/ppc/cpu/74xx_7xx/start.S b/arch/ppc/cpu/74xx_7xx/start.S
new file mode 100644
index 0000000..88fdf88
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/start.S
@@ -0,0 +1,874 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ *  Copyright (C) 2001  Josh Huber <huber@mclx.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*  U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ *  The processor starts at 0xfff00100 and the code is executed
+ *  from flash. The code is organized to be at an other address
+ *  in memory, but as long we don't jump around before relocating.
+ *  board_init lies at a quite high address and when the cpu has
+ *  jumped there, everything is ok.
+ */
+#include <config.h>
+#include <74xx_7xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if !defined(CONFIG_DB64360) && \
+    !defined(CONFIG_DB64460) && \
+    !defined(CONFIG_CPCI750) && \
+    !defined(CONFIG_P3Mx)
+#include <galileo/gt64260R.h>
+#endif
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+/* Machine Check and Recoverable Interr. */
+#define MSR_KERNEL ( MSR_ME | MSR_RI )
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+	.text
+	.long	0x27051956		/* U-Boot Magic Number		*/
+	.globl	version_string
+version_string:
+	.ascii	U_BOOT_VERSION
+	.ascii	" (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii	CONFIG_IDENT_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH */
+	b	boot_cold
+	sync
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM	/* Software reboot		*/
+	b	boot_warm
+	sync
+
+	/* the boot code is located below the exception table */
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	/* No FPU on MPC8xx.  This exception is not supposed to happen.
+	*/
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	/*
+	 * On the MPC8xx, this is a software emulation interrupt. It
+	 * occurs for all unimplemented and illegal instructions.
+	 */
+	STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+	STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+	STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+	STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+	STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+	STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+	STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+	STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+	STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+	STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x2000
+
+boot_cold:
+boot_warm:
+	/* disable everything */
+	li	r0, 0
+	mtspr	HID0, r0
+	sync
+	mtmsr	0
+	bl	invalidate_bats
+	sync
+
+#ifdef CONFIG_SYS_L2
+	/* init the L2 cache */
+	addis	r3, r0, L2_INIT@h
+	ori	r3, r3, L2_INIT@l
+	sync
+	mtspr	l2cr, r3
+#endif
+#if defined(CONFIG_ALTIVEC) && defined(CONFIG_74xx)
+	.long	0x7e00066c
+		/*
+		 * dssall instruction, gas doesn't have it yet
+		 * ...for altivec, data stream stop all this probably
+		 * isn't needed unless we warm (software) reboot U-Boot
+		 */
+#endif
+
+#ifdef CONFIG_SYS_L2
+	/* invalidate the L2 cache */
+	bl	l2cache_invalidate
+	sync
+#endif
+#ifdef CONFIG_SYS_BOARD_ASM_INIT
+	/* do early init */
+	bl	board_asm_init
+#endif
+
+	/*
+	 * Calculate absolute address in FLASH and jump there
+	 *------------------------------------------------------*/
+	lis	r3, CONFIG_SYS_MONITOR_BASE@h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE@l
+	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r3
+	blr
+
+in_flash:
+	/* let the C-code set up the rest			*/
+	/*							*/
+	/* Be careful to keep code relocatable !		*/
+	/*------------------------------------------------------*/
+
+	/* perform low-level init */
+	/* sdram init, galileo init, etc */
+	/* r3:	NHR bit from HID0 */
+
+	/* setup the bats */
+	bl	setup_bats
+	sync
+
+	/*
+	 * Cache must be enabled here for stack-in-cache trick.
+	 * This means we need to enable the BATS.
+	 * This means:
+	 *   1) for the EVB, original gt regs need to be mapped
+	 *   2) need to have an IBAT for the 0xf region,
+	 *      we are running there!
+	 * Cache should be turned on after BATs, since by default
+	 * everything is write-through.
+	 * The init-mem BAT can be reused after reloc. The old
+	 * gt-regs BAT can be reused after board_init_f calls
+	 * board_early_init_f (EVB only).
+	 */
+#if !defined(CONFIG_BAB7xx) && !defined(CONFIG_ELPPC) && !defined(CONFIG_P3Mx)
+	/* enable address translation */
+	bl	enable_addr_trans
+	sync
+
+	/* enable and invalidate the data cache */
+	bl	l1dcache_enable
+	sync
+#endif
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+	bl	lock_ram_in_cache
+	sync
+#endif
+
+	/* set up the stack pointer in our newly created
+	 * cache-ram (r1) */
+	lis	r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+	li	r0, 0		/* Make room for stack frame header and	*/
+	stwu	r0, -4(r1)	/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/
+
+	GET_GOT			/* initialize GOT access	*/
+
+	/* run low-level CPU init code     (from Flash)	*/
+	bl	cpu_init_f
+	sync
+
+	mr	r3, r21
+
+	/* r3: BOOTFLAG */
+	/* run 1st part of board init code (from Flash)   */
+	bl	board_init_f
+	sync
+
+	/* NOTREACHED */
+
+	.globl	invalidate_bats
+invalidate_bats:
+	/* invalidate BATs */
+	mtspr	IBAT0U, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT3U, r0
+#ifdef CONFIG_HIGH_BATS
+	mtspr   IBAT4U, r0
+	mtspr   IBAT5U, r0
+	mtspr   IBAT6U, r0
+	mtspr   IBAT7U, r0
+#endif
+	isync
+	mtspr	DBAT0U, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT3U, r0
+#ifdef CONFIG_HIGH_BATS
+	mtspr   DBAT4U, r0
+	mtspr   DBAT5U, r0
+	mtspr   DBAT6U, r0
+	mtspr   DBAT7U, r0
+#endif
+	isync
+	sync
+	blr
+
+	/* setup_bats - set them up to some initial state */
+	.globl	setup_bats
+setup_bats:
+	addis	r0, r0, 0x0000
+
+	/* IBAT 0 */
+	addis	r4, r0, CONFIG_SYS_IBAT0L@h
+	ori	r4, r4, CONFIG_SYS_IBAT0L@l
+	addis	r3, r0, CONFIG_SYS_IBAT0U@h
+	ori	r3, r3, CONFIG_SYS_IBAT0U@l
+	mtspr	IBAT0L, r4
+	mtspr	IBAT0U, r3
+	isync
+
+	/* DBAT 0 */
+	addis	r4, r0, CONFIG_SYS_DBAT0L@h
+	ori	r4, r4, CONFIG_SYS_DBAT0L@l
+	addis	r3, r0, CONFIG_SYS_DBAT0U@h
+	ori	r3, r3, CONFIG_SYS_DBAT0U@l
+	mtspr	DBAT0L, r4
+	mtspr	DBAT0U, r3
+	isync
+
+	/* IBAT 1 */
+	addis	r4, r0, CONFIG_SYS_IBAT1L@h
+	ori	r4, r4, CONFIG_SYS_IBAT1L@l
+	addis	r3, r0, CONFIG_SYS_IBAT1U@h
+	ori	r3, r3, CONFIG_SYS_IBAT1U@l
+	mtspr	IBAT1L, r4
+	mtspr	IBAT1U, r3
+	isync
+
+	/* DBAT 1 */
+	addis	r4, r0, CONFIG_SYS_DBAT1L@h
+	ori	r4, r4, CONFIG_SYS_DBAT1L@l
+	addis	r3, r0, CONFIG_SYS_DBAT1U@h
+	ori	r3, r3, CONFIG_SYS_DBAT1U@l
+	mtspr	DBAT1L, r4
+	mtspr	DBAT1U, r3
+	isync
+
+	/* IBAT 2 */
+	addis	r4, r0, CONFIG_SYS_IBAT2L@h
+	ori	r4, r4, CONFIG_SYS_IBAT2L@l
+	addis	r3, r0, CONFIG_SYS_IBAT2U@h
+	ori	r3, r3, CONFIG_SYS_IBAT2U@l
+	mtspr	IBAT2L, r4
+	mtspr	IBAT2U, r3
+	isync
+
+	/* DBAT 2 */
+	addis	r4, r0, CONFIG_SYS_DBAT2L@h
+	ori	r4, r4, CONFIG_SYS_DBAT2L@l
+	addis	r3, r0, CONFIG_SYS_DBAT2U@h
+	ori	r3, r3, CONFIG_SYS_DBAT2U@l
+	mtspr	DBAT2L, r4
+	mtspr	DBAT2U, r3
+	isync
+
+	/* IBAT 3 */
+	addis	r4, r0, CONFIG_SYS_IBAT3L@h
+	ori	r4, r4, CONFIG_SYS_IBAT3L@l
+	addis	r3, r0, CONFIG_SYS_IBAT3U@h
+	ori	r3, r3, CONFIG_SYS_IBAT3U@l
+	mtspr	IBAT3L, r4
+	mtspr	IBAT3U, r3
+	isync
+
+	/* DBAT 3 */
+	addis	r4, r0, CONFIG_SYS_DBAT3L@h
+	ori	r4, r4, CONFIG_SYS_DBAT3L@l
+	addis	r3, r0, CONFIG_SYS_DBAT3U@h
+	ori	r3, r3, CONFIG_SYS_DBAT3U@l
+	mtspr	DBAT3L, r4
+	mtspr	DBAT3U, r3
+	isync
+
+#ifdef CONFIG_HIGH_BATS
+	/* IBAT 4 */
+	addis   r4, r0, CONFIG_SYS_IBAT4L@h
+	ori     r4, r4, CONFIG_SYS_IBAT4L@l
+	addis   r3, r0, CONFIG_SYS_IBAT4U@h
+	ori     r3, r3, CONFIG_SYS_IBAT4U@l
+	mtspr   IBAT4L, r4
+	mtspr   IBAT4U, r3
+	isync
+
+	/* DBAT 4 */
+	addis   r4, r0, CONFIG_SYS_DBAT4L@h
+	ori     r4, r4, CONFIG_SYS_DBAT4L@l
+	addis   r3, r0, CONFIG_SYS_DBAT4U@h
+	ori     r3, r3, CONFIG_SYS_DBAT4U@l
+	mtspr   DBAT4L, r4
+	mtspr   DBAT4U, r3
+	isync
+
+	/* IBAT 5 */
+	addis   r4, r0, CONFIG_SYS_IBAT5L@h
+	ori     r4, r4, CONFIG_SYS_IBAT5L@l
+	addis   r3, r0, CONFIG_SYS_IBAT5U@h
+	ori     r3, r3, CONFIG_SYS_IBAT5U@l
+	mtspr   IBAT5L, r4
+	mtspr   IBAT5U, r3
+	isync
+
+	/* DBAT 5 */
+	addis   r4, r0, CONFIG_SYS_DBAT5L@h
+	ori     r4, r4, CONFIG_SYS_DBAT5L@l
+	addis   r3, r0, CONFIG_SYS_DBAT5U@h
+	ori     r3, r3, CONFIG_SYS_DBAT5U@l
+	mtspr   DBAT5L, r4
+	mtspr   DBAT5U, r3
+	isync
+
+	/* IBAT 6 */
+	addis   r4, r0, CONFIG_SYS_IBAT6L@h
+	ori     r4, r4, CONFIG_SYS_IBAT6L@l
+	addis   r3, r0, CONFIG_SYS_IBAT6U@h
+	ori     r3, r3, CONFIG_SYS_IBAT6U@l
+	mtspr   IBAT6L, r4
+	mtspr   IBAT6U, r3
+	isync
+
+	/* DBAT 6 */
+	addis   r4, r0, CONFIG_SYS_DBAT6L@h
+	ori     r4, r4, CONFIG_SYS_DBAT6L@l
+	addis   r3, r0, CONFIG_SYS_DBAT6U@h
+	ori     r3, r3, CONFIG_SYS_DBAT6U@l
+	mtspr   DBAT6L, r4
+	mtspr   DBAT6U, r3
+	isync
+
+	/* IBAT 7 */
+	addis   r4, r0, CONFIG_SYS_IBAT7L@h
+	ori     r4, r4, CONFIG_SYS_IBAT7L@l
+	addis   r3, r0, CONFIG_SYS_IBAT7U@h
+	ori     r3, r3, CONFIG_SYS_IBAT7U@l
+	mtspr   IBAT7L, r4
+	mtspr   IBAT7U, r3
+	isync
+
+	/* DBAT 7 */
+	addis   r4, r0, CONFIG_SYS_DBAT7L@h
+	ori     r4, r4, CONFIG_SYS_DBAT7L@l
+	addis   r3, r0, CONFIG_SYS_DBAT7U@h
+	ori     r3, r3, CONFIG_SYS_DBAT7U@l
+	mtspr   DBAT7L, r4
+	mtspr   DBAT7U, r3
+	isync
+#endif
+
+	/* bats are done, now invalidate the TLBs */
+
+	addis	r3, 0, 0x0000
+	addis	r5, 0, 0x4    /* upper bound of 0x00040000 for 7400/750 */
+
+	isync
+
+tlblp:
+	tlbie	r3
+	sync
+	addi	r3, r3, 0x1000
+	cmp	0, 0, r3, r5
+	blt tlblp
+
+	blr
+
+	.globl enable_addr_trans
+enable_addr_trans:
+	/* enable address translation */
+	mfmsr	r5
+	ori	r5, r5, (MSR_IR | MSR_DR)
+	mtmsr	r5
+	isync
+	blr
+
+	.globl disable_addr_trans
+disable_addr_trans:
+	/* disable address translation */
+	mflr	r4
+	mfmsr	r3
+	andi.	r0, r3, (MSR_IR | MSR_DR)
+	beqlr
+	andc	r3, r3, r0
+	mtspr	SRR0, r4
+	mtspr	SRR1, r3
+	rfi
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+	.globl	dc_read
+dc_read:
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+/*-----------------------------------------------------------------------*/
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3		/* Set new stack pointer		*/
+	mr	r9,  r4		/* Save copy of Global Data pointer	*/
+	mr	r10, r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+#ifdef CONFIG_ECC
+	bl	board_relocate_rom
+	sync
+	mr	r3, r10				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+#else
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+1:	lwzu	r0,4(r8)
+	stwu	r0,4(r7)
+	bdnz	1b
+	b	4f
+
+2:	slwi	r0,r0,2
+	add	r8,r4,r0
+	add	r7,r3,r0
+3:	lwzu	r0,-4(r8)
+	stwu	r0,-4(r7)
+	bdnz	3b
+#endif
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4:	cmpwi	r6,0
+	add	r5,r3,r5
+	beq	7f		/* Always flush prefetch queue in any case */
+	subi	r0,r6,1
+	andc	r3,r3,r0
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+#ifdef CONFIG_ECC
+	bl	board_init_ecc
+#endif
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+/* clear_bss: */
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+	mr	r3, r10		/* Destination Address		*/
+#if defined(CONFIG_AMIGAONEG3SE) || \
+    defined(CONFIG_DB64360)	 || \
+    defined(CONFIG_DB64460)      || \
+    defined(CONFIG_CPCI750)	|| \
+    defined(CONFIG_PPMC7XX)     || \
+    defined(CONFIG_P3Mx)
+	mr	r4, r9		/* Use RAM copy of the global data */
+#endif
+	bl	after_reloc
+
+	/* not reached - end relocate_code */
+/*-----------------------------------------------------------------------*/
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	/* enable execptions from RAM vectors */
+	mfmsr	r7
+	li	r8,MSR_IP
+	andc	r7,r7,r8
+	mtmsr	r7
+
+	mtlr	r4			/* restore link register	*/
+	blr
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+	/* Allocate Initial RAM in data cache.
+	 */
+	lis	r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+	ori	r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+	li	r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+		     (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+	mtctr	r4
+1:
+	dcbz	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+
+	/* Lock the data cache */
+	mfspr	r0, HID0
+	ori	r0, r0, 0x1000
+	sync
+	mtspr	HID0, r0
+	sync
+	blr
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+	/* invalidate the INIT_RAM section */
+	lis	r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+	ori	r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+	li	r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+		     (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+	mtctr	r4
+1:	icbi	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+	/* Unlock the data cache and invalidate it */
+	mfspr   r0, HID0
+	li      r3,0x1000
+	andc    r0,r0,r3
+	li	r3,0x0400
+	or	r0,r0,r3
+	sync
+	mtspr   HID0, r0
+	sync
+	blr
+#endif
diff --git a/arch/ppc/cpu/74xx_7xx/traps.c b/arch/ppc/cpu/74xx_7xx/traps.c
new file mode 100644
index 0000000..1d5dd01
--- /dev/null
+++ b/arch/ppc/cpu/74xx_7xx/traps.c
@@ -0,0 +1,252 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_AMIGAONEG3SE
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#ifdef CONFIG_AMIGAONEG3SE
+#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize)
+#else
+#define END_OF_MEM	0x02000000
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void
+show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+	       " %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP:"
+	       " %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0)
+		{
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7)
+		{
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		printf("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13):
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL;
+	int i, j;
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+
+	p = (unsigned char *) ((unsigned long)p & 0xFFFFFFE0);
+	p -= 32;
+	for (i = 0; i < 256; i+=16) {
+		printf("%08x: ", (unsigned int)p+i);
+		for (j = 0; j < 16; j++) {
+			printf("%02x ", p[i+j]);
+		}
+		printf("\n");
+	}
+
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc512x/Makefile b/arch/ppc/cpu/mpc512x/Makefile
new file mode 100644
index 0000000..1719c66
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/Makefile
@@ -0,0 +1,63 @@
+#
+# (C) Copyright 2007-2009 DENX Software Engineering
+#
+# 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
+
+$(shell mkdir -p $(OBJTREE)/board/freescale/common)
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+COBJS-y	:= cpu.o
+COBJS-y	+= traps.o
+COBJS-y += cpu_init.o
+COBJS-y += fixed_sdram.o
+COBJS-y += i2c.o
+COBJS-y += interrupts.o
+COBJS-y += iopin.o
+COBJS-y += serial.o
+COBJS-y += speed.o
+COBJS-${CONFIG_FSL_DIU_FB} += diu.o
+COBJS-${CONFIG_FSL_DIU_FB} += ../../../../board/freescale/common/fsl_diu_fb.o
+COBJS-${CONFIG_FSL_DIU_FB} += ../../../../board/freescale/common/fsl_logo_bmp.o
+COBJS-${CONFIG_CMD_IDE} += ide.o
+COBJS-${CONFIG_IIM} += iim.o
+COBJS-$(CONFIG_PCI) += pci.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc512x/asm-offsets.h b/arch/ppc/cpu/mpc512x/asm-offsets.h
new file mode 100644
index 0000000..5873fe0
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/asm-offsets.h
@@ -0,0 +1,15 @@
+/*
+ * needed for arch/ppc/cpu/mpc512x/start.S
+ *
+ * These should be auto-generated
+ */
+#define LPCS0AW			0x0024
+#define SRAMBAR			0x00C4
+#define SWCRR			0x0904
+#define LPC_OFFSET		0x10000
+#define CS0_CONFIG		0x00000
+#define CS_CTRL			0x00020
+#define CS_CTRL_ME		0x01000000	/* CS Master Enable bit */
+
+#define EXC_OFF_SYS_RESET	0x0100
+#define	_START_OFFSET		EXC_OFF_SYS_RESET
diff --git a/arch/ppc/cpu/mpc512x/config.mk b/arch/ppc/cpu/mpc512x/config.mk
new file mode 100644
index 0000000..b6727dc
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/config.mk
@@ -0,0 +1,29 @@
+#
+# (C) Copyright 2007-2009 DENX Software Engineering
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC512X -DCONFIG_E300 \
+			-ffixed-r2 -msoft-float -mcpu=603e
+
+# Use default linker script.
+# A board port can override this setting in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc512x/u-boot.lds
diff --git a/arch/ppc/cpu/mpc512x/cpu.c b/arch/ppc/cpu/mpc512x/cpu.c
new file mode 100644
index 0000000..09cbd20
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/cpu.c
@@ -0,0 +1,216 @@
+/*
+ * (C) Copyright 2007-2010 DENX Software Engineering
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC512x family.
+ *
+ * Derived from the MPC83xx code.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	ulong clock = gd->cpu_clk;
+	u32 pvr = get_pvr ();
+	u32 spridr = in_be32(&immr->sysconf.spridr);
+	char buf1[32], buf2[32];
+
+	puts ("CPU:   ");
+
+	switch (spridr & 0xffff0000) {
+	case SPR_5121E:
+		puts ("MPC5121e ");
+		break;
+	default:
+		printf ("Unknown part ID %08x ", spridr & 0xffff0000);
+	}
+	printf ("rev. %d.%d, Core ", SVR_MJREV (spridr), SVR_MNREV (spridr));
+
+	switch (pvr & 0xffff0000) {
+	case PVR_E300C4:
+		puts ("e300c4 ");
+		break;
+	default:
+		puts ("unknown ");
+	}
+	printf ("at %s MHz, CSB at %s MHz (RSR=0x%04lx)\n",
+		strmhz(buf1, clock),
+		strmhz(buf2, gd->csb_clk),
+		gd->reset_status & 0xffff);
+	return 0;
+}
+
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong msr;
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~( MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/*
+	 * Enable Reset Control Reg - "RSTE" is the magic word that let us go
+	 */
+	out_be32(&immap->reset.rpr, 0x52535445);
+
+	/* Verify Reset Control Reg is enabled */
+	while (!(in_be32(&immap->reset.rcer) & RCER_CRE))
+		;
+
+	printf ("Resetting the board.\n");
+	udelay(200);
+
+	/* Perform reset */
+	out_be32(&immap->reset.rcr, RCR_SWHR);
+
+	/* Unreached... */
+	return 1;
+}
+
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+unsigned long get_tbclk (void)
+{
+	ulong tbclk;
+
+	tbclk = (gd->bus_clk + 3L) / 4L;
+
+	return tbclk;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts ();
+
+	/* Reset watchdog */
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	out_be32(&immr->wdt.swsrr, 0x556c);
+	out_be32(&immr->wdt.swsrr, 0xaa39);
+
+	if (re_enable)
+		enable_interrupts ();
+}
+#endif
+
+#ifdef CONFIG_OF_LIBFDT
+
+#ifdef CONFIG_OF_SUPPORT_OLD_DEVICE_TREES
+/*
+ * fdt setup for old device trees
+ * fix up
+ * 	cpu clocks
+ * 	soc clocks
+ * 	ethernet addresses
+ */
+static void old_ft_cpu_setup(void *blob, bd_t *bd)
+{
+	/*
+	 * avoid fixing up by path because that
+	 * produces scary error messages
+	 */
+	uchar enetaddr[6];
+
+	/*
+	 * old device trees have ethernet nodes with
+	 * device_type = "network"
+	 */
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	do_fixup_by_prop(blob, "device_type", "network", 8,
+		"local-mac-address", enetaddr, 6, 0);
+	do_fixup_by_prop(blob, "device_type", "network", 8,
+		"address", enetaddr, 6, 0);
+	/*
+	 * old device trees have soc nodes with
+	 * device_type = "soc"
+	 */
+	do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+		"bus-frequency", bd->bi_ipsfreq, 0);
+}
+#endif
+
+static void ft_clock_setup(void *blob, bd_t *bd)
+{
+	char *cpu_path = "/cpus/" OF_CPU;
+
+	/*
+	 * fixup cpu clocks using path
+	 */
+	do_fixup_by_path_u32(blob, cpu_path,
+		"timebase-frequency", OF_TBCLK, 1);
+	do_fixup_by_path_u32(blob, cpu_path,
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_path_u32(blob, cpu_path,
+		"clock-frequency", bd->bi_intfreq, 1);
+	/*
+	 * fixup soc clocks using compatible
+	 */
+	do_fixup_by_compat_u32(blob, OF_SOC_COMPAT,
+		"bus-frequency", bd->bi_ipsfreq, 1);
+}
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_OF_SUPPORT_OLD_DEVICE_TREES
+	old_ft_cpu_setup(blob, bd);
+#endif
+	ft_clock_setup(blob, bd);
+#ifdef CONFIG_HAS_ETH0
+	fdt_fixup_ethernet(blob);
+#endif
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
+#endif
+
+#ifdef CONFIG_MPC512x_FEC
+/* Default initializations for FEC controllers.  To override,
+ * create a board-specific function called:
+ * 	int board_eth_init(bd_t *bis)
+ */
+
+int cpu_eth_init(bd_t *bis)
+{
+	return mpc512x_fec_initialize(bis);
+}
+#endif
diff --git a/arch/ppc/cpu/mpc512x/cpu_init.c b/arch/ppc/cpu/mpc512x/cpu_init.c
new file mode 100644
index 0000000..fe6beaf
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/cpu_init.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007-2009 DENX Software Engineering
+ *
+ * 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
+ *
+ * Derived from the MPC83xx code.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Set up the memory map, initialize registers,
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+	u32 ips_div;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	memset ((void *) gd, 0, sizeof (gd_t));
+
+	/* system performance tweaking */
+
+#ifdef CONFIG_SYS_ACR_PIPE_DEP
+	/* Arbiter pipeline depth */
+	out_be32(&im->arbiter.acr,
+		(im->arbiter.acr & ~ACR_PIPE_DEP) |
+		(CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT)
+	);
+#endif
+
+#ifdef CONFIG_SYS_ACR_RPTCNT
+	/* Arbiter repeat count */
+	out_be32(im->arbiter.acr,
+		(im->arbiter.acr & ~(ACR_RPTCNT)) |
+		(CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT)
+	);
+#endif
+
+	/* RSR - Reset Status Register - clear all status */
+	gd->reset_status = im->reset.rsr;
+	out_be32(&im->reset.rsr, ~RSR_RES);
+
+	/*
+	 * RMR - Reset Mode Register - enable checkstop reset
+	 */
+	out_be32(&im->reset.rmr, RMR_CSRE & (1 << RMR_CSRE_SHIFT));
+
+	/* Set IPS-CSB divider: IPS = 1/2 CSB */
+	ips_div = in_be32(&im->clk.scfr[0]);
+	ips_div &= ~(SCFR1_IPS_DIV_MASK);
+	ips_div |= SCFR1_IPS_DIV << SCFR1_IPS_DIV_SHIFT;
+	out_be32(&im->clk.scfr[0], ips_div);
+
+	/*
+	 * Enable Time Base/Decrementer
+	 *
+	 * NOTICE: TB needs to be enabled as early as possible in order to
+	 * have udelay() working; if not enabled, usually leads to a hang, like
+	 * during FLASH chip identification etc.
+	 */
+	setbits_be32(&im->sysconf.spcr, SPCR_TBEN);
+}
+
+int cpu_init_r (void)
+{
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc512x/diu.c b/arch/ppc/cpu/mpc512x/diu.c
new file mode 100644
index 0000000..9361161
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/diu.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ * York Sun <yorksun@freescale.com>
+ *
+ * FSL DIU Framebuffer driver
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#include "../../../../board/freescale/common/fsl_diu_fb.h"
+
+#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
+#include <stdio_dev.h>
+#include <video_fb.h>
+#endif
+
+#ifdef CONFIG_FSL_DIU_LOGO_BMP
+extern unsigned int FSL_Logo_BMP[];
+#else
+#define FSL_Logo_BMP NULL
+#endif
+
+static int xres, yres;
+
+void diu_set_pixel_clock(unsigned int pixclock)
+{
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+	volatile clk512x_t *clk = &immap->clk;
+	volatile unsigned int *clkdvdr = &clk->scfr[0];
+	unsigned long speed_ccb, temp, pixval;
+
+	speed_ccb = get_bus_freq(0) * 4;
+	temp = 1000000000/pixclock;
+	temp *= 1000;
+	pixval = speed_ccb / temp;
+	debug("DIU pixval = %lu\n", pixval);
+
+	/* Modify PXCLK in GUTS CLKDVDR */
+	debug("DIU: Current value of CLKDVDR = 0x%08x\n", in_be32(clkdvdr));
+	temp = in_be32(clkdvdr) & 0xFFFFFF00;
+	out_be32(clkdvdr, temp | (pixval & 0xFF));
+	debug("DIU: Modified value of CLKDVDR = 0x%08x\n", in_be32(clkdvdr));
+}
+
+char *valid_bmp(char *addr)
+{
+	unsigned long h_addr;
+
+	h_addr = simple_strtoul(addr, NULL, 16);
+	if (h_addr < CONFIG_SYS_FLASH_BASE ||
+			h_addr >= (CONFIG_SYS_FLASH_BASE + CONFIG_SYS_FLASH_SIZE - 1)) {
+		printf("bmp addr %lx is not a valid flash address\n", h_addr);
+		return 0;
+	} else if ((*(char *)(h_addr) != 'B') || (*(char *)(h_addr+1) != 'M')) {
+		printf("bmp addr is not a bmp\n");
+		return 0;
+	} else
+		return (char *)h_addr;
+}
+
+int mpc5121_diu_init(void)
+{
+	unsigned int pixel_format;
+	char *bmp = NULL;
+	char *bmp_env;
+
+	xres = 1024;
+	yres = 768;
+	pixel_format = 0x88883316;
+
+	debug("mpc5121_diu_init\n");
+	bmp_env = getenv("diu_bmp_addr");
+	if (bmp_env) {
+		bmp = valid_bmp(bmp_env);
+	}
+	if (!bmp)
+		bmp = (char *)FSL_Logo_BMP;
+	return fsl_diu_init(xres, pixel_format, 0, (unsigned char *)bmp);
+}
+
+int mpc5121diu_init_show_bmp(cmd_tbl_t *cmdtp,
+			     int flag, int argc, char *argv[])
+{
+	unsigned int addr;
+
+	if (argc < 2) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	if (!strncmp(argv[1], "init", 4)) {
+#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
+		fsl_diu_clear_screen();
+		drv_video_init();
+#else
+		return mpc5121_diu_init();
+#endif
+	} else {
+		addr = simple_strtoul(argv[1], NULL, 16);
+		fsl_diu_clear_screen();
+		fsl_diu_display_bmp((unsigned char *)addr, 0, 0, 0);
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	diufb, CONFIG_SYS_MAXARGS, 1, mpc5121diu_init_show_bmp,
+	"Init or Display BMP file",
+	"init\n    - initialize DIU\n"
+	"addr\n    - display bmp at address 'addr'"
+	);
+
+
+#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
+
+/*
+ * The Graphic Device
+ */
+GraphicDevice ctfb;
+void *video_hw_init(void)
+{
+	GraphicDevice *pGD = (GraphicDevice *) &ctfb;
+	struct fb_info *info;
+
+	if (mpc5121_diu_init() < 0)
+		return NULL;
+
+	/* fill in Graphic device struct */
+	sprintf(pGD->modeIdent, "%dx%dx%d %dkHz %dHz",
+		xres, yres, 32, 64, 60);
+
+	pGD->frameAdrs = (unsigned int)fsl_fb_open(&info);
+	pGD->winSizeX = xres;
+	pGD->winSizeY = yres - info->logo_height;
+	pGD->plnSizeX = pGD->winSizeX;
+	pGD->plnSizeY = pGD->winSizeY;
+
+	pGD->gdfBytesPP = 4;
+	pGD->gdfIndex = GDF_32BIT_X888RGB;
+
+	pGD->isaBase = 0;
+	pGD->pciBase = 0;
+	pGD->memSize = info->screen_size - info->logo_size;
+
+	/* Cursor Start Address */
+	pGD->dprBase = 0;
+	pGD->vprBase = 0;
+	pGD->cprBase = 0;
+
+	return (void *)pGD;
+}
+
+/**
+  * Set the LUT
+  *
+  * @index: color number
+  * @r: red
+  * @b: blue
+  * @g: green
+  */
+void video_set_lut
+	(unsigned int index, unsigned char r, unsigned char g, unsigned char b)
+{
+	return;
+}
+
+#endif /* defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) */
diff --git a/arch/ppc/cpu/mpc512x/fixed_sdram.c b/arch/ppc/cpu/mpc512x/fixed_sdram.c
new file mode 100644
index 0000000..442b5fc
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/fixed_sdram.c
@@ -0,0 +1,152 @@
+/*
+ * (C) Copyright 2007-2009 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/mpc512x.h>
+
+/*
+ * MDDRC Config Runtime Settings
+ */
+ddr512x_config_t default_mddrc_config = {
+	.ddr_sys_config   = CONFIG_SYS_MDDRC_SYS_CFG,
+	.ddr_time_config0 = CONFIG_SYS_MDDRC_TIME_CFG0,
+	.ddr_time_config1 = CONFIG_SYS_MDDRC_TIME_CFG1,
+	.ddr_time_config2 = CONFIG_SYS_MDDRC_TIME_CFG2,
+};
+
+u32 default_init_seq[] = {
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_PCHG_ALL,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_RFSH,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_RFSH,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_MICRON_INIT_DEV_OP,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_EM2,
+	CONFIG_SYS_DDRCMD_NOP,
+	CONFIG_SYS_DDRCMD_PCHG_ALL,
+	CONFIG_SYS_DDRCMD_EM2,
+	CONFIG_SYS_DDRCMD_EM3,
+	CONFIG_SYS_DDRCMD_EN_DLL,
+	CONFIG_SYS_MICRON_INIT_DEV_OP,
+	CONFIG_SYS_DDRCMD_PCHG_ALL,
+	CONFIG_SYS_DDRCMD_RFSH,
+	CONFIG_SYS_MICRON_INIT_DEV_OP,
+	CONFIG_SYS_DDRCMD_OCD_DEFAULT,
+	CONFIG_SYS_DDRCMD_PCHG_ALL,
+	CONFIG_SYS_DDRCMD_NOP
+};
+
+/*
+ * fixed sdram init:
+ * The board doesn't use memory modules that have serial presence
+ * detect or similar mechanism for discovery of the DRAM settings
+ */
+long int fixed_sdram(ddr512x_config_t *mddrc_config,
+			u32 *dram_init_seq, int seq_sz)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	u32 msize = CONFIG_SYS_DDR_SIZE * 1024 * 1024;
+	u32 msize_log2 = __ilog2(msize);
+	u32 i;
+
+	/* take default settings and init sequence if necessary */
+	if (mddrc_config == NULL)
+		mddrc_config = &default_mddrc_config;
+	if (dram_init_seq == NULL) {
+		dram_init_seq = default_init_seq;
+		seq_sz = sizeof(default_init_seq)/sizeof(u32);
+	}
+
+	/* Initialize IO Control */
+	out_be32(&im->io_ctrl.io_control_mem, IOCTRL_MUX_DDR);
+
+	/* Initialize DDR Local Window */
+	out_be32(&im->sysconf.ddrlaw.bar, CONFIG_SYS_DDR_BASE & 0xFFFFF000);
+	out_be32(&im->sysconf.ddrlaw.ar, msize_log2 - 1);
+	sync_law(&im->sysconf.ddrlaw.ar);
+
+	/* DDR Enable */
+	out_be32(&im->mddrc.ddr_sys_config, MDDRC_SYS_CFG_EN);
+
+	/* Initialize DDR Priority Manager */
+	out_be32(&im->mddrc.prioman_config1, CONFIG_SYS_MDDRCGRP_PM_CFG1);
+	out_be32(&im->mddrc.prioman_config2, CONFIG_SYS_MDDRCGRP_PM_CFG2);
+	out_be32(&im->mddrc.hiprio_config, CONFIG_SYS_MDDRCGRP_HIPRIO_CFG);
+	out_be32(&im->mddrc.lut_table0_main_upper, CONFIG_SYS_MDDRCGRP_LUT0_MU);
+	out_be32(&im->mddrc.lut_table0_main_lower, CONFIG_SYS_MDDRCGRP_LUT0_ML);
+	out_be32(&im->mddrc.lut_table1_main_upper, CONFIG_SYS_MDDRCGRP_LUT1_MU);
+	out_be32(&im->mddrc.lut_table1_main_lower, CONFIG_SYS_MDDRCGRP_LUT1_ML);
+	out_be32(&im->mddrc.lut_table2_main_upper, CONFIG_SYS_MDDRCGRP_LUT2_MU);
+	out_be32(&im->mddrc.lut_table2_main_lower, CONFIG_SYS_MDDRCGRP_LUT2_ML);
+	out_be32(&im->mddrc.lut_table3_main_upper, CONFIG_SYS_MDDRCGRP_LUT3_MU);
+	out_be32(&im->mddrc.lut_table3_main_lower, CONFIG_SYS_MDDRCGRP_LUT3_ML);
+	out_be32(&im->mddrc.lut_table4_main_upper, CONFIG_SYS_MDDRCGRP_LUT4_MU);
+	out_be32(&im->mddrc.lut_table4_main_lower, CONFIG_SYS_MDDRCGRP_LUT4_ML);
+	out_be32(&im->mddrc.lut_table0_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT0_AU);
+	out_be32(&im->mddrc.lut_table0_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT0_AL);
+	out_be32(&im->mddrc.lut_table1_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT1_AU);
+	out_be32(&im->mddrc.lut_table1_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT1_AL);
+	out_be32(&im->mddrc.lut_table2_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT2_AU);
+	out_be32(&im->mddrc.lut_table2_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT2_AL);
+	out_be32(&im->mddrc.lut_table3_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT3_AU);
+	out_be32(&im->mddrc.lut_table3_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT3_AL);
+	out_be32(&im->mddrc.lut_table4_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT4_AU);
+	out_be32(&im->mddrc.lut_table4_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT4_AL);
+
+	/*
+	 * Initialize MDDRC
+	 *  put MDDRC in CMD mode and
+	 *  set the max time between refreshes to 0 during init process
+	 */
+	out_be32(&im->mddrc.ddr_sys_config,
+		mddrc_config->ddr_sys_config | MDDRC_SYS_CFG_CMD_MASK);
+	out_be32(&im->mddrc.ddr_time_config0,
+		mddrc_config->ddr_time_config0 & MDDRC_REFRESH_ZERO_MASK);
+	out_be32(&im->mddrc.ddr_time_config1,
+		mddrc_config->ddr_time_config1);
+	out_be32(&im->mddrc.ddr_time_config2,
+		mddrc_config->ddr_time_config2);
+
+	/* Initialize DDR with either default or supplied init sequence */
+	for (i = 0; i < seq_sz; i++)
+		out_be32(&im->mddrc.ddr_command, dram_init_seq[i]);
+
+	/* Start MDDRC */
+	out_be32(&im->mddrc.ddr_time_config0, mddrc_config->ddr_time_config0);
+	out_be32(&im->mddrc.ddr_sys_config, mddrc_config->ddr_sys_config);
+
+	return msize;
+}
diff --git a/arch/ppc/cpu/mpc512x/i2c.c b/arch/ppc/cpu/mpc512x/i2c.c
new file mode 100644
index 0000000..e2d9097
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/i2c.c
@@ -0,0 +1,403 @@
+/*
+ * (C) Copyright 2003 - 2009
+ * 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
+ *
+ * Based on the MPC5xxx code.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_HARD_I2C
+
+#include <i2c.h>
+
+/* by default set I2C bus 0 active */
+static unsigned int bus_num __attribute__ ((section (".data"))) = 0;
+
+#define I2C_TIMEOUT	100
+#define I2C_RETRIES	3
+
+struct mpc512x_i2c_tap {
+	int scl2tap;
+	int tap2tap;
+};
+
+static int  mpc_reg_in(volatile u32 *reg);
+static void mpc_reg_out(volatile u32 *reg, int val, int mask);
+static int  wait_for_bb(void);
+static int  wait_for_pin(int *status);
+static int  do_address(uchar chip, char rdwr_flag);
+static int  send_bytes(uchar chip, char *buf, int len);
+static int  receive_bytes(uchar chip, char *buf, int len);
+static int  mpc_get_fdr(int);
+
+static int mpc_reg_in (volatile u32 *reg)
+{
+	int ret = in_be32(reg) >> 24;
+
+	return ret;
+}
+
+static void mpc_reg_out (volatile u32 *reg, int val, int mask)
+{
+	if (!mask) {
+		out_be32(reg, val << 24);
+	} else {
+		clrsetbits_be32(reg, mask << 24, (val & mask) << 24);
+	}
+}
+
+static int wait_for_bb (void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	int timeout = I2C_TIMEOUT;
+	int status;
+
+	status = mpc_reg_in (&regs->msr);
+
+	while (timeout-- && (status & I2C_BB)) {
+		volatile int temp;
+		mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+		temp = mpc_reg_in (&regs->mdr);
+		mpc_reg_out (&regs->mcr, 0, I2C_STA);
+		mpc_reg_out (&regs->mcr, 0, 0);
+		mpc_reg_out (&regs->mcr, I2C_EN, 0);
+
+		udelay (1000);
+		status = mpc_reg_in (&regs->msr);
+	}
+
+	return (status & I2C_BB);
+}
+
+static int wait_for_pin (int *status)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	int timeout = I2C_TIMEOUT;
+
+	*status = mpc_reg_in (&regs->msr);
+
+	while (timeout-- && !(*status & I2C_IF)) {
+		udelay (1000);
+		*status = mpc_reg_in (&regs->msr);
+	}
+
+	if (!(*status & I2C_IF)) {
+		return -1;
+	}
+
+	mpc_reg_out (&regs->msr, 0, I2C_IF);
+
+	return 0;
+}
+
+static int do_address (uchar chip, char rdwr_flag)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	int status;
+
+	chip <<= 1;
+
+	if (rdwr_flag) {
+		chip |= 1;
+	}
+
+	mpc_reg_out (&regs->mcr, I2C_TX, I2C_TX);
+	mpc_reg_out (&regs->mdr, chip, 0);
+
+	if (wait_for_pin (&status)) {
+		return -2;
+	}
+
+	if (status & I2C_RXAK) {
+		return -3;
+	}
+
+	return 0;
+}
+
+static int send_bytes (uchar chip, char *buf, int len)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	int wrcount;
+	int status;
+
+	for (wrcount = 0; wrcount < len; ++wrcount) {
+
+		mpc_reg_out (&regs->mdr, buf[wrcount], 0);
+
+		if (wait_for_pin (&status)) {
+			break;
+		}
+
+		if (status & I2C_RXAK) {
+			break;
+		}
+
+	}
+
+	return !(wrcount == len);
+}
+
+static int receive_bytes (uchar chip, char *buf, int len)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	int dummy   = 1;
+	int rdcount = 0;
+	int status;
+	int i;
+
+	mpc_reg_out (&regs->mcr, 0, I2C_TX);
+
+	for (i = 0; i < len; ++i) {
+		buf[rdcount] = mpc_reg_in (&regs->mdr);
+
+		if (dummy) {
+			dummy = 0;
+		} else {
+			rdcount++;
+		}
+
+		if (wait_for_pin (&status)) {
+			return -4;
+		}
+	}
+
+	mpc_reg_out (&regs->mcr, I2C_TXAK, I2C_TXAK);
+	buf[rdcount++] = mpc_reg_in (&regs->mdr);
+
+	if (wait_for_pin (&status)) {
+		return -5;
+	}
+
+	mpc_reg_out (&regs->mcr, 0, I2C_TXAK);
+
+	return 0;
+}
+
+/**************** I2C API ****************/
+
+void i2c_init (int speed, int saddr)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	int i;
+
+	for (i = 0; i < I2C_BUS_CNT; i++){
+		volatile i2c512x_dev_t *regs = &im->i2c.dev[i];
+
+		mpc_reg_out (&regs->mcr, 0, 0);
+
+		/* Set clock */
+		mpc_reg_out (&regs->mfdr, mpc_get_fdr (speed), 0);
+		mpc_reg_out (&regs->madr, saddr << 1, 0);
+
+		/* Enable module */
+		mpc_reg_out (&regs->mcr, I2C_EN, I2C_INIT_MASK);
+		mpc_reg_out (&regs->msr, 0, I2C_IF);
+	}
+
+	/* Disable interrupts */
+	out_be32(&im->i2c.icr, 0);
+
+	/* Turn off filters */
+	out_be32(&im->i2c.mifr, 0);
+}
+
+static int mpc_get_fdr (int speed)
+{
+	static int fdr = -1;
+
+	if (fdr == -1) {
+		ulong best_speed = 0;
+		ulong divider;
+		ulong ips, scl;
+		ulong bestmatch = 0xffffffffUL;
+		int best_i = 0, best_j = 0, i, j;
+		int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8};
+		struct mpc512x_i2c_tap scltap[] = {
+			{4, 1},
+			{4, 2},
+			{6, 4},
+			{6, 8},
+			{14, 16},
+			{30, 32},
+			{62, 64},
+			{126, 128}
+		};
+
+		ips = gd->ips_clk;
+		for (i = 7; i >= 0; i--) {
+			for (j = 7; j >= 0; j--) {
+				scl = 2 * (scltap[j].scl2tap +
+					   (SCL_Tap[i] - 1) * scltap[j].tap2tap
+					   + 2);
+				if (ips <= speed*scl) {
+					if ((speed*scl - ips) < bestmatch) {
+						bestmatch = speed*scl - ips;
+						best_i = i;
+						best_j = j;
+						best_speed = ips/scl;
+					}
+				}
+			}
+		}
+		divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+		if (gd->flags & GD_FLG_RELOC) {
+			fdr = divider;
+		} else {
+			debug("%ld kHz, \n", best_speed / 1000);
+			return divider;
+		}
+	}
+
+	return fdr;
+}
+
+int i2c_probe (uchar chip)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	int i;
+
+	for (i = 0; i < I2C_RETRIES; i++) {
+		mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+
+		if (! do_address (chip, 0)) {
+			mpc_reg_out (&regs->mcr, 0, I2C_STA);
+			udelay (500);
+			break;
+		}
+
+		mpc_reg_out (&regs->mcr, 0, I2C_STA);
+		udelay (500);
+	}
+
+	return (i == I2C_RETRIES);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	char xaddr[4];
+	int ret = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr	& 0xFF;
+
+	if (wait_for_bb ()) {
+		printf ("i2c_read: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+	if (do_address (chip, 0)) {
+		printf ("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, &xaddr[4-alen], alen)) {
+		printf ("i2c_read: send_bytes failed\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->mcr, I2C_RSTA, I2C_RSTA);
+	if (do_address (chip, 1)) {
+		printf ("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (receive_bytes (chip, (char *)buf, len)) {
+		printf ("i2c_read: receive_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+Done:
+	mpc_reg_out (&regs->mcr, 0, I2C_STA);
+	return ret;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+	char xaddr[4];
+	int ret = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr	& 0xFF;
+
+	if (wait_for_bb ()) {
+		printf ("i2c_write: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+	if (do_address (chip, 0)) {
+		printf ("i2c_write: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, &xaddr[4-alen], alen)) {
+		printf ("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, (char *)buf, len)) {
+		printf ("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+Done:
+	mpc_reg_out (&regs->mcr, 0, I2C_STA);
+	return ret;
+}
+
+int i2c_set_bus_num (unsigned int bus)
+{
+	if (bus >= I2C_BUS_CNT) {
+		return -1;
+	}
+	bus_num = bus;
+
+	return 0;
+}
+
+unsigned int i2c_get_bus_num (void)
+{
+	return bus_num;
+}
+
+#endif	/* CONFIG_HARD_I2C */
diff --git a/arch/ppc/cpu/mpc512x/ide.c b/arch/ppc/cpu/mpc512x/ide.c
new file mode 100644
index 0000000..dd6b2f4
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/ide.c
@@ -0,0 +1,128 @@
+/*
+ * (C) Copyright 2007-2009 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_IDE_RESET)
+
+void ide_set_reset (int idereset)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	debug ("ide_set_reset(%d)\n", idereset);
+
+	if (idereset) {
+		out_be32(&im->pata.pata_ata_control, 0);
+	} else {
+		out_be32(&im->pata.pata_ata_control, FSL_ATA_CTRL_ATA_RST_B);
+	}
+	udelay(100);
+}
+
+void init_ide_reset (void)
+{
+	debug ("init_ide_reset\n");
+
+	/*
+	 * Clear the reset bit to reset the interface
+	 * cf. RefMan MPC5121EE: 28.4.1 Resetting the ATA Bus
+	 */
+	ide_set_reset(1);
+
+	/* Assert the reset bit to enable the interface */
+	ide_set_reset(0);
+
+}
+
+#define CALC_TIMING(t) (t + period - 1) / period
+
+int ide_preinit (void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	long t;
+	const struct {
+		short t0;
+		short t1;
+		short t2_8;
+		short t2_16;
+		short t2i;
+		short t4;
+		short t9;
+		short tA;
+	} pio_specs = {
+		.t0    = 600,
+		.t1    =  70,
+		.t2_8  = 290,
+		.t2_16 = 165,
+		.t2i   =   0,
+		.t4    =  30,
+		.t9    =  20,
+		.tA    =  50,
+	};
+	union {
+		u32 config;
+		struct {
+			u8 field1;
+			u8 field2;
+			u8 field3;
+			u8 field4;
+		}bytes;
+	} cfg;
+
+	debug ("IDE preinit using PATA peripheral at IMMR-ADDR %08x\n",
+		(u32)&im->pata);
+
+	/* Set the reset bit to 1 to enable the interface */
+	ide_set_reset(0);
+
+	/* Init timings : we use PIO mode 0 timings */
+	t = 1000000000 / gd->ips_clk;	/* period in ns */
+	cfg.bytes.field1 = 3;
+	cfg.bytes.field2 = 3;
+	cfg.bytes.field3 = (pio_specs.t1 + t) / t;
+	cfg.bytes.field4 = (pio_specs.t2_8 + t) / t;
+
+	out_be32(&im->pata.pata_time1, cfg.config);
+
+	cfg.bytes.field1 = (pio_specs.t2_8 + t) / t;
+	cfg.bytes.field2 = (pio_specs.tA + t) / t + 2;
+	cfg.bytes.field3 = 1;
+	cfg.bytes.field4 = (pio_specs.t4 + t) / t;
+
+	out_be32(&im->pata.pata_time2, cfg.config);
+
+	cfg.config = in_be32(&im->pata.pata_time3);
+	cfg.bytes.field1 = (pio_specs.t9 + t) / t;
+
+	out_be32(&im->pata.pata_time3, cfg.config);
+
+	debug ("PATA preinit complete.\n");
+
+	return 0;
+}
+
+#endif /* defined(CONFIG_IDE_RESET) */
diff --git a/arch/ppc/cpu/mpc512x/iim.c b/arch/ppc/cpu/mpc512x/iim.c
new file mode 100644
index 0000000..8f2eb37
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/iim.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2008 Silicon Turnkey Express, Inc.
+ * Martha Marx <mmarx@silicontkx.com>
+ *
+ * ADS5121 IIM (Fusebox) Interface
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_CMD_FUSE
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char cur_bank = '1';
+
+char *iim_err_msg(u32 err)
+{
+	static char *IIM_errs[] = {
+		"Parity Error in cache",
+		"Explicit Sense Cycle Error",
+		"Write to Locked Register Error",
+		"Read Protect Error",
+		"Override Protect Error",
+		"Write Protect Error"};
+
+	int i;
+
+	if (!err)
+		return "";
+	for (i = 1; i < 8; i++)
+		if (err & (1 << i))
+			printf("IIM - %s\n", IIM_errs[i-1]);
+	return "";
+}
+
+int in_range(int n, int min, int max, char *err, char *usg)
+{
+	if (n > max || n < min) {
+		printf(err);
+		printf("Usage:\n%s\n", usg);
+		return 0;
+	}
+	return 1;
+}
+
+int ads5121_fuse_read(int bank, int fstart, int num)
+{
+	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
+	u32 *iim_fb, dummy;
+	int f, ctr;
+
+	out_be32(&iim->err, in_be32(&iim->err));
+	if (bank == 0)
+		iim_fb = (u32 *)&(iim->fbac0);
+	else
+		iim_fb = (u32 *)&(iim->fbac1);
+/* try a read to see if Read Protect is set */
+	dummy = in_be32(&iim_fb[0]);
+	if (in_be32(&iim->err) & IIM_ERR_RPE) {
+		printf("\tRead protect fuse is set\n");
+		out_be32(&iim->err, IIM_ERR_RPE);
+		return 0;
+	}
+	printf("Reading Bank %d cache\n", bank);
+	for (f = fstart, ctr = 0; num > 0; ctr++, num--, f++) {
+		if (ctr % 4 == 0)
+			printf("F%2d:", f);
+		printf("\t%#04x", (u8)(iim_fb[f]));
+		if (ctr % 4 == 3)
+			printf("\n");
+	}
+	if (ctr % 4 != 0)
+		printf("\n");
+}
+
+int ads5121_fuse_override(int bank, int f, u8 val)
+{
+	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
+	u32 *iim_fb;
+	u32 iim_stat;
+	int i;
+
+	out_be32(&iim->err, in_be32(&iim->err));
+	if (bank == 0)
+		iim_fb = (u32 *)&(iim->fbac0);
+	else
+		iim_fb = (u32 *)&(iim->fbac1);
+/* try a read to see if Read Protect is set */
+	iim_stat = in_be32(&iim_fb[0]);
+	if (in_be32(&iim->err) & IIM_ERR_RPE) {
+		printf("Read protect fuse is set on bank %d;"
+			"Override protect may also be set\n", bank);
+		printf("An attempt will be made to override\n");
+		out_be32(&iim->err, IIM_ERR_RPE);
+	}
+	if (iim_stat & IIM_FBAC_FBOP) {
+		printf("Override protect fuse is set on bank %d\n", bank);
+		return 1;
+	}
+	if (f > IIM_FMAX) /* reset the entire bank */
+		for (i = 0; i < IIM_FMAX + 1; i++)
+			out_be32(&iim_fb[i],  0);
+	else
+		out_be32(&iim_fb[f], val);
+	return 0;
+}
+
+int ads5121_fuse_prog(cmd_tbl_t *cmdtp, int bank, char *fuseno_bitno)
+{
+	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
+	int f, i, bitno;
+	u32 stat, err;
+
+	f = simple_strtol(fuseno_bitno, NULL, 10);
+	if (f == 0 && fuseno_bitno[0] != '0')
+		f = -1;
+	if (!in_range(f, 0, IIM_FMAX,
+		"<frow> must be between 0-31\n\n", cmdtp->usage))
+		return 1;
+	bitno = -1;
+	for (i = 0; i < 6; i++) {
+		if (fuseno_bitno[i] == '_') {
+			bitno = simple_strtol(&(fuseno_bitno[i+1]), NULL, 10);
+			if (bitno == 0 && fuseno_bitno[i+1] != '0')
+				bitno = -1;
+			break;
+		}
+	}
+	if (!in_range(bitno, 0, 7, "Bit number ranges from 0-7\n"
+		"Example of <frow_bitno>: \"18_4\" sets bit 4 of row 18\n",
+		cmdtp->usage))
+		return 1;
+	out_be32(&iim->err, in_be32(&iim->err));
+	out_be32(&iim->prg_p, IIM_PRG_P_SET);
+	out_be32(&iim->ua, IIM_SET_UA(bank, f));
+	out_be32(&iim->la, IIM_SET_LA(f, bitno));
+#ifdef DEBUG
+	printf("Programming disabled with DEBUG defined \n");
+	printf(""Set up to pro
+	printf("iim.ua = %x; iim.la = %x\n", iim->ua, iim->la);
+#else
+	out_be32(&iim->fctl, IIM_FCTL_PROG_PULSE | IIM_FCTL_PROG);
+	do
+		udelay(20);
+	while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY);
+	out_be32(&iim->prg_p, 0);
+	err = in_be32(&iim->err);
+	if (stat & IIM_STAT_PRGD) {
+		if (!(err & (IIM_ERR_WPE | IIM_ERR_WPE))) {
+			printf("Fuse is successfully set");
+			if (err)
+				printf(" - however there are other errors");
+			printf("\n");
+		}
+		iim->stat = 0;
+	}
+	if (err) {
+		iim_err_msg(err);
+		out_be32(&iim->err, in_be32(&iim->err));
+	}
+#endif
+}
+
+int ads5121_fuse_sense(int bank, int fstart, int num)
+{
+	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
+	u32 iim_fbac;
+	u32 stat, err, err_hold = 0;
+	int f, ctr;
+
+	out_be32(&iim->err, in_be32(&iim->err));
+	if (bank == 0)
+		iim_fbac = in_be32(&iim->fbac0);
+	else
+		iim_fbac = in_be32(&iim->fbac1);
+	if (iim_fbac & IIM_FBAC_FBESP) {
+		printf("\tSense Protect disallows this operation\n");
+		out_be32(&iim->err, IIM_FBAC_FBESP);
+		return 1;
+	}
+	err = in_be32(&iim->err);
+	if (err) {
+		iim_err_msg(err);
+		err_hold |= err;
+	}
+	if (err & IIM_ERR_RPE)
+		printf("\tRead protect fuse is set; "
+			"Sense Protect may be set but will be attempted\n");
+	if (err)
+		out_be32(&iim->err, err);
+	printf("Sensing fuse(s) on Bank %d\n", bank);
+	for (f = fstart, ctr = 0; num > 0; ctr++, f++, num--) {
+		out_be32(&iim->ua, IIM_SET_UA(bank, f));
+		out_be32(&iim->la, IIM_SET_LA(f, 0));
+		out_be32(&iim->fctl,  IIM_FCTL_ESNS_N);
+		do
+			udelay(20);
+		while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY);
+		err = in_be32(&iim->err);
+		if (err & IIM_ERR_SNSE) {
+			iim_err_msg(err);
+			out_be32(&iim->err, IIM_ERR_SNSE);
+			return 1;
+		}
+		if (stat & IIM_STAT_SNSD) {
+			out_be32(&iim->stat, 0);
+			if (ctr % 4 == 0)
+				printf("F%2d:", f);
+			printf("\t%#04x", (u8)iim->sdat);
+			if (ctr % 4 == 3)
+				printf("\n");
+		}
+		if (err) {
+			err_hold |= err;
+			out_be32(&iim->err, err);
+		}
+	}
+	if (ctr % 4 != 0)
+		printf("\n");
+	if (err_hold)
+		iim_err_msg(err_hold);
+
+	return 0;
+}
+
+int ads5121_fuse_stat(int bank)
+{
+	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
+	u32 iim_fbac;
+	u32 err;
+
+	out_be32(&iim->err, in_be32(&iim->err));
+	if (bank == 0)
+		iim_fbac = in_be32(&iim->fbac0);
+	else
+		iim_fbac = in_be32(&iim->fbac1);
+	err = in_be32(&iim->err);
+	if (err)
+		iim_err_msg(err);
+	if (err & IIM_ERR_RPE  || iim_fbac & IIM_FBAC_FBRP) {
+		if (iim_fbac == 0)
+			printf("Since protection settings can't be read - "
+				"try sensing fuse row 0;\n");
+		return 0;
+	}
+	if (iim_fbac & IIM_PROTECTION)
+		printf("Protection Fuses Bank %d = %#04x:\n", bank, iim_fbac);
+	else if (!(err & IIM_ERR_RPE))
+		printf("No Protection fuses are set\n");
+	if (iim_fbac & IIM_FBAC_FBWP)
+		printf("\tWrite Protect fuse is set\n");
+	if (iim_fbac & IIM_FBAC_FBOP)
+		printf("\tOverride Protect fuse is set\n");
+	if (iim_fbac & IIM_FBAC_FBESP)
+		printf("\tSense Protect Fuse is set\n");
+	out_be32(&iim->err, in_be32(&iim->err));
+
+	return 0;
+}
+
+int do_ads5121_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int frow, n, v, bank;
+
+	if (cur_bank == '0')
+		bank = 0;
+	else
+		bank = 1;
+
+	switch (argc) {
+	case 0:
+	case 1:
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	case 2:
+		if (strncmp(argv[1], "stat", 4) == 0)
+			return ads5121_fuse_stat(bank);
+		if (strncmp(argv[1], "read", 4) == 0)
+			return ads5121_fuse_read(bank, 0, IIM_FMAX + 1);
+		if (strncmp(argv[1], "sense", 5) == 0)
+			return ads5121_fuse_sense(bank, 0, IIM_FMAX + 1);
+		if (strncmp(argv[1], "ovride", 6) == 0)
+			return ads5121_fuse_override(bank, IIM_FMAX + 1, 0);
+		if (strncmp(argv[1], "bank", 4) == 0) {
+			printf("Active Fuse Bank is %c\n", cur_bank);
+			return 0;
+		}
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	case 3:
+		if (strncmp(argv[1], "bank", 4) == 0) {
+			if (argv[2][0] == '0')
+				cur_bank = '0';
+			else if (argv[2][0] == '1')
+				cur_bank = '1';
+			else {
+				printf("Usage:\n%s\n", cmdtp->usage);
+				return 1;
+			}
+
+			printf("Setting Active Fuse Bank to %c\n", cur_bank);
+			return 0;
+		}
+		if (strncmp(argv[1], "prog", 4) == 0)
+			return ads5121_fuse_prog(cmdtp, bank, argv[2]);
+
+		frow = (int)simple_strtol(argv[2], NULL, 10);
+		if (frow == 0 && argv[2][0] != '0')
+			frow = -1;
+		if (!in_range(frow, 0, IIM_FMAX,
+			"<frow> must be between 0-31\n\n", cmdtp->usage))
+			return 1;
+		if (strncmp(argv[1], "read", 4) == 0)
+			return ads5121_fuse_read(bank, frow, 1);
+		if (strncmp(argv[1], "ovride", 6) == 0)
+			return ads5121_fuse_override(bank, frow, 0);
+		if (strncmp(argv[1], "sense", 5) == 0)
+			return ads5121_fuse_sense(bank, frow, 1);
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	case 4:
+		frow = (int)simple_strtol(argv[2], NULL, 10);
+		if (frow == 0 && argv[2][0] != '0')
+			frow = -1;
+		if (!in_range(frow, 0, IIM_FMAX,
+			"<frow> must be between 0-31\n\n", cmdtp->usage))
+			return 1;
+		if (strncmp(argv[1], "read", 4) == 0) {
+			n = (int)simple_strtol(argv[3], NULL, 10);
+			if (!in_range(frow + n, frow + 1, IIM_FMAX + 1,
+				"<frow>+<n> must be between 1-32\n\n",
+				cmdtp->usage))
+				return 1;
+			return ads5121_fuse_read(bank, frow, n);
+		}
+		if (strncmp(argv[1], "ovride", 6) == 0) {
+			v = (int)simple_strtol(argv[3], NULL, 10);
+			return ads5121_fuse_override(bank, frow, v);
+		}
+		if (strncmp(argv[1], "sense", 5) == 0) {
+			n = (int)simple_strtol(argv[3], NULL, 10);
+			if (!in_range(frow + n, frow + 1, IIM_FMAX + 1,
+				"<frow>+<n> must be between 1-32\n\n",
+				cmdtp->usage))
+				return 1;
+			return ads5121_fuse_sense(bank, frow, n);
+		}
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	default: /* at least 5 args */
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+}
+
+U_BOOT_CMD(
+	fuse, CONFIG_SYS_MAXARGS, 0, do_ads5121_fuse,
+	"   - Read, Sense, Override or Program Fuses\n",
+	"bank <n>		- sets active Fuse Bank to 0 or 1\n"
+	"			    no args shows current active bank\n"
+	"fuse stat		- print active fuse bank's protection status\n"
+	"fuse read [<frow> [<n>]] - print <n> fuse rows starting at <frow>\n"
+	"			    no args to print entire bank's fuses\n"
+	"fuse ovride [<frow> [<v>]]- override fuses at <frow> with <v>\n"
+	"			    no <v> defaults to 0 for the row\n"
+	"			    no args resets entire bank to 0\n"
+	"			  NOTE - settings persist until hard reset\n"
+	"fuse sense [<frow>]	- senses current fuse at <frow>\n"
+	"			    no args for entire bank\n"
+	"fuse prog <frow_bit> 	- program fuse at row <frow>, bit <_bit>\n"
+	"			    <frow> is 0-31, <bit> is 0-7; eg. 13_2 \n"
+	"			  WARNING - this is permanent"
+);
+#endif /* CONFIG_CMD_FUSE */
diff --git a/arch/ppc/cpu/mpc512x/interrupts.c b/arch/ppc/cpu/mpc512x/interrupts.c
new file mode 100644
index 0000000..ef7c773
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/interrupts.c
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2000-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Derived from the MPC83xx code.
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	ulong count;
+};
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+	return 0;
+}
+
+/*
+ * Install and free an interrupt handler.
+ */
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+}
+
+void irq_free_handler (int irq)
+{
+}
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
diff --git a/arch/ppc/cpu/mpc512x/iopin.c b/arch/ppc/cpu/mpc512x/iopin.c
new file mode 100644
index 0000000..be20947
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/iopin.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2008
+ * Martha J Marx, Silicon Turnkey Express, mmarx@silicontkx.com
+ * mpc512x I/O pin/pad initialization for the ADS5121 board
+ * 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 <linux/types.h>
+#include <asm/io.h>
+
+void iopin_initialize(iopin_t *ioregs_init, int len)
+{
+	short i, j, p;
+	u32 *reg;
+	immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+
+	reg = (u32 *)&(im->io_ctrl);
+
+	if (sizeof(ioregs_init) == 0)
+		return;
+
+	for (i = 0; i < len; i++) {
+		for (p = 0, j = ioregs_init[i].p_offset / sizeof(u_long);
+			p < ioregs_init[i].nr_pins; p++, j++) {
+			if (ioregs_init[i].bit_or)
+				setbits_be32(reg + j, ioregs_init[i].val);
+			else
+				out_be32 (reg + j, ioregs_init[i].val);
+		}
+	}
+	return;
+}
diff --git a/arch/ppc/cpu/mpc512x/pci.c b/arch/ppc/cpu/mpc512x/pci.c
new file mode 100644
index 0000000..141db8b
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/pci.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2009-2010 DENX Software Engineering <wd@denx.de>
+ * Copyright (C) Freescale Semiconductor, Inc. 2006, 2007.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/global_data.h>
+#include <pci.h>
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* System RAM mapped to PCI space */
+#define CONFIG_PCI_SYS_MEM_BUS	CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_MEM_PHYS	CONFIG_SYS_SDRAM_BASE
+
+static struct pci_controller pci_hose;
+
+
+/**************************************************************************
+ * pci_init_board()
+ *
+ */
+void
+pci_init_board(void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile law512x_t *pci_law;
+	volatile pot512x_t *pci_pot;
+	volatile pcictrl512x_t *pci_ctrl;
+	volatile pciconf512x_t *pci_conf;
+	u16 reg16;
+	u32 reg32;
+	u32 dev;
+	int i;
+	struct pci_controller *hose;
+
+	/* Set PCI divider for 33MHz */
+	reg32 = in_be32(&im->clk.scfr[0]);
+	reg32 &= ~(SCFR1_PCI_DIV_MASK);
+	reg32 |= SCFR1_PCI_DIV << SCFR1_PCI_DIV_SHIFT;
+	out_be32(&im->clk.scfr[0], reg32);
+
+	clrsetbits_be32(&im->clk.scfr[0],
+			SCFR1_PCI_DIV_MASK,
+			SCFR1_PCI_DIV << SCFR1_PCI_DIV_SHIFT
+	);
+
+	pci_law = im->sysconf.pcilaw;
+	pci_pot = im->ios.pot;
+	pci_ctrl = &im->pci_ctrl;
+	pci_conf = &im->pci_conf;
+
+	hose = &pci_hose;
+
+	/*
+	 * Release PCI RST Output signal
+	 */
+	out_be32(&pci_ctrl->gcr, 0);
+	udelay(2000);
+	out_be32(&pci_ctrl->gcr, 1);
+
+	/* We need to wait at least a 1sec based on PCI specs */
+	for (i = 0; i < 1000; i++)
+		udelay(1000);
+
+	/*
+	 * Configure PCI Local Access Windows
+	 */
+	out_be32(&pci_law[0].bar, CONFIG_SYS_PCI_MEM_PHYS & LAWBAR_BAR);
+	out_be32(&pci_law[0].ar, LAWAR_EN | LAWAR_SIZE_512M);
+
+	out_be32(&pci_law[1].bar, CONFIG_SYS_PCI_IO_PHYS & LAWBAR_BAR);
+	out_be32(&pci_law[1].ar, LAWAR_EN | LAWAR_SIZE_16M);
+
+	/*
+	 * Configure PCI Outbound Translation Windows
+	 */
+
+	/* PCI mem space - prefetch */
+	out_be32(&pci_pot[0].potar,
+		(CONFIG_SYS_PCI_MEM_BASE >> 12) & POTAR_TA_MASK);
+	out_be32(&pci_pot[0].pobar,
+		(CONFIG_SYS_PCI_MEM_PHYS >> 12) & POBAR_BA_MASK);
+	out_be32(&pci_pot[0].pocmr,
+		POCMR_EN | POCMR_PRE | POCMR_CM_256M);
+
+	/* PCI IO space */
+	out_be32(&pci_pot[1].potar,
+		(CONFIG_SYS_PCI_IO_BASE >> 12) & POTAR_TA_MASK);
+	out_be32(&pci_pot[1].pobar,
+		(CONFIG_SYS_PCI_IO_PHYS >> 12) & POBAR_BA_MASK);
+	out_be32(&pci_pot[1].pocmr,
+		POCMR_EN | POCMR_IO | POCMR_CM_16M);
+
+	/* PCI mmio - non-prefetch mem space */
+	out_be32(&pci_pot[2].potar,
+		(CONFIG_SYS_PCI_MMIO_BASE >> 12) & POTAR_TA_MASK);
+	out_be32(&pci_pot[2].pobar,
+		(CONFIG_SYS_PCI_MMIO_PHYS >> 12) & POBAR_BA_MASK);
+	out_be32(&pci_pot[2].pocmr,
+		POCMR_EN | POCMR_CM_256M);
+
+	/*
+	 * Configure PCI Inbound Translation Windows
+	 */
+
+	/* we need RAM mapped to PCI space for the devices to
+	 * access main memory */
+	out_be32(&pci_ctrl[0].pitar1, 0x0);
+	out_be32(&pci_ctrl[0].pibar1, 0x0);
+	out_be32(&pci_ctrl[0].piebar1, 0x0);
+	out_be32(&pci_ctrl[0].piwar1,
+		PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP |
+		PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size) - 1));
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	/* PCI memory prefetch space */
+	pci_set_region(hose->regions + 0,
+		       CONFIG_SYS_PCI_MEM_BASE,
+		       CONFIG_SYS_PCI_MEM_PHYS,
+		       CONFIG_SYS_PCI_MEM_SIZE,
+		       PCI_REGION_MEM|PCI_REGION_PREFETCH);
+
+	/* PCI memory space */
+	pci_set_region(hose->regions + 1,
+		       CONFIG_SYS_PCI_MMIO_BASE,
+		       CONFIG_SYS_PCI_MMIO_PHYS,
+		       CONFIG_SYS_PCI_MMIO_SIZE,
+		       PCI_REGION_MEM);
+
+	/* PCI IO space */
+	pci_set_region(hose->regions + 2,
+		       CONFIG_SYS_PCI_IO_BASE,
+		       CONFIG_SYS_PCI_IO_PHYS,
+		       CONFIG_SYS_PCI_IO_SIZE,
+		       PCI_REGION_IO);
+
+	/* System memory space */
+	pci_set_region(hose->regions + 3,
+		       CONFIG_PCI_SYS_MEM_BUS,
+		       CONFIG_PCI_SYS_MEM_PHYS,
+		       gd->ram_size,
+		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+	hose->region_count = 4;
+
+	pci_setup_indirect(hose,
+			   (CONFIG_SYS_IMMR + 0x8300),
+			   (CONFIG_SYS_IMMR + 0x8304));
+
+	pci_register_hose(hose);
+
+	/*
+	 * Write to Command register
+	 */
+	reg16 = 0xff;
+	dev = PCI_BDF(hose->first_busno, 0, 0);
+	pci_hose_read_config_word(hose, dev, PCI_COMMAND, &reg16);
+	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+	/*
+	 * Clear non-reserved bits in status register.
+	 */
+	pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+	pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+	pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+	printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
+	/*
+	 * Hose scan.
+	 */
+	hose->last_busno = pci_hose_scan(hose);
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+	int nodeoffset;
+	int tmp[2];
+	const char *path;
+
+	nodeoffset = fdt_path_offset(blob, "/aliases");
+	if (nodeoffset >= 0) {
+		path = fdt_getprop(blob, nodeoffset, "pci", NULL);
+		if (path) {
+			tmp[0] = cpu_to_be32(pci_hose.first_busno);
+			tmp[1] = cpu_to_be32(pci_hose.last_busno);
+			do_fixup_by_path(blob, path, "bus-range",
+				&tmp, sizeof(tmp), 1);
+
+			tmp[0] = cpu_to_be32(gd->pci_clk);
+			do_fixup_by_path(blob, path, "clock-frequency",
+				&tmp, sizeof(tmp[0]), 1);
+		}
+	}
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/arch/ppc/cpu/mpc512x/serial.c b/arch/ppc/cpu/mpc512x/serial.c
new file mode 100644
index 0000000..ec2f41b
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/serial.c
@@ -0,0 +1,193 @@
+/*
+ * (C) Copyright 2000 - 2010
+ * 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
+ *
+ * Based ont the MPC5200 PSC driver.
+ * Adapted for MPC512x by Jan Wrobel <wrr@semihalf.com>
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_PSC_CONSOLE)
+
+static void fifo_init (volatile psc512x_t *psc)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+
+	/* reset Rx & Tx fifo slice */
+	out_be32(&psc->rfcmd, PSC_FIFO_RESET_SLICE);
+	out_be32(&psc->tfcmd, PSC_FIFO_RESET_SLICE);
+
+	/* disable Tx & Rx FIFO interrupts */
+	out_be32(&psc->rfintmask, 0);
+	out_be32(&psc->tfintmask, 0);
+
+	out_be32(&psc->tfsize, CONSOLE_FIFO_TX_SIZE | (CONSOLE_FIFO_TX_ADDR << 16));
+	out_be32(&psc->rfsize, CONSOLE_FIFO_RX_SIZE | (CONSOLE_FIFO_RX_ADDR << 16));
+
+	/* enable Tx & Rx FIFO slice */
+	out_be32(&psc->rfcmd, PSC_FIFO_ENABLE_SLICE);
+	out_be32(&psc->tfcmd, PSC_FIFO_ENABLE_SLICE);
+
+	out_be32(&im->fifoc.fifoc_cmd, FIFOC_DISABLE_CLOCK_GATE);
+	__asm__ volatile ("sync");
+}
+
+void serial_setbrg(void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+	unsigned long baseclk, div;
+
+	/* calculate dividor for setting PSC CTUR and CTLR registers */
+	baseclk = (gd->ips_clk + 8) / 16;
+	div = (baseclk + (gd->baudrate / 2)) / gd->baudrate;
+
+	out_8(&psc->ctur, (div >> 8) & 0xff);
+	out_8(&psc->ctlr,  div & 0xff); /* set baudrate */
+}
+
+int serial_init(void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	fifo_init (psc);
+
+	/* set MR register to point to MR1 */
+	out_8(&psc->command, PSC_SEL_MODE_REG_1);
+
+	/* disable Tx/Rx */
+	out_8(&psc->command, PSC_TX_DISABLE | PSC_RX_DISABLE);
+
+	/* choose the prescaler	by 16 for the Tx/Rx clock generation */
+	out_be16(&psc->psc_clock_select, 0xdd00);
+
+	/* switch to UART mode */
+	out_be32(&psc->sicr, 0);
+
+	/* mode register points to mr1 */
+	/* configure parity, bit length and so on in mode register 1*/
+	out_8(&psc->mode, PSC_MODE_8_BITS | PSC_MODE_PARNONE);
+	/* now, mode register points to mr2 */
+	out_8(&psc->mode, PSC_MODE_1_STOPBIT);
+
+	/* set baudrate */
+	serial_setbrg();
+
+	/* disable all interrupts */
+	out_be16(&psc->psc_imr, 0);
+
+	/* reset and enable Rx/Tx */
+	out_8(&psc->command, PSC_RST_RX);
+	out_8(&psc->command, PSC_RST_TX);
+	out_8(&psc->command, PSC_RX_ENABLE | PSC_TX_ENABLE);
+
+	return 0;
+}
+
+void serial_putc (const char c)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	/* Wait for last character to go. */
+	while (!(in_be16(&psc->psc_status) & PSC_SR_TXEMP))
+		;
+
+	out_8(&psc->tfdata_8, c);
+}
+
+void serial_putc_raw (const char c)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	/* Wait for last character to go. */
+	while (!(in_be16(&psc->psc_status) & PSC_SR_TXEMP))
+		;
+
+	out_8(&psc->tfdata_8, c);
+}
+
+
+void serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int serial_getc (void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	/* Wait for a character to arrive. */
+	while (in_be32(&psc->rfstat) & PSC_FIFO_EMPTY)
+		;
+
+	return in_8(&psc->rfdata_8);
+}
+
+int serial_tstc (void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	return !(in_be32(&psc->rfstat) & PSC_FIFO_EMPTY);
+}
+
+void serial_setrts(int s)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	if (s) {
+		/* Assert RTS (become LOW) */
+		out_8(&psc->op1, 0x1);
+	}
+	else {
+		/* Negate RTS (become HIGH) */
+		out_8(&psc->op0, 0x1);
+	}
+}
+
+int serial_getcts(void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE];
+
+	return (in_8(&psc->ip) & 0x1) ? 0 : 1;
+}
+#endif /* CONFIG_PSC_CONSOLE */
diff --git a/arch/ppc/cpu/mpc512x/speed.c b/arch/ppc/cpu/mpc512x/speed.c
new file mode 100644
index 0000000..ce8d094
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/speed.c
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on the MPC83xx code.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int spmf_mult[] = {
+	68, 1, 12, 16,
+	20, 24, 28, 32,
+	36, 40, 44, 48,
+	52, 56, 60, 64
+};
+
+static int cpmf_mult[][2] = {
+	{0, 1}, {0, 1}, /* 0 and 1 are not valid */
+	{1, 1}, {3, 2},
+	{2, 1}, {5, 2},
+	{3, 1}, {7, 2},
+	{0, 1}, {0, 1}, /* and all above 7 are not valid too */
+	{0, 1}, {0, 1},
+	{0, 1}, {0, 1},
+	{0, 1}, {0, 1}
+};
+
+static int sys_dividors[][2] = {
+	{2, 1}, {5, 2}, {3, 1}, {7, 2}, {4, 1},
+	{9, 2}, {5, 1}, {7, 1}, {6, 1}, {8, 1},
+	{9, 1}, {11, 1}, {10, 1}, {12, 1}, {13, 1},
+	{15, 1}, {14, 1}, {16, 1}, {17, 1}, {19, 1},
+	{18, 1}, {20, 1}, {21, 1}, {23, 1}, {22, 1},
+	{24, 1}, {25, 1}, {27, 1}, {26, 1}, {28, 1},
+	{29, 1}, {31, 1}, {30, 1}, {32, 1}, {33, 1}
+};
+
+int get_clocks (void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	u8 spmf;
+	u8 cpmf;
+	u8 sys_div;
+	u8 ips_div;
+	u8 pci_div;
+	u32 ref_clk = CONFIG_SYS_MPC512X_CLKIN;
+	u32 spll;
+	u32 sys_clk;
+	u32 core_clk;
+	u32 csb_clk;
+	u32 ips_clk;
+	u32 pci_clk;
+	u32 reg;
+
+	reg = in_be32(&im->sysconf.immrbar);
+	if ((reg & IMMRBAR_BASE_ADDR) != (u32) im)
+		return -1;
+
+	reg = in_be32(&im->clk.spmr);
+	spmf = (reg & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
+	spll = ref_clk * spmf_mult[spmf];
+
+	reg = in_be32(&im->clk.scfr[1]);
+	sys_div = (reg & SCFR2_SYS_DIV) >> SCFR2_SYS_DIV_SHIFT;
+	sys_clk = (spll * sys_dividors[sys_div][1]) / sys_dividors[sys_div][0];
+
+	csb_clk = sys_clk / 2;
+
+	reg = in_be32(&im->clk.spmr);
+	cpmf = (reg & SPMR_CPMF) >> SPMR_CPMF_SHIFT;
+	core_clk = (csb_clk * cpmf_mult[cpmf][0]) / cpmf_mult[cpmf][1];
+
+	reg = in_be32(&im->clk.scfr[0]);
+	ips_div = (reg & SCFR1_IPS_DIV_MASK) >> SCFR1_IPS_DIV_SHIFT;
+	if (ips_div != 0) {
+		ips_clk = csb_clk / ips_div;
+	} else {
+		/* in case we cannot get a sane IPS divisor, fail gracefully */
+		ips_clk = 0;
+	}
+
+	reg = in_be32(&im->clk.scfr[0]);
+	pci_div = (reg & SCFR1_PCI_DIV_MASK) >> SCFR1_PCI_DIV_SHIFT;
+	if (pci_div != 0) {
+		pci_clk = csb_clk / pci_div;
+	} else {
+		/* in case we cannot get a sane IPS divisor, fail gracefully */
+		pci_clk = 333333;
+	}
+
+	gd->ips_clk = ips_clk;
+	gd->pci_clk = pci_clk;
+	gd->csb_clk = csb_clk;
+	gd->cpu_clk = core_clk;
+	gd->bus_clk = csb_clk;
+	return 0;
+
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+	return gd->csb_clk;
+}
+
+int do_clocks (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	char buf[32];
+
+	printf("Clock configuration:\n");
+	printf("  CPU:                 %-4s MHz\n", strmhz(buf, gd->cpu_clk));
+	printf("  Coherent System Bus: %-4s MHz\n", strmhz(buf, gd->csb_clk));
+	printf("  IPS Bus:             %-4s MHz\n", strmhz(buf, gd->ips_clk));
+	printf("  PCI:                 %-4s MHz\n", strmhz(buf, gd->pci_clk));
+	printf("  DDR:                 %-4s MHz\n", strmhz(buf, 2*gd->csb_clk));
+	return 0;
+}
+
+U_BOOT_CMD(clocks, 1, 0, do_clocks,
+	"print clock configuration",
+	"    clocks"
+);
+
+int prt_mpc512x_clks (void)
+{
+	do_clocks (NULL, 0, 0, NULL);
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc512x/start.S b/arch/ppc/cpu/mpc512x/start.S
new file mode 100644
index 0000000..d26b617
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/start.S
@@ -0,0 +1,711 @@
+/*
+ * Copyright (C) 1998  Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999  Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000-2009 Wolfgang Denk <wd@denx.de>
+ * Copyright Freescale Semiconductor, Inc. 2004, 2006.
+ *
+ * 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
+ *
+ * Based on the MPC83xx code.
+ */
+
+/*
+ *  U-Boot - Startup Code for MPC512x based Embedded Boards
+ */
+
+#include <config.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_521X	1		/* needed for Linux kernel header files*/
+
+#include <asm/immap_512x.h>
+#include "asm-offsets.h"
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING "MPC512X"
+#endif
+
+/*
+ * Floating Point enable, Machine Check and Recoverable Interr.
+ */
+#undef	MSR_KERNEL
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/* Macros for manipulating CSx_START/STOP */
+#define START_REG(start)	((start) >> 16)
+#define STOP_REG(start, size)	(((start) + (size) - 1) >> 16)
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * Magic number and version string
+ */
+	.long	0x27051956		/* U-Boot Magic Number */
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii " ", CONFIG_IDENT_STRING, "\0"
+
+/*
+ * Vector Table
+ */
+	.text
+	. = EXC_OFF_SYS_RESET
+
+	.globl	_start
+	/* Start from here after reset/power on */
+_start:
+	li	r21, BOOTFLAG_COLD  /* Normal Power-On: Boot from FLASH */
+	b	boot_cold
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, UnknownException)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+/* Floating Point Unit unavailable exception */
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+/* Decrementer */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+/* Critical interrupt */
+	STD_EXCEPTION(0xa00, Critical, UnknownException)
+
+/* System Call */
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+
+/* Trace interrupt */
+	STD_EXCEPTION(0xd00, Trace, UnknownException)
+
+/* Performance Monitor interrupt */
+	STD_EXCEPTION(0xf00, PerfMon, UnknownException)
+
+/* Intruction Translation Miss */
+	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+
+/* Data Load Translation Miss */
+	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+
+/* Data Store Translation Miss */
+	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+
+/* Instruction Address Breakpoint */
+	STD_EXCEPTION(0x1300, InstructionAddrBreakpoint, DebugException)
+
+/* System Management interrupt */
+	STD_EXCEPTION(0x1400, SystemMgmtInterrupt, UnknownException)
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x3000
+boot_cold:
+	/* Save msr contents */
+	mfmsr	r5
+
+	/* Set IMMR area to our preferred location */
+	lis	r4, CONFIG_DEFAULT_IMMR@h
+	lis	r3, CONFIG_SYS_IMMR@h
+	ori	r3, r3, CONFIG_SYS_IMMR@l
+	stw	r3, IMMRBAR(r4)
+	mtspr	MBAR, r3		/* IMMRBAR is mirrored into the MBAR SPR (311) */
+
+	/* Initialise the machine */
+	bl	cpu_early_init
+
+	/*
+	 * Set up Local Access Windows:
+	 *
+	 * 1) Boot/CS0 (boot FLASH)
+	 * 2) On-chip SRAM (initial stack purposes)
+	 */
+
+	/* Boot CS/CS0 window range */
+	lis     r3, CONFIG_SYS_IMMR@h
+	ori     r3, r3, CONFIG_SYS_IMMR@l
+
+	lis	r4, START_REG(CONFIG_SYS_FLASH_BASE)
+	ori	r4, r4, STOP_REG(CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_SIZE)
+	stw	r4, LPCS0AW(r3)
+
+	/*
+	 * The SRAM window has a fixed size (256K), so only the start address
+	 * is necessary
+	 */
+	lis	r4, START_REG(CONFIG_SYS_SRAM_BASE) & 0xff00
+	stw	r4, SRAMBAR(r3)
+
+	/*
+	 * According to MPC5121e RM, configuring local access windows should
+	 * be followed by a dummy read of the config register that was
+	 * modified last and an isync
+	 */
+	lwz	r4, SRAMBAR(r3)
+	isync
+
+	/*
+	 * Set configuration of the Boot/CS0, the SRAM window does not have a
+	 * config register so no params can be set for it
+	 */
+	lis     r3, (CONFIG_SYS_IMMR + LPC_OFFSET)@h
+	ori     r3, r3, (CONFIG_SYS_IMMR + LPC_OFFSET)@l
+
+	lis     r4, CONFIG_SYS_CS0_CFG@h
+	ori     r4, r4, CONFIG_SYS_CS0_CFG@l
+	stw     r4, CS0_CONFIG(r3)
+
+	/* Master enable all CS's */
+	lis	r4, CS_CTRL_ME@h
+	ori	r4, r4, CS_CTRL_ME@l
+	stw	r4, CS_CTRL(r3)
+
+	lis	r4, (CONFIG_SYS_MONITOR_BASE)@h
+	ori	r4, r4, (CONFIG_SYS_MONITOR_BASE)@l
+	addi	r5, r4, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r5
+	blr
+
+in_flash:
+	lis	r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+	li	r0, 0		/* Make room for stack frame header and	*/
+	stwu	r0, -4(r1)	/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/
+
+	/* let the C-code set up the rest			*/
+	/*							*/
+	/* Be careful to keep code relocatable & stack humble	*/
+	/*------------------------------------------------------*/
+
+	GET_GOT			/* initialize GOT access	*/
+
+	/* r3: IMMR */
+	lis	r3, CONFIG_SYS_IMMR@h
+	/* run low-level CPU init code (in Flash) */
+	bl	cpu_init_f
+
+	/* r3: BOOTFLAG */
+	mr	r3, r21
+	/* run 1st part of board init code (in Flash) */
+	bl	board_init_f
+
+	/* NOTREACHED - board_init_f() does not return */
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+/*
+ * This code initialises the machine, it expects original MSR contents to be in r5.
+ */
+cpu_early_init:
+	/* Initialize machine status; enable machine check interrupt */
+	/*-----------------------------------------------------------*/
+
+	li	r3, MSR_KERNEL			/* Set ME and RI flags */
+	rlwimi	r3, r5, 0, 25, 25		/* preserve IP bit */
+#ifdef DEBUG
+	rlwimi	r3, r5, 0, 21, 22		/* debugger might set SE, BE bits */
+#endif
+	mtmsr	r3
+	SYNC
+	mtspr	SRR1, r3			/* Mirror current MSR state in SRR1 */
+
+	lis	r3, CONFIG_SYS_IMMR@h
+
+#if defined(CONFIG_WATCHDOG)
+	/* Initialise the watchdog and reset it */
+	/*--------------------------------------*/
+	lis r4, CONFIG_SYS_WATCHDOG_VALUE
+	ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)
+	stw r4, SWCRR(r3)
+
+	/* reset */
+	li	r4, 0x556C
+	sth	r4, SWSRR@l(r3)
+	li	r4, 0x0
+	ori	r4, r4, 0xAA39
+	sth	r4, SWSRR@l(r3)
+#else
+	/* Disable the watchdog */
+	/*----------------------*/
+	lwz r4, SWCRR(r3)
+	/*
+	 * Check to see if it's enabled for disabling: once disabled by s/w
+	 * it's not possible to re-enable it
+	 */
+	andi. r4, r4, 0x4
+	beq 1f
+	xor r4, r4, r4
+	stw r4, SWCRR(r3)
+1:
+#endif /* CONFIG_WATCHDOG */
+
+	/* Initialize the Hardware Implementation-dependent Registers */
+	/* HID0 also contains cache control			*/
+	/*------------------------------------------------------*/
+	lis	r3, CONFIG_SYS_HID0_INIT@h
+	ori	r3, r3, CONFIG_SYS_HID0_INIT@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID0_FINAL@h
+	ori	r3, r3, CONFIG_SYS_HID0_FINAL@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID2@h
+	ori	r3, r3, CONFIG_SYS_HID2@l
+	SYNC
+	mtspr	HID2, r3
+	sync
+	blr
+
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+	.globl	icache_enable
+icache_enable:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_ICE
+	lis	r4, 0
+	ori	r4, r4, HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4    /* sets enable and invalidate, clears lock */
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_ICE|HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4     /* sets invalidate, clears enable and lock*/
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	ori	r3, r3, HID0_DCE
+	ori	r5, r3, HID0_DCFI
+	mtspr	HID0, r5		/* enable + invalidate */
+	mtspr	HID0, r3		/* enable */
+	sync
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_DCE|HID0_DLOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_DCI
+	sync
+	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */
+	sync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+/*-------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3		/* Set new stack pointer	*/
+	mr	r9,  r4		/* Save copy of Global Data pointer */
+	mr	r10, r5		/* Save copy of Destination Address */
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address */
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address */
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size */
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE)
+	 *		+ Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary */
+	beq	7f		/* Protect against 0 count	  */
+	mtctr	r0
+	bge	cr1,2f
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+
+	/* copy */
+1:	lwzu	r0,4(r8)
+	stwu	r0,4(r7)
+	bdnz	1b
+
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	mtctr	r0
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+
+	/* and compare */
+20:	lwzu	r20,4(r8)
+	lwzu	r21,4(r7)
+	xor. r22, r20, r21
+	bne  30f
+	bdnz	20b
+	b 4f
+
+	/* compare failed */
+30:	li r3, 0
+	blr
+
+2:	slwi	r0,r0,2 /* re copy in reverse order ... y do we needed it? */
+	add	r8,r4,r0
+	add	r7,r3,r0
+3:	lwzu	r0,-4(r8)
+	stwu	r0,-4(r7)
+	bdnz	3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4:	cmpwi	r6,0
+	add	r5,r3,r5
+	beq	7f		/* Always flush prefetch queue in any case */
+	subi	r0,r6,1
+	andc	r3,r3,r0
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4		/* save link register */
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100	/* reset vector at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr			/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_Trace - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	4b
+
+	mfmsr	r3			/* now that the vectors have */
+	lis	r7, MSR_IP@h		/* relocated into low memory */
+	ori	r7, r7, MSR_IP@l	/* MSR[IP] can be turned off */
+	andc	r3, r3, r7		/* (if it was on) */
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+
+	mtlr	r4			/* restore link register    */
+	blr
diff --git a/arch/ppc/cpu/mpc512x/traps.c b/arch/ppc/cpu/mpc512x/traps.c
new file mode 100644
index 0000000..786f4a5
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/traps.c
@@ -0,0 +1,212 @@
+/*
+ * (C) Copyright 2000 - 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Derived from the MPC83xx code.
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware
+ * exceptions
+ */
+
+#include <common.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * End of addressable memory.  This may be less than the actual
+ * amount of memory on the system if we're unable to keep all
+ * the memory mapped in.
+ */
+extern ulong get_effective_memsize(void);
+#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize())
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace (unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	puts ("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			putc ('\n');
+		printf ("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *) *sp;
+	}
+	putc ('\n');
+}
+
+void show_regs (struct pt_regs * regs)
+{
+	int i;
+
+	printf ("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf ("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr & MSR_EE ? 1 : 0, regs->msr & MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr & MSR_ME ? 1 : 0,
+	       regs->msr & MSR_IR ? 1 : 0,
+	       regs->msr & MSR_DR ? 1 : 0);
+
+	putc ('\n');
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0) {
+			printf ("GPR%02d: ", i);
+		}
+
+		printf ("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			putc ('\n');
+		}
+	}
+}
+
+
+void
+_exception (int signr, struct pt_regs *regs)
+{
+	show_regs (regs);
+	print_backtrace ((unsigned long *)regs->gpr[1]);
+	panic ("Exception at pc %lx signal %d", regs->nip,signr);
+}
+
+
+void
+MachineCheckException (struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	if ((fixup = search_exception_table (regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#ifdef CONFIG_CMD_KGDB
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	puts ("Machine check.\nCaused by (from msr): ");
+	printf ("regs %p ",regs);
+	switch (regs->msr & 0x00FF0000) {
+	case (0x80000000 >> 10):
+		puts ("Instruction cache parity signal\n");
+		break;
+	case (0x80000000 >> 11):
+		puts ("Data cache parity signal\n");
+		break;
+	case (0x80000000 >> 12):
+		puts ("Machine check signal\n");
+		break;
+	case (0x80000000 >> 13):
+		puts ("Transfer error ack signal\n");
+		break;
+	case (0x80000000 >> 14):
+		puts ("Data parity signal\n");
+		break;
+	case (0x80000000 >> 15):
+		puts ("Address parity signal\n");
+		break;
+	default:
+		puts ("Unknown values in msr\n");
+	}
+	show_regs (regs);
+	print_backtrace ((unsigned long *)regs->gpr[1]);
+
+	panic ("machine check");
+}
+
+void
+AlignmentException (struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *)regs->gpr[1]);
+	panic ("Alignment Exception");
+}
+
+void
+ProgramCheckException (struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *)regs->gpr[1]);
+	panic ("Program Check Exception");
+}
+
+void
+SoftEmuException (struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *)regs->gpr[1]);
+	panic ("Software Emulation Exception");
+}
+
+
+void
+UnknownException (struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf ("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception (0, regs);
+}
+
+#ifdef CONFIG_CMD_BEDBUG
+extern void do_bedbug_breakpoint (struct pt_regs *);
+#endif
+
+void
+DebugException (struct pt_regs *regs)
+{
+	printf ("Debugger trap at @ %lx\n", regs->nip );
+	show_regs (regs);
+#ifdef CONFIG_CMD_BEDBUG
+	do_bedbug_breakpoint (regs);
+#endif
+}
diff --git a/arch/ppc/cpu/mpc512x/u-boot.lds b/arch/ppc/cpu/mpc512x/u-boot.lds
new file mode 100644
index 0000000..fbc2026
--- /dev/null
+++ b/arch/ppc/cpu/mpc512x/u-boot.lds
@@ -0,0 +1,120 @@
+/*
+ * (C) Copyright 2007 DENX Software Engineering.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    arch/ppc/cpu/mpc512x/start.o	(.text)
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+ENTRY(_start)
diff --git a/arch/ppc/cpu/mpc5xx/Makefile b/arch/ppc/cpu/mpc5xx/Makefile
new file mode 100644
index 0000000..f2ebb9a
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/Makefile
@@ -0,0 +1,59 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2003
+# Martin Winistoerfer, martinwinistoerfer@gmx.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
+#
+
+#
+# File:			arch/ppc/cpu/mpc5xx/Makefile
+#
+# Discription:		Makefile to build mpc5xx cpu configuration.
+#			Will include top config.mk which itselfs
+#			uses the definitions made in arch/ppc/cpu/mpc5xx/config.mk
+#
+
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+COBJS	= serial.o cpu.o cpu_init.o interrupts.o traps.o speed.o spi.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc5xx/config.mk b/arch/ppc/cpu/mpc5xx/config.mk
new file mode 100644
index 0000000..e0b0ce1
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/config.mk
@@ -0,0 +1,36 @@
+#
+# (C) Copyright 2003
+# Martin Winistoerfer, martinwinistoerfer@gmx.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
+#
+
+#
+# File:			config.mk
+#
+# Discription:		compiler flags and make definitions
+#
+
+
+PLATFORM_RELFLAGS +=	-fPIC -meabi
+
+PLATFORM_CPPFLAGS +=	-DCONFIG_5xx -ffixed-r2 -mpowerpc -msoft-float
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc5xx/u-boot.lds
diff --git a/arch/ppc/cpu/mpc5xx/cpu.c b/arch/ppc/cpu/mpc5xx/cpu.c
new file mode 100644
index 0000000..7fffebc
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/cpu.c
@@ -0,0 +1,171 @@
+/*
+ * (C) Copyright 2003
+ * Martin Winistoerfer, martinwinistoerfer@gmx.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,
+ */
+
+/*
+ * File:		cpu.c
+ *
+ * Discription:		Some cpu specific function for watchdog,
+ *                      cpu version test, clock setting ...
+ *
+ */
+
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc5xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if (defined(CONFIG_MPC555))
+#  define	ID_STR	"MPC555/556"
+
+/*
+ * Check version of cpu with Processor Version Register (PVR)
+ */
+static int check_cpu_version (long clock, uint pvr, uint immr)
+{
+    char buf[32];
+	/* The highest 16 bits should be 0x0002 for a MPC555/556 */
+	if ((pvr >> 16) == 0x0002) {
+		printf (" " ID_STR " Version %x", (pvr >> 16));
+		printf (" at %s MHz:", strmhz (buf, clock));
+	} else {
+		printf ("Not supported cpu version");
+		return -1;
+	}
+	return 0;
+}
+#endif /* CONFIG_MPC555 */
+
+
+/*
+ * Check version of mpc5xx
+ */
+int checkcpu (void)
+{
+	ulong clock = gd->cpu_clk;
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	uint pvr = get_pvr ();		/* Retrieve PVR register */
+
+	puts ("CPU:   ");
+
+	return check_cpu_version (clock, pvr, immr);
+}
+
+/*
+ * Called by macro WATCHDOG_RESET
+ */
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts ();
+
+	reset_5xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+	if (re_enable)
+		enable_interrupts ();
+}
+
+/*
+ * Will clear software reset
+ */
+void reset_5xx_watchdog (volatile immap_t * immr)
+{
+	/* Use the MPC5xx Internal Watchdog */
+	immr->im_siu_conf.sc_swsr = 0x556c;	/* Prevent SW time-out */
+	immr->im_siu_conf.sc_swsr = 0xaa39;
+}
+
+#endif /* CONFIG_WATCHDOG */
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+	volatile immap_t *immr = (volatile immap_t *) CONFIG_SYS_IMMR;
+	ulong oscclk, factor;
+
+	if (immr->im_clkrst.car_sccr & SCCR_TBS) {
+		return (gd->cpu_clk / 16);
+	}
+
+	factor = (((CONFIG_SYS_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);
+}
+
+void dcache_enable (void)
+{
+	return;
+}
+
+void dcache_disable (void)
+{
+	return;
+}
+
+int dcache_status (void)
+{
+	return 0;	/* always off */
+}
+
+/*
+ * Reset board
+ */
+int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_PATI)
+	volatile ulong *addr = (ulong *) CONFIG_SYS_RESET_ADDRESS;
+	*addr = 1;
+#else
+	ulong addr;
+
+	/* Interrupts off, enable reset */
+	__asm__ volatile	("  mtspr	81, %r0		\n\t"
+				 "  mfmsr	%r3		\n\t"
+				 "  rlwinm	%r31,%r3,0,25,23\n\t"
+				 "  mtmsr	%r31		\n\t");
+	/*
+	 * Trying to execute the next instruction at a non-existing address
+	 * should cause a machine check, resulting in reset
+	 */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+	addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE         * - sizeof (ulong) is usually a valid address. Better pick an address
+	 * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+	 * "(ulong)-1" used to be a good choice for many systems...
+	 */
+	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+	((void (*) (void)) addr) ();
+#endif  /* #if defined(CONFIG_PATI) */
+	return 1;
+}
diff --git a/arch/ppc/cpu/mpc5xx/cpu_init.c b/arch/ppc/cpu/mpc5xx/cpu_init.c
new file mode 100644
index 0000000..cb4bf84
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/cpu_init.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2003  Martin Winistoerfer, martinwinistoerfer@gmx.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,
+ */
+
+/*
+ * File:		cpu_init.c
+ *
+ * Discription:		Contains initialisation functions to setup
+ *			the cpu properly
+ *
+ */
+
+#include <common.h>
+#include <mpc5xx.h>
+#include <watchdog.h>
+
+/*
+ * Setup essential cpu registers to run
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+	volatile memctl5xx_t *memctl = &immr->im_memctl;
+	ulong reg;
+
+	/* SYPCR - contains watchdog control. This will enable watchdog */
+	/* if CONFIG_WATCHDOG is set */
+	immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+	reset_5xx_watchdog (immr);
+#endif
+
+	/* SIUMCR - contains debug pin configuration */
+	immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR;
+
+	/* Initialize timebase. Unlock TBSCRK */
+	immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+	immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR;
+
+	/* Full IMB bus speed */
+	immr->im_uimb.uimb_umcr = CONFIG_SYS_UMCR;
+
+	/* Time base and decrementer will be enables (TBE) */
+	/* in init_timebase() in time.c called from board_init_f(). */
+
+	/* Initialize the PIT. Unlock PISCRK */
+	immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+	immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+#if !defined(CONFIG_PATI)
+	/* PATI sest PLL in start.S */
+	/* PLL (CPU clock) settings */
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+	/* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
+	 * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
+	 * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the currentMF
+	 * field value.
+	 */
+#if ((CONFIG_SYS_PLPRCR & PLPRCR_MF_MSK) != 0)
+	reg = CONFIG_SYS_PLPRCR;			/* reset control bits   */
+#else
+	reg = immr->im_clkrst.car_plprcr;
+	reg &= PLPRCR_MF_MSK;			/* isolate MF field */
+	reg |= CONFIG_SYS_PLPRCR;			/* reset control bits   */
+#endif
+	immr->im_clkrst.car_plprcr = reg;
+
+#endif /* !defined(CONFIG_PATI) */
+
+	/* System integration timers. CONFIG_SYS_MASK has EBDF configuration */
+	immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+	reg = immr->im_clkrst.car_sccr;
+	reg &= SCCR_MASK;
+	reg |= CONFIG_SYS_SCCR;
+	immr->im_clkrst.car_sccr = reg;
+
+	/* Memory Controller */
+	memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+	memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
+	memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+	memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
+	memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+	memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
+	memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+	memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+}
+
+/*
+ * Initialize higher level parts of cpu
+ */
+int cpu_init_r (void)
+{
+	/* Nothing to do at the moment */
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc5xx/interrupts.c b/arch/ppc/cpu/mpc5xx/interrupts.c
new file mode 100644
index 0000000..167543f
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/interrupts.c
@@ -0,0 +1,207 @@
+/*
+ * (C) Copyright 2000-2002	Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * (C) Copyright 2003		Martin Winistoerfer, martinwinistoerfer@gmx.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,
+ */
+
+/*
+ * File:		interrupt.c
+ *
+ * Discription:		Contains interrupt routines needed by U-Boot
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc5xx.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_PATI)
+/* PATI uses IRQs for PCI doorbell */
+#undef NR_IRQS
+#define NR_IRQS 16
+#endif
+
+struct interrupt_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	int count;
+};
+
+static struct interrupt_action irq_vecs[NR_IRQS];
+
+/*
+ * Initialise interrupts
+ */
+
+int interrupt_init_cpu (ulong *decrementer_count)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int vec;
+
+	/* Decrementer used here for status led */
+	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+	/* Disable all interrupts */
+	immr->im_siu_conf.sc_simask = 0;
+	for (vec=0; vec<NR_IRQS; vec++) {
+		irq_vecs[vec].handler = NULL;
+		irq_vecs[vec].arg = NULL;
+		irq_vecs[vec].count = 0;
+	}
+
+	return (0);
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int irq;
+	ulong simask, newmask;
+	ulong vec, v_bit;
+
+	/*
+	 * read the SIVEC register and shift the bits down
+	 * to get the irq number
+	 */
+	vec = immr->im_siu_conf.sc_sivec;
+	irq = vec >> 26;
+	v_bit = 0x80000000UL >> irq;
+
+	/*
+	 * Read Interrupt Mask Register and Mask Interrupts
+	 */
+	simask = immr->im_siu_conf.sc_simask;
+	newmask = simask & (~(0xFFFF0000 >> irq));
+	immr->im_siu_conf.sc_simask = newmask;
+
+	if (!(irq & 0x1)) {		/* External Interrupt ?     */
+		ulong siel;
+
+		/*
+		 * Read Interrupt Edge/Level Register
+		 */
+		siel = immr->im_siu_conf.sc_siel;
+
+		if (siel & v_bit) {	/* edge triggered interrupt ?   */
+			/*
+			 * Rewrite SIPEND Register to clear interrupt
+			 */
+			immr->im_siu_conf.sc_sipend = v_bit;
+		}
+	}
+
+	if (irq_vecs[irq].handler != NULL) {
+		irq_vecs[irq].handler (irq_vecs[irq].arg);
+	} else {
+		printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+				irq, vec);
+		/* turn off the bogus interrupt to avoid it from now */
+		simask &= ~v_bit;
+	}
+	/*
+	 * Re-Enable old Interrupt Mask
+	 */
+	immr->im_siu_conf.sc_simask = simask;
+}
+
+/*
+ * Install and free an interrupt handler
+ */
+void irq_install_handler (int vec, interrupt_handler_t * handler,
+						  void *arg)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	/* SIU interrupt */
+	if (irq_vecs[vec].handler != NULL) {
+		printf ("SIU interrupt %d 0x%x\n",
+			vec,
+			(uint) handler);
+	}
+	irq_vecs[vec].handler = handler;
+	irq_vecs[vec].arg = arg;
+	immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
+#if 0
+	printf ("Install SIU interrupt for vector %d ==> %p\n",
+		vec, handler);
+#endif
+}
+
+void irq_free_handler (int vec)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	/* SIU interrupt */
+#if 0
+	printf ("Free CPM interrupt for vector %d\n",
+		vec);
+#endif
+	immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
+	irq_vecs[vec].handler = NULL;
+	irq_vecs[vec].arg = NULL;
+}
+
+/*
+ *  Timer interrupt - gets called when  bit 0 of DEC changes from
+ *  0. Decrementer is enabled with bit TBE in TBSCR.
+ */
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if 0
+	printf ("*** Timer Interrupt *** ");
+#endif
+	/* Reset Timer Status Bit and Timers Interrupt Status */
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+	__asm__ ("nop");
+	immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
+
+	return;
+}
+
+#if defined(CONFIG_CMD_IRQ)
+/*******************************************************************************
+ *
+ * irqinfo - print information about IRQs
+ *
+ */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int vec;
+
+	printf ("\nInterrupt-Information:\n");
+	printf ("Nr  Routine   Arg       Count\n");
+
+	for (vec=0; vec<NR_IRQS; vec++) {
+		if (irq_vecs[vec].handler != NULL) {
+			printf ("%02d  %08lx  %08lx  %d\n",
+				vec,
+				(ulong)irq_vecs[vec].handler,
+				(ulong)irq_vecs[vec].arg,
+				irq_vecs[vec].count);
+		}
+	}
+	return 0;
+}
+
+
+#endif
diff --git a/arch/ppc/cpu/mpc5xx/serial.c b/arch/ppc/cpu/mpc5xx/serial.c
new file mode 100644
index 0000000..88c6db8
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/serial.c
@@ -0,0 +1,170 @@
+/*
+ * (C) Copyright 2003
+ * Martin Winistoerfer, martinwinistoerfer@gmx.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,
+ */
+
+/*
+ * File:		serial.c
+ *
+ * Discription:		Serial interface driver for SCI1 and SCI2.
+ *			Since this code will be called from ROM use
+ *			only non-static local variables.
+ *
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc5xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Local function prototypes
+ */
+
+static int ready_to_send(void);
+
+/*
+ * Minimal global serial functions needed to use one of the SCI modules.
+ */
+
+int serial_init (void)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+	serial_setbrg();
+
+#if defined(CONFIG_5xx_CONS_SCI1)
+	/* 10-Bit, 1 start bit, 8 data bit, no parity, 1 stop bit */
+	immr->im_qsmcm.qsmcm_scc1r1 = SCI_M_10;
+	immr->im_qsmcm.qsmcm_scc1r1 = SCI_TE | SCI_RE;
+#else
+	immr->im_qsmcm.qsmcm_scc2r1 = SCI_M_10;
+	immr->im_qsmcm.qsmcm_scc2r1 = SCI_TE | SCI_RE;
+#endif
+	return 0;
+}
+
+void serial_putc(const char c)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+	/* Test for completition */
+	if(ready_to_send()) {
+#if defined(CONFIG_5xx_CONS_SCI1)
+		immr->im_qsmcm.qsmcm_sc1dr = (short)c;
+#else
+		immr->im_qsmcm.qsmcm_sc2dr = (short)c;
+#endif
+		if(c == '\n') {
+			if(ready_to_send());
+#if defined(CONFIG_5xx_CONS_SCI1)
+			immr->im_qsmcm.qsmcm_sc1dr = (short)'\r';
+#else
+			immr->im_qsmcm.qsmcm_sc2dr = (short)'\r';
+#endif
+		}
+	}
+}
+
+int serial_getc(void)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile short status;
+	unsigned char tmp;
+
+	/* New data ? */
+	do {
+#if defined(CONFIG_5xx_CONS_SCI1)
+		status = immr->im_qsmcm.qsmcm_sc1sr;
+#else
+		status = immr->im_qsmcm.qsmcm_sc2sr;
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+		reset_5xx_watchdog (immr);
+#endif
+	} while ((status & SCI_RDRF) == 0);
+
+	/* Read data */
+#if defined(CONFIG_5xx_CONS_SCI1)
+	tmp = (unsigned char)(immr->im_qsmcm.qsmcm_sc1dr & SCI_SCXDR_MK);
+#else
+	tmp = (unsigned char)( immr->im_qsmcm.qsmcm_sc2dr & SCI_SCXDR_MK);
+#endif
+	return	tmp;
+}
+
+int serial_tstc()
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	short status;
+
+	/* New data character ? */
+#if defined(CONFIG_5xx_CONS_SCI1)
+	status = immr->im_qsmcm.qsmcm_sc1sr;
+#else
+	status = immr->im_qsmcm.qsmcm_sc2sr;
+#endif
+	return (status & SCI_RDRF);
+}
+
+void serial_setbrg (void)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	short scxbr;
+
+	/* Set baudrate */
+	scxbr = (gd->cpu_clk / (32 * gd->baudrate));
+#if defined(CONFIG_5xx_CONS_SCI1)
+	immr->im_qsmcm.qsmcm_scc1r0 = (scxbr & SCI_SCXBR_MK);
+#else
+	immr->im_qsmcm.qsmcm_scc2r0 = (scxbr & SCI_SCXBR_MK);
+#endif
+}
+
+void serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc(*s);
+		++s;
+	}
+}
+
+int ready_to_send(void)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile short status;
+
+	do {
+#if defined(CONFIG_5xx_CONS_SCI1)
+		status = immr->im_qsmcm.qsmcm_sc1sr;
+#else
+		status = immr->im_qsmcm.qsmcm_sc2sr;
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+		reset_5xx_watchdog (immr);
+#endif
+	} while ((status & SCI_TDRE) == 0);
+	return 1;
+
+}
diff --git a/arch/ppc/cpu/mpc5xx/speed.c b/arch/ppc/cpu/mpc5xx/speed.c
new file mode 100644
index 0000000..ea5c1de
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/speed.c
@@ -0,0 +1,67 @@
+/*
+ * (C) Copyright 2003
+ * Martin Winistoerfer, martinwinistoerfer@gmx.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,
+ */
+
+/*
+ * File:		speed.c
+ *
+ * Discription:		Provides cpu speed calculation
+ *
+ */
+
+#include <common.h>
+#include <mpc5xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Get cpu and bus clock
+ */
+int get_clocks (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#ifndef	CONFIG_5xx_GCLK_FREQ
+	uint divf = (immr->im_clkrst.car_plprcr & PLPRCR_DIVF_MSK);
+	uint mf = ((immr->im_clkrst.car_plprcr & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT);
+	ulong vcoout;
+
+	vcoout = (CONFIG_SYS_OSC_CLK / (divf + 1)) * (mf + 1) * 2;
+	if(immr->im_clkrst.car_plprcr & PLPRCR_CSRC_MSK) {
+		gd->cpu_clk = vcoout / (2^(((immr->im_clkrst.car_sccr & SCCR_DFNL_MSK) >> SCCR_DFNL_SHIFT) + 1));
+	} else {
+		gd->cpu_clk = vcoout / (2^(immr->im_clkrst.car_sccr & SCCR_DFNH_MSK));
+	}
+
+#else /* CONFIG_5xx_GCLK_FREQ */
+	gd->bus_clk = CONFIG_5xx_GCLK_FREQ;
+#endif /* CONFIG_5xx_GCLK_FREQ */
+
+	if ((immr->im_clkrst.car_sccr & SCCR_EBDF11) == 0) {
+		/* No Bus Divider active */
+		gd->bus_clk = gd->cpu_clk;
+	} else {
+		/* CLKOUT is GCLK / 2 */
+		gd->bus_clk = gd->cpu_clk / 2;
+	}
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc5xx/spi.c b/arch/ppc/cpu/mpc5xx/spi.c
new file mode 100644
index 0000000..3ca15ea
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/spi.c
@@ -0,0 +1,412 @@
+/*
+ * 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
+ */
+
+/*
+ * MPC5xx 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
+ *
+ * Ported to MPC5xx
+ * Copyright (c) 2003 Denis Peter, MPL AG Switzerland, d.petr@mpl.ch.
+ */
+
+#include <common.h>
+#include <mpc5xx.h>
+#include <asm/5xx_immap.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <net.h>
+
+#if defined(CONFIG_SPI)
+
+#undef	DEBUG
+
+#define SPI_EEPROM_WREN		0x06
+#define SPI_EEPROM_RDSR		0x05
+#define SPI_EEPROM_READ		0x03
+#define SPI_EEPROM_WRITE	0x02
+
+
+#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);
+
+
+/* **************************************************************************
+ *
+ *  Function:    spi_init_f
+ *
+ *  Description: Init SPI-Controller (ROM part)
+ *
+ *  return:      ---
+ *
+ * *********************************************************************** */
+
+void spi_init_f (void)
+{
+	int i;
+
+	volatile immap_t *immr;
+	volatile qsmcm5xx_t *qsmcm;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+
+	qsmcm->qsmcm_qsmcr = 0; /* all accesses enabled */
+	qsmcm->qsmcm_qspi_il = 0; /* lowest IRQ */
+
+	/* --------------------------------------------
+	 * GPIO or per. Function
+	 * PQSPAR[00] = 0 reserved
+	 * PQSPAR[01] = 1 [0x4000] -> PERI: (SPICS3)
+	 * PQSPAR[02] = 0 [0x0000] -> GPIO
+	 * PQSPAR[03] = 0 [0x0000] -> GPIO
+	 * PQSPAR[04] = 1 [0x0800] -> PERI: (SPICS0)
+	 * PQSPAR[05] = 0 reseved
+	 * PQSPAR[06] = 1 [0x0200] -> PERI: (SPIMOSI)
+	 * PQSPAR[07] = 1 [0x0100] -> PERI: (SPIMISO)
+	 * -------------------------------------------- */
+	qsmcm->qsmcm_pqspar =  0x3 | (CONFIG_SYS_SPI_CS_USED << 3);
+
+	 /* --------------------------------------------
+	 * DDRQS[00] = 0 reserved
+	 * DDRQS[01] = 1 [0x0040] -> SPICS3 Output
+	 * DDRQS[02] = 0 [0x0000] -> GPIO Output
+	 * DDRQS[03] = 0 [0x0000] -> GPIO Output
+	 * DDRQS[04] = 1 [0x0008] -> SPICS0 Output
+	 * DDRQS[05] = 1 [0x0004] -> SPICLK Output
+	 * DDRQS[06] = 1 [0x0002] -> SPIMOSI Output
+	 * DDRQS[07] = 0 [0x0001] -> SPIMISO Input
+	 * -------------------------------------------- */
+	qsmcm->qsmcm_ddrqs = 0x7E;
+	 /* --------------------------------------------
+	 * Base state for used SPI CS pins, if base = 0 active must be 1
+	 * PORTQS[00] = 0 reserved
+	 * PORTQS[01] = 0 reserved
+	 * PORTQS[02] = 0 reserved
+	 * PORTQS[03] = 0 reserved
+	 * PORTQS[04] = 0 [0x0000] RxD2
+	 * PORTQS[05] = 1 [0x0400] TxD2
+	 * PORTQS[06] = 0 [0x0000] RxD1
+	 * PORTQS[07] = 1 [0x0100] TxD1
+	 * PORTQS[08] = 0 reserved
+	 * PORTQS[09] = 0 [0x0000] -> SPICS3 Base Output
+	 * PORTQS[10] = 0 [0x0000] -> SPICS2 Base Output
+	 * PORTQS[11] = 0 [0x0000] -> SPICS1 Base Output
+	 * PORTQS[12] = 0 [0x0000] -> SPICS0 Base Output
+	 * PORTQS[13] = 0 [0x0004] -> SPICLK Output
+	 * PORTQS[14] = 0 [0x0002] -> SPIMOSI Output
+	 * PORTQS[15] = 0 [0x0001] -> SPIMISO Input
+	 * -------------------------------------------- */
+	qsmcm->qsmcm_portqs |= (CONFIG_SYS_SPI_CS_BASE << 3);
+	/* --------------------------------------------
+	 * Controll Register 0
+	 * SPCR0[00] = 1 (0x8000) Master
+	 * SPCR0[01] = 0 (0x0000) Wired-Or
+	 * SPCR0[2..5] = (0x2000) Bits per transfer (default 8)
+	 * SPCR0[06] = 0 (0x0000) Normal polarity
+	 * SPCR0[07] = 0 (0x0000) Normal Clock Phase
+	 * SPCR0[08..15] = 14 1.4MHz
+	 */
+	qsmcm->qsmcm_spcr0=0xA00E;
+	/* --------------------------------------------
+	 * Controll Register 1
+	 * SPCR1[00] = 0 (0x0000) QSPI enabled
+	 * SPCR1[1..7] =  (0x7F00) Delay before Transfer
+	 * SPCR1[8..15] = (0x0000) Delay After transfer (204.8usec@40MHz)
+	 */
+	qsmcm->qsmcm_spcr1=0x7F00;
+	/* --------------------------------------------
+	 * Controll Register 2
+	 * SPCR2[00] = 0 (0x0000) SPI IRQs Disabeld
+	 * SPCR2[01] = 0 (0x0000) No Wrap around
+	 * SPCR2[02] = 0 (0x0000) Wrap to 0
+	 * SPCR2[3..7] = (0x0000) End Queue pointer = 0
+	 * SPCR2[8..10] = 0 (0x0000) reserved
+	 * SPCR2[11..15] = 0 (0x0000) NewQueue Address = 0
+	 */
+	qsmcm->qsmcm_spcr2=0x0000;
+	/* --------------------------------------------
+	 * Controll Register 3
+	 * SPCR3[00..04] = 0 (0x0000) reserved
+	 * SPCR3[05] = 0 (0x0000) Feedback disabled
+	 * SPCR3[06] = 0 (0x0000) IRQ on HALTA & MODF disabled
+	 * SPCR3[07] = 0 (0x0000) Not halted
+	 */
+	qsmcm->qsmcm_spcr3=0x00;
+	/* --------------------------------------------
+	 * SPSR (Controll Register 3) Read only/ reset Flags 08,09,10
+	 * SPCR3[08] = 1 (0x80) QSPI finished
+	 * SPCR3[09] = 1 (0x40) Mode Fault Flag
+	 * SPCR3[10] = 1 (0x20) HALTA
+	 * SPCR3[11..15] = 0 (0x0000) Last executed command
+	 */
+	qsmcm->qsmcm_spsr=0xE0;
+	/*-------------------------------------------
+	 * Setup RAM
+	 */
+	for(i=0;i<32;i++) {
+		 qsmcm->qsmcm_recram[i]=0x0000;
+		 qsmcm->qsmcm_tranram[i]=0x0000;
+		 qsmcm->qsmcm_comdram[i]=0x00;
+	}
+	return;
+}
+
+/* **************************************************************************
+ *
+ *  Function:    spi_init_r
+ *  Dummy, all initializations have been done in spi_init_r
+ * *********************************************************************** */
+void spi_init_r (void)
+{
+	return;
+
+}
+
+/****************************************************************************
+ *  Function:    spi_write
+ **************************************************************************** */
+ssize_t short_spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+	int i,dlen;
+	volatile immap_t *immr;
+	volatile qsmcm5xx_t *qsmcm;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+	for(i=0;i<32;i++) {
+		 qsmcm->qsmcm_recram[i]=0x0000;
+		 qsmcm->qsmcm_tranram[i]=0x0000;
+		 qsmcm->qsmcm_comdram[i]=0x00;
+	}
+	qsmcm->qsmcm_tranram[0] =  SPI_EEPROM_WREN; /* write enable */
+	spi_xfer(1);
+	i=0;
+	qsmcm->qsmcm_tranram[i++] =  SPI_EEPROM_WRITE; /* WRITE memory array */
+	qsmcm->qsmcm_tranram[i++] =  addr[0];
+	qsmcm->qsmcm_tranram[i++] =  addr[1];
+
+	for(dlen=0;dlen<len;dlen++) {
+		qsmcm->qsmcm_tranram[i+dlen] = buffer[dlen]; /* WRITE memory array */
+	}
+	/* transmit it */
+	spi_xfer(i+dlen);
+	/* ignore received data	*/
+	for (i = 0; i < 1000; i++) {
+		qsmcm->qsmcm_tranram[0] =  SPI_EEPROM_RDSR; /* read status */
+		qsmcm->qsmcm_tranram[1] = 0;
+		spi_xfer(2);
+		if (!(qsmcm->qsmcm_recram[1] & 1)) {
+			break;
+		}
+		udelay(1000);
+	}
+	if (i >= 1000) {
+		printf ("*** spi_write: Time out while writing!\n");
+	}
+	return len;
+}
+
+#define TRANSFER_LEN 16
+
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+	int index,i,newlen;
+	uchar newaddr[2];
+	int curraddr;
+
+	curraddr=(addr[alen-2]<<8)+addr[alen-1];
+	i=len;
+	index=0;
+	do {
+		newaddr[1]=(curraddr & 0xff);
+		newaddr[0]=((curraddr>>8) & 0xff);
+		if(i>TRANSFER_LEN) {
+			newlen=TRANSFER_LEN;
+			i-=TRANSFER_LEN;
+		}
+		else {
+			newlen=i;
+			i=0;
+		}
+		short_spi_write (newaddr, 2, &buffer[index], newlen);
+		index+=newlen;
+		curraddr+=newlen;
+	}while(i);
+	return (len);
+}
+
+/****************************************************************************
+ *  Function:    spi_read
+ **************************************************************************** */
+ssize_t short_spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+	int i;
+	volatile immap_t *immr;
+	volatile qsmcm5xx_t *qsmcm;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+
+	for(i=0;i<32;i++) {
+		 qsmcm->qsmcm_recram[i]=0x0000;
+		 qsmcm->qsmcm_tranram[i]=0x0000;
+		 qsmcm->qsmcm_comdram[i]=0x00;
+	}
+	i=0;
+	qsmcm->qsmcm_tranram[i++] = (SPI_EEPROM_READ); /* READ memory array */
+	qsmcm->qsmcm_tranram[i++] = addr[0] & 0xff;
+	qsmcm->qsmcm_tranram[i++] = addr[1] & 0xff;
+	spi_xfer(3 + len);
+	for(i=0;i<len;i++) {
+		*buffer++=(char)qsmcm->qsmcm_recram[i+3];
+	}
+	return len;
+}
+
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+	int index,i,newlen;
+	uchar newaddr[2];
+	int curraddr;
+
+	curraddr=(addr[alen-2]<<8)+addr[alen-1];
+	i=len;
+	index=0;
+	do {
+		newaddr[1]=(curraddr & 0xff);
+		newaddr[0]=((curraddr>>8) & 0xff);
+		if(i>TRANSFER_LEN) {
+			newlen=TRANSFER_LEN;
+			i-=TRANSFER_LEN;
+		}
+		else {
+			newlen=i;
+			i=0;
+		}
+		short_spi_read (newaddr, 2, &buffer[index], newlen);
+		index+=newlen;
+		curraddr+=newlen;
+	}while(i);
+	return (len);
+}
+
+/****************************************************************************
+ *  Function:    spi_xfer
+ **************************************************************************** */
+ssize_t spi_xfer (size_t count)
+{
+	volatile immap_t *immr;
+	volatile qsmcm5xx_t *qsmcm;
+	int i;
+	int tm;
+	ushort status;
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+	DPRINT (("*** spi_xfer entered count %d***\n",count));
+
+	/* Set CS for device */
+	for(i=0;i<(count-1);i++)
+		qsmcm->qsmcm_comdram[i] = 0x80 | CONFIG_SYS_SPI_CS_ACT;  /* CS3 is connected to the SPI EEPROM */
+
+	qsmcm->qsmcm_comdram[i] = CONFIG_SYS_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */
+	qsmcm->qsmcm_spcr2=((count-1)&0x1F)<<8;
+
+	DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n", count));
+
+	qsmcm->qsmcm_spsr=0xE0; /* clear all flags */
+
+	/* start spi transfer */
+	DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+	qsmcm->qsmcm_spcr1 |= 0x8000;		/* Start transmit */
+
+	/* --------------------------------
+	 * Wait for SPI transmit to get out
+	 * or time out (1 second = 1000 ms)
+	 * -------------------------------- */
+	for (tm=0; tm<1000; ++tm) {
+		status=qsmcm->qsmcm_spcr1;
+		if((status & 0x8000)==0)
+			break;
+		udelay (1000);
+	}
+	if (tm >= 1000) {
+		printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
+	}
+#ifdef	DEBUG
+	printf ("\nspi_xfer: txbuf after xfer\n");
+	memdump ((void *) qsmcm->qsmcm_tranram, 32);	/* dump of txbuf before transmit */
+	printf ("spi_xfer: rxbuf after xfer\n");
+	memdump ((void *) qsmcm->qsmcm_recram, 32);	/* dump of rxbuf after transmit */
+	printf ("\nspi_xfer: commbuf after xfer\n");
+	memdump ((void *) qsmcm->qsmcm_comdram, 32);	/* dump of txbuf before transmit */
+	printf ("\n");
+#endif
+
+	return count;
+}
+
+#endif	/* CONFIG_SPI  */
diff --git a/arch/ppc/cpu/mpc5xx/start.S b/arch/ppc/cpu/mpc5xx/start.S
new file mode 100644
index 0000000..0af879e
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/start.S
@@ -0,0 +1,576 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000, 2001, 2002 Wolfgang Denk <wd@denx.de>
+ *  Copyright (C) 2003  Martin Winistoerfer, martinwinistoerfer@gmx.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
+ */
+
+/*
+ * File:		start.S
+ *
+ * Discription:		startup code
+ *
+ */
+
+#include <config.h>
+#include <mpc5xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_5xx 1		/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <linux/config.h>
+#include <asm/processor.h>
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't have a MMU.
+*/
+#undef	MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI )		/* Machine Check and Recoverable Interr. */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+	.text
+	.long	0x27051956			/* U-Boot Magic Number */
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	mfspr	r3, 638
+	li	r4, CONFIG_SYS_ISB			/* Set ISB bit */
+	or	r3, r3, r4
+	mtspr	638, r3
+	li	r21, BOOTFLAG_COLD		/* Normal Power-On: Boot from FLASH	*/
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x20
+
+	.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 ME, RI flags */
+	mtmsr	r3
+	mtspr	SRR1, r3			/* Make SRR1 match MSR */
+
+	/* Initialize debug port registers					*/
+	/*----------------------------------------------------------------------*/
+	xor	r0, r0, r0			/* Clear R0 */
+	mtspr	LCTRL1, r0			/* Initialize debug port regs */
+	mtspr	LCTRL2, r0
+	mtspr	COUNTA, r0
+	mtspr	COUNTB, r0
+
+#if defined(CONFIG_PATI)
+	/* the external flash access on PATI fails if programming the PLL to 40MHz.
+	 * Copy the PLL programming code to the internal RAM and execute it
+	 *----------------------------------------------------------------------*/
+	lis	r3, CONFIG_SYS_MONITOR_BASE@h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE@l
+	addi	r3, r3, pll_prog_code_start - _start + EXC_OFF_SYS_RESET
+
+	lis	r4, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r4, r4, CONFIG_SYS_INIT_RAM_ADDR@l
+	mtlr	r4
+	addis	r5,0,0x0
+	ori	r5,r5,((pll_prog_code_end - pll_prog_code_start) >>2)
+	mtctr	r5
+	addi	r3, r3, -4
+	addi	r4, r4, -4
+0:
+	lwzu	r0,4(r3)
+	stwu	r0,4(r4)
+	bdnz	0b                /* copy loop */
+	blrl
+#endif
+
+	/*
+	 * Calculate absolute address in FLASH and jump there
+	 *----------------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_MONITOR_BASE@h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE@l
+	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r3
+	blr
+
+in_flash:
+
+	/* Initialize some SPRs that are hard to access from C			*/
+	/*----------------------------------------------------------------------*/
+
+	lis     r3, CONFIG_SYS_IMMR@h			/* Pass IMMR as arg1 to C routine */
+	lis	r2, CONFIG_SYS_INIT_SP_ADDR@h
+	ori	r1, r2, CONFIG_SYS_INIT_SP_ADDR@l	/* Set up the stack in internal SRAM */
+	/* Note: R0 is still 0 here */
+	stwu	r0, -4(r1)			/* Clear final stack frame so that	*/
+	stwu	r0, -4(r1)			/* stack backtraces terminate cleanly	*/
+
+	/*
+	 * Disable serialized ifetch and show cycles
+	 * (i.e. set processor to normal mode) for maximum
+	 * performance.
+	 */
+
+	li	r2, 0x0007
+	mtspr	ICTRL, r2
+
+	/* Set up debug mode entry */
+
+	lis	r2, CONFIG_SYS_DER@h
+	ori	r2, r2, CONFIG_SYS_DER@l
+	mtspr	DER, r2
+
+	/* 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(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	/* FPU on MPC5xx available. We will use it later.
+	*/
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	/* On the MPC8xx, this is a software emulation interrupt.  It occurs
+	 * for all unimplemented and illegal instructions.
+	 */
+	STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+	STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+	STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+	STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+	STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+	STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+	STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+	STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+	STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+	STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
+	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+
+	. = 0x2000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28			/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)		/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+	.globl	get_immr
+get_immr:
+	mr	r4,r3		/* save mask */
+	mfspr	r3, IMMR	/* IMMR */
+	cmpwi	0,r4,0		/* mask != 0 ? */
+	beq	4f
+	and	r3,r3,r4	/* IMMR & mask */
+4:
+	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 in SRAM	*/
+	mr	r9,  r4		/* Save copy of global data pointer in SRAM */
+	mr	r10, r5		/* Save copy of monitor destination Address in SRAM */
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* 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	4f		/* 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
+
+4:	sync
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	mtlr	r4			/* restore link register	*/
+	blr
+
+#if defined(CONFIG_PATI)
+/* Program the PLL */
+pll_prog_code_start:
+	lis	r4, (CONFIG_SYS_IMMR + 0x002fc384)@h
+	ori	r4, r4, (CONFIG_SYS_IMMR + 0x002fc384)@l
+	lis	r3, (0x55ccaa33)@h
+	ori	r3, r3, (0x55ccaa33)@l
+	stw	r3, 0(r4)
+	lis	r4, (CONFIG_SYS_IMMR + 0x002fc284)@h
+	ori	r4, r4, (CONFIG_SYS_IMMR + 0x002fc284)@l
+	lis	r3, CONFIG_SYS_PLPRCR@h
+	ori	r3, r3, CONFIG_SYS_PLPRCR@l
+	stw	r3, 0(r4)
+	addis	r3,0,0x0
+	ori	r3,r3,0xA000
+	mtctr	r3
+..spinlp:
+  bdnz    ..spinlp                /* spin loop */
+	blr
+pll_prog_code_end:
+	nop
+	blr
+#endif
diff --git a/arch/ppc/cpu/mpc5xx/traps.c b/arch/ppc/cpu/mpc5xx/traps.c
new file mode 100644
index 0000000..6882c21
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/traps.c
@@ -0,0 +1,227 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM	0x0001000
+
+
+/*
+ * Print stack backtrace
+ */
+void print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+/*
+ * Print current registers
+ */
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0)
+		{
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7)
+		{
+			printf("\n");
+		}
+	}
+}
+
+
+/*
+ * General exception handler routine
+ */
+void _exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+/*
+ * Machine check exception handler routine
+ */
+void MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		printf("Machine check signal\n");
+		break;
+	case (0x80000000>>13):
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+/*
+ * Alignment exception handler routine
+ */
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+/*
+ * Program check exception handler routine
+ */
+void ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+/*
+ * Software emulation exception handler routine
+ */
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+/*
+ * Unknown exception handler routine
+ */
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+/*
+ * Debug exception handler routine
+ */
+void DebugException(struct pt_regs *regs)
+{
+	printf("Debugger trap at @ %lx\n", regs->nip );
+	show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+	do_bedbug_breakpoint( regs );
+#endif
+}
diff --git a/arch/ppc/cpu/mpc5xx/u-boot.lds b/arch/ppc/cpu/mpc5xx/u-boot.lds
new file mode 100644
index 0000000..55190c7
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xx/u-boot.lds
@@ -0,0 +1,137 @@
+/*
+ * (C) Copyright 2001	Wolfgang Denk, DENX Software Engineering, wd@denx.de
+ * (C) Copyright 2003	Martin Winistoerfer, martinwinistoerfer@gmx.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
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    /* WARNING - the following is hand-optimized to fit within	*/
+    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
+
+    arch/ppc/cpu/mpc5xx/start.o	(.text)
+
+    *(.text)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x00FF) & 0xFFFFFF00;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2;
+  __fixup_entries = (. - _FIXUP_TABLE_)>>2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(256);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(256);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+
+  _end = . ;
+  PROVIDE (end = .);
+/*   . = env_start;
+	.ppcenv	:
+	{
+		common/env_embedded.o (.ppcenv)
+	}
+*/
+}
diff --git a/arch/ppc/cpu/mpc5xxx/Makefile b/arch/ppc/cpu/mpc5xxx/Makefile
new file mode 100644
index 0000000..0ee0611
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+SOBJS	= io.o firmware_sc_task_bestcomm.impl.o
+COBJS	= i2c.o traps.o cpu.o cpu_init.o ide.o interrupts.o \
+	  loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o usb.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc5xxx/config.mk b/arch/ppc/cpu/mpc5xxx/config.mk
new file mode 100644
index 0000000..9a64cb6
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/config.mk
@@ -0,0 +1,30 @@
+#
+# (C) Copyright 2003
+# 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
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC5xxx -ffixed-r2 \
+		     -mstring -mcpu=603e -mmultiple
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc5xxx/u-boot.lds
diff --git a/arch/ppc/cpu/mpc5xxx/cpu.c b/arch/ppc/cpu/mpc5xxx/cpu.c
new file mode 100644
index 0000000..b20234d
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/cpu.c
@@ -0,0 +1,205 @@
+/*
+ * (C) Copyright 2000-2010
+ * 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
+ */
+
+/*
+ * CPU specific code for the MPC5xxx CPUs
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <net.h>
+#include <mpc5xxx.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt_support.h>
+#endif
+
+#if defined(CONFIG_OF_IDE_FIXUP)
+#include <ide.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+	uint svr, pvr;
+
+	puts ("CPU:   ");
+
+	svr = get_svr();
+	pvr = get_pvr();
+
+	switch (pvr) {
+	case PVR_5200:
+		printf("MPC5200");
+		break;
+	case PVR_5200B:
+		printf("MPC5200B");
+		break;
+	default:
+		printf("Unknown MPC5xxx");
+		break;
+	}
+
+	printf (" v%d.%d, Core v%d.%d", SVR_MJREV (svr), SVR_MNREV (svr),
+		PVR_MAJ(pvr), PVR_MIN(pvr));
+	printf (" at %s MHz\n", strmhz (buf, clock));
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong msr;
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/* Charge the watchdog timer */
+	*(vu_long *)(MPC5XXX_GPT0_COUNTER) = 0x0001000f;
+	*(vu_long *)(MPC5XXX_GPT0_ENABLE) = 0x9004; /* wden|ce|timer_ms */
+	while(1);
+
+	return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+	ulong tbclk;
+
+	tbclk = (gd->bus_clk + 3L) / 4L;
+
+	return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_OF_LIBFDT) && defined (CONFIG_OF_BOARD_SETUP)
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	int div = in_8((void*)CONFIG_SYS_MBAR + 0x204) & 0x0020 ? 8 : 4;
+	char * cpu_path = "/cpus/" OF_CPU;
+#ifdef CONFIG_MPC5xxx_FEC
+	uchar enetaddr[6];
+	char * eth_path = "/" OF_SOC "/ethernet@3000";
+#endif
+
+	do_fixup_by_path_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1);
+	do_fixup_by_path_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_path_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1);
+	do_fixup_by_path_u32(blob, "/" OF_SOC, "bus-frequency", bd->bi_ipbfreq, 1);
+	do_fixup_by_path_u32(blob, "/" OF_SOC, "system-frequency",
+				bd->bi_busfreq*div, 1);
+#ifdef CONFIG_MPC5xxx_FEC
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	do_fixup_by_path(blob, eth_path, "mac-address", enetaddr, 6, 0);
+	do_fixup_by_path(blob, eth_path, "local-mac-address", enetaddr, 6, 0);
+#endif
+#if defined(CONFIG_OF_IDE_FIXUP)
+	if (!ide_device_present(0)) {
+		/* NO CF card detected -> delete ata node in DTS */
+		int nodeoffset = 0;
+		char nodename[] = "/soc5200@f0000000/ata@3a00";
+
+		nodeoffset = fdt_path_offset(blob, nodename);
+		if (nodeoffset >= 0) {
+			fdt_del_node(blob, nodeoffset);
+		} else {
+			printf("%s: cannot find %s node err:%s\n",
+				__func__, nodename, fdt_strerror(nodeoffset));
+		}
+	}
+
+#endif
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
+#endif
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+void bootcount_store (ulong a)
+{
+	volatile ulong *save_addr = (volatile ulong *) (MPC5XXX_CDM_BRDCRMB);
+
+	*save_addr = (BOOTCOUNT_MAGIC & 0xffff0000) | a;
+}
+
+ulong bootcount_load (void)
+{
+	volatile ulong *save_addr = (volatile ulong *) (MPC5XXX_CDM_BRDCRMB);
+
+	if ((*save_addr & 0xffff0000) != (BOOTCOUNT_MAGIC & 0xffff0000))
+		return 0;
+	else
+		return (*save_addr & 0x0000ffff);
+}
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
+
+#ifdef CONFIG_MPC5xxx_FEC
+/* Default initializations for FEC controllers.  To override,
+ * create a board-specific function called:
+ * 	int board_eth_init(bd_t *bis)
+ */
+
+int cpu_eth_init(bd_t *bis)
+{
+	return mpc5xxx_fec_initialize(bis);
+}
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset(void)
+{
+	int re_enable = disable_interrupts();
+	reset_5xxx_watchdog();
+	if (re_enable) enable_interrupts();
+}
+
+void reset_5xxx_watchdog(void)
+{
+	volatile struct mpc5xxx_gpt *gpt0 =
+		(struct mpc5xxx_gpt *) MPC5XXX_GPT;
+
+	/* Trigger TIMER_0 by writing A5 to OCPW */
+	clrsetbits_be32(&gpt0->emsr, 0xff000000, 0xa5000000);
+}
+#endif	/* CONFIG_WATCHDOG */
diff --git a/arch/ppc/cpu/mpc5xxx/cpu_init.c b/arch/ppc/cpu/mpc5xxx/cpu_init.c
new file mode 100644
index 0000000..9daf375
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/cpu_init.c
@@ -0,0 +1,233 @@
+/*
+ * (C) Copyright 2000-2010
+ * 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 <mpc5xxx.h>
+#include <asm/io.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers.
+ */
+void cpu_init_f (void)
+{
+	volatile struct mpc5xxx_mmap_ctl *mm =
+		(struct mpc5xxx_mmap_ctl *) CONFIG_SYS_MBAR;
+	volatile struct mpc5xxx_lpb *lpb =
+		(struct mpc5xxx_lpb *) MPC5XXX_LPB;
+	volatile struct mpc5xxx_gpio *gpio =
+		(struct mpc5xxx_gpio *) MPC5XXX_GPIO;
+	volatile struct mpc5xxx_xlb *xlb =
+		(struct mpc5xxx_xlb *) MPC5XXX_XLBARB;
+#if defined(CONFIG_SYS_IPBCLK_EQUALS_XLBCLK)
+	volatile struct mpc5xxx_cdm *cdm =
+		(struct mpc5xxx_cdm *) MPC5XXX_CDM;
+#endif	/* CONFIG_SYS_IPBCLK_EQUALS_XLBCLK */
+#if defined(CONFIG_WATCHDOG)
+	volatile struct mpc5xxx_gpt *gpt0 =
+		(struct mpc5xxx_gpt *) MPC5XXX_GPT;
+#endif /* CONFIG_WATCHDOG */
+	unsigned long addecr = (1 << 25); /* Boot_CS */
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	memset ((void *) gd, 0, sizeof (gd_t));
+
+	/*
+	 * Memory Controller: configure chip selects and enable them
+	 */
+#if defined(CONFIG_SYS_BOOTCS_START) && defined(CONFIG_SYS_BOOTCS_SIZE)
+	out_be32(&mm->boot_start, START_REG(CONFIG_SYS_BOOTCS_START));
+	out_be32(&mm->boot_stop, STOP_REG(CONFIG_SYS_BOOTCS_START,
+					  CONFIG_SYS_BOOTCS_SIZE));
+#endif
+#if defined(CONFIG_SYS_BOOTCS_CFG)
+	out_be32(&lpb->cs0_cfg, CONFIG_SYS_BOOTCS_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS0_START) && defined(CONFIG_SYS_CS0_SIZE)
+	out_be32(&mm->cs0_start, START_REG(CONFIG_SYS_CS0_START));
+	out_be32(&mm->cs0_stop, STOP_REG(CONFIG_SYS_CS0_START,
+					 CONFIG_SYS_CS0_SIZE));
+	/* CS0 and BOOT_CS cannot be enabled at once. */
+	/*	addecr |= (1 << 16); */
+#endif
+#if defined(CONFIG_SYS_CS0_CFG)
+	out_be32(&lpb->cs0_cfg, CONFIG_SYS_CS0_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS1_START) && defined(CONFIG_SYS_CS1_SIZE)
+	out_be32(&mm->cs1_start, START_REG(CONFIG_SYS_CS1_START));
+	out_be32(&mm->cs1_stop, STOP_REG(CONFIG_SYS_CS1_START,
+					 CONFIG_SYS_CS1_SIZE));
+	addecr |= (1 << 17);
+#endif
+#if defined(CONFIG_SYS_CS1_CFG)
+	out_be32(&lpb->cs1_cfg, CONFIG_SYS_CS1_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS2_START) && defined(CONFIG_SYS_CS2_SIZE)
+	out_be32(&mm->cs2_start, START_REG(CONFIG_SYS_CS2_START));
+	out_be32(&mm->cs2_stop, STOP_REG(CONFIG_SYS_CS2_START,
+					 CONFIG_SYS_CS2_SIZE));
+	addecr |= (1 << 18);
+#endif
+#if defined(CONFIG_SYS_CS2_CFG)
+	out_be32(&lpb->cs2_cfg, CONFIG_SYS_CS2_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS3_START) && defined(CONFIG_SYS_CS3_SIZE)
+	out_be32(&mm->cs3_start, START_REG(CONFIG_SYS_CS3_START));
+	out_be32(&mm->cs3_stop, STOP_REG(CONFIG_SYS_CS3_START,
+					 CONFIG_SYS_CS3_SIZE));
+	addecr |= (1 << 19);
+#endif
+#if defined(CONFIG_SYS_CS3_CFG)
+	out_be32(&lpb->cs3_cfg, CONFIG_SYS_CS3_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS4_START) && defined(CONFIG_SYS_CS4_SIZE)
+	out_be32(&mm->cs4_start, START_REG(CONFIG_SYS_CS4_START));
+	out_be32(&mm->cs4_stop, STOP_REG(CONFIG_SYS_CS4_START,
+					  CONFIG_SYS_CS4_SIZE));
+	addecr |= (1 << 20);
+#endif
+#if defined(CONFIG_SYS_CS4_CFG)
+	out_be32(&lpb->cs4_cfg, CONFIG_SYS_CS4_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS5_START) && defined(CONFIG_SYS_CS5_SIZE)
+	out_be32(&mm->cs5_start, START_REG(CONFIG_SYS_CS5_START));
+	out_be32(&mm->cs5_stop, STOP_REG(CONFIG_SYS_CS5_START,
+					  CONFIG_SYS_CS5_SIZE));
+	addecr |= (1 << 21);
+#endif
+#if defined(CONFIG_SYS_CS5_CFG)
+	out_be32(&lpb->cs5_cfg, CONFIG_SYS_CS5_CFG);
+#endif
+
+	addecr |= 1;
+#if defined(CONFIG_SYS_CS6_START) && defined(CONFIG_SYS_CS6_SIZE)
+	out_be32(&mm->cs6_start, START_REG(CONFIG_SYS_CS6_START));
+	out_be32(&mm->cs6_stop, STOP_REG(CONFIG_SYS_CS6_START,
+					  CONFIG_SYS_CS6_SIZE));
+	addecr |= (1 << 26);
+#endif
+#if defined(CONFIG_SYS_CS6_CFG)
+	out_be32(&lpb->cs6_cfg, CONFIG_SYS_CS6_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS7_START) && defined(CONFIG_SYS_CS7_SIZE)
+	out_be32(&mm->cs7_start, START_REG(CONFIG_SYS_CS7_START));
+	out_be32(&mm->cs7_stop, STOP_REG(CONFIG_SYS_CS7_START,
+					  CONFIG_SYS_CS7_SIZE));
+	addecr |= (1 << 27);
+#endif
+#if defined(CONFIG_SYS_CS7_CFG)
+	out_be32(&lpb->cs7_cfg, CONFIG_SYS_CS7_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS_BURST)
+	out_be32(&lpb->cs_burst, CONFIG_SYS_CS_BURST);
+#endif
+#if defined(CONFIG_SYS_CS_DEADCYCLE)
+	out_be32(&lpb->cs_deadcycle, CONFIG_SYS_CS_DEADCYCLE);
+#endif
+
+	/* Enable chip selects */
+	out_be32(&mm->ipbi_ws_ctrl, addecr);
+	out_be32(&lpb->cs_ctrl, (1 << 24));
+
+	/* Setup pin multiplexing */
+#if defined(CONFIG_SYS_GPS_PORT_CONFIG)
+	out_be32(&gpio->port_config, CONFIG_SYS_GPS_PORT_CONFIG);
+#endif
+
+	/* enable timebase */
+	setbits_be32(&xlb->config, (1 << 13));
+
+	/* Enable snooping for RAM */
+	setbits_be32(&xlb->config, (1 << 15));
+	out_be32(&xlb->snoop_window, CONFIG_SYS_SDRAM_BASE | 0x1d);
+
+#if defined(CONFIG_SYS_IPBCLK_EQUALS_XLBCLK)
+	/* Motorola reports IPB should better run at 133 MHz. */
+	setbits_be32(&mm->ipbi_ws_ctrl, 1);
+	/* pci_clk_sel = 0x02, ipb_clk_sel = 0x00; */
+	addecr = in_be32(&cdm->cfg);
+	addecr &= ~0x103;
+# if defined(CONFIG_SYS_PCICLK_EQUALS_IPBCLK_DIV2)
+	/* pci_clk_sel = 0x01 -> IPB_CLK/2 */
+	addecr |= 0x01;
+# else
+	/* pci_clk_sel = 0x02 -> XLB_CLK/4 = IPB_CLK/4 */
+	addecr |= 0x02;
+# endif /* CONFIG_SYS_PCICLK_EQUALS_IPBCLK_DIV2 */
+	out_be32(&cdm->cfg, addecr);
+#endif	/* CONFIG_SYS_IPBCLK_EQUALS_XLBCLK */
+	/* Configure the XLB Arbiter */
+	out_be32(&xlb->master_pri_enable, 0xff);
+	out_be32(&xlb->master_priority, 0x11111111);
+
+#if defined(CONFIG_SYS_XLB_PIPELINING)
+	/* Enable piplining */
+	clrbits_be32(&xlb->config, (1 << 31));
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+	/* Charge the watchdog timer - prescaler = 64k, count = 64k*/
+	out_be32(&gpt0->cir, 0x0000ffff);
+	out_be32(&gpt0->emsr, 0x9004);	/* wden|ce|timer_ms */
+
+	reset_5xxx_watchdog();
+#endif /* CONFIG_WATCHDOG */
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+	volatile struct mpc5xxx_intr *intr =
+		(struct mpc5xxx_intr *) MPC5XXX_ICTL;
+
+	/* mask all interrupts */
+	out_be32(&intr->per_mask, 0xffffff00);
+	setbits_be32(&intr->main_mask, 0x0001ffff);
+	clrbits_be32(&intr->ctrl, 0x00000f00);
+	/* route critical ints to normal ints */
+	setbits_be32(&intr->ctrl, 0x00000001);
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC5xxx_FEC)
+	/* load FEC microcode */
+	loadtask(0, 2);
+#endif
+
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S b/arch/ppc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S
new file mode 100644
index 0000000..00c2312
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2001, Software Center, Motorola China.
+ *
+ * This file contains microcode for the FEC controller of the MPC5200 CPU.
+ */
+
+#include <config.h>
+
+/* sas/sccg, gas target */
+.section        smartdmaInitData,"aw",@progbits	/* Initialized data for task variables */
+.section        smartdmaTaskTable,"aw",@progbits	/* Task tables */
+.align  9
+.globl taskTable
+taskTable:
+.globl scEthernetRecv_Entry
+scEthernetRecv_Entry:		/* Task 0 */
+.long   scEthernetRecv_TDT - taskTable	/* Task 0 Descriptor Table */
+.long   scEthernetRecv_TDT - taskTable + 0x000000a4
+.long   scEthernetRecv_VarTab - taskTable	/* Task 0 Variable Table */
+.long   scEthernetRecv_FDT - taskTable + 0x03	/* Task 0 Function Descriptor Table & Flags */
+.long   0x00000000
+.long   0x00000000
+.long   scEthernetRecv_CSave - taskTable	/* Task 0 context save space */
+.long   CONFIG_SYS_MBAR
+.globl scEthernetXmit_Entry
+scEthernetXmit_Entry:		/* Task 1 */
+.long   scEthernetXmit_TDT - taskTable	/* Task 1 Descriptor Table */
+.long   scEthernetXmit_TDT - taskTable + 0x000000d0
+.long   scEthernetXmit_VarTab - taskTable	/* Task 1 Variable Table */
+.long   scEthernetXmit_FDT - taskTable + 0x03	/* Task 1 Function Descriptor Table & Flags */
+.long   0x00000000
+.long   0x00000000
+.long   scEthernetXmit_CSave - taskTable	/* Task 1 context save space */
+.long   CONFIG_SYS_MBAR
+
+
+.globl scEthernetRecv_TDT
+scEthernetRecv_TDT:	/* Task 0 Descriptor Table */
+.long   0xc4c50000	/* 0000:  LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */
+.long   0x84c5e000	/* 0004:  LCD: idx1 = var9 + var11; ; idx1 += inc0 */
+.long   0x10001f08	/* 0008:    DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x10000380	/* 000C:    DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f88	/* 0010:    DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0x81980000	/* 0014:  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long   0x10000780	/* 0018:    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 001C:    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x010cf04c	/* 0020:    DRD2B1: var4 = EU3(); EU3(var1,var12)  */
+.long   0x82180349	/* 0024:  LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */
+.long   0x81c68004	/* 0028:    LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */
+.long   0x70000000	/* 002C:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x018cf04e	/* 0030:      DRD2B1: var6 = EU3(); EU3(var1,var14)  */
+.long   0x70000000	/* 0034:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x020cf04f	/* 0038:      DRD2B1: var8 = EU3(); EU3(var1,var15)  */
+.long   0x00000b88	/* 003C:      DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0x8000d184	/* 0040:    LCDEXT: idx1 = 0xf0003184; ; */
+.long   0xc6990452	/* 0044:    LCDEXT: idx2 = var13; idx2 < var17; idx2 += inc2 */
+.long   0x81486010	/* 0048:    LCD: idx3 = var2 + var16; ; idx3 += inc2 */
+.long   0x006acf88	/* 004C:      DRD1A: *idx3 = *idx1; FN=0 init=3 WS=1 RS=1 */
+.long   0x8000d184	/* 0050:    LCDEXT: idx1 = 0xf0003184; ; */
+.long   0x86810492	/* 0054:    LCD: idx2 = var13, idx3 = var2; idx2 < var18; idx2 += inc2, idx3 += inc2 */
+.long   0x006acf88	/* 0058:      DRD1A: *idx3 = *idx1; FN=0 init=3 WS=1 RS=1 */
+.long   0x8000d184	/* 005C:    LCDEXT: idx1 = 0xf0003184; ; */
+.long   0x868184d2	/* 0060:    LCD: idx2 = var13, idx3 = var3; idx2 < var19; idx2 += inc2, idx3 += inc2 */
+.long   0x000acf88	/* 0064:      DRD1A: *idx3 = *idx1; FN=0 init=0 WS=1 RS=1 */
+.long   0xc318839b	/* 0068:    LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc3 */
+.long   0x80190000	/* 006C:    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long   0x04008468	/* 0070:      DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */
+.long   0xc4038358	/* 0074:    LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc3, idx2 += inc0 */
+.long   0x81c50000	/* 0078:    LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */
+.long   0x1000cb18	/* 007C:      DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f18	/* 0080:      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long   0xc4188364	/* 0084:    LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc4 */
+.long   0x83990000	/* 0088:    LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */
+.long   0x10000c00	/* 008C:      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x0000c800	/* 0090:      DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */
+.long   0x81988000	/* 0094:    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x10000788	/* 0098:      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 009C:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x080cf04c	/* 00A0:      DRD2B1: idx0 = EU3(); EU3(var1,var12)  */
+.long   0x000001f8	/* 00A4(:0):    NOP */
+
+
+.globl scEthernetXmit_TDT
+scEthernetXmit_TDT:	/* Task 1 Descriptor Table */
+.long   0x80024800	/* 0000:  LCDEXT: idx0 = 0xf0008800; ; */
+.long   0x85c60004	/* 0004:  LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */
+.long   0x10002308	/* 0008:    DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x10000f88	/* 000C:    DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000380	/* 0010:    DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */
+.long   0x81980000	/* 0014:  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long   0x10000780	/* 0018:    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 001C:    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x024cf04d	/* 0020:    DRD2B1: var9 = EU3(); EU3(var1,var13)  */
+.long   0x84980309	/* 0024:  LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */
+.long   0xc0004003	/* 0028:    LCDEXT: idx1 = 0x00000003; ; */
+.long   0x81c60004	/* 002C:    LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */
+.long   0x70000000	/* 0030:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x010cf04e	/* 0034:      DRD2B1: var4 = EU3(); EU3(var1,var14)  */
+.long   0x70000000	/* 0038:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x014cf04f	/* 003C:      DRD2B1: var5 = EU3(); EU3(var1,var15)  */
+.long   0x70000000	/* 0040:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x028cf050	/* 0044:      DRD2B1: var10 = EU3(); EU3(var1,var16)  */
+.long   0x70000000	/* 0048:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x018cf051	/* 004C:      DRD2B1: var6 = EU3(); EU3(var1,var17)  */
+.long   0x10000b90	/* 0050:      DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 0054:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x01ccf0a1	/* 0058:      DRD2B1: var7 = EU3(); EU3(var2,idx1)  */
+.long   0xc2988312	/* 005C:    LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */
+.long   0x83490000	/* 0060:    LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */
+.long   0x00001b10	/* 0064:      DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */
+.long   0x8000d1a4	/* 0068:    LCDEXT: idx1 = 0xf00031a4; ; */
+.long   0x8301031c	/* 006C:    LCD: idx2 = var6, idx3 = var2; idx2 > var12; idx2 += inc3, idx3 += inc4 */
+.long   0x008ac798	/* 0070:      DRD1A: *idx1 = *idx3; FN=0 init=4 WS=1 RS=1 */
+.long   0x8000d1a4	/* 0074:    LCDEXT: idx1 = 0xf00031a4; ; */
+.long   0xc1430000	/* 0078:    LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */
+.long   0x82998312	/* 007C:    LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */
+.long   0x088ac790	/* 0080:      DRD1A: *idx1 = *idx2; FN=0 TFD init=4 WS=1 RS=1 */
+.long   0x81988000	/* 0084:    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x60000001	/* 0088:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=1 EXT init=0 WS=0 RS=0 */
+.long   0x0c4cfc4d	/* 008C:      DRD2B1: *idx1 = EU3(); EU3(*idx1,var13)  */
+.long   0xc21883ad	/* 0090:    LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */
+.long   0x80190000	/* 0094:    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long   0x04008460	/* 0098:      DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */
+.long   0xc4052305	/* 009C:    LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */
+.long   0x81c98000	/* 00A0:    LCD: idx3 = var3 + var19; idx3 once var0; idx3 += inc0 */
+.long   0x1000c718	/* 00A4:      DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f18	/* 00A8:      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long   0xc4188000	/* 00AC:    LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */
+.long   0x85190312	/* 00B0:    LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */
+.long   0x10000c00	/* 00B4:      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x1000c400	/* 00B8:      DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00008860	/* 00BC:      DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */
+.long   0x81988000	/* 00C0:    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x10000788	/* 00C4:      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 00C8:      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x080cf04d	/* 00CC:      DRD2B1: idx0 = EU3(); EU3(var1,var13)  */
+.long   0x000001f8	/* 00D0(:0):    NOP */
+
+.align  8
+
+.globl scEthernetRecv_VarTab
+scEthernetRecv_VarTab:	/* Task 0 Variable Table */
+.long   0x00000000	/* var[0] */
+.long   0x00000000	/* var[1] */
+.long   0x00000000	/* var[2] */
+.long   0x00000000	/* var[3] */
+.long   0x00000000	/* var[4] */
+.long   0x00000000	/* var[5] */
+.long   0x00000000	/* var[6] */
+.long   0x00000000	/* var[7] */
+.long   0x00000000	/* var[8] */
+.long   (CONFIG_SYS_MBAR + 0x8800)	/* var[9] */
+.long   0x00000008	/* var[10] */
+.long   0x0000000c	/* var[11] */
+.long   0x80000000	/* var[12] */
+.long   0x00000000	/* var[13] */
+.long   0x10000000	/* var[14] */
+.long   0x20000000	/* var[15] */
+.long   0x000005e4	/* var[16] */
+.long   0x0000000e	/* var[17] */
+.long   0x000005e0	/* var[18] */
+.long   0x00000004	/* var[19] */
+.long   0x00000000	/* var[20] */
+.long   0x00000000	/* var[21] */
+.long   0x00000000	/* var[22] */
+.long   0x00000000	/* var[23] */
+.long   0x00000000	/* inc[0] */
+.long   0x60000000	/* inc[1] */
+.long   0x20000001	/* inc[2] */
+.long   0x80000000	/* inc[3] */
+.long   0x40000000	/* inc[4] */
+.long   0x00000000	/* inc[5] */
+.long   0x00000000	/* inc[6] */
+.long   0x00000000	/* inc[7] */
+
+.align  8
+
+.globl scEthernetXmit_VarTab
+scEthernetXmit_VarTab:	/* Task 1 Variable Table */
+.long   0x00000000	/* var[0] */
+.long   0x00000000	/* var[1] */
+.long   0x00000000	/* var[2] */
+.long   0x00000000	/* var[3] */
+.long   0x00000000	/* var[4] */
+.long   0x00000000	/* var[5] */
+.long   0x00000000	/* var[6] */
+.long   0x00000000	/* var[7] */
+.long   0x00000000	/* var[8] */
+.long   0x00000000	/* var[9] */
+.long   0x00000000	/* var[10] */
+.long   (CONFIG_SYS_MBAR + 0x8800)	/* var[11] */
+.long   0x00000000	/* var[12] */
+.long   0x80000000	/* var[13] */
+.long   0x10000000	/* var[14] */
+.long   0x08000000	/* var[15] */
+.long   0x20000000	/* var[16] */
+.long   0x0000ffff	/* var[17] */
+.long   0xffffffff	/* var[18] */
+.long   0x00000008	/* var[19] */
+.long   0x00000000	/* var[20] */
+.long   0x00000000	/* var[21] */
+.long   0x00000000	/* var[22] */
+.long   0x00000000	/* var[23] */
+.long   0x00000000	/* inc[0] */
+.long   0x60000000	/* inc[1] */
+.long   0x40000000	/* inc[2] */
+.long   0x4000ffff	/* inc[3] */
+.long   0xe0000001	/* inc[4] */
+.long   0x80000000	/* inc[5] */
+.long   0x00000000	/* inc[6] */
+.long   0x00000000	/* inc[7] */
+
+.align  8
+
+.globl scEthernetRecv_FDT
+scEthernetRecv_FDT:	/* Task 0 Function Descriptor Table */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x21800000	/* and(), EU# 3 */
+.long   0x21400000	/* andn(), EU# 3 */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+
+.align  8
+
+.globl scEthernetXmit_FDT
+scEthernetXmit_FDT:	/* Task 1 Function Descriptor Table */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x21800000	/* and(), EU# 3 */
+.long   0x21400000	/* andn(), EU# 3 */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+
+
+.globl scEthernetRecv_CSave
+scEthernetRecv_CSave:	/* Task 0 context save space */
+.space  128, 0x0
+
+
+.globl scEthernetXmit_CSave
+scEthernetXmit_CSave:	/* Task 1 context save space */
+.space  128, 0x0
diff --git a/arch/ppc/cpu/mpc5xxx/i2c.c b/arch/ppc/cpu/mpc5xxx/i2c.c
new file mode 100644
index 0000000..4f7f716
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/i2c.c
@@ -0,0 +1,442 @@
+/*
+ * (C) Copyright 2003
+ * 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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_HARD_I2C
+
+#include <mpc5xxx.h>
+#include <i2c.h>
+
+#if (CONFIG_SYS_I2C_MODULE == 2)
+#define I2C_BASE	MPC5XXX_I2C2
+#elif (CONFIG_SYS_I2C_MODULE == 1)
+#define I2C_BASE	MPC5XXX_I2C1
+#else
+#error CONFIG_SYS_I2C_MODULE is not properly configured
+#endif
+
+#define I2C_TIMEOUT	6667
+#define I2C_RETRIES	3
+
+struct mpc5xxx_i2c_tap {
+	int scl2tap;
+	int tap2tap;
+};
+
+static int  mpc_reg_in    (volatile u32 *reg);
+static void mpc_reg_out   (volatile u32 *reg, int val, int mask);
+static int  wait_for_bb   (void);
+static int  wait_for_pin  (int *status);
+static int  do_address    (uchar chip, char rdwr_flag);
+static int  send_bytes    (uchar chip, char *buf, int len);
+static int  receive_bytes (uchar chip, char *buf, int len);
+static int  mpc_get_fdr   (int);
+
+static int mpc_reg_in(volatile u32 *reg)
+{
+	int ret = *reg >> 24;
+	__asm__ __volatile__ ("eieio");
+	return ret;
+}
+
+static void mpc_reg_out(volatile u32 *reg, int val, int mask)
+{
+	int tmp;
+
+	if (!mask) {
+		*reg = val << 24;
+	} else {
+		tmp = mpc_reg_in(reg);
+		*reg = ((tmp & ~mask) | (val & mask)) << 24;
+	}
+	__asm__ __volatile__ ("eieio");
+
+	return;
+}
+
+static int wait_for_bb(void)
+{
+	struct mpc5xxx_i2c *regs    = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 timeout = I2C_TIMEOUT;
+	int                 status;
+
+	status = mpc_reg_in(&regs->msr);
+
+	while (timeout-- && (status & I2C_BB)) {
+#if 1
+		volatile int temp;
+		mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+		temp = mpc_reg_in(&regs->mdr);
+		mpc_reg_out(&regs->mcr, 0, I2C_STA);
+		mpc_reg_out(&regs->mcr, 0, 0);
+		mpc_reg_out(&regs->mcr, I2C_EN, 0);
+#endif
+		udelay(15);
+		status = mpc_reg_in(&regs->msr);
+	}
+
+	return (status & I2C_BB);
+}
+
+static int wait_for_pin(int *status)
+{
+	struct mpc5xxx_i2c *regs    = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 timeout = I2C_TIMEOUT;
+
+	*status = mpc_reg_in(&regs->msr);
+
+	while (timeout-- && !(*status & I2C_IF)) {
+		udelay(15);
+		*status = mpc_reg_in(&regs->msr);
+	}
+
+	if (!(*status & I2C_IF)) {
+		return -1;
+	}
+
+	mpc_reg_out(&regs->msr, 0, I2C_IF);
+
+	return 0;
+}
+
+static int do_address(uchar chip, char rdwr_flag)
+{
+	struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 status;
+
+	chip <<= 1;
+
+	if (rdwr_flag) {
+		chip |= 1;
+	}
+
+	mpc_reg_out(&regs->mcr, I2C_TX, I2C_TX);
+	mpc_reg_out(&regs->mdr, chip, 0);
+
+	if (wait_for_pin(&status)) {
+		return -2;
+	}
+
+	if (status & I2C_RXAK) {
+		return -3;
+	}
+
+	return 0;
+}
+
+static int send_bytes(uchar chip, char *buf, int len)
+{
+	struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 wrcount;
+	int                 status;
+
+	for (wrcount = 0; wrcount < len; ++wrcount) {
+
+		mpc_reg_out(&regs->mdr, buf[wrcount], 0);
+
+		if (wait_for_pin(&status)) {
+			break;
+		}
+
+		if (status & I2C_RXAK) {
+			break;
+		}
+
+	}
+
+	return !(wrcount == len);
+}
+
+static int receive_bytes(uchar chip, char *buf, int len)
+{
+	struct mpc5xxx_i2c *regs    = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 dummy   = 1;
+	int                 rdcount = 0;
+	int                 status;
+	int                 i;
+
+	mpc_reg_out(&regs->mcr, 0, I2C_TX);
+
+	for (i = 0; i < len; ++i) {
+		buf[rdcount] = mpc_reg_in(&regs->mdr);
+
+		if (dummy) {
+			dummy = 0;
+		} else {
+			rdcount++;
+		}
+
+
+		if (wait_for_pin(&status)) {
+			return -4;
+		}
+	}
+
+	mpc_reg_out(&regs->mcr, I2C_TXAK, I2C_TXAK);
+	buf[rdcount++] = mpc_reg_in(&regs->mdr);
+
+	if (wait_for_pin(&status)) {
+		return -5;
+	}
+
+	mpc_reg_out(&regs->mcr, 0, I2C_TXAK);
+
+	return 0;
+}
+
+#if defined(CONFIG_SYS_I2C_INIT_MPC5XXX)
+
+#define FDR510(x) (u8) (((x & 0x20) >> 3) | (x & 0x3))
+#define FDR432(x) (u8) ((x & 0x1C) >> 2)
+/*
+ * Reset any i2c devices that may have been interrupted during a system reset.
+ * Normally this would be accomplished by clocking the line until SCL and SDA
+ * are released and then sending a start condtiion (From an Atmel datasheet).
+ * There is no direct access to the i2c pins so instead create start commands
+ * through the i2c interface.  Send a start command then delay for the SDA Hold
+ * time, repeat this by disabling/enabling the bus a total of 9 times.
+ */
+static void send_reset(void)
+{
+	struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+	int i;
+	u32 delay;
+	u8 fdr;
+	int SDA_Tap[] = { 3, 3, 4, 4, 1, 1, 2, 2};
+	struct mpc5xxx_i2c_tap scltap[] = {
+		{4, 1},
+		{4, 2},
+		{6, 4},
+		{6, 8},
+		{14, 16},
+		{30, 32},
+		{62, 64},
+		{126, 128}
+	};
+
+	fdr = (u8)mpc_reg_in(&regs->mfdr);
+
+	delay = scltap[FDR432(fdr)].scl2tap + ((SDA_Tap[FDR510(fdr)] - 1) * \
+		scltap[FDR432(fdr)].tap2tap) + 3;
+
+	for (i = 0; i < 9; i++) {
+		mpc_reg_out(&regs->mcr, I2C_EN|I2C_STA|I2C_TX, I2C_INIT_MASK);
+		udelay(delay);
+		mpc_reg_out(&regs->mcr, 0, I2C_INIT_MASK);
+		udelay(delay);
+	}
+
+	mpc_reg_out(&regs->mcr, I2C_EN, I2C_INIT_MASK);
+}
+#endif /* CONFIG_SYS_I2c_INIT_MPC5XXX */
+
+/**************** I2C API ****************/
+
+void i2c_init(int speed, int saddr)
+{
+	struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+
+	mpc_reg_out(&regs->mcr, 0, 0);
+	mpc_reg_out(&regs->madr, saddr << 1, 0);
+
+	/* Set clock
+	 */
+	mpc_reg_out(&regs->mfdr, mpc_get_fdr(speed), 0);
+
+	/* Enable module
+	 */
+	mpc_reg_out(&regs->mcr, I2C_EN, I2C_INIT_MASK);
+	mpc_reg_out(&regs->msr, 0, I2C_IF);
+
+#if defined(CONFIG_SYS_I2C_INIT_MPC5XXX)
+	send_reset();
+#endif
+	return;
+}
+
+static int mpc_get_fdr(int speed)
+{
+	static int fdr = -1;
+
+	if (fdr == -1) {
+		ulong best_speed = 0;
+		ulong divider;
+		ulong ipb, scl;
+		ulong bestmatch = 0xffffffffUL;
+		int best_i = 0, best_j = 0, i, j;
+		int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8};
+		struct mpc5xxx_i2c_tap scltap[] = {
+			{4, 1},
+			{4, 2},
+			{6, 4},
+			{6, 8},
+			{14, 16},
+			{30, 32},
+			{62, 64},
+			{126, 128}
+		};
+
+		ipb = gd->ipb_clk;
+		for (i = 7; i >= 0; i--) {
+			for (j = 7; j >= 0; j--) {
+				scl = 2 * (scltap[j].scl2tap +
+					(SCL_Tap[i] - 1) * scltap[j].tap2tap + 2);
+				if (ipb <= speed*scl) {
+					if ((speed*scl - ipb) < bestmatch) {
+						bestmatch = speed*scl - ipb;
+						best_i = i;
+						best_j = j;
+						best_speed = ipb/scl;
+					}
+				}
+			}
+		}
+		divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+		if (gd->flags & GD_FLG_RELOC) {
+			fdr = divider;
+		} else {
+			if (gd->have_console)
+				printf("%ld kHz, ", best_speed / 1000);
+			return divider;
+		}
+	}
+
+	return fdr;
+}
+
+int i2c_probe(uchar chip)
+{
+	struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 i;
+
+	for (i = 0; i < I2C_RETRIES; i++) {
+		mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+
+		if (! do_address(chip, 0)) {
+			mpc_reg_out(&regs->mcr, 0, I2C_STA);
+			udelay(500);
+			break;
+		}
+
+		mpc_reg_out(&regs->mcr, 0, I2C_STA);
+		udelay(500);
+	}
+
+	return (i == I2C_RETRIES);
+}
+
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	char                xaddr[4];
+	struct mpc5xxx_i2c * regs        = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                  ret         = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr	& 0xFF;
+
+	if (wait_for_bb()) {
+		if (gd->have_console)
+			printf("i2c_read: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+	if (do_address(chip, 0)) {
+		if (gd->have_console)
+			printf("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes(chip, &xaddr[4-alen], alen)) {
+		if (gd->have_console)
+			printf("i2c_read: send_bytes failed\n");
+		goto Done;
+	}
+
+	mpc_reg_out(&regs->mcr, I2C_RSTA, I2C_RSTA);
+	if (do_address(chip, 1)) {
+		if (gd->have_console)
+			printf("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (receive_bytes(chip, (char *)buf, len)) {
+		if (gd->have_console)
+			printf("i2c_read: receive_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+Done:
+	mpc_reg_out(&regs->mcr, 0, I2C_STA);
+	return ret;
+}
+
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	char               xaddr[4];
+	struct mpc5xxx_i2c *regs        = (struct mpc5xxx_i2c *)I2C_BASE;
+	int                 ret         = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr	& 0xFF;
+
+	if (wait_for_bb()) {
+		if (gd->have_console)
+			printf("i2c_write: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+	if (do_address(chip, 0)) {
+		if (gd->have_console)
+			printf("i2c_write: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes(chip, &xaddr[4-alen], alen)) {
+		if (gd->have_console)
+			printf("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	if (send_bytes(chip, (char *)buf, len)) {
+		if (gd->have_console)
+			printf("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+Done:
+	mpc_reg_out(&regs->mcr, 0, I2C_STA);
+	return ret;
+}
+
+#endif	/* CONFIG_HARD_I2C */
diff --git a/arch/ppc/cpu/mpc5xxx/ide.c b/arch/ppc/cpu/mpc5xxx/ide.c
new file mode 100644
index 0000000..d337abb
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/ide.c
@@ -0,0 +1,99 @@
+/*
+ * (C) Copyright 2004
+ * Pierre AUBERT, Staubli Faverges, <p.aubert@staubli.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
+ *
+ * Init is derived from Linux code.
+ */
+#include <common.h>
+
+#if defined(CONFIG_CMD_IDE)
+#include <mpc5xxx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CALC_TIMING(t) (t + period - 1) / period
+
+#ifdef CONFIG_IDE_RESET
+extern void init_ide_reset (void);
+#endif
+
+int ide_preinit (void)
+{
+	long period, t0, t1, t2_8, t2_16, t4, ta;
+	vu_long reg;
+	struct mpc5xxx_sdma *psdma = (struct mpc5xxx_sdma *) MPC5XXX_SDMA;
+
+	reg = *(vu_long *) MPC5XXX_GPS_PORT_CONFIG;
+#if defined(CONFIG_SYS_ATA_CS_ON_I2C2)
+	/* ATA cs0/1 on i2c2 clk/io */
+	reg = (reg & ~0x03000000ul) | 0x02000000ul;
+#elif defined(CONFIG_SYS_ATA_CS_ON_TIMER01)
+	/* ATA cs0/1 on Timer 0/1 */
+	reg = (reg & ~0x03000000ul) | 0x03000000ul;
+#else
+	/* ATA cs0/1 on Local Plus cs4/5 */
+	reg = (reg & ~0x03000000ul) | 0x01000000ul;
+#endif	/* CONFIG_TOTAL5200 */
+	*(vu_long *) MPC5XXX_GPS_PORT_CONFIG = reg;
+
+	/* All sample codes do that... */
+	*(vu_long *) MPC5XXX_ATA_SHARE_COUNT = 0;
+
+#if defined(CONFIG_UC101)
+	/* Configure and reset host */
+	*(vu_long *) MPC5XXX_ATA_HOST_CONFIG =
+		MPC5xxx_ATA_HOSTCONF_SMR | MPC5xxx_ATA_HOSTCONF_FR;
+	udelay (10);
+	*(vu_long *) MPC5XXX_ATA_HOST_CONFIG = 0;
+#else
+	/* Configure and reset host */
+	*(vu_long *) MPC5XXX_ATA_HOST_CONFIG = MPC5xxx_ATA_HOSTCONF_IORDY |
+		MPC5xxx_ATA_HOSTCONF_SMR | MPC5xxx_ATA_HOSTCONF_FR;
+	udelay (10);
+	*(vu_long *) MPC5XXX_ATA_HOST_CONFIG = MPC5xxx_ATA_HOSTCONF_IORDY;
+#endif
+
+	/* Disable prefetch on Commbus */
+	psdma->PtdCntrl |= 1;
+
+	/* Init timings : we use PIO mode 0 timings */
+	period = 1000000000 / gd->ipb_clk;	/* period in ns */
+
+	t0 = CALC_TIMING (600);
+	t2_8 = CALC_TIMING (290);
+	t2_16 = CALC_TIMING (165);
+	reg = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8);
+	*(vu_long *) MPC5XXX_ATA_PIO1 = reg;
+
+	t4 = CALC_TIMING (30);
+	t1 = CALC_TIMING (70);
+	ta = CALC_TIMING (35);
+	reg = (t4 << 24) | (t1 << 16) | (ta << 8);
+
+	*(vu_long *) MPC5XXX_ATA_PIO2 = reg;
+
+#ifdef CONFIG_IDE_RESET
+	init_ide_reset ();
+#endif /* CONFIG_IDE_RESET */
+
+	return (0);
+}
+#endif
diff --git a/arch/ppc/cpu/mpc5xxx/interrupts.c b/arch/ppc/cpu/mpc5xxx/interrupts.c
new file mode 100644
index 0000000..6035771
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/interrupts.c
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2006
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de
+ *
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* this section was ripped out of arch/ppc/syslib/mpc52xx_pic.c in the
+ * Linux 2.6 source with the following copyright.
+ *
+ * Based on (well, mostly copied from) the code from the 2.4 kernel by
+ * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Montavista Software, Inc
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <command.h>
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	ulong count;
+};
+
+static struct irq_action irq_handlers[NR_IRQS];
+
+static struct mpc5xxx_intr *intr;
+static struct mpc5xxx_sdma *sdma;
+
+static void mpc5xxx_ic_disable(unsigned int irq)
+{
+	u32 val;
+
+	if (irq == MPC5XXX_IRQ0) {
+		val = in_be32(&intr->ctrl);
+		val &= ~(1 << 11);
+		out_be32(&intr->ctrl, val);
+	} else if (irq < MPC5XXX_IRQ1) {
+		BUG();
+	} else if (irq <= MPC5XXX_IRQ3) {
+		val = in_be32(&intr->ctrl);
+		val &= ~(1 << (10 - (irq - MPC5XXX_IRQ1)));
+		out_be32(&intr->ctrl, val);
+	} else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
+		val = in_be32(&intr->main_mask);
+		val |= 1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE));
+		out_be32(&intr->main_mask, val);
+	} else if (irq < MPC5XXX_PERP_IRQ_BASE) {
+		val = in_be32(&sdma->IntMask);
+		val |= 1 << (irq - MPC5XXX_SDMA_IRQ_BASE);
+		out_be32(&sdma->IntMask, val);
+	} else {
+		val = in_be32(&intr->per_mask);
+		val |= 1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE));
+		out_be32(&intr->per_mask, val);
+	}
+}
+
+static void mpc5xxx_ic_enable(unsigned int irq)
+{
+	u32 val;
+
+	if (irq == MPC5XXX_IRQ0) {
+		val = in_be32(&intr->ctrl);
+		val |= 1 << 11;
+		out_be32(&intr->ctrl, val);
+	} else if (irq < MPC5XXX_IRQ1) {
+		BUG();
+	} else if (irq <= MPC5XXX_IRQ3) {
+		val = in_be32(&intr->ctrl);
+		val |= 1 << (10 - (irq - MPC5XXX_IRQ1));
+		out_be32(&intr->ctrl, val);
+	} else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
+		val = in_be32(&intr->main_mask);
+		val &= ~(1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE)));
+		out_be32(&intr->main_mask, val);
+	} else if (irq < MPC5XXX_PERP_IRQ_BASE) {
+		val = in_be32(&sdma->IntMask);
+		val &= ~(1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
+		out_be32(&sdma->IntMask, val);
+	} else {
+		val = in_be32(&intr->per_mask);
+		val &= ~(1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE)));
+		out_be32(&intr->per_mask, val);
+	}
+}
+
+static void mpc5xxx_ic_ack(unsigned int irq)
+{
+	u32 val;
+
+	/*
+	 * Only some irqs are reset here, others in interrupting hardware.
+	 */
+
+	switch (irq) {
+	case MPC5XXX_IRQ0:
+		val = in_be32(&intr->ctrl);
+		val |= 0x08000000;
+		out_be32(&intr->ctrl, val);
+		break;
+	case MPC5XXX_CCS_IRQ:
+		val = in_be32(&intr->enc_status);
+		val |= 0x00000400;
+		out_be32(&intr->enc_status, val);
+		break;
+	case MPC5XXX_IRQ1:
+		val = in_be32(&intr->ctrl);
+		val |= 0x04000000;
+		out_be32(&intr->ctrl, val);
+		break;
+	case MPC5XXX_IRQ2:
+		val = in_be32(&intr->ctrl);
+		val |= 0x02000000;
+		out_be32(&intr->ctrl, val);
+		break;
+	case MPC5XXX_IRQ3:
+		val = in_be32(&intr->ctrl);
+		val |= 0x01000000;
+		out_be32(&intr->ctrl, val);
+		break;
+	default:
+		if (irq >= MPC5XXX_SDMA_IRQ_BASE
+		    && irq < (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM)) {
+			out_be32(&sdma->IntPend,
+				 1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
+		}
+		break;
+	}
+}
+
+static void mpc5xxx_ic_disable_and_ack(unsigned int irq)
+{
+	mpc5xxx_ic_disable(irq);
+	mpc5xxx_ic_ack(irq);
+}
+
+static void mpc5xxx_ic_end(unsigned int irq)
+{
+	mpc5xxx_ic_enable(irq);
+}
+
+void mpc5xxx_init_irq(void)
+{
+	u32 intr_ctrl;
+
+	/* Remap the necessary zones */
+	intr = (struct mpc5xxx_intr *)(MPC5XXX_ICTL);
+	sdma = (struct mpc5xxx_sdma *)(MPC5XXX_SDMA);
+
+	/* Disable all interrupt sources. */
+	out_be32(&sdma->IntPend, 0xffffffff);	/* 1 means clear pending */
+	out_be32(&sdma->IntMask, 0xffffffff);	/* 1 means disabled */
+	out_be32(&intr->per_mask, 0x7ffffc00);	/* 1 means disabled */
+	out_be32(&intr->main_mask, 0x00010fff);	/* 1 means disabled */
+	intr_ctrl = in_be32(&intr->ctrl);
+	intr_ctrl |= 0x0f000000 |	/* clear IRQ 0-3 */
+	    0x00ff0000 |	/* IRQ 0-3 level sensitive low active */
+	    0x00001000 |	/* MEE master external enable */
+	    0x00000000 |	/* 0 means disable IRQ 0-3 */
+	    0x00000001;		/* CEb route critical normally */
+	out_be32(&intr->ctrl, intr_ctrl);
+
+	/* Zero a bunch of the priority settings.  */
+	out_be32(&intr->per_pri1, 0);
+	out_be32(&intr->per_pri2, 0);
+	out_be32(&intr->per_pri3, 0);
+	out_be32(&intr->main_pri1, 0);
+	out_be32(&intr->main_pri2, 0);
+}
+
+int mpc5xxx_get_irq(struct pt_regs *regs)
+{
+	u32 status;
+	int irq = -1;
+
+	status = in_be32(&intr->enc_status);
+
+	if (status & 0x00000400) {	/* critical */
+		irq = (status >> 8) & 0x3;
+		if (irq == 2)	/* high priority peripheral */
+			goto peripheral;
+		irq += MPC5XXX_CRIT_IRQ_BASE;
+	} else if (status & 0x00200000) {	/* main */
+		irq = (status >> 16) & 0x1f;
+		if (irq == 4)	/* low priority peripheral */
+			goto peripheral;
+		irq += MPC5XXX_MAIN_IRQ_BASE;
+	} else if (status & 0x20000000) {	/* peripheral */
+	      peripheral:
+		irq = (status >> 24) & 0x1f;
+		if (irq == 0) {	/* bestcomm */
+			status = in_be32(&sdma->IntPend);
+			irq = ffs(status) + MPC5XXX_SDMA_IRQ_BASE - 1;
+		} else
+			irq += MPC5XXX_PERP_IRQ_BASE;
+	}
+
+	return irq;
+}
+
+/****************************************************************************/
+
+int interrupt_init_cpu(ulong * decrementer_count)
+{
+	*decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+
+	mpc5xxx_init_irq();
+
+	return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+	int irq, unmask = 1;
+
+	irq = mpc5xxx_get_irq(regs);
+
+	mpc5xxx_ic_disable_and_ack(irq);
+
+	enable_interrupts();
+
+	if (irq_handlers[irq].handler != NULL)
+		(*irq_handlers[irq].handler) (irq_handlers[irq].arg);
+	else {
+		printf("\nBogus External Interrupt IRQ %d\n", irq);
+		/*
+		 * turn off the bogus interrupt, otherwise it
+		 * might repeat forever
+		 */
+		unmask = 0;
+	}
+
+	if (unmask)
+		mpc5xxx_ic_end(irq);
+}
+
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg)
+{
+	if (irq < 0 || irq >= NR_IRQS) {
+		printf("irq_install_handler: bad irq number %d\n", irq);
+		return;
+	}
+
+	if (irq_handlers[irq].handler != NULL)
+		printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+		       (ulong) handler, (ulong) irq_handlers[irq].handler);
+
+	irq_handlers[irq].handler = handler;
+	irq_handlers[irq].arg = arg;
+
+	mpc5xxx_ic_enable(irq);
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq < 0 || irq >= NR_IRQS) {
+		printf("irq_free_handler: bad irq number %d\n", irq);
+		return;
+	}
+
+	mpc5xxx_ic_disable(irq);
+
+	irq_handlers[irq].handler = NULL;
+	irq_handlers[irq].arg = NULL;
+}
+
+/****************************************************************************/
+
+#if defined(CONFIG_CMD_IRQ)
+void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+	int irq, re_enable;
+	u32 intr_ctrl;
+	char *irq_config[] = { "level sensitive, active high",
+		"edge sensitive, rising active edge",
+		"edge sensitive, falling active edge",
+		"level sensitive, active low"
+	};
+
+	re_enable = disable_interrupts();
+
+	intr_ctrl = in_be32(&intr->ctrl);
+	printf("Interrupt configuration:\n");
+
+	for (irq = 0; irq <= 3; irq++) {
+		printf("IRQ%d: %s\n", irq,
+		       irq_config[(intr_ctrl >> (22 - 2 * irq)) & 0x3]);
+	}
+
+	puts("\nInterrupt-Information:\n" "Nr  Routine   Arg       Count\n");
+
+	for (irq = 0; irq < NR_IRQS; irq++)
+		if (irq_handlers[irq].handler != NULL)
+			printf("%02d  %08lx  %08lx  %ld\n", irq,
+			       (ulong) irq_handlers[irq].handler,
+			       (ulong) irq_handlers[irq].arg,
+			       irq_handlers[irq].count);
+
+	if (re_enable)
+		enable_interrupts();
+}
+#endif
diff --git a/arch/ppc/cpu/mpc5xxx/io.S b/arch/ppc/cpu/mpc5xxx/io.S
new file mode 100644
index 0000000..2178a26
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/io.S
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2001	Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *			Andreas Heppel <aheppel@sysgo.de>
+ *  Copyright (C) 2003	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
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in8 */
+/*  Description:  Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  in8
+in8:
+	lbz     r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in16 */
+/*  Description:  Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  in16
+in16:
+	lhz     r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in16r */
+/*  Description:  Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+	.globl  in16r
+in16r:
+	lhbrx   r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in32 */
+/*  Description:  Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  in32
+in32:
+	lwz     3,0(3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     in32r */
+/*  Description:  Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+    .globl  in32r
+in32r:
+	lwbrx   r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out8 */
+/*  Description:  Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out8
+out8:
+	stb     r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out16 */
+/*  Description:  Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out16
+out16:
+	sth     r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out16r */
+/*  Description:  Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out16r
+out16r:
+	sthbrx  r4,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out32 */
+/*  Description:  Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out32
+out32:
+	stw     r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:     out32r */
+/*  Description:  Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl  out32r
+out32r:
+	stwbrx  r4,0,r3
+	sync
+	blr
diff --git a/arch/ppc/cpu/mpc5xxx/loadtask.c b/arch/ppc/cpu/mpc5xxx/loadtask.c
new file mode 100644
index 0000000..47e7b59
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/loadtask.c
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+
+/* BestComm/SmartComm microcode */
+extern int taskTable;
+
+void loadtask(int basetask, int tasks)
+{
+	int *sram = (int *)MPC5XXX_SRAM;
+	int *task_org = &taskTable;
+	unsigned int start, offset, end;
+	int i;
+
+#ifdef DEBUG
+	printf("basetask = %d, tasks = %d\n", basetask, tasks);
+	printf("task_org = 0x%08x\n", (unsigned int)task_org);
+#endif
+
+	/* setup TaskBAR register */
+	*(vu_long *)MPC5XXX_SDMA = MPC5XXX_SRAM;
+
+	/* relocate task table entries */
+	offset = (unsigned int)sram;
+	for (i = basetask; i < basetask + tasks; i++) {
+		sram[i * 8 + 0] = task_org[i * 8 + 0] + offset;
+		sram[i * 8 + 1] = task_org[i * 8 + 1] + offset;
+		sram[i * 8 + 2] = task_org[i * 8 + 2] + offset;
+		sram[i * 8 + 3] = task_org[i * 8 + 3] + offset;
+		sram[i * 8 + 4] = task_org[i * 8 + 4];
+		sram[i * 8 + 5] = task_org[i * 8 + 5];
+		sram[i * 8 + 6] = task_org[i * 8 + 6] + offset;
+		sram[i * 8 + 7] = task_org[i * 8 + 7];
+	}
+
+	/* relocate task descriptors */
+	start = (sram[basetask * 8] - (unsigned int)sram);
+	end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int)sram);
+
+#ifdef DEBUG
+	printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end);
+#endif
+
+	start /= 4;
+	end /= 4;
+	for (i = start; i <= end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	/* relocate variables */
+	start = (sram[basetask * 8 + 2] - (unsigned int)sram);
+	end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 - (unsigned int)sram);
+	start /= 4;
+	end /= 4;
+	for (i = start; i < end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	/* relocate function decriptors */
+	start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int)sram);
+	end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 - (unsigned int)sram);
+	start /= 4;
+	end /= 4;
+	for (i = start; i < end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	asm volatile ("sync");
+}
diff --git a/arch/ppc/cpu/mpc5xxx/pci_mpc5200.c b/arch/ppc/cpu/mpc5xxx/pci_mpc5200.c
new file mode 100644
index 0000000..8268f8a
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/pci_mpc5200.c
@@ -0,0 +1,187 @@
+/*
+ * (C) Copyright 2000-2003
+ * 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>
+
+#if defined(CONFIG_PCI)
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <mpc5xxx.h>
+
+/* System RAM mapped over PCI */
+#define CONFIG_PCI_MEMORY_BUS	CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_MEMORY_PHYS	CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_MEMORY_SIZE	(1024 * 1024 * 1024)
+
+/* PCIIWCR bit fields */
+#define IWCR_MEM	(0 << 3)
+#define IWCR_IO		(1 << 3)
+#define IWCR_READ	(0 << 1)
+#define IWCR_READLINE	(1 << 1)
+#define IWCR_READMULT	(2 << 1)
+#define IWCR_EN		(1 << 0)
+
+static int mpc5200_read_config_dword(struct pci_controller *hose,
+			      pci_dev_t dev, int offset, u32* value)
+{
+	*(volatile u32 *)MPC5XXX_PCI_CAR = (1 << 31) | dev | offset;
+	eieio();
+	udelay(10);
+#if (defined CONFIG_PF5200 || defined CONFIG_CPCI5200)
+	if (dev & 0x00ff0000) {
+		u32 val;
+		val  = in_le16((volatile u16 *)(CONFIG_PCI_IO_PHYS+2));
+		udelay(10);
+		val = val << 16;
+		val |= in_le16((volatile u16 *)(CONFIG_PCI_IO_PHYS+0));
+		*value = val;
+	} else {
+		*value = in_le32((volatile u32 *)CONFIG_PCI_IO_PHYS);
+	}
+	udelay(10);
+#else
+	*value = in_le32((volatile u32 *)CONFIG_PCI_IO_PHYS);
+#endif
+	eieio();
+	*(volatile u32 *)MPC5XXX_PCI_CAR = 0;
+	udelay(10);
+	return 0;
+}
+
+static int mpc5200_write_config_dword(struct pci_controller *hose,
+			      pci_dev_t dev, int offset, u32 value)
+{
+	*(volatile u32 *)MPC5XXX_PCI_CAR = (1 << 31) | dev | offset;
+	eieio();
+	udelay(10);
+	out_le32((volatile u32 *)CONFIG_PCI_IO_PHYS, value);
+	eieio();
+	*(volatile u32 *)MPC5XXX_PCI_CAR = 0;
+	udelay(10);
+	return 0;
+}
+
+void pci_mpc5xxx_init (struct pci_controller *hose)
+{
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	/* System space */
+	pci_set_region(hose->regions + 0,
+		       CONFIG_PCI_MEMORY_BUS,
+		       CONFIG_PCI_MEMORY_PHYS,
+		       CONFIG_PCI_MEMORY_SIZE,
+		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+	/* PCI memory space */
+	pci_set_region(hose->regions + 1,
+		       CONFIG_PCI_MEM_BUS,
+		       CONFIG_PCI_MEM_PHYS,
+		       CONFIG_PCI_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	/* PCI IO space */
+	pci_set_region(hose->regions + 2,
+		       CONFIG_PCI_IO_BUS,
+		       CONFIG_PCI_IO_PHYS,
+		       CONFIG_PCI_IO_SIZE,
+		       PCI_REGION_IO);
+
+	hose->region_count = 3;
+
+	pci_register_hose(hose);
+
+	/* GPIO Multiplexing - enable PCI */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~(1 << 15);
+
+	/* Set host bridge as pci master and enable memory decoding */
+	*(vu_long *)MPC5XXX_PCI_CMD |=
+		PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+
+	/* Set maximum latency timer */
+	*(vu_long *)MPC5XXX_PCI_CFG |= (0xf800);
+
+	/* Set cache line size */
+	*(vu_long *)MPC5XXX_PCI_CFG = (*(vu_long *)MPC5XXX_PCI_CFG & ~0xff) |
+		(CONFIG_SYS_CACHELINE_SIZE / 4);
+
+	/* Map MBAR to PCI space */
+	*(vu_long *)MPC5XXX_PCI_BAR0 = CONFIG_SYS_MBAR;
+	*(vu_long *)MPC5XXX_PCI_TBATR0 = CONFIG_SYS_MBAR | 1;
+
+	/* Map RAM to PCI space */
+	*(vu_long *)MPC5XXX_PCI_BAR1 = CONFIG_PCI_MEMORY_BUS | (1 << 3);
+	*(vu_long *)MPC5XXX_PCI_TBATR1 = CONFIG_PCI_MEMORY_PHYS | 1;
+
+	/* Park XLB on PCI */
+	*(vu_long *)(MPC5XXX_XLBARB + 0x40) &= ~((7 << 8) | (3 << 5));
+	*(vu_long *)(MPC5XXX_XLBARB + 0x40) |= (3 << 8) | (3 << 5);
+
+	/* Disable interrupts from PCI controller */
+	*(vu_long *)MPC5XXX_PCI_GSCR &= ~(7 << 12);
+	*(vu_long *)MPC5XXX_PCI_ICR  &= ~(7 << 24);
+
+	/* Set PCI retry counter to 0 = infinite retry. */
+	/* The default of 255 is too short for slow devices. */
+	*(vu_long *)MPC5XXX_PCI_ICR &= 0xFFFFFF00;
+
+	/* Disable initiator windows */
+	*(vu_long *)MPC5XXX_PCI_IWCR = 0;
+
+	/* Map PCI memory to physical space */
+	*(vu_long *)MPC5XXX_PCI_IW0BTAR = CONFIG_PCI_MEM_PHYS |
+		(((CONFIG_PCI_MEM_SIZE - 1) >> 8) & 0x00ff0000) |
+		(CONFIG_PCI_MEM_BUS >> 16);
+	*(vu_long *)MPC5XXX_PCI_IWCR |= (IWCR_MEM | IWCR_READ | IWCR_EN) << 24;
+
+	/* Map PCI I/O to physical space */
+	*(vu_long *)MPC5XXX_PCI_IW1BTAR = CONFIG_PCI_IO_PHYS |
+		(((CONFIG_PCI_IO_SIZE - 1) >> 8) & 0x00ff0000) |
+		(CONFIG_PCI_IO_BUS >> 16);
+	*(vu_long *)MPC5XXX_PCI_IWCR |= (IWCR_IO | IWCR_READ | IWCR_EN) << 16;
+
+	/* Reset the PCI bus */
+	*(vu_long *)MPC5XXX_PCI_GSCR |= 1;
+	udelay(1000);
+	*(vu_long *)MPC5XXX_PCI_GSCR &= ~1;
+	udelay(1000);
+
+	pci_set_ops(hose,
+		pci_hose_read_config_byte_via_dword,
+		pci_hose_read_config_word_via_dword,
+		mpc5200_read_config_dword,
+		pci_hose_write_config_byte_via_dword,
+		pci_hose_write_config_word_via_dword,
+		mpc5200_write_config_dword);
+
+	udelay(1000);
+
+#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 */
diff --git a/arch/ppc/cpu/mpc5xxx/serial.c b/arch/ppc/cpu/mpc5xxx/serial.c
new file mode 100644
index 0000000..6675988
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/serial.c
@@ -0,0 +1,363 @@
+/*
+ * (C) Copyright 2000 - 2003
+ * 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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
+ * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the
+ * Linux/PPC sources (m8260_tty.c had no copyright info in it).
+ *
+ * Martin Krause, 8 Jun 2006
+ * Added CONFIG_SERIAL_MULTI support
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+
+#if defined (CONFIG_SERIAL_MULTI)
+#include <serial.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_PSC_CONSOLE)
+
+#if CONFIG_PSC_CONSOLE == 1
+#define PSC_BASE MPC5XXX_PSC1
+#elif CONFIG_PSC_CONSOLE == 2
+#define PSC_BASE MPC5XXX_PSC2
+#elif CONFIG_PSC_CONSOLE == 3
+#define PSC_BASE MPC5XXX_PSC3
+#elif CONFIG_PSC_CONSOLE == 4
+#define PSC_BASE MPC5XXX_PSC4
+#elif CONFIG_PSC_CONSOLE == 5
+#define PSC_BASE MPC5XXX_PSC5
+#elif CONFIG_PSC_CONSOLE == 6
+#define PSC_BASE MPC5XXX_PSC6
+#else
+#error CONFIG_PSC_CONSOLE must be in 1 ... 6
+#endif
+
+#if defined(CONFIG_SERIAL_MULTI) && !defined(CONFIG_PSC_CONSOLE2)
+#error you must define CONFIG_PSC_CONSOLE2 if CONFIG_SERIAL_MULTI is set
+#endif
+
+#if defined(CONFIG_SERIAL_MULTI)
+#if CONFIG_PSC_CONSOLE2 == 1
+#define PSC_BASE2 MPC5XXX_PSC1
+#elif CONFIG_PSC_CONSOLE2 == 2
+#define PSC_BASE2 MPC5XXX_PSC2
+#elif CONFIG_PSC_CONSOLE2 == 3
+#define PSC_BASE2 MPC5XXX_PSC3
+#elif CONFIG_PSC_CONSOLE2 == 4
+#define PSC_BASE2 MPC5XXX_PSC4
+#elif CONFIG_PSC_CONSOLE2 == 5
+#define PSC_BASE2 MPC5XXX_PSC5
+#elif CONFIG_PSC_CONSOLE2 == 6
+#define PSC_BASE2 MPC5XXX_PSC6
+#else
+#error CONFIG_PSC_CONSOLE2 must be in 1 ... 6
+#endif
+#endif /* CONFIG_SERIAL_MULTI */
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_init_dev (unsigned long dev_base)
+#else
+int serial_init (void)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+	unsigned long baseclk;
+	int div;
+
+	/* reset PSC */
+	psc->command = PSC_SEL_MODE_REG_1;
+
+	/* select clock sources */
+	psc->psc_clock_select = 0;
+	baseclk = (gd->ipb_clk + 16) / 32;
+
+	/* switch to UART mode */
+	psc->sicr = 0;
+
+	/* configure parity, bit length and so on */
+	psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
+	psc->mode = PSC_MODE_ONE_STOP;
+
+	/* set up UART divisor */
+	div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
+	psc->ctur = (div >> 8) & 0xff;
+	psc->ctlr = div & 0xff;
+
+	/* disable all interrupts */
+	psc->psc_imr = 0;
+
+	/* reset and enable Rx/Tx */
+	psc->command = PSC_RST_RX;
+	psc->command = PSC_RST_TX;
+	psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
+
+	return (0);
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_putc_dev (unsigned long dev_base, const char c)
+#else
+void serial_putc(const char c)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+
+	if (c == '\n')
+#if defined(CONFIG_SERIAL_MULTI)
+		serial_putc_dev (dev_base, '\r');
+#else
+		serial_putc('\r');
+#endif
+
+	/* Wait for last character to go. */
+	while (!(psc->psc_status & PSC_SR_TXEMP))
+		;
+
+	psc->psc_buffer_8 = c;
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_putc_raw_dev(unsigned long dev_base, const char c)
+#else
+void serial_putc_raw(const char c)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+	/* Wait for last character to go. */
+	while (!(psc->psc_status & PSC_SR_TXEMP))
+		;
+
+	psc->psc_buffer_8 = c;
+}
+
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_puts_dev (unsigned long dev_base, const char *s)
+#else
+void serial_puts (const char *s)
+#endif
+{
+	while (*s) {
+#if defined(CONFIG_SERIAL_MULTI)
+		serial_putc_dev (dev_base, *s++);
+#else
+		serial_putc (*s++);
+#endif
+	}
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_getc_dev (unsigned long dev_base)
+#else
+int serial_getc(void)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+
+	/* Wait for a character to arrive. */
+	while (!(psc->psc_status & PSC_SR_RXRDY))
+		;
+
+	return psc->psc_buffer_8;
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_tstc_dev (unsigned long dev_base)
+#else
+int serial_tstc(void)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+
+	return (psc->psc_status & PSC_SR_RXRDY);
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_setbrg_dev (unsigned long dev_base)
+#else
+void serial_setbrg(void)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+	unsigned long baseclk, div;
+
+	baseclk = (gd->ipb_clk + 16) / 32;
+
+	/* set up UART divisor */
+	div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
+	psc->ctur = (div >> 8) & 0xFF;
+	psc->ctlr =  div & 0xff;
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+void serial_setrts_dev (unsigned long dev_base, int s)
+#else
+void serial_setrts(int s)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+
+	if (s) {
+		/* Assert RTS (become LOW) */
+		psc->op1 = 0x1;
+	}
+	else {
+		/* Negate RTS (become HIGH) */
+		psc->op0 = 0x1;
+	}
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial_getcts_dev (unsigned long dev_base)
+#else
+int serial_getcts(void)
+#endif
+{
+#if defined(CONFIG_SERIAL_MULTI)
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+#else
+	volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
+#endif
+
+	return (psc->ip & 0x1) ? 0 : 1;
+}
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial0_init(void)
+{
+	return (serial_init_dev(PSC_BASE));
+}
+
+int serial1_init(void)
+{
+	return (serial_init_dev(PSC_BASE2));
+}
+void serial0_setbrg (void)
+{
+	serial_setbrg_dev(PSC_BASE);
+}
+void serial1_setbrg (void)
+{
+	serial_setbrg_dev(PSC_BASE2);
+}
+
+void serial0_putc(const char c)
+{
+	serial_putc_dev(PSC_BASE,c);
+}
+
+void serial1_putc(const char c)
+{
+	serial_putc_dev(PSC_BASE2, c);
+}
+void serial0_puts(const char *s)
+{
+	serial_puts_dev(PSC_BASE, s);
+}
+
+void serial1_puts(const char *s)
+{
+	serial_puts_dev(PSC_BASE2, s);
+}
+
+int serial0_getc(void)
+{
+	return(serial_getc_dev(PSC_BASE));
+}
+
+int serial1_getc(void)
+{
+	return(serial_getc_dev(PSC_BASE2));
+}
+int serial0_tstc(void)
+{
+	return (serial_tstc_dev(PSC_BASE));
+}
+
+int serial1_tstc(void)
+{
+	return (serial_tstc_dev(PSC_BASE2));
+}
+
+struct serial_device serial0_device =
+{
+	"serial0",
+	"UART0",
+	serial0_init,
+	serial0_setbrg,
+	serial0_getc,
+	serial0_tstc,
+	serial0_putc,
+	serial0_puts,
+};
+
+struct serial_device serial1_device =
+{
+	"serial1",
+	"UART1",
+	serial1_init,
+	serial1_setbrg,
+	serial1_getc,
+	serial1_tstc,
+	serial1_putc,
+	serial1_puts,
+};
+#endif /* CONFIG_SERIAL_MULTI */
+
+#endif /* CONFIG_PSC_CONSOLE */
diff --git a/arch/ppc/cpu/mpc5xxx/speed.c b/arch/ppc/cpu/mpc5xxx/speed.c
new file mode 100644
index 0000000..8027d3e
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/speed.c
@@ -0,0 +1,94 @@
+/*
+ * (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 <mpc5xxx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+
+/* Bus-to-Core Multipliers */
+
+static int bus2core[] = {
+	3, 2, 2, 2, 4, 4, 5, 9,
+	6, 11, 8, 10, 3, 12, 7, 0,
+	6, 5, 13, 2, 14, 4, 15, 9,
+	0, 11, 8, 10, 16, 12, 7, 0
+};
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+	ulong val, vco;
+
+#if !defined(CONFIG_SYS_MPC5XXX_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_SYS_MPC5XXX_CLKIN
+#endif
+
+	val = *(vu_long *)MPC5XXX_CDM_PORCFG;
+	if (val & (1 << 6)) {
+		vco = CONFIG_SYS_MPC5XXX_CLKIN * 12;
+	} else {
+		vco = CONFIG_SYS_MPC5XXX_CLKIN * 16;
+	}
+	if (val & (1 << 5)) {
+		gd->bus_clk = vco / 8;
+	} else {
+		gd->bus_clk = vco / 4;
+	}
+	gd->cpu_clk = gd->bus_clk * bus2core[val & 0x1f] / 2;
+
+	val = *(vu_long *)MPC5XXX_CDM_CFG;
+	if (val & (1 << 8)) {
+		gd->ipb_clk = gd->bus_clk / 2;
+	} else {
+		gd->ipb_clk = gd->bus_clk;
+	}
+	switch (val & 3) {
+		case 0: gd->pci_clk = gd->ipb_clk; break;
+		case 1: gd->pci_clk = gd->ipb_clk / 2; break;
+		default: gd->pci_clk = gd->bus_clk / 4; break;
+	}
+
+	return (0);
+}
+
+int prt_mpc5xxx_clks (void)
+{
+	char buf1[32], buf2[32], buf3[32];
+
+	printf ("       Bus %s MHz, IPB %s MHz, PCI %s MHz\n",
+		strmhz(buf1, gd->bus_clk),
+		strmhz(buf2, gd->ipb_clk),
+		strmhz(buf3, gd->pci_clk)
+	);
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/ppc/cpu/mpc5xxx/start.S b/arch/ppc/cpu/mpc5xxx/start.S
new file mode 100644
index 0000000..ba49944
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/start.S
@@ -0,0 +1,777 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000 - 2003 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 MPC5xxx CPUs
+ */
+#include <config.h>
+#include <mpc5xxx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_MPC5xxx 1	/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * Version string
+ */
+	.data
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+/*
+ * Exception vectors
+ */
+	.text
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD	/* Normal Power-On		*/
+	nop
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM	/* Software reboot		*/
+	b	boot_warm
+
+boot_cold:
+boot_warm:
+	mfmsr	r5			/* save msr contents		*/
+
+	/* Move CSBoot and adjust instruction pointer                   */
+	/*--------------------------------------------------------------*/
+
+#if defined(CONFIG_SYS_LOWBOOT)
+# if defined(CONFIG_SYS_RAMBOOT)
+#  error CONFIG_SYS_LOWBOOT is incompatible with CONFIG_SYS_RAMBOOT
+# endif /* CONFIG_SYS_RAMBOOT */
+	lis	r4, CONFIG_SYS_DEFAULT_MBAR@h
+	lis	r3,	START_REG(CONFIG_SYS_BOOTCS_START)@h
+	ori	r3, r3, START_REG(CONFIG_SYS_BOOTCS_START)@l
+	stw	r3, 0x4(r4)		/* CS0 start */
+	lis	r3,	STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@h
+	ori	r3, r3, STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@l
+	stw	r3, 0x8(r4)		/* CS0 stop */
+	lis	r3,     0x02010000@h
+	ori	r3, r3, 0x02010000@l
+	stw	r3, 0x54(r4)		/* CS0 and Boot enable */
+
+	lis     r3,	lowboot_reentry@h	/* jump from bootlow address space (0x0000xxxx) */
+	ori     r3, r3, lowboot_reentry@l	/* to the address space the linker used */
+	mtlr	r3
+	blr
+
+lowboot_reentry:
+	lis	r3,	START_REG(CONFIG_SYS_BOOTCS_START)@h
+	ori	r3, r3, START_REG(CONFIG_SYS_BOOTCS_START)@l
+	stw	r3, 0x4c(r4)		/* Boot start */
+	lis	r3,	STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@h
+	ori	r3, r3, STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@l
+	stw	r3, 0x50(r4)		/* Boot stop */
+	lis	r3,     0x02000001@h
+	ori	r3, r3, 0x02000001@l
+	stw	r3, 0x54(r4)		/* Boot enable, CS0 disable */
+#endif	/* CONFIG_SYS_LOWBOOT */
+
+#if defined(CONFIG_SYS_DEFAULT_MBAR) && !defined(CONFIG_SYS_RAMBOOT)
+	lis	r3, CONFIG_SYS_MBAR@h
+	ori	r3, r3, CONFIG_SYS_MBAR@l
+	/* MBAR is mirrored into the MBAR SPR */
+	mtspr	MBAR,r3
+	rlwinm	r3, r3, 16, 16, 31
+	lis	r4, CONFIG_SYS_DEFAULT_MBAR@h
+	stw	r3, 0(r4)
+#endif /* CONFIG_SYS_DEFAULT_MBAR */
+
+	/* Initialise the MPC5xxx processor core			*/
+	/*--------------------------------------------------------------*/
+
+	bl	init_5xxx_core
+
+	/* initialize some things that are hard to access from C	*/
+	/*--------------------------------------------------------------*/
+
+	/* set up stack in on-chip SRAM */
+	lis	r3, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+	ori	r1, r3, CONFIG_SYS_INIT_SP_OFFSET
+	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 (in Flash)*/
+
+	mr	r3, r21
+	/* r3: BOOTFLAG */
+	bl	board_init_f	/* run 1st part of board init code (in Flash)*/
+
+/*
+ * Vector Table
+ */
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+	. = 0x1300
+	/*
+	 * This exception occurs when the program counter matches the
+	 * Instruction Address Breakpoint Register (IABR).
+	 *
+	 * I want the cpu to halt if this occurs so I can hunt around
+	 * with the debugger and look at things.
+	 *
+	 * When DEBUG is defined, both machine check enable (in the MSR)
+	 * and checkstop reset enable (in the reset mode register) are
+	 * turned off and so a checkstop condition will result in the cpu
+	 * halting.
+	 *
+	 * I force the cpu into a checkstop condition by putting an illegal
+	 * instruction here (at least this is the theory).
+	 *
+	 * well - that didnt work, so just do an infinite loop!
+	 */
+1:	b	1b
+#else
+	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+	STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+	STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+/*
+ * This code initialises the MPC5xxx processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+	.globl	init_5xx_core
+init_5xxx_core:
+
+	/* Initialize machine status; enable machine check interrupt	*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, MSR_KERNEL		/* Set ME and RI flags */
+	rlwimi	r3, r5, 0, 25, 25	/* preserve IP bit set by HRCW */
+#ifdef DEBUG
+	rlwimi	r3, r5, 0, 21, 22	/* debugger might set SE & BE bits */
+#endif
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+	mtspr	SRR1, r3		/* Make SRR1 match MSR */
+
+	/* Initialize the Hardware Implementation-dependent Registers	*/
+	/* HID0 also contains cache control				*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_HID0_INIT@h
+	ori	r3, r3, CONFIG_SYS_HID0_INIT@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID0_FINAL@h
+	ori	r3, r3, CONFIG_SYS_HID0_FINAL@l
+	SYNC
+	mtspr	HID0, r3
+
+	/* clear all BAT's						*/
+	/*--------------------------------------------------------------*/
+
+	li	r0, 0
+	mtspr	DBAT0U, r0
+	mtspr	DBAT0L, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT1L, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT2L, r0
+	mtspr	DBAT3U, r0
+	mtspr	DBAT3L, r0
+	mtspr	DBAT4U, r0
+	mtspr	DBAT4L, r0
+	mtspr	DBAT5U, r0
+	mtspr	DBAT5L, r0
+	mtspr	DBAT6U, r0
+	mtspr	DBAT6L, r0
+	mtspr	DBAT7U, r0
+	mtspr	DBAT7L, r0
+	mtspr	IBAT0U, r0
+	mtspr	IBAT0L, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT1L, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT2L, r0
+	mtspr	IBAT3U, r0
+	mtspr	IBAT3L, r0
+	mtspr	IBAT4U, r0
+	mtspr	IBAT4L, r0
+	mtspr	IBAT5U, r0
+	mtspr	IBAT5L, r0
+	mtspr	IBAT6U, r0
+	mtspr	IBAT6L, r0
+	mtspr	IBAT7U, r0
+	mtspr	IBAT7L, r0
+	SYNC
+
+	/* invalidate all tlb's						*/
+	/*								*/
+	/* From the 603e User Manual: "The 603e provides the ability to	*/
+	/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)	*/
+	/* instruction invalidates the TLB entry indexed by the EA, and	*/
+	/* operates on both the instruction and data TLBs simultaneously*/
+	/* invalidating four TLB entries (both sets in each TLB). The	*/
+	/* index corresponds to bits 15-19 of the EA. To invalidate all	*/
+	/* entries within both TLBs, 32 tlbie instructions should be	*/
+	/* issued, incrementing this field by one each time."		*/
+	/*								*/
+	/* "Note that the tlbia instruction is not implemented on the	*/
+	/* 603e."							*/
+	/*								*/
+	/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000	*/
+	/* incrementing by 0x1000 each time. The code below is sort of	*/
+	/* based on code in "flush_tlbs" from arch/ppc/kernel/head.S	*/
+	/*								*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, 32
+	mtctr	r3
+	li	r3, 0
+1:	tlbie	r3
+	addi	r3, r3, 0x1000
+	bdnz	1b
+	SYNC
+
+	/* Done!							*/
+	/*--------------------------------------------------------------*/
+
+	blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+	.globl	icache_enable
+icache_enable:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_ICE
+	lis	r4, 0
+	ori	r4, r4, HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4	/* sets enable and invalidate, clears lock */
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_ICE|HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_DCE
+	lis	r4, 0
+	ori	r4, r4, HID0_DLOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_DCI
+	sync
+	mtspr	HID0, r4	/* sets enable and invalidate, clears lock */
+	sync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_DCE|HID0_DLOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_DCI
+	sync
+	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */
+	sync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+	blr
+
+	.globl get_svr
+get_svr:
+	mfspr	r3, SVR
+	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	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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
+	mfspr	r7,HID0		/* don't do dcbst if dcache is disabled */
+	rlwinm	r7,r7,HID0_DCE_BITPOS+1,31,31
+	cmpwi	r7,0
+	beq	9f
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+9:	mfspr	r7,HID0		/* don't do icbi if icache is disabled */
+	rlwinm	r7,r7,HID0_ICE_BITPOS+1,31,31
+	cmpwi	r7,0
+	beq	7f
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	mfmsr	r3			/* now that the vectors have	*/
+	lis	r7, MSR_IP@h		/* relocated into low memory	*/
+	ori	r7, r7, MSR_IP@l	/* MSR[IP] can be turned off	*/
+	andc	r3, r3, r7		/* (if it was on)		*/
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+
+	mtlr	r4			/* restore link register    */
+	blr
diff --git a/arch/ppc/cpu/mpc5xxx/traps.c b/arch/ppc/cpu/mpc5xxx/traps.c
new file mode 100644
index 0000000..934a2f2
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/traps.c
@@ -0,0 +1,245 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de)
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM	0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0)
+		{
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7)
+		{
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ",regs);
+	/* refer to 603e Manual (MPC603EUM/AD), chapter 4.5.2.1 */
+	switch( regs->msr & 0x000F0000)
+	{
+	case (0x80000000>>12) :
+		printf("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13) :
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14) :
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000>>15) :
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+  do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc5xxx/u-boot-customlayout.lds b/arch/ppc/cpu/mpc5xxx/u-boot-customlayout.lds
new file mode 100644
index 0000000..81ebde9
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/u-boot-customlayout.lds
@@ -0,0 +1,133 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    /* WARNING - the following is hand-optimized to fit within  */
+    /* the sector layout of our flash chips!    XXX FIXME XXX   */
+
+    arch/ppc/cpu/mpc5xxx/start.o          (.text)
+    arch/ppc/cpu/mpc5xxx/traps.o          (.text)
+    lib/crc32.o         (.text)
+    arch/ppc/lib/cache.o             (.text)
+    arch/ppc/lib/time.o              (.text)
+
+    . = DEFINED(env_offset) ? env_offset : .;
+    common/env_embedded.o        (.ppcenv)
+
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc5xxx/u-boot.lds b/arch/ppc/cpu/mpc5xxx/u-boot.lds
new file mode 100644
index 0000000..64ef481
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/u-boot.lds
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2003-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    arch/ppc/cpu/mpc5xxx/start.o	(.text)
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc5xxx/usb.c b/arch/ppc/cpu/mpc5xxx/usb.c
new file mode 100644
index 0000000..bec7da3
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/usb.c
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2007
+ * Markus Klotzbuecher, DENX Software Engineering <mk@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>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+
+#include <mpc5xxx.h>
+
+int usb_cpu_init(void)
+{
+	/* Set the USB Clock						     */
+	*(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK;
+
+#ifdef CONFIG_PSC3_USB /* USB is using the alternate configuration */
+	/* remove all PSC3 USB bits first before ORing in ours */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00804f00;
+#else
+	/* remove all USB bits first before ORing in ours */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000;
+#endif
+	/* Activate USB port						     */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG;
+
+	return 0;
+}
+
+int usb_cpu_stop(void)
+{
+	return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+	return 0;
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
diff --git a/arch/ppc/cpu/mpc5xxx/usb_ohci.c b/arch/ppc/cpu/mpc5xxx/usb_ohci.c
new file mode 100644
index 0000000..7976e4d
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/usb_ohci.c
@@ -0,0 +1,1646 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the MPC5200.
+ *
+ * (C) Copyright 2003-2004
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * 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
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - this driver is intended for use with USB Mass Storage Devices
+ *     (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#include <mpc5xxx.h>
+
+#define OHCI_USE_NPS		/* force NoPowerSwitching mode */
+#undef OHCI_VERBOSE_DEBUG	/* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define readl(a) (*((volatile u32 *)(a)))
+#define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#define m16_swap(x) swap_16(x)
+#define m32_swap(x) swap_32(x)
+
+#define ohci_cpu_to_le16(x) (x)
+#define ohci_cpu_to_le32(x) (x)
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* urb_priv */
+urb_priv_t urb_priv;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+	u32 temp = readl (&hc->regs->roothub.register); \
+	if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = readl (&hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+	int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+	int		i;
+	int		last;
+	struct td	* td;
+
+	last = urb->length - 1;
+	if (last >= 0) {
+		for (i = 0; i <= last; i++) {
+			td = urb->td[i];
+			if (td) {
+				td->usb_dev = NULL;
+				urb->td[i] = NULL;
+			}
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
+	int transfer_len, struct devrequest * setup, char * str, int small)
+{
+	urb_priv_t * purb = &urb_priv;
+
+	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+			str,
+			sohci_get_current_frame_number (dev),
+			usb_pipedevice (pipe),
+			usb_pipeendpoint (pipe),
+			usb_pipeout (pipe)? 'O': 'I',
+			usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+				(usb_pipecontrol (pipe)? "CTRL": "BULK"),
+			purb->actual_length,
+			transfer_len, dev->status);
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printf (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++)
+				printf (" %02x", ((__u8 *) setup) [i]);
+			printf ("\n");
+		}
+		if (transfer_len > 0 && buffer) {
+			printf (__FILE__ ": data(%d/%d):",
+				purb->actual_length,
+				transfer_len);
+			len = usb_pipeout (pipe)?
+					transfer_len: purb->actual_length;
+			for (i = 0; i < 16 && i < len; i++)
+				printf (" %02x", ((__u8 *) buffer) [i]);
+			printf ("%s\n", i < len? "...": "");
+		}
+	}
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+	int i, j;
+	 __u32 * ed_p;
+	for (i= 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+		while (*ed_p != 0 && j--) {
+			ed_t *ed = (ed_t *)ohci_cpu_to_le32(ed_p);
+			printf (" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printf ("\n");
+	}
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	ed_t *edp = (ed_t *)value;
+
+	if (value) {
+		dbg ("%s %08x", label, value);
+		dbg ("%08x", edp->hwINFO);
+		dbg ("%08x", edp->hwTailP);
+		dbg ("%08x", edp->hwHeadP);
+		dbg ("%08x", edp->hwNextED);
+	}
+}
+
+static char * hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+	__u32			temp, ndp, i;
+
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = roothub_b (controller);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status (controller);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+	dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+	/* dumps some of the state we know about */
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	ohci_dump_roothub (controller, 1);
+}
+
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup, int interval)
+{
+	ohci_t *ohci;
+	ed_t * ed;
+	urb_priv_t *purb_priv;
+	int i, size = 0;
+
+	ohci = &gohci;
+
+	/* when controller's hung, permit only roothub cleanup attempts
+	 * such as powering down ports */
+	if (ohci->disabled) {
+		err("sohci_submit_job: EPIPE");
+		return -1;
+	}
+
+	/* if we have an unfinished URB from previous transaction let's
+	 * fail and scream as quickly as possible so as not to corrupt
+	 * further communication */
+	if (!urb_finished) {
+		err("sohci_submit_job: URB NOT FINISHED");
+		return -1;
+	}
+	/* we're about to begin a new transaction here so mark the URB unfinished */
+	urb_finished = 0;
+
+	/* every endpoint has a ed, locate and fill it */
+	if (!(ed = ep_add_ed (dev, pipe))) {
+		err("sohci_submit_job: ENOMEM");
+		return -1;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_BULK: /* one TD for every 4096 Byte */
+			size = (transfer_len - 1) / 4096 + 1;
+			break;
+		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+			size = (transfer_len == 0)? 2:
+						(transfer_len - 1) / 4096 + 3;
+			break;
+	}
+
+	if (size >= (N_URB_TD - 1)) {
+		err("need %d TDs, only have %d", size, N_URB_TD);
+		return -1;
+	}
+	purb_priv = &urb_priv;
+	purb_priv->pipe = pipe;
+
+	/* fill the private part of the URB */
+	purb_priv->length = size;
+	purb_priv->ed = ed;
+	purb_priv->actual_length = 0;
+
+	/* allocate the TDs */
+	/* note that td[0] was allocated in ep_add_ed */
+	for (i = 0; i < size; i++) {
+		purb_priv->td[i] = td_alloc (dev);
+		if (!purb_priv->td[i]) {
+			purb_priv->length = i;
+			urb_free_priv (purb_priv);
+			err("sohci_submit_job: ENOMEM");
+			return -1;
+		}
+	}
+
+	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_free_priv (purb_priv);
+		err("sohci_submit_job: EINVAL");
+		return -1;
+	}
+
+	/* link the ed into a chain if is not already */
+	if (ed->state != ED_OPER)
+		ep_link (ohci, ed);
+
+	/* fill the TDs and link it to the ed */
+	td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	ohci_t *ohci = &gohci;
+
+	return ohci_cpu_to_le16 (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+
+	ed->state = ED_OPER;
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+		if (ohci->ed_controltail == NULL) {
+			writel (ed, &ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_controltail = edi;
+		break;
+
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+		if (ohci->ed_bulktail == NULL) {
+			writel (ed, &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_bulktail = edi;
+		break;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+
+	ed->hwINFO |= ohci_cpu_to_le32 (OHCI_ED_SKIP);
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless	so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
+{
+	td_t *td;
+	ed_t *ed_ret;
+	volatile ed_t *ed;
+
+	ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+		err("ep_add_ed: pending delete");
+		/* pending delete request */
+		return NULL;
+	}
+
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = ohci_cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+		/* dummy td; end of td list for ed */
+		td = td_alloc (usb_dev);
+		ed->hwTailP = ohci_cpu_to_le32 ((unsigned long)td);
+		ed->hwHeadP = ed->hwTailP;
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+		ohci_dev.ed_cnt++;
+	}
+
+	ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+			| usb_pipeslow (pipe) << 13
+			| usb_maxpacket (usb_dev, pipe) << 16);
+
+	return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+	void *data, int len,
+	struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+	volatile td_t  *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+	int i;
+#endif
+
+	if (index > urb_priv->length) {
+		err("index > length");
+		return;
+	}
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = (td_t *)(ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf);
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+	if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
+		for (i = 0; i < len; i++)
+		printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+		printf("\n");
+	}
+#endif
+	if (!len)
+		data = 0;
+
+	td->hwINFO = ohci_cpu_to_le32 (info);
+	td->hwCBP = ohci_cpu_to_le32 ((unsigned long)data);
+	if (data)
+		td->hwBE = ohci_cpu_to_le32 ((unsigned long)(data + len - 1));
+	else
+		td->hwBE = 0;
+	td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
+
+	/* append to queue */
+	td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+	int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+	ohci_t *ohci = &gohci;
+	int data_len = transfer_len;
+	void *data;
+	int cnt = 0;
+	__u32 info = 0;
+	unsigned int toggle = 0;
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+	if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+		toggle = TD_T_TOGGLE;
+	} else {
+		toggle = TD_T_DATA0;
+		usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+	}
+	urb->td_cnt = 0;
+	if (data_len)
+		data = buffer;
+	else
+		data = 0;
+
+	switch (usb_pipetype (pipe)) {
+	case PIPE_BULK:
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+		while(data_len > 4096) {
+			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+			data += 4096; data_len -= 4096; cnt++;
+		}
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+		td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+		cnt++;
+
+		if (!ohci->sleeping)
+			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+		break;
+
+	case PIPE_CONTROL:
+		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+		if (data_len > 0) {
+			info = usb_pipeout (pipe)?
+				TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+			/* NOTE:  mishandles transfers >8K, some >4K */
+			td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+		}
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+		td_fill (ohci, info, data, 0, dev, cnt++, urb);
+		if (!ohci->sleeping)
+			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+		break;
+	}
+	if (urb->length != cnt)
+		dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+	__u32 tdINFO, tdBE, tdCBP;
+	urb_priv_t *lurb_priv = &urb_priv;
+
+	tdINFO = ohci_cpu_to_le32 (td->hwINFO);
+	tdBE   = ohci_cpu_to_le32 (td->hwBE);
+	tdCBP  = ohci_cpu_to_le32 (td->hwCBP);
+
+
+	if (!(usb_pipecontrol(lurb_priv->pipe) &&
+	    ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+		if (tdBE != 0) {
+			if (td->hwCBP == 0)
+				lurb_priv->actual_length += tdBE - td->data + 1;
+			else
+				lurb_priv->actual_length += tdCBP - td->data;
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+	__u32 td_list_hc;
+	td_t *td_rev = NULL;
+	td_t *td_list = NULL;
+	urb_priv_t *lurb_priv = NULL;
+
+	td_list_hc = ohci_cpu_to_le32 (ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
+
+	while (td_list_hc) {
+		td_list = (td_t *)td_list_hc;
+
+		if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
+			lurb_priv = &urb_priv;
+			dbg(" USB-error/status: %x : %p",
+					TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
+			if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
+				if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+					td_list->ed->hwHeadP =
+						(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
+									(td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
+					lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+				} else
+					td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
+			}
+			td_list->hwNextTD = 0;
+		}
+
+		td_list->next_dl_td = td_rev;
+		td_rev = td_list;
+		td_list_hc = ohci_cpu_to_le32 (td_list->hwNextTD) & 0xfffffff0;
+	}
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+	td_t *td_list_next = NULL;
+	ed_t *ed;
+	int cc = 0;
+	int stat = 0;
+	/* urb_t *urb; */
+	urb_priv_t *lurb_priv;
+	__u32 tdINFO, edHeadP, edTailP;
+
+	while (td_list) {
+		td_list_next = td_list->next_dl_td;
+
+		lurb_priv = &urb_priv;
+		tdINFO = ohci_cpu_to_le32 (td_list->hwINFO);
+
+		ed = td_list->ed;
+
+		dl_transfer_length(td_list);
+
+		/* error code of transfer */
+		cc = TD_CC_GET (tdINFO);
+		if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+			if ((ed->state & (ED_OPER | ED_UNLINK))
+					&& (lurb_priv->state != URB_DEL)) {
+				dbg("ConditionCode %#x", cc);
+				stat = cc_to_error[cc];
+				urb_finished = 1;
+			}
+		}
+
+		if (ed->state != ED_NEW) {
+			edHeadP = ohci_cpu_to_le32 (ed->hwHeadP) & 0xfffffff0;
+			edTailP = ohci_cpu_to_le32 (ed->hwTailP);
+
+			/* unlink eds if they are not busy */
+			if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+				ep_unlink (ohci, ed);
+		}
+
+		td_list = td_list_next;
+	}
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+	0x12,	    /*	__u8  bLength; */
+	0x01,	    /*	__u8  bDescriptorType; Device */
+	0x10,	    /*	__u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*	__u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  bDeviceSubClass; */
+	0x00,	    /*	__u8  bDeviceProtocol; */
+	0x08,	    /*	__u8  bMaxPacketSize0; 8 Bytes */
+	0x00,	    /*	__u16 idVendor; */
+	0x00,
+	0x00,	    /*	__u16 idProduct; */
+	0x00,
+	0x00,	    /*	__u16 bcdDevice; */
+	0x00,
+	0x00,	    /*	__u8  iManufacturer; */
+	0x01,	    /*	__u8  iProduct; */
+	0x00,	    /*	__u8  iSerialNumber; */
+	0x01	    /*	__u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,	    /*	__u8  bLength; */
+	0x02,	    /*	__u8  bDescriptorType; Configuration */
+	0x19,	    /*	__u16 wTotalLength; */
+	0x00,
+	0x01,	    /*	__u8  bNumInterfaces; */
+	0x01,	    /*	__u8  bConfigurationValue; */
+	0x00,	    /*	__u8  iConfiguration; */
+	0x40,	    /*	__u8  bmAttributes;
+		 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,	    /*	__u8  MaxPower; */
+
+	/* interface */
+	0x09,	    /*	__u8  if_bLength; */
+	0x04,	    /*	__u8  if_bDescriptorType; Interface */
+	0x00,	    /*	__u8  if_bInterfaceNumber; */
+	0x00,	    /*	__u8  if_bAlternateSetting; */
+	0x01,	    /*	__u8  if_bNumEndpoints; */
+	0x09,	    /*	__u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  if_bInterfaceSubClass; */
+	0x00,	    /*	__u8  if_bInterfaceProtocol; */
+	0x00,	    /*	__u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,	    /*	__u8  ep_bLength; */
+	0x05,	    /*	__u8  ep_bDescriptorType; Endpoint */
+	0x81,	    /*	__u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,	    /*	__u8  ep_bmAttributes; Interrupt */
+	0x02,	    /*	__u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff	    /*	__u8  ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+	0x04,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	0x09,			/*  __u8  lang ID */
+	0x04,			/*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+	28,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	'O',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'C',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'I',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'R',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	't',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'u',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'b',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x)			len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x)		{info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x)	{info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x)		writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x)	writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT		roothub_status(&gohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+	__u32 temp, ndp, i;
+	int res;
+
+	res = -1;
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		/* check for a device disconnect */
+		if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+			(RH_PS_PESC | RH_PS_CSC)) &&
+			((temp & RH_PS_CCS) == 0)) {
+			res = i;
+			break;
+		}
+	}
+	return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+		void *buffer, int transfer_len, struct devrequest *cmd)
+{
+	void * data = buffer;
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *)datab;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+#ifdef DEBUG
+urb_priv.actual_length = 0;
+pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#endif
+	if (usb_pipeint(pipe)) {
+		info("Root-Hub submit IRQ: NOT implemented");
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+	wValue	      = m16_swap (cmd->value);
+	wIndex	      = m16_swap (cmd->index);
+	wLength	      = m16_swap (cmd->length);
+
+	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device,
+	   RH_INTERFACE: interface,
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here,
+	   RH_OTHER | RH_CLASS	almost ever means HUB_PORT here
+	*/
+
+	case RH_GET_STATUS:
+			*(__u16 *) data_buf = m16_swap (1); OK (2);
+	case RH_GET_STATUS | RH_INTERFACE:
+			*(__u16 *) data_buf = m16_swap (0); OK (2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+			*(__u16 *) data_buf = m16_swap (0); OK (2);
+	case RH_GET_STATUS | RH_CLASS:
+			*(__u32 *) data_buf = m32_swap (
+				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+			OK (4);
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+			*(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+			case (RH_ENDPOINT_STALL): OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+			case RH_C_HUB_LOCAL_POWER:
+				OK(0);
+			case (RH_C_HUB_OVER_CURRENT):
+					WR_RH_STAT(RH_HS_OCIC); OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+			case (RH_PORT_ENABLE):
+					WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+			case (RH_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+			case (RH_PORT_POWER):
+					WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+			case (RH_C_PORT_CONNECTION):
+					WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+			case (RH_C_PORT_ENABLE):
+					WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+			case (RH_C_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+			case (RH_C_PORT_OVER_CURRENT):
+					WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+			case (RH_C_PORT_RESET):
+					WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+			case (RH_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+			case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+					if (RD_RH_PORTSTAT & RH_PS_CCS)
+					    WR_RH_PORTSTAT (RH_PS_PRS);
+					OK (0);
+			case (RH_PORT_POWER):
+					WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
+			case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+					if (RD_RH_PORTSTAT & RH_PS_CCS)
+					    WR_RH_PORTSTAT (RH_PS_PES );
+					OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+			case (0x01): /* device descriptor */
+				len = min_t(unsigned int,
+					  leni,
+					  min_t(unsigned int,
+					      sizeof (root_hub_dev_des),
+					      wLength));
+				data_buf = root_hub_dev_des; OK(len);
+			case (0x02): /* configuration descriptor */
+				len = min_t(unsigned int,
+					  leni,
+					  min_t(unsigned int,
+					      sizeof (root_hub_config_des),
+					      wLength));
+				data_buf = root_hub_config_des; OK(len);
+			case (0x03): /* string descriptors */
+				if(wValue==0x0300) {
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_str_index0),
+						      wLength));
+					data_buf = root_hub_str_index0;
+					OK(len);
+				}
+				if(wValue==0x0301) {
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_str_index1),
+						      wLength));
+					data_buf = root_hub_str_index1;
+					OK(len);
+			}
+			default:
+				stat = USB_ST_STALLED;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+	    {
+		    __u32 temp = roothub_a (&gohci);
+
+		    data_buf [0] = 9;		/* min length; */
+		    data_buf [1] = 0x29;
+		    data_buf [2] = temp & RH_A_NDP;
+		    data_buf [3] = 0;
+		    if (temp & RH_A_PSM)	/* per-port power switching? */
+			data_buf [3] |= 0x1;
+		    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+			data_buf [3] |= 0x10;
+		    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+			data_buf [3] |= 0x8;
+
+		    /* corresponds to data_buf[4-7] */
+		    datab [1] = 0;
+		    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+		    temp = roothub_b (&gohci);
+		    data_buf [7] = temp & RH_B_DR;
+		    if (data_buf [2] < 7) {
+			data_buf [8] = 0xff;
+		    } else {
+			data_buf [0] += 2;
+			data_buf [8] = (temp & RH_B_DR) >> 8;
+			data_buf [10] = data_buf [9] = 0xff;
+		    }
+
+		    len = min_t(unsigned int, leni,
+			      min_t(unsigned int, data_buf [0], wLength));
+		    OK (len);
+		}
+
+	case RH_GET_CONFIGURATION:	*(__u8 *) data_buf = 0x01; OK (1);
+
+	case RH_SET_CONFIGURATION:	WR_RH_STAT (0x10000); OK (0);
+
+	default:
+		dbg ("unsupported root hub command");
+		stat = USB_ST_STALLED;
+	}
+
+#ifdef	DEBUG
+	ohci_dump_roothub (&gohci, 1);
+#endif
+
+	len = min_t(int, len, leni);
+	if (data != data_buf)
+	    memcpy (data, data_buf, len);
+	dev->act_len = len;
+	dev->status = stat;
+
+#ifdef DEBUG
+	if (transfer_len)
+		urb_priv.actual_length = transfer_len;
+	pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#endif
+
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup, int interval)
+{
+	int stat = 0;
+	int maxsize = usb_maxpacket(dev, pipe);
+	int timeout;
+
+	/* device pulled? Shortcut the action. */
+	if (devgone == dev) {
+		dev->status = USB_ST_CRC_ERR;
+		return 0;
+	}
+
+#ifdef DEBUG
+	urb_priv.actual_length = 0;
+	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+	if (!maxsize) {
+		err("submit_common_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+
+	if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
+		err("sohci_submit_job failed");
+		return -1;
+	}
+
+	/* allow more time for a BULK device to react - some are slow */
+#define BULK_TO	 5000	/* timeout in milliseconds */
+	if (usb_pipebulk(pipe))
+		timeout = BULK_TO;
+	else
+		timeout = 100;
+
+	/* wait for it to complete */
+	for (;;) {
+		/* check whether the controller is done */
+		stat = hc_interrupt();
+		if (stat < 0) {
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+
+		/* NOTE: since we are not interrupt driven in U-Boot and always
+		 * handle only one URB at a time, we cannot assume the
+		 * transaction finished on the first successful return from
+		 * hc_interrupt().. unless the flag for current URB is set,
+		 * meaning that all TD's to/from device got actually
+		 * transferred and processed. If the current URB is not
+		 * finished we need to re-iterate this loop so as
+		 * hc_interrupt() gets called again as there needs to be some
+		 * more TD's to process still */
+		if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
+			/* 0xff is returned for an SF-interrupt */
+			break;
+		}
+
+		if (--timeout) {
+			wait_ms(1);
+			if (!urb_finished)
+				dbg("\%");
+
+		} else {
+			err("CTL:TIMEOUT ");
+			dbg("submit_common_msg: TO status %x\n", stat);
+			stat = USB_ST_CRC_ERR;
+			urb_finished = 1;
+			break;
+		}
+	}
+#if 0
+	/* we got an Root Hub Status Change interrupt */
+	if (got_rhsc) {
+#ifdef DEBUG
+		ohci_dump_roothub (&gohci, 1);
+#endif
+		got_rhsc = 0;
+		/* abuse timeout */
+		timeout = rh_check_port_status(&gohci);
+		if (timeout >= 0) {
+#if 0 /* this does nothing useful, but leave it here in case that changes */
+			/* the called routine adds 1 to the passed value */
+			usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
+#endif
+			/*
+			 * XXX
+			 * This is potentially dangerous because it assumes
+			 * that only one device is ever plugged in!
+			 */
+			devgone = dev;
+		}
+	}
+#endif
+
+	dev->status = stat;
+	dev->act_len = transfer_len;
+
+#ifdef DEBUG
+	pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#endif
+
+	/* free TDs in urb_priv */
+	urb_free_priv (&urb_priv);
+	return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len)
+{
+	info("submit_bulk_msg");
+	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup)
+{
+	int maxsize = usb_maxpacket(dev, pipe);
+
+	info("submit_control_msg");
+#ifdef DEBUG
+	urb_priv.actual_length = 0;
+	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+	if (!maxsize) {
+		err("submit_control_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+	if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+		gohci.rh.dev = dev;
+		/* root hub - redirect */
+		return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+			setup);
+	}
+
+	return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, int interval)
+{
+	info("submit_int_msg");
+	return -1;
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+		info("USB HC TakeOver from SMM");
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+			wait_ms (10);
+			if (--smm_timeout == 0) {
+				err("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}
+
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+		ohci->slot_name,
+		readl (&ohci->regs->control));
+
+	/* Reset USB (needed by some controllers) */
+	ohci->hc_control = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
+
+	/* HC Reset requires max 10 us delay */
+	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err("USB HC reset timed out!");
+			return -1;
+		}
+		udelay (1);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+	__u32 mask;
+	unsigned int fminterval;
+
+	ohci->disabled = 1;
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+
+	writel (0, &ohci->regs->ed_controlhead);
+	writel (0, &ohci->regs->ed_bulkhead);
+
+	writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+	fminterval = 0x2edf;
+	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+	writel (fminterval, &ohci->regs->fminterval);
+	writel (0x628, &ohci->regs->lsthresh);
+
+	/* start controller operations */
+	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ohci->disabled = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
+
+	/* disable all interrupts */
+	mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+			OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+			OHCI_INTR_OC | OHCI_INTR_MIE);
+	writel (mask, &ohci->regs->intrdisable);
+	/* clear all interrupts */
+	mask &= ~OHCI_INTR_MIE;
+	writel (mask, &ohci->regs->intrstatus);
+	/* Choose the interrupts we care about now  - but w/o MIE */
+	mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	writel (mask, &ohci->regs->intrenable);
+
+#ifdef	OHCI_USE_NPS
+	/* required for AMD-756 and some Mac platforms */
+	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+		&ohci->regs->roothub.a);
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif	/* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+	/* POTPGT delay is bits 24-31, in 2 ms units. */
+	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+	/* connect the virtual root hub */
+	ohci->rh.devnum = 0;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int
+hc_interrupt (void)
+{
+	ohci_t *ohci = &gohci;
+	struct ohci_regs *regs = ohci->regs;
+	int ints;
+	int stat = -1;
+
+	if ((ohci->hcca->done_head != 0) &&
+	     !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+		ints =  OHCI_INTR_WDH;
+
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->slot_name);
+		return -1;
+
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+		dbg("hc_interrupt: returning..\n");
+		return 0xff;
+	}
+
+	/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+	if (ints & OHCI_INTR_RHSC) {
+		got_rhsc = 1;
+		stat = 0xff;
+	}
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+			ohci->slot_name);
+		/* e.g. due to PCI Master/Target Abort */
+
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#endif
+		/* FIXME: be optimistic, hope that bug won't repeat often. */
+		/* Make some non-interrupt context restart the controller. */
+		/* Count and limit the retries though; either hardware or */
+		/* software errors can go forever... */
+		hc_reset (ohci);
+		return -1;
+	}
+
+	if (ints & OHCI_INTR_WDH) {
+		writel (OHCI_INTR_WDH, &regs->intrdisable);
+		stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+		writel (OHCI_INTR_WDH, &regs->intrenable);
+	}
+
+	if (ints & OHCI_INTR_SO) {
+		dbg("USB Schedule overrun\n");
+		writel (OHCI_INTR_SO, &regs->intrenable);
+		stat = -1;
+	}
+
+	/* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
+	if (ints & OHCI_INTR_SF) {
+		unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
+		wait_ms(1);
+		writel (OHCI_INTR_SF, &regs->intrdisable);
+		if (ohci->ed_rm_list[frame] != NULL)
+			writel (OHCI_INTR_SF, &regs->intrenable);
+		stat = 0xff;
+	}
+
+	writel (ints, &regs->intrstatus);
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+	dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+	if (!ohci->disabled)
+		hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+
+	/* Set the USB Clock						     */
+	*(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK;
+
+#ifdef CONFIG_PSC3_USB /* USB is using the alternate configuration */
+	/* remove all PSC3 USB bits first before ORing in ours */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00804f00;
+#else
+	/* remove all USB bits first before ORing in ours */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000;
+#endif
+	/* Activate USB port						     */
+	*(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG;
+
+	memset (&gohci, 0, sizeof (ohci_t));
+	memset (&urb_priv, 0, sizeof (urb_priv_t));
+
+	/* align the storage */
+	if ((__u32)&ghcca[0] & 0xff) {
+		err("HCCA not aligned!!");
+		return -1;
+	}
+	phcca = &ghcca[0];
+	info("aligned ghcca %p", phcca);
+	memset(&ohci_dev, 0, sizeof(struct ohci_device));
+	if ((__u32)&ohci_dev.ed[0] & 0x7) {
+		err("EDs not aligned!!");
+		return -1;
+	}
+	memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+	if ((__u32)gtd & 0x7) {
+		err("TDs not aligned!!");
+		return -1;
+	}
+	ptd = gtd;
+	gohci.hcca = phcca;
+	memset (phcca, 0, sizeof (struct ohci_hcca));
+
+	gohci.disabled = 1;
+	gohci.sleeping = 0;
+	gohci.irq = -1;
+	gohci.regs = (struct ohci_regs *)MPC5XXX_USB;
+
+	gohci.flags = 0;
+	gohci.slot_name = "mpc5200";
+
+	if (hc_reset (&gohci) < 0) {
+		hc_release_ohci (&gohci);
+		return -1;
+	}
+
+	if (hc_start (&gohci) < 0) {
+		err ("can't start usb-%s", gohci.slot_name);
+		hc_release_ohci (&gohci);
+		return -1;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (&gohci, 1);
+#endif
+	ohci_inited = 1;
+	urb_finished = 1;
+
+	return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+	/* this gets called really early - before the controller has */
+	/* even been initialized! */
+	if (!ohci_inited)
+		return 0;
+	/* TODO release any interrupts, etc. */
+	/* call hc_release_ohci() here ? */
+	hc_reset (&gohci);
+	return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
diff --git a/arch/ppc/cpu/mpc5xxx/usb_ohci.h b/arch/ppc/cpu/mpc5xxx/usb_ohci.h
new file mode 100644
index 0000000..629b529
--- /dev/null
+++ b/arch/ppc/cpu/mpc5xxx/usb_ohci.h
@@ -0,0 +1,418 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+	/* No  Error  */	       0,
+	/* CRC Error  */	       USB_ST_CRC_ERR,
+	/* Bit Stuff  */	       USB_ST_BIT_ERR,
+	/* Data Togg  */	       USB_ST_CRC_ERR,
+	/* Stall      */	       USB_ST_STALLED,
+	/* DevNotResp */	       -1,
+	/* PIDCheck   */	       USB_ST_BIT_ERR,
+	/* UnExpPID   */	       USB_ST_BIT_ERR,
+	/* DataOver   */	       USB_ST_BUF_ERR,
+	/* DataUnder  */	       USB_ST_BUF_ERR,
+	/* reservd    */	       -1,
+	/* reservd    */	       -1,
+	/* BufferOver */	       USB_ST_BUF_ERR,
+	/* BuffUnder  */	       USB_ST_BUF_ERR,
+	/* Not Access */	       -1,
+	/* Not Access */	       -1
+};
+
+/* ED States */
+
+#define ED_NEW		0x00
+#define ED_UNLINK	0x01
+#define ED_OPER		0x02
+#define ED_DEL		0x04
+#define ED_URB_DEL	0x08
+
+/* usb_ohci_ed */
+struct ed {
+	__u32 hwINFO;
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed *ed_prev;
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load;
+	__u8 int_interval;
+	__u8 state;
+	__u8 type;
+	__u16 last_iso;
+	struct ed *ed_rm_list;
+
+	struct usb_device *usb_dev;
+	__u32 unused[3];
+} __attribute__((aligned(16)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC	    0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC	    0x0C000000
+#define TD_T	    0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R	    0x00040000
+#define TD_DI	    0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP	    0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO	    0x00010000
+#define TD_DEL	    0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR	   0x00
+#define TD_CC_CRC	   0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL	   0x04
+#define TD_DEVNOTRESP	   0x05
+#define TD_PIDCHECKFAIL	   0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN	   0x08
+#define TD_DATAUNDERRUN	   0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED	   0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+	__u32 hwINFO;
+	__u32 hwCBP;		/* Current Buffer Pointer */
+	__u32 hwNextTD;		/* Next TD Pointer */
+	__u32 hwBE;		/* Memory Buffer End Pointer */
+
+	__u8 unused;
+	__u8 index;
+	struct ed *ed;
+	struct td *next_dl_td;
+	struct usb_device *usb_dev;
+	int transfer_len;
+	__u32 data;
+
+	__u32 unused2[2];
+} __attribute__((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u16	frame_no;		/* current frame number */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute__((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.	You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute__((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF	(1 << 1)	/* control list filled */
+#define OHCI_BLF	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR	(1 << 3)	/* ownership change request */
+#define OHCI_SOC	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int devnum; /* Address of Root Hub endpoint */
+	void *dev;  /* was urb */
+	void *int_addr;
+	int send;
+	int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE		   0x01
+#define RH_ENDPOINT		   0x02
+#define RH_OTHER		   0x03
+
+#define RH_CLASS		   0x20
+#define RH_VENDOR		   0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	   0x00
+#define RH_PORT_ENABLE		   0x01
+#define RH_PORT_SUSPEND		   0x02
+#define RH_PORT_OVER_CURRENT	   0x03
+#define RH_PORT_RESET		   0x04
+#define RH_PORT_POWER		   0x08
+#define RH_PORT_LOW_SPEED	   0x09
+
+#define RH_C_PORT_CONNECTION	   0x10
+#define RH_C_PORT_ENABLE	   0x11
+#define RH_C_PORT_SUSPEND	   0x12
+#define RH_C_PORT_OVER_CURRENT	   0x13
+#define RH_C_PORT_RESET		   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	   0x00
+#define RH_C_HUB_OVER_CURRENT	   0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	   0x00
+#define RH_ENDPOINT_STALL	   0x01
+
+#define RH_ACK			   0x01
+#define RH_REQ_ERR		   -1
+#define RH_NACK			   0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS	     0x00000001		/* current connect status */
+#define RH_PS_PES	     0x00000002		/* port enable status*/
+#define RH_PS_PSS	     0x00000004		/* port suspend status */
+#define RH_PS_POCI	     0x00000008		/* port over current indicator */
+#define RH_PS_PRS	     0x00000010		/* port reset status */
+#define RH_PS_PPS	     0x00000100		/* port power status */
+#define RH_PS_LSDA	     0x00000200		/* low speed device attached */
+#define RH_PS_CSC	     0x00010000		/* connect status change */
+#define RH_PS_PESC	     0x00020000		/* port enable status change */
+#define RH_PS_PSSC	     0x00040000		/* port suspend status change */
+#define RH_PS_OCIC	     0x00080000		/* over current indicator change */
+#define RH_PS_PRSC	     0x00100000		/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001		/* local power status */
+#define RH_HS_OCI	     0x00000002		/* over current indicator */
+#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000		/* local power status change */
+#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff		/* device removable flags */
+#define RH_B_PPCM	0xffff0000		/* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)		/* number of downstream ports */
+#define RH_A_PSM	(1 << 8)		/* power switching mode */
+#define RH_A_NPS	(1 << 9)		/* no power switching */
+#define RH_A_DT		(1 << 10)		/* device type (mbz) */
+#define RH_A_OCPM	(1 << 11)		/* over current protection mode */
+#define RH_A_NOCP	(1 << 12)		/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+	ed_t *ed;
+	__u16 length;	/* number of tds associated with this request */
+	__u16 td_cnt;	/* number of tds already serviced */
+	int   state;
+	unsigned long pipe;
+	int actual_length;
+	td_t *td[N_URB_TD];	/* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+	struct ohci_hcca *hcca;		/* hcca */
+	/*dma_addr_t hcca_dma;*/
+
+	int irq;
+	int disabled;			/* e.g. got a UE, we're hung */
+	int sleeping;
+	unsigned long flags;		/* for HC bugs */
+
+	struct ohci_regs *regs; /* OHCI controller's memory */
+
+	ed_t *ed_rm_list[2];	 /* lists of all endpoints to be removed */
+	ed_t *ed_bulktail;	 /* last endpoint of bulk list */
+	ed_t *ed_controltail;	 /* last endpoint of control list */
+	int intrstatus;
+	__u32 hc_control;		/* copy of the hc control reg */
+	struct usb_device *dev[32];
+	struct virt_root_hub rh;
+
+	const char	*slot_name;
+} ohci_t;
+
+#define NUM_EDS 8		/* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+	ed_t	ed[NUM_EDS];
+	int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD+1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct usb_device *usb_dev)
+{
+	int i;
+	struct td	*td;
+
+	td = NULL;
+	for (i = 0; i < NUM_TD; i++)
+	{
+		if (ptd[i].usb_dev == NULL)
+		{
+			td = &ptd[i];
+			td->usb_dev = usb_dev;
+			break;
+		}
+	}
+
+	return td;
+}
+
+static inline void
+ed_free (struct ed *ed)
+{
+	ed->usb_dev = NULL;
+}
diff --git a/arch/ppc/cpu/mpc8220/Makefile b/arch/ppc/cpu/mpc8220/Makefile
new file mode 100644
index 0000000..b4fad28
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2003-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+SOBJS	= io.o fec_dma_tasks.o
+COBJS	= cpu.o cpu_init.o dramSetup.o fec.o i2c.o \
+	  interrupts.o loadtask.o speed.o \
+	  traps.o uart.o pci.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc8220/config.mk b/arch/ppc/cpu/mpc8220/config.mk
new file mode 100644
index 0000000..e2ebf38
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/config.mk
@@ -0,0 +1,30 @@
+#
+# (C) Copyright 2003
+# 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
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC8220 -ffixed-r2 \
+		     -mstring -mcpu=603e -mmultiple
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc8220/u-boot.lds
diff --git a/arch/ppc/cpu/mpc8220/cpu.c b/arch/ppc/cpu/mpc8220/cpu.c
new file mode 100644
index 0000000..563cfe0
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/cpu.c
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2000-2003
+ * 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
+ */
+
+/*
+ * CPU specific code for the MPC8220 CPUs
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8220.h>
+#include <netdev.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+
+	puts ("CPU:   ");
+
+	printf (CPU_ID_STR);
+
+	printf (" (JTAG ID %08lx)", *(vu_long *) (CONFIG_SYS_MBAR + 0x50));
+
+	printf (" at %s MHz\n", strmhz (buf, clock));
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	volatile gptmr8220_t *gptmr = (volatile gptmr8220_t *) MMAP_GPTMR;
+	ulong msr;
+
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/* Charge the watchdog timer */
+	gptmr->Prescl = 10;
+	gptmr->Count = 1;
+
+	gptmr->Mode = GPT_TMS_SGPIO;
+
+	gptmr->Control = GPT_CTRL_WDEN | GPT_CTRL_CE;
+
+	return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+	ulong tbclk;
+
+	tbclk = (gd->bus_clk + 3L) / 4L;
+
+	return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_MPC8220_FEC)
+	mpc8220_fec_initialize(bis);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8220/cpu_init.c b/arch/ppc/cpu/mpc8220/cpu_init.c
new file mode 100644
index 0000000..8f52c7d
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/cpu_init.c
@@ -0,0 +1,136 @@
+/*
+ * (C) Copyright 2000-2003
+ * 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 <mpc8220.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers.
+ */
+void cpu_init_f (void)
+{
+	volatile flexbus8220_t *flexbus = (volatile flexbus8220_t *) MMAP_FB;
+	volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG;
+	volatile xlbarb8220_t *xlbarb = (volatile xlbarb8220_t *) MMAP_XLBARB;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	memset ((void *) gd, 0, sizeof (gd_t));
+
+	/* Clear all port configuration */
+	portcfg->pcfg0 = 0;
+	portcfg->pcfg1 = 0;
+	portcfg->pcfg2 = 0;
+	portcfg->pcfg3 = 0;
+	portcfg->pcfg2 = CONFIG_SYS_GP1_PORT2_CONFIG;
+	portcfg->pcfg3 = CONFIG_SYS_PCI_PORT3_CONFIG | CONFIG_SYS_GP2_PORT3_CONFIG;
+
+	/*
+	 * Flexbus Controller: configure chip selects and enable them
+	 */
+#if defined (CONFIG_SYS_CS0_BASE)
+	flexbus->csar0 = CONFIG_SYS_CS0_BASE;
+
+/* Sorcery-C can hang-up after CTRL reg initialization */
+#if defined (CONFIG_SYS_CS0_CTRL)
+	flexbus->cscr0 = CONFIG_SYS_CS0_CTRL;
+#endif
+	flexbus->csmr0 = ((CONFIG_SYS_CS0_MASK - 1) & 0xffff0000) | 1;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS1_BASE)
+	flexbus->csar1 = CONFIG_SYS_CS1_BASE;
+	flexbus->cscr1 = CONFIG_SYS_CS1_CTRL;
+	flexbus->csmr1 = ((CONFIG_SYS_CS1_MASK - 1) & 0xffff0000) | 1;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS2_BASE)
+	flexbus->csar2 = CONFIG_SYS_CS2_BASE;
+	flexbus->cscr2 = CONFIG_SYS_CS2_CTRL;
+	flexbus->csmr2 = ((CONFIG_SYS_CS2_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CONFIG_SYS_CS2_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS3_BASE)
+	flexbus->csar3 = CONFIG_SYS_CS3_BASE;
+	flexbus->cscr3 = CONFIG_SYS_CS3_CTRL;
+	flexbus->csmr3 = ((CONFIG_SYS_CS3_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CONFIG_SYS_CS3_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS4_BASE)
+	flexbus->csar4 = CONFIG_SYS_CS4_BASE;
+	flexbus->cscr4 = CONFIG_SYS_CS4_CTRL;
+	flexbus->csmr4 = ((CONFIG_SYS_CS4_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CONFIG_SYS_CS4_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS5_BASE)
+	flexbus->csar5 = CONFIG_SYS_CS5_BASE;
+	flexbus->cscr5 = CONFIG_SYS_CS5_CTRL;
+	flexbus->csmr5 = ((CONFIG_SYS_CS5_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CONFIG_SYS_CS5_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+
+	/* This section of the code cannot place in cpu_init_r(),
+	   it will cause the system to hang */
+	/* enable timebase */
+	xlbarb->addrTenTimeOut = 0x1000;
+	xlbarb->dataTenTimeOut = 0x1000;
+	xlbarb->busActTimeOut = 0x2000;
+
+	xlbarb->config = 0x00002000;
+
+	/* Master Priority Enable */
+	xlbarb->mastPriority = 0;
+	xlbarb->mastPriEn = 0xff;
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+	/* this may belongs to disable interrupt section */
+	/* mask all interrupts */
+	*(vu_long *) 0xf0000700 = 0xfffffc00;
+	*(vu_long *) 0xf0000714 |= 0x0001ffff;
+	*(vu_long *) 0xf0000710 &= ~0x00000f00;
+
+	/* route critical ints to normal ints */
+	*(vu_long *) 0xf0000710 |= 0x00000001;
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC8220_FEC)
+	/* load FEC microcode */
+	loadtask (0, 2);
+#endif
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc8220/dma.h b/arch/ppc/cpu/mpc8220/dma.h
new file mode 100644
index 0000000..d06ee63
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/dma.h
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * MPC8220 dma header file
+ */
+
+#ifndef __MPC8220_DMA_H
+#define __MPC8220_DMA_H
+
+#include <common.h>
+#include <mpc8220.h>
+
+/* Task number assignment */
+#define FEC_RECV_TASK_NO            0
+#define FEC_XMIT_TASK_NO            1
+
+/*---------------------------------------------------------------------
+ * Stuff for Ethernet Tx/Rx tasks
+ *---------------------------------------------------------------------
+ */
+
+/* Layout of Ethernet controller Parameter SRAM area:
+ * ----------------------------------------------------------------
+ * 0x00: TBD_BASE, base address of TX BD ring
+ * 0x04: TBD_NEXT, address of next TX BD to be processed
+ * 0x08: RBD_BASE, base address of RX BD ring
+ * 0x0C: RBD_NEXT, address of next RX BD to be processed
+ * ---------------------------------------------------------------
+ * ALL PARAMETERS ARE ALL LONGWORDS (FOUR BYTES EACH).
+ */
+
+/* base address of SRAM area to store parameters used by Ethernet tasks */
+#define FEC_PARAM_BASE  (MMAP_SRAM + 0x5b00)
+
+/* base address of SRAM area for buffer descriptors */
+#define FEC_BD_BASE     (MMAP_SRAM + 0x5b20)
+
+/*---------------------------------------------------------------------
+ * common shortcuts  used  by driver C code
+ *---------------------------------------------------------------------
+ */
+
+/* Disable SmartDMA task */
+#define DMA_TASK_DISABLE(tasknum)						\
+{										\
+	volatile ushort *tcr = (ushort *)(MMAP_DMA + 0x0000001c + 2 * tasknum); \
+	*tcr = (*tcr) & (~0x8000);						\
+}
+
+/* Enable SmartDMA task */
+#define DMA_TASK_ENABLE(tasknum)						\
+{										\
+	volatile ushort *tcr = (ushort *) (MMAP_DMA + 0x0000001c + 2 * tasknum);\
+	*tcr = (*tcr)  | 0x8000;						\
+}
+
+/* Clear interrupt pending bits */
+#define DMA_CLEAR_IEVENT(tasknum)						\
+{										\
+	struct mpc8220_dma *dma = (struct mpc8220_dma *)MMAP_DMA;		\
+	dma->IntPend = (1 << tasknum);						\
+}
+
+#endif  /* __MPC8220_DMA_H */
diff --git a/arch/ppc/cpu/mpc8220/dramSetup.c b/arch/ppc/cpu/mpc8220/dramSetup.c
new file mode 100644
index 0000000..52cf133
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/dramSetup.c
@@ -0,0 +1,752 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+DESCRIPTION
+Read Dram spd and base on its information to calculate the memory size,
+characteristics to initialize the dram on MPC8220
+*/
+
+#include <common.h>
+#include <mpc8220.h>
+#include "i2cCore.h"
+#include "dramSetup.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SPD_SIZE	CONFIG_SYS_SDRAM_SPD_SIZE
+#define DRAM_SPD	(CONFIG_SYS_SDRAM_SPD_I2C_ADDR)<<1	/* on Board SPD eeprom */
+#define TOTAL_BANK	CONFIG_SYS_SDRAM_TOTAL_BANKS
+
+int spd_status (volatile i2c8220_t * pi2c, u8 sta_bit, u8 truefalse)
+{
+	int i;
+
+	for (i = 0; i < I2C_POLL_COUNT; i++) {
+		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0))
+			return (OK);
+	}
+
+	return (ERROR);
+}
+
+int spd_clear (volatile i2c8220_t * pi2c)
+{
+	pi2c->adr = 0;
+	pi2c->fdr = 0;
+	pi2c->cr = 0;
+	pi2c->sr = 0;
+
+	return (OK);
+}
+
+int spd_stop (volatile i2c8220_t * pi2c)
+{
+	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal         */
+	if (spd_status (pi2c, I2C_STA_BB, 0) != OK)
+		return ERROR;
+
+	return (OK);
+}
+
+int spd_readbyte (volatile i2c8220_t * pi2c, u8 * readb, int *index)
+{
+	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit          */
+	*readb = pi2c->dr;	/* Read a byte                  */
+
+	/*
+	   Set I2C_CTRL_TXAK will cause Transfer pending and
+	   set I2C_CTRL_STA will cause Interrupt pending
+	 */
+	if (*index != 2) {
+		if (spd_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?       */
+			return ERROR;
+	}
+
+	if (*index != 1) {
+		if (spd_status (pi2c, I2C_STA_IF, 1) != OK)
+			return ERROR;
+	}
+
+	return (OK);
+}
+
+int readSpdData (u8 * spdData)
+{
+	volatile i2c8220_t *pi2cReg;
+	volatile pcfg8220_t *pcfg;
+	u8 slvAdr = DRAM_SPD;
+	u8 Tmp;
+	int Length = SPD_SIZE;
+	int i = 0;
+
+	/* Enable Port Configuration for SDA and SDL signals */
+	pcfg = (volatile pcfg8220_t *) (MMAP_PCFG);
+	__asm__ ("sync");
+	pcfg->pcfg3 &= ~CONFIG_SYS_I2C_PORT3_CONFIG;
+	__asm__ ("sync");
+
+	/* Points the structure to I2c mbar memory offset */
+	pi2cReg = (volatile i2c8220_t *) (MMAP_I2C);
+
+
+	/* Clear FDR, ADR, SR and CR reg */
+	pi2cReg->adr = 0;
+	pi2cReg->fdr = 0;
+	pi2cReg->cr = 0;
+	pi2cReg->sr = 0;
+
+	/* Set for fix XLB Bus Frequency */
+	switch (gd->bus_clk) {
+	case 60000000:
+		pi2cReg->fdr = 0x15;
+		break;
+	case 70000000:
+		pi2cReg->fdr = 0x16;
+		break;
+	case 80000000:
+		pi2cReg->fdr = 0x3a;
+		break;
+	case 90000000:
+		pi2cReg->fdr = 0x17;
+		break;
+	case 100000000:
+		pi2cReg->fdr = 0x3b;
+		break;
+	case 110000000:
+		pi2cReg->fdr = 0x18;
+		break;
+	case 120000000:
+		pi2cReg->fdr = 0x19;
+		break;
+	case 130000000:
+		pi2cReg->fdr = 0x1a;
+		break;
+	}
+
+	pi2cReg->adr = CONFIG_SYS_I2C_SLAVE<<1;
+
+	pi2cReg->cr = I2C_CTL_EN;	/* Set Enable         */
+
+	/*
+	   The I2C bus should be in Idle state. If the bus is busy,
+	   clear the STA bit in control register
+	 */
+	if (spd_status (pi2cReg, I2C_STA_BB, 0) != OK) {
+		if ((pi2cReg->cr & I2C_CTL_STA) == I2C_CTL_STA)
+			pi2cReg->cr &= ~I2C_CTL_STA;
+
+		/* Check again if it is still busy, return error if found */
+		if (spd_status (pi2cReg, I2C_STA_BB, 1) == OK)
+			return ERROR;
+	}
+
+	pi2cReg->cr |= I2C_CTL_TX;	/* Enable the I2c for TX, Ack   */
+	pi2cReg->cr |= I2C_CTL_STA;	/* Generate start signal        */
+
+	if (spd_status (pi2cReg, I2C_STA_BB, 1) != OK)
+		return ERROR;
+
+
+	/* Write slave address */
+	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */
+	pi2cReg->dr = slvAdr;	/* Write a byte                 */
+
+	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+
+	/* Issue the offset to start */
+	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */
+	pi2cReg->dr = 0;	/* Write a byte                 */
+
+	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+
+	/* Set repeat start */
+	pi2cReg->cr |= I2C_CTL_RSTA;	/* Repeat Start                 */
+
+	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */
+	pi2cReg->dr = slvAdr | 1;	/* Write a byte                 */
+
+	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01))
+		return ERROR;
+
+	pi2cReg->cr &= ~I2C_CTL_TX;	/* Set receive mode             */
+
+	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01))
+		return ERROR;
+
+	/* Dummy Read */
+	if (spd_readbyte (pi2cReg, &Tmp, &i) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	i = 0;
+	while (Length) {
+		if (Length == 2)
+			pi2cReg->cr |= I2C_CTL_TXAK;
+
+		if (Length == 1)
+			pi2cReg->cr &= ~I2C_CTL_STA;
+
+		if (spd_readbyte (pi2cReg, spdData, &Length) != OK) {
+			return spd_stop (pi2cReg);
+		}
+		i++;
+		Length--;
+		spdData++;
+	}
+
+	/* Stop the service */
+	spd_stop (pi2cReg);
+
+	return OK;
+}
+
+int getBankInfo (int bank, draminfo_t * pBank)
+{
+	int status;
+	int checksum;
+	int count;
+	u8 spdData[SPD_SIZE];
+
+
+	if (bank > 2 || pBank == 0) {
+		/* illegal values */
+		return (-42);
+	}
+
+	status = readSpdData (&spdData[0]);
+	if (status < 0)
+		return (-1);
+
+	/* check the checksum */
+	for (count = 0, checksum = 0; count < LOC_CHECKSUM; count++)
+		checksum += spdData[count];
+
+	checksum = checksum - ((checksum / 256) * 256);
+
+	if (checksum != spdData[LOC_CHECKSUM])
+		return (-2);
+
+	/* Get the memory type */
+	if (!
+	    ((spdData[LOC_TYPE] == TYPE_DDR)
+	     || (spdData[LOC_TYPE] == TYPE_SDR)))
+		/* not one of the types we support */
+		return (-3);
+
+	pBank->type = spdData[LOC_TYPE];
+
+	/* Set logical banks */
+	pBank->banks = spdData[LOC_LOGICAL_BANKS];
+
+	/* Check that we have enough physical banks to cover the bank we are
+	 * figuring out.  Odd-numbered banks correspond to the second bank
+	 * on the device.
+	 */
+	if (bank & 1) {
+		/* Second bank of a "device" */
+		if (spdData[LOC_PHYS_BANKS] < 2)
+			/* this bank doesn't exist on the "device" */
+			return (-4);
+
+		if (spdData[LOC_ROWS] & 0xf0)
+			/* Two asymmetric banks */
+			pBank->rows = spdData[LOC_ROWS] >> 4;
+		else
+			pBank->rows = spdData[LOC_ROWS];
+
+		if (spdData[LOC_COLS] & 0xf0)
+			/* Two asymmetric banks */
+			pBank->cols = spdData[LOC_COLS] >> 4;
+		else
+			pBank->cols = spdData[LOC_COLS];
+	} else {
+		/* First bank of a "device" */
+		pBank->rows = spdData[LOC_ROWS];
+		pBank->cols = spdData[LOC_COLS];
+	}
+
+	pBank->width = spdData[LOC_WIDTH_HIGH] << 8 | spdData[LOC_WIDTH_LOW];
+	pBank->bursts = spdData[LOC_BURSTS];
+	pBank->CAS = spdData[LOC_CAS];
+	pBank->CS = spdData[LOC_CS];
+	pBank->WE = spdData[LOC_WE];
+	pBank->Trp = spdData[LOC_Trp];
+	pBank->Trcd = spdData[LOC_Trcd];
+	pBank->buffered = spdData[LOC_Buffered] & 1;
+	pBank->refresh = spdData[LOC_REFRESH];
+
+	return (0);
+}
+
+
+/* checkMuxSetting -- given a row/column device geometry, return a mask
+ *                    of the valid DRAM controller addr_mux settings for
+ *                    that geometry.
+ *
+ *  Arguments:        u8 rows:     number of row addresses in this device
+ *                    u8 columns:  number of column addresses in this device
+ *
+ *  Returns:          a mask of the allowed addr_mux settings for this
+ *                    geometry.  Each bit in the mask represents a
+ *                    possible addr_mux settings (for example, the
+ *                    (1<<2) bit in the mask represents the 0b10 setting)/
+ *
+ */
+u8 checkMuxSetting (u8 rows, u8 columns)
+{
+	muxdesc_t *pIdx, *pMux;
+	u8 mask;
+	int lrows, lcolumns;
+	u32 mux[4] = { 0x00080c04, 0x01080d03, 0x02080e02, 0xffffffff };
+
+	/* Setup MuxDescriptor in SRAM space */
+	/* MUXDESC AddressRuns [] = {
+	   { 0, 8, 12, 4 },         / setting, columns, rows, extra columns /
+	   { 1, 8, 13, 3 },         / setting, columns, rows, extra columns /
+	   { 2, 8, 14, 2 },         / setting, columns, rows, extra columns /
+	   { 0xff }                 / list terminator /
+	   }; */
+
+	pIdx = (muxdesc_t *) & mux[0];
+
+	/* Check rows x columns against each possible address mux setting */
+	for (pMux = pIdx, mask = 0;; pMux++) {
+		lrows = rows;
+		lcolumns = columns;
+
+		if (pMux->MuxValue == 0xff)
+			break;	/* end of list */
+
+		/* For a given mux setting, since we want all the memory in a
+		 * device to be contiguous, we want the device "use up" the
+		 * address lines such that there are no extra column or row
+		 * address lines on the device.
+		 */
+
+		lcolumns -= pMux->Columns;
+		if (lcolumns < 0)
+			/* Not enough columns to get to the rows */
+			continue;
+
+		lrows -= pMux->Rows;
+		if (lrows > 0)
+			/* we have extra rows left -- can't do that! */
+			continue;
+
+		/* At this point, we either have to have used up all the
+		 * rows or we have to have no columns left.
+		 */
+
+		if (lcolumns != 0 && lrows != 0)
+			/* rows AND columns are left.  Bad! */
+			continue;
+
+		lcolumns -= pMux->MoreColumns;
+
+		if (lcolumns <= 0)
+			mask |= (1 << pMux->MuxValue);
+	}
+
+	return (mask);
+}
+
+
+u32 dramSetup (void)
+{
+	draminfo_t DramInfo[TOTAL_BANK];
+	draminfo_t *pDramInfo;
+	u32 size, temp, cfg_value, mode_value, refresh;
+	u8 *ptr;
+	u8 bursts, Trp, Trcd, type, buffered;
+	u8 muxmask, rows, columns;
+	int count, banknum;
+	u32 *prefresh, *pIdx;
+	u32 refrate[8] = { 15625, 3900, 7800, 31300,
+		62500, 125000, 0xffffffff, 0xffffffff
+	};
+	volatile sysconf8220_t *sysconf;
+	volatile memctl8220_t *memctl;
+
+	sysconf = (volatile sysconf8220_t *) MMAP_MBAR;
+	memctl = (volatile memctl8220_t *) MMAP_MEMCTL;
+
+	/* Set everything in the descriptions to zero */
+	ptr = (u8 *) & DramInfo[0];
+	for (count = 0; count < sizeof (DramInfo); count++)
+		*ptr++ = 0;
+
+	for (banknum = 0; banknum < TOTAL_BANK; banknum++)
+		sysconf->cscfg[banknum];
+
+	/* Descriptions of row/column address muxing for various
+	 * addr_mux settings.
+	 */
+
+	pIdx = prefresh = (u32 *) & refrate[0];
+
+	/* Get all the info for all three logical banks */
+	bursts = 0xff;
+	Trp = 0;
+	Trcd = 0;
+	type = 0;
+	buffered = 0xff;
+	refresh = 0xffffffff;
+	muxmask = 0xff;
+
+	/* Two bank, CS0 and CS1 */
+	for (banknum = 0, pDramInfo = &DramInfo[0];
+	     banknum < TOTAL_BANK; banknum++, pDramInfo++) {
+		pDramInfo->ordinal = banknum;	/* initial sorting */
+		if (getBankInfo (banknum, pDramInfo) < 0)
+			continue;
+
+		/* get cumulative parameters of all three banks */
+		if (type && pDramInfo->type != type)
+			return 0;
+
+		type = pDramInfo->type;
+		rows = pDramInfo->rows;
+		columns = pDramInfo->cols;
+
+		/* This chip only supports 13 DRAM memory lines, but some devices
+		 * have 14 rows.  To deal with this, ignore the 14th address line
+		 * by limiting the number of rows (and columns) to 13.  This will
+		 * mean that for 14-row devices we will only be able to use
+		 * half of the memory, but it's better than nothing.
+		 */
+		if (rows > 13)
+			rows = 13;
+		if (columns > 13)
+			columns = 13;
+
+		pDramInfo->size =
+			((1 << (rows + columns)) * pDramInfo->width);
+		pDramInfo->size *= pDramInfo->banks;
+		pDramInfo->size >>= 3;
+
+		/* figure out which addr_mux configurations will support this device */
+		muxmask &= checkMuxSetting (rows, columns);
+		if (muxmask == 0)
+			return 0;
+
+		buffered = pDramInfo->buffered;
+		bursts &= pDramInfo->bursts;	/* union of all bursts */
+		if (pDramInfo->Trp > Trp)	/* worst case (longest) Trp */
+			Trp = pDramInfo->Trp;
+
+		if (pDramInfo->Trcd > Trcd)	/* worst case (longest) Trcd */
+			Trcd = pDramInfo->Trcd;
+
+		prefresh = pIdx;
+		/* worst case (shortest) Refresh period */
+		if (refresh > prefresh[pDramInfo->refresh & 7])
+			refresh = prefresh[pDramInfo->refresh & 7];
+
+	}			/* for loop */
+
+
+	/* We only allow a burst length of 8! */
+	if (!(bursts & 8))
+		bursts = 8;
+
+	/* Sort the devices.  In order to get each chip select region
+	 * aligned properly, put the biggest device at the lowest address.
+	 * A simple bubble sort will do the trick.
+	 */
+	for (banknum = 0, pDramInfo = &DramInfo[0];
+	     banknum < TOTAL_BANK; banknum++, pDramInfo++) {
+		int i;
+
+		for (i = 0; i < TOTAL_BANK; i++) {
+			if (pDramInfo->size < DramInfo[i].size &&
+			    pDramInfo->ordinal < DramInfo[i].ordinal) {
+				/* If the current bank is smaller, but if the ordinal is also
+				 * smaller, swap the ordinals
+				 */
+				u8 temp8;
+
+				temp8 = DramInfo[i].ordinal;
+				DramInfo[i].ordinal = pDramInfo->ordinal;
+				pDramInfo->ordinal = temp8;
+			}
+		}
+	}
+
+
+	/* Now figure out the base address for each bank.  While
+	 * we're at it, figure out how much memory there is.
+	 *
+	 */
+	size = 0;
+	for (banknum = 0; banknum < TOTAL_BANK; banknum++) {
+		int i;
+
+		for (i = 0; i < TOTAL_BANK; i++) {
+			if (DramInfo[i].ordinal == banknum
+			    && DramInfo[i].size != 0) {
+				DramInfo[i].base = size;
+				size += DramInfo[i].size;
+			}
+		}
+	}
+
+	/* Set up the Drive Strength register */
+	sysconf->sdramds = CONFIG_SYS_SDRAM_DRIVE_STRENGTH;
+
+	/* ********************** Cfg 1 ************************* */
+
+	/* Set the single read to read/write/precharge delay */
+	cfg_value = CFG1_SRD2RWP ((type == TYPE_DDR) ? 7 : 0xb);
+
+	/* Set the single write to read/write/precharge delay.
+	 * This may or may not be correct.  The controller spec
+	 * says "tWR", but "tWR" does not appear in the SPD.  It
+	 * always seems to be 15nsec for the class of device we're
+	 * using, which turns out to be 2 clock cycles at 133MHz,
+	 * so that's what we're going to use.
+	 *
+	 * HOWEVER, because of a bug in the controller, for DDR
+	 * we need to set this to be the same as the value
+	 * calculated for bwt2rwp.
+	 */
+	cfg_value |= CFG1_SWT2RWP ((type == TYPE_DDR) ? 7 : 2);
+
+	/* Set the Read CAS latency.  We're going to use a CL of
+	 * 2.5 for DDR and 2 SDR.
+	 */
+	cfg_value |= CFG1_RLATENCY ((type == TYPE_DDR) ? 7 : 2);
+
+
+	/* Set the Active to Read/Write delay.  This depends
+	 * on Trcd which is reported as nanoseconds times 4.
+	 * We want to calculate Trcd (in nanoseconds) times XLB clock (in Hz)
+	 * which gives us a dimensionless quantity.  Play games with
+	 * the divisions so we don't run out of dynamic ranges.
+	 */
+	/* account for megaherz and the times 4 */
+	temp = (Trcd * (gd->bus_clk / 1000000)) / 4;
+
+	/* account for nanoseconds and round up, with a minimum value of 2 */
+	temp = ((temp + 999) / 1000) - 1;
+	if (temp < 2)
+		temp = 2;
+
+	cfg_value |= CFG1_ACT2WR (temp);
+
+	/* Set the precharge to active delay.  This depends
+	 * on Trp which is reported as nanoseconds times 4.
+	 * We want to calculate Trp (in nanoseconds) times XLB clock (in Hz)
+	 * which gives us a dimensionless quantity.  Play games with
+	 * the divisions so we don't run out of dynamic ranges.
+	 */
+	/* account for megaherz and the times 4 */
+	temp = (Trp * (gd->bus_clk / 1000000)) / 4;
+
+	/* account for nanoseconds and round up, then subtract 1, with a
+	 * minumum value of 1 and a maximum value of 7.
+	 */
+	temp = (((temp + 999) / 1000) - 1) & 7;
+	if (temp < 1)
+		temp = 1;
+
+	cfg_value |= CFG1_PRE2ACT (temp);
+
+	/* Set refresh to active delay.  This depends
+	 * on Trfc which is not reported in the SPD.
+	 * We'll use a nominal value of 75nsec which is
+	 * what the controller spec uses.
+	 */
+	temp = (75 * (gd->bus_clk / 1000000));
+	/* account for nanoseconds and round up, then subtract 1 */
+	cfg_value |= CFG1_REF2ACT (((temp + 999) / 1000) - 1);
+
+	/* Set the write latency, using the values given in the controller spec */
+	cfg_value |= CFG1_WLATENCY ((type == TYPE_DDR) ? 3 : 0);
+	memctl->cfg1 = cfg_value;	/* cfg 1 */
+	asm volatile ("sync");
+
+
+	/* ********************** Cfg 2 ************************* */
+
+	/* Set the burst read to read/precharge delay */
+	cfg_value = CFG2_BRD2RP ((type == TYPE_DDR) ? 5 : 8);
+
+	/* Set the burst write to read/precharge delay.  Semi-magic numbers
+	 * based on the controller spec recommendations, assuming tWR is
+	 * two clock cycles.
+	 */
+	cfg_value |= CFG2_BWT2RWP ((type == TYPE_DDR) ? 7 : 10);
+
+	/* Set the Burst read to write delay.  Semi-magic numbers
+	 * based on the DRAM controller documentation.
+	 */
+	cfg_value |= CFG2_BRD2WT ((type == TYPE_DDR) ? 7 : 0xb);
+
+	/* Set the burst length -- must be 8!! Well, 7, actually, becuase
+	 * it's burst lenght minus 1.
+	 */
+	cfg_value |= CFG2_BURSTLEN (7);
+	memctl->cfg2 = cfg_value;	/* cfg 2 */
+	asm volatile ("sync");
+
+
+	/* ********************** mode ************************* */
+
+	/* Set enable bit, CKE high/low bits, and the DDR/SDR mode bit,
+	 * disable automatic refresh.
+	 */
+	cfg_value = CTL_MODE_ENABLE | CTL_CKE_HIGH |
+		((type == TYPE_DDR) ? CTL_DDR_MODE : 0);
+
+	/* Set the address mux based on whichever setting(s) is/are common
+	 * to all the devices we have.  If there is more than one, choose
+	 * one arbitrarily.
+	 */
+	if (muxmask & 0x4)
+		cfg_value |= CTL_ADDRMUX (2);
+	else if (muxmask & 0x2)
+		cfg_value |= CTL_ADDRMUX (1);
+	else
+		cfg_value |= CTL_ADDRMUX (0);
+
+	/* Set the refresh interval. */
+	temp = ((refresh * (gd->bus_clk / 1000000)) / (1000 * 64)) - 1;
+	cfg_value |= CTL_REFRESH_INTERVAL (temp);
+
+	/* Set buffered/non-buffered memory */
+	if (buffered)
+		cfg_value |= CTL_BUFFERED;
+
+	memctl->ctrl = cfg_value;	/* ctrl */
+	asm volatile ("sync");
+
+	if (type == TYPE_DDR) {
+		/* issue precharge all */
+		temp = cfg_value | CTL_PRECHARGE_CMD;
+		memctl->ctrl = temp;	/* ctrl */
+		asm volatile ("sync");
+	}
+
+
+	/* Set up mode value for CAS latency */
+#if (CONFIG_SYS_SDRAM_CAS_LATENCY==5) /* CL=2.5 */
+	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) |
+		MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2p5) | MODE_CMD);
+#else
+	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) |
+		      MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2) | MODE_CMD);
+#endif
+	asm volatile ("sync");
+
+	/* Write Extended Mode  - enable DLL */
+	if (type == TYPE_DDR) {
+		temp = MODE_EXTENDED | MODE_X_DLL_ENABLE |
+			MODE_X_DS_NORMAL | MODE_CMD;
+		memctl->mode = (temp >> 16);	/* mode */
+		asm volatile ("sync");
+
+		/* Write Mode - reset DLL, set CAS latency */
+		temp = mode_value | MODE_OPMODE (MODE_OPMODE_RESETDLL);
+		memctl->mode = (temp >> 16);	/* mode */
+		asm volatile ("sync");
+	}
+
+	/* Program the chip selects. */
+	for (banknum = 0; banknum < TOTAL_BANK; banknum++) {
+		if (DramInfo[banknum].size != 0) {
+			u32 mask;
+			int i;
+
+			for (i = 0, mask = 1; i < 32; mask <<= 1, i++) {
+				if (DramInfo[banknum].size & mask)
+					break;
+			}
+			temp = (DramInfo[banknum].base & 0xfff00000) | (i -
+									1);
+
+			sysconf->cscfg[banknum] = temp;
+			asm volatile ("sync");
+		}
+	}
+
+	/* Wait for DLL lock */
+	udelay (200);
+
+	temp = cfg_value | CTL_PRECHARGE_CMD;	/* issue precharge all */
+	memctl->ctrl = temp;	/* ctrl */
+	asm volatile ("sync");
+
+	temp = cfg_value | CTL_REFRESH_CMD;	/* issue precharge all */
+	memctl->ctrl = temp;	/* ctrl */
+	asm volatile ("sync");
+
+	memctl->ctrl = temp;	/* ctrl */
+	asm volatile ("sync");
+
+	/* Write Mode - DLL normal */
+	temp = mode_value | MODE_OPMODE (MODE_OPMODE_NORMAL);
+	memctl->mode = (temp >> 16);	/* mode */
+	asm volatile ("sync");
+
+	/* Enable refresh, enable DQS's (if DDR), and lock the control register */
+	cfg_value &= ~CTL_MODE_ENABLE;	/* lock register */
+	cfg_value |= CTL_REFRESH_ENABLE;	/* enable refresh */
+
+	if (type == TYPE_DDR)
+		cfg_value |= CTL_DQSOEN (0xf);	/* enable DQS's for DDR */
+
+	memctl->ctrl = cfg_value;	/* ctrl */
+	asm volatile ("sync");
+
+	return size;
+}
diff --git a/arch/ppc/cpu/mpc8220/dramSetup.h b/arch/ppc/cpu/mpc8220/dramSetup.h
new file mode 100644
index 0000000..3b64e08
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/dramSetup.h
@@ -0,0 +1,108 @@
+/*
+ * dramSetup.h
+ *
+ * Prototypes, etc. for the Motorola MPC8220
+ * embedded cpu chips
+ *
+ * 2004 (c) Freescale, Inc.
+ * Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __INCdramsetuph
+#define __INCdramsetuph
+#ifndef __ASSEMBLY__
+/* Where various things are in the SPD */
+#define LOC_TYPE                    2
+#define LOC_CHECKSUM                63
+#define LOC_PHYS_BANKS              5
+#define LOC_LOGICAL_BANKS           17
+#define LOC_ROWS                    3
+#define LOC_COLS                    4
+#define LOC_WIDTH_HIGH              7
+#define LOC_WIDTH_LOW               6
+#define LOC_REFRESH                 12
+#define LOC_BURSTS                  16
+#define LOC_CAS                     18
+#define LOC_CS                      19
+#define LOC_WE                      20
+#define LOC_Tcyc                    9
+#define LOC_Tac                     10
+#define LOC_Trp                     27
+#define LOC_Trrd                    28
+#define LOC_Trcd                    29
+#define LOC_Tras                    30
+#define LOC_Buffered                21
+/* Types of memory the SPD can tell us about.
+ * We can actually only use SDRAM and DDR.
+ */
+#define TYPE_DRAM                   1	/* plain old dram */
+#define TYPE_EDO                    2	/* EDO dram */
+#define TYPE_Nibble                 3	/* serial nibble memory */
+#define TYPE_SDR                    4	/* SDRAM */
+#define TYPE_ROM                    5	/*  */
+#define TYPE_SGRRAM                 6	/* graphics memory */
+#define TYPE_DDR                    7	/* DDR sdram */
+#define SDRAMDS_MASK        0x3	/* each field is 2 bits wide */
+#define SDRAMDS_SBE_SHIFT     8	/* Clock enable drive strength */
+#define SDRAMDS_SBC_SHIFT     6	/* Clocks drive strength */
+#define SDRAMDS_SBA_SHIFT     4	/* Address drive strength */
+#define SDRAMDS_SBS_SHIFT     2	/* SDR DQS drive strength */
+#define SDRAMDS_SBD_SHIFT     0	/* Data and DQS drive strength */
+#define  DRIVE_STRENGTH_HIGH 0
+#define  DRIVE_STRENGTH_MED  1
+#define  DRIVE_STRENGTH_LOW  2
+#define  DRIVE_STRENGTH_OFF  3
+
+#define OK      0
+#define ERROR   -1
+/* Structure to hold information about address muxing. */
+	typedef struct tagMuxDescriptor {
+	u8 MuxValue;
+	u8 Columns;
+	u8 Rows;
+	u8 MoreColumns;
+} muxdesc_t;
+
+/* Structure to define one physical bank of
+ * memory.  Note that dram size in bytes is
+ * (2^^(rows+columns)) * width * banks / 8
+*/
+typedef struct tagDramInfo {
+	u32 size;		/* size in bytes */
+	u32 base;		/* base address */
+	u8 ordinal;		/* where in the memory map will we put this */
+	u8 type;
+	u8 rows;
+	u8 cols;
+	u16 width;		/* width of each chip in bits */
+	u8 banks;		/* number of chips, aka logical banks */
+	u8 bursts;		/* bit-encoded allowable burst length */
+	u8 CAS;			/* bit-encoded CAS latency values */
+	u8 CS;			/* bit-encoded CS latency values */
+	u8 WE;			/* bit-encoded WE latency values */
+	u8 Trp;			/* bit-encoded row precharge time */
+	u8 Trcd;		/* bit-encoded RAS to CAS delay */
+	u8 buffered;		/* buffered or not */
+	u8 refresh;		/* encoded refresh rate */
+} draminfo_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __INCdramsetuph */
diff --git a/arch/ppc/cpu/mpc8220/fec.c b/arch/ppc/cpu/mpc8220/fec.c
new file mode 100644
index 0000000..992e0ff
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/fec.c
@@ -0,0 +1,1000 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.c,
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include "dma.h"
+#include "fec.h"
+
+#undef  DEBUG
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+    defined(CONFIG_MPC8220_FEC)
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#ifdef DEBUG
+static void tfifo_print (char *devname, mpc8220_fec_priv * fec);
+static void rfifo_print (char *devname, mpc8220_fec_priv * fec);
+#endif /* DEBUG */
+
+#ifdef DEBUG
+static u32 local_crc32 (char *string, unsigned int crc_value, int len);
+#endif
+
+typedef struct {
+	u8 data[1500];		/* actual data */
+	int length;		/* actual length */
+	int used;		/* buffer in use or not */
+	u8 head[16];		/* MAC header(6 + 6 + 2) + 2(aligned) */
+} NBUF;
+
+int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal);
+int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data);
+
+/********************************************************************/
+#ifdef DEBUG
+static void mpc8220_fec_phydump (char *devname)
+{
+	u16 phyStatus, i;
+	u8 phyAddr = CONFIG_PHY_ADDR;
+	u8 reg_mask[] = {
+#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
+		/* regs to print: 0...7, 16...19, 21, 23, 24 */
+		1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+#else
+		/* regs to print: 0...8, 16...20 */
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+		1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+	};
+
+	for (i = 0; i < 32; i++) {
+		if (reg_mask[i]) {
+			miiphy_read (devname, phyAddr, i, &phyStatus);
+			printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
+		}
+	}
+}
+#endif
+
+/********************************************************************/
+static int mpc8220_fec_rbd_init (mpc8220_fec_priv * fec)
+{
+	int ix;
+	char *data;
+	static int once = 0;
+
+	for (ix = 0; ix < FEC_RBD_NUM; ix++) {
+		if (!once) {
+			data = (char *) malloc (FEC_MAX_PKT_SIZE);
+			if (data == NULL) {
+				printf ("RBD INIT FAILED\n");
+				return -1;
+			}
+			fec->rbdBase[ix].dataPointer = (u32) data;
+		}
+		fec->rbdBase[ix].status = FEC_RBD_EMPTY;
+		fec->rbdBase[ix].dataLength = 0;
+	}
+	once++;
+
+	/*
+	 * have the last RBD to close the ring
+	 */
+	fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP;
+	fec->rbdIndex = 0;
+
+	return 0;
+}
+
+/********************************************************************/
+static void mpc8220_fec_tbd_init (mpc8220_fec_priv * fec)
+{
+	int ix;
+
+	for (ix = 0; ix < FEC_TBD_NUM; ix++) {
+		fec->tbdBase[ix].status = 0;
+	}
+
+	/*
+	 * Have the last TBD to close the ring
+	 */
+	fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP;
+
+	/*
+	 * Initialize some indices
+	 */
+	fec->tbdIndex = 0;
+	fec->usedTbdIndex = 0;
+	fec->cleanTbdNum = FEC_TBD_NUM;
+}
+
+/********************************************************************/
+static void mpc8220_fec_rbd_clean (mpc8220_fec_priv * fec, FEC_RBD * pRbd)
+{
+	/*
+	 * Reset buffer descriptor as empty
+	 */
+	if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
+		pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
+	else
+		pRbd->status = FEC_RBD_EMPTY;
+
+	pRbd->dataLength = 0;
+
+	/*
+	 * Now, we have an empty RxBD, restart the SmartDMA receive task
+	 */
+	DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
+
+	/*
+	 * Increment BD count
+	 */
+	fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
+}
+
+/********************************************************************/
+static void mpc8220_fec_tbd_scrub (mpc8220_fec_priv * fec)
+{
+	FEC_TBD *pUsedTbd;
+
+#ifdef DEBUG
+	printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
+		fec->cleanTbdNum, fec->usedTbdIndex);
+#endif
+
+	/*
+	 * process all the consumed TBDs
+	 */
+	while (fec->cleanTbdNum < FEC_TBD_NUM) {
+		pUsedTbd = &fec->tbdBase[fec->usedTbdIndex];
+		if (pUsedTbd->status & FEC_TBD_READY) {
+#ifdef DEBUG
+			printf ("Cannot clean TBD %d, in use\n",
+				fec->cleanTbdNum);
+#endif
+			return;
+		}
+
+		/*
+		 * clean this buffer descriptor
+		 */
+		if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
+			pUsedTbd->status = FEC_TBD_WRAP;
+		else
+			pUsedTbd->status = 0;
+
+		/*
+		 * update some indeces for a correct handling of the TBD ring
+		 */
+		fec->cleanTbdNum++;
+		fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
+	}
+}
+
+/********************************************************************/
+static void mpc8220_fec_set_hwaddr (mpc8220_fec_priv * fec, char *mac)
+{
+	u8 currByte;		/* byte for which to compute the CRC */
+	int byte;		/* loop - counter */
+	int bit;		/* loop - counter */
+	u32 crc = 0xffffffff;	/* initial value */
+
+	/*
+	 * The algorithm used is the following:
+	 * we loop on each of the six bytes of the provided address,
+	 * and we compute the CRC by left-shifting the previous
+	 * value by one position, so that each bit in the current
+	 * byte of the address may contribute the calculation. If
+	 * the latter and the MSB in the CRC are different, then
+	 * the CRC value so computed is also ex-ored with the
+	 * "polynomium generator". The current byte of the address
+	 * is also shifted right by one bit at each iteration.
+	 * This is because the CRC generatore in hardware is implemented
+	 * as a shift-register with as many ex-ores as the radixes
+	 * in the polynomium. This suggests that we represent the
+	 * polynomiumm itself as a 32-bit constant.
+	 */
+	for (byte = 0; byte < 6; byte++) {
+		currByte = mac[byte];
+		for (bit = 0; bit < 8; bit++) {
+			if ((currByte & 0x01) ^ (crc & 0x01)) {
+				crc >>= 1;
+				crc = crc ^ 0xedb88320;
+			} else {
+				crc >>= 1;
+			}
+			currByte >>= 1;
+		}
+	}
+
+	crc = crc >> 26;
+
+	/*
+	 * Set individual hash table register
+	 */
+	if (crc >= 32) {
+		fec->eth->iaddr1 = (1 << (crc - 32));
+		fec->eth->iaddr2 = 0;
+	} else {
+		fec->eth->iaddr1 = 0;
+		fec->eth->iaddr2 = (1 << crc);
+	}
+
+	/*
+	 * Set physical address
+	 */
+	fec->eth->paddr1 =
+		(mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
+	fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
+}
+
+/********************************************************************/
+static int mpc8220_fec_init (struct eth_device *dev, bd_t * bis)
+{
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	struct mpc8220_dma *dma = (struct mpc8220_dma *) MMAP_DMA;
+	const u8 phyAddr = CONFIG_PHY_ADDR;	/* Only one PHY */
+
+#ifdef DEBUG
+	printf ("mpc8220_fec_init... Begin\n");
+#endif
+
+	/*
+	 * Initialize RxBD/TxBD rings
+	 */
+	mpc8220_fec_rbd_init (fec);
+	mpc8220_fec_tbd_init (fec);
+
+	/*
+	 * Set up Pin Muxing for FEC 1
+	 */
+	*(vu_long *) MMAP_PCFG = 0;
+	*(vu_long *) (MMAP_PCFG + 4) = 0;
+	/*
+	 * Clear FEC-Lite interrupt event register(IEVENT)
+	 */
+	fec->eth->ievent = 0xffffffff;
+
+	/*
+	 * Set interrupt mask register
+	 */
+	fec->eth->imask = 0x00000000;
+
+	/*
+	 * Set FEC-Lite receive control register(R_CNTRL):
+	 */
+	if (fec->xcv_type == SEVENWIRE) {
+		/*
+		 * Frame length=1518; 7-wire mode
+		 */
+		fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */
+	} else {
+		/*
+		 * Frame length=1518; MII mode;
+		 */
+		fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
+	}
+
+	fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
+	if (fec->xcv_type != SEVENWIRE) {
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		/* tbd - rtm */
+		/*fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); */
+		/* No MII for 7-wire mode */
+		fec->eth->mii_speed = 0x00000030;
+	}
+
+	/*
+	 * Set Opcode/Pause Duration Register
+	 */
+	fec->eth->op_pause = 0x00010020;	/*FIXME0xffff0020; */
+
+	/*
+	 * Set Rx FIFO alarm and granularity value
+	 */
+	fec->eth->rfifo_cntrl = 0x0c000000;
+	fec->eth->rfifo_alarm = 0x0000030c;
+#ifdef DEBUG
+	if (fec->eth->rfifo_status & 0x00700000) {
+		printf ("mpc8220_fec_init() RFIFO error\n");
+	}
+#endif
+
+	/*
+	 * Set Tx FIFO granularity value
+	 */
+	/*fec->eth->tfifo_cntrl = 0x0c000000; */ /*tbd - rtm */
+	fec->eth->tfifo_cntrl = 0x0e000000;
+#ifdef DEBUG
+	printf ("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
+	printf ("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
+#endif
+
+	/*
+	 * Set transmit fifo watermark register(X_WMRK), default = 64
+	 */
+	fec->eth->tfifo_alarm = 0x00000080;
+	fec->eth->x_wmrk = 0x2;
+
+	/*
+	 * Set individual address filter for unicast address
+	 * and set physical address registers.
+	 */
+	mpc8220_fec_set_hwaddr (fec, (char *)(dev->enetaddr));
+
+	/*
+	 * Set multicast address filter
+	 */
+	fec->eth->gaddr1 = 0x00000000;
+	fec->eth->gaddr2 = 0x00000000;
+
+	/*
+	 * Turn ON cheater FSM: ????
+	 */
+	fec->eth->xmit_fsm = 0x03000000;
+
+#if 1
+/*#if defined(CONFIG_MPC5200)*/
+	/*
+	 * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't
+	 * work w/ the current receive task.
+	 */
+	dma->PtdCntrl |= 0x00000001;
+#endif
+
+	/*
+	 * Set priority of different initiators
+	 */
+	dma->IPR0 = 7;		/* always */
+	dma->IPR3 = 6;		/* Eth RX */
+	dma->IPR4 = 5;		/* Eth Tx */
+
+	/*
+	 * Clear SmartDMA task interrupt pending bits
+	 */
+	DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+
+	/*
+	 * Initialize SmartDMA parameters stored in SRAM
+	 */
+	*(int *) FEC_TBD_BASE = (int) fec->tbdBase;
+	*(int *) FEC_RBD_BASE = (int) fec->rbdBase;
+	*(int *) FEC_TBD_NEXT = (int) fec->tbdBase;
+	*(int *) FEC_RBD_NEXT = (int) fec->rbdBase;
+
+	if (fec->xcv_type != SEVENWIRE) {
+		/*
+		 * Initialize PHY(LXT971A):
+		 *
+		 *   Generally, on power up, the LXT971A reads its configuration
+		 *   pins to check for forced operation, If not cofigured for
+		 *   forced operation, it uses auto-negotiation/parallel detection
+		 *   to automatically determine line operating conditions.
+		 *   If the PHY device on the other side of the link supports
+		 *   auto-negotiation, the LXT971A auto-negotiates with it
+		 *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
+		 *   support auto-negotiation, the LXT971A automatically detects
+		 *   the presence of either link pulses(10Mbps PHY) or Idle
+		 *   symbols(100Mbps) and sets its operating conditions accordingly.
+		 *
+		 *   When auto-negotiation is controlled by software, the following
+		 *   steps are recommended.
+		 *
+		 * Note:
+		 *   The physical address is dependent on hardware configuration.
+		 *
+		 */
+		int timeout = 1;
+		u16 phyStatus;
+
+		/*
+		 * Reset PHY, then delay 300ns
+		 */
+		miiphy_write (dev->name, phyAddr, 0x0, 0x8000);
+		udelay (1000);
+
+		if (fec->xcv_type == MII10) {
+			/*
+			 * Force 10Base-T, FDX operation
+			 */
+#ifdef DEBUG
+			printf ("Forcing 10 Mbps ethernet link... ");
+#endif
+			miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+			/*
+			   miiphy_write(fec, phyAddr, 0x0, 0x0100);
+			 */
+			miiphy_write (dev->name, phyAddr, 0x0, 0x0180);
+
+			timeout = 20;
+			do {	/* wait for link status to go down */
+				udelay (10000);
+				if ((timeout--) == 0) {
+#ifdef DEBUG
+					printf ("hmmm, should not have waited...");
+#endif
+					break;
+				}
+				miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+#ifdef DEBUG
+				printf ("=");
+#endif
+			} while ((phyStatus & 0x0004)); /* !link up */
+
+			timeout = 1000;
+			do {	/* wait for link status to come back up */
+				udelay (10000);
+				if ((timeout--) == 0) {
+					printf ("failed. Link is down.\n");
+					break;
+				}
+				miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+#ifdef DEBUG
+				printf ("+");
+#endif
+			} while (!(phyStatus & 0x0004));	/* !link up */
+
+#ifdef DEBUG
+			printf ("done.\n");
+#endif
+		} else {	/* MII100 */
+			/*
+			 * Set the auto-negotiation advertisement register bits
+			 */
+			miiphy_write (dev->name, phyAddr, 0x4, 0x01e1);
+
+			/*
+			 * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
+			 */
+			miiphy_write (dev->name, phyAddr, 0x0, 0x1200);
+
+			/*
+			 * Wait for AN completion
+			 */
+			timeout = 5000;
+			do {
+				udelay (1000);
+
+				if ((timeout--) == 0) {
+#ifdef DEBUG
+					printf ("PHY auto neg 0 failed...\n");
+#endif
+					return -1;
+				}
+
+				if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) !=
+				    0) {
+#ifdef DEBUG
+					printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
+#endif
+					return -1;
+				}
+			} while (!(phyStatus & 0x0004));
+
+#ifdef DEBUG
+			printf ("PHY auto neg complete! \n");
+#endif
+		}
+
+	}
+
+	/*
+	 * Enable FEC-Lite controller
+	 */
+	fec->eth->ecntrl |= 0x00000006;
+
+#ifdef DEBUG
+	if (fec->xcv_type != SEVENWIRE)
+		mpc8220_fec_phydump (dev->name);
+#endif
+
+	/*
+	 * Enable SmartDMA receive task
+	 */
+	DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
+
+#ifdef DEBUG
+	printf ("mpc8220_fec_init... Done \n");
+#endif
+
+	return 1;
+}
+
+/********************************************************************/
+static void mpc8220_fec_halt (struct eth_device *dev)
+{
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	int counter = 0xffff;
+
+#ifdef DEBUG
+	if (fec->xcv_type != SEVENWIRE)
+		mpc8220_fec_phydump (dev->name);
+#endif
+
+	/*
+	 * mask FEC chip interrupts
+	 */
+	fec->eth->imask = 0;
+
+	/*
+	 * issue graceful stop command to the FEC transmitter if necessary
+	 */
+	fec->eth->x_cntrl |= 0x00000001;
+
+	/*
+	 * wait for graceful stop to register
+	 */
+	while ((counter--) && (!(fec->eth->ievent & 0x10000000)));
+
+	/*
+	 * Disable SmartDMA tasks
+	 */
+	DMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
+	DMA_TASK_DISABLE (FEC_RECV_TASK_NO);
+
+	/*
+	 * Disable the Ethernet Controller
+	 */
+	fec->eth->ecntrl &= 0xfffffffd;
+
+	/*
+	 * Clear FIFO status registers
+	 */
+	fec->eth->rfifo_status &= 0x00700000;
+	fec->eth->tfifo_status &= 0x00700000;
+
+	fec->eth->reset_cntrl = 0x01000000;
+
+	/*
+	 * Issue a reset command to the FEC chip
+	 */
+	fec->eth->ecntrl |= 0x1;
+
+	/*
+	 * wait at least 16 clock cycles
+	 */
+	udelay (10);
+
+#ifdef DEBUG
+	printf ("Ethernet task stopped\n");
+#endif
+}
+
+#ifdef DEBUG
+/********************************************************************/
+
+static void tfifo_print (char *devname, mpc8220_fec_priv * fec)
+{
+	u16 phyAddr = CONFIG_PHY_ADDR;
+	u16 phyStatus;
+
+	if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
+	    || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
+
+		miiphy_read (devname, phyAddr, 0x1, &phyStatus);
+		printf ("\nphyStatus: 0x%04x\n", phyStatus);
+		printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl);
+		printf ("ievent:   0x%08x\n", fec->eth->ievent);
+		printf ("x_status: 0x%08x\n", fec->eth->x_status);
+		printf ("tfifo: status	0x%08x\n", fec->eth->tfifo_status);
+
+		printf ("	control 0x%08x\n", fec->eth->tfifo_cntrl);
+		printf ("	lrfp	0x%08x\n", fec->eth->tfifo_lrf_ptr);
+		printf ("	lwfp	0x%08x\n", fec->eth->tfifo_lwf_ptr);
+		printf ("	alarm	0x%08x\n", fec->eth->tfifo_alarm);
+		printf ("	readptr 0x%08x\n", fec->eth->tfifo_rdptr);
+		printf ("	writptr 0x%08x\n", fec->eth->tfifo_wrptr);
+	}
+}
+
+static void rfifo_print (char *devname, mpc8220_fec_priv * fec)
+{
+	u16 phyAddr = CONFIG_PHY_ADDR;
+	u16 phyStatus;
+
+	if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
+	    || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
+
+		miiphy_read (devname, phyAddr, 0x1, &phyStatus);
+		printf ("\nphyStatus: 0x%04x\n", phyStatus);
+		printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl);
+		printf ("ievent:   0x%08x\n", fec->eth->ievent);
+		printf ("x_status: 0x%08x\n", fec->eth->x_status);
+		printf ("rfifo: status	0x%08x\n", fec->eth->rfifo_status);
+
+		printf ("	control 0x%08x\n", fec->eth->rfifo_cntrl);
+		printf ("	lrfp	0x%08x\n", fec->eth->rfifo_lrf_ptr);
+		printf ("	lwfp	0x%08x\n", fec->eth->rfifo_lwf_ptr);
+		printf ("	alarm	0x%08x\n", fec->eth->rfifo_alarm);
+		printf ("	readptr 0x%08x\n", fec->eth->rfifo_rdptr);
+		printf ("	writptr 0x%08x\n", fec->eth->rfifo_wrptr);
+	}
+}
+#endif /* DEBUG */
+
+/********************************************************************/
+
+static int mpc8220_fec_send (struct eth_device *dev, volatile void *eth_data,
+			     int data_length)
+{
+	/*
+	 * This routine transmits one frame.  This routine only accepts
+	 * 6-byte Ethernet addresses.
+	 */
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	FEC_TBD *pTbd;
+
+#ifdef DEBUG
+	printf ("tbd status: 0x%04x\n", fec->tbdBase[0].status);
+	tfifo_print (dev->name, fec);
+#endif
+
+	/*
+	 * Clear Tx BD ring at first
+	 */
+	mpc8220_fec_tbd_scrub (fec);
+
+	/*
+	 * Check for valid length of data.
+	 */
+	if ((data_length > 1500) || (data_length <= 0)) {
+		return -1;
+	}
+
+	/*
+	 * Check the number of vacant TxBDs.
+	 */
+	if (fec->cleanTbdNum < 1) {
+#ifdef DEBUG
+		printf ("No available TxBDs ...\n");
+#endif
+		return -1;
+	}
+
+	/*
+	 * Get the first TxBD to send the mac header
+	 */
+	pTbd = &fec->tbdBase[fec->tbdIndex];
+	pTbd->dataLength = data_length;
+	pTbd->dataPointer = (u32) eth_data;
+	pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+	fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
+
+#ifdef DEBUG
+	printf ("DMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
+#endif
+
+	/*
+	 * Kick the MII i/f
+	 */
+	if (fec->xcv_type != SEVENWIRE) {
+		u16 phyStatus;
+
+		miiphy_read (dev->name, 0, 0x1, &phyStatus);
+	}
+
+	/*
+	 * Enable SmartDMA transmit task
+	 */
+
+#ifdef DEBUG
+	tfifo_print (dev->name, fec);
+#endif
+
+	DMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
+
+#ifdef DEBUG
+	tfifo_print (dev->name, fec);
+#endif
+
+#ifdef DEBUG
+	printf ("+");
+#endif
+
+	fec->cleanTbdNum -= 1;
+
+#ifdef DEBUG
+	printf ("smartDMA ethernet Tx task enabled\n");
+#endif
+	/*
+	 * wait until frame is sent .
+	 */
+	while (pTbd->status & FEC_TBD_READY) {
+		udelay (10);
+#ifdef DEBUG
+		printf ("TDB status = %04x\n", pTbd->status);
+#endif
+	}
+
+	return 0;
+}
+
+
+/********************************************************************/
+static int mpc8220_fec_recv (struct eth_device *dev)
+{
+	/*
+	 * This command pulls one frame from the card
+	 */
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
+	unsigned long ievent;
+	int frame_length, len = 0;
+	NBUF *frame;
+
+#ifdef DEBUG
+	printf ("mpc8220_fec_recv %d Start...\n", fec->rbdIndex);
+	printf ("-");
+#endif
+
+	/*
+	 * Check if any critical events have happened
+	 */
+	ievent = fec->eth->ievent;
+	fec->eth->ievent = ievent;
+	if (ievent & 0x20060000) {
+		/* BABT, Rx/Tx FIFO errors */
+		mpc8220_fec_halt (dev);
+		mpc8220_fec_init (dev, NULL);
+		return 0;
+	}
+	if (ievent & 0x80000000) {
+		/* Heartbeat error */
+		fec->eth->x_cntrl |= 0x00000001;
+	}
+	if (ievent & 0x10000000) {
+		/* Graceful stop complete */
+		if (fec->eth->x_cntrl & 0x00000001) {
+			mpc8220_fec_halt (dev);
+			fec->eth->x_cntrl &= ~0x00000001;
+			mpc8220_fec_init (dev, NULL);
+		}
+	}
+
+	if (!(pRbd->status & FEC_RBD_EMPTY)) {
+		if ((pRbd->status & FEC_RBD_LAST)
+		    && !(pRbd->status & FEC_RBD_ERR)
+		    && ((pRbd->dataLength - 4) > 14)) {
+
+			/*
+			 * Get buffer address and size
+			 */
+			frame = (NBUF *) pRbd->dataPointer;
+			frame_length = pRbd->dataLength - 4;
+
+#if (0)
+			{
+				int i;
+
+				printf ("recv data hdr:");
+				for (i = 0; i < 14; i++)
+					printf ("%x ", *(frame->head + i));
+				printf ("\n");
+			}
+#endif
+			/*
+			 *  Fill the buffer and pass it to upper layers
+			 */
+/*			memcpy(buff, frame->head, 14);
+			memcpy(buff + 14, frame->data, frame_length);*/
+			NetReceive ((volatile uchar *) pRbd->dataPointer,
+				    frame_length);
+			len = frame_length;
+		}
+		/*
+		 * Reset buffer descriptor as empty
+		 */
+		mpc8220_fec_rbd_clean (fec, pRbd);
+	}
+	DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+	return len;
+}
+
+
+/********************************************************************/
+int mpc8220_fec_initialize (bd_t * bis)
+{
+	mpc8220_fec_priv *fec;
+
+#ifdef CONFIG_HAS_ETH1
+	mpc8220_fec_priv *fec2;
+#endif
+	struct eth_device *dev;
+	char *tmp, *end;
+	char env_enetaddr[6];
+
+#ifdef CONFIG_HAS_ETH1
+	char env_enet1addr[6];
+#endif
+	int i;
+
+	fec = (mpc8220_fec_priv *) malloc (sizeof (*fec));
+	dev = (struct eth_device *) malloc (sizeof (*dev));
+	memset (dev, 0, sizeof *dev);
+
+	fec->eth = (ethernet_regs *) MMAP_FEC1;
+#ifdef CONFIG_HAS_ETH1
+	fec2 = (mpc8220_fec_priv *) malloc (sizeof (*fec));
+	fec2->eth = (ethernet_regs *) MMAP_FEC2;
+#endif
+	fec->tbdBase = (FEC_TBD *) FEC_BD_BASE;
+	fec->rbdBase =
+		(FEC_RBD *) (FEC_BD_BASE + FEC_TBD_NUM * sizeof (FEC_TBD));
+	fec->xcv_type = MII100;
+
+	dev->priv = (void *) fec;
+	dev->iobase = MMAP_FEC1;
+	dev->init = mpc8220_fec_init;
+	dev->halt = mpc8220_fec_halt;
+	dev->send = mpc8220_fec_send;
+	dev->recv = mpc8220_fec_recv;
+
+	sprintf (dev->name, "FEC ETHERNET");
+	eth_register (dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register (dev->name,
+			fec8220_miiphy_read, fec8220_miiphy_write);
+#endif
+
+	/*
+	 * Try to set the mac address now. The fec mac address is
+	 * a garbage after reset. When not using fec for booting
+	 * the Linux fec driver will try to work with this garbage.
+	 */
+	tmp = getenv ("ethaddr");
+	if (tmp) {
+		for (i = 0; i < 6; i++) {
+			env_enetaddr[i] =
+				tmp ? simple_strtoul (tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+		mpc8220_fec_set_hwaddr (fec, env_enetaddr);
+	}
+#ifdef CONFIG_HAS_ETH1
+	tmp = getenv ("eth1addr");
+	if (tmp) {
+		for (i = 0; i < 6; i++) {
+			env_enet1addr[i] =
+				tmp ? simple_strtoul (tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+		mpc8220_fec_set_hwaddr (fec2, env_enet1addr);
+	}
+#endif
+
+	return 1;
+}
+
+/* MII-interface related functions */
+/********************************************************************/
+int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal)
+{
+	ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1;
+	u32 reg;		/* convenient holder for the PHY register */
+	u32 phy;		/* convenient holder for the PHY */
+	int timeout = 0xffff;
+
+	/*
+	 * reading from any PHY's register is done by properly
+	 * programming the FEC's MII data register.
+	 */
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	eth->mii_data =
+		(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy
+		 | reg);
+
+	/*
+	 * wait for the related interrupt
+	 */
+	while ((timeout--) && (!(eth->ievent & 0x00800000)));
+
+	if (timeout == 0) {
+#ifdef DEBUG
+		printf ("Read MDIO failed...\n");
+#endif
+		return -1;
+	}
+
+	/*
+	 * clear mii interrupt bit
+	 */
+	eth->ievent = 0x00800000;
+
+	/*
+	 * it's now safe to read the PHY's register
+	 */
+	*retVal = (u16) eth->mii_data;
+
+	return 0;
+}
+
+/********************************************************************/
+int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data)
+{
+	ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1;
+	u32 reg;		/* convenient holder for the PHY register */
+	u32 phy;		/* convenient holder for the PHY */
+	int timeout = 0xffff;
+
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+			 FEC_MII_DATA_TA | phy | reg | data);
+
+	/*
+	 * wait for the MII interrupt
+	 */
+	while ((timeout--) && (!(eth->ievent & 0x00800000)));
+
+	if (timeout == 0) {
+#ifdef DEBUG
+		printf ("Write MDIO failed...\n");
+#endif
+		return -1;
+	}
+
+	/*
+	 * clear MII interrupt bit
+	 */
+	eth->ievent = 0x00800000;
+
+	return 0;
+}
+
+#ifdef DEBUG
+static u32 local_crc32 (char *string, unsigned int crc_value, int len)
+{
+	int i;
+	char c;
+	unsigned int crc, count;
+
+	/*
+	 * crc32 algorithm
+	 */
+	/*
+	 * crc = 0xffffffff; * The initialized value should be 0xffffffff
+	 */
+	crc = crc_value;
+
+	for (i = len; --i >= 0;) {
+		c = *string++;
+		for (count = 0; count < 8; count++) {
+			if ((c & 0x01) ^ (crc & 0x01)) {
+				crc >>= 1;
+				crc = crc ^ 0xedb88320;
+			} else {
+				crc >>= 1;
+			}
+			c >>= 1;
+		}
+	}
+
+	/*
+	 * In big endian system, do byte swaping for crc value
+	 */
+	return crc;
+}
+#endif /* DEBUG */
+
+#endif /* CONFIG_MPC8220_FEC */
diff --git a/arch/ppc/cpu/mpc8220/fec.h b/arch/ppc/cpu/mpc8220/fec.h
new file mode 100644
index 0000000..a8927fc
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/fec.h
@@ -0,0 +1,283 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * odin ethernet header file
+ */
+
+#ifndef __MPC8220_FEC_H
+#define __MPC8220_FEC_H
+
+#include <common.h>
+#include <mpc8220.h>
+#include "dma.h"
+
+typedef struct ethernet_register_set {
+
+/* [10:2]addr = 00 */
+
+/*  Control and status Registers (offset 000-1FF) */
+
+	volatile u32 fec_id;		/* MBAR_ETH + 0x000 */
+	volatile u32 ievent;		/* MBAR_ETH + 0x004 */
+	volatile u32 imask;		/* MBAR_ETH + 0x008 */
+
+	volatile u32 RES0[1];		/* MBAR_ETH + 0x00C */
+	volatile u32 r_des_active;	/* MBAR_ETH + 0x010 */
+	volatile u32 x_des_active;	/* MBAR_ETH + 0x014 */
+	volatile u32 r_des_active_cl;	/* MBAR_ETH + 0x018 */
+	volatile u32 x_des_active_cl;	/* MBAR_ETH + 0x01C */
+	volatile u32 ivent_set;		/* MBAR_ETH + 0x020 */
+	volatile u32 ecntrl;		/* MBAR_ETH + 0x024 */
+
+	volatile u32 RES1[6];		/* MBAR_ETH + 0x028-03C */
+	volatile u32 mii_data;		/* MBAR_ETH + 0x040 */
+	volatile u32 mii_speed;		/* MBAR_ETH + 0x044 */
+	volatile u32 mii_status;	/* MBAR_ETH + 0x048 */
+
+	volatile u32 RES2[5];		/* MBAR_ETH + 0x04C-05C */
+	volatile u32 mib_data;		/* MBAR_ETH + 0x060 */
+	volatile u32 mib_control;	/* MBAR_ETH + 0x064 */
+
+	volatile u32 RES3[6];		/* MBAR_ETH + 0x068-7C */
+	volatile u32 r_activate;	/* MBAR_ETH + 0x080 */
+	volatile u32 r_cntrl;		/* MBAR_ETH + 0x084 */
+	volatile u32 r_hash;		/* MBAR_ETH + 0x088 */
+	volatile u32 r_data;		/* MBAR_ETH + 0x08C */
+	volatile u32 ar_done;		/* MBAR_ETH + 0x090 */
+	volatile u32 r_test;		/* MBAR_ETH + 0x094 */
+	volatile u32 r_mib;		/* MBAR_ETH + 0x098 */
+	volatile u32 r_da_low;		/* MBAR_ETH + 0x09C */
+	volatile u32 r_da_high;		/* MBAR_ETH + 0x0A0 */
+
+	volatile u32 RES4[7];		/* MBAR_ETH + 0x0A4-0BC */
+	volatile u32 x_activate;	/* MBAR_ETH + 0x0C0 */
+	volatile u32 x_cntrl;		/* MBAR_ETH + 0x0C4 */
+	volatile u32 backoff;		/* MBAR_ETH + 0x0C8 */
+	volatile u32 x_data;		/* MBAR_ETH + 0x0CC */
+	volatile u32 x_status;		/* MBAR_ETH + 0x0D0 */
+	volatile u32 x_mib;		/* MBAR_ETH + 0x0D4 */
+	volatile u32 x_test;		/* MBAR_ETH + 0x0D8 */
+	volatile u32 fdxfc_da1;		/* MBAR_ETH + 0x0DC */
+	volatile u32 fdxfc_da2;		/* MBAR_ETH + 0x0E0 */
+	volatile u32 paddr1;		/* MBAR_ETH + 0x0E4 */
+	volatile u32 paddr2;		/* MBAR_ETH + 0x0E8 */
+	volatile u32 op_pause;		/* MBAR_ETH + 0x0EC */
+
+	volatile u32 RES5[4];		/* MBAR_ETH + 0x0F0-0FC */
+	volatile u32 instr_reg;		/* MBAR_ETH + 0x100 */
+	volatile u32 context_reg;	/* MBAR_ETH + 0x104 */
+	volatile u32 test_cntrl;	/* MBAR_ETH + 0x108 */
+	volatile u32 acc_reg;		/* MBAR_ETH + 0x10C */
+	volatile u32 ones;		/* MBAR_ETH + 0x110 */
+	volatile u32 zeros;		/* MBAR_ETH + 0x114 */
+	volatile u32 iaddr1;		/* MBAR_ETH + 0x118 */
+	volatile u32 iaddr2;		/* MBAR_ETH + 0x11C */
+	volatile u32 gaddr1;		/* MBAR_ETH + 0x120 */
+	volatile u32 gaddr2;		/* MBAR_ETH + 0x124 */
+	volatile u32 random;		/* MBAR_ETH + 0x128 */
+	volatile u32 rand1;		/* MBAR_ETH + 0x12C */
+	volatile u32 tmp;		/* MBAR_ETH + 0x130 */
+
+	volatile u32 RES6[3];		/* MBAR_ETH + 0x134-13C */
+	volatile u32 fifo_id;		/* MBAR_ETH + 0x140 */
+	volatile u32 x_wmrk;		/* MBAR_ETH + 0x144 */
+	volatile u32 fcntrl;		/* MBAR_ETH + 0x148 */
+	volatile u32 r_bound;		/* MBAR_ETH + 0x14C */
+	volatile u32 r_fstart;		/* MBAR_ETH + 0x150 */
+	volatile u32 r_count;		/* MBAR_ETH + 0x154 */
+	volatile u32 r_lag;		/* MBAR_ETH + 0x158 */
+	volatile u32 r_read;		/* MBAR_ETH + 0x15C */
+	volatile u32 r_write;		/* MBAR_ETH + 0x160 */
+	volatile u32 x_count;		/* MBAR_ETH + 0x164 */
+	volatile u32 x_lag;		/* MBAR_ETH + 0x168 */
+	volatile u32 x_retry;		/* MBAR_ETH + 0x16C */
+	volatile u32 x_write;		/* MBAR_ETH + 0x170 */
+	volatile u32 x_read;		/* MBAR_ETH + 0x174 */
+
+	volatile u32 RES7[2];		/* MBAR_ETH + 0x178-17C */
+	volatile u32 fm_cntrl;		/* MBAR_ETH + 0x180 */
+	volatile u32 rfifo_data;	/* MBAR_ETH + 0x184 */
+	volatile u32 rfifo_status;	/* MBAR_ETH + 0x188 */
+	volatile u32 rfifo_cntrl;	/* MBAR_ETH + 0x18C */
+	volatile u32 rfifo_lrf_ptr;	/* MBAR_ETH + 0x190 */
+	volatile u32 rfifo_lwf_ptr;	/* MBAR_ETH + 0x194 */
+	volatile u32 rfifo_alarm;	/* MBAR_ETH + 0x198 */
+	volatile u32 rfifo_rdptr;	/* MBAR_ETH + 0x19C */
+	volatile u32 rfifo_wrptr;	/* MBAR_ETH + 0x1A0 */
+	volatile u32 tfifo_data;	/* MBAR_ETH + 0x1A4 */
+	volatile u32 tfifo_status;	/* MBAR_ETH + 0x1A8 */
+	volatile u32 tfifo_cntrl;	/* MBAR_ETH + 0x1AC */
+	volatile u32 tfifo_lrf_ptr;	/* MBAR_ETH + 0x1B0 */
+	volatile u32 tfifo_lwf_ptr;	/* MBAR_ETH + 0x1B4 */
+	volatile u32 tfifo_alarm;	/* MBAR_ETH + 0x1B8 */
+	volatile u32 tfifo_rdptr;	/* MBAR_ETH + 0x1BC */
+	volatile u32 tfifo_wrptr;	/* MBAR_ETH + 0x1C0 */
+
+	volatile u32 reset_cntrl;	/* MBAR_ETH + 0x1C4 */
+	volatile u32 xmit_fsm;		/* MBAR_ETH + 0x1C8 */
+
+	volatile u32 RES8[3];		/* MBAR_ETH + 0x1CC-1D4 */
+	volatile u32 rdes_data0;	/* MBAR_ETH + 0x1D8 */
+	volatile u32 rdes_data1;	/* MBAR_ETH + 0x1DC */
+	volatile u32 r_length;		/* MBAR_ETH + 0x1E0 */
+	volatile u32 x_length;		/* MBAR_ETH + 0x1E4 */
+	volatile u32 x_addr;		/* MBAR_ETH + 0x1E8 */
+	volatile u32 cdes_data;		/* MBAR_ETH + 0x1EC */
+	volatile u32 status;		/* MBAR_ETH + 0x1F0 */
+	volatile u32 dma_control;	/* MBAR_ETH + 0x1F4 */
+	volatile u32 des_cmnd;		/* MBAR_ETH + 0x1F8 */
+	volatile u32 data;		/* MBAR_ETH + 0x1FC */
+
+	/*  MIB COUNTERS (Offset 200-2FF) */
+
+	volatile u32 rmon_t_drop;	/* MBAR_ETH + 0x200 */
+	volatile u32 rmon_t_packets;	/* MBAR_ETH + 0x204 */
+	volatile u32 rmon_t_bc_pkt;	/* MBAR_ETH + 0x208 */
+	volatile u32 rmon_t_mc_pkt;	/* MBAR_ETH + 0x20C */
+	volatile u32 rmon_t_crc_align;	/* MBAR_ETH + 0x210 */
+	volatile u32 rmon_t_undersize;	/* MBAR_ETH + 0x214 */
+	volatile u32 rmon_t_oversize;	/* MBAR_ETH + 0x218 */
+	volatile u32 rmon_t_frag;	/* MBAR_ETH + 0x21C */
+	volatile u32 rmon_t_jab;	/* MBAR_ETH + 0x220 */
+	volatile u32 rmon_t_col;	/* MBAR_ETH + 0x224 */
+	volatile u32 rmon_t_p64;	/* MBAR_ETH + 0x228 */
+	volatile u32 rmon_t_p65to127;	/* MBAR_ETH + 0x22C */
+	volatile u32 rmon_t_p128to255;	/* MBAR_ETH + 0x230 */
+	volatile u32 rmon_t_p256to511;	/* MBAR_ETH + 0x234 */
+	volatile u32 rmon_t_p512to1023;	/* MBAR_ETH + 0x238 */
+	volatile u32 rmon_t_p1024to2047;/* MBAR_ETH + 0x23C */
+	volatile u32 rmon_t_p_gte2048;	/* MBAR_ETH + 0x240 */
+	volatile u32 rmon_t_octets;	/* MBAR_ETH + 0x244 */
+	volatile u32 ieee_t_drop;	/* MBAR_ETH + 0x248 */
+	volatile u32 ieee_t_frame_ok;	/* MBAR_ETH + 0x24C */
+	volatile u32 ieee_t_1col;	/* MBAR_ETH + 0x250 */
+	volatile u32 ieee_t_mcol;	/* MBAR_ETH + 0x254 */
+	volatile u32 ieee_t_def;	/* MBAR_ETH + 0x258 */
+	volatile u32 ieee_t_lcol;	/* MBAR_ETH + 0x25C */
+	volatile u32 ieee_t_excol;	/* MBAR_ETH + 0x260 */
+	volatile u32 ieee_t_macerr;	/* MBAR_ETH + 0x264 */
+	volatile u32 ieee_t_cserr;	/* MBAR_ETH + 0x268 */
+	volatile u32 ieee_t_sqe;	/* MBAR_ETH + 0x26C */
+	volatile u32 t_fdxfc;		/* MBAR_ETH + 0x270 */
+	volatile u32 ieee_t_octets_ok;	/* MBAR_ETH + 0x274 */
+
+	volatile u32 RES9[2];		/* MBAR_ETH + 0x278-27C */
+	volatile u32 rmon_r_drop;	/* MBAR_ETH + 0x280 */
+	volatile u32 rmon_r_packets;	/* MBAR_ETH + 0x284 */
+	volatile u32 rmon_r_bc_pkt;	/* MBAR_ETH + 0x288 */
+	volatile u32 rmon_r_mc_pkt;	/* MBAR_ETH + 0x28C */
+	volatile u32 rmon_r_crc_align;	/* MBAR_ETH + 0x290 */
+	volatile u32 rmon_r_undersize;	/* MBAR_ETH + 0x294 */
+	volatile u32 rmon_r_oversize;	/* MBAR_ETH + 0x298 */
+	volatile u32 rmon_r_frag;	/* MBAR_ETH + 0x29C */
+	volatile u32 rmon_r_jab;	/* MBAR_ETH + 0x2A0 */
+
+	volatile u32 rmon_r_resvd_0;	/* MBAR_ETH + 0x2A4 */
+
+	volatile u32 rmon_r_p64;	/* MBAR_ETH + 0x2A8 */
+	volatile u32 rmon_r_p65to127;	/* MBAR_ETH + 0x2AC */
+	volatile u32 rmon_r_p128to255;	/* MBAR_ETH + 0x2B0 */
+	volatile u32 rmon_r_p256to511;	/* MBAR_ETH + 0x2B4 */
+	volatile u32 rmon_r_p512to1023;	/* MBAR_ETH + 0x2B8 */
+	volatile u32 rmon_r_p1024to2047;/* MBAR_ETH + 0x2BC */
+	volatile u32 rmon_r_p_gte2048;	/* MBAR_ETH + 0x2C0 */
+	volatile u32 rmon_r_octets;	/* MBAR_ETH + 0x2C4 */
+	volatile u32 ieee_r_drop;	/* MBAR_ETH + 0x2C8 */
+	volatile u32 ieee_r_frame_ok;	/* MBAR_ETH + 0x2CC */
+	volatile u32 ieee_r_crc;	/* MBAR_ETH + 0x2D0 */
+	volatile u32 ieee_r_align;	/* MBAR_ETH + 0x2D4 */
+	volatile u32 r_macerr;		/* MBAR_ETH + 0x2D8 */
+	volatile u32 r_fdxfc;		/* MBAR_ETH + 0x2DC */
+	volatile u32 ieee_r_octets_ok;	/* MBAR_ETH + 0x2E0 */
+
+	volatile u32 RES10[6];		/* MBAR_ETH + 0x2E4-2FC */
+
+	volatile u32 RES11[64];		/* MBAR_ETH + 0x300-3FF */
+} ethernet_regs;
+
+/* Receive & Transmit Buffer Descriptor definitions */
+typedef struct BufferDescriptor {
+	u16 status;
+	u16 dataLength;
+	u32 dataPointer;
+} FEC_RBD;
+
+typedef struct {
+	u16 status;
+	u16 dataLength;
+	u32 dataPointer;
+} FEC_TBD;
+
+/* private structure */
+typedef enum {
+	SEVENWIRE,		/* 7-wire       */
+	MII10,			/* MII 10Mbps   */
+	MII100			/* MII 100Mbps  */
+} xceiver_type;
+
+typedef struct {
+	ethernet_regs *eth;
+	xceiver_type xcv_type;	/* transceiver type */
+	FEC_RBD *rbdBase;	/* RBD ring */
+	FEC_TBD *tbdBase;	/* TBD ring */
+	u16 rbdIndex;		/* next receive BD to read */
+	u16 tbdIndex;		/* next transmit BD to send */
+	u16 usedTbdIndex;	/* next transmit BD to clean */
+	u16 cleanTbdNum;	/* the number of available transmit BDs */
+} mpc8220_fec_priv;
+
+/* Ethernet parameter area */
+#define FEC_TBD_BASE	    (FEC_PARAM_BASE + 0x00)
+#define FEC_TBD_NEXT	    (FEC_PARAM_BASE + 0x04)
+#define FEC_RBD_BASE	    (FEC_PARAM_BASE + 0x08)
+#define FEC_RBD_NEXT	    (FEC_PARAM_BASE + 0x0c)
+
+/* BD Numer definitions */
+#define FEC_TBD_NUM	   48	/* The user can adjust this value */
+#define FEC_RBD_NUM	   32	/* The user can adjust this value */
+
+/* packet size limit */
+#define FEC_MAX_PKT_SIZE   1536
+
+/* RBD bits definitions */
+#define FEC_RBD_EMPTY	0x8000	/* Buffer is empty */
+#define FEC_RBD_WRAP	0x2000	/* Last BD in ring */
+#define FEC_RBD_INT	0x1000	/* Interrupt */
+#define FEC_RBD_LAST	0x0800	/* Buffer is last in frame(useless) */
+#define FEC_RBD_MISS	0x0100	/* Miss bit for prom mode */
+#define FEC_RBD_BC	0x0080	/* The received frame is broadcast frame */
+#define FEC_RBD_MC	0x0040	/* The received frame is multicast frame */
+#define FEC_RBD_LG	0x0020	/* Frame length violation */
+#define FEC_RBD_NO	0x0010	/* Nonoctet align frame */
+#define FEC_RBD_SH	0x0008	/* Short frame */
+#define FEC_RBD_CR	0x0004	/* CRC error */
+#define FEC_RBD_OV	0x0002	/* Receive FIFO overrun */
+#define FEC_RBD_TR	0x0001	/* Frame is truncated */
+#define FEC_RBD_ERR	(FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+			 FEC_RBD_OV | FEC_RBD_TR)
+
+/* TBD bits definitions */
+#define FEC_TBD_READY	0x8000	/* Buffer is ready */
+#define FEC_TBD_WRAP	0x2000	/* Last BD in ring */
+#define FEC_TBD_INT	0x1000	/* Interrupt */
+#define FEC_TBD_LAST	0x0800	/* Buffer is last in frame */
+#define FEC_TBD_TC	0x0400	/* Transmit the CRC */
+#define FEC_TBD_ABC	0x0200	/* Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST		0x40000000	/* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform a read operation */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register field mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x0000ffff	/* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT	18	/* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT	23	/* MII PHY address bits */
+
+#endif /* __MPC8220_FEC_H */
diff --git a/arch/ppc/cpu/mpc8220/fec_dma_tasks.S b/arch/ppc/cpu/mpc8220/fec_dma_tasks.S
new file mode 100644
index 0000000..3f8a03b
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/fec_dma_tasks.S
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2004, Freescale Semiconductor, Inc.
+ *
+ * This file contains microcode for the FEC controller of the MPC8220.
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_MPC8220)
+
+/* sas/sccg, gas target */
+.section        smartdmaInitData,"aw",@progbits	/* Initialized data for task variables */
+.section        smartdmaTaskTable,"aw",@progbits	/* Task tables */
+.align  9
+.globl taskTable
+taskTable:
+.globl scEthernetRecv_Entry
+scEthernetRecv_Entry:		/* Task 0 */
+.long   scEthernetRecv_TDT - taskTable	/* Task 0 Descriptor Table */
+.long   scEthernetRecv_TDT - taskTable + 0x00000094
+.long   scEthernetRecv_VarTab - taskTable	/* Task 0 Variable Table */
+.long   scEthernetRecv_FDT - taskTable + 0x03	/* Task 0 Function Descriptor Table & Flags */
+.long   0x00000000
+.long   0x00000000
+.long   scEthernetRecv_CSave - taskTable	/* Task 0 context save space */
+.long   0xf0000000
+.globl scEthernetXmit_Entry
+scEthernetXmit_Entry:		/* Task 1 */
+.long   scEthernetXmit_TDT - taskTable	/* Task 1 Descriptor Table */
+.long   scEthernetXmit_TDT - taskTable + 0x000000e0
+.long   scEthernetXmit_VarTab - taskTable	/* Task 1 Variable Table */
+.long   scEthernetXmit_FDT - taskTable + 0x03	/* Task 1 Function Descriptor Table & Flags */
+.long   0x00000000
+.long   0x00000000
+.long   scEthernetXmit_CSave - taskTable	/* Task 1 context save space */
+.long   0xf0000000
+
+
+.globl scEthernetRecv_TDT
+scEthernetRecv_TDT:	/* Task 0 Descriptor Table */
+.long   0xc4c50000	/* 0000(153):  LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */
+.long   0x84c5e000	/* 0004(153):  LCD: idx1 = var9 + var11; ; idx1 += inc0 */
+.long   0x10001f08	/* 0008(156):    DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x10000380	/* 000C(157):    DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f88	/* 0010(158):    DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0x81980000	/* 0014(162):  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long   0x10000780	/* 0018(164):    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 001C(165):    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x010cf04c	/* 0020(165):    DRD2B1: var4 = EU3(); EU3(var1,var12)  */
+.long   0x82180349	/* 0024(169):  LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */
+.long   0x81c68004	/* 0028(172):    LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */
+.long   0x70000000	/* 002C(174):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x018cf04e	/* 0030(174):      DRD2B1: var6 = EU3(); EU3(var1,var14)  */
+.long   0x70000000	/* 0034(175):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x020cf04f	/* 0038(175):      DRD2B1: var8 = EU3(); EU3(var1,var15)  */
+.long   0x00000b88	/* 003C(176):      DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0x80025184	/* 0040(205):    LCDEXT: idx1 = 0xf0009184; ; */
+.long   0x86810412	/* 0044(205):    LCD: idx2 = var13, idx3 = var2; idx2 < var16; idx2 += inc2, idx3 += inc2 */
+.long   0x0200cf88	/* 0048(209):      DRD1A: *idx3 = *idx1; FN=0 init=16 WS=0 RS=0 */
+.long   0x80025184	/* 004C(217):    LCDEXT: idx1 = 0xf0009184; ; */
+.long   0x8681845b	/* 0050(217):    LCD: idx2 = var13, idx3 = var3; idx2 < var17; idx2 += inc3, idx3 += inc3 */
+.long   0x0000cf88	/* 0054(221):      DRD1A: *idx3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0xc31883a4	/* 0058(225):    LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc4 */
+.long   0x80190000	/* 005C(225):    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long   0x04008468	/* 0060(227):      DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */
+.long   0xc4038360	/* 0064(232):    LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc4, idx2 += inc0 */
+.long   0x81c50000	/* 0068(233):    LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */
+.long   0x1000cb18	/* 006C(235):      DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f18	/* 0070(236):      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long   0xc418836d	/* 0074(238):    LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc5 */
+.long   0x83990000	/* 0078(238):    LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */
+.long   0x10000c00	/* 007C(240):      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x0000c800	/* 0080(241):      DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */
+.long   0x81988000	/* 0084(245):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x10000788	/* 0088(247):      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 008C(248):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x080cf04c	/* 0090(248):      DRD2B1: idx0 = EU3(); EU3(var1,var12)  */
+.long   0x000001f8	/* 0094(:0):    NOP */
+
+
+.globl scEthernetXmit_TDT
+scEthernetXmit_TDT:	/* Task 1 Descriptor Table */
+.long   0x80095b00	/* 0000(280):  LCDEXT: idx0 = 0xf0025b00; ; */
+.long   0x85c60004	/* 0004(280):  LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */
+.long   0x10002308	/* 0008(283):    DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x10000f88	/* 000C(284):    DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000380	/* 0010(285):    DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */
+.long   0x81980000	/* 0014(288):  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long   0x10000780	/* 0018(290):    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 001C(291):    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x024cf04d	/* 0020(291):    DRD2B1: var9 = EU3(); EU3(var1,var13)  */
+.long   0x84980309	/* 0024(294):  LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */
+.long   0xc0004003	/* 0028(297):    LCDEXT: idx1 = 0x00000003; ; */
+.long   0x81c60004	/* 002C(297):    LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */
+.long   0x70000000	/* 0030(299):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x010cf04e	/* 0034(299):      DRD2B1: var4 = EU3(); EU3(var1,var14)  */
+.long   0x70000000	/* 0038(300):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x014cf04f	/* 003C(300):      DRD2B1: var5 = EU3(); EU3(var1,var15)  */
+.long   0x70000000	/* 0040(301):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x028cf050	/* 0044(301):      DRD2B1: var10 = EU3(); EU3(var1,var16)  */
+.long   0x70000000	/* 0048(302):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x018cf051	/* 004C(302):      DRD2B1: var6 = EU3(); EU3(var1,var17)  */
+.long   0x10000b90	/* 0050(303):      DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 0054(304):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x01ccf0a1	/* 0058(304):      DRD2B1: var7 = EU3(); EU3(var2,idx1)  */
+.long   0xc2988312	/* 005C(308):    LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */
+.long   0x83490000	/* 0060(308):    LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */
+.long   0x00001b10	/* 0064(310):      DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */
+.long   0x800251a4	/* 0068(315):    LCDEXT: idx1 = 0xf00091a4; ; */
+.long   0xc30104dc	/* 006C(315):    LCDEXT: idx2 = var6, idx3 = var2; idx2 >= var19; idx2 += inc3, idx3 += inc4 */
+.long   0x839a032d	/* 0070(316):    LCD: idx4 = var7; idx4 == var12; idx4 += inc5 */
+.long   0x0220c798	/* 0074(321):      DRD1A: *idx1 = *idx3; FN=0 init=17 WS=0 RS=0 */
+.long   0x800251a4	/* 0078(329):    LCDEXT: idx1 = 0xf00091a4; ; */
+.long   0x99198337	/* 007C(329):    LCD: idx2 = idx2, idx3 = idx3; idx2 > var12; idx2 += inc6, idx3 += inc7 */
+.long   0x022ac798	/* 0080(333):      DRD1A: *idx1 = *idx3; FN=0 init=17 WS=1 RS=1 */
+.long   0x800251a4	/* 0084(350):    LCDEXT: idx1 = 0xf00091a4; ; */
+.long   0xc1430000	/* 0088(350):    LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */
+.long   0x82998312	/* 008C(351):    LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */
+.long   0x0a2ac790	/* 0090(354):      DRD1A: *idx1 = *idx2; FN=0 TFD init=17 WS=1 RS=1 */
+.long   0x81988000	/* 0094(359):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x60000002	/* 0098(361):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
+.long   0x0c4cfc4d	/* 009C(361):      DRD2B1: *idx1 = EU3(); EU3(*idx1,var13)  */
+.long   0xc21883ad	/* 00A0(365):    LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */
+.long   0x80190000	/* 00A4(365):    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long   0x04008460	/* 00A8(367):      DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */
+.long   0xc4052305	/* 00AC(371):    LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */
+.long   0x81ca0000	/* 00B0(372):    LCD: idx3 = var3 + var20; idx3 once var0; idx3 += inc0 */
+.long   0x1000c718	/* 00B4(374):      DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f18	/* 00B8(375):      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long   0xc4188000	/* 00BC(378):    LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */
+.long   0x85190312	/* 00C0(378):    LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */
+.long   0x10000c00	/* 00C4(380):      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x1000c400	/* 00C8(381):      DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00008860	/* 00CC(382):      DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */
+.long   0x81988000	/* 00D0(386):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x10000788	/* 00D4(388):      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 00D8(389):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x080cf04d	/* 00DC(389):      DRD2B1: idx0 = EU3(); EU3(var1,var13)  */
+.long   0x000001f8	/* 00E0(:0):    NOP */
+
+.align 8
+
+.globl scEthernetRecv_VarTab
+scEthernetRecv_VarTab:	/* Task 0 Variable Table */
+.long   0x00000000	/* var[0] */
+.long   0x00000000	/* var[1] */
+.long   0x00000000	/* var[2] */
+.long   0x00000000	/* var[3] */
+.long   0x00000000	/* var[4] */
+.long   0x00000000	/* var[5] */
+.long   0x00000000	/* var[6] */
+.long   0x00000000	/* var[7] */
+.long   0x00000000	/* var[8] */
+.long   0xf0025b00	/* var[9] */
+.long   0x00000008	/* var[10] */
+.long   0x0000000c	/* var[11] */
+.long   0x80000000	/* var[12] */
+.long   0x00000000	/* var[13] */
+.long   0x10000000	/* var[14] */
+.long   0x20000000	/* var[15] */
+.long   0x00000800	/* var[16] */
+.long   0x00000001	/* var[17] */
+.long   0x00000000	/* var[18] */
+.long   0x00000000	/* var[19] */
+.long   0x00000000	/* var[20] */
+.long   0x00000000	/* var[21] */
+.long   0x00000000	/* var[22] */
+.long   0x00000000	/* var[23] */
+.long   0x00000000	/* inc[0] */
+.long   0x60000000	/* inc[1] */
+.long   0x20000004	/* inc[2] */
+.long   0x20000001	/* inc[3] */
+.long   0x80000000	/* inc[4] */
+.long   0x40000000	/* inc[5] */
+.long   0x00000000	/* inc[6] */
+.long   0x00000000	/* inc[7] */
+
+.align  8
+
+.globl scEthernetXmit_VarTab
+scEthernetXmit_VarTab:	/* Task 1 Variable Table */
+.long   0x00000000	/* var[0] */
+.long   0x00000000	/* var[1] */
+.long   0x00000000	/* var[2] */
+.long   0x00000000	/* var[3] */
+.long   0x00000000	/* var[4] */
+.long   0x00000000	/* var[5] */
+.long   0x00000000	/* var[6] */
+.long   0x00000000	/* var[7] */
+.long   0x00000000	/* var[8] */
+.long   0x00000000	/* var[9] */
+.long   0x00000000	/* var[10] */
+.long   0xf0025b00	/* var[11] */
+.long   0x00000000	/* var[12] */
+.long   0x80000000	/* var[13] */
+.long   0x10000000	/* var[14] */
+.long   0x08000000	/* var[15] */
+.long   0x20000000	/* var[16] */
+.long   0x0000ffff	/* var[17] */
+.long   0xffffffff	/* var[18] */
+.long   0x00000004	/* var[19] */
+.long   0x00000008	/* var[20] */
+.long   0x00000000	/* var[21] */
+.long   0x00000000	/* var[22] */
+.long   0x00000000	/* var[23] */
+.long   0x00000000	/* inc[0] */
+.long   0x60000000	/* inc[1] */
+.long   0x40000000	/* inc[2] */
+.long   0xc000fffc	/* inc[3] */
+.long   0xe0000004	/* inc[4] */
+.long   0x80000000	/* inc[5] */
+.long   0x4000ffff	/* inc[6] */
+.long   0xe0000001	/* inc[7] */
+
+.align 8
+
+.globl scEthernetRecv_FDT
+scEthernetRecv_FDT:	/* Task 0 Function Descriptor Table */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x21800000	/* and(), EU# 3 */
+.long   0x21e00000	/* or(), EU# 3 */
+.long   0x21400000	/* andn(), EU# 3 */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+
+.align 8
+
+.globl scEthernetXmit_FDT
+scEthernetXmit_FDT:	/* Task 1 Function Descriptor Table */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x21800000	/* and(), EU# 3 */
+.long   0x21e00000	/* or(), EU# 3 */
+.long   0x21400000	/* andn(), EU# 3 */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+
+
+.globl scEthernetRecv_CSave
+scEthernetRecv_CSave:	/* Task 0 context save space */
+.space  128, 0x0
+
+
+.globl scEthernetXmit_CSave
+scEthernetXmit_CSave:	/* Task 1 context save space */
+.space  128, 0x0
+
+#endif
diff --git a/arch/ppc/cpu/mpc8220/i2c.c b/arch/ppc/cpu/mpc8220/i2c.c
new file mode 100644
index 0000000..76ecdf1
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/i2c.c
@@ -0,0 +1,390 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_HARD_I2C
+
+#include <mpc8220.h>
+#include <i2c.h>
+
+typedef struct mpc8220_i2c {
+	volatile u32 adr;	/* I2Cn + 0x00 */
+	volatile u32 fdr;	/* I2Cn + 0x04 */
+	volatile u32 cr;	/* I2Cn + 0x08 */
+	volatile u32 sr;	/* I2Cn + 0x0C */
+	volatile u32 dr;	/* I2Cn + 0x10 */
+} i2c_t;
+
+/* I2Cn control register bits */
+#define I2C_EN      0x80
+#define I2C_IEN     0x40
+#define I2C_STA     0x20
+#define I2C_TX      0x10
+#define I2C_TXAK    0x08
+#define I2C_RSTA    0x04
+#define I2C_INIT_MASK   (I2C_EN | I2C_STA | I2C_TX | I2C_RSTA)
+
+/* I2Cn status register bits */
+#define I2C_CF      0x80
+#define I2C_AAS     0x40
+#define I2C_BB      0x20
+#define I2C_AL      0x10
+#define I2C_SRW     0x04
+#define I2C_IF      0x02
+#define I2C_RXAK    0x01
+
+#define I2C_TIMEOUT 100
+#define I2C_RETRIES 1
+
+struct mpc8220_i2c_tap {
+	int scl2tap;
+	int tap2tap;
+};
+
+static int mpc_reg_in (volatile u32 * reg);
+static void mpc_reg_out (volatile u32 * reg, int val, int mask);
+static int wait_for_bb (void);
+static int wait_for_pin (int *status);
+static int do_address (uchar chip, char rdwr_flag);
+static int send_bytes (uchar chip, char *buf, int len);
+static int receive_bytes (uchar chip, char *buf, int len);
+static int mpc_get_fdr (int);
+
+static int mpc_reg_in (volatile u32 * reg)
+{
+	int ret;
+	ret = *reg >> 24;
+	__asm__ __volatile__ ("eieio");
+	return ret;
+}
+
+static void mpc_reg_out (volatile u32 * reg, int val, int mask)
+{
+	int tmp;
+
+	if (!mask) {
+		*reg = val << 24;
+	} else {
+		tmp = mpc_reg_in (reg);
+		*reg = ((tmp & ~mask) | (val & mask)) << 24;
+	}
+	__asm__ __volatile__ ("eieio");
+
+	return;
+}
+
+static int wait_for_bb (void)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int timeout = I2C_TIMEOUT;
+	int status;
+
+	status = mpc_reg_in (&regs->sr);
+
+	while (timeout-- && (status & I2C_BB)) {
+#if 1
+		volatile int temp;
+
+		mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+		temp = mpc_reg_in (&regs->dr);
+		mpc_reg_out (&regs->cr, 0, I2C_STA);
+		mpc_reg_out (&regs->cr, 0, 0);
+		mpc_reg_out (&regs->cr, I2C_EN, 0);
+#endif
+		udelay (1000);
+		status = mpc_reg_in (&regs->sr);
+	}
+
+	return (status & I2C_BB);
+}
+
+static int wait_for_pin (int *status)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int timeout = I2C_TIMEOUT;
+
+	*status = mpc_reg_in (&regs->sr);
+
+	while (timeout-- && !(*status & I2C_IF)) {
+		udelay (1000);
+		*status = mpc_reg_in (&regs->sr);
+	}
+
+	if (!(*status & I2C_IF)) {
+		return -1;
+	}
+
+	mpc_reg_out (&regs->sr, 0, I2C_IF);
+	return 0;
+}
+
+static int do_address (uchar chip, char rdwr_flag)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int status;
+
+	chip <<= 1;
+
+	if (rdwr_flag)
+		chip |= 1;
+
+	mpc_reg_out (&regs->cr, I2C_TX, I2C_TX);
+	mpc_reg_out (&regs->dr, chip, 0);
+
+	if (wait_for_pin (&status))
+		return -2;
+	if (status & I2C_RXAK)
+		return -3;
+	return 0;
+}
+
+static int send_bytes (uchar chip, char *buf, int len)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int wrcount;
+	int status;
+
+	for (wrcount = 0; wrcount < len; ++wrcount) {
+
+		mpc_reg_out (&regs->dr, buf[wrcount], 0);
+
+		if (wait_for_pin (&status))
+			break;
+
+		if (status & I2C_RXAK)
+			break;
+
+	}
+
+	return !(wrcount == len);
+	return 0;
+}
+
+static int receive_bytes (uchar chip, char *buf, int len)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int dummy = 1;
+	int rdcount = 0;
+	int status;
+	int i;
+
+	mpc_reg_out (&regs->cr, 0, I2C_TX);
+
+	for (i = 0; i < len; ++i) {
+		buf[rdcount] = mpc_reg_in (&regs->dr);
+
+		if (dummy)
+			dummy = 0;
+		else
+			rdcount++;
+
+		if (wait_for_pin (&status))
+			return -4;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_TXAK, I2C_TXAK);
+	buf[rdcount++] = mpc_reg_in (&regs->dr);
+
+	if (wait_for_pin (&status))
+		return -5;
+
+	mpc_reg_out (&regs->cr, 0, I2C_TXAK);
+	return 0;
+}
+
+/**************** I2C API ****************/
+
+void i2c_init (int speed, int saddr)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+
+	mpc_reg_out (&regs->cr, 0, 0);
+	mpc_reg_out (&regs->adr, saddr << 1, 0);
+
+	/* Set clock
+	 */
+	mpc_reg_out (&regs->fdr, mpc_get_fdr (speed), 0);
+
+	/* Enable module
+	 */
+	mpc_reg_out (&regs->cr, I2C_EN, I2C_INIT_MASK);
+	mpc_reg_out (&regs->sr, 0, I2C_IF);
+	return;
+}
+
+static int mpc_get_fdr (int speed)
+{
+	static int fdr = -1;
+
+	if (fdr == -1) {
+		ulong best_speed = 0;
+		ulong divider;
+		ulong ipb, scl;
+		ulong bestmatch = 0xffffffffUL;
+		int best_i = 0, best_j = 0, i, j;
+		int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8 };
+		struct mpc8220_i2c_tap scltap[] = {
+			{4, 1},
+			{4, 2},
+			{6, 4},
+			{6, 8},
+			{14, 16},
+			{30, 32},
+			{62, 64},
+			{126, 128}
+		};
+
+		ipb = gd->bus_clk;
+		for (i = 7; i >= 0; i--) {
+			for (j = 7; j >= 0; j--) {
+				scl = 2 * (scltap[j].scl2tap +
+					   (SCL_Tap[i] -
+					    1) * scltap[j].tap2tap + 2);
+				if (ipb <= speed * scl) {
+					if ((speed * scl - ipb) < bestmatch) {
+						bestmatch = speed * scl - ipb;
+						best_i = i;
+						best_j = j;
+						best_speed = ipb / scl;
+					}
+				}
+			}
+		}
+		divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+		if (gd->flags & GD_FLG_RELOC) {
+			fdr = divider;
+		} else {
+			printf ("%ld kHz, ", best_speed / 1000);
+			return divider;
+		}
+	}
+
+	return fdr;
+}
+
+int i2c_probe (uchar chip)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int i;
+
+	for (i = 0; i < I2C_RETRIES; i++) {
+		mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+
+		if (!do_address (chip, 0)) {
+			mpc_reg_out (&regs->cr, 0, I2C_STA);
+			break;
+		}
+
+		mpc_reg_out (&regs->cr, 0, I2C_STA);
+		udelay (50);
+	}
+
+	return (i == I2C_RETRIES);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buf, int len)
+{
+	uchar xaddr[4];
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int ret = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >> 8) & 0xFF;
+	xaddr[3] = addr & 0xFF;
+
+	if (wait_for_bb ()) {
+		printf ("i2c_read: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+	if (do_address (chip, 0)) {
+		printf ("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, (char *)&xaddr[4 - alen], alen)) {
+		printf ("i2c_read: send_bytes failed\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_RSTA, I2C_RSTA);
+	if (do_address (chip, 1)) {
+		printf ("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (receive_bytes (chip, (char *)buf, len)) {
+		printf ("i2c_read: receive_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+      Done:
+	mpc_reg_out (&regs->cr, 0, I2C_STA);
+	return ret;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buf, int len)
+{
+	uchar xaddr[4];
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int ret = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >> 8) & 0xFF;
+	xaddr[3] = addr & 0xFF;
+
+	if (wait_for_bb ()) {
+		printf ("i2c_write: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+	if (do_address (chip, 0)) {
+		printf ("i2c_write: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, (char *)&xaddr[4 - alen], alen)) {
+		printf ("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, (char *)buf, len)) {
+		printf ("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+      Done:
+	mpc_reg_out (&regs->cr, 0, I2C_STA);
+	return ret;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/ppc/cpu/mpc8220/i2cCore.c b/arch/ppc/cpu/mpc8220/i2cCore.c
new file mode 100644
index 0000000..b89ad03
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/i2cCore.c
@@ -0,0 +1,627 @@
+/* I2cCore.c - MPC8220 PPC I2C Library */
+
+/* Copyright 2004      Freescale Semiconductor, Inc. */
+
+/*
+modification history
+--------------------
+01c,29jun04,tcl	 1.3	removed CR. Added two bytes offset support.
+01b,19jan04,tcl	 1.2	removed i2cMsDelay and sysDecGet. renamed i2cMsDelay
+			back to sysMsDelay
+01a,19jan04,tcl	 1.1	created and seperated from i2c.c
+*/
+
+/*
+DESCRIPTION
+This file contain I2C low level handling library functions
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vxWorks.h>
+#include <sysLib.h>
+#include <iosLib.h>
+#include <logLib.h>
+#include <tickLib.h>
+
+/* BSP Includes */
+#include "config.h"
+#include "mpc8220.h"
+#include "i2cCore.h"
+
+#ifdef DEBUG_I2CCORE
+int I2CCDbg = 0;
+#endif
+
+#define ABS(x)	((x < 0)? -x : x)
+
+char *I2CERR[16] = {
+	"Transfer in Progress\n",	/* 0 */
+	"Transfer complete\n",
+	"Not Addressed\n",		/* 2 */
+	"Addressed as a slave\n",
+	"Bus is Idle\n",		/* 4 */
+	"Bus is busy\n",
+	"Arbitration Lost\n",		/* 6 */
+	"Arbitration on Track\n",
+	"Slave receive, master writing to slave\n",	/* 8 */
+	"Slave transmit, master reading from slave\n",
+	"Interrupt is pending\n",	/* 10 */
+	"Interrupt complete\n",
+	"Acknowledge received\n",	/* 12 */
+	"No acknowledge received\n",
+	"Unknown status\n",		/* 14 */
+	"\n"
+};
+
+/******************************************************************************
+ *
+ * chk_status - Check I2C status bit
+ *
+ * RETURNS: OK, or ERROR if the bit encounter
+ *
+ */
+
+STATUS chk_status (PSI2C pi2c, UINT8 sta_bit, UINT8 truefalse)
+{
+	int i, status = 0;
+
+	for (i = 0; i < I2C_POLL_COUNT; i++) {
+		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0))
+			return (OK);
+	}
+
+	I2CCDBG (L2, ("--- sr %x stabit %x truefalse %d\n",
+		      pi2c->sr, sta_bit, truefalse, 0, 0, 0));
+
+	if (i == I2C_POLL_COUNT) {
+		switch (sta_bit) {
+		case I2C_STA_CF:
+			status = 0;
+			break;
+		case I2C_STA_AAS:
+			status = 2;
+			break;
+		case I2C_STA_BB:
+			status = 4;
+			break;
+		case I2C_STA_AL:
+			status = 6;
+			break;
+		case I2C_STA_SRW:
+			status = 8;
+			break;
+		case I2C_STA_IF:
+			status = 10;
+			break;
+		case I2C_STA_RXAK:
+			status = 12;
+			break;
+		default:
+			status = 14;
+			break;
+		}
+
+		if (!truefalse)
+			status++;
+
+		I2CCDBG (NO, ("--- status %d\n", status, 0, 0, 0, 0, 0));
+		I2CCDBG (NO, (I2CERR[status], 0, 0, 0, 0, 0, 0));
+	}
+
+	return (ERROR);
+}
+
+/******************************************************************************
+ *
+ * I2C Enable - Enable the I2C Controller
+ *
+ */
+STATUS i2c_enable (SI2C * pi2c, PI2CSET pi2cSet)
+{
+	int fdr = pi2cSet->bit_rate;
+	UINT8 adr = pi2cSet->i2c_adr;
+
+	I2CCDBG (L2, ("i2c_enable fdr %d adr %x\n", fdr, adr, 0, 0, 0, 0));
+
+	i2c_clear (pi2c);	/* Clear FDR, ADR, SR and CR reg */
+
+	SetI2cFDR (pi2c, fdr);	/* Frequency			*/
+	pi2c->adr = adr;
+
+	pi2c->cr = I2C_CTL_EN;	/* Set Enable			*/
+
+	/*
+	   The I2C bus should be in Idle state. If the bus is busy,
+	   clear the STA bit in control register
+	 */
+	if (chk_status (pi2c, I2C_STA_BB, 0) != OK) {
+		if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA)
+			pi2c->cr &= ~I2C_CTL_STA;
+
+		/* Check again if it is still busy, return error if found */
+		if (chk_status (pi2c, I2C_STA_BB, 1) == OK)
+			return ERROR;
+	}
+
+	return (OK);
+}
+
+/******************************************************************************
+ *
+ * I2C Disable - Disable the I2C Controller
+ *
+ */
+STATUS i2c_disable (PSI2C pi2c)
+{
+	i2c_clear (pi2c);
+
+	pi2c->cr &= I2C_CTL_EN; /* Disable I2c			*/
+
+	if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA)
+		pi2c->cr &= ~I2C_CTL_STA;
+
+	if (chk_status (pi2c, I2C_STA_BB, 0) != OK)
+		return ERROR;
+
+	return (OK);
+}
+
+/******************************************************************************
+ *
+ * I2C Clear - Clear the I2C Controller
+ *
+ */
+STATUS i2c_clear (PSI2C pi2c)
+{
+	pi2c->adr = 0;
+	pi2c->fdr = 0;
+	pi2c->cr = 0;
+	pi2c->sr = 0;
+
+	return (OK);
+}
+
+
+STATUS i2c_start (PSI2C pi2c, PI2CSET pi2cSet)
+{
+#ifdef TWOBYTES
+	UINT16 ByteOffset = pi2cSet->str_adr;
+#else
+	UINT8 ByteOffset = pi2cSet->str_adr;
+#endif
+#if 1
+	UINT8 tmp = 0;
+#endif
+	UINT8 Addr = pi2cSet->slv_adr;
+
+	pi2c->cr |= I2C_CTL_STA;	/* Generate start signal	*/
+
+	if (chk_status (pi2c, I2C_STA_BB, 1) != OK)
+		return ERROR;
+
+	/* Write slave address */
+	if (i2c_writebyte (pi2c, &Addr) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#ifdef TWOBYTES
+#   if 0
+	/* Issue the offset to start */
+	if (i2c_write2byte (pi2c, &ByteOffset) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#endif
+	tmp = (ByteOffset >> 8) & 0xff;
+	if (i2c_writebyte (pi2c, &tmp) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+	tmp = ByteOffset & 0xff;
+	if (i2c_writebyte (pi2c, &tmp) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#else
+	if (i2c_writebyte (pi2c, &ByteOffset) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#endif
+
+	return (OK);
+}
+
+STATUS i2c_stop (PSI2C pi2c)
+{
+	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal		*/
+	if (chk_status (pi2c, I2C_STA_BB, 0) != OK)
+		return ERROR;
+
+	return (OK);
+}
+
+/******************************************************************************
+ *
+ * Read Len bytes to the location pointed to by *Data from the device
+ * with address Addr.
+ */
+int i2c_readblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data)
+{
+	int i = 0;
+	UINT8 Tmp;
+
+/*    UINT8 ByteOffset = pi2cSet->str_adr; not used? */
+	UINT8 Addr = pi2cSet->slv_adr;
+	int Length = pi2cSet->xfer_size;
+
+	I2CCDBG (L1, ("i2c_readblock addr %x data 0x%08x len %d offset %d\n",
+		      Addr, (int) Data, Length, ByteOffset, 0, 0));
+
+	if (pi2c->sr & I2C_STA_AL) {	/* Check if Arbitration lost	*/
+		I2CCDBG (FN, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0));
+		pi2c->sr &= ~I2C_STA_AL;	/* Clear Arbitration status bit */
+		return ERROR;
+	}
+
+	pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack	*/
+
+	if (i2c_start (pi2c, pi2cSet) == ERROR)
+		return ERROR;
+
+	pi2c->cr |= I2C_CTL_RSTA;	/* Repeat Start */
+
+	Tmp = Addr | 1;
+
+	if (i2c_writebyte (pi2c, &Tmp) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c	*/
+		return ERROR;
+	}
+
+	if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01))
+		return ERROR;
+
+	pi2c->cr &= ~I2C_CTL_TX;	/* Set receive mode	*/
+
+	if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01))
+		return ERROR;
+
+	/* Dummy Read */
+	if (i2c_readbyte (pi2c, &Tmp, &i) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c	*/
+		return ERROR;
+	}
+
+	i = 0;
+	while (Length) {
+		if (Length == 2)
+			pi2c->cr |= I2C_CTL_TXAK;
+
+		if (Length == 1)
+			pi2c->cr &= ~I2C_CTL_STA;
+
+		if (i2c_readbyte (pi2c, Data, &Length) != OK) {
+			return i2c_stop (pi2c);
+		}
+		i++;
+		Length--;
+		Data++;
+	}
+
+	if (i2c_stop (pi2c) == ERROR)
+		return ERROR;
+
+	return i;
+}
+
+STATUS i2c_writeblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data)
+{
+	int Length = pi2cSet->xfer_size;
+
+#ifdef TWOBYTES
+	UINT16 ByteOffset = pi2cSet->str_adr;
+#else
+	UINT8 ByteOffset = pi2cSet->str_adr;
+#endif
+	int j, k;
+
+	I2CCDBG (L2, ("i2c_writeblock\n", 0, 0, 0, 0, 0, 0));
+
+	if (pi2c->sr & I2C_STA_AL) {
+		/* Check if arbitration lost */
+		I2CCDBG (L2, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0));
+		pi2c->sr &= ~I2C_STA_AL;	/* Clear the condition	*/
+		return ERROR;
+	}
+
+	pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack	*/
+
+	/* Do the not even offset first */
+	if ((ByteOffset % 8) != 0) {
+		int remain;
+
+		if (Length > 8) {
+			remain = 8 - (ByteOffset % 8);
+			Length -= remain;
+
+			pi2cSet->str_adr = ByteOffset;
+
+			if (i2c_start (pi2c, pi2cSet) == ERROR)
+				return ERROR;
+
+			for (j = ByteOffset; j < remain; j++) {
+				if (i2c_writebyte (pi2c, Data++) != OK)
+					return ERROR;
+			}
+
+			if (i2c_stop (pi2c) == ERROR)
+				return ERROR;
+
+			sysMsDelay (32);
+
+			/* Update the new ByteOffset */
+			ByteOffset += remain;
+		}
+	}
+
+	for (j = ByteOffset, k = 0; j < (Length + ByteOffset); j++) {
+		if ((j % 8) == 0) {
+			pi2cSet->str_adr = j;
+			if (i2c_start (pi2c, pi2cSet) == ERROR)
+				return ERROR;
+		}
+
+		k++;
+
+		if (i2c_writebyte (pi2c, Data++) != OK)
+			return ERROR;
+
+		if ((j == (Length - 1)) || ((k % 8) == 0)) {
+			if (i2c_stop (pi2c) == ERROR)
+				return ERROR;
+
+			sysMsDelay (50);
+		}
+
+	}
+
+	return k;
+}
+
+STATUS i2c_readbyte (SI2C * pi2c, UINT8 * readb, int *index)
+{
+	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit	*/
+	*readb = pi2c->dr;		/* Read a byte		*/
+
+	/*
+	   Set I2C_CTRL_TXAK will cause Transfer pending and
+	   set I2C_CTRL_STA will cause Interrupt pending
+	 */
+	if (*index != 2) {
+		if (chk_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?	*/
+			return ERROR;
+	}
+
+	if (*index != 1) {
+		if (chk_status (pi2c, I2C_STA_IF, 1) != OK)
+			return ERROR;
+	}
+
+	return (OK);
+}
+
+
+STATUS i2c_writebyte (SI2C * pi2c, UINT8 * writeb)
+{
+	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt	*/
+	pi2c->dr = *writeb;		/* Write a byte		*/
+
+	if (chk_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?	*/
+		return ERROR;
+
+	if (chk_status (pi2c, I2C_STA_IF, 1) != OK)
+		return ERROR;
+
+	return OK;
+}
+
+STATUS i2c_write2byte (SI2C * pi2c, UINT16 * writeb)
+{
+	UINT8 data;
+
+	data = (UINT8) ((*writeb >> 8) & 0xff);
+	if (i2c_writebyte (pi2c, &data) != OK)
+		return ERROR;
+	data = (UINT8) (*writeb & 0xff);
+	if (i2c_writebyte (pi2c, &data) != OK)
+		return ERROR;
+	return OK;
+}
+
+/* FDR table base on 33MHz - more detail please refer to Odini2c_dividers.xls
+FDR FDR scl sda scl2tap2
+510 432 tap tap tap tap scl_per	    sda_hold	I2C Freq    0	1   2	3   4	5
+000 000 9   3	4   1	28 Clocks   9 Clocks	1190 KHz    0	0   0	0   0	0
+000 001 9   3	4   2	44 Clocks   11 Clocks	758 KHz	    0	0   1	0   0	0
+000 010 9   3	6   4	80 Clocks   17 Clocks	417 KHz	    0	0   0	1   0	0
+000 011 9   3	6   8	144 Clocks  25 Clocks	231 KHz	    0	0   1	1   0	0
+000 100 9   3	14  16	288 Clocks  49 Clocks	116 KHz	    0	0   0	0   1	0
+000 101 9   3	30  32	576 Clocks  97 Clocks	58 KHz	    0	0   1	0   1	0
+000 110 9   3	62  64	1152 Clocks 193 Clocks	29 KHz	    0	0   0	1   1	0
+000 111 9   3	126 128 2304 Clocks 385 Clocks	14 KHz	    0	0   1	1   1	0
+001 000 10  3	4   1	30 Clocks   9 Clocks	1111 KHz1   0	0   0	0   0
+001 001 10  3	4   2	48 Clocks   11 Clocks	694 KHz	    1	0   1	0   0	0
+001 010 10  3	6   4	88 Clocks   17 Clocks	379 KHz	    1	0   0	1   0	0
+001 011 10  3	6   8	160 Clocks  25 Clocks	208 KHz	    1	0   1	1   0	0
+001 100 10  3	14  16	320 Clocks  49 Clocks	104 KHz	    1	0   0	0   1	0
+001 101 10  3	30  32	640 Clocks  97 Clocks	52 KHz	    1	0   1	0   1	0
+001 110 10  3	62  64	1280 Clocks 193 Clocks	26 KHz	    1	0   0	1   1	0
+001 111 10  3	126 128 2560 Clocks 385 Clocks	13 KHz	    1	0   1	1   1	0
+010 000 12  4	4   1	34 Clocks   10 Clocks	980 KHz	    0	1   0	0   0	0
+010 001 12  4	4   2	56 Clocks   13 Clocks	595 KHz	    0	1   1	0   0	0
+010 010 12  4	6   4	104 Clocks  21 Clocks	321 KHz	    0	1   0	1   0	0
+010 011 12  4	6   8	192 Clocks  33 Clocks	174 KHz	    0	1   1	1   0	0
+010 100 12  4	14  16	384 Clocks  65 Clocks	87 KHz	    0	1   0	0   1	0
+010 101 12  4	30  32	768 Clocks  129 Clocks	43 KHz	    0	1   1	0   1	0
+010 110 12  4	62  64	1536 Clocks 257 Clocks	22 KHz	    0	1   0	1   1	0
+010 111 12  4	126 128 3072 Clocks 513 Clocks	11 KHz	    0	1   1	1   1	0
+011 000 15  4	4   1	40 Clocks   10 Clocks	833 KHz	    1	1   0	0   0	0
+011 001 15  4	4   2	68 Clocks   13 Clocks	490 KHz	    1	1   1	0   0	0
+011 010 15  4	6   4	128 Clocks  21 Clocks	260 KHz	    1	1   0	1   0	0
+011 011 15  4	6   8	240 Clocks  33 Clocks	139 KHz	    1	1   1	1   0	0
+011 100 15  4	14  16	480 Clocks  65 Clocks	69 KHz	    1	1   0	0   1	0
+011 101 15  4	30  32	960 Clocks  129 Clocks	35 KHz	    1	1   1	0   1	0
+011 110 15  4	62  64	1920 Clocks 257 Clocks	17 KHz	    1	1   0	1   1	0
+011 111 15  4	126 128 3840 Clocks 513 Clocks	9 KHz	    1	1   1	1   1	0
+100 000 5   1	4   1	20 Clocks   7 Clocks	1667 KHz    0	0   0	0   0	1
+100 001 5   1	4   2	28 Clocks   7 Clocks	1190 KHz    0	0   1	0   0	1
+100 010 5   1	6   4	48 Clocks   9 Clocks	694 KHz	    0	0   0	1   0	1
+100 011 5   1	6   8	80 Clocks   9 Clocks	417 KHz	    0	0   1	1   0	1
+100 100 5   1	14  16	160 Clocks  17 Clocks	208 KHz	    0	0   0	0   1	1
+100 101 5   1	30  32	320 Clocks  33 Clocks	104 KHz	    0	0   1	0   1	1
+100 110 5   1	62  64	640 Clocks  65 Clocks	52 KHz	    0	0   0	1   1	1
+100 111 5   1	126 128 1280 Clocks 129 Clocks	26 KHz	    0	0   1	1   1	1
+101 000 6   1	4   1	22 Clocks   7 Clocks	1515 KHz    1	0   0	0   0	1
+101 001 6   1	4   2	32 Clocks   7 Clocks	1042 KHz    1	0   1	0   0	1
+101 010 6   1	6   4	56 Clocks   9 Clocks	595 KHz	    1	0   0	1   0	1
+101 011 6   1	6   8	96 Clocks   9 Clocks	347 KHz	    1	0   1	1   0	1
+101 100 6   1	14  16	192 Clocks  17 Clocks	174 KHz	    1	0   0	0   1	1
+101 101 6   1	30  32	384 Clocks  33 Clocks	87 KHz	    1	0   1	0   1	1
+101 110 6   1	62  64	768 Clocks  65 Clocks	43 KHz	    1	0   0	1   1	1
+101 111 6   1	126 128 1536 Clocks 129 Clocks	22 KHz	    1	0   1	1   1	1
+110 000 7   2	4   1	24 Clocks   8 Clocks	1389 KHz    0	1   0	0   0	1
+110 001 7   2	4   2	36 Clocks   9 Clocks	926 KHz	    0	1   1	0   0	1
+110 010 7   2	6   4	64 Clocks   13 Clocks	521 KHz	    0	1   0	1   0	1
+110 011 7   2	6   8	112 Clocks  17 Clocks	298 KHz	    0	1   1	1   0	1
+110 100 7   2	14  16	224 Clocks  33 Clocks	149 KHz	    0	1   0	0   1	1
+110 101 7   2	30  32	448 Clocks  65 Clocks	74 KHz	    0	1   1	0   1	1
+110 110 7   2	62  64	896 Clocks  129 Clocks	37 KHz	    0	1   0	1   1	1
+110 111 7   2	126 128 1792 Clocks 257 Clocks	19 KHz	    0	1   1	1   1	1
+111 000 8   2	4   1	26 Clocks   8 Clocks	1282 KHz    1	1   0	0   0	1
+111 001 8   2	4   2	40 Clocks   9 Clocks	833 KHz	    1	1   1	0   0	1
+111 010 8   2	6   4	72 Clocks   13 Clocks	463 KHz	    1	1   0	1   0	1
+111 011 8   2	6   8	128 Clocks  17 Clocks	260 KHz	    1	1   1	1   0	1
+111 100 8   2	14  16	256 Clocks  33 Clocks	130 KHz	    1	1   0	0   1	1
+111 101 8   2	30  32	512 Clocks  65 Clocks	65 KHz	    1	1   1	0   1	1
+111 110 8   2	62  64	1024 Clocks 129 Clocks	33 KHz	    1	1   0	1   1	1
+111 111 8   2	126 128 2048 Clocks 257 Clocks	16 KHz	    1	1   1	1   1	1
+*/
+STATUS SetI2cFDR (PSI2C pi2cRegs, int bitrate)
+{
+/* Constants */
+	const UINT8 div_hold[8][3] = { {9, 3}, {10, 3},
+	{12, 4}, {15, 4},
+	{5, 1}, {6, 1},
+	{7, 2}, {8, 2}
+	};
+
+	const UINT8 scl_tap[8][2] = { {4, 1}, {4, 2},
+	{6, 4}, {6, 8},
+	{14, 16}, {30, 32},
+	{62, 64}, {126, 128}
+	};
+
+	UINT8 mfdr_bits;
+
+	int i = 0;
+	int j = 0;
+
+	int Diff, min;
+	int WhichFreq, iRec, jRec;
+	int SCL_Period;
+	int SCL_Hold;
+	int I2C_Freq;
+
+	I2CCDBG (L2, ("Entering getBitRate: bitrate %d pi2cRegs 0x%08x\n",
+		      bitrate, (int) pi2cRegs, 0, 0, 0, 0));
+
+	if (bitrate < 0) {
+		I2CCDBG (NO, ("Invalid bitrate\n", 0, 0, 0, 0, 0, 0));
+		return ERROR;
+	}
+
+	/* Initialize */
+	mfdr_bits = 0;
+	min = 0x7fffffff;
+	WhichFreq = iRec = jRec = 0;
+
+	for (i = 0; i < 8; i++) {
+		for (j = 0; j < 8; j++) {
+			/* SCL Period = 2 * (scl2tap + [(SCL_Tap - 1) * tap2tap] + 2)
+			 * SCL Hold   = scl2tap + ((SDA_Tap - 1) * tap2tap) + 3
+			 * Bit Rate (I2C Freq) = System Freq / SCL Period
+			 */
+			SCL_Period =
+				2 * (scl_tap[i][0] +
+				     ((div_hold[j][0] - 1) * scl_tap[i][1]) +
+				     2);
+
+			/* Now get the I2C Freq */
+			I2C_Freq = DEV_CLOCK_FREQ / SCL_Period;
+
+			/* Take equal or slower */
+			if (I2C_Freq > bitrate)
+				continue;
+
+			/* Take the differences */
+			Diff = I2C_Freq - bitrate;
+
+			Diff = ABS (Diff);
+
+			/* Find the closer value */
+			if (Diff < min) {
+				min = Diff;
+				WhichFreq = I2C_Freq;
+				iRec = i;
+				jRec = j;
+			}
+
+			I2CCDBG (L2,
+				 ("--- (%d,%d) I2C_Freq %d minDiff %d min %d\n",
+				  i, j, I2C_Freq, Diff, min, 0));
+		}
+	}
+
+	SCL_Period =
+		2 * (scl_tap[iRec][0] +
+		     ((div_hold[jRec][0] - 1) * scl_tap[iRec][1]) + 2);
+
+	I2CCDBG (L2, ("\nmin %d WhichFreq %d iRec %d jRec %d\n",
+		      min, WhichFreq, iRec, jRec, 0, 0));
+	I2CCDBG (L2, ("--- scl2tap %d SCL_Tap %d tap2tap %d\n",
+		      scl_tap[iRec][0], div_hold[jRec][0], scl_tap[iRec][1],
+		      0, 0, 0));
+
+	/* This may no require */
+	SCL_Hold =
+		scl_tap[iRec][0] +
+		((div_hold[jRec][1] - 1) * scl_tap[iRec][1]) + 3;
+	I2CCDBG (L2,
+		 ("--- SCL_Period %d SCL_Hold %d\n", SCL_Period, SCL_Hold, 0,
+		  0, 0, 0));
+
+	I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0));
+
+	/* FDR 4,3,2 */
+	if ((iRec & 1) == 1)
+		mfdr_bits |= 0x04;	/* FDR 2 */
+	if ((iRec & 2) == 2)
+		mfdr_bits |= 0x08;	/* FDR 3 */
+	if ((iRec & 4) == 4)
+		mfdr_bits |= 0x10;	/* FDR 4 */
+	/* FDR 5,1,0 */
+	if ((jRec & 1) == 1)
+		mfdr_bits |= 0x01;	/* FDR 0 */
+	if ((jRec & 2) == 2)
+		mfdr_bits |= 0x02;	/* FDR 1 */
+	if ((jRec & 4) == 4)
+		mfdr_bits |= 0x20;	/* FDR 5 */
+
+	I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0));
+
+	pi2cRegs->fdr = mfdr_bits;
+
+	return OK;
+}
diff --git a/arch/ppc/cpu/mpc8220/i2cCore.h b/arch/ppc/cpu/mpc8220/i2cCore.h
new file mode 100644
index 0000000..72783fd
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/i2cCore.h
@@ -0,0 +1,103 @@
+/*
+ * i2cCore.h
+ *
+ * Prototypes, etc. for the Motorola MPC8220
+ * embedded cpu chips
+ *
+ * 2004 (c) Freescale, Inc.
+ * Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __INCi2ccoreh
+#define __INCi2ccoreh
+#ifndef __ASSEMBLY__
+/* device types */
+#define I2C_DEVICE_TYPE_EEPROM 0
+#define I2C_EEPROM_ADRS 0xa0
+#define I2C_CTRL_ADRS   I2C_EEPROM_ADRS
+#define EEPROM_ADDR0    0xA2	/* on Dimm SPD eeprom */
+#define EEPROM_ADDR1    0xA4	/* on Board SPD eeprom */
+#define EEPROM_ADDR2    0xD2	/* non-standard eeprom - clock generator */
+/* Control Register */
+#define I2C_CTL_EN      0x80	/* I2C Enable                   */
+#define I2C_CTL_IEN     0x40	/* I2C Interrupt Enable         */
+#define I2C_CTL_STA     0x20	/* Master/Slave Mode select     */
+#define I2C_CTL_TX      0x10	/* Transmit/Receive Mode Select */
+#define I2C_CTL_TXAK    0x08	/* Transmit Acknowledge Enable  */
+#define I2C_CTL_RSTA    0x04	/* Repeat Start                 */
+/* Status Register */
+#define I2C_STA_CF      0x80	/* Data Transfer       */
+#define I2C_STA_AAS     0x40	/* Adressed As Slave   */
+#define I2C_STA_BB      0x20	/* Bus Busy            */
+#define I2C_STA_AL      0x10	/* Arbitration Lost    */
+#define I2C_STA_SRW     0x04	/* Slave Read/Write    */
+#define I2C_STA_IF      0x02	/* I2C Interrupt       */
+#define I2C_STA_RXAK    0x01	/* Receive Acknowledge */
+/* Interrupt Contol Register */
+#define I2C_INT_BNBE2   0x80	/* Bus Not Busy Enable 2 */
+#define I2C_INT_TE2     0x40	/* Transmit Enable 2     */
+#define I2C_INT_RE2     0x20	/* Receive Enable 2      */
+#define I2C_INT_IE2     0x10	/* Interrupt Enable 2    */
+#define I2C_INT_BNBE1   0x08	/* Bus Not Busy Enable 1 */
+#define I2C_INT_TE1     0x04	/* Transmit Enable 1     */
+#define I2C_INT_RE1     0x02	/* Receive Enable 1      */
+#define I2C_INT_IE1     0x01	/* Interrupt Enable 1    */
+#define I2C_POLL_COUNT 0x100000
+#define I2C_ENABLE      0x00000001
+#define I2C_DISABLE     0x00000002
+#define I2C_START       0x00000004
+#define I2C_REPSTART    0x00000008
+#define I2C_STOP        0x00000010
+#define I2C_BITRATE     0x00000020
+#define I2C_SLAVEADR    0x00000040
+#define I2C_STARTADR    0x00000080
+#undef TWOBYTES
+typedef struct i2c_settings {
+	/* Device settings */
+	int bit_rate;		/* Device bit rate */
+	u8 i2c_adr;		/* I2C address */
+	u8 slv_adr;		/* Slave address */
+#ifdef TWOBYTES
+	u16 str_adr;		/* Start address */
+#else
+	u8 str_adr;		/* Start address */
+#endif
+	int xfer_size;		/* Transfer Size */
+
+	int bI2c_en;		/* Enable or Disable */
+	int cmdFlag;		/* I2c Command Flags */
+} i2cset_t;
+
+/*
+int check_status(PSI2C pi2c, u8 sta_bit, u8 truefalse);
+int i2c_enable(PSI2C pi2c, PI2CSET pi2cSet);
+int i2c_disable(PSI2C pi2c);
+int i2c_start(PSI2C pi2c, PI2CSET pi2cSet);
+int i2c_stop(PSI2C pi2c);
+int i2c_clear(PSI2C pi2c);
+int i2c_readblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data);
+int i2c_writeblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data);
+int i2c_readbyte(PSI2C pi2c, u8 *readb, int *index);
+int i2c_writebyte(PSI2C pi2c, u8 *writeb);
+int SetI2cFDR( PSI2C pi2cRegs, int bitrate );
+*/
+#endif /* __ASSEMBLY__ */
+
+#endif /* __INCi2ccoreh */
diff --git a/arch/ppc/cpu/mpc8220/interrupts.c b/arch/ppc/cpu/mpc8220/interrupts.c
new file mode 100644
index 0000000..78e9917
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/interrupts.c
@@ -0,0 +1,80 @@
+/*
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * interrupts.c - just enough support for the decrementer/timer
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <command.h>
+
+int interrupt_init_cpu (ulong * decrementer_count)
+{
+	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+	return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	puts ("external_interrupt (oops!)\n");
+}
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+
+}
+
+void irq_free_handler (int vec)
+{
+
+}
+
+/****************************************************************************/
+
+void
+do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+	puts ("IRQ related functions are unimplemented currently.\n");
+}
diff --git a/arch/ppc/cpu/mpc8220/io.S b/arch/ppc/cpu/mpc8220/io.S
new file mode 100644
index 0000000..5ecdf55
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/io.S
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2001	Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *			Andreas Heppel <aheppel@sysgo.de>
+ *  Copyright (C) 2003	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
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in8 */
+/*  Description:  Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	in8
+in8:
+	lbz	r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in16 */
+/*  Description:  Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	in16
+in16:
+	lhz	r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in16r */
+/*  Description:  Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+	.globl	in16r
+in16r:
+	lhbrx	r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in32 */
+/*  Description:  Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	in32
+in32:
+	lwz	3,0(3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in32r */
+/*  Description:  Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+	.globl	in32r
+in32r:
+	lwbrx	r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out8 */
+/*  Description:  Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out8
+out8:
+	stb	r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out16 */
+/*  Description:  Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out16
+out16:
+	sth	r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out16r */
+/*  Description:  Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out16r
+out16r:
+	sthbrx	r4,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out32 */
+/*  Description:  Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out32
+out32:
+	stw	r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out32r */
+/*  Description:  Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out32r
+out32r:
+	stwbrx	r4,0,r3
+	sync
+	blr
diff --git a/arch/ppc/cpu/mpc8220/loadtask.c b/arch/ppc/cpu/mpc8220/loadtask.c
new file mode 100644
index 0000000..6d8b627
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/loadtask.c
@@ -0,0 +1,78 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+/* Multichannel DMA microcode */
+extern int taskTable;
+
+void loadtask (int basetask, int tasks)
+{
+	int *sram = (int *) (MMAP_SRAM + 512);
+	int *task_org = &taskTable;
+	unsigned int start, offset, end;
+	int i;
+
+#ifdef DEBUG
+	printf ("basetask = %d, tasks = %d\n", basetask, tasks);
+	printf ("task_org = 0x%08x\n", (unsigned int) task_org);
+#endif
+
+	/* setup TaskBAR register */
+	*(vu_long *) MMAP_DMA = (MMAP_SRAM + 512);
+
+	/* relocate task table entries */
+	offset = (unsigned int) sram;
+	for (i = basetask; i < basetask + tasks; i++) {
+		sram[i * 8 + 0] = task_org[i * 8 + 0] + offset;
+		sram[i * 8 + 1] = task_org[i * 8 + 1] + offset;
+		sram[i * 8 + 2] = task_org[i * 8 + 2] + offset;
+		sram[i * 8 + 3] = task_org[i * 8 + 3] + offset;
+		sram[i * 8 + 4] = task_org[i * 8 + 4];
+		sram[i * 8 + 5] = task_org[i * 8 + 5];
+		sram[i * 8 + 6] = task_org[i * 8 + 6] + offset;
+		sram[i * 8 + 7] = task_org[i * 8 + 7];
+	}
+
+	/* relocate task descriptors */
+	start = (sram[basetask * 8] - (unsigned int) sram);
+	end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int) sram);
+
+#ifdef DEBUG
+	printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end);
+#endif
+
+	start /= 4;
+	end /= 4;
+	for (i = start; i <= end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	/* relocate variables */
+	start = (sram[basetask * 8 + 2] - (unsigned int) sram);
+	end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 -
+	       (unsigned int) sram);
+	start /= 4;
+	end /= 4;
+	for (i = start; i < end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	/* relocate function decriptors */
+	start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int) sram);
+	end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 -
+	       (unsigned int) sram);
+	start /= 4;
+	end /= 4;
+	for (i = start; i < end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	asm volatile ("sync");
+}
diff --git a/arch/ppc/cpu/mpc8220/pci.c b/arch/ppc/cpu/mpc8220/pci.c
new file mode 100644
index 0000000..7ef43b7
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/pci.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Copyright (C) 2003 Motorola Inc.
+ * Xianghua Xiao (x.xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI Configuration space access support for MPC8220 PCI Bridge
+ */
+#include <common.h>
+#include <mpc8220.h>
+#include <pci.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PCI)
+
+/* System RAM mapped over PCI */
+#define CONFIG_PCI_SYS_MEM_BUS	 CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_MEM_PHYS	 CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_MEM_SIZE	 (1024 * 1024 * 1024)
+
+#define cfg_read(val, addr, type, op)		*val = op((type)(addr));
+#define cfg_write(val, addr, type, op)		op((type *)(addr), (val));
+
+#define PCI_OP(rw, size, type, op, mask)				\
+int mpc8220_pci_##rw##_config_##size(struct pci_controller *hose,	\
+	pci_dev_t dev, int offset, type val)				\
+{									\
+	u32 addr = 0;							\
+	u16 cfg_type = 0;						\
+	addr = ((offset & 0xfc) | cfg_type | (dev)  | 0x80000000);	\
+	out_be32(hose->cfg_addr, addr);					\
+	__asm__ __volatile__("sync");					\
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	\
+	out_be32(hose->cfg_addr, addr & 0x7fffffff);			\
+	__asm__ __volatile__("sync");					\
+	return 0;							\
+}
+
+PCI_OP(read, byte, u8 *, in_8, 3)
+PCI_OP(read, word, u16 *, in_le16, 2)
+PCI_OP(write, byte, u8, out_8, 3)
+PCI_OP(write, word, u16, out_le16, 2)
+PCI_OP(write, dword, u32, out_le32, 0)
+
+int mpc8220_pci_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+	int offset, u32 *val)
+{
+	u32 addr;
+	u32 tmpv;
+	u32 mask = 2;	 /* word access */
+	/* Read lower 16 bits */
+	addr = ((offset & 0xfc) | (dev) | 0x80000000);
+	out_be32(hose->cfg_addr, addr);
+	__asm__ __volatile__("sync");
+	*val = (u32) in_le16((u16 *) (hose->cfg_data + (offset & mask)));
+	out_be32(hose->cfg_addr, addr & 0x7fffffff);
+	__asm__ __volatile__("sync");
+
+	/* Read upper 16 bits */
+	offset += 2;
+	addr = ((offset & 0xfc) | 1 | (dev) | 0x80000000);
+	out_be32(hose->cfg_addr, addr);
+	__asm__ __volatile__("sync");
+	tmpv = (u32) in_le16((u16 *) (hose->cfg_data + (offset & mask)));
+	out_be32(hose->cfg_addr, addr & 0x7fffffff);
+	__asm__ __volatile__("sync");
+
+	/* combine results into dword value */
+	*val = (tmpv << 16) | *val;
+
+	return 0;
+}
+
+void
+pci_mpc8220_init(struct pci_controller *hose)
+{
+	u32 win0, win1, win2;
+	volatile mpc8220_xcpci_t *xcpci =
+		(volatile mpc8220_xcpci_t *) MMAP_XCPCI;
+
+	volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG;
+
+	win0 = (u32) CONFIG_PCI_MEM_PHYS;
+	win1 = (u32) CONFIG_PCI_IO_PHYS;
+	win2 = (u32) CONFIG_PCI_CFG_PHYS;
+
+	/* Assert PCI reset */
+	out_be32 (&xcpci->glb_stat_ctl, PCI_GLB_STAT_CTRL_PR);
+
+	/* Disable prefetching but read-multiples will still prefetch */
+	out_be32 (&xcpci->target_ctrl, 0x00000000);
+
+	/* Initiator windows */
+	out_be32 (&xcpci->init_win0,  (win0 >> 16) | win0 | 0x003f0000);
+	out_be32 (&xcpci->init_win1, ((win1 >> 16) | win1 ));
+	out_be32 (&xcpci->init_win2, ((win2 >> 16) | win2 ));
+
+	out_be32 (&xcpci->init_win_cfg,
+		PCI_INIT_WIN_CFG_WIN0_CTRL_EN |
+		PCI_INIT_WIN_CFG_WIN1_CTRL_EN | PCI_INIT_WIN_CFG_WIN1_CTRL_IO |
+		PCI_INIT_WIN_CFG_WIN2_CTRL_EN | PCI_INIT_WIN_CFG_WIN2_CTRL_IO);
+
+	out_be32 (&xcpci->init_ctrl, 0x00000000);
+
+	/* Enable bus master and mem access */
+	out_be32 (&xcpci->stat_cmd_reg, PCI_STAT_CMD_B | PCI_STAT_CMD_M);
+
+	/* Cache line size and master latency */
+	out_be32 (&xcpci->bist_htyp_lat_cshl, (0xf8 << PCI_CFG1_LT_SHIFT));
+
+	out_be32 (&xcpci->base0, PCI_BASE_ADDR_REG0); /* 256MB - MBAR space */
+	out_be32 (&xcpci->base1, PCI_BASE_ADDR_REG1); /* 1GB - SDRAM space */
+
+	out_be32 (&xcpci->target_bar0,
+		PCI_TARGET_BASE_ADDR_REG0 | PCI_TARGET_BASE_ADDR_EN);
+	out_be32 (&xcpci->target_bar1,
+		PCI_TARGET_BASE_ADDR_REG1 | PCI_TARGET_BASE_ADDR_EN);
+
+	/* Deassert reset bit */
+	out_be32 (&xcpci->glb_stat_ctl, 0x00000000);
+
+	/* Enable PCI bus master support */
+	/* Set PCIGNT1, PCIREQ1, PCIREQ0/PCIGNTIN, PCIGNT0/PCIREQOUT,
+	       PCIREQ2, PCIGNT2 */
+	out_be32((volatile u32 *)&portcfg->pcfg3,
+		(in_be32((volatile u32 *)&portcfg->pcfg3) & 0xFC3FCE7F));
+	out_be32((volatile u32 *)&portcfg->pcfg3,
+		(in_be32((volatile u32 *)&portcfg->pcfg3) | 0x01400180));
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_set_region(hose->regions + 0,
+		CONFIG_PCI_MEM_BUS,
+		CONFIG_PCI_MEM_PHYS,
+		CONFIG_PCI_MEM_SIZE,
+		PCI_REGION_MEM);
+
+	pci_set_region(hose->regions + 1,
+		CONFIG_PCI_IO_BUS,
+		CONFIG_PCI_IO_PHYS,
+		CONFIG_PCI_IO_SIZE,
+		PCI_REGION_IO);
+
+	pci_set_region(hose->regions + 2,
+		CONFIG_PCI_SYS_MEM_BUS,
+		CONFIG_PCI_SYS_MEM_PHYS,
+		CONFIG_PCI_SYS_MEM_SIZE,
+		PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+	hose->region_count = 3;
+
+	hose->cfg_addr = &(xcpci->cfg_adr);
+	hose->cfg_data = (volatile unsigned char *)CONFIG_PCI_CFG_BUS;
+
+	pci_set_ops(hose,
+		mpc8220_pci_read_config_byte,
+		mpc8220_pci_read_config_word,
+		mpc8220_pci_read_config_dword,
+		mpc8220_pci_write_config_byte,
+		mpc8220_pci_write_config_word,
+		mpc8220_pci_write_config_dword);
+
+	/* Hose scan */
+	pci_register_hose(hose);
+	hose->last_busno = pci_hose_scan(hose);
+
+	out_be32 (&xcpci->base0, PCI_BASE_ADDR_REG0); /* 256MB - MBAR space */
+	out_be32 (&xcpci->base1, PCI_BASE_ADDR_REG1); /* 1GB - SDRAM space */
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/ppc/cpu/mpc8220/speed.c b/arch/ppc/cpu/mpc8220/speed.c
new file mode 100644
index 0000000..62ac845
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/speed.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+typedef struct pllmultiplier {
+	u8 hid1;
+	int multi;
+	int vco_div;
+} pllcfg_t;
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+	pllcfg_t bus2core[] = {
+		{0x02, 2, 8},	/* 1 */
+		{0x01, 2, 4},
+		{0x0C, 3, 8},	/* 1.5 */
+		{0x00, 3, 4},
+		{0x18, 3, 2},
+		{0x05, 4, 4},	/* 2 */
+		{0x04, 4, 2},
+		{0x11, 5, 4},	/* 2.5 */
+		{0x06, 5, 2},
+		{0x10, 6, 4},	/* 3 */
+		{0x08, 6, 2},
+		{0x0E, 7, 2},	/* 3.5 */
+		{0x0A, 8, 2},	/* 4 */
+		{0x07, 9, 2},	/* 4.5 */
+		{0x0B, 10, 2},	/* 5 */
+		{0x09, 11, 2},	/* 5.5 */
+		{0x0D, 12, 2},	/* 6 */
+		{0x12, 13, 2},	/* 6.5 */
+		{0x14, 14, 2},	/* 7 */
+		{0x16, 15, 2},	/* 7.5 */
+		{0x1C, 16, 2}	/* 8 */
+	};
+	u32 hid1;
+	int i, size, pci2bus;
+
+#if !defined(CONFIG_SYS_MPC8220_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_SYS_MPC8220_CLKIN
+#endif
+
+	gd->inp_clk = CONFIG_SYS_MPC8220_CLKIN;
+
+	/* Read XLB to PCI(INP) clock multiplier */
+	pci2bus = (*((volatile u32 *)PCI_REG_PCIGSCR) &
+		PCI_REG_PCIGSCR_PCI2XLB_CLK_MASK)>>PCI_REG_PCIGSCR_PCI2XLB_CLK_BIT;
+
+	/* XLB bus clock */
+	gd->bus_clk = CONFIG_SYS_MPC8220_CLKIN * pci2bus;
+
+	/* PCI clock is same as input clock */
+	gd->pci_clk = CONFIG_SYS_MPC8220_CLKIN;
+
+	/* FlexBus is temporary set as the same as input clock */
+	/* will do dynamic in the future */
+	gd->flb_clk = CONFIG_SYS_MPC8220_CLKIN;
+
+	/* CPU Clock - Read HID1 */
+	asm volatile ("mfspr %0, 1009":"=r" (hid1):);
+
+	size = sizeof (bus2core) / sizeof (pllcfg_t);
+
+	hid1 >>= 27;
+
+	for (i = 0; i < size; i++)
+		if (hid1 == bus2core[i].hid1) {
+			gd->cpu_clk = (bus2core[i].multi * gd->bus_clk) >> 1;
+			gd->vco_clk = CONFIG_SYS_MPC8220_SYSPLL_VCO_MULTIPLIER * (gd->pci_clk * bus2core[i].vco_div)/2;
+			break;
+		}
+
+	/* hardcoded 81MHz for now */
+	gd->pev_clk = 81000000;
+
+	return (0);
+}
+
+int prt_mpc8220_clks (void)
+{
+	char buf1[32], buf2[32], buf3[32], buf4[32];
+
+	printf ("       Bus %s MHz, CPU %s MHz, PCI %s MHz, VCO %s MHz\n",
+		strmhz(buf1, gd->bus_clk),
+		strmhz(buf2, gd->cpu_clk),
+		strmhz(buf3, gd->pci_clk),
+		strmhz(buf4, gd->vco_clk)
+	);
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/ppc/cpu/mpc8220/start.S b/arch/ppc/cpu/mpc8220/start.S
new file mode 100644
index 0000000..e28999d
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/start.S
@@ -0,0 +1,750 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000 - 2003 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 MPC8220 CPUs
+ */
+#include <config.h>
+#include <mpc8220.h>
+#include <timestamp.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
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * Version string
+ */
+	.data
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+/*
+ * Exception vectors
+ */
+	.text
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD  /* Normal Power-On	    */
+	nop
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM  /* Software reboot	    */
+	b	boot_warm
+
+boot_cold:
+boot_warm:
+	mfmsr	r5		    /* save msr contents    */
+
+	/* replace default MBAR base address from 0x80000000
+	    to 0xf0000000 */
+
+#if defined(CONFIG_SYS_DEFAULT_MBAR) && !defined(CONFIG_SYS_RAMBOOT)
+	lis	r3, CONFIG_SYS_MBAR@h
+	ori	r3, r3, CONFIG_SYS_MBAR@l
+
+	/* MBAR is mirrored into the MBAR SPR */
+	mtspr	MBAR,r3
+	mtspr	SPRN_SPRG7W,r3
+	lis	r4, CONFIG_SYS_DEFAULT_MBAR@h
+	stw	r3, 0(r4)
+#endif /* CONFIG_SYS_DEFAULT_MBAR */
+
+	/* Initialise the MPC8220 processor core			*/
+	/*--------------------------------------------------------------*/
+
+	bl  init_8220_core
+
+	/* initialize some things that are hard to access from C	*/
+	/*--------------------------------------------------------------*/
+
+	/* set up stack in on-chip SRAM */
+	lis	r3, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+	ori	r1, r3, CONFIG_SYS_INIT_SP_OFFSET
+
+	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 (in Flash)*/
+
+	mr	r3, r21
+	/* r3: BOOTFLAG */
+	bl	board_init_f	/* run 1st part of board init code (in Flash)*/
+
+/*
+ * Vector Table
+ */
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+	. = 0x1300
+	/*
+	 * This exception occurs when the program counter matches the
+	 * Instruction Address Breakpoint Register (IABR).
+	 *
+	 * I want the cpu to halt if this occurs so I can hunt around
+	 * with the debugger and look at things.
+	 *
+	 * When DEBUG is defined, both machine check enable (in the MSR)
+	 * and checkstop reset enable (in the reset mode register) are
+	 * turned off and so a checkstop condition will result in the cpu
+	 * halting.
+	 *
+	 * I force the cpu into a checkstop condition by putting an illegal
+	 * instruction here (at least this is the theory).
+	 *
+	 * well - that didnt work, so just do an infinite loop!
+	 */
+1:	b	1b
+#else
+	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+	STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+	STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00	    /* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi			    /* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		    /* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			    /* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	    /* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+/*
+ * This code initialises the MPC8220 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+	.globl	init_8220_core
+init_8220_core:
+
+	/* Initialize machine status; enable machine check interrupt	*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, MSR_KERNEL	    /* Set ME and RI flags		*/
+	rlwimi	r3, r5, 0, 25, 25   /* preserve IP bit set by HRCW	*/
+#ifdef DEBUG
+	rlwimi	r3, r5, 0, 21, 22   /* debugger might set SE & BE bits	*/
+#endif
+	SYNC			    /* Some chip revs need this...	*/
+	mtmsr	r3
+	SYNC
+	mtspr	SRR1, r3	    /* Make SRR1 match MSR		*/
+
+	/* Initialize the Hardware Implementation-dependent Registers	*/
+	/* HID0 also contains cache control				*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_HID0_INIT@h
+	ori	r3, r3, CONFIG_SYS_HID0_INIT@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID0_FINAL@h
+	ori	r3, r3, CONFIG_SYS_HID0_FINAL@l
+	SYNC
+	mtspr	HID0, r3
+
+	/* Enable Extra BATs */
+	mfspr	r3, 1011    /* HID2 */
+	lis	r4, 0x0004
+	ori	r4, r4, 0x0000
+	or	r4, r4, r3
+	mtspr	1011, r4
+	sync
+
+	/* clear all BAT's						*/
+	/*--------------------------------------------------------------*/
+
+	li	r0, 0
+	mtspr	DBAT0U, r0
+	mtspr	DBAT0L, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT1L, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT2L, r0
+	mtspr	DBAT3U, r0
+	mtspr	DBAT3L, r0
+	mtspr	DBAT4U, r0
+	mtspr	DBAT4L, r0
+	mtspr	DBAT5U, r0
+	mtspr	DBAT5L, r0
+	mtspr	DBAT6U, r0
+	mtspr	DBAT6L, r0
+	mtspr	DBAT7U, r0
+	mtspr	DBAT7L, r0
+	mtspr	IBAT0U, r0
+	mtspr	IBAT0L, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT1L, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT2L, r0
+	mtspr	IBAT3U, r0
+	mtspr	IBAT3L, r0
+	mtspr	IBAT4U, r0
+	mtspr	IBAT4L, r0
+	mtspr	IBAT5U, r0
+	mtspr	IBAT5L, r0
+	mtspr	IBAT6U, r0
+	mtspr	IBAT6L, r0
+	mtspr	IBAT7U, r0
+	mtspr	IBAT7L, r0
+	SYNC
+
+	/* invalidate all tlb's						*/
+	/*								*/
+	/* From the 603e User Manual: "The 603e provides the ability to */
+	/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)	*/
+	/* instruction invalidates the TLB entry indexed by the EA, and */
+	/* operates on both the instruction and data TLBs simultaneously*/
+	/* invalidating four TLB entries (both sets in each TLB). The	*/
+	/* index corresponds to bits 15-19 of the EA. To invalidate all */
+	/* entries within both TLBs, 32 tlbie instructions should be	*/
+	/* issued, incrementing this field by one each time."		*/
+	/*								*/
+	/* "Note that the tlbia instruction is not implemented on the	*/
+	/* 603e."							*/
+	/*								*/
+	/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000	*/
+	/* incrementing by 0x1000 each time. The code below is sort of	*/
+	/* based on code in "flush_tlbs" from arch/ppc/kernel/head.S	*/
+	/*								*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, 32
+	mtctr	r3
+	li	r3, 0
+1:	tlbie	r3
+	addi	r3, r3, 0x1000
+	bdnz	1b
+	SYNC
+
+	/* Done!							*/
+	/*--------------------------------------------------------------*/
+
+	blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+	.globl	icache_enable
+icache_enable:
+	lis	r4, 0
+	ori	r4, r4, CONFIG_SYS_HID0_INIT /* set ICE & ICFI bit		*/
+	rlwinm	r3, r4, 0, 21, 19     /* clear the ICFI bit		*/
+
+	/*
+	 * The setting of the instruction cache enable (ICE) bit must be
+	 * preceded by an isync instruction to prevent the cache from being
+	 * enabled or disabled while an instruction access is in progress.
+	 */
+	isync
+	mtspr	HID0, r4	      /* Enable Instr Cache & Inval cache */
+	mtspr	HID0, r3	      /* using 2 consec instructions	*/
+	isync
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, 0, 17, 15     /* clear the ICE bit		*/
+	mtspr	HID0, r3
+	isync
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	lis	r4, 0
+	ori	r4, r4, HID0_DCE|HID0_DCFI /* set DCE & DCFI bit	*/
+	rlwinm	r3, r4, 0, 22, 20     /* clear the DCFI bit		*/
+
+	/* Enable address translation in MSR bit */
+	mfmsr	r5
+	ori	r5, r5, 0x
+
+
+	/*
+	 * The setting of the instruction cache enable (ICE) bit must be
+	 * preceded by an isync instruction to prevent the cache from being
+	 * enabled or disabled while an instruction access is in progress.
+	 */
+	isync
+	mtspr	HID0, r4	      /* Enable Data Cache & Inval cache*/
+	mtspr	HID0, r3	      /* using 2 consec instructions	*/
+	isync
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, 0, 18, 16     /* clear the DCE bit */
+	mtspr	HID0, r3
+	isync
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+	blr
+
+	.globl	get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3	    /* Set new stack pointer		*/
+	mr	r9,  r4	    /* Save copy of Global Data pointer */
+	mr	r10, r5	    /* Save copy of Destination Address */
+
+	GET_GOT
+	mr	r3,  r5	    /* Destination Address		*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h	/* Source Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE	/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f	    /* In place copy is not necessary	*/
+	beq	7f	    /* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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
+	mfspr	r7,HID0	    /* don't do dcbst if dcache is disabled	*/
+	rlwinm	r7,r7,HID0_DCE_BITPOS+1,31,31
+	cmpwi	r7,0
+	beq	9f
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync		    /* Wait for all dcbst to complete on bus	*/
+9:	mfspr	r7,HID0	    /* don't do icbi if icache is disabled	*/
+	rlwinm	r7,r7,HID0_ICE_BITPOS+1,31,31
+	cmpwi	r7,0
+	beq	7f
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync		    /* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9	    /* Global Data pointer	*/
+	mr	r4, r10	    /* Destination Address	*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4	    /* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100   /* reset vector always at 0x100	*/
+
+	cmplw	0, r7, r8
+	bgelr		    /* return if r7>=r8 - just in case	*/
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100	    /* next exception vector	    */
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100	    /* next exception vector	    */
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100	    /* next exception vector	    */
+	cmplw	0, r7, r8
+	blt	4b
+
+	mfmsr	r3		    /* now that the vectors have    */
+	lis	r7, MSR_IP@h	    /* relocated into low memory    */
+	ori	r7, r7, MSR_IP@l    /* MSR[IP] can be turned off    */
+	andc	r3, r3, r7	    /* (if it was on)		    */
+	SYNC			    /* Some chip revs need this...  */
+	mtmsr	r3
+	SYNC
+
+	mtlr	r4		    /* restore link register	    */
+	blr
diff --git a/arch/ppc/cpu/mpc8220/traps.c b/arch/ppc/cpu/mpc8220/traps.c
new file mode 100644
index 0000000..4565780
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/traps.c
@@ -0,0 +1,236 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de)
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table (unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM      0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void print_backtrace (unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf ("Call backtrace: ");
+	while (sp) {
+		if ((uint) sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf ("\n");
+		printf ("%08lX ", i);
+		if (cnt > 32)
+			break;
+		sp = (unsigned long *) *sp;
+	}
+	printf ("\n");
+}
+
+void show_regs (struct pt_regs *regs)
+{
+	int i;
+
+	printf ("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+		regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf ("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+		regs->msr,
+		regs->msr & MSR_EE ? 1 : 0, regs->msr & MSR_PR ? 1 : 0,
+		regs->msr & MSR_FP ? 1 : 0, regs->msr & MSR_ME ? 1 : 0,
+		regs->msr & MSR_IR ? 1 : 0, regs->msr & MSR_DR ? 1 : 0);
+
+	printf ("\n");
+	for (i = 0; i < 32; i++) {
+		if ((i % 8) == 0) {
+			printf ("GPR%02d: ", i);
+		}
+
+		printf ("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			printf ("\n");
+		}
+	}
+}
+
+
+void _exception (int signr, struct pt_regs *regs)
+{
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Exception in kernel pc %lx signal %d", regs->nip, signr);
+}
+
+void MachineCheckException (struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table (regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+
+	printf ("Machine check in kernel mode.\n");
+	printf ("Caused by (from msr): ");
+	printf ("regs %p ", regs);
+	/* refer to 603e Manual (MPC603EUM/AD), chapter 4.5.2.1 */
+	switch (regs->msr & 0x000F0000) {
+	case (0x80000000 >> 12):
+		printf ("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000 >> 13):
+		printf ("Transfer error ack signal\n");
+		break;
+	case (0x80000000 >> 14):
+		printf ("Data parity signal\n");
+		break;
+	case (0x80000000 >> 15):
+		printf ("Address parity signal\n");
+		break;
+	default:
+		printf ("Unknown values in msr\n");
+	}
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("machine check");
+}
+
+void AlignmentException (struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Alignment Exception");
+}
+
+void ProgramCheckException (struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Program Check Exception");
+}
+
+void SoftEmuException (struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Software Emulation Exception");
+}
+
+
+void UnknownException (struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	printf ("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+		regs->nip, regs->msr, regs->trap);
+	_exception (0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint (struct pt_regs *);
+#endif
+
+void DebugException (struct pt_regs *regs)
+{
+
+	printf ("Debugger trap at @ %lx\n", regs->nip);
+	show_regs (regs);
+#if defined(CONFIG_CMD_BEDBUG)
+	do_bedbug_breakpoint (regs);
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe (uint * addr)
+{
+#if 0
+	int retval;
+
+	__asm__ __volatile__ ("1: lwz %0,0(%1)\n"
+			      "   eieio\n"
+			      "   li %0,0\n"
+			      "2:\n"
+			      ".section .fixup,\"ax\"\n"
+			      "3: li %0,-1\n"
+			      "   b 2b\n"
+			      ".section __ex_table,\"a\"\n"
+			      "   .align 2\n"
+			      "   .long 1b,3b\n"
+			      ".text":"=r" (retval):"r" (addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8220/u-boot.lds b/arch/ppc/cpu/mpc8220/u-boot.lds
new file mode 100644
index 0000000..8c5d307
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/u-boot.lds
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    arch/ppc/cpu/mpc8220/start.o	(.text)
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc8220/uart.c b/arch/ppc/cpu/mpc8220/uart.c
new file mode 100644
index 0000000..0c4b536
--- /dev/null
+++ b/arch/ppc/cpu/mpc8220/uart.c
@@ -0,0 +1,126 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PSC_BASE   MMAP_PSC1
+
+#if defined(CONFIG_PSC_CONSOLE)
+int serial_init (void)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+	u32 counter;
+
+	/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
+	psc->cr = 0;
+	psc->ipcr_acr = 0;
+	psc->isr_imr = 0;
+
+	/* write to CSR: RX/TX baud rate from timers */
+	psc->sr_csr = 0xdd000000;
+
+	psc->mr1_2 = PSC_MR1_BITS_CHAR_8 | PSC_MR1_NO_PARITY | PSC_MR2_STOP_BITS_1;
+
+	/* Setting up BaudRate */
+	counter = ((gd->bus_clk / gd->baudrate)) >> 5;
+	counter++;
+
+	/* write to CTUR: divide counter upper byte */
+	psc->ctur = ((counter & 0xff00) << 16);
+	/* write to CTLR: divide counter lower byte */
+	psc->ctlr = ((counter & 0x00ff) << 24);
+
+	psc->cr = PSC_CR_RST_RX_CMD;
+	psc->cr = PSC_CR_RST_TX_CMD;
+	psc->cr = PSC_CR_RST_ERR_STS_CMD;
+	psc->cr = PSC_CR_RST_BRK_INT_CMD;
+	psc->cr = PSC_CR_RST_MR_PTR_CMD;
+
+	psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE;
+	return (0);
+}
+
+void serial_putc (const char c)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	/* Wait for last character to go. */
+	while (!(psc->sr_csr & PSC_SR_TXRDY));
+
+	psc->xmitbuf[0] = c;
+}
+
+void serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int serial_getc (void)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+	/* Wait for a character to arrive. */
+	while (!(psc->sr_csr & PSC_SR_RXRDY));
+	return psc->xmitbuf[2];
+}
+
+int serial_tstc (void)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+	return (psc->sr_csr & PSC_SR_RXRDY);
+}
+
+void serial_setbrg (void)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+	u32 counter;
+
+	counter = ((gd->bus_clk / gd->baudrate)) >> 5;
+	counter++;
+
+	/* write to CTUR: divide counter upper byte */
+	psc->ctur = ((counter & 0xff00) << 16);
+	/* write to CTLR: divide counter lower byte */
+	psc->ctlr = ((counter & 0x00ff) << 24);
+
+	psc->cr = PSC_CR_RST_RX_CMD;
+	psc->cr = PSC_CR_RST_TX_CMD;
+
+	psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE;
+}
+#endif /* CONFIG_PSC_CONSOLE */
diff --git a/arch/ppc/cpu/mpc824x/.gitignore b/arch/ppc/cpu/mpc824x/.gitignore
new file mode 100644
index 0000000..2d79931
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/.gitignore
@@ -0,0 +1 @@
+/bedbug_603e.c
diff --git a/arch/ppc/cpu/mpc824x/Makefile b/arch/ppc/cpu/mpc824x/Makefile
new file mode 100644
index 0000000..a57ad12
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/Makefile
@@ -0,0 +1,56 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+ifneq ($(OBJTREE),$(SRCTREE))
+$(shell mkdir -p $(obj)drivers/epic)
+$(shell mkdir -p $(obj)drivers/i2c)
+endif
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+COBJS	= traps.o cpu.o cpu_init.o interrupts.o speed.o \
+	  drivers/epic/epic1.o drivers/i2c/i2c.o pci.o
+COBJS_LN = bedbug_603e.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) $(addprefix $(obj),$(COBJS_LN:.o=.c))
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS) $(COBJS_LN))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+$(obj)bedbug_603e.c:
+	ln -sf $(src)../mpc8260/bedbug_603e.c $(obj)bedbug_603e.c
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc824x/config.mk b/arch/ppc/cpu/mpc824x/config.mk
new file mode 100644
index 0000000..31ecd20
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/config.mk
@@ -0,0 +1,29 @@
+#
+# (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
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC824X -ffixed-r2 -mstring -mcpu=603e -msoft-float
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc824x/u-boot.lds
diff --git a/arch/ppc/cpu/mpc824x/cpu.c b/arch/ppc/cpu/mpc824x/cpu.c
new file mode 100644
index 0000000..08f6a94
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/cpu.c
@@ -0,0 +1,280 @@
+/*
+ * (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 <config.h>
+#include <mpc824x.h>
+#include <common.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+	unsigned int pvr = get_pvr ();
+	unsigned int version = pvr >> 16;
+	unsigned char revision;
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+
+	puts ("CPU:   ");
+
+	switch (version) {
+	case CPU_TYPE_8240:
+		puts ("MPC8240");
+		break;
+
+	case CPU_TYPE_8245:
+		puts ("MPC8245");
+		break;
+
+	default:
+		return -1;		/*not valid for this source */
+	}
+
+	CONFIG_READ_BYTE (REVID, revision);
+
+	if (revision) {
+		printf (" Revision %d.%d",
+			(revision & 0xf0) >> 4,
+			(revision & 0x0f));
+	} else {
+		return -1;		/* no valid CPU revision info */
+	}
+
+	printf (" at %s MHz:", strmhz (buf, clock));
+
+	printf (" %u kB I-Cache", checkicache () >> 10);
+	printf (" %u kB D-Cache", checkdcache () >> 10);
+
+	puts ("\n");
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache                                                                */
+
+int checkicache (void)
+{
+	 /*TODO*/
+	 return 128 * 4 * 32;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache                                                                */
+
+int checkdcache (void)
+{
+	 /*TODO*/
+	 return 128 * 4 * 32;
+
+};
+
+/*------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	ulong msr, addr;
+
+	/* Interrupts and MMU off */
+	__asm__ ("mtspr    81, 0");
+
+	/* Interrupts and MMU off */
+	__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 CONFIG_SYS_RESET_ADDRESS
+	addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address,
+	 * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid
+	 * address. Better pick an address known to be invalid on
+	 * your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+	 * "(ulong)-1" used to be a good choice for many systems...
+	 */
+	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+	((void (*)(void)) addr) ();
+	return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ * This is the sys_logic_clk (memory bus) divided by 4
+ */
+unsigned long get_tbclk (void)
+{
+	return ((get_bus_freq (0) + 2L) / 4L);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * The MPC824x has an integrated PCI controller known as the MPC107.
+ * The following are MPC107 Bridge Controller and PCI Support functions
+ *
+ */
+
+/*
+ *  This procedure reads a 32-bit address MPC107 register, and returns
+ *  a 32 bit value.  It swaps the address to little endian before
+ *  writing it to config address, and swaps the value to big endian
+ *  before returning to the caller.
+ */
+unsigned int mpc824x_mpc107_getreg (unsigned int regNum)
+{
+	unsigned int temp;
+
+	/* swap the addr. to little endian */
+	*(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum);
+	temp = *(volatile unsigned int *) CHRP_REG_DATA;
+	return PCISWAP (temp);		/* swap the data upon return */
+}
+
+/*
+ *  This procedure writes a 32-bit address MPC107 register.  It swaps
+ *  the address to little endian before writing it to config address.
+ */
+
+void mpc824x_mpc107_setreg (unsigned int regNum, unsigned int regVal)
+{
+	/* swap the addr. to little endian */
+	*(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum);
+	*(volatile unsigned int *) CHRP_REG_DATA = PCISWAP (regVal);
+	return;
+}
+
+
+/*
+ *  Write a byte (8 bits) to a memory location.
+ */
+void mpc824x_mpc107_write8 (unsigned int addr, unsigned char data)
+{
+	*(unsigned char *) addr = data;
+	__asm__ ("sync");
+}
+
+/*
+ *  Write a word (16 bits) to a memory location after the value
+ *  has been byte swapped (big to little endian or vice versa)
+ */
+
+void mpc824x_mpc107_write16 (unsigned int address, unsigned short data)
+{
+	*(volatile unsigned short *) address = BYTE_SWAP_16_BIT (data);
+	__asm__ ("sync");
+}
+
+/*
+ *  Write a long word (32 bits) to a memory location after the value
+ *  has been byte swapped (big to little endian or vice versa)
+ */
+
+void mpc824x_mpc107_write32 (unsigned int address, unsigned int data)
+{
+	*(volatile unsigned int *) address = LONGSWAP (data);
+	__asm__ ("sync");
+}
+
+/*
+ *  Read a byte (8 bits) from a memory location.
+ */
+unsigned char mpc824x_mpc107_read8 (unsigned int addr)
+{
+	return *(volatile unsigned char *) addr;
+}
+
+
+/*
+ *  Read a word (16 bits) from a memory location, and byte swap the
+ *  value before returning to the caller.
+ */
+unsigned short mpc824x_mpc107_read16 (unsigned int address)
+{
+	unsigned short retVal;
+
+	retVal = BYTE_SWAP_16_BIT (*(unsigned short *) address);
+	return retVal;
+}
+
+
+/*
+ *  Read a long word (32 bits) from a memory location, and byte
+ *  swap the value before returning to the caller.
+ */
+unsigned int mpc824x_mpc107_read32 (unsigned int address)
+{
+	unsigned int retVal;
+
+	retVal = LONGSWAP (*(unsigned int *) address);
+	return (retVal);
+}
+
+
+/*
+ *  Read a register in the Embedded Utilities Memory Block address
+ *  space.
+ *  Input: regNum - register number + utility base address.  Example,
+ *         the base address of EPIC is 0x40000, the register number
+ *	   being passed is 0x40000+the address of the target register.
+ *	   (See epic.h for register addresses).
+ *  Output:  The 32 bit little endian value of the register.
+ */
+
+unsigned int mpc824x_eummbar_read (unsigned int regNum)
+{
+	unsigned int temp;
+
+	temp = *(volatile unsigned int *) (EUMBBAR_VAL + regNum);
+	temp = PCISWAP (temp);
+	return temp;
+}
+
+
+/*
+ *  Write a value to a register in the Embedded Utilities Memory
+ *  Block address space.
+ *  Input: regNum - register number + utility base address.  Example,
+ *                  the base address of EPIC is 0x40000, the register
+ *	            number is 0x40000+the address of the target register.
+ *	            (See epic.h for register addresses).
+ *         regVal - value to be written to the register.
+ */
+
+void mpc824x_eummbar_write (unsigned int regNum, unsigned int regVal)
+{
+	*(volatile unsigned int *) (EUMBBAR_VAL + regNum) = PCISWAP (regVal);
+	return;
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/ppc/cpu/mpc824x/cpu_init.c b/arch/ppc/cpu/mpc824x/cpu_init.c
new file mode 100644
index 0000000..395f776
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/cpu_init.c
@@ -0,0 +1,417 @@
+/*
+ * (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 CONFIG_SYS_BANK0_ROW
+#define CONFIG_SYS_BANK0_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK1_ROW
+#define CONFIG_SYS_BANK1_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK2_ROW
+#define CONFIG_SYS_BANK2_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK3_ROW
+#define CONFIG_SYS_BANK3_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK4_ROW
+#define CONFIG_SYS_BANK4_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK5_ROW
+#define CONFIG_SYS_BANK5_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK6_ROW
+#define CONFIG_SYS_BANK6_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK7_ROW
+#define CONFIG_SYS_BANK7_ROW 0
+#endif
+#ifndef CONFIG_SYS_DBUS_SIZE2
+#define CONFIG_SYS_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 */
+	CONFIG_WRITE_BYTE (PLTR, 0x40); /* set PCI latency timer */
+	/*
+	* 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);
+#ifdef CONFIG_MPC8245
+	/* silicon bug 28 MPC8245 */
+	CONFIG_READ_BYTE(AMBOR,val);
+	CONFIG_WRITE_BYTE(AMBOR,val|0x1);
+
+#if 0
+	/*
+	 * The following bug only affects older (XPC8245) processors.
+	 * DMA transfers initiated by external devices get corrupted due
+	 * to a hardware scheduling problem.
+	 *
+	 * The effect is:
+	 * when transferring X words, the first 32 words are transferred
+	 * OK, the next 3 x 32 words are 'old' data (from previous DMA)
+	 * while the rest of the X words is xferred fine.
+	 *
+	 * Disabling 3 of the 4 32 word hardware buffers solves the problem
+	 * with no significant performance loss.
+	 */
+
+	CONFIG_READ_BYTE(PCMBCR,val);
+	/* in order not to corrupt data which is being read over the PCI bus
+	* with the PPC as slave, we need to reduce the number of PCMRBs to 1,
+	* 4.11 in the  processor user manual
+	* */
+
+#if 1
+	CONFIG_WRITE_BYTE(PCMBCR,(val|0xC0)); /* 1 PCMRB */
+#else
+	CONFIG_WRITE_BYTE(PCMBCR,(val|0x80)); /* 2 PCMRBs */
+	CONFIG_WRITE_BYTE(PCMBCR,(val|0x40)); /* 3 PCMRBs */
+	/* default, 4 PCMRBs are used */
+#endif
+#endif
+#endif
+
+	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, CONFIG_SYS_EUMB_ADDR);
+#ifndef CONFIG_SYS_RAMBOOT
+	CONFIG_WRITE_WORD(MCCR1, (CONFIG_SYS_ROMNAL << MCCR1_ROMNAL_SHIFT) |
+				 (CONFIG_SYS_BANK0_ROW) |
+				 (CONFIG_SYS_BANK1_ROW << MCCR1_BANK1ROW_SHIFT) |
+				 (CONFIG_SYS_BANK2_ROW << MCCR1_BANK2ROW_SHIFT) |
+				 (CONFIG_SYS_BANK3_ROW << MCCR1_BANK3ROW_SHIFT) |
+				 (CONFIG_SYS_BANK4_ROW << MCCR1_BANK4ROW_SHIFT) |
+				 (CONFIG_SYS_BANK5_ROW << MCCR1_BANK5ROW_SHIFT) |
+				 (CONFIG_SYS_BANK6_ROW << MCCR1_BANK6ROW_SHIFT) |
+				 (CONFIG_SYS_BANK7_ROW << MCCR1_BANK7ROW_SHIFT) |
+				 (CONFIG_SYS_ROMFAL << MCCR1_ROMFAL_SHIFT));
+#endif
+
+#if defined(CONFIG_SYS_ASRISE) && defined(CONFIG_SYS_ASFALL)
+	CONFIG_WRITE_WORD(MCCR2, CONFIG_SYS_REFINT << MCCR2_REFINT_SHIFT |
+				 CONFIG_SYS_ASRISE << MCCR2_ASRISE_SHIFT |
+				 CONFIG_SYS_ASFALL << MCCR2_ASFALL_SHIFT);
+#else
+	CONFIG_WRITE_WORD(MCCR2, CONFIG_SYS_REFINT << MCCR2_REFINT_SHIFT);
+#endif
+
+#if defined(CONFIG_MPC8240)
+	CONFIG_WRITE_WORD(MCCR3,
+		(((CONFIG_SYS_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+		(CONFIG_SYS_REFREC << MCCR3_REFREC_SHIFT) |
+		(CONFIG_SYS_RDLAT  << MCCR3_RDLAT_SHIFT));
+#elif defined(CONFIG_MPC8245)
+	CONFIG_WRITE_WORD(MCCR3,
+		(((CONFIG_SYS_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+		(CONFIG_SYS_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 CONFIG_SYS_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,
+	(CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+	(CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+	MCCR4_BIT21 |
+	(CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+	((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+	(((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) |
+		  CONFIG_SYS_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) |
+	(CONFIG_SYS_ACTORW << MCCR4_ACTTORW_SHIFT) |
+	(((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) << MCCR4_BSTOPRE6TO9_SHIFT));
+#elif defined(CONFIG_MPC8240)
+	CONFIG_WRITE_WORD(MCCR4,
+	(CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+	(CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+	MCCR4_BIT21 |
+	(CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+	((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+	(((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) |
+		  (CONFIG_SYS_SDMODE_BURSTLEN)) <<MCCR4_SDMODE_SHIFT) |
+	(((CONFIG_SYS_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,
+		(CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+		(CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+		(CONFIG_SYS_EXTROM ? MCCR4_EXTROM : 0) |
+		(CONFIG_SYS_REGDIMM ? MCCR4_REGDIMM : 0) |
+		(CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+		((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+		(CONFIG_SYS_DBUS_SIZE2 << MCCR4_DBUS_SIZE2_SHIFT) |
+		(((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) |
+		      (val ? 2 : 3)) << MCCR4_SDMODE_SHIFT)  |
+		(CONFIG_SYS_ACTORW << MCCR4_ACTTORW_SHIFT) |
+		(((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+	CONFIG_WRITE_WORD(MSAR1,
+		( (CONFIG_SYS_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+		(((CONFIG_SYS_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(EMSAR1,
+		( (CONFIG_SYS_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+		(((CONFIG_SYS_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(MSAR2,
+		( (CONFIG_SYS_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+		(((CONFIG_SYS_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(EMSAR2,
+		( (CONFIG_SYS_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+		(((CONFIG_SYS_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(MEAR1,
+		( (CONFIG_SYS_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+		(((CONFIG_SYS_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(EMEAR1,
+		( (CONFIG_SYS_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+		(((CONFIG_SYS_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(MEAR2,
+		( (CONFIG_SYS_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+		(((CONFIG_SYS_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+	CONFIG_WRITE_WORD(EMEAR2,
+		( (CONFIG_SYS_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+		(((CONFIG_SYS_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+		(((CONFIG_SYS_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+		(((CONFIG_SYS_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+
+	CONFIG_WRITE_BYTE(ODCR, CONFIG_SYS_ODCR);
+#ifdef CONFIG_SYS_DLL_MAX_DELAY
+	CONFIG_WRITE_BYTE(MIOCR1, CONFIG_SYS_DLL_MAX_DELAY);	/* needed to make DLL lock */
+#endif
+#if defined(CONFIG_SYS_DLL_EXTEND) && defined(CONFIG_SYS_PCI_HOLD_DEL)
+	CONFIG_WRITE_BYTE(PMCR2, CONFIG_SYS_DLL_EXTEND | CONFIG_SYS_PCI_HOLD_DEL);
+#endif
+#if defined(MIOCR2) && defined(CONFIG_SYS_SDRAM_DSCD)
+	CONFIG_WRITE_BYTE(MIOCR2, CONFIG_SYS_SDRAM_DSCD);	/* change memory input */
+#endif /* setup & hold time */
+
+	CONFIG_WRITE_BYTE(MBER,
+		 CONFIG_SYS_BANK0_ENABLE |
+		(CONFIG_SYS_BANK1_ENABLE << 1) |
+		(CONFIG_SYS_BANK2_ENABLE << 2) |
+		(CONFIG_SYS_BANK3_ENABLE << 3) |
+		(CONFIG_SYS_BANK4_ENABLE << 4) |
+		(CONFIG_SYS_BANK5_ENABLE << 5) |
+		(CONFIG_SYS_BANK6_ENABLE << 6) |
+		(CONFIG_SYS_BANK7_ENABLE << 7));
+
+#ifdef CONFIG_SYS_PGMAX
+	CONFIG_WRITE_BYTE(MPMR, CONFIG_SYS_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 +  0x00, "MPC107 Vendor/Device ID"		},
+	{ BMC_BASE +  0x04, "MPC107 PCI Command/Status Register" },
+	{ BMC_BASE +  0x08, "MPC107 Revision"			},
+	{ BMC_BASE +  0x0C, "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/arch/ppc/cpu/mpc824x/drivers/epic.h b/arch/ppc/cpu/mpc824x/drivers/epic.h
new file mode 100644
index 0000000..2803f63
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/epic.h
@@ -0,0 +1 @@
+#include "epic/epic.h"
diff --git a/arch/ppc/cpu/mpc824x/drivers/epic/README b/arch/ppc/cpu/mpc824x/drivers/epic/README
new file mode 100644
index 0000000..5798996
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/epic/README
@@ -0,0 +1,102 @@
+CONTENT:
+
+   epic.h
+   epic1.c
+   epic2.s
+
+WHAT ARE THESE FILES:
+
+These files contain MPC8240 (Kahlua) EPIC
+driver routines. The driver routines are not
+written for any specific operating system.
+They serves the purpose of code sample, and
+jump-start for using the MPC8240 EPIC unit.
+
+For the reason of correctness of C language
+syntax, these files are compiled by Metaware
+C compiler and assembler.
+
+ENDIAN NOTATION:
+
+The algorithm is designed for big-endian mode,
+software is responsible for byte swapping.
+
+USAGE:
+
+1. The host system that is running on MPC8240
+   shall link the files listed here. The memory
+   location of driver routines shall take into
+   account of that driver routines need to run
+   in supervisor mode and they process external
+   interrupts.
+
+   The routine epic_exception shall be called by
+   exception vector at location 0x500, i.e.,
+   603e core external exception vector.
+
+2. The host system is responsible for configuring
+   the MPC8240 including Embedded Utilities Memory
+   Block. All EPIC driver functions require the
+   content of Embedded Utilities Memory Block
+   Base Address Register, EUMBBAR, as the first
+   parameter.
+
+3. Before EPIC unit of MPC8240 can be used,
+   initialize EPIC unit by calling epicInit
+   with the corresponding parameters.
+
+   The initialization shall disable the 603e
+   core External Exception by calling CoreExtIntDisable( ).
+   Next, call epicInit( ). Last, enable the 603e core
+   External Exception by calling CoreExtIntEnable( ).
+
+4. After EPIC unit has been successfully initialized,
+   epicIntSourceSet( ) shall be used to register each
+   external interrupt source. Anytime, an external
+   interrupt source can be disabled or enabled by
+   calling corresponding function, epicIntDisable( ),
+   or epicIntEnable( ).
+
+   Global Timers' resource, base count and frequency,
+   can be changed by calling epicTmFrequencySet( )
+   and epicTmBaseSet( ).
+
+   To stop counting a specific global timer, use
+   the function, epicTmInhibit while epicTmEnable
+   can be used to start counting a timer.
+
+5. To mask a set of external interrupts that are
+   are certain level below, epicIntPrioritySet( )
+   can be used. For example, if the processor's
+   current task priority register is set to 0x7,
+   only interrupts of priority 0x8 or higher will
+   be passed to the processor.
+
+   Be careful when using this function. It may
+   corrupt the current interrupt pending, selector,
+   and request registers, resulting an invalid vetor.
+
+   After enabling an interrupt, disable it may also
+   cause an invalid vector. User may consider using
+   the spurious vector interrupt service routine to
+   handle this case.
+
+6. The EPIC driver routines contains a set
+   of utilities, Set and Get, for host system
+   to query and modify the desired EPIC source
+   registers.
+
+7. Each external interrupt source shall register
+   its interrupt service routine. The routine
+   shall contain all interrupt source specific
+   processes and keep as short as possible.
+
+   Special customized end of interrupt routine
+   is optional. If it is needed, it shall contain
+   the external interrupt source specific end of
+   interrupt process.
+
+   External interrupt exception vector at 0x500
+   shall always call the epicEOI just before
+   rfi instruction. Refer to the routine,
+   epic_exception, for a code sample.
diff --git a/arch/ppc/cpu/mpc824x/drivers/epic/epic.h b/arch/ppc/cpu/mpc824x/drivers/epic/epic.h
new file mode 100644
index 0000000..58f81c5
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/epic/epic.h
@@ -0,0 +1,163 @@
+/*********************************************************************
+ * mpc8240epic.h - EPIC module of the MPC8240 micro-controller
+ *
+ * Copyrigh 1999  Motorola Inc.
+ *
+ * Modification History:
+ * =====================
+ * 01a,04Feb99,My  Created.
+ * 15Nov200, robt -modified to use in U-Boot
+ *
+*/
+
+#ifndef __INCEPICh
+#define __INCEPICh
+
+#define ULONG unsigned long
+#define MAXVEC             20
+#define MAXIRQ        5 /* IRQs */
+#define EPIC_DIRECT_IRQ     0 /* Direct interrupt type */
+
+/* EPIC register addresses */
+
+#define EPIC_EUMBBAR      0x40000     /* EUMBBAR of EPIC  */
+#define EPIC_FEATURES_REG (EPIC_EUMBBAR + 0x01000)/* Feature reporting */
+#define EPIC_GLOBAL_REG   (EPIC_EUMBBAR + 0x01020)/* Global config.  */
+#define EPIC_INT_CONF_REG (EPIC_EUMBBAR + 0x01030)/* Interrupt config. */
+#define EPIC_VENDOR_ID_REG  (EPIC_EUMBBAR + 0x01080)/* Vendor id */
+#define EPIC_PROC_INIT_REG  (EPIC_EUMBBAR + 0x01090)/* Processor init. */
+#define EPIC_SPUR_VEC_REG (EPIC_EUMBBAR + 0x010e0)/* Spurious vector */
+#define EPIC_TM_FREQ_REG  (EPIC_EUMBBAR + 0x010f0)/* Timer Frequency */
+
+#define EPIC_TM0_CUR_COUNT_REG  (EPIC_EUMBBAR + 0x01100)/* Gbl TM0 Cur. Count*/
+#define EPIC_TM0_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01110)/* Gbl TM0 Base Count*/
+#define EPIC_TM0_VEC_REG  (EPIC_EUMBBAR + 0x01120)/* Gbl TM0 Vector Pri*/
+#define EPIC_TM0_DES_REG  (EPIC_EUMBBAR + 0x01130)/* Gbl TM0 Dest. */
+
+#define EPIC_TM1_CUR_COUNT_REG  (EPIC_EUMBBAR + 0x01140)/* Gbl TM1 Cur. Count*/
+#define EPIC_TM1_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01150)/* Gbl TM1 Base Count*/
+#define EPIC_TM1_VEC_REG  (EPIC_EUMBBAR + 0x01160)/* Gbl TM1 Vector Pri*/
+#define EPIC_TM1_DES_REG  (EPIC_EUMBBAR + 0x01170)/* Gbl TM1 Dest. */
+
+#define EPIC_TM2_CUR_COUNT_REG  (EPIC_EUMBBAR + 0x01180)/* Gbl TM2 Cur. Count*/
+#define EPIC_TM2_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01190)/* Gbl TM2 Base Count*/
+#define EPIC_TM2_VEC_REG  (EPIC_EUMBBAR + 0x011a0)/* Gbl TM2 Vector Pri*/
+#define EPIC_TM2_DES_REG  (EPIC_EUMBBAR + 0x011b0)/* Gbl TM2 Dest */
+
+#define EPIC_TM3_CUR_COUNT_REG  (EPIC_EUMBBAR + 0x011c0)/* Gbl TM3 Cur. Count*/
+#define EPIC_TM3_BASE_COUNT_REG (EPIC_EUMBBAR + 0x011d0)/* Gbl TM3 Base Count*/
+#define EPIC_TM3_VEC_REG  (EPIC_EUMBBAR + 0x011e0)/* Gbl TM3 Vector Pri*/
+#define EPIC_TM3_DES_REG  (EPIC_EUMBBAR + 0x011f0)/* Gbl TM3 Dest. */
+
+#define EPIC_EX_INT0_VEC_REG  (EPIC_EUMBBAR + 0x10200)/* Ext. Int. Sr0 Des */
+#define EPIC_EX_INT0_DES_REG  (EPIC_EUMBBAR + 0x10210)/* Ext. Int. Sr0 Vect*/
+#define EPIC_EX_INT1_VEC_REG  (EPIC_EUMBBAR + 0x10220)/* Ext. Int. Sr1 Des */
+#define EPIC_EX_INT1_DES_REG  (EPIC_EUMBBAR + 0x10230)/* Ext. Int. Sr1 Vect*/
+#define EPIC_EX_INT2_VEC_REG  (EPIC_EUMBBAR + 0x10240)/* Ext. Int. Sr2 Des */
+#define EPIC_EX_INT2_DES_REG  (EPIC_EUMBBAR + 0x10250)/* Ext. Int. Sr2 Vect*/
+#define EPIC_EX_INT3_VEC_REG  (EPIC_EUMBBAR + 0x10260)/* Ext. Int. Sr3 Des */
+#define EPIC_EX_INT3_DES_REG  (EPIC_EUMBBAR + 0x10270)/* Ext. Int. Sr3 Vect*/
+#define EPIC_EX_INT4_VEC_REG  (EPIC_EUMBBAR + 0x10280)/* Ext. Int. Sr4 Des */
+#define EPIC_EX_INT4_DES_REG  (EPIC_EUMBBAR + 0x10290)/* Ext. Int. Sr4 Vect*/
+
+#define EPIC_SR_INT0_VEC_REG  (EPIC_EUMBBAR + 0x10200)/* Sr. Int. Sr0 Des */
+#define EPIC_SR_INT0_DES_REG  (EPIC_EUMBBAR + 0x10210)/* Sr. Int. Sr0 Vect */
+#define EPIC_SR_INT1_VEC_REG  (EPIC_EUMBBAR + 0x10220)/* Sr. Int. Sr1 Des */
+#define EPIC_SR_INT1_DES_REG  (EPIC_EUMBBAR + 0x10230)/* Sr. Int. Sr1 Vect.*/
+#define EPIC_SR_INT2_VEC_REG  (EPIC_EUMBBAR + 0x10240)/* Sr. Int. Sr2 Des */
+#define EPIC_SR_INT2_DES_REG  (EPIC_EUMBBAR + 0x10250)/* Sr. Int. Sr2 Vect.*/
+#define EPIC_SR_INT3_VEC_REG  (EPIC_EUMBBAR + 0x10260)/* Sr. Int. Sr3 Des */
+#define EPIC_SR_INT3_DES_REG  (EPIC_EUMBBAR + 0x10270)/* Sr. Int. Sr3 Vect.*/
+#define EPIC_SR_INT4_VEC_REG  (EPIC_EUMBBAR + 0x10280)/* Sr. Int. Sr4 Des */
+#define EPIC_SR_INT4_DES_REG  (EPIC_EUMBBAR + 0x10290)/* Sr. Int. Sr4 Vect.*/
+
+#define EPIC_SR_INT5_VEC_REG  (EPIC_EUMBBAR + 0x102a0)/* Sr. Int. Sr5 Des */
+#define EPIC_SR_INT5_DES_REG  (EPIC_EUMBBAR + 0x102b0)/* Sr. Int. Sr5 Vect.*/
+#define EPIC_SR_INT6_VEC_REG  (EPIC_EUMBBAR + 0x102c0)/* Sr. Int. Sr6 Des */
+#define EPIC_SR_INT6_DES_REG  (EPIC_EUMBBAR + 0x102d0)/* Sr. Int. Sr6 Vect.*/
+#define EPIC_SR_INT7_VEC_REG  (EPIC_EUMBBAR + 0x102e0)/* Sr. Int. Sr7 Des */
+#define EPIC_SR_INT7_DES_REG  (EPIC_EUMBBAR + 0x102f0)/* Sr. Int. Sr7 Vect.*/
+#define EPIC_SR_INT8_VEC_REG  (EPIC_EUMBBAR + 0x10300)/* Sr. Int. Sr8 Des */
+#define EPIC_SR_INT8_DES_REG  (EPIC_EUMBBAR + 0x10310)/* Sr. Int. Sr8 Vect.*/
+#define EPIC_SR_INT9_VEC_REG  (EPIC_EUMBBAR + 0x10320)/* Sr. Int. Sr9 Des */
+#define EPIC_SR_INT9_DES_REG  (EPIC_EUMBBAR + 0x10330)/* Sr. Int. Sr9 Vect.*/
+
+#define EPIC_SR_INT10_VEC_REG (EPIC_EUMBBAR + 0x10340)/* Sr. Int. Sr10 Des */
+#define EPIC_SR_INT10_DES_REG (EPIC_EUMBBAR + 0x10350)/* Sr. Int. Sr10 Vect*/
+#define EPIC_SR_INT11_VEC_REG (EPIC_EUMBBAR + 0x10360)/* Sr. Int. Sr11 Des */
+#define EPIC_SR_INT11_DES_REG (EPIC_EUMBBAR + 0x10370)/* Sr. Int. Sr11 Vect*/
+#define EPIC_SR_INT12_VEC_REG (EPIC_EUMBBAR + 0x10380)/* Sr. Int. Sr12 Des */
+#define EPIC_SR_INT12_DES_REG (EPIC_EUMBBAR + 0x10390)/* Sr. Int. Sr12 Vect*/
+#define EPIC_SR_INT13_VEC_REG (EPIC_EUMBBAR + 0x103a0)/* Sr. Int. Sr13 Des */
+#define EPIC_SR_INT13_DES_REG (EPIC_EUMBBAR + 0x103b0)/* Sr. Int. Sr13 Vect*/
+#define EPIC_SR_INT14_VEC_REG (EPIC_EUMBBAR + 0x103c0)/* Sr. Int. Sr14 Des */
+#define EPIC_SR_INT14_DES_REG (EPIC_EUMBBAR + 0x103d0)/* Sr. Int. Sr14 Vect*/
+#define EPIC_SR_INT15_VEC_REG (EPIC_EUMBBAR + 0x103e0)/* Sr. Int. Sr15 Des */
+#define EPIC_SR_INT15_DES_REG (EPIC_EUMBBAR + 0x103f0)/* Sr. Int. Sr15 Vect*/
+
+#define EPIC_I2C_INT_VEC_REG  (EPIC_EUMBBAR + 0x11020)/* I2C Int. Vect Pri.*/
+#define EPIC_I2C_INT_DES_REG  (EPIC_EUMBBAR + 0x11030)/* I2C Int. Dest */
+#define EPIC_DMA0_INT_VEC_REG (EPIC_EUMBBAR + 0x11040)/* DMA0 Int. Vect Pri*/
+#define EPIC_DMA0_INT_DES_REG (EPIC_EUMBBAR + 0x11050)/* DMA0 Int. Dest */
+#define EPIC_DMA1_INT_VEC_REG (EPIC_EUMBBAR + 0x11060)/* DMA1 Int. Vect Pri*/
+#define EPIC_DMA1_INT_DES_REG (EPIC_EUMBBAR + 0x11070)/* DMA1 Int. Dest */
+#define EPIC_MSG_INT_VEC_REG  (EPIC_EUMBBAR + 0x110c0)/* Msg Int. Vect Pri*/
+#define EPIC_MSG_INT_DES_REG  (EPIC_EUMBBAR + 0x110d0)/* Msg Int. Dest  */
+
+#define EPIC_PROC_CTASK_PRI_REG (EPIC_EUMBBAR + 0x20080)/* Proc. current task*/
+#define EPIC_PROC_INT_ACK_REG (EPIC_EUMBBAR + 0x200a0)/* Int. acknowledge */
+#define EPIC_PROC_EOI_REG (EPIC_EUMBBAR + 0x200b0)/* End of interrupt */
+
+#define EPIC_VEC_PRI_MASK      0x80000000 /* Mask Interrupt bit in IVPR */
+#define EPIC_VEC_PRI_DFLT_PRI  8          /* Interrupt Priority in IVPR */
+
+/* Error code */
+
+#define OK       0
+#define ERROR    -1
+
+/* function prototypes */
+
+void epicVendorId( unsigned int *step,
+       unsigned int *devId,
+       unsigned int *venId
+     );
+void epicFeatures( unsigned int *noIRQs,
+	     unsigned int *noCPUs,
+       unsigned int *VerId );
+extern void epicInit( unsigned int IRQType, unsigned int clkRatio);
+ULONG sysEUMBBARRead ( ULONG regNum );
+void sysEUMBBARWrite ( ULONG regNum, ULONG regVal);
+extern void epicTmFrequencySet( unsigned int frq );
+extern unsigned int epicTmFrequencyGet(void);
+extern unsigned int epicTmBaseSet( ULONG srcAddr,
+		 unsigned int cnt,
+		 unsigned int inhibit );
+extern unsigned int epicTmBaseGet ( ULONG srcAddr, unsigned int *val );
+extern unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val );
+extern unsigned int epicTmInhibit( unsigned int timer );
+extern unsigned int epicTmEnable( ULONG srcAdr );
+extern void CoreExtIntEnable(void);  /* Enable 603e external interrupts */
+extern void CoreExtIntDisable(void); /* Disable 603e external interrupts */
+extern unsigned char epicIntTaskGet(void);
+extern void epicIntTaskSet( unsigned char val );
+extern unsigned int epicIntAck(void);
+extern void epicSprSet( unsigned int eumbbar, unsigned char );
+extern void epicConfigGet( unsigned int *clkRatio,
+	       unsigned int *serEnable );
+extern void SrcVecTableInit(void);
+extern unsigned int  epicModeGet(void);
+extern void epicIntEnable(int Vect);
+extern void epicIntDisable(int Vect);
+extern int epicIntSourceConfig(int Vect, int Polarity, int Sense, int Prio);
+extern unsigned int epicIntAck(void);
+extern void epicEOI(void);
+extern int epicCurTaskPrioSet(int Vect);
+
+struct SrcVecTable
+    {
+     ULONG srcAddr;
+     char  srcName[40];
+    };
+
+#endif   /*  EPIC_H */
diff --git a/arch/ppc/cpu/mpc824x/drivers/epic/epic1.c b/arch/ppc/cpu/mpc824x/drivers/epic/epic1.c
new file mode 100644
index 0000000..ecbb42d
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/epic/epic1.c
@@ -0,0 +1,517 @@
+/**************************************************
+ *
+ * copyright @ motorola, 1999
+ *
+ *************************************************/
+#include <mpc824x.h>
+#include <common.h>
+#include "epic.h"
+
+
+#define PRINT(format, args...) printf(format , ## args)
+
+typedef void (*VOIDFUNCPTR)  (void);  /* ptr to function returning void */
+struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */
+    {
+    { EPIC_EX_INT0_VEC_REG,  "External Direct/Serial Source 0"},
+    { EPIC_EX_INT1_VEC_REG,  "External Direct/Serial Source 1"},
+    { EPIC_EX_INT2_VEC_REG,  "External Direct/Serial Source 2"},
+    { EPIC_EX_INT3_VEC_REG,  "External Direct/Serial Source 3"},
+    { EPIC_EX_INT4_VEC_REG,  "External Direct/Serial Source 4"},
+
+    { EPIC_SR_INT5_VEC_REG,  "External Serial Source 5"},
+    { EPIC_SR_INT6_VEC_REG,  "External Serial Source 6"},
+    { EPIC_SR_INT7_VEC_REG,  "External Serial Source 7"},
+    { EPIC_SR_INT8_VEC_REG,  "External Serial Source 8"},
+    { EPIC_SR_INT9_VEC_REG,  "External Serial Source 9"},
+    { EPIC_SR_INT10_VEC_REG, "External Serial Source 10"},
+    { EPIC_SR_INT11_VEC_REG, "External Serial Source 11"},
+    { EPIC_SR_INT12_VEC_REG, "External Serial Source 12"},
+    { EPIC_SR_INT13_VEC_REG, "External Serial Source 13"},
+    { EPIC_SR_INT14_VEC_REG, "External Serial Source 14"},
+    { EPIC_SR_INT15_VEC_REG, "External Serial Source 15"},
+
+    { EPIC_I2C_INT_VEC_REG,  "Internal I2C Source"},
+    { EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"},
+    { EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"},
+    { EPIC_MSG_INT_VEC_REG,  "Internal Message Source"},
+    };
+
+VOIDFUNCPTR intVecTbl[MAXVEC];    /* Interrupt vector table */
+
+
+/****************************************************************************
+*  epicInit - Initialize the EPIC registers
+*
+*  This routine resets the Global Configuration Register, thus it:
+*     -  Disables all interrupts
+*     -  Sets epic registers to reset values
+*     -  Sets the value of the Processor Current Task Priority to the
+*        highest priority (0xF).
+*  epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass
+*  Through or 8259 compatible mode).
+*
+*  If IRQType (input) is Direct IRQs:
+*     - IRQType is written to the SIE bit of the EPIC Interrupt
+*       Configuration register (ICR).
+*     - clkRatio is ignored.
+*  If IRQType is Serial IRQs:
+*     - both IRQType and clkRatio will be written to the ICR register
+*/
+
+void epicInit
+    (
+    unsigned int IRQType,      /* Direct or Serial */
+    unsigned int clkRatio      /* Clk Ratio for Serial IRQs */
+    )
+    {
+    ULONG tmp;
+
+    tmp = sysEUMBBARRead(EPIC_GLOBAL_REG);
+    tmp |= 0xa0000000;                  /* Set the Global Conf. register */
+    sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp);
+	/*
+	 * Wait for EPIC to reset - CLH
+	 */
+    while( (sysEUMBBARRead(EPIC_GLOBAL_REG) & 0x80000000) == 1);
+    sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000);
+    tmp = sysEUMBBARRead(EPIC_INT_CONF_REG);    /* Read interrupt conf. reg */
+
+    if (IRQType == EPIC_DIRECT_IRQ)             /* direct mode */
+	sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff);
+    else                                        /* Serial mode */
+	{
+	tmp = (clkRatio << 28) | 0x08000000;    /* Set clock ratio */
+	sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp);
+	}
+
+    while (epicIntAck() != 0xff)       /* Clear all pending interrupts */
+		epicEOI();
+}
+
+/****************************************************************************
+ *  epicIntEnable - Enable an interrupt source
+ *
+ *  This routine clears the mask bit of an external, an internal or
+ *  a Timer register to enable the interrupt.
+ *
+ *  RETURNS:  None
+ */
+void epicIntEnable(int intVec)
+{
+    ULONG tmp;
+    ULONG srAddr;
+
+    srAddr = SrcVecTable[intVec].srcAddr;  /* Retrieve src Vec/Prio register */
+    tmp = sysEUMBBARRead(srAddr);
+    tmp &= ~EPIC_VEC_PRI_MASK;             /* Clear the mask bit */
+    tmp |= (EPIC_VEC_PRI_DFLT_PRI << 16);   /* Set priority to Default - CLH */
+    tmp |= intVec;				           /* Set Vector number */
+    sysEUMBBARWrite(srAddr, tmp);
+
+    return;
+    }
+
+/****************************************************************************
+ *  epicIntDisable - Disable an interrupt source
+ *
+ *  This routine sets the mask bit of an external, an internal or
+ *  a Timer register to disable the interrupt.
+ *
+ *  RETURNS:  OK or ERROR
+ *
+ */
+
+void epicIntDisable
+    (
+    int intVec        /* Interrupt vector number */
+    )
+    {
+
+    ULONG tmp, srAddr;
+
+    srAddr = SrcVecTable[intVec].srcAddr;
+    tmp = sysEUMBBARRead(srAddr);
+    tmp |= 0x80000000;                      /* Set the mask bit */
+    sysEUMBBARWrite(srAddr, tmp);
+    return;
+    }
+
+/****************************************************************************
+ * epicIntSourceConfig - Set properties of an interrupt source
+ *
+ * This function sets interrupt properites (Polarity, Sense, Interrupt
+ * Prority, and Interrupt Vector) of an Interrupt Source.  The properties
+ * can be set when the current source is not in-request or in-service,
+ * which is determined by the Activity bit.  This routine return ERROR
+ * if the the Activity bit is 1 (in-request or in-service).
+ *
+ * This function assumes that the Source Vector/Priority register (input)
+ * is a valid address.
+ *
+ * RETURNS:  OK or ERROR
+ */
+
+int epicIntSourceConfig
+    (
+    int   Vect,                         /* interrupt source vector number */
+    int   Polarity,                     /* interrupt source polarity */
+    int   Sense,                        /* interrupt source Sense */
+    int   Prio                          /* interrupt source priority */
+    )
+
+    {
+    ULONG tmp, newVal;
+    ULONG actBit, srAddr;
+
+    srAddr = SrcVecTable[Vect].srcAddr;
+    tmp = sysEUMBBARRead(srAddr);
+    actBit = (tmp & 40000000) >> 30;    /* retrieve activity bit - bit 30 */
+    if (actBit == 1)
+	return ERROR;
+
+    tmp &= 0xff30ff00;     /* Erase previously set P,S,Prio,Vector bits */
+    newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect;
+    sysEUMBBARWrite(srAddr, tmp | newVal );
+    return (OK);
+    }
+
+/****************************************************************************
+ * epicIntAck - acknowledge an interrupt
+ *
+ * This function reads the Interrupt acknowldge register and return
+ * the vector number of the highest pending interrupt.
+ *
+ * RETURNS: Interrupt Vector number.
+ */
+
+unsigned int epicIntAck(void)
+{
+    return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG ));
+}
+
+/****************************************************************************
+ * epicEOI - signal an end of interrupt
+ *
+ * This function writes 0x0 to the EOI register to signal end of interrupt.
+ * It is usually called after an interrupt routine is served.
+ *
+ * RETURNS: None
+ */
+
+void epicEOI(void)
+    {
+    sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0);
+    }
+
+/****************************************************************************
+ *  epicCurTaskPrioSet - sets the priority of the Processor Current Task
+ *
+ *  This function should be called after epicInit() to lower the priority
+ *  of the processor current task.
+ *
+ *  RETURNS:  OK or ERROR
+ */
+
+int epicCurTaskPrioSet
+    (
+    int prioNum                 /* New priority value */
+    )
+    {
+
+    if ( (prioNum < 0) || (prioNum > 0xF))
+	return ERROR;
+    sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum);
+    return OK;
+    }
+
+
+/************************************************************************
+ * function: epicIntTaskGet
+ *
+ * description: Get value of processor current interrupt task priority register
+ *
+ * note:
+ ***********************************************************************/
+unsigned char epicIntTaskGet()
+{
+  /* get the interrupt task priority register */
+    ULONG reg;
+    unsigned char rec;
+
+    reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG );
+    rec = ( reg & 0x0F );
+    return rec;
+}
+
+
+/**************************************************************
+ * function: epicISR
+ *
+ * description: EPIC service routine called by the core exception
+ *              at 0x500
+ *
+ * note:
+ **************************************************************/
+unsigned int epicISR(void)
+{
+   return 0;
+}
+
+
+/************************************************************
+ * function: epicModeGet
+ *
+ * description: query EPIC mode, return 0 if pass through mode
+ *                               return 1 if mixed mode
+ *
+ * note:
+ *************************************************************/
+unsigned int epicModeGet(void)
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( EPIC_GLOBAL_REG );
+    return (( val & 0x20000000 ) >> 29);
+}
+
+
+/*********************************************
+ * function: epicConfigGet
+ *
+ * description: Get the EPIC interrupt Configuration
+ *              return 0 if not error, otherwise return 1
+ *
+ * note:
+ ********************************************/
+void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable)
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( EPIC_INT_CONF_REG );
+    *clkRatio = ( val & 0x70000000 ) >> 28;
+    *serEnable = ( val & 0x8000000 ) >> 27;
+}
+
+
+/*******************************************************************
+ *  sysEUMBBARRead - Read a 32-bit EUMBBAR register
+ *
+ *  This routine reads the content of a register in the Embedded
+ *  Utilities Memory Block, and swaps to big endian before returning
+ *  the value.
+ *
+ *  RETURNS:  The content of the specified EUMBBAR register.
+ */
+
+ULONG sysEUMBBARRead
+    (
+    ULONG regNum
+    )
+    {
+    ULONG temp;
+
+    temp = *(ULONG *) (CONFIG_SYS_EUMB_ADDR + regNum);
+    return ( LONGSWAP(temp));
+    }
+
+/*******************************************************************
+ *  sysEUMBBARWrite - Write a 32-bit EUMBBAR register
+ *
+ *  This routine swaps the value to little endian then writes it to
+ *  a register in the Embedded Utilities Memory Block address space.
+ *
+ *  RETURNS: N/A
+ */
+
+void sysEUMBBARWrite
+    (
+    ULONG regNum,               /* EUMBBAR register address */
+    ULONG regVal                /* Value to be written */
+    )
+    {
+
+    *(ULONG *) (CONFIG_SYS_EUMB_ADDR + regNum) = LONGSWAP(regVal);
+    return ;
+    }
+
+
+/********************************************************
+ * function: epicVendorId
+ *
+ * description: return the EPIC Vendor Identification
+ *              register:
+ *
+ *              siliccon version, device id, and vendor id
+ *
+ * note:
+ ********************************************************/
+void epicVendorId
+   (
+    unsigned int *step,
+    unsigned int *devId,
+    unsigned int *venId
+   )
+   {
+    ULONG val;
+    val = sysEUMBBARRead( EPIC_VENDOR_ID_REG );
+    *step  = ( val & 0x00FF0000 ) >> 16;
+    *devId = ( val & 0x0000FF00 ) >> 8;
+    *venId = ( val & 0x000000FF );
+    }
+
+/**************************************************
+ * function: epicFeatures
+ *
+ * description: return the number of IRQ supported,
+ *              number of CPU, and the version of the
+ *              OpenEPIC
+ *
+ * note:
+ *************************************************/
+void epicFeatures
+    (
+    unsigned int *noIRQs,
+    unsigned int *noCPUs,
+    unsigned int *verId
+    )
+    {
+    ULONG val;
+
+    val = sysEUMBBARRead( EPIC_FEATURES_REG );
+    *noIRQs  = ( val & 0x07FF0000 ) >> 16;
+    *noCPUs  = ( val & 0x00001F00 ) >> 8;
+    *verId   = ( val & 0x000000FF );
+}
+
+
+/*********************************************************
+ * function: epciTmFrequncySet
+ *
+ * description: Set the timer frequency reporting register
+ ********************************************************/
+void epicTmFrequencySet( unsigned int frq )
+{
+    sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq);
+}
+
+/*******************************************************
+ * function: epicTmFrequncyGet
+ *
+ * description: Get the current value of the Timer Frequency
+ * Reporting register
+ *
+ ******************************************************/
+unsigned int epicTmFrequencyGet(void)
+{
+    return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ;
+}
+
+
+/****************************************************
+ * function: epicTmBaseSet
+ *
+ * description: Set the #n global timer base count register
+ *              return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ****************************************************/
+unsigned int epicTmBaseSet
+    (
+    ULONG srcAddr,         /* Address of the Timer Base register */
+    unsigned int cnt,    /* Base count */
+    unsigned int inhibit   /* 1 - count inhibit */
+    )
+{
+
+    unsigned int val = 0x80000000;
+    /* First inhibit counting the timer */
+    sysEUMBBARWrite(srcAddr, val) ;
+
+    /* set the new value */
+    val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31);
+    sysEUMBBARWrite(srcAddr, val) ;
+    return 0;
+}
+
+/***********************************************************************
+ * function: epicTmBaseGet
+ *
+ * description: Get the current value of the global timer base count register
+ *              return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ***********************************************************************/
+unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val )
+{
+    *val = sysEUMBBARRead( srcAddr );
+    *val = *val & 0x7fffffff;
+    return 0;
+}
+
+/***********************************************************
+ * function: epicTmCountGet
+ *
+ * description: Get the value of a given global timer
+ *              current count register
+ *              return 0 if no error, otherwise return 1
+ * note:
+ **********************************************************/
+unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val )
+{
+    *val = sysEUMBBARRead( srcAddr );
+    *val = *val & 0x7fffffff;
+    return 0;
+}
+
+
+/***********************************************************
+ * function: epicTmInhibit
+ *
+ * description: Stop counting of a given global timer
+ *              return 0 if no error, otherwise return 1
+ *
+ * note:
+ ***********************************************************/
+unsigned int epicTmInhibit( unsigned int srcAddr )
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( srcAddr );
+    val |= 0x80000000;
+    sysEUMBBARWrite( srcAddr, val );
+    return 0;
+}
+
+/******************************************************************
+ * function: epicTmEnable
+ *
+ * description: Enable counting of a given global timer
+ *              return 0 if no error, otherwise return 1
+ *
+ * note:
+ *****************************************************************/
+unsigned int epicTmEnable( ULONG srcAddr )
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( srcAddr );
+    val &= 0x7fffffff;
+    sysEUMBBARWrite( srcAddr, val );
+    return 0;
+}
+
+void epicSourcePrint(int Vect)
+    {
+    ULONG srcVal;
+
+    srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr);
+    PRINT("%s\n", SrcVecTable[Vect].srcName);
+    PRINT("Address   = 0x%lx\n", SrcVecTable[Vect].srcAddr);
+    PRINT("Vector    = %ld\n", (srcVal & 0x000000FF) );
+    PRINT("Mask      = %ld\n", srcVal >> 31);
+    PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30);
+    PRINT("Polarity  = %ld\n", (srcVal & 0x00800000) >> 23);
+    PRINT("Sense     = %ld\n", (srcVal & 0x00400000) >> 22);
+    PRINT("Priority  = %ld\n", (srcVal & 0x000F0000) >> 16);
+    }
diff --git a/arch/ppc/cpu/mpc824x/drivers/epic/epic2.S b/arch/ppc/cpu/mpc824x/drivers/epic/epic2.S
new file mode 100644
index 0000000..52d19aa
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/epic/epic2.S
@@ -0,0 +1,196 @@
+/**************************************
+ *
+ * copyright @ Motorola, 1999
+ *
+ **************************************/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/processor.h>
+
+/*********************************************
+ * function: CoreExtIntEnable
+ *
+ * description: Enable 603e core external interrupt
+ *
+ * note: mtmsr is context-synchronization
+ **********************************************/
+		.text
+		.align 2
+	.global CoreExtIntEnable
+CoreExtIntEnable:
+	 mfmsr    r3
+
+	 ori      r3,r3,0x8000         /* enable external interrupt */
+	 mtmsr    r3
+
+	 bclr 20, 0
+
+/*******************************************
+ * function: CoreExtIntDisable
+ *
+ * description: Disable 603e core external interrupt
+ *
+ * note:
+ *******************************************/
+		.text
+		.align 2
+	.global CoreExtIntDisable
+CoreExtIntDisable:
+	mfmsr    r4
+
+	xor	r3,r3,r3
+	or      r3,r3,r4
+
+	andis.	r4,r4,0xffff
+	andi.   r3,r3,0x7fff         /* disable external interrupt */
+
+	or      r3,r3,r4
+	mtmsr    r3
+
+	bclr 20, 0
+
+/*********************************************************
+ * function: epicEOI
+ *
+ * description: signal the EOI and restore machine status
+ *       Input: r3 - value of eumbbar
+ *       Output: r3 - value of eumbbar
+ *               r4 - ISR vector value
+ * note:
+ ********************************************************/
+		.text
+		.align 2
+	.global epicEOI
+epicEOI:
+	lis	r5,0x0006	        /* Build End Of Interrupt Register offset */
+	ori	r5,r5,0x00b0
+	xor	r7,r7,r7	        /* Clear r7 */
+	stwbrx	r7,r5,r3	    /* Save r7, writing to this register will
+					     * intidate the end of processing the
+					     * highest interrupt.
+			     */
+	sync
+
+	/* ---RESTORE MACHINE STATE */
+	mfmsr	r13		        /* Clear Recoverable Interrupt bit in MSR */
+	or      r7,r7,r13
+
+	andis.  r7,r7,0xffff
+	andi.	r13,r13,0x7ffd	/* (and disable interrupts) */
+	or      r13,r13,r7
+	mtmsr	r13
+
+	lwz   r13,0x1c(r1)      /* pull ctr */
+	mtctr r13
+
+	lwz   r13,0x18(r1)      /* pull xer */
+	mtctr r13
+
+	lwz   r13,0x14(r1)      /* pull lr */
+	mtctr r13
+
+	lwz	    r13,0x10(r1)	/* Pull SRR1 from stack */
+	mtspr   SRR1,r13	    /* Restore SRR1 */
+
+	lwz	    r13,0xc(r1)	    /* Pull SRR0 from stack */
+	mtspr   SRR0,r13	    /* Restore SRR0 */
+
+	lwz	    r13,0x8(r1)	    /* Pull User stack pointer from stack */
+	mtspr   SPRG1,r13	    /* Restore SPRG1 */
+
+	lwz	r4,0x4(r1)          /* vector value */
+	lwz	r3,0x0(r1)          /* eumbbar */
+	sync
+
+	addi	r1,r1,0x20	/* Deallocate stack */
+	mtspr   SPRG0,r1	/* Save updated Supervisor stack pointer */
+	mfspr   r1,SPRG1	/* Restore User stack pointer */
+
+	bclr     20,0
+
+/***********************************************************
+ * function: exception routine called by exception vector
+ *           at 0x500, external interrupt
+ *
+ * description: Kahlua EPIC controller
+ *
+ * input:  r3 - content of eumbbar
+ * output: r3 - ISR return value
+ *         r4 - Interrupt vector number
+ * note:
+ ***********************************************************/
+
+       .text
+	   .align 2
+       .global epic_exception
+
+epic_exception:
+
+	/*---SAVE MACHINE STATE TO A STACK */
+	mtspr   SPRG1,r1	/* Save User stack pointer to SPRG1 */
+	mfspr	r1,SPRG0	/* Load Supervisor stack pointer into r1 */
+
+	stwu	r3,-0x20(r1)	/* Push the value of eumbbar onto stack */
+
+	mfspr	r3,SPRG1	/* Push User stack pointer onto stack */
+	stw	    r3,0x8(r1)
+	mfspr	r3,SRR0	    /* Push SRR0 onto stack */
+	stw	    r1,0xc(r1)
+	mfspr	r3,SRR1	    /* Push SRR1 onto stack */
+	stw	    r3,0x10(r1)
+	mflr    r3
+	stw     r3,0x14(r1) /* Push LR */
+	mfxer   r3
+	stw     r3,0x18(r1) /* Push Xer */
+	mfctr   r3
+	stw     r3,0x1c(r1) /* Push CTR */
+
+	mtspr	SPRG0,r1	/* Save updated Supervisor stack pointer
+					 * value to SPRG0
+			 */
+	mfmsr	r3
+	ori	    r3,r3,0x0002	/* Set Recoverable Interrupt bit in MSR */
+	mtmsr	r3
+
+	/* ---READ IN THE EUMBAR REGISTER */
+    lwz     r6,0(r1)       /* this is eumbbar */
+    sync
+
+	/* ---READ EPIC REGISTER:	PROCESSOR INTERRUPT ACKNOWLEDGE REGISTER */
+	lis	r5,0x0006	        /* Build Interrupt Acknowledge Register
+					     * offset
+			     */
+	ori	r5,r5,0x00a0
+	lwbrx	r7,r5,r6    /* Load interrupt vector into r7 */
+	sync
+
+	/* --MASK OFF ALL BITS EXCEPT THE VECTOR */
+	xor	r3,r3,r3
+    xor r4,r4,r4
+	or    r3, r3, r6        /*  eumbbar in r3 */
+	andi. r4,r7,0x00ff	/* Mask off bits, vector in r4 */
+
+    stw     r4,0x04(r1)     /* save the vector value */
+
+    lis     r5,epicISR@ha
+	ori     r5,r5,epicISR@l
+	mtlr    r5
+	blrl
+
+    xor   r30,r30,r30
+	or    r30,r30,r3        /* save the r3 which containts the return value from epicISR */
+
+	/* ---READ IN THE EUMBAR REGISTER */
+    lwz     r3,0(r1)
+    sync
+
+    lis     r5,epicEOI@ha
+	ori     r5,r5,epicEOI@l
+	mtlr    r5
+	blrl
+
+    xor  r3,r3,r3
+	or   r3,r3,r30           /* restore the ISR return value  */
+
+	bclr     20,0
diff --git a/arch/ppc/cpu/mpc824x/drivers/epic/epicutil.S b/arch/ppc/cpu/mpc824x/drivers/epic/epicutil.S
new file mode 100644
index 0000000..4877050
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/epic/epicutil.S
@@ -0,0 +1,57 @@
+/**************************************
+ *
+ * copyright @ Motorola, 1999
+ *
+ *
+ * This file contains two commonly used
+ * lower level utility routines.
+ *
+ * The utility routines are also in other
+ * Kahlua device driver libraries. The
+ * need to be linked in only once.
+ **************************************/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+/**********************************************************
+ * function: load_runtime_reg
+ *
+ * input:  r3 - value of eumbbar
+ *         r4 - register offset in embedded utility space
+ *
+ * output: r3 - register content
+ **********************************************************/
+      .text
+      .align 2
+      .global load_runtime_reg
+
+load_runtime_reg:
+
+		  xor r5,r5,r5
+	  or  r5,r5,r3       /* save eumbbar */
+
+	      lwbrx	r3,r4,r5
+	      sync
+
+	      bclr 20, 0
+
+/****************************************************************
+ * function: store_runtime_reg
+ *
+ * input: r3 - value of eumbbar
+ *        r4 - register offset in embedded utility space
+ *        r5 - new value to be stored
+ *
+ ****************************************************************/
+	   .text
+	   .align 2
+	   .global store_runtime_reg
+store_runtime_reg:
+
+		  xor r0,r0,r0
+
+	      stwbrx r5,  r4, r3
+	      sync
+
+		  bclr   20,0
diff --git a/arch/ppc/cpu/mpc824x/drivers/errors.h b/arch/ppc/cpu/mpc824x/drivers/errors.h
new file mode 100644
index 0000000..20794a2
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/errors.h
@@ -0,0 +1,212 @@
+/*	Copyright Motorola, Inc. 1993, 1994
+	ALL RIGHTS RESERVED
+
+	You are hereby granted a copyright license to use, modify, and
+	distribute the SOFTWARE so long as this entire notice is retained
+	without alteration in any modified and/or redistributed versions,
+	and that such modified versions are clearly identified as such.
+	No licenses are granted by implication, estoppel or otherwise under
+	any patents or trademarks of Motorola, Inc.
+
+	The SOFTWARE is provided on an "AS IS" basis and without warranty.
+	To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS
+	ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED
+	WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+	PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
+	REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS
+	THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS.
+
+	To the maximum extent permitted by applicable law, IN NO EVENT SHALL
+	MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+	(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF
+	BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
+	INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR
+	INABILITY TO USE THE SOFTWARE.   Motorola assumes no responsibility
+	for the maintenance and support of the SOFTWARE.
+
+*/
+
+
+#include "config.h"
+
+/*
+	 1         2         3         4         5         6         7         8
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+*/
+/* List define statements here */
+
+/* These are for all the toolboxes and functions to use. These will help
+to standardize the error handling in the current project */
+
+				/* this is the "data type" for the error
+				messages in the system */
+#define STATUS unsigned int
+
+				/* this is a success status code */
+#define SUCCESS 1
+
+				/* likewise this is failure */
+#define FAILURE 0
+
+#define NUM_ERRORS 47
+
+/* This first section of "defines" are for error codes ONLY.  The called
+   routine will return one of these error codes to the caller.  If the final
+   returned code is "VALID", then everything is a-okay.  However, if one
+   of the functions returns a non-valid status, that error code should be
+   propogated back to all the callers.  At the end, the last caller will
+   call an error_processing function, and send in the status which was
+   returned.  It's up to the error_processing function to determine which
+   error occured (as indicated by the status), and print an appropriate
+   message back to the user.
+*/
+/*----------------------------------------------------------------------*/
+/* these are specifically for the parser routines			*/
+
+#define UNKNOWN_COMMAND		0xfb00 /* "unrecognized command " */
+#define UNKNOWN_REGISTER	0xfb01 /* "unknown register "*/
+#define ILLEGAL_RD_STAGE	0xfb02 /* cannot specify reg. family in range*/
+#define ILLEGAL_REG_FAMILY	0xfb03 /* "cannot specify a range of special
+					or miscellaneous registers"*/
+#define RANGE_CROSS_FAMILY	0xfb04 /* "cannot specify a range across
+					register families" */
+#define UNIMPLEMENTED_STAGE	0xfb05 /* invalid rd or rmm parameter format */
+#define REG_NOT_WRITEABLE	0xfb06 /* "unknown operator in arguements"*/
+#define INVALID_FILENAME	0xfb07 /* "invalid download filename" */
+#define INVALID_BAUD_RATE	0xfb08	/* invalid baud rate from sb command */
+#define UNSUPPORTED_REGISTER	0xfb09	/* Special register is not supported */
+#define FOR_BOARD_ONLY		0xfb0a  /* "Not available for Unix." */
+
+
+/*----------------------------------------------------------------------*/
+/* these are for the error checking toolbox				*/
+
+#define INVALID			0xfd00 /* NOT valid */
+#define VALID			0xfd01 /* valid */
+
+					/* This error is found in the fcn:
+					is_right_size_input() to indicate
+					that the input was not 8 characters
+					long.  */
+#define INVALID_SIZE		0xfd02
+
+					/* This error is found in the fcn:
+					is_valid_address_range() to indicate
+					that the address given falls outside
+					of valid memory defined by MEM_START
+					to MEM_END.
+					*/
+#define OUT_OF_BOUNDS_ADDRESS	0xfd03
+
+					/* This error is found in the fcn:
+					is_valid_hex_input() to indicate that
+					one of more of the characters entered
+					are not valid hex characters.  Valid
+					hex characters are 0-9, A-F, a-f.
+					*/
+#define INVALID_HEX_INPUT	0xfd04
+
+					/* This error is found in the fcn:
+					is_valid_register_number() to indicate
+					that a given register does not exist.
+					*/
+#define REG_NOT_READABLE	0xfd05
+
+					/* This error is found in the fcn:
+					is_word_aligned_address() to indicate
+					that the given address is not word-
+					aligned.  A word-aligned address ends
+					in 0x0,0x4,0x8,0xc.
+					*/
+#define	NOT_WORD_ALIGNED	0xfd07
+
+					/* This error is found in the fcn:
+					is_valid_address_range() to indicate
+					that the starting address is greater
+					than the ending address.
+					*/
+#define REVERSED_ADDRESS	0xfd08
+
+					/* this error tells us that the address
+					specified as the destination is within
+					the source addresses  */
+#define RANGE_OVERLAP		0xfd09
+
+
+#define	ERROR			0xfd0a /* An error occured */
+#define INVALID_PARAM		0xfd0b /* "invalid input parameter " */
+
+
+#define INVALID_FLAG		0xfd0c	/* invalid flag */
+
+/*----------------------------------------------------------------------*/
+/* these are for the getarg toolbox					*/
+
+#define INVALID_NUMBER_ARGS	0xFE00 /* invalid number of commd arguements */
+#define UNKNOWN_PARAMETER	0xFE01 /* "unknown type of parameter "*/
+
+
+/*----------------------------------------------------------------------*/
+/* these are for the tokenizer toolbox					*/
+
+#define ILLEGAL_CHARACTER	0xFF00 /* unrecognized char. in input stream*/
+#define TTL_NOT_SORTED		0xFF01 /* token translation list not sorted */
+#define TTL_NOT_DEFINED		0xFF02 /* token translation list not assigned*/
+#define INVALID_STRING		0xFF03 /* unable to extract string from input */
+#define BUFFER_EMPTY		0xFF04 /* "input buffer is empty" */
+#define INVALID_MODE		0xFF05 /* input buf is in an unrecognized mode*/
+#define TOK_INTERNAL_ERROR	0xFF06 /* "internal tokenizer error" */
+#define TOO_MANY_IBS		0xFF07 /* "too many open input buffers" */
+#define NO_OPEN_IBS		0xFF08 /* "no open input buffers" */
+
+
+/* these are for the read from screen toolbox */
+
+#define RESERVED_WORD		0xFC00 /* used a reserved word as an arguement*/
+
+
+/* these are for the breakpoint routines */
+
+#define FULL_BPDS		0xFA00 /* breakpoint data structure is full */
+
+
+/* THESE are for the downloader */
+
+#define NOT_IN_S_RECORD_FORMAT	0xf900 /* "not in S-Record Format" */
+#define UNREC_RECORD_TYPE	0xf901 /* "unrecognized record type" */
+#define CONVERSION_ERROR	0xf902 /* "ascii to int conversion error" */
+#define INVALID_MEMORY		0xf903 /* "bad s-record memory address " */
+
+
+/* these are for the compression and decompression stuff */
+
+#define COMP_UNK_CHARACTER	0xf800 /* "unknown compressed character " */
+
+#define COMP_UNKNOWN_STATE	0xf801 /* "unknown binary state" */
+
+#define NOT_IN_COMPRESSED_FORMAT 0xf802 /* not in compressed S-Record format */
+
+
+/* these are for the DUART handling things */
+
+					/* "unrecognized serial port configuration" */
+#define UNKNOWN_PORT_STATE	0xf700
+
+
+/* these are for the register toolbox */
+
+					/* "cannot find register in special
+					 purpose register file " */
+#define SPR_NOT_FOUND		0xf600
+
+
+/* these are for the duart specific stuff */
+
+					/* "transparent mode needs access to
+						two serial ports" */
+#define TM_NEEDS_BOTH_PORTS	0xf500
+
+
+/*----------------------------------------------------------------------*/
+/* these are specifically for the flash routines			*/
+#define FLASH_ERROR		0xf100		/* general flash error */
diff --git a/arch/ppc/cpu/mpc824x/drivers/i2c/i2c.c b/arch/ppc/cpu/mpc824x/drivers/i2c/i2c.c
new file mode 100644
index 0000000..637ae4c
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/i2c/i2c.c
@@ -0,0 +1,270 @@
+/*
+ * (C) Copyright 2003
+ * Gleb Natapov <gnatapov@mrv.com>
+ * Some bits are taken from linux driver writen by adrian@humboldt.co.uk
+ *
+ * Hardware I2C driver for MPC107 PCI bridge.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#undef I2CDBG
+
+#ifdef CONFIG_HARD_I2C
+#include <i2c.h>
+
+#define TIMEOUT (CONFIG_SYS_HZ/4)
+
+#define I2C_Addr ((unsigned *)(CONFIG_SYS_EUMB_ADDR + 0x3000))
+
+#define I2CADR &I2C_Addr[0]
+#define I2CFDR  &I2C_Addr[1]
+#define I2CCCR  &I2C_Addr[2]
+#define I2CCSR  &I2C_Addr[3]
+#define I2CCDR  &I2C_Addr[4]
+
+#define MPC107_CCR_MEN  0x80
+#define MPC107_CCR_MIEN 0x40
+#define MPC107_CCR_MSTA 0x20
+#define MPC107_CCR_MTX  0x10
+#define MPC107_CCR_TXAK 0x08
+#define MPC107_CCR_RSTA 0x04
+
+#define MPC107_CSR_MCF  0x80
+#define MPC107_CSR_MAAS 0x40
+#define MPC107_CSR_MBB  0x20
+#define MPC107_CSR_MAL  0x10
+#define MPC107_CSR_SRW  0x04
+#define MPC107_CSR_MIF  0x02
+#define MPC107_CSR_RXAK 0x01
+
+#define I2C_READ  1
+#define I2C_WRITE 0
+
+/* taken from linux include/asm-ppc/io.h */
+inline unsigned in_le32 (volatile unsigned *addr)
+{
+	unsigned ret;
+
+	__asm__ __volatile__ ("lwbrx %0,0,%1;\n"
+			      "twi 0,%0,0;\n"
+			      "isync":"=r" (ret): "r" (addr), "m" (*addr));
+	return ret;
+}
+
+inline void out_le32 (volatile unsigned *addr, int val)
+{
+	__asm__ __volatile__ ("stwbrx %1,0,%2; eieio":"=m" (*addr):"r" (val),
+			      "r" (addr));
+}
+
+#define writel(val, addr) out_le32(addr, val)
+#define readl(addr) in_le32(addr)
+
+void i2c_init (int speed, int slaveadd)
+{
+	/* stop I2C controller */
+	writel (0x0, I2CCCR);
+	/* set clock */
+	writel (0x1020, I2CFDR);
+	/* write slave address */
+	writel (slaveadd, I2CADR);
+	/* clear status register */
+	writel (0x0, I2CCSR);
+	/* start I2C controller */
+	writel (MPC107_CCR_MEN, I2CCCR);
+
+	return;
+}
+
+static __inline__ int i2c_wait4bus (void)
+{
+	ulong timeval = get_timer (0);
+
+	while (readl (I2CCSR) & MPC107_CSR_MBB)
+		if (get_timer (timeval) > TIMEOUT)
+			return -1;
+
+	return 0;
+}
+
+static __inline__ int i2c_wait (int write)
+{
+	u32 csr;
+	ulong timeval = get_timer (0);
+
+	do {
+		csr = readl (I2CCSR);
+
+		if (!(csr & MPC107_CSR_MIF))
+			continue;
+
+		writel (0x0, I2CCSR);
+
+		if (csr & MPC107_CSR_MAL) {
+#ifdef I2CDBG
+			printf ("i2c_wait: MAL\n");
+#endif
+			return -1;
+		}
+
+		if (!(csr & MPC107_CSR_MCF)) {
+#ifdef I2CDBG
+			printf ("i2c_wait: unfinished\n");
+#endif
+			return -1;
+		}
+
+		if (write == I2C_WRITE && (csr & MPC107_CSR_RXAK)) {
+#ifdef I2CDBG
+			printf ("i2c_wait: No RXACK\n");
+#endif
+			return -1;
+		}
+
+		return 0;
+	} while (get_timer (timeval) < TIMEOUT);
+
+#ifdef I2CDBG
+	printf ("i2c_wait: timed out\n");
+#endif
+	return -1;
+}
+
+static __inline__ int i2c_write_addr (u8 dev, u8 dir, int rsta)
+{
+	writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX |
+		(rsta ? MPC107_CCR_RSTA : 0), I2CCCR);
+
+	writel ((dev << 1) | dir, I2CCDR);
+
+	if (i2c_wait (I2C_WRITE) < 0)
+		return 0;
+
+	return 1;
+}
+
+static __inline__ int __i2c_write (u8 * data, int length)
+{
+	int i;
+
+	writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX, I2CCCR);
+
+	for (i = 0; i < length; i++) {
+		writel (data[i], I2CCDR);
+
+		if (i2c_wait (I2C_WRITE) < 0)
+			break;
+	}
+
+	return i;
+}
+
+static __inline__ int __i2c_read (u8 * data, int length)
+{
+	int i;
+
+	writel (MPC107_CCR_MEN | MPC107_CCR_MSTA |
+		((length == 1) ? MPC107_CCR_TXAK : 0), I2CCCR);
+
+	/* dummy read */
+	readl (I2CCDR);
+
+	for (i = 0; i < length; i++) {
+		if (i2c_wait (I2C_READ) < 0)
+			break;
+
+		/* Generate ack on last next to last byte */
+		if (i == length - 2)
+			writel (MPC107_CCR_MEN | MPC107_CCR_MSTA |
+				MPC107_CCR_TXAK, I2CCCR);
+
+		/* Generate stop on last byte */
+		if (i == length - 1)
+			writel (MPC107_CCR_MEN | MPC107_CCR_TXAK, I2CCCR);
+
+		data[i] = readl (I2CCDR);
+	}
+
+	return i;
+}
+
+int i2c_read (u8 dev, uint addr, int alen, u8 * data, int length)
+{
+	int i = 0;
+	u8 *a = (u8 *) & addr;
+
+	if (i2c_wait4bus () < 0)
+		goto exit;
+
+	if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
+		goto exit;
+
+	if (__i2c_write (&a[4 - alen], alen) != alen)
+		goto exit;
+
+	if (i2c_write_addr (dev, I2C_READ, 1) == 0)
+		goto exit;
+
+	i = __i2c_read (data, length);
+
+exit:
+	writel (MPC107_CCR_MEN, I2CCCR);
+
+	return !(i == length);
+}
+
+int i2c_write (u8 dev, uint addr, int alen, u8 * data, int length)
+{
+	int i = 0;
+	u8 *a = (u8 *) & addr;
+
+	if (i2c_wait4bus () < 0)
+		goto exit;
+
+	if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
+		goto exit;
+
+	if (__i2c_write (&a[4 - alen], alen) != alen)
+		goto exit;
+
+	i = __i2c_write (data, length);
+
+exit:
+	writel (MPC107_CCR_MEN, I2CCCR);
+
+	return !(i == length);
+}
+
+int i2c_probe (uchar chip)
+{
+	int tmp;
+
+	/*
+	 * Try to read the first location of the chip.  The underlying
+	 * driver doesn't appear to support sending just the chip address
+	 * and looking for an <ACK> back.
+	 */
+	udelay (10000);
+	return i2c_read (chip, 0, 1, (uchar *) &tmp, 1);
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/ppc/cpu/mpc824x/drivers/i2c_export.h b/arch/ppc/cpu/mpc824x/drivers/i2c_export.h
new file mode 100644
index 0000000..6264d18
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/drivers/i2c_export.h
@@ -0,0 +1,103 @@
+#ifndef I2C_EXPORT_H
+#define I2C_EXPORT_H
+
+/****************************************************
+ *
+ * Copyright Motrola 1999
+ *
+ ****************************************************/
+
+/* These are the defined return values for the I2C_do_transaction function.
+ * Any non-zero value indicates failure.  Failure modes can be added for
+ * more detailed error reporting.
+ */
+typedef enum _i2c_status
+{
+ I2C_SUCCESS     = 0,
+ I2C_ERROR,
+} I2C_Status;
+
+/* These are the defined tasks for I2C_do_transaction.
+ * Modes for SLAVE_RCV and SLAVE_XMIT will be added.
+ */
+typedef enum _i2c_transaction_mode
+{
+	I2C_MASTER_RCV =  0,
+	I2C_MASTER_XMIT = 1,
+} I2C_TRANSACTION_MODE;
+
+typedef enum _i2c_interrupt_mode
+{
+	I2C_INT_DISABLE =  0,
+	I2C_INT_ENABLE = 1,
+} I2C_INTERRUPT_MODE;
+
+typedef enum _i2c_stop
+{
+	I2C_NO_STOP =  0,
+	I2C_STOP = 1,
+} I2C_STOP_MODE;
+
+typedef enum _i2c_restart
+{
+	I2C_NO_RESTART =  0,
+	I2C_RESTART = 1,
+} I2C_RESTART_MODE;
+
+/******************** App. API ********************
+ * The application API is for user level application
+ * to use the functionality provided by I2C driver.
+ * This is a "generic" I2C interface, it should contain
+ * nothing specific to the Kahlua implementation.
+ * Only the generic functions are exported by the library.
+ *
+ * Note: Its App.s responsibility to swap the data
+ *       byte. In our API, we just transfer whatever
+ *       we are given
+ **************************************************/
+
+
+/*  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.
+ */
+extern I2C_Status I2C_Initialize(
+	unsigned char addr,            /* driver's I2C slave address */
+	I2C_INTERRUPT_MODE en_int,     /* 1 - enable I2C interrupt
+					* 0 - disable I2C interrupt
+					*/
+	int (*app_print_function)(char *,...)); /* pointer to optional "printf"
+						 * provided by application
+						 */
+
+/* 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
+ * 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
+ */
+extern 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);
+#endif
diff --git a/arch/ppc/cpu/mpc824x/interrupts.c b/arch/ppc/cpu/mpc824x/interrupts.c
new file mode 100644
index 0000000..139c52c
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/interrupts.c
@@ -0,0 +1,93 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * 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 <mpc824x.h>
+#include <asm/processor.h>
+#include <asm/pci_io.h>
+#include <commproc.h>
+#include "drivers/epic.h"
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	*decrementer_count = (get_bus_freq (0) / 4) / CONFIG_SYS_HZ;
+
+	/*
+	 * It's all broken at the moment and I currently don't need
+	 * interrupts. If you want to fix it, have a look at the epic
+	 * drivers in dink32 v12. They do everthing and Motorola said
+	 * I could use the dink source in this project as long as
+	 * copyright notices remain intact.
+	 */
+
+	epicInit (EPIC_DIRECT_IRQ, 0);
+	/* EPIC won't generate INT unless Current Task Pri < 15 */
+	epicCurTaskPrioSet(0);
+
+	return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	register unsigned long temp;
+
+	pci_readl (CONFIG_SYS_EUMB_ADDR + EPIC_PROC_INT_ACK_REG, temp);
+	sync ();					/* i'm not convinced this is needed, but dink source has it */
+	temp &= 0xff;				/*get vector */
+
+	/*TODO: handle them -... */
+	epicEOI ();
+}
+
+/****************************************************************************/
+
+/*
+ * blank int handlers.
+ */
+
+void
+irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+}
+
+void irq_free_handler (int vec)
+{
+
+}
+
+/*TODO: some handlers for winbond and 87308 interrupts
+ and what about generic pci inteerupts?
+ vga?
+ */
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
diff --git a/arch/ppc/cpu/mpc824x/pci.c b/arch/ppc/cpu/mpc824x/pci.c
new file mode 100644
index 0000000..cf9cf41
--- /dev/null
+++ b/arch/ppc/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_SYS_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/arch/ppc/cpu/mpc824x/speed.c b/arch/ppc/cpu/mpc824x/speed.c
new file mode 100644
index 0000000..fdcb972
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/speed.c
@@ -0,0 +1,118 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Gregory E. Allen, gallen@arlut.utexas.edu
+ * Applied Research Laboratories, The University of Texas at Austin
+ *
+ * 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 <mpc824x.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+/* NOTE: This describes the proper use of this file.
+ *
+ * CONFIG_SYS_CLK_FREQ should be defined as the input frequency on
+ * PCI_SYNC_IN .
+ *
+ * CONFIG_PLL_PCI_TO_MEM_MULTIPLIER is only required on MPC8240
+ * boards. It should be defined as the PCI to Memory Multiplier as
+ * documented in the MPC8240 Hardware Specs.
+ *
+ * Other mpc824x boards don't need CONFIG_PLL_PCI_TO_MEM_MULTIPLIER
+ * because they can determine it from the PCR.
+ *
+ * Gary Milliorn <gary.milliorn@motorola.com> (who should know since
+ * he designed the Sandpoint) told us that the PCR is not in all revs
+ * of the MPC8240 CPU, so it's not guaranteeable and we cannot do
+ * away with CONFIG_PLL_PCI_TO_MEM_MULTIPLIER altogether.
+ */
+/* ------------------------------------------------------------------------- */
+
+/* This gives the PCI to Memory multiplier times 10 */
+/* The index is the value of PLL_CFG[0:4] */
+/* This is documented in the MPC8240/5 Hardware Specs */
+
+short pll_pci_to_mem_multiplier[] = {
+#if defined(CONFIG_MPC8240)
+	30, 30, 10, 10, 20, 10,  0, 10,
+	10,  0, 20,  0, 20,  0, 20,  0,
+	30,  0, 15,  0, 20,  0, 20,  0,
+	25,  0, 10,  0, 15, 15,  0,  0,
+#elif defined(CONFIG_MPC8245)
+	30, 30, 10, 10, 20, 10, 10, 10,
+	10, 20, 20, 15, 20, 15, 20, 30,
+	30, 40, 15, 40, 20, 25, 20, 40,
+	25, 20, 10, 20, 15, 15, 15,  0,
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+};
+
+#define CU824_PLL_STATE_REG	0xFE80002F
+#define PCR			0x800000E2
+
+/* ------------------------------------------------------------------------- */
+
+/* compute the memory bus clock frequency */
+ulong get_bus_freq (ulong dummy)
+{
+	unsigned char pll_cfg;
+#if defined(CONFIG_MPC8240) && !defined(CONFIG_CU824)
+	return (CONFIG_SYS_CLK_FREQ) * (CONFIG_PLL_PCI_TO_MEM_MULTIPLIER);
+#elif defined(CONFIG_CU824)
+	pll_cfg = *(volatile unsigned char *) (CU824_PLL_STATE_REG);
+	pll_cfg &= 0x1f;
+#else
+	CONFIG_READ_BYTE(PCR, pll_cfg);
+	pll_cfg = (pll_cfg >> 3) & 0x1f;
+#endif
+	return ((CONFIG_SYS_CLK_FREQ) * pll_pci_to_mem_multiplier[pll_cfg] + 5) / 10;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/* This gives the Memory to CPU Core multiplier times 10 */
+/* The index is the value of PLLRATIO in HID1 */
+/* This is documented in the MPC8240 Hardware Specs */
+/* This is not documented for MPC8245 ? FIXME */
+short pllratio_to_factor[] = {
+     0,  0,  0, 10, 20, 20, 25, 45,
+    30,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0, 10,  0,  0,  0, 45,
+    30,  0, 40,  0,  0,  0, 35,  0,
+};
+
+/* compute the CPU and memory bus clock frequencies */
+int get_clocks (void)
+{
+	uint hid1 = mfspr(HID1);
+	hid1 = (hid1 >> (32-5)) & 0x1f;
+	gd->cpu_clk = (pllratio_to_factor[hid1] * get_bus_freq(0) + 5)
+			  / 10;
+	gd->bus_clk = get_bus_freq(0);
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc824x/start.S b/arch/ppc/cpu/mpc824x/start.S
new file mode 100644
index 0000000..f3f595a
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/start.S
@@ -0,0 +1,766 @@
+/*
+ *  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 <timestamp.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 r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+#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 " (", U_BOOT_DATE, " - ", U_BOOT_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, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3, r3, CONFIG_SYS_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, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+	li	r0, 0			/* Make room for stack frame header and	*/
+	stwu	r0, -4(r1)		/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)		/* stack backtraces terminate cleanly	*/
+
+	/* let the C-code set up the rest					*/
+	/*									*/
+	/* Be careful to keep code relocatable !				*/
+	/*----------------------------------------------------------------------*/
+
+	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(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = EXC_OFF_PROGRAM
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	/* 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)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+
+	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, DebugException)
+	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	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+#ifdef CONFIG_SYS_RAMBOOT
+	lis	r4, CONFIG_SYS_SDRAM_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_SDRAM_BASE@l
+#else
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+#endif
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* 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
+
+4:
+#if !defined(CONFIG_BMW)
+/* Unlock the data cache and invalidate locked area */
+	xor	r0, r0, r0
+	mtspr	1011, r0
+	lis	r4, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r4, r4, CONFIG_SYS_INIT_RAM_ADDR@l
+	li	r0, 128
+	mtctr	r0
+41:
+	dcbi	r0, r4
+	addi	r4, r4, 32
+	bdnz	41b
+#endif
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+	cmpwi	r6,0
+	add	r5,r3,r5
+	beq	7f		/* Always flush prefetch queue in any case */
+	subi	r0,r6,1
+	andc	r3,r3,r0
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	blt	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	mtlr	r4			/* restore link register	*/
+	blr
+
+	/* Setup the BAT registers.
+	 */
+setup_bats:
+	lis	r4, CONFIG_SYS_IBAT0L@h
+	ori	r4, r4, CONFIG_SYS_IBAT0L@l
+	lis	r3, CONFIG_SYS_IBAT0U@h
+	ori	r3, r3, CONFIG_SYS_IBAT0U@l
+	mtspr	IBAT0L, r4
+	mtspr	IBAT0U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_DBAT0L@h
+	ori	r4, r4, CONFIG_SYS_DBAT0L@l
+	lis	r3, CONFIG_SYS_DBAT0U@h
+	ori	r3, r3, CONFIG_SYS_DBAT0U@l
+	mtspr	DBAT0L, r4
+	mtspr	DBAT0U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_IBAT1L@h
+	ori	r4, r4, CONFIG_SYS_IBAT1L@l
+	lis	r3, CONFIG_SYS_IBAT1U@h
+	ori	r3, r3, CONFIG_SYS_IBAT1U@l
+	mtspr	IBAT1L, r4
+	mtspr	IBAT1U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_DBAT1L@h
+	ori	r4, r4, CONFIG_SYS_DBAT1L@l
+	lis	r3, CONFIG_SYS_DBAT1U@h
+	ori	r3, r3, CONFIG_SYS_DBAT1U@l
+	mtspr	DBAT1L, r4
+	mtspr	DBAT1U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_IBAT2L@h
+	ori	r4, r4, CONFIG_SYS_IBAT2L@l
+	lis	r3, CONFIG_SYS_IBAT2U@h
+	ori	r3, r3, CONFIG_SYS_IBAT2U@l
+	mtspr	IBAT2L, r4
+	mtspr	IBAT2U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_DBAT2L@h
+	ori	r4, r4, CONFIG_SYS_DBAT2L@l
+	lis	r3, CONFIG_SYS_DBAT2U@h
+	ori	r3, r3, CONFIG_SYS_DBAT2U@l
+	mtspr	DBAT2L, r4
+	mtspr	DBAT2U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_IBAT3L@h
+	ori	r4, r4, CONFIG_SYS_IBAT3L@l
+	lis	r3, CONFIG_SYS_IBAT3U@h
+	ori	r3, r3, CONFIG_SYS_IBAT3U@l
+	mtspr	IBAT3L, r4
+	mtspr	IBAT3U, r3
+	isync
+
+	lis	r4, CONFIG_SYS_DBAT3L@h
+	ori	r4, r4, CONFIG_SYS_DBAT3L@l
+	lis	r3, CONFIG_SYS_DBAT3U@h
+	ori	r3, r3, CONFIG_SYS_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/arch/ppc/cpu/mpc824x/traps.c b/arch/ppc/cpu/mpc824x/traps.c
new file mode 100644
index 0000000..0a72430
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/traps.c
@@ -0,0 +1,219 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM	0x00400000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0)
+		{
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7)
+		{
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		printf("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13):
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+  do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc824x/u-boot.lds b/arch/ppc/cpu/mpc824x/u-boot.lds
new file mode 100644
index 0000000..8a6d508
--- /dev/null
+++ b/arch/ppc/cpu/mpc824x/u-boot.lds
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2001-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    arch/ppc/cpu/mpc824x/start.o		(.text)
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc8260/Makefile b/arch/ppc/cpu/mpc8260/Makefile
new file mode 100644
index 0000000..9f0c2dd
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/Makefile
@@ -0,0 +1,53 @@
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o kgdb.o
+COBJS	= traps.o serial_smc.o serial_scc.o cpu.o cpu_init.o speed.o \
+	  interrupts.o ether_fcc.o i2c.o commproc.o \
+	  bedbug_603e.o pci.o spi.o
+
+COBJS-$(CONFIG_ETHER_ON_SCC) = ether_scc.o
+
+COBJS	+= $(COBJS-y)
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS) $(obj)kgdb.o
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc8260/bedbug_603e.c b/arch/ppc/cpu/mpc8260/bedbug_603e.c
new file mode 100644
index 0000000..c969ff6
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/bedbug_603e.c
@@ -0,0 +1,238 @@
+/*
+ * Bedbug Functions specific to the MPC603e core
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/type.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+
+#if defined(CONFIG_CMD_BEDBUG) \
+	&& (defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260))
+
+#define MAX_BREAK_POINTS 1
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug603e_init __P((void));
+void bedbug603e_do_break __P((cmd_tbl_t*,int,int,char*[]));
+void bedbug603e_break_isr __P((struct pt_regs*));
+int  bedbug603e_find_empty __P((void));
+int  bedbug603e_set __P((int,unsigned long));
+int  bedbug603e_clear __P((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the processor.  Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug603e_init( void )
+{
+  int	i;
+  /* -------------------------------------------------- */
+
+  bug_ctx.hw_debug_enabled = 0;
+  bug_ctx.stopped = 0;
+  bug_ctx.current_bp = 0;
+  bug_ctx.regs = NULL;
+
+  bug_ctx.do_break   = bedbug603e_do_break;
+  bug_ctx.break_isr  = bedbug603e_break_isr;
+  bug_ctx.find_empty = bedbug603e_find_empty;
+  bug_ctx.set        = bedbug603e_set;
+  bug_ctx.clear      = bedbug603e_clear;
+
+  for( i = 1; i <= MAX_BREAK_POINTS; ++i )
+    (*bug_ctx.clear)( i );
+
+  puts ("BEDBUG:ready\n");
+  return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show the hardware breakpoint for the 603e.  The "off"
+ * string will disable a specific breakpoint.  The "show" string will
+ * display the current breakpoints.  Otherwise an address will set a
+ * breakpoint at that address.  Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug603e_do_break (cmd_tbl_t *cmdtp, int flag, int argc,
+			 char *argv[])
+{
+  long		addr;           /* Address to break at  */
+  int		which_bp;       /* Breakpoint number    */
+  /* -------------------------------------------------- */
+
+  if (argc < 2)
+  {
+    cmd_usage(cmdtp);
+    return;
+  }
+
+  /* Turn off a breakpoint */
+
+  if( strcmp( argv[ 1 ], "off" ) == 0 )
+  {
+    if( bug_ctx.hw_debug_enabled == 0 )
+    {
+      puts ( "No breakpoints enabled\n" );
+      return;
+    }
+
+    which_bp = simple_strtoul( argv[ 2 ], NULL, 10 );
+
+    if( bug_ctx.clear )
+      (*bug_ctx.clear)( which_bp );
+
+    printf( "Breakpoint %d removed\n", which_bp );
+    return;
+  }
+
+  /* Show a list of breakpoints */
+
+  if( strcmp( argv[ 1 ], "show" ) == 0 )
+  {
+    for( which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp )
+    {
+
+      addr = GET_IABR();
+
+      printf( "Breakpoint [%d]: ", which_bp );
+      if( (addr & 0x00000002) == 0 )
+	puts ( "NOT SET\n" );
+      else
+	disppc( (unsigned char *)(addr & 0xFFFFFFFC), 0, 1, bedbug_puts, F_RADHEX );
+    }
+    return;
+  }
+
+  /* Set a breakpoint at the address */
+
+  if(!(( isdigit( argv[ 1 ][ 0 ] )) ||
+	(( argv[ 1 ][ 0 ] >= 'a' ) && ( argv[ 1 ][ 0 ] <= 'f' )) ||
+	(( argv[ 1 ][ 0 ] >= 'A' ) && ( argv[ 1 ][ 0 ] <= 'F' ))))
+  {
+    cmd_usage(cmdtp);
+    return;
+  }
+
+  addr = simple_strtoul( argv[ 1 ], NULL, 16 );
+
+  if(( bug_ctx.set ) && ( which_bp = (*bug_ctx.set)( 0, addr )) > 0 )
+  {
+    printf( "Breakpoint [%d]: ", which_bp );
+    disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+  }
+
+  return;
+} /* bedbug603e_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint.  Enter a mini main loop.  Stay in the loop until
+ * the stopped flag in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug603e_break_isr( struct pt_regs *regs )
+{
+  unsigned long	addr;           /* Address stopped at   */
+  /* -------------------------------------------------- */
+
+  bug_ctx.current_bp = 1;
+  addr = GET_IABR() & 0xFFFFFFFC;
+
+  bedbug_main_loop( addr, regs );
+  return;
+} /* bedbug603e_break_isr */
+
+
+
+/* ======================================================================
+ * See if the hardware breakpoint is available.
+ * ====================================================================== */
+
+int bedbug603e_find_empty( void )
+{
+  /* -------------------------------------------------- */
+
+  if( (GET_IABR() && 0x00000002) == 0 )
+    return 1;
+
+  return 0;
+} /* bedbug603e_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint.  If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint.  If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0.  Set the break
+ * address in the IABR register.
+ * ====================================================================== */
+
+int bedbug603e_set( int which_bp, unsigned long addr )
+{
+  /* -------------------------------------------------- */
+
+  if(( addr & 0x00000003 ) != 0 )
+  {
+    puts ( "Breakpoints must be on a 32 bit boundary\n" );
+    return 0;
+  }
+
+  /* Only look if which_bp == 0, else use which_bp */
+  if(( bug_ctx.find_empty ) && ( !which_bp ) &&
+     ( which_bp = (*bug_ctx.find_empty)()) == 0 )
+  {
+    puts ( "All breakpoints in use\n" );
+    return 0;
+  }
+
+  if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+  {
+    printf( "Invalid break point # %d\n", which_bp );
+    return 0;
+  }
+
+  if( ! bug_ctx.hw_debug_enabled )
+  {
+    bug_ctx.hw_debug_enabled = 1;
+  }
+
+  SET_IABR( addr | 0x00000002 );
+
+  return which_bp;
+} /* bedbug603e_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the IABR register to zero.
+ * ====================================================================== */
+
+int bedbug603e_clear( int which_bp )
+{
+  /* -------------------------------------------------- */
+
+  if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+  {
+    printf( "Invalid break point # (%d)\n", which_bp );
+    return -1;
+  }
+
+  SET_IABR( 0 );
+
+  return 0;
+} /* bedbug603e_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/ppc/cpu/mpc8260/commproc.c b/arch/ppc/cpu/mpc8260/commproc.c
new file mode 100644
index 0000000..94f6bc2
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/commproc.c
@@ -0,0 +1,221 @@
+/*
+ * This file is based on "arch/ppc/8260_io/commproc.c" - here is it's
+ * copyright notice:
+ *
+ * General Purpose functions for the global management of the
+ * 8260 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ *	2.3.99 Updates
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ */
+#include <common.h>
+#include <asm/cpm_8260.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void
+m8260_cpm_reset(void)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ulong count;
+
+	/* Reclaim the DP memory for our use.
+	*/
+	gd->dp_alloc_base = CPM_DATAONLY_BASE;
+	gd->dp_alloc_top = gd->dp_alloc_base + CPM_DATAONLY_SIZE;
+
+	/*
+	 * Reset CPM
+	 */
+	immr->im_cpm.cp_cpcr = CPM_CR_RST;
+	count = 0;
+	do {			/* Spin until command processed		*/
+		__asm__ __volatile__ ("eieio");
+	} while ((immr->im_cpm.cp_cpcr & CPM_CR_FLG) && ++count < 1000000);
+
+#ifdef CONFIG_HARD_I2C
+	*((unsigned short*)(&immr->im_dprambase[PROFF_I2C_BASE])) = 0;
+#endif
+}
+
+/* Allocate some memory from the dual ported ram.
+ * To help protocols with object alignment restrictions, we do that
+ * if they ask.
+ */
+uint
+m8260_cpm_dpalloc(uint size, uint align)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	uint	retloc;
+	uint	align_mask, off;
+	uint	savebase;
+
+	align_mask = align - 1;
+	savebase = gd->dp_alloc_base;
+
+	if ((off = (gd->dp_alloc_base & align_mask)) != 0)
+		gd->dp_alloc_base += (align - off);
+
+	if ((off = size & align_mask) != 0)
+		size += align - off;
+
+	if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top) {
+		gd->dp_alloc_base = savebase;
+		panic("m8260_cpm_dpalloc: ran out of dual port ram!");
+	}
+
+	retloc = gd->dp_alloc_base;
+	gd->dp_alloc_base += size;
+
+	memset((void *)&immr->im_dprambase[retloc], 0, size);
+
+	return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8260_cpm_hostalloc(uint size, uint align)
+{
+	/* the host might not even have RAM yet - just use dual port RAM */
+	return (m8260_cpm_dpalloc(size, align));
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks.  The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers).  Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK	gd->brg_clk
+#define BRG_UART_CLK	(BRG_INT_CLK / 16)
+
+/* This function is used by UARTs, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+m8260_cpm_setbrg(uint brg, uint rate)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile uint	*bp;
+	uint cd = BRG_UART_CLK / rate;
+
+	if ((BRG_UART_CLK % rate) < (rate / 2))
+		cd--;
+	if (brg < 4) {
+		bp = (uint *)&immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = (cd << 1) | CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+m8260_cpm_fastbrg(uint brg, uint rate, int div16)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	if (brg < 4) {
+		bp = (uint *)&immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+	if (div16)
+		*bp |= CPM_BRG_DIV16;
+}
+
+/* This function is used to set baud rate generators using an external
+ * clock source and 16x oversampling.
+ */
+
+void
+m8260_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile uint	*bp;
+
+	if (brg < 4) {
+		bp = (uint *)&immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+	if (pinsel == 0)
+		*bp |= CPM_BRG_EXTC_CLK3_9;
+	else
+		*bp |= CPM_BRG_EXTC_CLK5_15;
+}
+
+#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
+
+void post_word_store (ulong a)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_POST_WORD_ADDR);
+
+	*save_addr = a;
+}
+
+ulong post_word_load (void)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_POST_WORD_ADDR);
+
+	return *save_addr;
+}
+
+#endif	/* CONFIG_POST || CONFIG_LOGBUFFER*/
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+void bootcount_store (ulong a)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_BOOTCOUNT_ADDR);
+
+	save_addr[0] = a;
+	save_addr[1] = BOOTCOUNT_MAGIC;
+}
+
+ulong bootcount_load (void)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_BOOTCOUNT_ADDR);
+
+	if (save_addr[1] != BOOTCOUNT_MAGIC)
+		return 0;
+	else
+		return save_addr[0];
+}
+
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/arch/ppc/cpu/mpc8260/config.mk b/arch/ppc/cpu/mpc8260/config.mk
new file mode 100644
index 0000000..51bb9fa
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/config.mk
@@ -0,0 +1,30 @@
+#
+# (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
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_8260 -DCONFIG_CPM2 -ffixed-r2 \
+		     -mstring -mcpu=603e -mmultiple
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc8260/u-boot.lds
diff --git a/arch/ppc/cpu/mpc8260/cpu.c b/arch/ppc/cpu/mpc8260/cpu.c
new file mode 100644
index 0000000..aedbf29
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/cpu.c
@@ -0,0 +1,338 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC825x / MPC826x / MPC827x / MPC828x
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * modified by
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * modified for 8260 by
+ * Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * added 8260 masks by
+ * Marius Groeger <mag@sysgo.de>
+ *
+ * added HiP7 (824x/827x/8280) processors support by
+ * Yuli Barcohen <yuli@arabellasw.com>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <netdev.h>
+#include <asm/processor.h>
+#include <asm/cpm_8260.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_GET_CPU_STR_F)
+extern int get_cpu_str_f (char *buf);
+#endif
+
+int checkcpu (void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	ulong clock = gd->cpu_clk;
+	uint pvr = get_pvr ();
+	uint immr, rev, m, k;
+	char buf[32];
+
+	puts ("CPU:   ");
+
+	switch (pvr) {
+	case PVR_8260:
+	case PVR_8260_HIP3:
+		k = 3;
+		break;
+	case PVR_8260_HIP4:
+		k = 4;
+		break;
+	case PVR_8260_HIP7R1:
+	case PVR_8260_HIP7RA:
+	case PVR_8260_HIP7:
+		k = 7;
+		break;
+	default:
+		return -1;	/* whoops! not an MPC8260 */
+	}
+	rev = pvr & 0xff;
+
+	immr = immap->im_memctl.memc_immr;
+	if ((immr & IMMR_ISB_MSK) != CONFIG_SYS_IMMR)
+		return -1;	/* whoops! someone moved the IMMR */
+
+#if defined(CONFIG_GET_CPU_STR_F)
+	get_cpu_str_f (buf);
+	printf ("%s (HiP%d Rev %02x, Mask ", buf, k, rev);
+#else
+	printf (CPU_ID_STR " (HiP%d Rev %02x, Mask ", k, rev);
+#endif
+
+	/*
+	 * the bottom 16 bits of the immr are the Part Number and Mask Number
+	 * (4-34); the 16 bits at PROFF_REVNUM (0x8af0) in dual port ram is the
+	 * RISC Microcode Revision Number (13-10).
+	 * For the 8260, Motorola doesn't include the Microcode Revision
+	 * in the mask.
+	 */
+	m = immr & (IMMR_PARTNUM_MSK | IMMR_MASKNUM_MSK);
+	k = *((ushort *) & immap->im_dprambase[PROFF_REVNUM]);
+
+	switch (m) {
+	case 0x0000:
+		puts ("0.2 2J24M");
+		break;
+	case 0x0010:
+		puts ("A.0 K22A");
+		break;
+	case 0x0011:
+		puts ("A.1 1K22A-XC");
+		break;
+	case 0x0001:
+		puts ("B.1 1K23A");
+		break;
+	case 0x0021:
+		puts ("B.2 2K23A-XC");
+		break;
+	case 0x0023:
+		puts ("B.3 3K23A");
+		break;
+	case 0x0024:
+		puts ("C.2 6K23A");
+		break;
+	case 0x0060:
+		puts ("A.0(A) 2K25A");
+		break;
+	case 0x0062:
+		puts ("B.1 4K25A");
+		break;
+	case 0x0064:
+		puts ("C.0 5K25A");
+		break;
+	case 0x0A00:
+		puts ("0.0 0K49M");
+		break;
+	case 0x0A01:
+		puts ("0.1 1K49M");
+		break;
+	case 0x0A10:
+		puts ("1.0 1K49M");
+		break;
+	case 0x0C00:
+		puts ("0.0 0K50M");
+		break;
+	case 0x0C10:
+		puts ("1.0 1K50M");
+		break;
+	case 0x0D00:
+		puts ("0.0 0K50M");
+		break;
+	case 0x0D10:
+		puts ("1.0 1K50M");
+		break;
+	default:
+		printf ("unknown [immr=0x%04x,k=0x%04x]", m, k);
+		break;
+	}
+
+	printf (") at %s MHz\n", strmhz (buf, clock));
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* configures a UPM by writing into the UPM RAM array			     */
+/* uses bank 11 and a dummy physical address (=BRx_BA_MSK)		     */
+/* NOTE: the physical address chosen must not overlap into any other area    */
+/* mapped by the memory controller because bank 11 has the lowest priority   */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile memctl8260_t *memctl = &immap->im_memctl;
+	volatile uchar *dummy = (uchar *) BRx_BA_MSK;	/* set all BA bits */
+	uint i;
+
+	/* first set up bank 11 to reference the correct UPM at a dummy address */
+
+	memctl->memc_or11 = ORxU_AM_MSK;	/* set all AM bits */
+
+	switch (upm) {
+
+	case UPMA:
+		memctl->memc_br11 =
+			((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMA |
+			BRx_V;
+		memctl->memc_mamr = MxMR_OP_WARR;
+		break;
+
+	case UPMB:
+		memctl->memc_br11 =
+			((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMB |
+			BRx_V;
+		memctl->memc_mbmr = MxMR_OP_WARR;
+		break;
+
+	case UPMC:
+		memctl->memc_br11 =
+			((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMC |
+			BRx_V;
+		memctl->memc_mcmr = MxMR_OP_WARR;
+		break;
+
+	default:
+		panic ("upmconfig passed invalid UPM number (%u)\n", upm);
+		break;
+
+	}
+
+	/*
+	 * at this point, the dummy address is set up to access the selected UPM,
+	 * the MAD pointer is zero, and the MxMR OP is set for writing to RAM
+	 *
+	 * now we simply load the mdr with each word and poke the dummy address.
+	 * the MAD is incremented on each access.
+	 */
+
+	for (i = 0; i < size; i++) {
+		memctl->memc_mdr = table[i];
+		*dummy = 0;
+	}
+
+	/* now kill bank 11 */
+	memctl->memc_br11 = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if !defined(CONFIG_HAVE_OWN_RESET)
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong msr, addr;
+
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	immap->im_clkrst.car_rmr = RMR_CSRE;	/* Checkstop Reset enable */
+
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/*
+	 * Trying to execute the next instruction at a non-existing address
+	 * should cause a machine check, resulting in reset
+	 */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+	addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
+	 * - sizeof (ulong) is usually a valid address. Better pick an address
+	 * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+	 */
+	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+	((void (*)(void)) addr) ();
+	return 1;
+
+}
+#endif	/* CONFIG_HAVE_OWN_RESET */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+	ulong tbclk;
+
+	tbclk = (gd->bus_clk + 3L) / 4L;
+
+	return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts ();
+
+	reset_8260_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+	if (re_enable)
+		enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+/* ------------------------------------------------------------------------- */
+#if defined(CONFIG_OF_LIBFDT) && defined (CONFIG_OF_BOARD_SETUP)
+void ft_cpu_setup (void *blob, bd_t *bd)
+{
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
+    defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
+	fdt_fixup_ethernet(blob);
+#endif
+
+	do_fixup_by_compat_u32(blob, "fsl,cpm2-brg",
+			       "clock-frequency", bd->bi_brgfreq, 1);
+
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"timebase-frequency", OF_TBCLK, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"clock-frequency", bd->bi_intfreq, 1);
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
+#endif /* CONFIG_OF_LIBFDT */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_ETHER_ON_FCC)
+	fec_initialize(bis);
+#endif
+#if defined(CONFIG_ETHER_ON_SCC)
+	mpc82xx_scc_enet_initialize(bis);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8260/cpu_init.c b/arch/ppc/cpu/mpc8260/cpu_init.c
new file mode 100644
index 0000000..1d52773
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/cpu_init.c
@@ -0,0 +1,292 @@
+/*
+ * (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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+extern unsigned long board_get_cpu_clk_f (void);
+#endif
+
+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->podr = (iop->podr & tpmsk) | podr;
+			iop->pdat = (iop->pdat & tpmsk) | pdat;
+			iop->pdir = (iop->pdir & tpmsk) | pdir;
+			iop->ppar |= ppar;
+		}
+	}
+}
+
+#define SET_VAL_MASK(a, b, mask) ((a & mask) | (b & ~mask))
+/*
+ * 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)
+{
+#if !defined(CONFIG_COGENT)		/* done in start.S for the cogent */
+	uint sccr;
+#endif
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+	unsigned long cpu_clk;
+#endif
+	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 *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_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 = CONFIG_SYS_RMR;
+
+	/* BCR - Bus Configuration Register (4-25) */
+#if defined(CONFIG_SYS_BCR_60x) && (CONFIG_SYS_BCR_SINGLE)
+	if (immr->im_siu_conf.sc_bcr & BCR_EBM) {
+		immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CONFIG_SYS_BCR_60x, 0x80000010);
+	} else {
+		immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CONFIG_SYS_BCR_SINGLE, 0x80000010);
+	}
+#else
+	immr->im_siu_conf.sc_bcr = CONFIG_SYS_BCR;
+#endif
+
+	/* SIUMCR - contains debug pin configuration (4-31) */
+#if defined(CONFIG_SYS_SIUMCR_LOW) && (CONFIG_SYS_SIUMCR_HIGH)
+	cpu_clk = board_get_cpu_clk_f ();
+	if (cpu_clk >= 100000000) {
+		immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR_HIGH, 0x9f3cc000);
+	} else {
+		immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR_LOW, 0x9f3cc000);
+	}
+#else
+	immr->im_siu_conf.sc_siumcr = CONFIG_SYS_SIUMCR;
+#endif
+
+	config_8260_ioports (immr);
+
+	/* initialize time counter status and control register (4-40) */
+	immr->im_sit.sit_tmcntsc = CONFIG_SYS_TMCNTSC;
+
+	/* initialize the PIT (4-42) */
+	immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+#if !defined(CONFIG_COGENT)		/* done in start.S for the cogent */
+	/* System clock control register (9-8) */
+	sccr = immr->im_clkrst.car_sccr &
+		(SCCR_PCI_MODE | SCCR_PCI_MODCK | SCCR_PCIDF_MSK);
+	immr->im_clkrst.car_sccr = sccr |
+		(CONFIG_SYS_SCCR & ~(SCCR_PCI_MODE | SCCR_PCI_MODCK | SCCR_PCIDF_MSK) );
+#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(CONFIG_SYS_OR0_REMAP)
+	memctl->memc_or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+	memctl->memc_or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+
+	/* now restrict to preliminary range */
+	/* the PS came from the HRCW, don´t change it */
+	memctl->memc_br0 = SET_VAL_MASK(memctl->memc_br0 , CONFIG_SYS_BR0_PRELIM, BRx_PS_MSK);
+	memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+	memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+	memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+	memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+	memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+	memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+	memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+	memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
+	memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+	memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
+	memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+	memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
+	memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+	memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
+	memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR8_PRELIM) && defined(CONFIG_SYS_OR8_PRELIM)
+	memctl->memc_or8 = CONFIG_SYS_OR8_PRELIM;
+	memctl->memc_br8 = CONFIG_SYS_BR8_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR9_PRELIM) && defined(CONFIG_SYS_OR9_PRELIM)
+	memctl->memc_or9 = CONFIG_SYS_OR9_PRELIM;
+	memctl->memc_br9 = CONFIG_SYS_BR9_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR10_PRELIM) && defined(CONFIG_SYS_OR10_PRELIM)
+	memctl->memc_or10 = CONFIG_SYS_OR10_PRELIM;
+	memctl->memc_br10 = CONFIG_SYS_BR10_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR11_PRELIM) && defined(CONFIG_SYS_OR11_PRELIM)
+	memctl->memc_or11 = CONFIG_SYS_OR11_PRELIM;
+	memctl->memc_br11 = CONFIG_SYS_BR11_PRELIM;
+#endif
+
+	m8260_cpm_reset ();
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+	volatile immap_t *immr = (immap_t *) gd->bd->bi_immr_base;
+
+	immr->im_cpm.cp_rccr = CONFIG_SYS_RCCR;
+
+	return (0);
+}
+
+/*
+ * print out the reason for the reset
+ */
+int prt_8260_rsr (void)
+{
+	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 (CPU_ID_STR " 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/arch/ppc/cpu/mpc8260/ether_fcc.c b/arch/ppc/cpu/mpc8260/ether_fcc.c
new file mode 100644
index 0000000..5ac02a0
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/ether_fcc.c
@@ -0,0 +1,1190 @@
+/*
+ * MPC8260 FCC Fast Ethernet
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
+ *
+ * (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
+ */
+
+/*
+ * MPC8260 FCC Fast Ethernet
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * This code will not perform the IO port configuration. This should be
+ * done in the iop_conf_t structure specific for the board.
+ *
+ * TODO:
+ * add a PHY driver to do the negotiation
+ * reflect negotiation results in FPSMR
+ * look for ways to configure the board specific stuff elsewhere, eg.
+ *    config_xxx.h or the board directory
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/cpm_8260.h>
+#include <mpc8260.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET) && \
+	defined(CONFIG_NET_MULTI)
+
+static struct ether_fcc_info_s
+{
+	int ether_index;
+	int proff_enet;
+	ulong cpm_cr_enet_sblock;
+	ulong cpm_cr_enet_page;
+	ulong cmxfcr_mask;
+	ulong cmxfcr_value;
+}
+	ether_fcc_info[] =
+{
+#ifdef CONFIG_ETHER_ON_FCC1
+{
+	0,
+	PROFF_FCC1,
+	CPM_CR_FCC1_SBLOCK,
+	CPM_CR_FCC1_PAGE,
+	CONFIG_SYS_CMXFCR_MASK1,
+	CONFIG_SYS_CMXFCR_VALUE1
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC2
+{
+	1,
+	PROFF_FCC2,
+	CPM_CR_FCC2_SBLOCK,
+	CPM_CR_FCC2_PAGE,
+	CONFIG_SYS_CMXFCR_MASK2,
+	CONFIG_SYS_CMXFCR_VALUE2
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC3
+{
+	2,
+	PROFF_FCC3,
+	CPM_CR_FCC3_SBLOCK,
+	CPM_CR_FCC3_PAGE,
+	CONFIG_SYS_CMXFCR_MASK3,
+	CONFIG_SYS_CMXFCR_VALUE3
+},
+#endif
+};
+
+/*---------------------------------------------------------------------*/
+
+/* Maximum input DMA size.  Must be a should(?) be a multiple of 4. */
+#define PKT_MAXDMA_SIZE         1520
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets. */
+#define PKT_MAXBUF_SIZE         1518
+#define PKT_MINBUF_SIZE         64
+
+/* Maximum input buffer size.  Must be a multiple of 32. */
+#define PKT_MAXBLR_SIZE         1536
+
+#define TOUT_LOOP 1000000
+
+#define TX_BUF_CNT 2
+#ifdef __GNUC__
+static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
+#else
+#error "txbuf must be 64-bit aligned"
+#endif
+
+static uint rxIdx;	/* index of the current RX buffer */
+static uint txIdx;	/* index of the current TX buffer */
+
+/*
+ * FCC Ethernet Tx and Rx buffer descriptors.
+ * Provide for Double Buffering
+ * Note: PKTBUFSRX is defined in net.h
+ */
+
+typedef volatile struct rtxbd {
+    cbd_t rxbd[PKTBUFSRX];
+    cbd_t txbd[TX_BUF_CNT];
+} RTXBD;
+
+/*  Good news: the FCC supports external BDs! */
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length)
+{
+    int i;
+    int result = 0;
+
+    if (length <= 0) {
+	printf("fec: bad packet size: %d\n", length);
+	goto out;
+    }
+
+    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+	if (i >= TOUT_LOOP) {
+	    puts ("fec: tx buffer not ready\n");
+	    goto out;
+	}
+    }
+
+    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 |
+			       BD_ENET_TX_WRAP);
+
+    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+	if (i >= TOUT_LOOP) {
+	    puts ("fec: tx error\n");
+	    goto out;
+	}
+    }
+
+#ifdef ET_DEBUG
+    printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
+#endif
+
+    /* return only status bits */
+    result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+
+out:
+    return result;
+}
+
+static int fec_recv(struct eth_device* dev)
+{
+    int length;
+
+    for (;;)
+    {
+	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) {
+	    printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
+	}
+	else {
+	    /* Pass the packet up to the protocol layers. */
+	    NetReceive(NetRxPackets[rxIdx], length - 4);
+	}
+
+
+	/* Give the buffer back to the FCC. */
+	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++;
+	}
+    }
+    return length;
+}
+
+
+static int fec_init(struct eth_device* dev, bd_t *bis)
+{
+    struct ether_fcc_info_s * info = dev->priv;
+    int i;
+    volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+    volatile cpm8260_t *cp = &(immr->im_cpm);
+    fcc_enet_t *pram_ptr;
+    unsigned long mem_addr;
+
+#if 0
+    mii_discover_phy();
+#endif
+
+    /* 28.9 - (1-2): ioports have been set up already */
+
+    /* 28.9 - (3): connect FCC's tx and rx clocks */
+    immr->im_cpmux.cmx_uar = 0;
+    immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~info->cmxfcr_mask) |
+							info->cmxfcr_value;
+
+    /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
+    immr->im_fcc[info->ether_index].fcc_gfmr =
+      FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+
+    /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
+    immr->im_fcc[info->ether_index].fcc_fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+
+    /* 28.9 - (6): FDSR: Ethernet Syn */
+    immr->im_fcc[info->ether_index].fcc_fdsr = 0xD555;
+
+    /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
+    rxIdx = 0;
+    txIdx = 0;
+
+    /* Setup Receiver Buffer Descriptors */
+    for (i = 0; i < PKTBUFSRX; i++)
+    {
+      rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+      rtx.rxbd[i].cbd_datlen = 0;
+      rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+    }
+    rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+    /* Setup Ethernet Transmitter Buffer Descriptors */
+    for (i = 0; i < TX_BUF_CNT; i++)
+    {
+      rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+      rtx.txbd[i].cbd_datlen = 0;
+      rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
+    }
+    rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+    /* 28.9 - (7): initialise parameter ram */
+    pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[info->proff_enet]);
+
+    /* clear whole structure to make sure all reserved fields are zero */
+    memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
+
+    /*
+     * common Parameter RAM area
+     *
+     * Allocate space in the reserved FCC area of DPRAM for the
+     * internal buffers.  No one uses this space (yet), so we
+     * can do this.  Later, we will add resource management for
+     * this area.
+     */
+    mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64);
+    pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
+    pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
+    /*
+     * Set maximum bytes per receive buffer.
+     * It must be a multiple of 32.
+     */
+    pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+    pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
+				       CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+    pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+    pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
+				       CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+    pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
+
+    /* protocol-specific area */
+    pram_ptr->fen_cmask = 0xdebb20e3;	/* CRC mask */
+    pram_ptr->fen_cpres = 0xffffffff;	/* CRC preset */
+    pram_ptr->fen_retlim = 15;		/* Retry limit threshold */
+    pram_ptr->fen_mflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */
+    /*
+     * Set Ethernet station address.
+     *
+     * This is supplied in the board information structure, so we
+     * copy that into the controller.
+     * So, far we have only been given one Ethernet address. We make
+     * it unique by setting a few bits in the upper byte of the
+     * non-static part of the address.
+     */
+#define ea eth_get_dev()->enetaddr
+    pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
+    pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
+    pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+    pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
+    /* pad pointer. use tiptr since we don't need a specific padding char */
+    pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
+    pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE;	/* maximum DMA1 length */
+    pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE;	/* maximum DMA2 length */
+    pram_ptr->fen_rfthr = 1;
+    pram_ptr->fen_rfcnt = 1;
+#if 0
+    printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
+	pram_ptr->fen_genfcc.fcc_rbase);
+    printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
+	pram_ptr->fen_genfcc.fcc_tbase);
+#endif
+
+    /* 28.9 - (8): clear out events in FCCE */
+    immr->im_fcc[info->ether_index].fcc_fcce = ~0x0;
+
+    /* 28.9 - (9): FCCM: mask all events */
+    immr->im_fcc[info->ether_index].fcc_fccm = 0;
+
+    /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+    /* 28.9 - (13)
+     *
+     * Let's re-initialize the channel now.  We have to do it later
+     * than the manual describes because we have just now finished
+     * the BD initialization.
+     */
+    cp->cp_cpcr = mk_cr_cmd(info->cpm_cr_enet_page,
+			    info->cpm_cr_enet_sblock,
+			    0x0c,
+			    CPM_CR_INIT_TRX) | CPM_CR_FLG;
+    do {
+	__asm__ __volatile__ ("eieio");
+    } while (cp->cp_cpcr & CPM_CR_FLG);
+
+    /* 28.9 - (14): enable tx/rx in gfmr */
+    immr->im_fcc[info->ether_index].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+
+    return 1;
+}
+
+static void fec_halt(struct eth_device* dev)
+{
+    struct ether_fcc_info_s * info = dev->priv;
+    volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+    /* write GFMR: disable tx/rx */
+    immr->im_fcc[info->ether_index].fcc_gfmr &=
+						~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+}
+
+int fec_initialize(bd_t *bis)
+{
+	struct eth_device* dev;
+	int i;
+
+	for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+	{
+		dev = (struct eth_device*) malloc(sizeof *dev);
+		memset(dev, 0, sizeof *dev);
+
+		sprintf(dev->name, "FCC%d ETHERNET",
+			ether_fcc_info[i].ether_index + 1);
+		dev->priv   = &ether_fcc_info[i];
+		dev->init   = fec_init;
+		dev->halt   = fec_halt;
+		dev->send   = fec_send;
+		dev->recv   = fec_recv;
+
+		eth_register(dev);
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \
+		&& defined(CONFIG_BITBANGMII)
+		miiphy_register(dev->name,
+				bb_miiphy_read,	bb_miiphy_write);
+#endif
+	}
+
+	return 1;
+}
+
+#ifdef CONFIG_ETHER_LOOPBACK_TEST
+
+#define ELBT_BUFSZ	1024	/* must be multiple of 32 */
+
+#define ELBT_CRCSZ	4
+
+#define ELBT_NRXBD	4	/* must be at least 2 */
+#define ELBT_NTXBD	4
+
+#define ELBT_MAXRXERR	32
+#define ELBT_MAXTXERR	32
+
+#define ELBT_CLSWAIT	1000	/* msec to wait for further input frames */
+
+typedef
+	struct {
+		uint off;
+		char *lab;
+	}
+elbt_prdesc;
+
+typedef
+	struct {
+		uint _l, _f, m, bc, mc, lg, no, sh, cr, ov, cl;
+		uint badsrc, badtyp, badlen, badbit;
+	}
+elbt_rxeacc;
+
+static elbt_prdesc rxeacc_descs[] = {
+	{ offsetof(elbt_rxeacc, _l),		"Not Last in Frame"	},
+	{ offsetof(elbt_rxeacc, _f),		"Not First in Frame"	},
+	{ offsetof(elbt_rxeacc, m),		"Address Miss"		},
+	{ offsetof(elbt_rxeacc, bc),		"Broadcast Address"	},
+	{ offsetof(elbt_rxeacc, mc),		"Multicast Address"	},
+	{ offsetof(elbt_rxeacc, lg),		"Frame Length Violation"},
+	{ offsetof(elbt_rxeacc, no),		"Non-Octet Alignment"	},
+	{ offsetof(elbt_rxeacc, sh),		"Short Frame"		},
+	{ offsetof(elbt_rxeacc, cr),		"CRC Error"		},
+	{ offsetof(elbt_rxeacc, ov),		"Overrun"		},
+	{ offsetof(elbt_rxeacc, cl),		"Collision"		},
+	{ offsetof(elbt_rxeacc, badsrc),	"Bad Src Address"	},
+	{ offsetof(elbt_rxeacc, badtyp),	"Bad Frame Type"	},
+	{ offsetof(elbt_rxeacc, badlen),	"Bad Frame Length"	},
+	{ offsetof(elbt_rxeacc, badbit),	"Data Compare Errors"	},
+};
+static int rxeacc_ndesc = sizeof (rxeacc_descs) / sizeof (rxeacc_descs[0]);
+
+typedef
+	struct {
+		uint def, hb, lc, rl, rc, un, csl;
+	}
+elbt_txeacc;
+
+static elbt_prdesc txeacc_descs[] = {
+	{ offsetof(elbt_txeacc, def),		"Defer Indication"	},
+	{ offsetof(elbt_txeacc, hb),		"Heartbeat"		},
+	{ offsetof(elbt_txeacc, lc),		"Late Collision"	},
+	{ offsetof(elbt_txeacc, rl),		"Retransmission Limit"	},
+	{ offsetof(elbt_txeacc, rc),		"Retry Count"		},
+	{ offsetof(elbt_txeacc, un),		"Underrun"		},
+	{ offsetof(elbt_txeacc, csl),		"Carrier Sense Lost"	},
+};
+static int txeacc_ndesc = sizeof (txeacc_descs) / sizeof (txeacc_descs[0]);
+
+typedef
+	struct {
+		uchar rxbufs[ELBT_NRXBD][ELBT_BUFSZ];
+		uchar txbufs[ELBT_NTXBD][ELBT_BUFSZ];
+		cbd_t rxbd[ELBT_NRXBD];
+		cbd_t txbd[ELBT_NTXBD];
+		enum { Idle, Running, Closing, Closed } state;
+		int proff, page, sblock;
+		uint clstime, nsent, ntxerr, nrcvd, nrxerr;
+		ushort rxerrs[ELBT_MAXRXERR], txerrs[ELBT_MAXTXERR];
+		elbt_rxeacc rxeacc;
+		elbt_txeacc txeacc;
+	} __attribute__ ((aligned(8)))
+elbt_chan;
+
+static uchar patbytes[ELBT_NTXBD] = {
+	0xff, 0xaa, 0x55, 0x00
+};
+static uint patwords[ELBT_NTXBD] = {
+	0xffffffff, 0xaaaaaaaa, 0x55555555, 0x00000000
+};
+
+#ifdef __GNUC__
+static elbt_chan elbt_chans[3] __attribute__ ((aligned(8)));
+#else
+#error "elbt_chans must be 64-bit aligned"
+#endif
+
+#define CPM_CR_GRACEFUL_STOP_TX	((ushort)0x0005)
+
+static elbt_prdesc epram_descs[] = {
+	{ offsetof(fcc_enet_t, fen_crcec),	"CRC Errors"		},
+	{ offsetof(fcc_enet_t, fen_alec),	"Alignment Errors"	},
+	{ offsetof(fcc_enet_t, fen_disfc),	"Discarded Frames"	},
+	{ offsetof(fcc_enet_t, fen_octc),	"Octets"		},
+	{ offsetof(fcc_enet_t, fen_colc),	"Collisions"		},
+	{ offsetof(fcc_enet_t, fen_broc),	"Broadcast Frames"	},
+	{ offsetof(fcc_enet_t, fen_mulc),	"Multicast Frames"	},
+	{ offsetof(fcc_enet_t, fen_uspc),	"Undersize Frames"	},
+	{ offsetof(fcc_enet_t, fen_frgc),	"Fragments"		},
+	{ offsetof(fcc_enet_t, fen_ospc),	"Oversize Frames"	},
+	{ offsetof(fcc_enet_t, fen_jbrc),	"Jabbers"		},
+	{ offsetof(fcc_enet_t, fen_p64c),	"64 Octet Frames"	},
+	{ offsetof(fcc_enet_t, fen_p65c),	"65-127 Octet Frames"	},
+	{ offsetof(fcc_enet_t, fen_p128c),	"128-255 Octet Frames"	},
+	{ offsetof(fcc_enet_t, fen_p256c),	"256-511 Octet Frames"	},
+	{ offsetof(fcc_enet_t, fen_p512c),	"512-1023 Octet Frames"	},
+	{ offsetof(fcc_enet_t, fen_p1024c),	"1024-1518 Octet Frames"},
+};
+static int epram_ndesc = sizeof (epram_descs) / sizeof (epram_descs[0]);
+
+/*
+ * given an elbt_prdesc array and an array of base addresses, print
+ * each prdesc down the screen with the values fetched from each
+ * base address across the screen
+ */
+static void
+print_desc (elbt_prdesc descs[], int ndesc, uchar *bases[], int nbase)
+{
+	elbt_prdesc *dp = descs, *edp = dp + ndesc;
+	int i;
+
+	printf ("%32s", "");
+
+	for (i = 0; i < nbase; i++)
+		printf ("  Channel %d", i);
+
+	putc ('\n');
+
+	while (dp < edp) {
+
+		printf ("%-32s", dp->lab);
+
+		for (i = 0; i < nbase; i++) {
+			uint val = *(uint *)(bases[i] + dp->off);
+
+			printf (" %10u", val);
+		}
+
+		putc ('\n');
+
+		dp++;
+	}
+}
+
+/*
+ * return number of bits that are set in a value; value contains
+ * nbits (right-justified) bits.
+ */
+static uint __inline__
+nbs (uint value, uint nbits)
+{
+	uint cnt = 0;
+#if 1
+	uint pos = sizeof (uint) * 8;
+
+	__asm__ __volatile__ ("\
+	mtctr	%2\n\
+1:	rlwnm.	%2,%1,%4,31,31\n\
+	beq	2f\n\
+	addi	%0,%0,1\n\
+2:	subi	%4,%4,1\n\
+	bdnz	1b"
+	: "=r"(cnt)
+	: "r"(value), "r"(nbits), "r"(cnt), "r"(pos)
+	: "ctr", "cc" );
+#else
+	uint mask = 1;
+
+	do {
+		if (value & mask)
+			cnt++;
+		mask <<= 1;
+	} while (--nbits);
+#endif
+
+	return (cnt);
+}
+
+static ulong
+badbits (uchar *bp, int n, ulong pat)
+{
+	ulong *lp, cnt = 0;
+	int nl;
+
+	while (n > 0 && ((ulong)bp & (sizeof (ulong) - 1)) != 0) {
+		uchar diff;
+
+		diff = *bp++ ^ (uchar)pat;
+
+		if (diff)
+			cnt += nbs ((ulong)diff, 8);
+
+		n--;
+	}
+
+	lp = (ulong *)bp;
+	nl = n / sizeof (ulong);
+	n -= nl * sizeof (ulong);
+
+	while (nl > 0) {
+		ulong diff;
+
+		diff = *lp++ ^ pat;
+
+		if (diff)
+			cnt += nbs (diff, 32);
+
+		nl--;
+	}
+
+	bp = (uchar *)lp;
+
+	while (n > 0) {
+		uchar diff;
+
+		diff = *bp++ ^ (uchar)pat;
+
+		if (diff)
+			cnt += nbs ((ulong)diff, 8);
+
+		n--;
+	}
+
+	return (cnt);
+}
+
+static inline unsigned short
+swap16 (unsigned short x)
+{
+	return (((x & 0xff) << 8) | ((x & 0xff00) >> 8));
+}
+
+/* broadcast is not an error - we send them like that */
+#define BD_ENET_RX_ERRS	(BD_ENET_RX_STATS & ~BD_ENET_RX_BC)
+
+void
+eth_loopback_test (void)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8260_t *cp = &(immr->im_cpm);
+	int c, nclosed;
+	ulong runtime, nmsec;
+	uchar *bases[3];
+
+	puts ("FCC Ethernet External loopback test\n");
+
+	eth_getenv_enetaddr("ethaddr", NetOurEther);
+
+	/*
+	 * global initialisations for all FCC channels
+	 */
+
+	/* 28.9 - (1-2): ioports have been set up already */
+
+#if defined(CONFIG_HYMOD)
+	/*
+	 * Attention: this is board-specific
+	 * 0, FCC1
+	 * 1, FCC2
+	 * 2, FCC3
+	 */
+#       define FCC_START_LOOP 0
+#       define FCC_END_LOOP   2
+
+	/*
+	 * Attention: this is board-specific
+	 * - FCC1 Rx-CLK is CLK10
+	 * - FCC1 Tx-CLK is CLK11
+	 * - FCC2 Rx-CLK is CLK13
+	 * - FCC2 Tx-CLK is CLK14
+	 * - FCC3 Rx-CLK is CLK15
+	 * - FCC3 Tx-CLK is CLK16
+	 */
+
+	/* 28.9 - (3): connect FCC's tx and rx clocks */
+	immr->im_cpmux.cmx_uar = 0;
+	immr->im_cpmux.cmx_fcr = CMXFCR_RF1CS_CLK10|CMXFCR_TF1CS_CLK11|\
+	    CMXFCR_RF2CS_CLK13|CMXFCR_TF2CS_CLK14|\
+	    CMXFCR_RF3CS_CLK15|CMXFCR_TF3CS_CLK16;
+#elif defined(CONFIG_SBC8260) || defined(CONFIG_SACSng)
+	/*
+	 * Attention: this is board-specific
+	 * 1, FCC2
+	 */
+#       define FCC_START_LOOP 1
+#       define FCC_END_LOOP   1
+
+	/*
+	 * Attention: this is board-specific
+	 * - FCC2 Rx-CLK is CLK13
+	 * - FCC2 Tx-CLK is CLK14
+	 */
+
+	/* 28.9 - (3): connect FCC's tx and rx clocks */
+	immr->im_cpmux.cmx_uar = 0;
+	immr->im_cpmux.cmx_fcr = CMXFCR_RF2CS_CLK13|CMXFCR_TF2CS_CLK14;
+#else
+#error "eth_loopback_test not supported on your board"
+#endif
+
+	puts ("Initialise FCC channels:");
+
+	for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++) {
+		elbt_chan *ecp = &elbt_chans[c];
+		volatile fcc_t *fcp = &immr->im_fcc[c];
+		volatile fcc_enet_t *fpp;
+		int i;
+		ulong addr;
+
+		/*
+		 * initialise channel data
+		 */
+
+		printf (" %d", c);
+
+		memset ((void *)ecp, 0, sizeof (*ecp));
+
+		ecp->state = Idle;
+
+		switch (c) {
+
+		case 0: /* FCC1 */
+			ecp->proff = PROFF_FCC1;
+			ecp->page = CPM_CR_FCC1_PAGE;
+			ecp->sblock = CPM_CR_FCC1_SBLOCK;
+			break;
+
+		case 1: /* FCC2 */
+			ecp->proff = PROFF_FCC2;
+			ecp->page = CPM_CR_FCC2_PAGE;
+			ecp->sblock = CPM_CR_FCC2_SBLOCK;
+			break;
+
+		case 2: /* FCC3 */
+			ecp->proff = PROFF_FCC3;
+			ecp->page = CPM_CR_FCC3_PAGE;
+			ecp->sblock = CPM_CR_FCC3_SBLOCK;
+			break;
+		}
+
+		/*
+		 * set up tx buffers and bds
+		 */
+
+		for (i = 0; i < ELBT_NTXBD; i++) {
+			cbd_t *bdp = &ecp->txbd[i];
+			uchar *bp = &ecp->txbufs[i][0];
+
+			bdp->cbd_bufaddr = (uint)bp;
+			/* room for crc */
+			bdp->cbd_datlen = ELBT_BUFSZ - ELBT_CRCSZ;
+			bdp->cbd_sc = BD_ENET_TX_READY | BD_ENET_TX_PAD | \
+				BD_ENET_TX_LAST | BD_ENET_TX_TC;
+
+			memset ((void *)bp, patbytes[i], ELBT_BUFSZ);
+			NetSetEther (bp, NetBcastAddr, 0x8000);
+		}
+		ecp->txbd[ELBT_NTXBD - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+		/*
+		 * set up rx buffers and bds
+		 */
+
+		for (i = 0; i < ELBT_NRXBD; i++) {
+		    cbd_t *bdp = &ecp->rxbd[i];
+		    uchar *bp = &ecp->rxbufs[i][0];
+
+		    bdp->cbd_bufaddr = (uint)bp;
+		    bdp->cbd_datlen = 0;
+		    bdp->cbd_sc = BD_ENET_RX_EMPTY;
+
+		    memset ((void *)bp, 0, ELBT_BUFSZ);
+		}
+		ecp->rxbd[ELBT_NRXBD - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+		/*
+		 * set up the FCC channel hardware
+		 */
+
+		/* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
+		fcp->fcc_gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+
+		/* 28.9 - (5): FPSMR: fd, enet CRC, Promis, RMON, Rx SHort */
+		fcp->fcc_fpsmr = FCC_PSMR_FDE | FCC_PSMR_LPB | \
+			FCC_PSMR_ENCRC | FCC_PSMR_PRO | \
+			FCC_PSMR_MON | FCC_PSMR_RSH;
+
+		/* 28.9 - (6): FDSR: Ethernet Syn */
+		fcp->fcc_fdsr = 0xD555;
+
+		/* 29.9 - (7): initialise parameter ram */
+		fpp = (fcc_enet_t *)&(immr->im_dprambase[ecp->proff]);
+
+		/* clear whole struct to make sure all resv fields are zero */
+		memset ((void *)fpp, 0, sizeof (fcc_enet_t));
+
+		/*
+		 * common Parameter RAM area
+		 *
+		 * Allocate space in the reserved FCC area of DPRAM for the
+		 * internal buffers.  No one uses this space (yet), so we
+		 * can do this.  Later, we will add resource management for
+		 * this area.
+		 */
+		addr = CPM_FCC_SPECIAL_BASE + (c * 64);
+		fpp->fen_genfcc.fcc_riptr = addr;
+		fpp->fen_genfcc.fcc_tiptr = addr + 32;
+
+		/*
+		 * Set maximum bytes per receive buffer.
+		 * It must be a multiple of 32.
+		 * buffers are in 60x bus memory.
+		 */
+		fpp->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+		fpp->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24;
+		fpp->fen_genfcc.fcc_rbase = (unsigned int)(&ecp->rxbd[0]);
+		fpp->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24;
+		fpp->fen_genfcc.fcc_tbase = (unsigned int)(&ecp->txbd[0]);
+
+		/* protocol-specific area */
+		fpp->fen_cmask = 0xdebb20e3;	/* CRC mask */
+		fpp->fen_cpres = 0xffffffff;	/* CRC preset */
+		fpp->fen_retlim = 15;		/* Retry limit threshold */
+		fpp->fen_mflr = PKT_MAXBUF_SIZE;/* max frame length register */
+
+		/*
+		 * Set Ethernet station address.
+		 *
+		 * This is supplied in the board information structure, so we
+		 * copy that into the controller.
+		 * So, far we have only been given one Ethernet address. We use
+		 * the same address for all channels
+		 */
+#define ea NetOurEther
+		fpp->fen_paddrh = (ea[5] << 8) + ea[4];
+		fpp->fen_paddrm = (ea[3] << 8) + ea[2];
+		fpp->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+
+		fpp->fen_minflr = PKT_MINBUF_SIZE; /* min frame len register */
+		/*
+		 * pad pointer. use tiptr since we don't need
+		 * a specific padding char
+		 */
+		fpp->fen_padptr = fpp->fen_genfcc.fcc_tiptr;
+		fpp->fen_maxd1 = PKT_MAXDMA_SIZE;	/* max DMA1 length */
+		fpp->fen_maxd2 = PKT_MAXDMA_SIZE;	/* max DMA2 length */
+		fpp->fen_rfthr = 1;
+		fpp->fen_rfcnt = 1;
+
+		/* 28.9 - (8): clear out events in FCCE */
+		fcp->fcc_fcce = ~0x0;
+
+		/* 28.9 - (9): FCCM: mask all events */
+		fcp->fcc_fccm = 0;
+
+		/* 28.9 - (10-12): we don't use ethernet interrupts */
+
+		/* 28.9 - (13)
+		 *
+		 * Let's re-initialize the channel now.  We have to do it later
+		 * than the manual describes because we have just now finished
+		 * the BD initialization.
+		 */
+		cp->cp_cpcr = mk_cr_cmd (ecp->page, ecp->sblock, \
+			0x0c, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		do {
+			__asm__ __volatile__ ("eieio");
+		} while (cp->cp_cpcr & CPM_CR_FLG);
+	}
+
+	puts (" done\nStarting test... (Ctrl-C to Finish)\n");
+
+	/*
+	 * Note: don't want serial output from here until the end of the
+	 * test - the delays would probably stuff things up.
+	 */
+
+	clear_ctrlc ();
+	runtime = get_timer (0);
+
+	do {
+		nclosed = 0;
+
+		for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++) {
+			volatile fcc_t *fcp = &immr->im_fcc[c];
+			elbt_chan *ecp = &elbt_chans[c];
+			int i;
+
+			switch (ecp->state) {
+
+			case Idle:
+				/*
+				 * set the channel Running ...
+				 */
+
+				/* 28.9 - (14): enable tx/rx in gfmr */
+				fcp->fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+
+				ecp->state = Running;
+				break;
+
+			case Running:
+				/*
+				 * (while Running only) check for
+				 * termination of the test
+				 */
+
+				(void)ctrlc ();
+
+				if (had_ctrlc ()) {
+					/*
+					 * initiate a "graceful stop transmit"
+					 * on the channel
+					 */
+					cp->cp_cpcr = mk_cr_cmd (ecp->page, \
+						ecp->sblock, 0x0c, \
+						CPM_CR_GRACEFUL_STOP_TX) | \
+						CPM_CR_FLG;
+					do {
+						__asm__ __volatile__ ("eieio");
+					} while (cp->cp_cpcr & CPM_CR_FLG);
+
+					ecp->clstime = get_timer (0);
+					ecp->state = Closing;
+				}
+				/* fall through ... */
+
+			case Closing:
+				/*
+				 * (while Running or Closing) poll the channel:
+				 * - check for any non-READY tx buffers and
+				 *   make them ready
+				 * - check for any non-EMPTY rx buffers and
+				 *   check that they were received correctly,
+				 *   adjust counters etc, then make empty
+				 */
+
+				for (i = 0; i < ELBT_NTXBD; i++) {
+					cbd_t *bdp = &ecp->txbd[i];
+					ushort sc = bdp->cbd_sc;
+
+					if ((sc & BD_ENET_TX_READY) != 0)
+						continue;
+
+					/*
+					 * this frame has finished
+					 * transmitting
+					 */
+					ecp->nsent++;
+
+					if (sc & BD_ENET_TX_STATS) {
+						ulong n;
+
+						/*
+						 * we had an error on
+						 * the transmission
+						 */
+						n = ecp->ntxerr++;
+						if (n < ELBT_MAXTXERR)
+							ecp->txerrs[n] = sc;
+
+						if (sc & BD_ENET_TX_DEF)
+							ecp->txeacc.def++;
+						if (sc & BD_ENET_TX_HB)
+							ecp->txeacc.hb++;
+						if (sc & BD_ENET_TX_LC)
+							ecp->txeacc.lc++;
+						if (sc & BD_ENET_TX_RL)
+							ecp->txeacc.rl++;
+						if (sc & BD_ENET_TX_RCMASK)
+							ecp->txeacc.rc++;
+						if (sc & BD_ENET_TX_UN)
+							ecp->txeacc.un++;
+						if (sc & BD_ENET_TX_CSL)
+							ecp->txeacc.csl++;
+
+						bdp->cbd_sc &= \
+							~BD_ENET_TX_STATS;
+					}
+
+					if (ecp->state == Closing)
+						ecp->clstime = get_timer (0);
+
+					/* make it ready again */
+					bdp->cbd_sc |= BD_ENET_TX_READY;
+				}
+
+				for (i = 0; i < ELBT_NRXBD; i++) {
+					cbd_t *bdp = &ecp->rxbd[i];
+					ushort sc = bdp->cbd_sc, mask;
+
+					if ((sc & BD_ENET_RX_EMPTY) != 0)
+						continue;
+
+					/* we have a new frame in this buffer */
+					ecp->nrcvd++;
+
+					mask = BD_ENET_RX_LAST|BD_ENET_RX_FIRST;
+					if ((sc & mask) != mask) {
+						/* somethings wrong here ... */
+						if (!(sc & BD_ENET_RX_LAST))
+							ecp->rxeacc._l++;
+						if (!(sc & BD_ENET_RX_FIRST))
+							ecp->rxeacc._f++;
+					}
+
+					if (sc & BD_ENET_RX_ERRS) {
+						ulong n;
+
+						/*
+						 * we had some sort of error
+						 * on the frame
+						 */
+						n = ecp->nrxerr++;
+						if (n < ELBT_MAXRXERR)
+							ecp->rxerrs[n] = sc;
+
+						if (sc & BD_ENET_RX_MISS)
+							ecp->rxeacc.m++;
+						if (sc & BD_ENET_RX_BC)
+							ecp->rxeacc.bc++;
+						if (sc & BD_ENET_RX_MC)
+							ecp->rxeacc.mc++;
+						if (sc & BD_ENET_RX_LG)
+							ecp->rxeacc.lg++;
+						if (sc & BD_ENET_RX_NO)
+							ecp->rxeacc.no++;
+						if (sc & BD_ENET_RX_SH)
+							ecp->rxeacc.sh++;
+						if (sc & BD_ENET_RX_CR)
+							ecp->rxeacc.cr++;
+						if (sc & BD_ENET_RX_OV)
+							ecp->rxeacc.ov++;
+						if (sc & BD_ENET_RX_CL)
+							ecp->rxeacc.cl++;
+
+						bdp->cbd_sc &= \
+							~BD_ENET_RX_ERRS;
+					}
+					else {
+						ushort datlen = bdp->cbd_datlen;
+						Ethernet_t *ehp;
+						ushort prot;
+						int ours, tb, n, nbytes;
+
+						ehp = (Ethernet_t *) \
+							&ecp->rxbufs[i][0];
+
+						ours = memcmp (ehp->et_src, \
+							NetOurEther, 6);
+
+						prot = swap16 (ehp->et_protlen);
+						tb = prot & 0x8000;
+						n = prot & 0x7fff;
+
+						nbytes = ELBT_BUFSZ - \
+							offsetof (Ethernet_t, \
+								et_dsap) - \
+							ELBT_CRCSZ;
+
+						/* check the frame is correct */
+						if (datlen != ELBT_BUFSZ)
+							ecp->rxeacc.badlen++;
+						else if (!ours)
+							ecp->rxeacc.badsrc++;
+						else if (!tb || n >= ELBT_NTXBD)
+							ecp->rxeacc.badtyp++;
+						else {
+							ulong patword = \
+								patwords[n];
+							uint nbb;
+
+							nbb = badbits ( \
+								&ehp->et_dsap, \
+								nbytes, \
+								patword);
+
+							ecp->rxeacc.badbit += \
+								nbb;
+						}
+					}
+
+					if (ecp->state == Closing)
+					    ecp->clstime = get_timer (0);
+
+					/* make it empty again */
+					bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+				}
+
+				if (ecp->state != Closing)
+					break;
+
+				/*
+				 * (while Closing) check to see if
+				 * waited long enough
+				 */
+
+				if (get_timer (ecp->clstime) >= ELBT_CLSWAIT) {
+					/* write GFMR: disable tx/rx */
+					fcp->fcc_gfmr &= \
+						~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+					ecp->state = Closed;
+				}
+
+				break;
+
+			case Closed:
+				nclosed++;
+				break;
+			}
+		}
+
+	} while (nclosed < (FCC_END_LOOP - FCC_START_LOOP + 1));
+
+	runtime = get_timer (runtime);
+	if (runtime <= ELBT_CLSWAIT) {
+		printf ("Whoops! somehow elapsed time (%ld) is wrong (<= %d)\n",
+			runtime, ELBT_CLSWAIT);
+		return;
+	}
+	nmsec = runtime - ELBT_CLSWAIT;
+
+	printf ("Test Finished in %ldms (plus %dms close wait period)!\n\n",
+		nmsec, ELBT_CLSWAIT);
+
+	/*
+	 * now print stats
+	 */
+
+	for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++) {
+		elbt_chan *ecp = &elbt_chans[c];
+		uint rxpps, txpps, nerr;
+
+		rxpps = (ecp->nrcvd * 1000) / nmsec;
+		txpps = (ecp->nsent * 1000) / nmsec;
+
+		printf ("Channel %d: %d rcvd (%d pps, %d rxerrs), "
+			"%d sent (%d pps, %d txerrs)\n\n", c,
+			ecp->nrcvd, rxpps, ecp->nrxerr,
+			ecp->nsent, txpps, ecp->ntxerr);
+
+		if ((nerr = ecp->nrxerr) > 0) {
+			ulong i;
+
+			printf ("\tFirst %d rx errs:", nerr);
+			for (i = 0; i < nerr; i++)
+				printf (" %04x", ecp->rxerrs[i]);
+			putc ('\n');
+		}
+
+		if ((nerr = ecp->ntxerr) > 0) {
+			ulong i;
+
+			printf ("\tFirst %d tx errs:", nerr);
+			for (i = 0; i < nerr; i++)
+				printf (" %04x", ecp->txerrs[i]);
+			putc ('\n');
+		}
+	}
+
+	puts ("Receive Error Counts:\n");
+	for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++)
+		bases[c] = (uchar *)&elbt_chans[c].rxeacc;
+	print_desc (rxeacc_descs, rxeacc_ndesc, bases, 3);
+
+	puts ("\nTransmit Error Counts:\n");
+	for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++)
+		bases[c] = (uchar *)&elbt_chans[c].txeacc;
+	print_desc (txeacc_descs, txeacc_ndesc, bases, 3);
+
+	puts ("\nRMON(-like) Counters:\n");
+	for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++)
+		bases[c] = (uchar *)&immr->im_dprambase[elbt_chans[c].proff];
+	print_desc (epram_descs, epram_ndesc, bases, 3);
+}
+
+#endif /* CONFIG_ETHER_LOOPBACK_TEST */
+
+#endif
diff --git a/arch/ppc/cpu/mpc8260/ether_scc.c b/arch/ppc/cpu/mpc8260/ether_scc.c
new file mode 100644
index 0000000..432111d
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/ether_scc.c
@@ -0,0 +1,387 @@
+/*
+ * MPC8260 SCC Ethernet
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright (c) 2001
+ * Advent Networks, Inc. <http://www.adventnetworks.com>
+ * Jay Monkman <jtm@smoothsmoothie.com>
+ *
+ * Modified so that it plays nicely when more than one ETHERNET interface
+ * is in use a la ether_fcc.c.
+ * (C) Copyright 2008
+ * DENX Software Engineerin GmbH
+ * Gary Jennejohn <garyj@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 <asm/cpm_8260.h>
+#include <mpc8260.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <config.h>
+
+#ifndef CONFIG_NET_MULTI
+#error "CONFIG_NET_MULTI must be defined."
+#endif
+
+#if (CONFIG_ETHER_INDEX == 1)
+#  define PROFF_ENET            PROFF_SCC1
+#  define CPM_CR_ENET_PAGE      CPM_CR_SCC1_PAGE
+#  define CPM_CR_ENET_SBLOCK    CPM_CR_SCC1_SBLOCK
+#  define CMXSCR_MASK          (CMXSCR_SC1          |\
+				CMXSCR_RS1CS_MSK    |\
+				CMXSCR_TS1CS_MSK)
+
+#elif (CONFIG_ETHER_INDEX == 2)
+#  define PROFF_ENET            PROFF_SCC2
+#  define CPM_CR_ENET_PAGE      CPM_CR_SCC2_PAGE
+#  define CPM_CR_ENET_SBLOCK    CPM_CR_SCC2_SBLOCK
+#  define CMXSCR_MASK          (CMXSCR_SC2          |\
+				CMXSCR_RS2CS_MSK    |\
+				CMXSCR_TS2CS_MSK)
+
+#elif (CONFIG_ETHER_INDEX == 3)
+#  define PROFF_ENET            PROFF_SCC3
+#  define CPM_CR_ENET_PAGE      CPM_CR_SCC3_PAGE
+#  define CPM_CR_ENET_SBLOCK    CPM_CR_SCC3_SBLOCK
+#  define CMXSCR_MASK          (CMXSCR_SC3          |\
+				CMXSCR_RS3CS_MSK    |\
+				CMXSCR_TS3CS_MSK)
+#elif (CONFIG_ETHER_INDEX == 4)
+#  define PROFF_ENET            PROFF_SCC4
+#  define CPM_CR_ENET_PAGE      CPM_CR_SCC4_PAGE
+#  define CPM_CR_ENET_SBLOCK    CPM_CR_SCC4_SBLOCK
+#  define CMXSCR_MASK          (CMXSCR_SC4          |\
+				CMXSCR_RS4CS_MSK    |\
+				CMXSCR_TS4CS_MSK)
+
+#endif
+
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH  1520
+
+#define TX_BUF_CNT 2
+
+#if !defined(CONFIG_SYS_SCC_TOUT_LOOP)
+  #define CONFIG_SYS_SCC_TOUT_LOOP 1000000
+#endif
+
+static char txbuf[TX_BUF_CNT][ DBUF_LENGTH ];
+
+static uint rxIdx;      /* index of the current RX buffer */
+static uint txIdx;      /* index of the current TX buffer */
+
+/*
+ * SCC 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;
+
+
+static int sec_send(struct eth_device *dev, volatile void *packet, int length)
+{
+    int i;
+    int result = 0;
+
+    if (length <= 0) {
+	printf("scc: bad packet size: %d\n", length);
+	goto out;
+    }
+
+    for(i=0; rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+	if (i >= CONFIG_SYS_SCC_TOUT_LOOP) {
+	    puts ("scc: tx buffer not ready\n");
+	    goto out;
+	}
+    }
+
+    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 |
+				BD_ENET_TX_WRAP);
+
+    for(i=0; rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+	if (i >= CONFIG_SYS_SCC_TOUT_LOOP) {
+	    puts ("scc: tx error\n");
+	    goto out;
+	}
+    }
+
+    /* return only status bits */
+    result = rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+
+ out:
+    return result;
+}
+
+
+static int sec_rx(struct eth_device *dev)
+{
+    int length;
+
+    for (;;)
+    {
+	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)
+	{
+	    printf("err: %x\n", rtx->rxbd[rxIdx].cbd_sc);
+	}
+	else
+	{
+	    /* Pass the packet up to the protocol layers. */
+	    NetReceive(NetRxPackets[rxIdx], length - 4);
+	}
+
+
+	/* Give the buffer back to the SCC. */
+	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++;
+	}
+    }
+    return length;
+}
+
+/**************************************************************
+ *
+ * SCC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+static int sec_init(struct eth_device *dev, bd_t *bis)
+{
+    int i;
+    volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+    scc_enet_t *pram_ptr;
+    uint dpaddr;
+    uchar ea[6];
+
+    rxIdx = 0;
+    txIdx = 0;
+
+    /*
+     * Assign static pointer to BD area.
+     * Avoid exhausting DPRAM, which would cause a panic.
+     */
+    if (rtx == NULL) {
+	    dpaddr = m8260_cpm_dpalloc(sizeof(RTXBD) + 2, 16);
+	    rtx = (RTXBD *)&immr->im_dprambase[dpaddr];
+    }
+
+    /* 24.21 - (1-3): ioports have been set up already */
+
+    /* 24.21 - (4,5): connect SCC's tx and rx clocks, use NMSI for SCC */
+    immr->im_cpmux.cmx_uar = 0;
+    immr->im_cpmux.cmx_scr = ( (immr->im_cpmux.cmx_scr & ~CMXSCR_MASK) |
+			       CONFIG_SYS_CMXSCR_VALUE);
+
+
+    /* 24.21 (6) write RBASE and TBASE to parameter RAM */
+    pram_ptr = (scc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
+    pram_ptr->sen_genscc.scc_rbase = (unsigned int)(&rtx->rxbd[0]);
+    pram_ptr->sen_genscc.scc_tbase = (unsigned int)(&rtx->txbd[0]);
+
+    pram_ptr->sen_genscc.scc_rfcr = 0x18;  /* Nrml Ops and Mot byte ordering */
+    pram_ptr->sen_genscc.scc_tfcr = 0x18;  /* Mot byte ordering, Nrml access */
+
+    pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH; /* max. package len 1520 */
+
+    pram_ptr->sen_cpres  = ~(0x0);        /* Preset CRC */
+    pram_ptr->sen_cmask  = 0xdebb20e3;    /* Constant Mask for CRC */
+
+
+    /* 24.21 - (7): Write INIT RX AND TX PARAMETERS to CPCR */
+    while(immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+    immr->im_cpm.cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
+				     CPM_CR_ENET_SBLOCK,
+				     0x0c,
+				     CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+    /* 24.21 - (8-18): Set up parameter RAM */
+    pram_ptr->sen_crcec  = 0x0;           /* Error Counter CRC (unused) */
+    pram_ptr->sen_alec   = 0x0;           /* Align Error Counter (unused) */
+    pram_ptr->sen_disfc  = 0x0;           /* Discard Frame Counter (unused) */
+
+    pram_ptr->sen_pads   = 0x8888;        /* Short Frame PAD Characters */
+
+    pram_ptr->sen_retlim = 15;            /* Retry Limit Threshold */
+
+    pram_ptr->sen_maxflr = 1518;  /* MAX Frame Length Register */
+    pram_ptr->sen_minflr = 64;            /* MIN Frame Length Register */
+
+    pram_ptr->sen_maxd1  = DBUF_LENGTH;   /* MAX DMA1 Length Register */
+    pram_ptr->sen_maxd2  = DBUF_LENGTH;   /* MAX DMA2 Length Register */
+
+    pram_ptr->sen_gaddr1 = 0x0;   /* Group Address Filter 1 (unused) */
+    pram_ptr->sen_gaddr2 = 0x0;   /* Group Address Filter 2 (unused) */
+    pram_ptr->sen_gaddr3 = 0x0;   /* Group Address Filter 3 (unused) */
+    pram_ptr->sen_gaddr4 = 0x0;   /* Group Address Filter 4 (unused) */
+
+    eth_getenv_enetaddr("ethaddr", ea);
+    pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
+    pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
+    pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
+
+    pram_ptr->sen_pper   = 0x0;   /* Persistence (unused) */
+
+    pram_ptr->sen_iaddr1 = 0x0;   /* Individual Address Filter 1 (unused) */
+    pram_ptr->sen_iaddr2 = 0x0;   /* Individual Address Filter 2 (unused) */
+    pram_ptr->sen_iaddr3 = 0x0;   /* Individual Address Filter 3 (unused) */
+    pram_ptr->sen_iaddr4 = 0x0;   /* Individual Address Filter 4 (unused) */
+
+    pram_ptr->sen_taddrh = 0x0;   /* Tmp Address (MSB) (unused) */
+    pram_ptr->sen_taddrm = 0x0;   /* Tmp Address (unused) */
+    pram_ptr->sen_taddrl = 0x0;   /* Tmp Address (LSB) (unused) */
+
+    /* 24.21 - (19): Initialize RxBD */
+    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;
+
+    /* 24.21 - (20): Initialize TxBD */
+    for (i = 0; i < TX_BUF_CNT; i++)
+    {
+	rtx->txbd[i].cbd_sc = (BD_ENET_TX_PAD  |
+			       BD_ENET_TX_LAST |
+			       BD_ENET_TX_TC);
+	rtx->txbd[i].cbd_datlen = 0;                  /* Reset */
+	rtx->txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
+    }
+
+    rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+    /* 24.21 - (21): Write 0xffff to SCCE */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_scce = ~(0x0);
+
+    /* 24.21 - (22): Write to SCCM to enable TXE, RXF, TXB events */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_sccm = (SCCE_ENET_TXE |
+						   SCCE_ENET_RXF |
+						   SCCE_ENET_TXB);
+
+    /* 24.21 - (23): we don't use ethernet interrupts */
+
+    /* 24.21 - (24): Clear GSMR_H to enable normal operations */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrh = 0;
+
+    /* 24.21 - (25): Clear GSMR_L to enable normal operations */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl = (SCC_GSMRL_TCI        |
+						    SCC_GSMRL_TPL_48     |
+						    SCC_GSMRL_TPP_10     |
+						    SCC_GSMRL_MODE_ENET);
+
+    /* 24.21 - (26): Initialize DSR */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_dsr = 0xd555;
+
+    /* 24.21 - (27): Initialize PSMR2
+     *
+     * Settings:
+     *	CRC = 32-Bit CCITT
+     *	NIB = Begin searching for SFD 22 bits after RENA
+     *	FDE = Full Duplex Enable
+     *	BRO = Reject broadcast packets
+     *	PROMISCOUS = Catch all packets regardless of dest. MAC adress
+     */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_psmr   =	SCC_PSMR_ENCRC	|
+							SCC_PSMR_NIB22	|
+#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
+							SCC_PSMR_FDE	|
+#endif
+#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
+							SCC_PSMR_BRO	|
+#endif
+#if defined(CONFIG_SCC_ENET_PROMISCOUS)
+							SCC_PSMR_PRO	|
+#endif
+							0;
+
+    /* 24.21 - (28): Write to GSMR_L to enable SCC */
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl |= (SCC_GSMRL_ENR |
+						     SCC_GSMRL_ENT);
+
+    return 0;
+}
+
+
+static void sec_halt(struct eth_device *dev)
+{
+    volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+    immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl &= ~(SCC_GSMRL_ENR |
+						      SCC_GSMRL_ENT);
+}
+
+#if 0
+static void sec_restart(void)
+{
+    volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+    immr->im_cpm.cp_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl |= (SCC_GSMRL_ENR |
+							    SCC_GSMRL_ENT);
+}
+#endif
+
+int mpc82xx_scc_enet_initialize(bd_t *bis)
+{
+	struct eth_device *dev;
+
+	dev = (struct eth_device *) malloc(sizeof *dev);
+	memset(dev, 0, sizeof *dev);
+
+	sprintf(dev->name, "SCC ETHERNET");
+	dev->init   = sec_init;
+	dev->halt   = sec_halt;
+	dev->send   = sec_send;
+	dev->recv   = sec_rx;
+
+	eth_register(dev);
+
+	return 1;
+}
diff --git a/arch/ppc/cpu/mpc8260/i2c.c b/arch/ppc/cpu/mpc8260/i2c.c
new file mode 100644
index 0000000..d2bdcc2
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/i2c.c
@@ -0,0 +1,785 @@
+/*
+ * (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
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = 0;
+#endif /* CONFIG_I2C_MULTI_BUS */
+
+/* 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	CONFIG_SYS_I2C_SPEED
+#define	CONFIG_SYS_I2C_SPEED	50000
+#endif
+
+/*-----------------------------------------------------------------------
+ */
+
+typedef void (*i2c_ecb_t)(int, int, void *);    /* 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    */
+	void		*cb_data;	/* private data to be passed  */
+} 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	1	/* no more BDs or buffer space	*/
+#define I2CERR_MSG_TOO_LONG	2	/* tried to send/receive to much data   */
+#define I2CERR_TIMEOUT		3	/* timeout in i2c_doio()	*/
+#define I2CERR_QUEUE_EMPTY	4	/* i2c_doio called without send/receive */
+#define I2CERR_IO_ERROR		5	/* had an error during comms	*/
+
+/* error callback flags */
+#define I2CECB_RX_ERR		0x10	/* this is a receive error	*/
+#define     I2CECB_RX_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 + 1) / 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;
+
+    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 *)CONFIG_SYS_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)
+{
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_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;
+
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+	/* call board specific i2c bus reset routine before accessing the   */
+	/* environment, which might be in a chip on that bus. For details   */
+	/* about this problem see doc/I2C_Edge_Conditions.                  */
+	i2c_init_board();
+#endif
+
+	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, CONFIG_SYS_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 *)CONFIG_SYS_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;
+	state->cb_data = 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 *)CONFIG_SYS_IMMR ;
+	volatile iic_t *iip;
+	volatile i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
+	volatile I2C_BD *txbd, *rxbd;
+	int  n, i, b, rxcnt = 0, rxtimeo = 0, txcnt = 0, txtimeo = 0, rc = 0;
+	uint dpaddr;
+
+	PRINTD(("[I2C] i2c_doio\n"));
+
+	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 */
+
+	if ((n = state->tx_idx) > 0) {
+
+		txbd = ((I2C_BD*)state->txbd) - n;
+		for (i = 0; i < n; i++) {
+			txtimeo += TOUT_LOOP * txbd->length;
+			txbd++;
+		}
+
+		txbd--; /* wait until last in list is done */
+
+		PRINTD(("[I2C] Transmitting...(txbd=0x%08lx)\n", (ulong)txbd));
+
+		udelay(START_DELAY_US);	/* give it time to start */
+		while((txbd->status & BD_SC_READY) && (++txcnt < txtimeo)) {
+			udelay(DELAY_US);
+			if (ctrlc())
+				return (-1);
+			__asm__ __volatile__ ("eieio");
+		}
+	}
+
+	if (txcnt < txtimeo && (n = state->rx_idx) > 0) {
+
+		rxbd = ((I2C_BD*)state->rxbd) - n;
+		for (i = 0; i < n; i++) {
+			rxtimeo += TOUT_LOOP * rxbd->length;
+			rxbd++;
+		}
+
+		rxbd--; /* wait until last in list is done */
+
+		PRINTD(("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong)rxbd));
+
+		udelay(START_DELAY_US);	/* give it time to start */
+		while((rxbd->status & BD_SC_EMPTY) && (++rxcnt < rxtimeo)) {
+			udelay(DELAY_US);
+			if (ctrlc())
+				return (-1);
+			__asm__ __volatile__ ("eieio");
+		}
+	}
+
+	/* Turn off I2C */
+	i2c->i2c_i2mod &= ~0x01;
+
+	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) {
+				if (state->err_cb != NULL)
+					(*state->err_cb)(I2CECB_TX_ERR|b, i,
+						state->cb_data);
+				if (rc == 0)
+					rc = I2CERR_IO_ERROR;
+			}
+		}
+	}
+
+	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) {
+				if (state->err_cb != NULL)
+					(*state->err_cb)(I2CECB_RX_ERR|b, i,
+						state->cb_data);
+				if (rc == 0)
+					rc = I2CERR_IO_ERROR;
+			}
+		}
+	}
+
+	if ((txtimeo > 0 && txcnt >= txtimeo) || \
+	    (rxtimeo > 0 && rxcnt >= rxtimeo)) {
+		if (state->err_cb != NULL)
+			(*state->err_cb)(I2CECB_TIMEOUT, -1, state->cb_data);
+		if (rc == 0)
+			rc = I2CERR_TIMEOUT;
+	}
+
+	return (rc);
+}
+
+static void
+i2c_probe_callback(int flags, int xnum, void *data)
+{
+	/*
+	 * the only acceptable errors are a transmit NAK or a receive
+	 * overrun - tx NAK means the device does not exist, rx OV
+	 * means the device must have responded to the slave address
+	 * even though the transfer failed
+	 */
+	if (flags == (I2CECB_TX_ERR|I2CECB_TX_NAK))
+		*(int *)data |= 1;
+	if (flags == (I2CECB_RX_ERR|I2CECB_RX_OV))
+		*(int *)data |= 2;
+}
+
+int
+i2c_probe(uchar chip)
+{
+	i2c_state_t state;
+	int rc, err_flag;
+	uchar buf[1];
+
+	i2c_newio(&state);
+
+	state.err_cb = i2c_probe_callback;
+	state.cb_data = (void *) &err_flag;
+	err_flag = 0;
+
+	rc = i2c_receive(&state, chip, 0, I2CF_START_COND|I2CF_STOP_COND, 1, buf);
+
+	if (rc != 0)
+		return (rc);	/* probe failed */
+
+	rc = i2c_doio(&state);
+
+	if (rc == 0)
+		return (0);	/* device exists - read succeeded */
+
+	if (rc == I2CERR_TIMEOUT)
+		return (-1);	/* device does not exist - timeout */
+
+	if (rc != I2CERR_IO_ERROR || err_flag == 0)
+		return (rc);	/* probe failed */
+
+	if (err_flag & 1)
+		return (-1);	/* device does not exist - had transmit NAK */
+
+	return (0);	/* device exists - had receive overrun */
+}
+
+
+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 CONFIG_SYS_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)) & CONFIG_SYS_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 CONFIG_SYS_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)) & CONFIG_SYS_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;
+}
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+/*
+ * Functions for multiple I2C bus handling
+ */
+unsigned int i2c_get_bus_num(void)
+{
+	return i2c_bus_num;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+#if defined(CONFIG_I2C_MUX)
+	if (bus < CONFIG_SYS_MAX_I2C_BUS) {
+		i2c_bus_num = bus;
+	} else {
+		int	ret;
+
+		ret = i2x_mux_select_mux(bus);
+		if (ret == 0)
+			i2c_bus_num = bus;
+		else
+			return ret;
+	}
+#else
+	if (bus >= CONFIG_SYS_MAX_I2C_BUS)
+		return -1;
+	i2c_bus_num = bus;
+#endif
+	return 0;
+}
+
+#endif	/* CONFIG_I2C_MULTI_BUS */
+#endif	/* CONFIG_HARD_I2C */
diff --git a/arch/ppc/cpu/mpc8260/interrupts.c b/arch/ppc/cpu/mpc8260/interrupts.c
new file mode 100644
index 0000000..a7700c4
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/interrupts.c
@@ -0,0 +1,279 @@
+/*
+ * (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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <mpc8260_irq.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/****************************************************************************/
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	ulong count;
+};
+
+static struct irq_action irq_handlers[NR_IRQS];
+
+static ulong ppc_cached_irq_mask[NR_MASK_WORDS];
+
+/****************************************************************************/
+/* this section was ripped out of arch/ppc/kernel/ppc8260_pic.c in the	    */
+/* Linux/PPC 2.4.x source. There was no copyright notice in that file.	    */
+
+/* The 8260 internal interrupt controller.  It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+static u_char irq_to_siureg[] = {
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static u_char irq_to_siubit[] = {
+	31, 16, 17, 18, 19, 20, 21, 22,
+	23, 24, 25, 26, 27, 28, 29, 30,
+	29, 30, 16, 17, 18, 19, 20, 21,
+	22, 23, 24, 25, 26, 27, 28, 31,
+	0, 1, 2, 3, 4, 5, 6, 7,
+	8, 9, 10, 11, 12, 13, 14, 15,
+	15, 14, 13, 12, 11, 10, 9, 8,
+	7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static void m8260_mask_irq (unsigned int irq_nr)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int bit, word;
+	volatile uint *simr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_unmask_irq (unsigned int irq_nr)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int bit, word;
+	volatile uint *simr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_mask_and_ack (unsigned int irq_nr)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int bit, word;
+	volatile uint *simr, *sipnr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	sipnr = &(immr->im_intctl.ic_sipnrh);
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+	sipnr[word] = 1 << (31 - bit);
+}
+
+static int m8260_get_irq (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int irq;
+	unsigned long bits;
+
+	/* For MPC8260, read the SIVEC register and shift the bits down
+	 * to get the irq number.         */
+	bits = immr->im_intctl.ic_sivec;
+	irq = bits >> 26;
+	return irq;
+}
+
+/* end of code ripped out of arch/ppc/kernel/ppc8260_pic.c		    */
+/****************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	*decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_HZ;
+
+	/* Initialize the default interrupt mapping priorities */
+	immr->im_intctl.ic_sicr = 0;
+	immr->im_intctl.ic_siprr = 0x05309770;
+	immr->im_intctl.ic_scprrh = 0x05309770;
+	immr->im_intctl.ic_scprrl = 0x05309770;
+
+	/* disable all interrupts and clear all pending bits */
+	immr->im_intctl.ic_simrh = ppc_cached_irq_mask[0] = 0;
+	immr->im_intctl.ic_simrl = ppc_cached_irq_mask[1] = 0;
+	immr->im_intctl.ic_sipnrh = 0xffffffff;
+	immr->im_intctl.ic_sipnrl = 0xffffffff;
+
+#ifdef CONFIG_HYMOD
+	/*
+	 * ensure all external interrupt sources default to trigger on
+	 * high-to-low transition (i.e. edge triggered active low)
+	 */
+	immr->im_intctl.ic_siexr = -1;
+#endif
+
+	return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	int irq, unmask = 1;
+
+	irq = m8260_get_irq (regs);
+
+	m8260_mask_and_ack (irq);
+
+	enable_interrupts ();
+
+	if (irq_handlers[irq].handler != NULL)
+		(*irq_handlers[irq].handler) (irq_handlers[irq].arg);
+	else {
+		printf ("\nBogus External Interrupt IRQ %d\n", irq);
+		/*
+		 * turn off the bogus interrupt, otherwise it
+		 * might repeat forever
+		 */
+		unmask = 0;
+	}
+
+	if (unmask)
+		m8260_unmask_irq (irq);
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free an interrupt handler.
+ */
+
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+	if (irq < 0 || irq >= NR_IRQS) {
+		printf ("irq_install_handler: bad irq number %d\n", irq);
+		return;
+	}
+
+	if (irq_handlers[irq].handler != NULL)
+		printf ("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+				(ulong) handler, (ulong) irq_handlers[irq].handler);
+
+	irq_handlers[irq].handler = handler;
+	irq_handlers[irq].arg = arg;
+
+	m8260_unmask_irq (irq);
+}
+
+void irq_free_handler (int irq)
+{
+	if (irq < 0 || irq >= NR_IRQS) {
+		printf ("irq_free_handler: bad irq number %d\n", irq);
+		return;
+	}
+
+	m8260_mask_irq (irq);
+
+	irq_handlers[irq].handler = NULL;
+	irq_handlers[irq].arg = NULL;
+}
+
+/****************************************************************************/
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+/****************************************************************************/
+
+#if defined(CONFIG_CMD_IRQ)
+
+/* ripped this out of ppc4xx/interrupts.c */
+
+/*******************************************************************************
+*
+* irqinfo - print information about PCI devices
+*
+*/
+void
+do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+	int irq, re_enable;
+
+	re_enable = disable_interrupts ();
+
+	puts ("\nInterrupt-Information:\n"
+		"Nr  Routine   Arg       Count\n");
+
+	for (irq = 0; irq < 32; irq++)
+		if (irq_handlers[irq].handler != NULL)
+			printf ("%02d  %08lx  %08lx  %ld\n", irq,
+					(ulong) irq_handlers[irq].handler,
+					(ulong) irq_handlers[irq].arg,
+					irq_handlers[irq].count);
+
+	if (re_enable)
+		enable_interrupts ();
+}
+
+#endif
diff --git a/arch/ppc/cpu/mpc8260/kgdb.S b/arch/ppc/cpu/mpc8260/kgdb.S
new file mode 100644
index 0000000..c5936c7
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/kgdb.S
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 2000	Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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 <command.h>
+#include <mpc8260.h>
+#include <version.h>
+
+#define CONFIG_8260 1		/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+
+ /*
+ * cache flushing routines for kgdb
+ */
+
+	.globl	kgdb_flush_cache_all
+kgdb_flush_cache_all:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_ICFI|HID0_DCI	/* Invalidate All */
+	SYNC
+	mtspr	HID0, r3
+	blr
+
+	.globl	kgdb_flush_cache_range
+kgdb_flush_cache_range:
+	li	r5,CONFIG_SYS_CACHELINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,CONFIG_SYS_CACHELINE_SHIFT
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	2b
+	SYNC
+	blr
+
+#endif
diff --git a/arch/ppc/cpu/mpc8260/pci.c b/arch/ppc/cpu/mpc8260/pci.c
new file mode 100644
index 0000000..6a14ba4
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/pci.c
@@ -0,0 +1,466 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (c) 2005 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ * Added support for PCI bridge on MPC8272ADS
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <pci.h>
+#include <mpc8260.h>
+#include <asm/m8260_pci.h>
+#include <asm/io.h>
+#ifdef CONFIG_OF_LIBFDT
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272 || defined CONFIG_PM826
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ *   Local->PCI map (from CPU)				   controlled by
+ *   MPC826x master window
+ *
+ *   0x80000000 - 0xBFFFFFFF	CPU2PCI space		   PCIBR0
+ *   0xF4000000 - 0xF7FFFFFF	CPU2PCI space		   PCIBR1
+ *
+ *   0x80000000 - 0x9FFFFFFF	0x80000000 - 0x9FFFFFFF	  (Outbound ATU #1)
+ *				PCI Mem with prefetch
+ *
+ *   0xA0000000 - 0xBFFFFFFF	0xA0000000 - 0xBFFFFFFF	  (Outbound ATU #2)
+ *				PCI Mem w/o  prefetch
+ *
+ *   0xF4000000 - 0xF7FFFFFF	0x00000000 - 0x03FFFFFF	  (Outbound ATU #3)
+ *				32-bit PCI IO
+ *
+ *   PCI->Local map (from PCI)
+ *   MPC826x slave window				   controlled by
+ *
+ *   0x00000000 - 0x1FFFFFFF	0x00000000 - 0x1FFFFFFF	  (Inbound ATU #1)
+ *				MPC826x local memory
+ */
+
+/*
+ * Slave window that allows PCI masters to access MPC826x local memory.
+ * This window is set up using the first set of Inbound ATU registers
+ */
+
+#ifndef CONFIG_SYS_PCI_SLV_MEM_LOCAL
+#define PCI_SLV_MEM_LOCAL CONFIG_SYS_SDRAM_BASE	/* Local base */
+#else
+#define PCI_SLV_MEM_LOCAL CONFIG_SYS_PCI_SLV_MEM_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_SLV_MEM_BUS
+#define PCI_SLV_MEM_BUS 0x00000000	/* PCI base */
+#else
+#define PCI_SLV_MEM_BUS CONFIG_SYS_PCI_SLV_MEM_BUS
+#endif
+
+#ifndef CONFIG_SYS_PICMR0_MASK_ATTRIB
+#define PICMR0_MASK_ATTRIB	(PICMR_MASK_512MB | PICMR_ENABLE | \
+				 PICMR_PREFETCH_EN)
+#else
+#define PICMR0_MASK_ATTRIB CONFIG_SYS_PICMR0_MASK_ATTRIB
+#endif
+
+/*
+ * These are the windows that allow the CPU to access PCI address space.
+ * All three PCI master windows, which allow the CPU to access PCI
+ * prefetch, non prefetch, and IO space (see below), must all fit within
+ * these windows.
+ */
+
+/* PCIBR0 */
+#ifndef CONFIG_SYS_PCI_MSTR0_LOCAL
+#define PCI_MSTR0_LOCAL		0x80000000	/* Local base */
+#else
+#define PCI_MSTR0_LOCAL CONFIG_SYS_PCI_MSTR0_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCIMSK0_MASK
+#define PCIMSK0_MASK		PCIMSK_1GB	/* Size of window */
+#else
+#define PCIMSK0_MASK	CONFIG_SYS_PCIMSK0_MASK
+#endif
+
+/* PCIBR1 */
+#ifndef CONFIG_SYS_PCI_MSTR1_LOCAL
+#define PCI_MSTR1_LOCAL		0xF4000000	/* Local base */
+#else
+#define PCI_MSTR1_LOCAL		CONFIG_SYS_PCI_MSTR1_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCIMSK1_MASK
+#define	 PCIMSK1_MASK		PCIMSK_64MB	/* Size of window */
+#else
+#define	 PCIMSK1_MASK		CONFIG_SYS_PCIMSK1_MASK
+#endif
+
+/*
+ * Master window that allows the CPU to access PCI Memory (prefetch).
+ * This window will be setup with the first set of Outbound ATU registers
+ * in the bridge.
+ */
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEM_LOCAL
+#define PCI_MSTR_MEM_LOCAL 0x80000000	/* Local base */
+#else
+#define PCI_MSTR_MEM_LOCAL CONFIG_SYS_PCI_MSTR_MEM_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEM_BUS
+#define PCI_MSTR_MEM_BUS 0x80000000	/* PCI base   */
+#else
+#define PCI_MSTR_MEM_BUS CONFIG_SYS_PCI_MSTR_MEM_BUS
+#endif
+
+#ifndef CONFIG_SYS_CPU_PCI_MEM_START
+#define CPU_PCI_MEM_START PCI_MSTR_MEM_LOCAL
+#else
+#define CPU_PCI_MEM_START CONFIG_SYS_CPU_PCI_MEM_START
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEM_SIZE
+#define PCI_MSTR_MEM_SIZE 0x10000000	/* 256MB */
+#else
+#define PCI_MSTR_MEM_SIZE CONFIG_SYS_PCI_MSTR_MEM_SIZE
+#endif
+
+#ifndef CONFIG_SYS_POCMR0_MASK_ATTRIB
+#define POCMR0_MASK_ATTRIB	(POCMR_MASK_256MB | POCMR_ENABLE | POCMR_PREFETCH_EN)
+#else
+#define POCMR0_MASK_ATTRIB CONFIG_SYS_POCMR0_MASK_ATTRIB
+#endif
+
+/*
+ * Master window that allows the CPU to access PCI Memory (non-prefetch).
+ * This window will be setup with the second set of Outbound ATU registers
+ * in the bridge.
+ */
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_LOCAL
+#define PCI_MSTR_MEMIO_LOCAL 0x90000000 /* Local base */
+#else
+#define PCI_MSTR_MEMIO_LOCAL CONFIG_SYS_PCI_MSTR_MEMIO_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_BUS
+#define PCI_MSTR_MEMIO_BUS 0x90000000	/* PCI base   */
+#else
+#define PCI_MSTR_MEMIO_BUS CONFIG_SYS_PCI_MSTR_MEMIO_BUS
+#endif
+
+#ifndef CONFIG_SYS_CPU_PCI_MEMIO_START
+#define CPU_PCI_MEMIO_START PCI_MSTR_MEMIO_LOCAL
+#else
+#define CPU_PCI_MEMIO_START CONFIG_SYS_CPU_PCI_MEMIO_START
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_SIZE
+#define PCI_MSTR_MEMIO_SIZE 0x10000000	/* 256 MB */
+#else
+#define PCI_MSTR_MEMIO_SIZE CONFIG_SYS_PCI_MSTR_MEMIO_SIZE
+#endif
+
+#ifndef CONFIG_SYS_POCMR1_MASK_ATTRIB
+#define POCMR1_MASK_ATTRIB	(POCMR_MASK_512MB | POCMR_ENABLE)
+#else
+#define POCMR1_MASK_ATTRIB CONFIG_SYS_POCMR1_MASK_ATTRIB
+#endif
+
+/*
+ * Master window that allows the CPU to access PCI IO space.
+ * This window will be setup with the third set of Outbound ATU registers
+ * in the bridge.
+ */
+
+#ifndef CONFIG_SYS_PCI_MSTR_IO_LOCAL
+#define PCI_MSTR_IO_LOCAL 0xA0000000	/* Local base */
+#else
+#define PCI_MSTR_IO_LOCAL CONFIG_SYS_PCI_MSTR_IO_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_IO_BUS
+#define PCI_MSTR_IO_BUS 0xA0000000	/* PCI base   */
+#else
+#define PCI_MSTR_IO_BUS CONFIG_SYS_PCI_MSTR_IO_BUS
+#endif
+
+#ifndef CONFIG_SYS_CPU_PCI_IO_START
+#define CPU_PCI_IO_START PCI_MSTR_IO_LOCAL
+#else
+#define CPU_PCI_IO_START CONFIG_SYS_CPU_PCI_IO_START
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_IO_SIZE
+#define PCI_MSTR_IO_SIZE 0x10000000	/* 256MB */
+#else
+#define PCI_MSTR_IO_SIZE CONFIG_SYS_PCI_MSTR_IO_SIZE
+#endif
+
+#ifndef CONFIG_SYS_POCMR2_MASK_ATTRIB
+#define POCMR2_MASK_ATTRIB	(POCMR_MASK_256MB | POCMR_ENABLE | POCMR_PCI_IO)
+#else
+#define POCMR2_MASK_ATTRIB CONFIG_SYS_POCMR2_MASK_ATTRIB
+#endif
+
+/* PCI bus configuration registers.
+ */
+
+#define PCI_CLASS_BRIDGE_CTLR	0x06
+
+
+static inline void pci_outl (u32 addr, u32 data)
+{
+	*(volatile u32 *) addr = cpu_to_le32 (data);
+}
+
+void pci_mpc8250_init (struct pci_controller *hose)
+{
+	u16 tempShort;
+
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	pci_dev_t host_devno = PCI_BDF (0, 0, 0);
+
+	pci_setup_indirect (hose, CONFIG_SYS_IMMR + PCI_CFG_ADDR_REG,
+			    CONFIG_SYS_IMMR + PCI_CFG_DATA_REG);
+
+	/*
+	 * Setting required to enable local bus for PCI (SIUMCR [LBPC]).
+	 */
+#ifdef CONFIG_MPC8266ADS
+	immap->im_siu_conf.sc_siumcr =
+		(immap->im_siu_conf.sc_siumcr & ~SIUMCR_LBPC11)
+		| SIUMCR_LBPC01;
+#elif defined(CONFIG_ADSTYPE) && CONFIG_ADSTYPE == CONFIG_SYS_PQ2FADS
+/* nothing to do for this board here */
+#elif defined CONFIG_MPC8272
+	immap->im_siu_conf.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
+				  ~SIUMCR_BBD &
+				  ~SIUMCR_ESE &
+				  ~SIUMCR_PBSE &
+				  ~SIUMCR_CDIS &
+				  ~SIUMCR_DPPC11 &
+				  ~SIUMCR_L2CPC11 &
+				  ~SIUMCR_LBPC11 &
+				  ~SIUMCR_APPC11 &
+				  ~SIUMCR_CS10PC11 &
+				  ~SIUMCR_BCTLC11 &
+				  ~SIUMCR_MMR11)
+				  | SIUMCR_DPPC11
+				  | SIUMCR_L2CPC01
+				  | SIUMCR_LBPC00
+				  | SIUMCR_APPC10
+				  | SIUMCR_CS10PC00
+				  | SIUMCR_BCTLC00
+				  | SIUMCR_MMR11;
+#elif defined(CONFIG_TQM8272)
+/* nothing to do for this Board here */
+#else
+	/*
+	 * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
+	 * and local bus for PCI (SIUMCR [LBPC]).
+	 */
+	immap->im_siu_conf.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
+						~SIUMCR_LBPC11 &
+						~SIUMCR_CS10PC11 &
+						~SIUMCR_LBPC11) |
+					SIUMCR_LBPC01 |
+					SIUMCR_CS10PC01 |
+					SIUMCR_APPC10;
+#endif
+
+	/* Make PCI lowest priority */
+	/* Each 4 bits is a device bus request	and the MS 4bits
+	   is highest priority */
+	/* Bus		     4bit value
+	   ---		     ----------
+	   CPM high	     0b0000
+	   CPM middle	     0b0001
+	   CPM low	     0b0010
+	   PCI reguest	     0b0011
+	   Reserved	     0b0100
+	   Reserved	     0b0101
+	   Internal Core     0b0110
+	   External Master 1 0b0111
+	   External Master 2 0b1000
+	   External Master 3 0b1001
+	   The rest are reserved */
+	immap->im_siu_conf.sc_ppc_alrh = 0x61207893;
+
+	/* Park bus on core while modifying PCI Bus accesses */
+	immap->im_siu_conf.sc_ppc_acr = 0x6;
+
+	/*
+	 * Set up master windows that allow the CPU to access PCI space. These
+	 * windows are set up using the two SIU PCIBR registers.
+	 */
+	immap->im_memctl.memc_pcimsk0 = PCIMSK0_MASK;
+	immap->im_memctl.memc_pcibr0 = PCI_MSTR0_LOCAL | PCIBR_ENABLE;
+
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272
+	immap->im_memctl.memc_pcimsk1 = PCIMSK1_MASK;
+	immap->im_memctl.memc_pcibr1 = PCI_MSTR1_LOCAL | PCIBR_ENABLE;
+#endif
+
+	/* Release PCI RST (by default the PCI RST signal is held low)	*/
+	immap->im_pci.pci_gcr = cpu_to_le32 (PCIGCR_PCI_BUS_EN);
+
+	/* give it some time */
+	{
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272
+		/* Give the PCI cards more time to initialize before query
+		   This might be good for other boards also
+		 */
+		int i;
+
+		for (i = 0; i < 1000; ++i)
+#endif
+			udelay (1000);
+	}
+
+	/*
+	 * Set up master window that allows the CPU to access PCI Memory (prefetch)
+	 * space. This window is set up using the first set of Outbound ATU registers.
+	 */
+	immap->im_pci.pci_potar0 = cpu_to_le32 (PCI_MSTR_MEM_BUS >> 12);	/* PCI base */
+	immap->im_pci.pci_pobar0 = cpu_to_le32 (PCI_MSTR_MEM_LOCAL >> 12);	/* Local base */
+	immap->im_pci.pci_pocmr0 = cpu_to_le32 (POCMR0_MASK_ATTRIB);	/* Size & attribute */
+
+	/*
+	 * Set up master window that allows the CPU to access PCI Memory (non-prefetch)
+	 * space. This window is set up using the second set of Outbound ATU registers.
+	 */
+	immap->im_pci.pci_potar1 = cpu_to_le32 (PCI_MSTR_MEMIO_BUS >> 12);	/* PCI base */
+	immap->im_pci.pci_pobar1 = cpu_to_le32 (PCI_MSTR_MEMIO_LOCAL >> 12);	/* Local base */
+	immap->im_pci.pci_pocmr1 = cpu_to_le32 (POCMR1_MASK_ATTRIB);	/* Size & attribute */
+
+	/*
+	 * Set up master window that allows the CPU to access PCI IO space. This window
+	 * is set up using the third set of Outbound ATU registers.
+	 */
+	immap->im_pci.pci_potar2 = cpu_to_le32 (PCI_MSTR_IO_BUS >> 12); /* PCI base */
+	immap->im_pci.pci_pobar2 = cpu_to_le32 (PCI_MSTR_IO_LOCAL >> 12);	/* Local base */
+	immap->im_pci.pci_pocmr2 = cpu_to_le32 (POCMR2_MASK_ATTRIB);	/* Size & attribute */
+
+	/*
+	 * Set up slave window that allows PCI masters to access MPC826x local memory.
+	 * This window is set up using the first set of Inbound ATU registers
+	 */
+	immap->im_pci.pci_pitar0 = cpu_to_le32 (PCI_SLV_MEM_LOCAL >> 12);	/* PCI base */
+	immap->im_pci.pci_pibar0 = cpu_to_le32 (PCI_SLV_MEM_BUS >> 12); /* Local base */
+	immap->im_pci.pci_picmr0 = cpu_to_le32 (PICMR0_MASK_ATTRIB);	/* Size & attribute */
+
+	/* See above for description - puts PCI request as highest priority */
+#ifdef CONFIG_MPC8272
+	immap->im_siu_conf.sc_ppc_alrh = 0x01236745;
+#else
+	immap->im_siu_conf.sc_ppc_alrh = 0x03124567;
+#endif
+
+	/* Park the bus on the PCI */
+	immap->im_siu_conf.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
+
+	/* Host mode - specify the bridge as a host-PCI bridge */
+
+	pci_hose_write_config_byte (hose, host_devno, PCI_CLASS_CODE,
+				    PCI_CLASS_BRIDGE_CTLR);
+
+	/* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
+	pci_hose_read_config_word (hose, host_devno, PCI_COMMAND, &tempShort);
+	pci_hose_write_config_word (hose, host_devno, PCI_COMMAND,
+				    tempShort | PCI_COMMAND_MASTER |
+				    PCI_COMMAND_MEMORY);
+
+	/* do some bridge init, should be done on all 8260 based bridges */
+	pci_hose_write_config_byte (hose, host_devno, PCI_CACHE_LINE_SIZE,
+				    0x08);
+	pci_hose_write_config_byte (hose, host_devno, PCI_LATENCY_TIMER,
+				    0xF8);
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	/* System memory space */
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272 || defined CONFIG_PM826
+	pci_set_region (hose->regions + 0,
+			PCI_SLV_MEM_BUS,
+			PCI_SLV_MEM_LOCAL,
+			gd->ram_size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+#else
+	pci_set_region (hose->regions + 0,
+			CONFIG_SYS_SDRAM_BASE,
+			CONFIG_SYS_SDRAM_BASE,
+			0x4000000, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+#endif
+
+	/* PCI memory space */
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272
+	pci_set_region (hose->regions + 1,
+			PCI_MSTR_MEMIO_BUS,
+			PCI_MSTR_MEMIO_LOCAL,
+			PCI_MSTR_MEMIO_SIZE, PCI_REGION_MEM);
+#else
+	pci_set_region (hose->regions + 1,
+			PCI_MSTR_MEM_BUS,
+			PCI_MSTR_MEM_LOCAL,
+			PCI_MSTR_MEM_SIZE, PCI_REGION_MEM);
+#endif
+
+	/* PCI I/O space */
+	pci_set_region (hose->regions + 2,
+			PCI_MSTR_IO_BUS,
+			PCI_MSTR_IO_LOCAL, PCI_MSTR_IO_SIZE, PCI_REGION_IO);
+
+	hose->region_count = 3;
+
+	pci_register_hose (hose);
+	/* Mask off master abort machine checks */
+	immap->im_pci.pci_emr &= cpu_to_le32 (~PCI_ERROR_PCI_NO_RSP);
+	eieio ();
+
+	hose->last_busno = pci_hose_scan (hose);
+
+
+	/* clear the error in the error status register */
+	immap->im_pci.pci_esr = cpu_to_le32 (PCI_ERROR_PCI_NO_RSP);
+
+	/* unmask master abort machine checks */
+	immap->im_pci.pci_emr |= cpu_to_le32 (PCI_ERROR_PCI_NO_RSP);
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+	do_fixup_by_prop_u32(blob, "device_type", "pci", 4,
+		"clock-frequency", gd->pci_clk, 1);
+}
+#endif
+
+#endif /* CONFIG_PCI */
diff --git a/arch/ppc/cpu/mpc8260/serial_scc.c b/arch/ppc/cpu/mpc8260/serial_scc.c
new file mode 100644
index 0000000..4ab6a28
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/serial_scc.c
@@ -0,0 +1,498 @@
+/*
+ * (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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00.
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SCC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_ON_SCC)
+
+#if CONFIG_CONS_INDEX == 1	/* Console on SCC1 */
+
+#define SCC_INDEX		0
+#define PROFF_SCC		PROFF_SCC1
+#define CMXSCR_MASK		(CMXSCR_GR1|CMXSCR_SC1|\
+					CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC1_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 2	/* Console on SCC2 */
+
+#define SCC_INDEX		1
+#define PROFF_SCC		PROFF_SCC2
+#define CMXSCR_MASK		(CMXSCR_GR2|CMXSCR_SC2|\
+					CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC2_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 3	/* Console on SCC3 */
+
+#define SCC_INDEX		2
+#define PROFF_SCC		PROFF_SCC3
+#define CMXSCR_MASK		(CMXSCR_GR3|CMXSCR_SC3|\
+					CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC3_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 4	/* Console on SCC4 */
+
+#define SCC_INDEX		3
+#define PROFF_SCC		PROFF_SCC4
+#define CMXSCR_MASK		(CMXSCR_GR4|CMXSCR_SC4|\
+					CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC4_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+int serial_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile scc_t *sp;
+	volatile scc_uart_t *up;
+	volatile cbd_t *tbdf, *rbdf;
+	volatile cpm8260_t *cp = &(im->im_cpm);
+	uint	dpaddr;
+
+	/* initialize pointers to SCC */
+
+	sp = (scc_t *) &(im->im_scc[SCC_INDEX]);
+	up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+
+	/* Disable transmitter/receiver.
+	*/
+	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* put the SCC channel into NMSI (non multiplexd serial interface)
+	 * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+	 */
+	im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr&~CMXSCR_MASK)|CMXSCR_VALUE;
+
+	/* Set up the baud rate generator.
+	*/
+	serial_setbrg ();
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+	rbdf->cbd_bufaddr = (uint) (rbdf+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+	tbdf->cbd_sc = BD_SC_WRAP;
+
+	/* Set up the uart parameters in the parameter ram.
+	*/
+	up->scc_genscc.scc_rbase = dpaddr;
+	up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+	up->scc_genscc.scc_rfcr = CPMFCR_EB;
+	up->scc_genscc.scc_tfcr = CPMFCR_EB;
+	up->scc_genscc.scc_mrblr = 1;
+	up->scc_maxidl = 0;
+	up->scc_brkcr = 1;
+	up->scc_parec = 0;
+	up->scc_frmec = 0;
+	up->scc_nosec = 0;
+	up->scc_brkec = 0;
+	up->scc_uaddr1 = 0;
+	up->scc_uaddr2 = 0;
+	up->scc_toseq = 0;
+	up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+	up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+	up->scc_rccm = 0xc0ff;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->scc_sccm = 0;
+	sp->scc_scce = 0xffff;
+
+	/* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+	*/
+	sp->scc_gsmrh = SCC_GSMRH_RFW;	/* 8 bit FIFO */
+	sp->scc_gsmrl = \
+		SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+	/* Set CTS flow control, 1 stop bit, 8 bit character length,
+	 * normal async UART mode, no parity
+	 */
+	sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL;
+
+	/* execute the "Init Rx and Tx params" CP command.
+	*/
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
+					0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver.
+	*/
+	sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+	return (0);
+}
+
+void
+serial_setbrg (void)
+{
+#if defined(CONFIG_CONS_USE_EXTC)
+	m8260_cpm_extcbrg(SCC_INDEX, gd->baudrate,
+		CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+	m8260_cpm_setbrg(SCC_INDEX, gd->baudrate);
+#endif
+}
+
+void
+serial_putc(const char c)
+{
+	volatile scc_uart_t	*up;
+	volatile cbd_t		*tbdf;
+	volatile immap_t	*im;
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	im = (immap_t *)CONFIG_SYS_IMMR;
+	up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+	tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase];
+
+	/* Wait for last character to go.
+	 */
+	while (tbdf->cbd_sc & BD_SC_READY)
+		;
+
+	/* Load the character into the transmit buffer.
+	 */
+	*(volatile char *)tbdf->cbd_bufaddr = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int
+serial_getc(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im;
+	unsigned char		c;
+
+	im = (immap_t *)CONFIG_SYS_IMMR;
+	up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+	rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+	/* Wait for character to show up.
+	 */
+	while (rbdf->cbd_sc & BD_SC_EMPTY)
+		;
+
+	/* Grab the char and clear the buffer again.
+	 */
+	c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return (c);
+}
+
+int
+serial_tstc()
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im;
+
+	im = (immap_t *)CONFIG_SYS_IMMR;
+	up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+	rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+	return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0);
+}
+
+#endif	/* CONFIG_CONS_ON_SCC */
+
+#if defined(CONFIG_KGDB_ON_SCC)
+
+#if defined(CONFIG_CONS_ON_SCC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Whoops! serial console and kgdb are on the same scc serial port
+#endif
+
+#if CONFIG_KGDB_INDEX == 1	/* KGDB Port on SCC1 */
+
+#define KGDB_SCC_INDEX		0
+#define KGDB_PROFF_SCC		PROFF_SCC1
+#define KGDB_CMXSCR_MASK	(CMXSCR_GR1|CMXSCR_SC1|\
+					CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define KGDB_CMXSCR_VALUE	(CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define KGDB_CPM_CR_SCC_PAGE	CPM_CR_SCC1_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK	CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 2	/* KGDB Port on SCC2 */
+
+#define KGDB_SCC_INDEX		1
+#define KGDB_PROFF_SCC		PROFF_SCC2
+#define KGDB_CMXSCR_MASK	(CMXSCR_GR2|CMXSCR_SC2|\
+					CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define KGDB_CMXSCR_VALUE	(CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define KGDB_CPM_CR_SCC_PAGE	CPM_CR_SCC2_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK	CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 3	/* KGDB Port on SCC3 */
+
+#define KGDB_SCC_INDEX		2
+#define KGDB_PROFF_SCC		PROFF_SCC3
+#define KGDB_CMXSCR_MASK	(CMXSCR_GR3|CMXSCR_SC3|\
+					CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define KGDB_CMXSCR_VALUE	(CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define KGDB_CPM_CR_SCC_PAGE	CPM_CR_SCC3_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK	CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 4	/* KGDB Port on SCC4 */
+
+#define KGDB_SCC_INDEX		3
+#define KGDB_PROFF_SCC		PROFF_SCC4
+#define KGDB_CMXSCR_MASK	(CMXSCR_GR4|CMXSCR_SC4|\
+					CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define KGDB_CMXSCR_VALUE	(CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define KGDB_CPM_CR_SCC_PAGE	CPM_CR_SCC4_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK	CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "kgdb serial port not correctly defined"
+
+#endif
+
+void
+kgdb_serial_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile scc_t *sp;
+	volatile scc_uart_t *up;
+	volatile cbd_t *tbdf, *rbdf;
+	volatile cpm8260_t *cp = &(im->im_cpm);
+	uint dpaddr, speed = CONFIG_KGDB_BAUDRATE;
+	char *s, *e;
+
+	if ((s = getenv("kgdbrate")) != NULL && *s != '\0') {
+		ulong rate = simple_strtoul(s, &e, 10);
+		if (e > s && *e == '\0')
+			speed = rate;
+	}
+
+	/* initialize pointers to SCC */
+
+	sp = (scc_t *) &(im->im_scc[KGDB_SCC_INDEX]);
+	up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+
+	/* Disable transmitter/receiver.
+	*/
+	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* put the SCC channel into NMSI (non multiplexd serial interface)
+	 * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+	 */
+	im->im_cpmux.cmx_scr = \
+		(im->im_cpmux.cmx_scr & ~KGDB_CMXSCR_MASK) | KGDB_CMXSCR_VALUE;
+
+	/* Set up the baud rate generator.
+	*/
+#if defined(CONFIG_KGDB_USE_EXTC)
+	m8260_cpm_extcbrg(KGDB_SCC_INDEX, speed,
+		CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
+#else
+	m8260_cpm_setbrg(KGDB_SCC_INDEX, speed);
+#endif
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+	rbdf->cbd_bufaddr = (uint) (rbdf+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+	tbdf->cbd_sc = BD_SC_WRAP;
+
+	/* Set up the uart parameters in the parameter ram.
+	*/
+	up->scc_genscc.scc_rbase = dpaddr;
+	up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+	up->scc_genscc.scc_rfcr = CPMFCR_EB;
+	up->scc_genscc.scc_tfcr = CPMFCR_EB;
+	up->scc_genscc.scc_mrblr = 1;
+	up->scc_maxidl = 0;
+	up->scc_brkcr = 1;
+	up->scc_parec = 0;
+	up->scc_frmec = 0;
+	up->scc_nosec = 0;
+	up->scc_brkec = 0;
+	up->scc_uaddr1 = 0;
+	up->scc_uaddr2 = 0;
+	up->scc_toseq = 0;
+	up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+	up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+	up->scc_rccm = 0xc0ff;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->scc_sccm = 0;
+	sp->scc_scce = 0xffff;
+
+	/* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+	*/
+	sp->scc_gsmrh = SCC_GSMRH_RFW;	/* 8 bit FIFO */
+	sp->scc_gsmrl = \
+		SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+	/* Set CTS flow control, 1 stop bit, 8 bit character length,
+	 * normal async UART mode, no parity
+	 */
+	sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL;
+
+	/* execute the "Init Rx and Tx params" CP command.
+	*/
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SCC_PAGE, KGDB_CPM_CR_SCC_SBLOCK,
+					0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver.
+	*/
+	sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+	printf("SCC%d at %dbps ", CONFIG_KGDB_INDEX, speed);
+}
+
+void
+putDebugChar(const char c)
+{
+	volatile scc_uart_t	*up;
+	volatile cbd_t		*tbdf;
+	volatile immap_t	*im;
+
+	if (c == '\n')
+		putDebugChar ('\r');
+
+	im = (immap_t *)CONFIG_SYS_IMMR;
+	up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+	tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase];
+
+	/* Wait for last character to go.
+	 */
+	while (tbdf->cbd_sc & BD_SC_READY)
+		;
+
+	/* Load the character into the transmit buffer.
+	 */
+	*(volatile char *)tbdf->cbd_bufaddr = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+putDebugStr (const char *s)
+{
+	while (*s) {
+		putDebugChar (*s++);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im;
+	unsigned char		c;
+
+	im = (immap_t *)CONFIG_SYS_IMMR;
+	up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+	rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+	/* Wait for character to show up.
+	 */
+	while (rbdf->cbd_sc & BD_SC_EMPTY)
+		;
+
+	/* Grab the char and clear the buffer again.
+	 */
+	c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return (c);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+	return;
+}
+
+#endif	/* CONFIG_KGDB_ON_SCC */
diff --git a/arch/ppc/cpu/mpc8260/serial_smc.c b/arch/ppc/cpu/mpc8260/serial_smc.c
new file mode 100644
index 0000000..fbb3fb0
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/serial_smc.c
@@ -0,0 +1,467 @@
+/*
+ * (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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
+ * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the
+ * Linux/PPC sources (m8260_tty.c had no copyright info in it).
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_ON_SMC)
+
+#if CONFIG_CONS_INDEX == 1	/* Console on SMC1 */
+
+#define SMC_INDEX		0
+#define PROFF_SMC_BASE		PROFF_SMC1_BASE
+#define PROFF_SMC		PROFF_SMC1
+#define CPM_CR_SMC_PAGE		CPM_CR_SMC1_PAGE
+#define CPM_CR_SMC_SBLOCK	CPM_CR_SMC1_SBLOCK
+#define CMXSMR_MASK		(CMXSMR_SMC1|CMXSMR_SMC1CS_MSK)
+#define CMXSMR_VALUE		CMXSMR_SMC1CS_BRG7
+
+#elif CONFIG_CONS_INDEX == 2	/* Console on SMC2 */
+
+#define SMC_INDEX		1
+#define PROFF_SMC_BASE		PROFF_SMC2_BASE
+#define PROFF_SMC		PROFF_SMC2
+#define CPM_CR_SMC_PAGE		CPM_CR_SMC2_PAGE
+#define CPM_CR_SMC_SBLOCK	CPM_CR_SMC2_SBLOCK
+#define CMXSMR_MASK		(CMXSMR_SMC2|CMXSMR_SMC2CS_MSK)
+#define CMXSMR_VALUE		CMXSMR_SMC2CS_BRG8
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+#if !defined(CONFIG_SYS_SMC_RXBUFLEN)
+#define CONFIG_SYS_SMC_RXBUFLEN	1
+#define CONFIG_SYS_MAXIDLE	0
+#else
+#if !defined(CONFIG_SYS_MAXIDLE)
+#error "you must define CONFIG_SYS_MAXIDLE"
+#endif
+#endif
+
+typedef volatile struct serialbuffer {
+	cbd_t	rxbd;		/* Rx BD */
+	cbd_t	txbd;		/* Tx BD */
+	uint	rxindex;	/* index for next character to read */
+	volatile uchar	rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
+	volatile uchar	txbuf;	/* tx buffers */
+} serialbuffer_t;
+
+/* map rs_table index to baud rate generator index */
+static unsigned char brg_map[] = {
+	6,	/* BRG7 for SMC1 */
+	7,	/* BRG8 for SMC2 */
+	0,	/* BRG1 for SCC1 */
+	1,	/* BRG1 for SCC2 */
+	2,	/* BRG1 for SCC3 */
+	3,	/* BRG1 for SCC4 */
+};
+
+int serial_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile smc_t *sp;
+	volatile smc_uart_t *up;
+	volatile cpm8260_t *cp = &(im->im_cpm);
+	uint	dpaddr;
+	volatile serialbuffer_t *rtx;
+
+	/* initialize pointers to SMC */
+
+	sp = (smc_t *) &(im->im_smc[SMC_INDEX]);
+	*(ushort *)(&im->im_dprambase[PROFF_SMC_BASE]) = PROFF_SMC;
+	up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC];
+
+	/* Disable transmitter/receiver. */
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+	/* NOTE: I/O port pins are set up via the iop_conf_tab[] table */
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	/* allocate size of struct serialbuffer with bd rx/tx,
+	 * buffer rx/tx and rx index
+	 */
+	dpaddr = m8260_cpm_dpalloc((sizeof(serialbuffer_t)), 16);
+
+	rtx = (serialbuffer_t *)&im->im_dprambase[dpaddr];
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
+	rtx->rxbd.cbd_sc      = 0;
+
+	rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
+	rtx->txbd.cbd_sc      = 0;
+
+	/* Set up the uart parameters in the parameter ram. */
+	up->smc_rbase = dpaddr;
+	up->smc_tbase = dpaddr+sizeof(cbd_t);
+	up->smc_rfcr = CPMFCR_EB;
+	up->smc_tfcr = CPMFCR_EB;
+	up->smc_brklen = 0;
+	up->smc_brkec = 0;
+	up->smc_brkcr = 0;
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Mask all interrupts and remove anything pending. */
+	sp->smc_smcm = 0;
+	sp->smc_smce = 0xff;
+
+	/* put the SMC channel into NMSI (non multiplexd serial interface)
+	 * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17).
+	 */
+	im->im_cpmux.cmx_smr = (im->im_cpmux.cmx_smr&~CMXSMR_MASK)|CMXSMR_VALUE;
+
+	/* Set up the baud rate generator. */
+	serial_setbrg ();
+
+	/* Make the first buffer the only buffer. */
+	rtx->txbd.cbd_sc |= BD_SC_WRAP;
+	rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* single/multi character receive. */
+	up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN;
+	up->smc_maxidl = CONFIG_SYS_MAXIDLE;
+	rtx->rxindex = 0;
+
+	/* Initialize Tx/Rx parameters. */
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC_PAGE, CPM_CR_SMC_SBLOCK,
+					0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver. */
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+	return (0);
+}
+
+void
+serial_setbrg (void)
+{
+#if defined(CONFIG_CONS_USE_EXTC)
+	m8260_cpm_extcbrg(brg_map[SMC_INDEX], gd->baudrate,
+		CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+	m8260_cpm_setbrg(brg_map[SMC_INDEX], gd->baudrate);
+#endif
+}
+
+void
+serial_putc(const char c)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile serialbuffer_t	*rtx;
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+	rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
+
+	/* Wait for last character to go. */
+	while (rtx->txbd.cbd_sc & BD_SC_READY & BD_SC_READY)
+		;
+	rtx->txbuf = c;
+	rtx->txbd.cbd_datlen = 1;
+	rtx->txbd.cbd_sc |= BD_SC_READY;
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int
+serial_getc(void)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile serialbuffer_t	*rtx;
+	unsigned char  c;
+
+	up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+	rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
+
+	/* Wait for character to show up. */
+	while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
+		;
+
+	/* the characters are read one by one,
+	 * use the rxindex to know the next char to deliver
+	 */
+	c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr + rtx->rxindex);
+	rtx->rxindex++;
+
+	/* check if all char are readout, then make prepare for next receive */
+	if (rtx->rxindex >= rtx->rxbd.cbd_datlen) {
+		rtx->rxindex = 0;
+		rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+	}
+	return(c);
+}
+
+int
+serial_tstc()
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile serialbuffer_t	*rtx;
+
+	up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+	rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
+
+	return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
+}
+
+#endif	/* CONFIG_CONS_ON_SMC */
+
+#if defined(CONFIG_KGDB_ON_SMC)
+
+#if defined(CONFIG_CONS_ON_SMC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Whoops! serial console and kgdb are on the same smc serial port
+#endif
+
+#if CONFIG_KGDB_INDEX == 1	/* KGDB Port on SMC1 */
+
+#define KGDB_SMC_INDEX		0
+#define KGDB_PROFF_SMC_BASE	PROFF_SMC1_BASE
+#define KGDB_PROFF_SMC		PROFF_SMC1
+#define KGDB_CPM_CR_SMC_PAGE	CPM_CR_SMC1_PAGE
+#define KGDB_CPM_CR_SMC_SBLOCK	CPM_CR_SMC1_SBLOCK
+#define KGDB_CMXSMR_MASK	(CMXSMR_SMC1|CMXSMR_SMC1CS_MSK)
+#define KGDB_CMXSMR_VALUE	CMXSMR_SMC1CS_BRG7
+
+#elif CONFIG_KGDB_INDEX == 2	/* KGDB Port on SMC2 */
+
+#define KGDB_SMC_INDEX		1
+#define KGDB_PROFF_SMC_BASE	PROFF_SMC2_BASE
+#define KGDB_PROFF_SMC		PROFF_SMC2
+#define KGDB_CPM_CR_SMC_PAGE	CPM_CR_SMC2_PAGE
+#define KGDB_CPM_CR_SMC_SBLOCK	CPM_CR_SMC2_SBLOCK
+#define KGDB_CMXSMR_MASK	(CMXSMR_SMC2|CMXSMR_SMC2CS_MSK)
+#define KGDB_CMXSMR_VALUE	CMXSMR_SMC2CS_BRG8
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+void
+kgdb_serial_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile smc_t *sp;
+	volatile smc_uart_t *up;
+	volatile cbd_t *tbdf, *rbdf;
+	volatile cpm8260_t *cp = &(im->im_cpm);
+	uint dpaddr, speed = CONFIG_KGDB_BAUDRATE;
+	char *s, *e;
+
+	if ((s = getenv("kgdbrate")) != NULL && *s != '\0') {
+		ulong rate = simple_strtoul(s, &e, 10);
+		if (e > s && *e == '\0')
+			speed = rate;
+	}
+
+	/* initialize pointers to SMC */
+
+	sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]);
+	*(ushort *)(&im->im_dprambase[KGDB_PROFF_SMC_BASE]) = KGDB_PROFF_SMC;
+	up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC];
+
+	/* Disable transmitter/receiver. */
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+	/* NOTE: I/O port pins are set up via the iop_conf_tab[] table */
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+	rbdf->cbd_bufaddr = (uint) (rbdf+2);
+	rbdf->cbd_sc = 0;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+	tbdf->cbd_sc = 0;
+
+	/* Set up the uart parameters in the parameter ram. */
+	up->smc_rbase = dpaddr;
+	up->smc_tbase = dpaddr+sizeof(cbd_t);
+	up->smc_rfcr = CPMFCR_EB;
+	up->smc_tfcr = CPMFCR_EB;
+	up->smc_brklen = 0;
+	up->smc_brkec = 0;
+	up->smc_brkcr = 0;
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Mask all interrupts and remove anything pending. */
+	sp->smc_smcm = 0;
+	sp->smc_smce = 0xff;
+
+	/* put the SMC channel into NMSI (non multiplexd serial interface)
+	 * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17).
+	 */
+	im->im_cpmux.cmx_smr =
+		(im->im_cpmux.cmx_smr & ~KGDB_CMXSMR_MASK) | KGDB_CMXSMR_VALUE;
+
+	/* Set up the baud rate generator. */
+#if defined(CONFIG_KGDB_USE_EXTC)
+	m8260_cpm_extcbrg(brg_map[KGDB_SMC_INDEX], speed,
+		CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
+#else
+	m8260_cpm_setbrg(brg_map[KGDB_SMC_INDEX], speed);
+#endif
+
+	/* Make the first buffer the only buffer. */
+	tbdf->cbd_sc |= BD_SC_WRAP;
+	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* Single character receive. */
+	up->smc_mrblr = 1;
+	up->smc_maxidl = 0;
+
+	/* Initialize Tx/Rx parameters. */
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SMC_PAGE, KGDB_CPM_CR_SMC_SBLOCK,
+					0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver.	*/
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+	printf("SMC%d at %dbps ", CONFIG_KGDB_INDEX, speed);
+}
+
+void
+putDebugChar(const char c)
+{
+	volatile cbd_t		*tbdf;
+	volatile char		*buf;
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+
+	if (c == '\n')
+		putDebugChar ('\r');
+
+	up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]);
+
+	tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase];
+
+	/* Wait for last character to go. */
+	buf = (char *)tbdf->cbd_bufaddr;
+	while (tbdf->cbd_sc & BD_SC_READY)
+		;
+
+	*buf = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+putDebugStr (const char *s)
+{
+	while (*s) {
+		putDebugChar (*s++);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile unsigned char	*buf;
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	unsigned char		c;
+
+	up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]);
+
+	rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase];
+
+	/* Wait for character to show up. */
+	buf = (unsigned char *)rbdf->cbd_bufaddr;
+	while (rbdf->cbd_sc & BD_SC_EMPTY)
+		;
+	c = *buf;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return(c);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+	return;
+}
+
+#endif	/* CONFIG_KGDB_ON_SMC */
diff --git a/arch/ppc/cpu/mpc8260/speed.c b/arch/ppc/cpu/mpc8260/speed.c
new file mode 100644
index 0000000..0e1c2b0
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/speed.c
@@ -0,0 +1,253 @@
+/*
+ * (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/processor.h>
+
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+extern unsigned long board_get_cpu_clk_f (void);
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+
+/* Bus-to-Core Multiplier */
+#define _1x	2
+#define _1_5x	3
+#define _2x	4
+#define _2_5x	5
+#define _3x	6
+#define _3_5x	7
+#define _4x	8
+#define _4_5x	9
+#define _5x	10
+#define _5_5x	11
+#define _6x	12
+#define _6_5x	13
+#define _7x	14
+#define _7_5x	15
+#define _8x	16
+#define _byp	-1
+#define _off	-2
+#define _unk	-3
+
+typedef struct {
+	int b2c_mult;
+	int vco_div;
+	char *freq_60x;
+	char *freq_core;
+} corecnf_t;
+
+/*
+ * this table based on "Errata to MPC8260 PowerQUICC II User's Manual",
+ * Rev. 1, 8/2000, page 10.
+ */
+corecnf_t corecnf_tab[] = {
+	{ _1_5x,  4, " 33-100", " 33-100" },	/* 0x00 */
+	{   _1x,  4, " 50-150", " 50-150" },	/* 0x01 */
+	{   _1x,  8, " 25-75 ", " 25-75 " },	/* 0x02 */
+	{  _byp, -1, "  ?-?  ", "  ?-?  " },	/* 0x03 */
+	{   _2x,  2, " 50-150", "100-300" },	/* 0x04 */
+	{   _2x,  4, " 25-75 ", " 50-150" },	/* 0x05 */
+	{ _2_5x,  2, " 40-120", "100-240" },	/* 0x06 */
+	{ _4_5x,  2, " 22-65 ", "100-300" },	/* 0x07 */
+	{   _3x,  2, " 33-100", "100-300" },	/* 0x08 */
+	{ _5_5x,  2, " 18-55 ", "100-300" },	/* 0x09 */
+	{   _4x,  2, " 25-75 ", "100-300" },	/* 0x0A */
+	{   _5x,  2, " 20-60 ", "100-300" },	/* 0x0B */
+	{ _1_5x,  8, " 16-50 ", " 16-50 " },	/* 0x0C */
+	{   _6x,  2, " 16-50 ", "100-300" },	/* 0x0D */
+	{ _3_5x,  2, " 30-85 ", "100-300" },	/* 0x0E */
+	{  _off, -1, "  ?-?  ", "  ?-?  " },	/* 0x0F */
+	{   _3x,  4, " 16-50 ", " 50-150" },	/* 0x10 */
+	{ _2_5x,  4, " 20-60 ", " 50-120" },	/* 0x11 */
+	{ _6_5x,  2, " 15-46 ", "100-300" },	/* 0x12 */
+	{  _byp, -1, "  ?-?  ", "  ?-?  " },	/* 0x13 */
+	{   _7x,  2, " 14-43 ", "100-300" },	/* 0x14 */
+	{   _2x,  4, " 25-75 ", " 50-150" },	/* 0x15 */
+	{ _7_5x,  2, " 13-40 ", "100-300" },	/* 0x16 */
+	{ _4_5x,  2, " 22-65 ", "100-300" },	/* 0x17 */
+	{  _unk, -1, "  ?-?  ", "  ?-?  " },	/* 0x18 */
+	{ _5_5x,  2, " 18-55 ", "100-300" },	/* 0x19 */
+	{   _4x,  2, " 25-75 ", "100-300" },	/* 0x1A */
+	{   _5x,  2, " 20-60 ", "100-300" },	/* 0x1B */
+	{   _8x,  2, " 12-38 ", "100-300" },	/* 0x1C */
+	{   _6x,  2, " 16-50 ", "100-300" },	/* 0x1D */
+	{ _3_5x,  2, " 30-85 ", "100-300" },	/* 0x1E */
+	{  _off, -1, "  ?-?  ", "  ?-?  " },	/* 0x1F */
+};
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	ulong clkin;
+	ulong sccr, dfbrg;
+	ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf;
+	corecnf_t *cp;
+
+#if !defined(CONFIG_8260_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_8260_CLKIN
+#else
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+	clkin = board_get_cpu_clk_f ();
+#else
+	clkin = CONFIG_8260_CLKIN;
+#endif
+#endif
+
+	sccr = immap->im_clkrst.car_sccr;
+	dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+	scmr = immap->im_clkrst.car_scmr;
+	corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+	cp = &corecnf_tab[corecnf];
+
+	busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT;
+	cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT;
+
+	/* HiP7, HiP7 Rev01, HiP7 RevA */
+	if ((get_pvr () == PVR_8260_HIP7) ||
+	    (get_pvr () == PVR_8260_HIP7R1) ||
+	    (get_pvr () == PVR_8260_HIP7RA)) {
+		pllmf = (scmr & SCMR_PLLMF_MSKH7) >> SCMR_PLLMF_SHIFT;
+		gd->vco_out = clkin * (pllmf + 1);
+	} else {                        /* HiP3, HiP4 */
+		pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+		plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+		gd->vco_out = (clkin * 2 * (pllmf + 1)) / (plldf + 1);
+	}
+#if 0
+	if (gd->vco_out / (busdf + 1) != clkin) {
+		/* aaarrrggghhh!!! */
+		return (1);
+	}
+#endif
+
+	gd->cpm_clk = gd->vco_out / 2;
+	gd->bus_clk = clkin;
+	gd->scc_clk = gd->vco_out / 4;
+	gd->brg_clk = gd->vco_out / (1 << (2 * (dfbrg + 1)));
+
+	if (cp->b2c_mult > 0) {
+		gd->cpu_clk = (clkin * cp->b2c_mult) / 2;
+	} else {
+		gd->cpu_clk = clkin;
+	}
+
+#ifdef CONFIG_PCI
+	gd->pci_clk = clkin;
+
+	if (sccr & SCCR_PCI_MODE) {
+		uint pci_div;
+		uint pcidf = (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT;
+
+		if (sccr & SCCR_PCI_MODCK) {
+			pci_div = 2;
+			if (pcidf == 9) {
+				pci_div *= 5;
+			} else if (pcidf == 0xB) {
+				pci_div *= 6;
+			} else {
+				pci_div *= (pcidf + 1);
+			}
+		} else {
+			pci_div = pcidf + 1;
+		}
+
+		gd->pci_clk = (gd->cpm_clk * 2) / pci_div;
+	}
+#endif
+
+	return (0);
+}
+
+int prt_8260_clks (void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	ulong sccr, dfbrg;
+	ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf, pcidf;
+	corecnf_t *cp;
+
+	sccr = immap->im_clkrst.car_sccr;
+	dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+	scmr = immap->im_clkrst.car_scmr;
+	corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+	busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT;
+	cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT;
+	plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+	pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+	pcidf = (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT;
+
+	cp = &corecnf_tab[corecnf];
+
+	puts (CPU_ID_STR " Clock Configuration\n - Bus-to-Core Mult ");
+
+	switch (cp->b2c_mult) {
+	case _byp:
+		puts ("BYPASS");
+		break;
+
+	case _off:
+		puts ("OFF");
+		break;
+
+	case _unk:
+		puts ("UNKNOWN");
+		break;
+
+	default:
+		printf ("%d%sx",
+			cp->b2c_mult / 2,
+			(cp->b2c_mult % 2) ? ".5" : "");
+		break;
+	}
+
+	printf (", VCO Div %d, 60x Bus Freq %s, Core Freq %s\n",
+			cp->vco_div, cp->freq_60x, cp->freq_core);
+
+	printf (" - dfbrg %ld, corecnf 0x%02lx, busdf %ld, cpmdf %ld, "
+		"plldf %ld, pllmf %ld, pcidf %ld\n",
+			dfbrg, corecnf, busdf, cpmdf,
+			plldf, pllmf, pcidf);
+
+	printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n",
+			gd->vco_out, gd->scc_clk, gd->brg_clk);
+
+	printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n",
+			gd->cpu_clk, gd->cpm_clk, gd->bus_clk);
+#ifdef CONFIG_PCI
+	printf (" - pci_clk %10ld\n", gd->pci_clk);
+#endif
+	putc ('\n');
+
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc8260/speed.h b/arch/ppc/cpu/mpc8260/speed.h
new file mode 100644
index 0000000..3f32a14
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/speed.h
@@ -0,0 +1,54 @@
+/*
+ * (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
+ */
+
+/*-----------------------------------------------------------------------
+ * Timer value for timer 2, ICLK = 10
+ *
+ * SPEED_FCOUNT2 =  GCLK / (16 * (TIMER_TMR_PS + 1))
+ * SPEED_TMR3_PS = (GCLK / (16 * SPEED_FCOUNT3)) - 1
+ *
+ * SPEED_FCOUNT2	timer 2 counting frequency
+ * GCLK			CPU clock
+ * SPEED_TMR2_PS	prescaler
+ */
+#define SPEED_TMR2_PS	(250 - 1)	/* divide by 250	*/
+
+/*-----------------------------------------------------------------------
+ * Timer value for PIT
+ *
+ * PIT_TIME = SPEED_PITC / PITRTCLK
+ * PITRTCLK = 8192
+ */
+#define SPEED_PITC	(82 << 16)	/* start counting from 82	*/
+
+/*
+ * The new value for PTA is calculated from
+ *
+ *	PTA = (gclk * Trefresh) / (2 ^ (2 * DFBRG) * PTP * NCS)
+ *
+ * gclk		CPU clock (not bus clock !)
+ * Trefresh	Refresh cycle * 4 (four word bursts used)
+ * DFBRG	For normal mode (no clock reduction) always 0
+ * PTP		Prescaler (already adjusted for no. of banks and 4K / 8K refresh)
+ * NCS		Number of SDRAM banks (chip selects) on this UPM.
+ */
diff --git a/arch/ppc/cpu/mpc8260/spi.c b/arch/ppc/cpu/mpc8260/spi.c
new file mode 100644
index 0000000..f5d2ac3
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/spi.c
@@ -0,0 +1,435 @@
+/*
+ * 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-2003 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
+ */
+
+/*
+ * MPC8260 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 <asm/cpm_8260.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <net.h>
+
+#if defined(CONFIG_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 0x2000 makes it far enough from the start of the data
+ * area (as well as from the stack pointer).
+ * --------------------------------------------------------------- */
+#ifndef	CONFIG_SYS_SPI_INIT_OFFSET
+#define	CONFIG_SYS_SPI_INIT_OFFSET	0x2000
+#endif
+
+#define CPM_SPI_BASE 0x100
+
+#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 *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
+			[CONFIG_SYS_SPI_INIT_OFFSET];
+static uchar *txbuf =
+  (uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
+			[CONFIG_SYS_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 cpm8260_t *cp;
+	volatile cbd_t *tbdf, *rbdf;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	cp   = (cpm8260_t *) &immr->im_cpm;
+
+	*(ushort *)(&immr->im_dprambase[PROFF_SPI_BASE]) = PROFF_SPI;
+	spi  = (spi_t *)&immr->im_dprambase[PROFF_SPI];
+
+/* 1 */
+	/* ------------------------------------------------
+	 * Initialize Port D SPI pins
+	 * (we are only in Master Mode !)
+	 * ------------------------------------------------ */
+
+	/* --------------------------------------------
+	 * GPIO or per. Function
+	 * PPARD[16] = 1 [0x00008000] (SPIMISO)
+	 * PPARD[17] = 1 [0x00004000] (SPIMOSI)
+	 * PPARD[18] = 1 [0x00002000] (SPICLK)
+	 * PPARD[12] = 0 [0x00080000] -> GPIO: (CS for ATC EEPROM)
+	 * -------------------------------------------- */
+	immr->im_ioport.iop_ppard |=  0x0000E000;	/* set  bits	*/
+	immr->im_ioport.iop_ppard &= ~0x00080000;	/* reset bit	*/
+
+	/* ----------------------------------------------
+	 * In/Out or per. Function 0/1
+	 * PDIRD[16] = 0 [0x00008000] -> PERI1: SPIMISO
+	 * PDIRD[17] = 0 [0x00004000] -> PERI1: SPIMOSI
+	 * PDIRD[18] = 0 [0x00002000] -> PERI1: SPICLK
+	 * PDIRD[12] = 1 [0x00080000] -> GPIO OUT: CS for ATC EEPROM
+	 * ---------------------------------------------- */
+	immr->im_ioport.iop_pdird &= ~0x0000E000;
+	immr->im_ioport.iop_pdird |= 0x00080000;
+
+	/* ----------------------------------------------
+	 * special option reg.
+	 * PSORD[16] = 1 [0x00008000] -> SPIMISO
+	 * PSORD[17] = 1 [0x00004000] -> SPIMOSI
+	 * PSORD[18] = 1 [0x00002000] -> SPICLK
+	 * ---------------------------------------------- */
+	immr->im_ioport.iop_psord |= 0x0000E000;
+
+	/* 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 CONFIG_SYS_ALLOC_DPRAM
+	dpaddr = m8260_cpm_dpalloc (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 */
+	/* Init SPI Tx + Rx Parameters */
+	while (cp->cp_cpcr & CPM_CR_FLG)
+		;
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK,
+							0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG)
+		;
+
+/* 6 */
+	/* Set to big endian. */
+	spi->spi_tfcr = CPMFCR_EB;
+	spi->spi_rfcr = CPMFCR_EB;
+
+/* 7 */
+	/* Set maximum receive size. */
+	spi->spi_mrblr = MAX_BUFFER;
+
+/* 8 + 9 */
+	/* tx and rx buffer descriptors */
+	tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
+	rbdf = (cbd_t *) & immr->im_dprambase[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 */
+	immr->im_spi.spi_spie = SPI_EMASK;		/* Clear all SPI events	*/
+	immr->im_spi.spi_spim = 0x00;			/* Mask  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 spi_t *spi;
+	volatile immap_t *immr;
+	volatile cpm8260_t *cp;
+	volatile cbd_t *tbdf, *rbdf;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	cp   = (cpm8260_t *) &immr->im_cpm;
+
+	spi  = (spi_t *)&immr->im_dprambase[PROFF_SPI];
+
+	/* tx and rx buffer descriptors */
+	tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
+	rbdf = (cbd_t *) & immr->im_dprambase[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 cpm8260_t *cp;
+	volatile spi_t *spi;
+	cbd_t *tbdf, *rbdf;
+	int tm;
+
+	DPRINT (("*** spi_xfer entered ***\n"));
+
+	immr = (immap_t *) CONFIG_SYS_IMMR;
+	cp   = (cpm8260_t *) &immr->im_cpm;
+
+	spi  = (spi_t *)&immr->im_dprambase[PROFF_SPI];
+
+	tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
+	rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
+
+	/* Board-specific: Set CS for device (ATC EEPROM) */
+	immr->im_ioport.iop_pdatd &= ~0x00080000;
+
+	/* 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 */
+
+	immr->im_spi.spi_spmode = SPMODE_REV	|
+			SPMODE_MSTR	|
+			SPMODE_EN	|
+			SPMODE_LEN(8)	|	/* 8 Bits per char */
+			SPMODE_PM(0x8) ;	/* medium speed */
+	immr->im_spi.spi_spie = SPI_EMASK;		/* Clear all SPI events	*/
+	immr->im_spi.spi_spim = 0x00;			/* Mask  all SPI events */
+
+	/* start spi transfer */
+	DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+	immr->im_spi.spi_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 (immr->im_spi.spi_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 */
+	immr->im_ioport.iop_pdatd |= 0x00080000;
+
+	return count;
+}
+#endif	/* CONFIG_SPI */
diff --git a/arch/ppc/cpu/mpc8260/start.S b/arch/ppc/cpu/mpc8260/start.S
new file mode 100644
index 0000000..1fc70bc
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/start.S
@@ -0,0 +1,1023 @@
+/*
+ *  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 MPC8260 PowerPC based Embedded Boards
+ */
+#include <config.h>
+#include <mpc8260.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_8260 1		/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+#if defined(CONFIG_HYMOD)
+	GOT_ENTRY(environment)
+#endif
+	END_GOT
+
+/*
+ * Version string - must be in data segment because MPC8260 uses the first
+ * 256 bytes for the Hard Reset Configuration Word table (see below).
+ * Similarly, can't have the U-Boot Magic Number as the first thing in
+ * the image - don't know how this will affect the image tools, but I guess
+ * I'll find out soon
+ */
+	.data
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+/*
+ *  Hard Reset Configuration Word (HRCW) table
+ *
+ *  The Hard Reset Configuration Word (HRCW) sets a number of useful things
+ *  such as whether there is an external memory controller, whether the
+ *  PowerPC core is disabled (i.e. only the communications processor is
+ *  active, accessed by another CPU on the bus), whether using external
+ *  arbitration, external bus mode, boot port size, core initial prefix,
+ *  internal space base, boot memory space, etc.
+ *
+ *  These things dictate where the processor begins execution, where the
+ *  boot ROM appears in memory, the memory controller setup when access
+ *  boot ROM, etc. The HRCW is *extremely* important.
+ *
+ *  The HRCW is read from the bus during reset. One CPU on the bus will
+ *  be a hard reset configuration master, any others will be hard reset
+ *  configuration slaves. The master reads eight HRCWs from flash during
+ *  reset - the first it uses for itself, the other 7 it communicates to
+ *  up to 7 configuration slaves by some complicated mechanism, which is
+ *  not really important here.
+ *
+ *  The configuration master performs 32 successive reads starting at address
+ *  0 and incrementing by 8 each read (i.e. on 64 bit boundaries) but only 8
+ *  bits is read, and always from byte lane D[0-7] (so that port size of the
+ *  boot device does not matter). The first four reads form the 32 bit HRCW
+ *  for the master itself. The second four reads form the HRCW for the first
+ *  slave, and so on, up to seven slaves. The 32 bit HRCW is formed by
+ *  concatenating the four bytes, with the first read placed in byte 0 (the
+ *  most significant byte), and so on with the fourth read placed in byte 3
+ *  (the least significant byte).
+ */
+#define _HRCW_TABLE_ENTRY(w)		\
+	.fill	8,1,(((w)>>24)&0xff);	\
+	.fill	8,1,(((w)>>16)&0xff);	\
+	.fill	8,1,(((w)>> 8)&0xff);	\
+	.fill	8,1,(((w)    )&0xff)
+	.text
+	.globl	_hrcw_table
+_hrcw_table:
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_MASTER)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE1)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE2)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE3)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE4)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE5)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE6)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE7)
+/*
+ *  After configuration, a system reset exception is executed using the
+ *  vector at offset 0x100 relative to the base set by MSR[IP]. If MSR[IP]
+ *  is 0, the base address is 0x00000000. If MSR[IP] is 1, the base address
+ *  is 0xfff00000. In the case of a Power On Reset or Hard Reset, the value
+ *  of MSR[IP] is determined by the CIP field in the HRCW.
+ *
+ *  Other bits in the HRCW set up the Base Address and Port Size in BR0.
+ *  This determines the location of the boot ROM (flash or EPROM) in the
+ *  processor's address space at boot time. As long as the HRCW is set up
+ *  so that we eventually end up executing the code below when the processor
+ *  executes the reset exception, the actual values used should not matter.
+ *
+ *  Once we have got here, the address mask in OR0 is cleared so that the
+ *  bottom 32K of the boot ROM is effectively repeated all throughout the
+ *  processor's address space, after which we can jump to the absolute
+ *  address at which the boot ROM was linked at compile time, and proceed
+ *  to initialise the memory controller without worrying if the rug will be
+ *  pulled out from under us, so to speak (it will be fine as long as we
+ *  configure BR0 with the same boot ROM link address).
+ */
+	. = EXC_OFF_SYS_RESET
+
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH*/
+	nop
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM	/* Software reboot		*/
+	b	boot_warm
+
+boot_cold:
+#if defined(CONFIG_MPC8260ADS) && defined(CONFIG_SYS_DEFAULT_IMMR)
+	lis	r3, CONFIG_SYS_DEFAULT_IMMR@h
+	nop
+	lwz	r4, 0(r3)
+	nop
+	rlwinm	r4, r4, 0, 8, 5
+	nop
+	oris	r4, r4, 0x0200
+	nop
+	stw	r4, 0(r3)
+	nop
+#endif /* CONFIG_MPC8260ADS && CONFIG_SYS_DEFAULT_IMMR */
+boot_warm:
+	mfmsr	r5			/* save msr contents		*/
+
+#if defined(CONFIG_COGENT)
+	/* this is what the cogent EPROM does */
+	li	r0, 0
+	mtmsr	r0
+	isync
+	bl	cogent_init_8260
+#endif	/* CONFIG_COGENT */
+
+#if defined(CONFIG_SYS_DEFAULT_IMMR)
+	lis	r3, CONFIG_SYS_IMMR@h
+	ori	r3, r3, CONFIG_SYS_IMMR@l
+	lis	r4, CONFIG_SYS_DEFAULT_IMMR@h
+	stw	r3, 0x1A8(r4)
+#endif /* CONFIG_SYS_DEFAULT_IMMR */
+
+	/* Initialise the MPC8260 processor core			*/
+	/*--------------------------------------------------------------*/
+
+	bl	init_8260_core
+
+#ifndef CONFIG_SYS_RAMBOOT
+	/* When booting from ROM (Flash or EPROM), clear the		*/
+	/* Address Mask in OR0 so ROM appears everywhere		*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+	lwz	r4, IM_OR0@l(r3)
+	li	r5, 0x7fff
+	and	r4, r4, r5
+	stw	r4, IM_OR0@l(r3)
+
+	/* Calculate absolute address in FLASH and jump there		*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_MONITOR_BASE@h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE@l
+	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r3
+	blr
+
+in_flash:
+#endif	/* CONFIG_SYS_RAMBOOT */
+
+	/* initialize some things that are hard to access from C	*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_IMMR@h		/* set up stack in internal DPRAM */
+	ori	r1, r3, CONFIG_SYS_INIT_SP_OFFSET
+	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 (in Flash)*/
+
+#ifdef DEBUG
+	bl	init_debug	/* set up debugging stuff		*/
+#endif
+
+	mr	r3, r21
+	/* r3: BOOTFLAG */
+	bl	board_init_f	/* run 1st part of board init code (in Flash)*/
+
+/*
+ * Vector Table
+ */
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+	. = 0x1300
+	/*
+	 * This exception occurs when the program counter matches the
+	 * Instruction Address Breakpoint Register (IABR).
+	 *
+	 * I want the cpu to halt if this occurs so I can hunt around
+	 * with the debugger and look at things.
+	 *
+	 * When DEBUG is defined, both machine check enable (in the MSR)
+	 * and checkstop reset enable (in the reset mode register) are
+	 * turned off and so a checkstop condition will result in the cpu
+	 * halting.
+	 *
+	 * I force the cpu into a checkstop condition by putting an illegal
+	 * instruction here (at least this is the theory).
+	 *
+	 * well - that didnt work, so just do an infinite loop!
+	 */
+1:	b	1b
+#else
+	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+	STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+	STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+#if defined(CONFIG_COGENT)
+
+/*
+ * This code initialises the MPC8260 processor core
+ * (conforms to PowerPC 603e spec)
+ */
+
+	.globl	cogent_init_8260
+cogent_init_8260:
+
+	/* Taken from page 14 of CMA282 manual				*/
+	/*--------------------------------------------------------------*/
+
+	lis	r4, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+	lis	r3, CONFIG_SYS_IMMR@h
+	stw	r3, IM_IMMR@l(r4)
+	lwz	r3, IM_IMMR@l(r4)
+	stw	r3, 0(r0)
+	lis	r3, CONFIG_SYS_SYPCR@h
+	ori	r3, r3, CONFIG_SYS_SYPCR@l
+	stw	r3, IM_SYPCR@l(r4)
+	lwz	r3, IM_SYPCR@l(r4)
+	stw	r3, 4(r0)
+	lis	r3, CONFIG_SYS_SCCR@h
+	ori	r3, r3, CONFIG_SYS_SCCR@l
+	stw	r3, IM_SCCR@l(r4)
+	lwz	r3, IM_SCCR@l(r4)
+	stw	r3, 8(r0)
+
+	/* the rest of this was disassembled from the			*/
+	/* EPROM code that came with my CMA282 CPU module		*/
+	/*--------------------------------------------------------------*/
+
+	lis	r1, 0x1234
+	ori	r1, r1, 0x5678
+	stw	r1, 0x20(r0)
+	lwz	r1, 0x20(r0)
+	stw	r1, 0x24(r0)
+	lwz	r1, 0x24(r0)
+	lis	r3, 0x0e80
+	ori	r3, r3, 0
+	stw	r1, 4(r3)
+	lwz	r1, 4(r3)
+
+	/* Done!							*/
+	/*--------------------------------------------------------------*/
+
+	blr
+
+#endif	/* CONFIG_COGENT */
+
+/*
+ * This code initialises the MPC8260 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+	.globl	init_8260_core
+init_8260_core:
+
+	/* Initialize machine status; enable machine check interrupt	*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, MSR_KERNEL		/* Set ME and RI flags */
+	rlwimi	r3, r5, 0, 25, 25	/* preserve IP bit set by HRCW */
+#ifdef DEBUG
+	rlwimi	r3, r5, 0, 21, 22	/* debugger might set SE & BE bits */
+#endif
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+	mtspr	SRR1, r3		/* Make SRR1 match MSR */
+
+	/* Initialise the SYPCR early, and reset the watchdog (if req)	*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+#if !defined(CONFIG_COGENT)
+	lis	r4, CONFIG_SYS_SYPCR@h
+	ori	r4, r4, CONFIG_SYS_SYPCR@l
+	stw	r4, IM_SYPCR@l(r3)
+#endif /* !CONFIG_COGENT */
+#if defined(CONFIG_WATCHDOG)
+	li	r4, 21868		/* = 0x556c */
+	sth	r4, IM_SWSR@l(r3)
+	li	r4, -21959		/* = 0xaa39 */
+	sth	r4, IM_SWSR@l(r3)
+#endif /* CONFIG_WATCHDOG */
+
+	/* Initialize the Hardware Implementation-dependent Registers	*/
+	/* HID0 also contains cache control				*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_HID0_INIT@h
+	ori	r3, r3, CONFIG_SYS_HID0_INIT@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID0_FINAL@h
+	ori	r3, r3, CONFIG_SYS_HID0_FINAL@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID2@h
+	ori	r3, r3, CONFIG_SYS_HID2@l
+	mtspr	HID2, r3
+
+	/* clear all BAT's						*/
+	/*--------------------------------------------------------------*/
+
+	li	r0, 0
+	mtspr	DBAT0U, r0
+	mtspr	DBAT0L, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT1L, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT2L, r0
+	mtspr	DBAT3U, r0
+	mtspr	DBAT3L, r0
+	mtspr	IBAT0U, r0
+	mtspr	IBAT0L, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT1L, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT2L, r0
+	mtspr	IBAT3U, r0
+	mtspr	IBAT3L, r0
+	SYNC
+
+	/* invalidate all tlb's						*/
+	/*								*/
+	/* From the 603e User Manual: "The 603e provides the ability to	*/
+	/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)	*/
+	/* instruction invalidates the TLB entry indexed by the EA, and	*/
+	/* operates on both the instruction and data TLBs simultaneously*/
+	/* invalidating four TLB entries (both sets in each TLB). The	*/
+	/* index corresponds to bits 15-19 of the EA. To invalidate all	*/
+	/* entries within both TLBs, 32 tlbie instructions should be	*/
+	/* issued, incrementing this field by one each time."		*/
+	/*								*/
+	/* "Note that the tlbia instruction is not implemented on the	*/
+	/* 603e."							*/
+	/*								*/
+	/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000	*/
+	/* incrementing by 0x1000 each time. The code below is sort of	*/
+	/* based on code in "flush_tlbs" from arch/ppc/kernel/head.S	*/
+	/*								*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, 32
+	mtctr	r3
+	li	r3, 0
+1:	tlbie	r3
+	addi	r3, r3, 0x1000
+	bdnz	1b
+	SYNC
+
+	/* Done!							*/
+	/*--------------------------------------------------------------*/
+
+	blr
+
+#ifdef DEBUG
+
+/*
+ * initialise things related to debugging.
+ *
+ * must be called after the global offset table (GOT) is initialised
+ * (GET_GOT) and after cpu_init_f() has executed.
+ */
+
+	.globl	init_debug
+init_debug:
+
+	lis	r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+
+	/* Quick and dirty hack to enable the RAM and copy the		*/
+	/* vectors so that we can take exceptions.			*/
+	/*--------------------------------------------------------------*/
+	/* write Memory Refresh Prescaler */
+	li	r4, CONFIG_SYS_MPTPR
+	sth	r4, IM_MPTPR@l(r3)
+	/* write 60x Refresh Timer */
+	li	r4, CONFIG_SYS_PSRT
+	stb	r4, IM_PSRT@l(r3)
+	/* init the 60x SDRAM Mode Register */
+	lis	r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM)@h
+	ori	r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM)@l
+	stw	r4, IM_PSDMR@l(r3)
+	/* write Precharge All Banks command */
+	lis	r4, (CONFIG_SYS_PSDMR|PSDMR_OP_PREA)@h
+	ori	r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_PREA)@l
+	stw	r4, IM_PSDMR@l(r3)
+	stb	r0, 0(0)
+	/* write eight CBR Refresh commands */
+	lis	r4, (CONFIG_SYS_PSDMR|PSDMR_OP_CBRR)@h
+	ori	r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_CBRR)@l
+	stw	r4, IM_PSDMR@l(r3)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	stb	r0, 0(0)
+	/* write Mode Register Write command */
+	lis	r4, (CONFIG_SYS_PSDMR|PSDMR_OP_MRW)@h
+	ori	r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_MRW)@l
+	stw	r4, IM_PSDMR@l(r3)
+	stb	r0, 0(0)
+	/* write Normal Operation command and enable Refresh */
+	lis	r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@h
+	ori	r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@l
+	stw	r4, IM_PSDMR@l(r3)
+	stb	r0, 0(0)
+	/* RAM should now be operational */
+
+#define VEC_WRD_CNT	((_end_of_vectors - _start + EXC_OFF_SYS_RESET) / 4)
+	mflr	r3
+	GET_GOT
+	mtlr	r3
+	lwz	r3, GOT(_end_of_vectors)
+	rlwinm	r4, r3, 0, 18, 31	/* _end_of_vectors & 0x3FFF	*/
+	lis	r5, VEC_WRD_CNT@h
+	ori	r5, r5, VEC_WRD_CNT@l
+	mtctr	r5
+1:
+	lwzu	r5, -4(r3)
+	stwu	r5, -4(r4)
+	bdnz	1b
+
+	/* Load the Instruction Address Breakpoint Register (IABR).	*/
+	/*								*/
+	/* The address to load is stored in the first word of dual port	*/
+	/* ram and should be preserved while the power is on, so you	*/
+	/* can plug addresses into that location then reset the cpu and	*/
+	/* this code will load that address into the IABR after the	*/
+	/* reset.							*/
+	/*								*/
+	/* When the program counter matches the contents of the IABR,	*/
+	/* an exception is generated (before the instruction at that	*/
+	/* location completes). The vector for this exception is 0x1300 */
+	/*--------------------------------------------------------------*/
+	lis	r3, CONFIG_SYS_IMMR@h
+	lwz	r3, 0(r3)
+	mtspr	IABR, r3
+
+	/* Set the entire dual port RAM (where the initial stack	*/
+	/* resides) to a known value - makes it easier to see where	*/
+	/* the stack has been written					*/
+	/*--------------------------------------------------------------*/
+	lis	r3, (CONFIG_SYS_IMMR + CONFIG_SYS_INIT_SP_OFFSET)@h
+	ori	r3, r3, (CONFIG_SYS_IMMR + CONFIG_SYS_INIT_SP_OFFSET)@l
+	li	r4, ((CONFIG_SYS_INIT_SP_OFFSET - 4) / 4)
+	mtctr	r4
+	lis	r4, 0xdeadbeaf@h
+	ori	r4, r4, 0xdeadbeaf@l
+1:
+	stwu	r4, -4(r3)
+	bdnz	1b
+
+	/* Done!							*/
+	/*--------------------------------------------------------------*/
+
+	blr
+#endif
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+	.globl	icache_enable
+icache_enable:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_ICE
+	lis	r4, 0
+	ori	r4, r4, HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4	/* sets enable and invalidate, clears lock */
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_ICE|HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_DCE
+	lis	r4, 0
+	ori	r4, r4, HID0_DLOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_DCI
+	sync
+	mtspr	HID0, r4	/* sets enable and invalidate, clears lock */
+	sync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_DCE|HID0_DLOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_DCI
+	sync
+	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */
+	sync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3		/* Set new stack pointer		*/
+	mr	r9,  r4		/* Save copy of Global Data pointer	*/
+	mr	r10, r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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
+	mfspr	r7,HID0		/* don't do dcbst if dcache is disabled */
+	rlwinm	r7,r7,HID0_DCE_BITPOS+1,31,31
+	cmpwi	r7,0
+	beq	9f
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+9:	mfspr	r7,HID0		/* don't do icbi if icache is disabled */
+	rlwinm	r7,r7,HID0_ICE_BITPOS+1,31,31
+	cmpwi	r7,0
+	beq	7f
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+#if defined(CONFIG_HYMOD)
+	/*
+	 * For HYMOD - the environment is the very last item in flash.
+	 * The real .bss stops just before environment starts, so only
+	 * clear up to that point.
+	 *
+	 * taken from mods for FADS board
+	 */
+	lwz	r4,GOT(environment)
+#else
+	lwz	r4,GOT(_end)
+#endif
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	mfmsr	r3			/* now that the vectors have	*/
+	lis	r7, MSR_IP@h		/* relocated into low memory	*/
+	ori	r7, r7, MSR_IP@l	/* MSR[IP] can be turned off	*/
+	andc	r3, r3, r7		/* (if it was on)		*/
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+
+	mtlr	r4			/* restore link register    */
+	blr
diff --git a/arch/ppc/cpu/mpc8260/traps.c b/arch/ppc/cpu/mpc8260/traps.c
new file mode 100644
index 0000000..d216f71
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/traps.c
@@ -0,0 +1,273 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+#include <asm/m8260_pci.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM	0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	puts ("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			putc ('\n');
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	putc ('\n');
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	putc ('\n');
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0) {
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			putc ('\n');
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+#ifdef CONFIG_PCI
+void dump_pci (void)
+{
+
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	printf ("PCI: err status %x err mask %x err ctrl %x\n",
+		le32_to_cpu (immap->im_pci.pci_esr),
+		le32_to_cpu (immap->im_pci.pci_emr),
+		le32_to_cpu (immap->im_pci.pci_ecr));
+	printf ("     error address %x error data %x ctrl %x\n",
+		le32_to_cpu (immap->im_pci.pci_eacr),
+		le32_to_cpu (immap->im_pci.pci_edcr),
+		le32_to_cpu (immap->im_pci.pci_eccr));
+
+}
+#endif
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+#ifdef CONFIG_PCI
+	volatile immap_t *immap  = (immap_t *)CONFIG_SYS_IMMR;
+#ifdef DEBUG
+	dump_pci();
+#endif
+	/* clear the error in the error status register */
+	if(immap->im_pci.pci_esr & cpu_to_le32(PCI_ERROR_PCI_NO_RSP)) {
+		immap->im_pci.pci_esr = cpu_to_le32(PCI_ERROR_PCI_NO_RSP);
+		return;
+	}
+#endif
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	puts ("Machine check in kernel mode.\n"
+		"Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		puts ("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13):
+		puts ("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		puts ("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		puts ("Address parity signal\n");
+		break;
+	default:
+		puts ("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_PCI
+	dump_pci();
+#endif
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+  do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8260/u-boot.lds b/arch/ppc/cpu/mpc8260/u-boot.lds
new file mode 100644
index 0000000..9887844
--- /dev/null
+++ b/arch/ppc/cpu/mpc8260/u-boot.lds
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2001-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    arch/ppc/cpu/mpc8260/start.o		(.text)
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc83xx/Makefile b/arch/ppc/cpu/mpc83xx/Makefile
new file mode 100644
index 0000000..15e2c18
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/Makefile
@@ -0,0 +1,62 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright 2004 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+
+COBJS-y += traps.o
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += speed.o
+COBJS-y += interrupts.o
+COBJS-y += spd_sdram.o
+COBJS-y += ecc.o
+COBJS-$(CONFIG_QE) += qe_io.o
+COBJS-$(CONFIG_FSL_SERDES) += serdes.o
+COBJS-$(CONFIG_PCI) += pci.o
+COBJS-$(CONFIG_PCIE) += pcie.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc83xx/config.mk b/arch/ppc/cpu/mpc83xx/config.mk
new file mode 100644
index 0000000..8596f6a
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/config.mk
@@ -0,0 +1,29 @@
+#
+# Copyright 2004 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC83xx -DCONFIG_E300 \
+			-ffixed-r2 -msoft-float
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc83xx/u-boot.lds
diff --git a/arch/ppc/cpu/mpc83xx/cpu.c b/arch/ppc/cpu/mpc83xx/cpu.c
new file mode 100644
index 0000000..51180d6
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/cpu.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC83xx family.
+ *
+ * Derived from the MPC8260 and MPC85xx.
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+#include <libfdt.h>
+#include <tsec.h>
+#include <netdev.h>
+#include <fsl_esdhc.h>
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+#include <asm/immap_qe.h>
+#include <asm/io.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu(void)
+{
+	volatile immap_t *immr;
+	ulong clock = gd->cpu_clk;
+	u32 pvr = get_pvr();
+	u32 spridr;
+	char buf[32];
+	int i;
+
+	const struct cpu_type {
+		char name[15];
+		u32 partid;
+	} cpu_type_list [] = {
+		CPU_TYPE_ENTRY(8311),
+		CPU_TYPE_ENTRY(8313),
+		CPU_TYPE_ENTRY(8314),
+		CPU_TYPE_ENTRY(8315),
+		CPU_TYPE_ENTRY(8321),
+		CPU_TYPE_ENTRY(8323),
+		CPU_TYPE_ENTRY(8343),
+		CPU_TYPE_ENTRY(8347_TBGA_),
+		CPU_TYPE_ENTRY(8347_PBGA_),
+		CPU_TYPE_ENTRY(8349),
+		CPU_TYPE_ENTRY(8358_TBGA_),
+		CPU_TYPE_ENTRY(8358_PBGA_),
+		CPU_TYPE_ENTRY(8360),
+		CPU_TYPE_ENTRY(8377),
+		CPU_TYPE_ENTRY(8378),
+		CPU_TYPE_ENTRY(8379),
+	};
+
+	immr = (immap_t *)CONFIG_SYS_IMMR;
+
+	puts("CPU:   ");
+
+	switch (pvr & 0xffff0000) {
+		case PVR_E300C1:
+			printf("e300c1, ");
+			break;
+
+		case PVR_E300C2:
+			printf("e300c2, ");
+			break;
+
+		case PVR_E300C3:
+			printf("e300c3, ");
+			break;
+
+		case PVR_E300C4:
+			printf("e300c4, ");
+			break;
+
+		default:
+			printf("Unknown core, ");
+	}
+
+	spridr = immr->sysconf.spridr;
+
+	for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++)
+		if (cpu_type_list[i].partid == PARTID_NO_E(spridr)) {
+			puts("MPC");
+			puts(cpu_type_list[i].name);
+			if (IS_E_PROCESSOR(spridr))
+				puts("E");
+			if (REVID_MAJOR(spridr) >= 2)
+				puts("A");
+			printf(", Rev: %d.%d", REVID_MAJOR(spridr),
+			       REVID_MINOR(spridr));
+			break;
+		}
+
+	if (i == ARRAY_SIZE(cpu_type_list))
+		printf("(SPRIDR %08x unknown), ", spridr);
+
+	printf(" at %s MHz, ", strmhz(buf, clock));
+
+	printf("CSB: %s MHz\n", strmhz(buf, gd->csb_clk));
+
+	return 0;
+}
+
+
+/*
+ * Program a UPM with the code supplied in the table.
+ *
+ * The 'dummy' variable is used to increment the MAD. 'dummy' is
+ * supposed to be a pointer to the memory of the device being
+ * programmed by the UPM.  The data in the MDR is written into
+ * memory and the MAD is incremented every time there's a write
+ * to 'dummy'. Unfortunately, the current prototype for this
+ * function doesn't allow for passing the address of this
+ * device, and changing the prototype will break a number lots
+ * of other code, so we need to use a round-about way of finding
+ * the value for 'dummy'.
+ *
+ * The value can be extracted from the base address bits of the
+ * Base Register (BR) associated with the specific UPM.  To find
+ * that BR, we need to scan all 8 BRs until we find the one that
+ * has its MSEL bits matching the UPM we want.  Once we know the
+ * right BR, we can extract the base address bits from it.
+ *
+ * The MxMR and the BR and OR of the chosen bank should all be
+ * configured before calling this function.
+ *
+ * Parameters:
+ * upm: 0=UPMA, 1=UPMB, 2=UPMC
+ * table: Pointer to an array of values to program
+ * size: Number of elements in the array.  Must be 64 or less.
+ */
+void upmconfig (uint upm, uint *table, uint size)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile fsl_lbus_t *lbus = &immap->lbus;
+	volatile uchar *dummy = NULL;
+	const u32 msel = (upm + 4) << BR_MSEL_SHIFT;	/* What the MSEL field in BRn should be */
+	volatile u32 *mxmr = &lbus->mamr + upm;	/* Pointer to mamr, mbmr, or mcmr */
+	uint i;
+
+	/* Scan all the banks to determine the base address of the device */
+	for (i = 0; i < 8; i++) {
+		if ((lbus->bank[i].br & BR_MSEL) == msel) {
+			dummy = (uchar *) (lbus->bank[i].br & BR_BA);
+			break;
+		}
+	}
+
+	if (!dummy) {
+		printf("Error: %s() could not find matching BR\n", __FUNCTION__);
+		hang();
+	}
+
+	/* Set the OP field in the MxMR to "write" and the MAD field to 000000 */
+	*mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000;
+
+	for (i = 0; i < size; i++) {
+		lbus->mdr = table[i];
+		__asm__ __volatile__ ("sync");
+		*dummy = 0;	/* Write the value to memory and increment MAD */
+		__asm__ __volatile__ ("sync");
+		while(((*mxmr & 0x3f) != ((i + 1) & 0x3f)));
+	}
+
+	/* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */
+	*mxmr &= 0xCFFFFFC0;
+}
+
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong msr;
+#ifndef MPC83xx_RESET
+	ulong addr;
+#endif
+
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	puts("Resetting the board.\n");
+
+#ifdef MPC83xx_RESET
+
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~( MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/* enable Reset Control Reg */
+	immap->reset.rpr = 0x52535445;
+	__asm__ __volatile__ ("sync");
+	__asm__ __volatile__ ("isync");
+
+	/* confirm Reset Control Reg is enabled */
+	while(!((immap->reset.rcer) & RCER_CRE));
+
+	udelay(200);
+
+	/* perform reset, only one bit */
+	immap->reset.rcr = RCR_SWHR;
+
+#else	/* ! MPC83xx_RESET */
+
+	immap->reset.rmr = RMR_CSRE;    /* Checkstop Reset enable */
+
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/*
+	 * Trying to execute the next instruction at a non-existing address
+	 * should cause a machine check, resulting in reset
+	 */
+	addr = CONFIG_SYS_RESET_ADDRESS;
+
+	((void (*)(void)) addr) ();
+#endif	/* MPC83xx_RESET */
+
+	return 1;
+}
+
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+
+unsigned long get_tbclk(void)
+{
+	ulong tbclk;
+
+	tbclk = (gd->bus_clk + 3L) / 4L;
+
+	return tbclk;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts();
+
+	/* Reset the 83xx watchdog */
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	immr->wdt.swsrr = 0x556c;
+	immr->wdt.swsrr = 0xaa39;
+
+	if (re_enable)
+		enable_interrupts ();
+}
+#endif
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_UEC_ETH)
+	uec_standard_init(bis);
+#endif
+
+#if defined(CONFIG_TSEC_ENET)
+	tsec_standard_init(bis);
+#endif
+	return 0;
+}
+
+/*
+ * Initializes on-chip MMC controllers.
+ * to override, implement board_mmc_init()
+ */
+int cpu_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FSL_ESDHC
+	return fsl_esdhc_mmc_init(bis);
+#else
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+#if !defined(CONFIG_MPC8360)
+#error "CONFIG_BOOTCOUNT_LIMIT only for MPC8360 implemented"
+#endif
+
+#if !defined(CONFIG_BOOTCOUNT_ADDR)
+#define CONFIG_BOOTCOUNT_ADDR	(0x110000 + QE_MURAM_SIZE - 2 * sizeof(unsigned long))
+#endif
+
+#include <asm/io.h>
+
+void bootcount_store (ulong a)
+{
+	void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR);
+	out_be32 (reg, a);
+	out_be32 (reg + 4, BOOTCOUNT_MAGIC);
+}
+
+ulong bootcount_load (void)
+{
+	void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR);
+
+	if (in_be32 (reg + 4) != BOOTCOUNT_MAGIC)
+		return 0;
+	else
+		return in_be32 (reg);
+}
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/arch/ppc/cpu/mpc83xx/cpu_init.c b/arch/ppc/cpu/mpc83xx/cpu_init.c
new file mode 100644
index 0000000..75b4522
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/cpu_init.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <ioports.h>
+#include <asm/io.h>
+#ifdef CONFIG_USB_EHCI_FSL
+#include <usb/ehci-fsl.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_QE
+extern qe_iop_conf_t qe_iop_conf_tab[];
+extern void qe_config_iopin(u8 port, u8 pin, int dir,
+			 int open_drain, int assign);
+extern void qe_init(uint qe_base);
+extern void qe_reset(void);
+
+static void config_qe_ioports(void)
+{
+	u8	port, pin;
+	int	dir, open_drain, assign;
+	int	i;
+
+	for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) {
+		port		= qe_iop_conf_tab[i].port;
+		pin		= qe_iop_conf_tab[i].pin;
+		dir		= qe_iop_conf_tab[i].dir;
+		open_drain	= qe_iop_conf_tab[i].open_drain;
+		assign		= qe_iop_conf_tab[i].assign;
+		qe_config_iopin(port, pin, dir, open_drain, assign);
+	}
+}
+#endif
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+	__be32 acr_mask =
+#ifdef CONFIG_SYS_ACR_PIPE_DEP /* Arbiter pipeline depth */
+		(ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_RPTCNT /* Arbiter repeat count */
+		(ACR_RPTCNT << ACR_RPTCNT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_APARK	/* Arbiter address parking mode */
+		(ACR_APARK << ACR_APARK_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_PARKM	/* Arbiter parking master */
+		(ACR_PARKM << ACR_PARKM_SHIFT) |
+#endif
+		0;
+	__be32 acr_val =
+#ifdef CONFIG_SYS_ACR_PIPE_DEP /* Arbiter pipeline depth */
+		(CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_RPTCNT /* Arbiter repeat count */
+		(CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_APARK	/* Arbiter address parking mode */
+		(CONFIG_SYS_ACR_APARK << ACR_APARK_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_PARKM	/* Arbiter parking master */
+		(CONFIG_SYS_ACR_PARKM << ACR_PARKM_SHIFT) |
+#endif
+		0;
+	__be32 spcr_mask =
+#ifdef CONFIG_SYS_SPCR_OPT /* Optimize transactions between CSB and other dev */
+		(SPCR_OPT << SPCR_OPT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSECEP /* all eTSEC's Emergency priority */
+		(SPCR_TSECEP << SPCR_TSECEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC1EP /* TSEC1 Emergency priority */
+		(SPCR_TSEC1EP << SPCR_TSEC1EP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC2EP /* TSEC2 Emergency priority */
+		(SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT) |
+#endif
+		0;
+	__be32 spcr_val =
+#ifdef CONFIG_SYS_SPCR_OPT
+		(CONFIG_SYS_SPCR_OPT << SPCR_OPT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSECEP /* all eTSEC's Emergency priority */
+		(CONFIG_SYS_SPCR_TSECEP << SPCR_TSECEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC1EP /* TSEC1 Emergency priority */
+		(CONFIG_SYS_SPCR_TSEC1EP << SPCR_TSEC1EP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC2EP /* TSEC2 Emergency priority */
+		(CONFIG_SYS_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT) |
+#endif
+		0;
+	__be32 sccr_mask =
+#ifdef CONFIG_SYS_SCCR_ENCCM /* Encryption clock mode */
+		(SCCR_ENCCM << SCCR_ENCCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCICM /* PCI & DMA clock mode */
+		(SCCR_PCICM << SCCR_PCICM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSECCM /* all TSEC's clock mode */
+		(SCCR_TSECCM << SCCR_TSECCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1CM /* TSEC1 clock mode */
+		(SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2CM /* TSEC2 clock mode */
+		(SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1ON /* TSEC1 clock switch */
+		(SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2ON /* TSEC2 clock switch */
+		(SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBMPHCM /* USB MPH clock mode */
+		(SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBDRCM /* USB DR clock mode */
+		(SCCR_USBDRCM << SCCR_USBDRCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_SATACM /* SATA controller clock mode */
+		(SCCR_SATACM << SCCR_SATACM_SHIFT) |
+#endif
+		0;
+	__be32 sccr_val =
+#ifdef CONFIG_SYS_SCCR_ENCCM /* Encryption clock mode */
+		(CONFIG_SYS_SCCR_ENCCM << SCCR_ENCCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCICM /* PCI & DMA clock mode */
+		(CONFIG_SYS_SCCR_PCICM << SCCR_PCICM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSECCM /* all TSEC's clock mode */
+		(CONFIG_SYS_SCCR_TSECCM << SCCR_TSECCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1CM /* TSEC1 clock mode */
+		(CONFIG_SYS_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2CM /* TSEC2 clock mode */
+		(CONFIG_SYS_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1ON /* TSEC1 clock switch */
+		(CONFIG_SYS_SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2ON /* TSEC2 clock switch */
+		(CONFIG_SYS_SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBMPHCM /* USB MPH clock mode */
+		(CONFIG_SYS_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBDRCM /* USB DR clock mode */
+		(CONFIG_SYS_SCCR_USBDRCM << SCCR_USBDRCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_SATACM /* SATA controller clock mode */
+		(CONFIG_SYS_SCCR_SATACM << SCCR_SATACM_SHIFT) |
+#endif
+		0;
+	__be32 lcrr_mask =
+#ifdef CONFIG_SYS_LCRR_DBYP /* PLL bypass */
+		LCRR_DBYP |
+#endif
+#ifdef CONFIG_SYS_LCRR_EADC /* external address delay */
+		LCRR_EADC |
+#endif
+#ifdef CONFIG_SYS_LCRR_CLKDIV /* system clock divider */
+		LCRR_CLKDIV |
+#endif
+		0;
+	__be32 lcrr_val =
+#ifdef CONFIG_SYS_LCRR_DBYP /* PLL bypass */
+		CONFIG_SYS_LCRR_DBYP |
+#endif
+#ifdef CONFIG_SYS_LCRR_EADC
+		CONFIG_SYS_LCRR_EADC |
+#endif
+#ifdef CONFIG_SYS_LCRR_CLKDIV /* system clock divider */
+		CONFIG_SYS_LCRR_CLKDIV |
+#endif
+		0;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	memset ((void *) gd, 0, sizeof (gd_t));
+
+	/* system performance tweaking */
+	clrsetbits_be32(&im->arbiter.acr, acr_mask, acr_val);
+
+	clrsetbits_be32(&im->sysconf.spcr, spcr_mask, spcr_val);
+
+	clrsetbits_be32(&im->clk.sccr, sccr_mask, sccr_val);
+
+	/* RSR - Reset Status Register - clear all status (4.6.1.3) */
+	gd->reset_status = __raw_readl(&im->reset.rsr);
+	__raw_writel(~(RSR_RES), &im->reset.rsr);
+
+	/* AER - Arbiter Event Register - store status */
+	gd->arbiter_event_attributes = __raw_readl(&im->arbiter.aeatr);
+	gd->arbiter_event_address = __raw_readl(&im->arbiter.aeadr);
+
+	/*
+	 * RMR - Reset Mode Register
+	 * contains checkstop reset enable (4.6.1.4)
+	 */
+	__raw_writel(RMR_CSRE & (1<<RMR_CSRE_SHIFT), &im->reset.rmr);
+
+	/* LCRR - Clock Ratio Register (10.3.1.16)
+	 * write, read, and isync per MPC8379ERM rev.1 CLKDEV field description
+	 */
+	clrsetbits_be32(&im->lbus.lcrr, lcrr_mask, lcrr_val);
+	__raw_readl(&im->lbus.lcrr);
+	isync();
+
+	/* Enable Time Base & Decrementer ( so we will have udelay() )*/
+	setbits_be32(&im->sysconf.spcr, SPCR_TBEN);
+
+	/* System General Purpose Register */
+#ifdef CONFIG_SYS_SICRH
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC8313)
+	/* regarding to MPC34x manual rev.1 bits 28..29 must be preserved */
+	__raw_writel((im->sysconf.sicrh & 0x0000000C) | CONFIG_SYS_SICRH,
+		     &im->sysconf.sicrh);
+#else
+	__raw_writel(CONFIG_SYS_SICRH, &im->sysconf.sicrh);
+#endif
+#endif
+#ifdef CONFIG_SYS_SICRL
+	__raw_writel(CONFIG_SYS_SICRL, &im->sysconf.sicrl);
+#endif
+#ifdef CONFIG_SYS_DDRCDR /* DDR control driver register */
+	__raw_writel(CONFIG_SYS_DDRCDR, &im->sysconf.ddrcdr);
+#endif
+#ifdef CONFIG_SYS_OBIR /* Output buffer impedance register */
+	__raw_writel(CONFIG_SYS_OBIR, &im->sysconf.obir);
+#endif
+
+#ifdef CONFIG_QE
+	/* Config QE ioports */
+	config_qe_ioports();
+#endif
+
+	/*
+	 * Memory Controller:
+	 */
+
+	/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+	 * addresses - these have to be modified later when FLASH size
+	 * has been determined
+	 */
+
+#if defined(CONFIG_SYS_BR0_PRELIM)  \
+	&& defined(CONFIG_SYS_OR0_PRELIM) \
+	&& defined(CONFIG_SYS_LBLAWBAR0_PRELIM) \
+	&& defined(CONFIG_SYS_LBLAWAR0_PRELIM)
+	im->lbus.bank[0].br = CONFIG_SYS_BR0_PRELIM;
+	im->lbus.bank[0].or = CONFIG_SYS_OR0_PRELIM;
+	im->sysconf.lblaw[0].bar = CONFIG_SYS_LBLAWBAR0_PRELIM;
+	im->sysconf.lblaw[0].ar = CONFIG_SYS_LBLAWAR0_PRELIM;
+#else
+#error	CONFIG_SYS_BR0_PRELIM, CONFIG_SYS_OR0_PRELIM, CONFIG_SYS_LBLAWBAR0_PRELIM & CONFIG_SYS_LBLAWAR0_PRELIM must be defined
+#endif
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+	im->lbus.bank[1].br = CONFIG_SYS_BR1_PRELIM;
+	im->lbus.bank[1].or = CONFIG_SYS_OR1_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR1_PRELIM) && defined(CONFIG_SYS_LBLAWAR1_PRELIM)
+	im->sysconf.lblaw[1].bar = CONFIG_SYS_LBLAWBAR1_PRELIM;
+	im->sysconf.lblaw[1].ar = CONFIG_SYS_LBLAWAR1_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+	im->lbus.bank[2].br = CONFIG_SYS_BR2_PRELIM;
+	im->lbus.bank[2].or = CONFIG_SYS_OR2_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR2_PRELIM) && defined(CONFIG_SYS_LBLAWAR2_PRELIM)
+	im->sysconf.lblaw[2].bar = CONFIG_SYS_LBLAWBAR2_PRELIM;
+	im->sysconf.lblaw[2].ar = CONFIG_SYS_LBLAWAR2_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+	im->lbus.bank[3].br = CONFIG_SYS_BR3_PRELIM;
+	im->lbus.bank[3].or = CONFIG_SYS_OR3_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR3_PRELIM) && defined(CONFIG_SYS_LBLAWAR3_PRELIM)
+	im->sysconf.lblaw[3].bar = CONFIG_SYS_LBLAWBAR3_PRELIM;
+	im->sysconf.lblaw[3].ar = CONFIG_SYS_LBLAWAR3_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+	im->lbus.bank[4].br = CONFIG_SYS_BR4_PRELIM;
+	im->lbus.bank[4].or = CONFIG_SYS_OR4_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR4_PRELIM) && defined(CONFIG_SYS_LBLAWAR4_PRELIM)
+	im->sysconf.lblaw[4].bar = CONFIG_SYS_LBLAWBAR4_PRELIM;
+	im->sysconf.lblaw[4].ar = CONFIG_SYS_LBLAWAR4_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+	im->lbus.bank[5].br = CONFIG_SYS_BR5_PRELIM;
+	im->lbus.bank[5].or = CONFIG_SYS_OR5_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR5_PRELIM) && defined(CONFIG_SYS_LBLAWAR5_PRELIM)
+	im->sysconf.lblaw[5].bar = CONFIG_SYS_LBLAWBAR5_PRELIM;
+	im->sysconf.lblaw[5].ar = CONFIG_SYS_LBLAWAR5_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+	im->lbus.bank[6].br = CONFIG_SYS_BR6_PRELIM;
+	im->lbus.bank[6].or = CONFIG_SYS_OR6_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR6_PRELIM) && defined(CONFIG_SYS_LBLAWAR6_PRELIM)
+	im->sysconf.lblaw[6].bar = CONFIG_SYS_LBLAWBAR6_PRELIM;
+	im->sysconf.lblaw[6].ar = CONFIG_SYS_LBLAWAR6_PRELIM;
+#endif
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+	im->lbus.bank[7].br = CONFIG_SYS_BR7_PRELIM;
+	im->lbus.bank[7].or = CONFIG_SYS_OR7_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR7_PRELIM) && defined(CONFIG_SYS_LBLAWAR7_PRELIM)
+	im->sysconf.lblaw[7].bar = CONFIG_SYS_LBLAWBAR7_PRELIM;
+	im->sysconf.lblaw[7].ar = CONFIG_SYS_LBLAWAR7_PRELIM;
+#endif
+#ifdef CONFIG_SYS_GPIO1_PRELIM
+	im->gpio[0].dat = CONFIG_SYS_GPIO1_DAT;
+	im->gpio[0].dir = CONFIG_SYS_GPIO1_DIR;
+#endif
+#ifdef CONFIG_SYS_GPIO2_PRELIM
+	im->gpio[1].dat = CONFIG_SYS_GPIO2_DAT;
+	im->gpio[1].dir = CONFIG_SYS_GPIO2_DIR;
+#endif
+#ifdef CONFIG_USB_EHCI_FSL
+#ifndef CONFIG_MPC834x
+	uint32_t temp;
+	struct usb_ehci *ehci = (struct usb_ehci *)CONFIG_SYS_MPC8xxx_USB_ADDR;
+
+	/* Configure interface. */
+	setbits_be32(&ehci->control, REFSEL_16MHZ | UTMI_PHY_EN);
+
+	/* Wait for clock to stabilize */
+	do {
+		temp = __raw_readl(&ehci->control);
+		udelay(1000);
+	} while (!(temp & PHY_CLK_VALID));
+#endif
+#endif
+}
+
+int cpu_init_r (void)
+{
+#ifdef CONFIG_QE
+	uint qe_base = CONFIG_SYS_IMMR + 0x00100000; /* QE immr base */
+
+	qe_init(qe_base);
+	qe_reset();
+#endif
+	return 0;
+}
+
+/*
+ * Print out the bus arbiter event
+ */
+#if defined(CONFIG_DISPLAY_AER_FULL)
+static int print_83xx_arb_event(int force)
+{
+	static char* event[] = {
+		"Address Time Out",
+		"Data Time Out",
+		"Address Only Transfer Type",
+		"External Control Word Transfer Type",
+		"Reserved Transfer Type",
+		"Transfer Error",
+		"reserved",
+		"reserved"
+	};
+	static char* master[] = {
+		"e300 Core Data Transaction",
+		"reserved",
+		"e300 Core Instruction Fetch",
+		"reserved",
+		"TSEC1",
+		"TSEC2",
+		"USB MPH",
+		"USB DR",
+		"Encryption Core",
+		"I2C Boot Sequencer",
+		"JTAG",
+		"reserved",
+		"eSDHC",
+		"PCI1",
+		"PCI2",
+		"DMA",
+		"QUICC Engine 00",
+		"QUICC Engine 01",
+		"QUICC Engine 10",
+		"QUICC Engine 11",
+		"reserved",
+		"reserved",
+		"reserved",
+		"reserved",
+		"SATA1",
+		"SATA2",
+		"SATA3",
+		"SATA4",
+		"reserved",
+		"PCI Express 1",
+		"PCI Express 2",
+		"TDM-DMAC"
+	};
+	static char *transfer[] = {
+		"Address-only, Clean Block",
+		"Address-only, lwarx reservation set",
+		"Single-beat or Burst write",
+		"reserved",
+		"Address-only, Flush Block",
+		"reserved",
+		"Burst write",
+		"reserved",
+		"Address-only, sync",
+		"Address-only, tlbsync",
+		"Single-beat or Burst read",
+		"Single-beat or Burst read",
+		"Address-only, Kill Block",
+		"Address-only, icbi",
+		"Burst read",
+		"reserved",
+		"Address-only, eieio",
+		"reserved",
+		"Single-beat write",
+		"reserved",
+		"ecowx - Illegal single-beat write",
+		"reserved",
+		"reserved",
+		"reserved",
+		"Address-only, TLB Invalidate",
+		"reserved",
+		"Single-beat or Burst read",
+		"reserved",
+		"eciwx - Illegal single-beat read",
+		"reserved",
+		"Burst read",
+		"reserved"
+	};
+
+	int etype = (gd->arbiter_event_attributes & AEATR_EVENT)
+	            >> AEATR_EVENT_SHIFT;
+	int mstr_id = (gd->arbiter_event_attributes & AEATR_MSTR_ID)
+	              >> AEATR_MSTR_ID_SHIFT;
+	int tbst = (gd->arbiter_event_attributes & AEATR_TBST)
+	           >> AEATR_TBST_SHIFT;
+	int tsize = (gd->arbiter_event_attributes & AEATR_TSIZE)
+	            >> AEATR_TSIZE_SHIFT;
+	int ttype = (gd->arbiter_event_attributes & AEATR_TTYPE)
+	            >> AEATR_TTYPE_SHIFT;
+
+	if (!force && !gd->arbiter_event_address)
+		return 0;
+
+	puts("Arbiter Event Status:\n");
+	printf("       Event Address: 0x%08lX\n", gd->arbiter_event_address);
+	printf("       Event Type:    0x%1x  = %s\n", etype, event[etype]);
+	printf("       Master ID:     0x%02x = %s\n", mstr_id, master[mstr_id]);
+	printf("       Transfer Size: 0x%1x  = %d bytes\n", (tbst<<3) | tsize,
+				tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize);
+	printf("       Transfer Type: 0x%02x = %s\n", ttype, transfer[ttype]);
+
+	return gd->arbiter_event_address;
+}
+
+#elif defined(CONFIG_DISPLAY_AER_BRIEF)
+
+static int print_83xx_arb_event(int force)
+{
+	if (!force && !gd->arbiter_event_address)
+		return 0;
+
+	printf("Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+		gd->arbiter_event_attributes, gd->arbiter_event_address);
+
+	return gd->arbiter_event_address;
+}
+#endif /* CONFIG_DISPLAY_AER_xxxx */
+
+/*
+ * Figure out the cause of the reset
+ */
+int prt_83xx_rsr(void)
+{
+	static struct {
+		ulong mask;
+		char *desc;
+	} bits[] = {
+		{
+		RSR_SWSR, "Software Soft"}, {
+		RSR_SWHR, "Software Hard"}, {
+		RSR_JSRS, "JTAG Soft"}, {
+		RSR_CSHR, "Check Stop"}, {
+		RSR_SWRS, "Software Watchdog"}, {
+		RSR_BMRS, "Bus Monitor"}, {
+		RSR_SRS,  "External/Internal Soft"}, {
+		RSR_HRS,  "External/Internal Hard"}
+	};
+	static int n = sizeof bits / sizeof bits[0];
+	ulong rsr = gd->reset_status;
+	int i;
+	char *sep;
+
+	puts("Reset Status:");
+
+	sep = " ";
+	for (i = 0; i < n; i++)
+		if (rsr & bits[i].mask) {
+			printf("%s%s", sep, bits[i].desc);
+			sep = ", ";
+		}
+	puts("\n");
+
+#if defined(CONFIG_DISPLAY_AER_FULL) || defined(CONFIG_DISPLAY_AER_BRIEF)
+	print_83xx_arb_event(rsr & RSR_BMRS);
+#endif
+	puts("\n");
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc83xx/ecc.c b/arch/ppc/cpu/mpc83xx/ecc.c
new file mode 100644
index 0000000..f3942b4
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/ecc.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on the contribution of Marian Balakowicz <m8@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <command.h>
+
+#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD)
+void ecc_print_status(void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile ddr83xx_t *ddr = &immap->ddr;
+
+	printf("\nECC mode: %s\n\n",
+	       (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF");
+
+	/* Interrupts */
+	printf("Memory Error Interrupt Enable:\n");
+	printf("  Multiple-Bit Error Interrupt Enable: %d\n",
+	       (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0);
+	printf("  Single-Bit Error Interrupt Enable: %d\n",
+	       (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0);
+	printf("  Memory Select Error Interrupt Enable: %d\n\n",
+	       (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0);
+
+	/* Error disable */
+	printf("Memory Error Disable:\n");
+	printf("  Multiple-Bit Error Disable: %d\n",
+	       (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0);
+	printf("  Sinle-Bit Error Disable: %d\n",
+	       (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0);
+	printf("  Memory Select Error Disable: %d\n\n",
+	       (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0);
+
+	/* Error injection */
+	printf("Memory Data Path Error Injection Mask High/Low: %08x %08x\n",
+	       ddr->data_err_inject_hi, ddr->data_err_inject_lo);
+
+	printf("Memory Data Path Error Injection Mask ECC:\n");
+	printf("  ECC Mirror Byte: %d\n",
+	       (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0);
+	printf("  ECC Injection Enable: %d\n",
+	       (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0);
+	printf("  ECC Error Injection Mask: 0x%02x\n\n",
+	       ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM);
+
+	/* SBE counter/threshold */
+	printf("Memory Single-Bit Error Management (0..255):\n");
+	printf("  Single-Bit Error Threshold: %d\n",
+	       (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT);
+	printf("  Single-Bit Error Counter: %d\n\n",
+	       (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT);
+
+	/* Error detect */
+	printf("Memory Error Detect:\n");
+	printf("  Multiple Memory Errors: %d\n",
+	       (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0);
+	printf("  Multiple-Bit Error: %d\n",
+	       (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0);
+	printf("  Single-Bit Error: %d\n",
+	       (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0);
+	printf("  Memory Select Error: %d\n\n",
+	       (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0);
+
+	/* Capture data */
+	printf("Memory Error Address Capture: 0x%08x\n", ddr->capture_address);
+	printf("Memory Data Path Read Capture High/Low: %08x %08x\n",
+	       ddr->capture_data_hi, ddr->capture_data_lo);
+	printf("Memory Data Path Read Capture ECC: 0x%02x\n\n",
+	       ddr->capture_ecc & CAPTURE_ECC_ECE);
+
+	printf("Memory Error Attributes Capture:\n");
+	printf(" Data Beat Number: %d\n",
+	       (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >>
+	       ECC_CAPT_ATTR_BNUM_SHIFT);
+	printf("  Transaction Size: %d\n",
+	       (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >>
+	       ECC_CAPT_ATTR_TSIZ_SHIFT);
+	printf("  Transaction Source: %d\n",
+	       (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >>
+	       ECC_CAPT_ATTR_TSRC_SHIFT);
+	printf("  Transaction Type: %d\n",
+	       (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >>
+	       ECC_CAPT_ATTR_TTYP_SHIFT);
+	printf("  Error Information Valid: %d\n\n",
+	       ddr->capture_attributes & ECC_CAPT_ATTR_VLD);
+}
+
+int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile ddr83xx_t *ddr = &immap->ddr;
+	volatile u32 val;
+	u64 *addr;
+	u32 count;
+	register u64 *i;
+	u32 ret[2];
+	u32 pattern[2];
+	u32 writeback[2];
+
+	/* The pattern is written into memory to generate error */
+	pattern[0] = 0xfedcba98UL;
+	pattern[1] = 0x76543210UL;
+
+	/* After injecting error, re-initialize the memory with the value */
+	writeback[0] = 0x01234567UL;
+	writeback[1] = 0x89abcdefUL;
+
+	if (argc > 4) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	if (argc == 2) {
+		if (strcmp(argv[1], "status") == 0) {
+			ecc_print_status();
+			return 0;
+		} else if (strcmp(argv[1], "captureclear") == 0) {
+			ddr->capture_address = 0;
+			ddr->capture_data_hi = 0;
+			ddr->capture_data_lo = 0;
+			ddr->capture_ecc = 0;
+			ddr->capture_attributes = 0;
+			return 0;
+		}
+	}
+	if (argc == 3) {
+		if (strcmp(argv[1], "sbecnt") == 0) {
+			val = simple_strtoul(argv[2], NULL, 10);
+			if (val > 255) {
+				printf("Incorrect Counter value, "
+				       "should be 0..255\n");
+				return 1;
+			}
+
+			val = (val << ECC_ERROR_MAN_SBEC_SHIFT);
+			val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET);
+
+			ddr->err_sbe = val;
+			return 0;
+		} else if (strcmp(argv[1], "sbethr") == 0) {
+			val = simple_strtoul(argv[2], NULL, 10);
+			if (val > 255) {
+				printf("Incorrect Counter value, "
+				       "should be 0..255\n");
+				return 1;
+			}
+
+			val = (val << ECC_ERROR_MAN_SBET_SHIFT);
+			val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC);
+
+			ddr->err_sbe = val;
+			return 0;
+		} else if (strcmp(argv[1], "errdisable") == 0) {
+			val = ddr->err_disable;
+
+			if (strcmp(argv[2], "+sbe") == 0) {
+				val |= ECC_ERROR_DISABLE_SBED;
+			} else if (strcmp(argv[2], "+mbe") == 0) {
+				val |= ECC_ERROR_DISABLE_MBED;
+			} else if (strcmp(argv[2], "+mse") == 0) {
+				val |= ECC_ERROR_DISABLE_MSED;
+			} else if (strcmp(argv[2], "+all") == 0) {
+				val |= (ECC_ERROR_DISABLE_SBED |
+					ECC_ERROR_DISABLE_MBED |
+					ECC_ERROR_DISABLE_MSED);
+			} else if (strcmp(argv[2], "-sbe") == 0) {
+				val &= ~ECC_ERROR_DISABLE_SBED;
+			} else if (strcmp(argv[2], "-mbe") == 0) {
+				val &= ~ECC_ERROR_DISABLE_MBED;
+			} else if (strcmp(argv[2], "-mse") == 0) {
+				val &= ~ECC_ERROR_DISABLE_MSED;
+			} else if (strcmp(argv[2], "-all") == 0) {
+				val &= ~(ECC_ERROR_DISABLE_SBED |
+					 ECC_ERROR_DISABLE_MBED |
+					 ECC_ERROR_DISABLE_MSED);
+			} else {
+				printf("Incorrect err_disable field\n");
+				return 1;
+			}
+
+			ddr->err_disable = val;
+			__asm__ __volatile__("sync");
+			__asm__ __volatile__("isync");
+			return 0;
+		} else if (strcmp(argv[1], "errdetectclr") == 0) {
+			val = ddr->err_detect;
+
+			if (strcmp(argv[2], "mme") == 0) {
+				val |= ECC_ERROR_DETECT_MME;
+			} else if (strcmp(argv[2], "sbe") == 0) {
+				val |= ECC_ERROR_DETECT_SBE;
+			} else if (strcmp(argv[2], "mbe") == 0) {
+				val |= ECC_ERROR_DETECT_MBE;
+			} else if (strcmp(argv[2], "mse") == 0) {
+				val |= ECC_ERROR_DETECT_MSE;
+			} else if (strcmp(argv[2], "all") == 0) {
+				val |= (ECC_ERROR_DETECT_MME |
+					ECC_ERROR_DETECT_MBE |
+					ECC_ERROR_DETECT_SBE |
+					ECC_ERROR_DETECT_MSE);
+			} else {
+				printf("Incorrect err_detect field\n");
+				return 1;
+			}
+
+			ddr->err_detect = val;
+			return 0;
+		} else if (strcmp(argv[1], "injectdatahi") == 0) {
+			val = simple_strtoul(argv[2], NULL, 16);
+
+			ddr->data_err_inject_hi = val;
+			return 0;
+		} else if (strcmp(argv[1], "injectdatalo") == 0) {
+			val = simple_strtoul(argv[2], NULL, 16);
+
+			ddr->data_err_inject_lo = val;
+			return 0;
+		} else if (strcmp(argv[1], "injectecc") == 0) {
+			val = simple_strtoul(argv[2], NULL, 16);
+			if (val > 0xff) {
+				printf("Incorrect ECC inject mask, "
+				       "should be 0x00..0xff\n");
+				return 1;
+			}
+			val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM);
+
+			ddr->ecc_err_inject = val;
+			return 0;
+		} else if (strcmp(argv[1], "inject") == 0) {
+			val = ddr->ecc_err_inject;
+
+			if (strcmp(argv[2], "en") == 0)
+				val |= ECC_ERR_INJECT_EIEN;
+			else if (strcmp(argv[2], "dis") == 0)
+				val &= ~ECC_ERR_INJECT_EIEN;
+			else
+				printf("Incorrect command\n");
+
+			ddr->ecc_err_inject = val;
+			__asm__ __volatile__("sync");
+			__asm__ __volatile__("isync");
+			return 0;
+		} else if (strcmp(argv[1], "mirror") == 0) {
+			val = ddr->ecc_err_inject;
+
+			if (strcmp(argv[2], "en") == 0)
+				val |= ECC_ERR_INJECT_EMB;
+			else if (strcmp(argv[2], "dis") == 0)
+				val &= ~ECC_ERR_INJECT_EMB;
+			else
+				printf("Incorrect command\n");
+
+			ddr->ecc_err_inject = val;
+			return 0;
+		}
+	}
+	if (argc == 4) {
+		if (strcmp(argv[1], "testdw") == 0) {
+			addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+			count = simple_strtoul(argv[3], NULL, 16);
+
+			if ((u32) addr % 8) {
+				printf("Address not alligned on "
+				       "double word boundary\n");
+				return 1;
+			}
+			disable_interrupts();
+
+			for (i = addr; i < addr + count; i++) {
+
+				/* enable injects */
+				ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+				__asm__ __volatile__("sync");
+				__asm__ __volatile__("isync");
+
+				/* write memory location injecting errors */
+				ppcDWstore((u32 *) i, pattern);
+				__asm__ __volatile__("sync");
+
+				/* disable injects */
+				ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+				__asm__ __volatile__("sync");
+				__asm__ __volatile__("isync");
+
+				/* read data, this generates ECC error */
+				ppcDWload((u32 *) i, ret);
+				__asm__ __volatile__("sync");
+
+				/* re-initialize memory, double word write the location again,
+				 * generates new ECC code this time */
+				ppcDWstore((u32 *) i, writeback);
+				__asm__ __volatile__("sync");
+			}
+			enable_interrupts();
+			return 0;
+		}
+		if (strcmp(argv[1], "testword") == 0) {
+			addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+			count = simple_strtoul(argv[3], NULL, 16);
+
+			if ((u32) addr % 8) {
+				printf("Address not alligned on "
+				       "double word boundary\n");
+				return 1;
+			}
+			disable_interrupts();
+
+			for (i = addr; i < addr + count; i++) {
+
+				/* enable injects */
+				ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+				__asm__ __volatile__("sync");
+				__asm__ __volatile__("isync");
+
+				/* write memory location injecting errors */
+				*(u32 *) i = 0xfedcba98UL;
+				__asm__ __volatile__("sync");
+
+				/* sub double word write,
+				 * bus will read-modify-write,
+				 * generates ECC error */
+				*((u32 *) i + 1) = 0x76543210UL;
+				__asm__ __volatile__("sync");
+
+				/* disable injects */
+				ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+				__asm__ __volatile__("sync");
+				__asm__ __volatile__("isync");
+
+				/* re-initialize memory,
+				 * double word write the location again,
+				 * generates new ECC code this time */
+				ppcDWstore((u32 *) i, writeback);
+				__asm__ __volatile__("sync");
+			}
+			enable_interrupts();
+			return 0;
+		}
+	}
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+U_BOOT_CMD(ecc, 4, 0, do_ecc,
+	   "support for DDR ECC features",
+	   "status              - print out status info\n"
+	   "ecc captureclear        - clear capture regs data\n"
+	   "ecc sbecnt <val>        - set Single-Bit Error counter\n"
+	   "ecc sbethr <val>        - set Single-Bit Threshold\n"
+	   "ecc errdisable <flag>   - clear/set disable Memory Error Disable, flag:\n"
+	   "  [-|+]sbe - Single-Bit Error\n"
+	   "  [-|+]mbe - Multiple-Bit Error\n"
+	   "  [-|+]mse - Memory Select Error\n"
+	   "  [-|+]all - all errors\n"
+	   "ecc errdetectclr <flag> - clear Memory Error Detect, flag:\n"
+	   "  mme - Multiple Memory Errors\n"
+	   "  sbe - Single-Bit Error\n"
+	   "  mbe - Multiple-Bit Error\n"
+	   "  mse - Memory Select Error\n"
+	   "  all - all errors\n"
+	   "ecc injectdatahi <hi>  - set Memory Data Path Error Injection Mask High\n"
+	   "ecc injectdatalo <lo>  - set Memory Data Path Error Injection Mask Low\n"
+	   "ecc injectecc <ecc>    - set ECC Error Injection Mask\n"
+	   "ecc inject <en|dis>    - enable/disable error injection\n"
+	   "ecc mirror <en|dis>    - enable/disable mirror byte\n"
+	   "ecc testdw <addr> <cnt>  - test mem region with double word access:\n"
+	   "  - enables injects\n"
+	   "  - writes pattern injecting errors with double word access\n"
+	   "  - disables injects\n"
+	   "  - reads pattern back with double word access, generates error\n"
+	   "  - re-inits memory\n"
+	   "ecc testword <addr> <cnt>  - test mem region with word access:\n"
+	   "  - enables injects\n"
+	   "  - writes pattern injecting errors with word access\n"
+	   "  - writes pattern with word access, generates error\n"
+	   "  - disables injects\n" "  - re-inits memory");
+#endif
diff --git a/arch/ppc/cpu/mpc83xx/fdt.c b/arch/ppc/cpu/mpc83xx/fdt.c
new file mode 100644
index 0000000..daf73a6
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/fdt.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/processor.h>
+
+extern void ft_qe_setup(void *blob);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT) && defined(CONFIG_MPC8360)
+#include <asm/immap_qe.h>
+
+void fdt_fixup_muram (void *blob)
+{
+	ulong data[2];
+
+	data[0] = 0;
+	data[1] = QE_MURAM_SIZE - 2 * sizeof(unsigned long);
+	do_fixup_by_compat(blob, "fsl,qe-muram-data", "reg",
+			data, sizeof (data), 0);
+}
+#endif
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	int spridr = immr->sysconf.spridr;
+
+	/*
+	 * delete crypto node if not on an E-processor
+	 * initial revisions of the MPC834xE/6xE have the original SEC 2.0.
+	 * EA revisions got the SEC uprevved to 2.4 but since the default device
+	 * tree contains SEC 2.0 properties we uprev them here.
+	 */
+	if (!IS_E_PROCESSOR(spridr))
+		fdt_fixup_crypto_node(blob, 0);
+	else if (IS_E_PROCESSOR(spridr) &&
+		 (SPR_FAMILY(spridr) == SPR_834X_FAMILY ||
+		  SPR_FAMILY(spridr) == SPR_836X_FAMILY) &&
+		 REVID_MAJOR(spridr) >= 2)
+		fdt_fixup_crypto_node(blob, 0x0204);
+
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
+    defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3) ||\
+    defined(CONFIG_HAS_ETH4) || defined(CONFIG_HAS_ETH5)
+	fdt_fixup_ethernet(blob);
+#ifdef CONFIG_MPC8313
+	/*
+	* mpc8313e erratum IPIC1 swapped TSEC interrupt ID numbers on rev. 1
+	* h/w (see AN3545).  The base device tree in use has rev. 1 ID numbers,
+	* so if on Rev. 2 (and higher) h/w, we fix them up here
+	*/
+	if (REVID_MAJOR(immr->sysconf.spridr) >= 2) {
+		int nodeoffset, path;
+		const char *prop;
+
+		nodeoffset = fdt_path_offset(blob, "/aliases");
+		if (nodeoffset >= 0) {
+#if defined(CONFIG_HAS_ETH0)
+			prop = fdt_getprop(blob, nodeoffset, "ethernet0", NULL);
+			if (prop) {
+				u32 tmp[] = { 32, 0x8, 33, 0x8, 34, 0x8 };
+
+				path = fdt_path_offset(blob, prop);
+				prop = fdt_getprop(blob, path, "interrupts", 0);
+				if (prop)
+					fdt_setprop(blob, path, "interrupts",
+						    &tmp, sizeof(tmp));
+			}
+#endif
+#if defined(CONFIG_HAS_ETH1)
+			prop = fdt_getprop(blob, nodeoffset, "ethernet1", NULL);
+			if (prop) {
+				u32 tmp[] = { 35, 0x8, 36, 0x8, 37, 0x8 };
+
+				path = fdt_path_offset(blob, prop);
+				prop = fdt_getprop(blob, path, "interrupts", 0);
+				if (prop)
+					fdt_setprop(blob, path, "interrupts",
+						    &tmp, sizeof(tmp));
+			}
+#endif
+		}
+	}
+#endif
+#endif
+
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"timebase-frequency", (bd->bi_busfreq / 4), 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"clock-frequency", gd->core_clk, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_compat_u32(blob, "fsl,soc",
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_compat_u32(blob, "fsl,soc",
+		"clock-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_compat_u32(blob, "fsl,immr",
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_compat_u32(blob, "fsl,immr",
+		"clock-frequency", bd->bi_busfreq, 1);
+#ifdef CONFIG_QE
+	ft_qe_setup(blob);
+#endif
+
+#ifdef CONFIG_SYS_NS16550
+	do_fixup_by_compat_u32(blob, "ns16550",
+		"clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT)
+	fdt_fixup_muram (blob);
+#endif
+}
diff --git a/arch/ppc/cpu/mpc83xx/interrupts.c b/arch/ppc/cpu/mpc83xx/interrupts.c
new file mode 100644
index 0000000..faffbaf
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/interrupts.c
@@ -0,0 +1,97 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	ulong count;
+};
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	*decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_HZ;
+
+	/* Enable e300 time base */
+
+	immr->sysconf.spcr |= 0x00400000;
+
+	return 0;
+}
+
+
+/*
+ * Handle external interrupts
+ */
+
+void external_interrupt (struct pt_regs *regs)
+{
+}
+
+
+/*
+ * Install and free an interrupt handler.
+ */
+
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+}
+
+
+void irq_free_handler (int irq)
+{
+}
+
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+
+#if defined(CONFIG_CMD_IRQ)
+
+/* ripped this out of ppc4xx/interrupts.c */
+
+/*
+ * irqinfo - print information about PCI devices
+ */
+
+void
+do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+}
+
+#endif
diff --git a/arch/ppc/cpu/mpc83xx/nand_init.c b/arch/ppc/cpu/mpc83xx/nand_init.c
new file mode 100644
index 0000000..38e141a
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/nand_init.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+	int i;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	for (i = 0; i < sizeof(gd_t); i++)
+		((char *)gd)[i] = 0;
+
+	/* system performance tweaking */
+
+#ifdef CONFIG_SYS_ACR_PIPE_DEP
+	/* Arbiter pipeline depth */
+	im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) |
+			  (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT);
+#endif
+
+#ifdef CONFIG_SYS_ACR_RPTCNT
+	/* Arbiter repeat count */
+	im->arbiter.acr = (im->arbiter.acr & ~(ACR_RPTCNT)) |
+			  (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT);
+#endif
+
+#ifdef CONFIG_SYS_SPCR_OPT
+	/* Optimize transactions between CSB and other devices */
+	im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_OPT) |
+			   (CONFIG_SYS_SPCR_OPT << SPCR_OPT_SHIFT);
+#endif
+
+	/* Enable Time Base & Decrimenter (so we will have udelay()) */
+	im->sysconf.spcr |= SPCR_TBEN;
+
+	/* DDR control driver register */
+#ifdef CONFIG_SYS_DDRCDR
+	im->sysconf.ddrcdr = CONFIG_SYS_DDRCDR;
+#endif
+	/* Output buffer impedance register */
+#ifdef CONFIG_SYS_OBIR
+	im->sysconf.obir = CONFIG_SYS_OBIR;
+#endif
+
+	/*
+	 * Memory Controller:
+	 */
+
+	/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+	 * addresses - these have to be modified later when FLASH size
+	 * has been determined
+	 */
+
+#if defined(CONFIG_SYS_NAND_BR_PRELIM)  \
+	&& defined(CONFIG_SYS_NAND_OR_PRELIM) \
+	&& defined(CONFIG_SYS_NAND_LBLAWBAR_PRELIM) \
+	&& defined(CONFIG_SYS_NAND_LBLAWAR_PRELIM)
+	im->lbus.bank[0].br = CONFIG_SYS_NAND_BR_PRELIM;
+	im->lbus.bank[0].or = CONFIG_SYS_NAND_OR_PRELIM;
+	im->sysconf.lblaw[0].bar = CONFIG_SYS_NAND_LBLAWBAR_PRELIM;
+	im->sysconf.lblaw[0].ar = CONFIG_SYS_NAND_LBLAWAR_PRELIM;
+#else
+#error CONFIG_SYS_NAND_BR_PRELIM, CONFIG_SYS_NAND_OR_PRELIM, CONFIG_SYS_NAND_LBLAWBAR_PRELIM & CONFIG_SYS_NAND_LBLAWAR_PRELIM must be defined
+#endif
+}
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+unsigned long get_tbclk(void)
+{
+	return (gd->bus_clk + 3L) / 4L;
+}
+
+void puts(const char *str)
+{
+	while (*str)
+		putc(*str++);
+}
diff --git a/arch/ppc/cpu/mpc83xx/pci.c b/arch/ppc/cpu/mpc83xx/pci.c
new file mode 100644
index 0000000..a42b230
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/pci.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) Freescale Semiconductor, Inc. 2007
+ *
+ * Author: Scott Wood <scottwood@freescale.com>,
+ * with some bits from older board-specific PCI initialization.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#include <asm/mpc8349_pci.h>
+
+#define MAX_BUSES 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct pci_controller pci_hose[MAX_BUSES];
+static int pci_num_buses;
+
+static void pci_init_bus(int bus, struct pci_region *reg)
+{
+	volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+	volatile pot83xx_t *pot = immr->ios.pot;
+	volatile pcictrl83xx_t *pci_ctrl = &immr->pci_ctrl[bus];
+	struct pci_controller *hose = &pci_hose[bus];
+	u32 dev;
+	u16 reg16;
+	int i;
+
+	if (bus == 1)
+		pot += 3;
+
+	/* Setup outbound translation windows */
+	for (i = 0; i < 3; i++, reg++, pot++) {
+		if (reg->size == 0)
+			break;
+
+		hose->regions[i] = *reg;
+		hose->region_count++;
+
+		pot->potar = reg->bus_start >> 12;
+		pot->pobar = reg->phys_start >> 12;
+		pot->pocmr = ~(reg->size - 1) >> 12;
+
+		if (reg->flags & PCI_REGION_IO)
+			pot->pocmr |= POCMR_IO;
+#ifdef CONFIG_83XX_PCI_STREAMING
+		else if (reg->flags & PCI_REGION_PREFETCH)
+			pot->pocmr |= POCMR_SE;
+#endif
+
+		if (bus == 1)
+			pot->pocmr |= POCMR_DST;
+
+		pot->pocmr |= POCMR_EN;
+	}
+
+	/* Point inbound translation at RAM */
+	pci_ctrl->pitar1 = 0;
+	pci_ctrl->pibar1 = 0;
+	pci_ctrl->piebar1 = 0;
+	pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP |
+	                   PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size - 1));
+
+	i = hose->region_count++;
+	hose->regions[i].bus_start = 0;
+	hose->regions[i].phys_start = 0;
+	hose->regions[i].size = gd->ram_size;
+	hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+	hose->first_busno = pci_last_busno() + 1;
+	hose->last_busno = 0xff;
+
+	pci_setup_indirect(hose, CONFIG_SYS_IMMR + 0x8300 + bus * 0x80,
+	                         CONFIG_SYS_IMMR + 0x8304 + bus * 0x80);
+
+	pci_register_hose(hose);
+
+	/*
+	 * Write to Command register
+	 */
+	reg16 = 0xff;
+	dev = PCI_BDF(hose->first_busno, 0, 0);
+	pci_hose_read_config_word(hose, dev, PCI_COMMAND, &reg16);
+	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+	/*
+	 * Clear non-reserved bits in status register.
+	 */
+	pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+	pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+	pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+	printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
+#ifndef CONFIG_PCISLAVE
+	/*
+	 * Hose scan.
+	 */
+	hose->last_busno = pci_hose_scan(hose);
+#endif
+}
+
+/*
+ * The caller must have already set OCCR, and the PCI_LAW BARs
+ * must have been set to cover all of the requested regions.
+ *
+ * If fewer than three regions are requested, then the region
+ * list is terminated with a region of size 0.
+ */
+void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot)
+{
+	volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+	int i;
+
+	if (num_buses > MAX_BUSES) {
+		printf("%d PCI buses requsted, %d supported\n",
+		       num_buses, MAX_BUSES);
+
+		num_buses = MAX_BUSES;
+	}
+
+	pci_num_buses = num_buses;
+
+	/*
+	 * Release PCI RST Output signal.
+	 * Power on to RST high must be at least 100 ms as per PCI spec.
+	 * On warm boots only 1 ms is required.
+	 */
+	udelay(warmboot ? 1000 : 100000);
+
+	for (i = 0; i < num_buses; i++)
+		immr->pci_ctrl[i].gcr = 1;
+
+	/*
+	 * RST high to first config access must be at least 2^25 cycles
+	 * as per PCI spec.  This could be cut in half if we know we're
+	 * running at 66MHz.  This could be insufficiently long if we're
+	 * running the PCI bus at significantly less than 33MHz.
+	 */
+	udelay(1020000);
+
+	for (i = 0; i < num_buses; i++)
+		pci_init_bus(i, reg[i]);
+}
+
+#ifdef CONFIG_PCISLAVE
+
+#define PCI_FUNCTION_CONFIG	0x44
+#define PCI_FUNCTION_CFG_LOCK	0x20
+
+/*
+ * Unlock the configuration bit so that the host system can begin booting
+ *
+ * This should be used after you have:
+ * 1) Called mpc83xx_pci_init()
+ * 2) Set up your inbound translation windows to the appropriate size
+ */
+void mpc83xx_pcislave_unlock(int bus)
+{
+	struct pci_controller *hose = &pci_hose[bus];
+	u32 dev;
+	u16 reg16;
+
+	/* Unlock configuration lock in PCI function configuration register */
+	dev = PCI_BDF(hose->first_busno, 0, 0);
+	pci_hose_read_config_word (hose, dev, PCI_FUNCTION_CONFIG, &reg16);
+	reg16 &= ~(PCI_FUNCTION_CFG_LOCK);
+	pci_hose_write_config_word (hose, dev, PCI_FUNCTION_CONFIG, reg16);
+
+	/* The configuration bit is now unlocked, so we can scan the bus */
+	hose->last_busno = pci_hose_scan(hose);
+}
+#endif
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+	int nodeoffset;
+	int tmp[2];
+	const char *path;
+
+	if (pci_num_buses < 1)
+		return;
+
+	nodeoffset = fdt_path_offset(blob, "/aliases");
+	if (nodeoffset >= 0) {
+		path = fdt_getprop(blob, nodeoffset, "pci0", NULL);
+		if (path) {
+			tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+			tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+			do_fixup_by_path(blob, path, "bus-range",
+				&tmp, sizeof(tmp), 1);
+
+			tmp[0] = cpu_to_be32(gd->pci_clk);
+			do_fixup_by_path(blob, path, "clock-frequency",
+				&tmp, sizeof(tmp[0]), 1);
+		}
+
+		if (pci_num_buses < 2)
+			return;
+
+		path = fdt_getprop(blob, nodeoffset, "pci1", NULL);
+		if (path) {
+			tmp[0] = cpu_to_be32(pci_hose[1].first_busno);
+			tmp[1] = cpu_to_be32(pci_hose[1].last_busno);
+			do_fixup_by_path(blob, path, "bus-range",
+				&tmp, sizeof(tmp), 1);
+
+			tmp[0] = cpu_to_be32(gd->pci_clk);
+			do_fixup_by_path(blob, path, "clock-frequency",
+				&tmp, sizeof(tmp[0]), 1);
+		}
+	}
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/arch/ppc/cpu/mpc83xx/pcie.c b/arch/ppc/cpu/mpc83xx/pcie.c
new file mode 100644
index 0000000..77f8906
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/pcie.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2007-2009  Freescale Semiconductor, Inc.
+ * Copyright (C) 2008-2009  MontaVista Software, Inc.
+ *
+ * Authors: Tony Li <tony.li@freescale.com>
+ *          Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <mpc83xx.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PCIE_MAX_BUSES 2
+
+#ifdef CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES
+
+static int mpc83xx_pcie_remap_cfg(struct pci_controller *hose, pci_dev_t dev)
+{
+	int bus = PCI_BUS(dev) - hose->first_busno;
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	pex83xx_t *pex = &immr->pciexp[bus];
+	struct pex_outbound_window *out_win = &pex->bridge.pex_outbound_win[0];
+	u8 devfn = PCI_DEV(dev) << 3 | PCI_FUNC(dev);
+	u32 dev_base = bus << 24 | devfn << 16;
+
+	if (hose->indirect_type == INDIRECT_TYPE_NO_PCIE_LINK)
+		return -1;
+	/*
+	 * Workaround for the HW bug: for Type 0 configure transactions the
+	 * PCI-E controller does not check the device number bits and just
+	 * assumes that the device number bits are 0.
+	 */
+	if (devfn & 0xf8)
+		return -1;
+
+	out_le32(&out_win->tarl, dev_base);
+	return 0;
+}
+
+#define cfg_read(val, addr, type, op) \
+	do { *val = op((type)(addr)); } while (0)
+#define cfg_write(val, addr, type, op) \
+	do { op((type *)(addr), (val)); } while (0)
+
+#define cfg_read_err(val) do { *val = -1; } while (0)
+#define cfg_write_err(val) do { } while (0)
+
+#define PCIE_OP(rw, size, type, op)					\
+static int pcie_##rw##_config_##size(struct pci_controller *hose,	\
+				     pci_dev_t dev, int offset,		\
+				     type val)				\
+{									\
+	int ret;							\
+									\
+	ret = mpc83xx_pcie_remap_cfg(hose, dev);			\
+	if (ret) {							\
+		cfg_##rw##_err(val); 					\
+		return ret; 						\
+	}								\
+	cfg_##rw(val, (void *)hose->cfg_addr + offset, type, op);	\
+	return 0;							\
+}
+
+PCIE_OP(read, byte, u8 *, in_8)
+PCIE_OP(read, word, u16 *, in_le16)
+PCIE_OP(read, dword, u32 *, in_le32)
+PCIE_OP(write, byte, u8, out_8)
+PCIE_OP(write, word, u16, out_le16)
+PCIE_OP(write, dword, u32, out_le32)
+
+static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
+				       u8 link)
+{
+	extern void disable_addr_trans(void); /* start.S */
+	static struct pci_controller pcie_hose[PCIE_MAX_BUSES];
+	struct pci_controller *hose = &pcie_hose[bus];
+	int i;
+
+	/*
+	 * There are no spare BATs to remap all PCI-E windows for U-Boot, so
+	 * disable translations. In general, this is not great solution, and
+	 * that's why we don't register PCI-E hoses by default.
+	 */
+	disable_addr_trans();
+
+	for (i = 0; i < 2; i++, reg++) {
+		if (reg->size == 0)
+			break;
+
+		hose->regions[i] = *reg;
+		hose->region_count++;
+	}
+
+	i = hose->region_count++;
+	hose->regions[i].bus_start = 0;
+	hose->regions[i].phys_start = 0;
+	hose->regions[i].size = gd->ram_size;
+	hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+	i = hose->region_count++;
+	hose->regions[i].bus_start = CONFIG_SYS_IMMR;
+	hose->regions[i].phys_start = CONFIG_SYS_IMMR;
+	hose->regions[i].size = 0x100000;
+	hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+	hose->first_busno = pci_last_busno() + 1;
+	hose->last_busno = 0xff;
+
+	if (bus == 0)
+		hose->cfg_addr = (unsigned int *)CONFIG_SYS_PCIE1_CFG_BASE;
+	else
+		hose->cfg_addr = (unsigned int *)CONFIG_SYS_PCIE2_CFG_BASE;
+
+	pci_set_ops(hose,
+			pcie_read_config_byte,
+			pcie_read_config_word,
+			pcie_read_config_dword,
+			pcie_write_config_byte,
+			pcie_write_config_word,
+			pcie_write_config_dword);
+
+	if (!link)
+		hose->indirect_type = INDIRECT_TYPE_NO_PCIE_LINK;
+
+	pci_register_hose(hose);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+	printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
+	/*
+	 * Hose scan.
+	 */
+	hose->last_busno = pci_hose_scan(hose);
+}
+
+#else
+
+static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
+				       u8 link) {}
+
+#endif /* CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES */
+
+static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
+{
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	pex83xx_t *pex = &immr->pciexp[bus];
+	struct pex_outbound_window *out_win;
+	struct pex_inbound_window *in_win;
+	void *hose_cfg_base;
+	unsigned int ram_sz;
+	unsigned int barl;
+	unsigned int tar;
+	u16 reg16;
+	int i;
+
+	/* Enable pex csb bridge inbound & outbound transactions */
+	out_le32(&pex->bridge.pex_csb_ctrl,
+		in_le32(&pex->bridge.pex_csb_ctrl) | PEX_CSB_CTRL_OBPIOE |
+		PEX_CSB_CTRL_IBPIOE);
+
+	/* Enable bridge outbound */
+	out_le32(&pex->bridge.pex_csb_obctrl, PEX_CSB_OBCTRL_PIOE |
+		PEX_CSB_OBCTRL_MEMWE | PEX_CSB_OBCTRL_IOWE |
+		PEX_CSB_OBCTRL_CFGWE);
+
+	out_win = &pex->bridge.pex_outbound_win[0];
+	if (bus) {
+		out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+			CONFIG_SYS_PCIE2_CFG_SIZE);
+		out_le32(&out_win->bar, CONFIG_SYS_PCIE2_CFG_BASE);
+	} else {
+		out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+			CONFIG_SYS_PCIE1_CFG_SIZE);
+		out_le32(&out_win->bar, CONFIG_SYS_PCIE1_CFG_BASE);
+	}
+	out_le32(&out_win->tarl, 0);
+	out_le32(&out_win->tarh, 0);
+
+	for (i = 0; i < 2; i++, reg++) {
+		u32 ar;
+
+		if (reg->size == 0)
+			break;
+
+		out_win = &pex->bridge.pex_outbound_win[i + 1];
+		out_le32(&out_win->bar, reg->phys_start);
+		out_le32(&out_win->tarl, reg->bus_start);
+		out_le32(&out_win->tarh, 0);
+		ar = PEX_OWAR_EN | (reg->size & PEX_OWAR_SIZE);
+		if (reg->flags & PCI_REGION_IO)
+			ar |= PEX_OWAR_TYPE_IO;
+		else
+			ar |= PEX_OWAR_TYPE_MEM;
+		out_le32(&out_win->ar, ar);
+	}
+
+	out_le32(&pex->bridge.pex_csb_ibctrl, PEX_CSB_IBCTRL_PIOE);
+
+	ram_sz = gd->ram_size;
+	barl = 0;
+	tar = 0;
+	i = 0;
+	while (ram_sz > 0) {
+		in_win = &pex->bridge.pex_inbound_win[i];
+		out_le32(&in_win->barl, barl);
+		out_le32(&in_win->barh, 0x0);
+		out_le32(&in_win->tar, tar);
+		if (ram_sz >= 0x10000000) {
+			/* The maxium windows size is 256M */
+			out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+				PEX_IWAR_TYPE_PF | 0x0FFFF000);
+			barl += 0x10000000;
+			tar += 0x10000000;
+			ram_sz -= 0x10000000;
+		} else {
+			/* The UM  is not clear here.
+			 * So, round up to even Mb boundary */
+
+			ram_sz = ram_sz >> (20 +
+					((ram_sz & 0xFFFFF) ? 1 : 0));
+			if (!(ram_sz % 2))
+				ram_sz -= 1;
+			out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+				PEX_IWAR_TYPE_PF | (ram_sz << 20) | 0xFF000);
+			ram_sz = 0;
+		}
+		i++;
+	}
+
+	in_win = &pex->bridge.pex_inbound_win[i];
+	out_le32(&in_win->barl, CONFIG_SYS_IMMR);
+	out_le32(&in_win->barh, 0);
+	out_le32(&in_win->tar, CONFIG_SYS_IMMR);
+	out_le32(&in_win->ar, PEX_IWAR_EN |
+		PEX_IWAR_TYPE_NO_PF | PEX_IWAR_SIZE_1M);
+
+	/* Enable the host virtual INTX interrupts */
+	out_le32(&pex->bridge.pex_int_axi_misc_enb,
+		in_le32(&pex->bridge.pex_int_axi_misc_enb) | 0x1E0);
+
+	/* Hose configure header is memory-mapped */
+	hose_cfg_base = (void *)pex;
+
+	get_clocks();
+	/* Configure the PCIE controller core clock ratio */
+	out_le32(hose_cfg_base + PEX_GCLK_RATIO,
+		(((bus ? gd->pciexp2_clk : gd->pciexp1_clk) / 1000000) * 16)
+		/ 333);
+	udelay(1000000);
+
+	/* Do Type 1 bridge configuration */
+	out_8(hose_cfg_base + PCI_PRIMARY_BUS, 0);
+	out_8(hose_cfg_base + PCI_SECONDARY_BUS, 1);
+	out_8(hose_cfg_base + PCI_SUBORDINATE_BUS, 255);
+
+	/*
+	 * Write to Command register
+	 */
+	reg16 = in_le16(hose_cfg_base + PCI_COMMAND);
+	reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO |
+			PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
+	out_le16(hose_cfg_base + PCI_COMMAND, reg16);
+
+	/*
+	 * Clear non-reserved bits in status register.
+	 */
+	out_le16(hose_cfg_base + PCI_STATUS, 0xffff);
+	out_8(hose_cfg_base + PCI_LATENCY_TIMER, 0x80);
+	out_8(hose_cfg_base + PCI_CACHE_LINE_SIZE, 0x08);
+
+	printf("PCIE%d: ", bus);
+
+	reg16 = in_le16(hose_cfg_base + PCI_LTSSM);
+	if (reg16 >= PCI_LTSSM_L0)
+		printf("link\n");
+	else
+		printf("No link\n");
+
+	mpc83xx_pcie_register_hose(bus, reg, reg16 >= PCI_LTSSM_L0);
+}
+
+/*
+ * The caller must have already set SCCR, SERDES and the PCIE_LAW BARs
+ * must have been set to cover all of the requested regions.
+ */
+void mpc83xx_pcie_init(int num_buses, struct pci_region **reg, int warmboot)
+{
+	int i;
+
+	/*
+	 * Release PCI RST Output signal.
+	 * Power on to RST high must be at least 100 ms as per PCI spec.
+	 * On warm boots only 1 ms is required.
+	 */
+	udelay(warmboot ? 1000 : 100000);
+
+	for (i = 0; i < num_buses; i++)
+		mpc83xx_pcie_init_bus(i, reg[i]);
+}
diff --git a/arch/ppc/cpu/mpc83xx/qe_io.c b/arch/ppc/cpu/mpc83xx/qe_io.c
new file mode 100644
index 0000000..db94f00
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/qe_io.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "common.h"
+#include "asm/errno.h"
+#include "asm/io.h"
+#include "asm/immap_83xx.h"
+
+#define	NUM_OF_PINS	32
+void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
+{
+	u32			pin_2bit_mask;
+	u32			pin_2bit_dir;
+	u32			pin_2bit_assign;
+	u32			pin_1bit_mask;
+	u32			tmp_val;
+	volatile immap_t	*im = (volatile immap_t *)CONFIG_SYS_IMMR;
+	volatile qepio83xx_t	*par_io = (volatile qepio83xx_t *)&im->qepio;
+
+	/* Caculate pin location and 2bit mask and dir */
+	pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+	pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+
+	/* Setup the direction */
+	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \
+		in_be32(&par_io->ioport[port].dir2) :
+		in_be32(&par_io->ioport[port].dir1);
+
+	if (pin > (NUM_OF_PINS/2) -1) {
+		out_be32(&par_io->ioport[port].dir2, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io->ioport[port].dir2, pin_2bit_dir | tmp_val);
+	} else {
+		out_be32(&par_io->ioport[port].dir1, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io->ioport[port].dir1, pin_2bit_dir | tmp_val);
+	}
+
+	/* Calculate pin location for 1bit mask */
+	pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1)));
+
+	/* Setup the open drain */
+	tmp_val = in_be32(&par_io->ioport[port].podr);
+	if (open_drain) {
+		out_be32(&par_io->ioport[port].podr, pin_1bit_mask | tmp_val);
+	} else {
+		out_be32(&par_io->ioport[port].podr, ~pin_1bit_mask & tmp_val);
+	}
+
+	/* Setup the assignment */
+	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ?
+		in_be32(&par_io->ioport[port].ppar2):
+		in_be32(&par_io->ioport[port].ppar1);
+	pin_2bit_assign = (u32)(assign
+				<< (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2));
+
+	/* Clear and set 2 bits mask */
+	if (pin > (NUM_OF_PINS/2) - 1) {
+		out_be32(&par_io->ioport[port].ppar2, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io->ioport[port].ppar2, pin_2bit_assign | tmp_val);
+	} else {
+		out_be32(&par_io->ioport[port].ppar1, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io->ioport[port].ppar1, pin_2bit_assign | tmp_val);
+	}
+}
diff --git a/arch/ppc/cpu/mpc83xx/serdes.c b/arch/ppc/cpu/mpc83xx/serdes.c
new file mode 100644
index 0000000..64033fe
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/serdes.c
@@ -0,0 +1,145 @@
+/*
+ * Freescale SerDes initialization routine
+ *
+ * Copyright (C) 2007 Freescale Semicondutor, Inc.
+ * Copyright (C) 2008 MontaVista Software, Inc.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_serdes.h>
+
+/* SerDes registers */
+#define FSL_SRDSCR0_OFFS		0x0
+#define FSL_SRDSCR0_DPP_1V2		0x00008800
+#define FSL_SRDSCR1_OFFS		0x4
+#define FSL_SRDSCR1_PLLBW		0x00000040
+#define FSL_SRDSCR2_OFFS		0x8
+#define FSL_SRDSCR2_VDD_1V2		0x00800000
+#define FSL_SRDSCR2_SEIC_MASK		0x00001c1c
+#define FSL_SRDSCR2_SEIC_SATA		0x00001414
+#define FSL_SRDSCR2_SEIC_PEX		0x00001010
+#define FSL_SRDSCR2_SEIC_SGMII		0x00000101
+#define FSL_SRDSCR3_OFFS		0xc
+#define FSL_SRDSCR3_KFR_SATA		0x10100000
+#define FSL_SRDSCR3_KPH_SATA		0x04040000
+#define FSL_SRDSCR3_SDFM_SATA_PEX	0x01010000
+#define FSL_SRDSCR3_SDTXL_SATA		0x00000505
+#define FSL_SRDSCR4_OFFS		0x10
+#define FSL_SRDSCR4_PROT_SATA		0x00000808
+#define FSL_SRDSCR4_PROT_PEX		0x00000101
+#define FSL_SRDSCR4_PROT_SGMII		0x00000505
+#define FSL_SRDSCR4_PLANE_X2		0x01000000
+#define FSL_SRDSRSTCTL_OFFS		0x20
+#define FSL_SRDSRSTCTL_RST		0x80000000
+#define FSL_SRDSRSTCTL_SATA_RESET	0xf
+
+void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd)
+{
+	void *regs = (void *)CONFIG_SYS_IMMR + offset;
+	u32 tmp;
+
+	/* 1.0V corevdd */
+	if (vdd) {
+		/* DPPE/DPPA = 0 */
+		tmp = in_be32(regs + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_DPP_1V2;
+		out_be32(regs + FSL_SRDSCR0_OFFS, tmp);
+
+		/* VDD = 0 */
+		tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_VDD_1V2;
+		out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+	}
+
+	/* protocol specific configuration */
+	switch (proto) {
+	case FSL_SERDES_PROTO_SATA:
+		/* Set and clear reset bits */
+		tmp = in_be32(regs + FSL_SRDSRSTCTL_OFFS);
+		tmp |= FSL_SRDSRSTCTL_SATA_RESET;
+		out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+		udelay(1000);
+		tmp &= ~FSL_SRDSRSTCTL_SATA_RESET;
+		out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+
+		/* Configure SRDSCR1 */
+		tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_PLLBW;
+		out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+		/* Configure SRDSCR2 */
+		tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+		tmp |= FSL_SRDSCR2_SEIC_SATA;
+		out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+		/* Configure SRDSCR3 */
+		tmp = FSL_SRDSCR3_KFR_SATA | FSL_SRDSCR3_KPH_SATA |
+			FSL_SRDSCR3_SDFM_SATA_PEX |
+			FSL_SRDSCR3_SDTXL_SATA;
+		out_be32(regs + FSL_SRDSCR3_OFFS, tmp);
+
+		/* Configure SRDSCR4 */
+		tmp = rfcks | FSL_SRDSCR4_PROT_SATA;
+		out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+		break;
+	case FSL_SERDES_PROTO_PEX:
+	case FSL_SERDES_PROTO_PEX_X2:
+		/* Configure SRDSCR1 */
+		tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+		tmp |= FSL_SRDSCR1_PLLBW;
+		out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+		/* Configure SRDSCR2 */
+		tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+		tmp |= FSL_SRDSCR2_SEIC_PEX;
+		out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+		/* Configure SRDSCR3 */
+		tmp = FSL_SRDSCR3_SDFM_SATA_PEX;
+		out_be32(regs + FSL_SRDSCR3_OFFS, tmp);
+
+		/* Configure SRDSCR4 */
+		tmp = rfcks | FSL_SRDSCR4_PROT_PEX;
+		if (proto == FSL_SERDES_PROTO_PEX_X2)
+			tmp |= FSL_SRDSCR4_PLANE_X2;
+		out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+		break;
+	case FSL_SERDES_PROTO_SGMII:
+		/* Configure SRDSCR1 */
+		tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_PLLBW;
+		out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+		/* Configure SRDSCR2 */
+		tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+		tmp |= FSL_SRDSCR2_SEIC_SGMII;
+		out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+		/* Configure SRDSCR3 */
+		out_be32(regs + FSL_SRDSCR3_OFFS, 0);
+
+		/* Configure SRDSCR4 */
+		tmp = rfcks | FSL_SRDSCR4_PROT_SGMII;
+		out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+		break;
+	default:
+		return;
+	}
+
+	/* Do a software reset */
+	tmp = in_be32(regs + FSL_SRDSRSTCTL_OFFS);
+	tmp |= FSL_SRDSRSTCTL_RST;
+	out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+}
diff --git a/arch/ppc/cpu/mpc83xx/spd_sdram.c b/arch/ppc/cpu/mpc83xx/spd_sdram.c
new file mode 100644
index 0000000..44aaa9a
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/spd_sdram.c
@@ -0,0 +1,918 @@
+/*
+ * (C) Copyright 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <spd.h>
+#include <asm/mmu.h>
+#include <spd_sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_add_ram_info(int use_default)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile ddr83xx_t *ddr = &immap->ddr;
+	char buf[32];
+
+	printf(" (DDR%d", ((ddr->sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK)
+			   >> SDRAM_CFG_SDRAM_TYPE_SHIFT) - 1);
+
+	if (ddr->sdram_cfg & SDRAM_CFG_32_BE)
+		puts(", 32-bit");
+	else
+		puts(", 64-bit");
+
+	if (ddr->sdram_cfg & SDRAM_CFG_ECC_EN)
+		puts(", ECC on");
+	else
+		puts(", ECC off");
+
+	printf(", %s MHz)", strmhz(buf, gd->mem_clk));
+
+#if defined(CONFIG_SYS_LB_SDRAM) && defined(CONFIG_SYS_LBC_SDRAM_SIZE)
+	puts("\nSDRAM: ");
+	print_size (CONFIG_SYS_LBC_SDRAM_SIZE * 1024 * 1024, " (local bus)");
+#endif
+}
+
+#ifdef CONFIG_SPD_EEPROM
+#ifndef	CONFIG_SYS_READ_SPD
+#define CONFIG_SYS_READ_SPD	i2c_read
+#endif
+
+/*
+ * Convert picoseconds into clock cycles (rounding up if needed).
+ */
+int
+picos_to_clk(int picos)
+{
+	unsigned int mem_bus_clk;
+	int clks;
+
+	mem_bus_clk = gd->mem_clk >> 1;
+	clks = picos / (1000000000 / (mem_bus_clk / 1000));
+	if (picos % (1000000000 / (mem_bus_clk / 1000)) != 0)
+		clks++;
+
+	return clks;
+}
+
+unsigned int banksize(unsigned char row_dens)
+{
+	return ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24;
+}
+
+int read_spd(uint addr)
+{
+	return ((int) addr);
+}
+
+#undef SPD_DEBUG
+#ifdef SPD_DEBUG
+static void spd_debug(spd_eeprom_t *spd)
+{
+	printf ("\nDIMM type:       %-18.18s\n", spd->mpart);
+	printf ("SPD size:        %d\n", spd->info_size);
+	printf ("EEPROM size:     %d\n", 1 << spd->chip_size);
+	printf ("Memory type:     %d\n", spd->mem_type);
+	printf ("Row addr:        %d\n", spd->nrow_addr);
+	printf ("Column addr:     %d\n", spd->ncol_addr);
+	printf ("# of rows:       %d\n", spd->nrows);
+	printf ("Row density:     %d\n", spd->row_dens);
+	printf ("# of banks:      %d\n", spd->nbanks);
+	printf ("Data width:      %d\n",
+			256 * spd->dataw_msb + spd->dataw_lsb);
+	printf ("Chip width:      %d\n", spd->primw);
+	printf ("Refresh rate:    %02X\n", spd->refresh);
+	printf ("CAS latencies:   %02X\n", spd->cas_lat);
+	printf ("Write latencies: %02X\n", spd->write_lat);
+	printf ("tRP:             %d\n", spd->trp);
+	printf ("tRCD:            %d\n", spd->trcd);
+	printf ("\n");
+}
+#endif /* SPD_DEBUG */
+
+long int spd_sdram()
+{
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ddr83xx_t *ddr = &immap->ddr;
+	volatile law83xx_t *ecm = &immap->sysconf.ddrlaw[0];
+	spd_eeprom_t spd;
+	unsigned int n_ranks;
+	unsigned int odt_rd_cfg, odt_wr_cfg;
+	unsigned char twr_clk, twtr_clk;
+	unsigned int sdram_type;
+	unsigned int memsize;
+	unsigned int law_size;
+	unsigned char caslat, caslat_ctrl;
+	unsigned int trfc, trfc_clk, trfc_low, trfc_high;
+	unsigned int trcd_clk, trtp_clk;
+	unsigned char cke_min_clk;
+	unsigned char add_lat, wr_lat;
+	unsigned char wr_data_delay;
+	unsigned char four_act;
+	unsigned char cpo;
+	unsigned char burstlen;
+	unsigned char odt_cfg, mode_odt_enable;
+	unsigned int max_bus_clk;
+	unsigned int max_data_rate, effective_data_rate;
+	unsigned int ddrc_clk;
+	unsigned int refresh_clk;
+	unsigned int sdram_cfg;
+	unsigned int ddrc_ecc_enable;
+	unsigned int pvr = get_pvr();
+
+	/*
+	 * First disable the memory controller (could be enabled
+	 * by the debugger)
+	 */
+	clrsetbits_be32(&ddr->sdram_cfg, SDRAM_CFG_MEM_EN, 0);
+	sync();
+	isync();
+
+	/* Read SPD parameters with I2C */
+	CONFIG_SYS_READ_SPD(SPD_EEPROM_ADDRESS, 0, 1, (uchar *) & spd, sizeof (spd));
+#ifdef SPD_DEBUG
+	spd_debug(&spd);
+#endif
+	/* Check the memory type */
+	if (spd.mem_type != SPD_MEMTYPE_DDR && spd.mem_type != SPD_MEMTYPE_DDR2) {
+		debug("DDR: Module mem type is %02X\n", spd.mem_type);
+		return 0;
+	}
+
+	/* Check the number of physical bank */
+	if (spd.mem_type == SPD_MEMTYPE_DDR) {
+		n_ranks = spd.nrows;
+	} else {
+		n_ranks = (spd.nrows & 0x7) + 1;
+	}
+
+	if (n_ranks > 2) {
+		printf("DDR: The number of physical bank is %02X\n", n_ranks);
+		return 0;
+	}
+
+	/* Check if the number of row of the module is in the range of DDRC */
+	if (spd.nrow_addr < 12 || spd.nrow_addr > 15) {
+		printf("DDR: Row number is out of range of DDRC, row=%02X\n",
+							 spd.nrow_addr);
+		return 0;
+	}
+
+	/* Check if the number of col of the module is in the range of DDRC */
+	if (spd.ncol_addr < 8 || spd.ncol_addr > 11) {
+		printf("DDR: Col number is out of range of DDRC, col=%02X\n",
+							 spd.ncol_addr);
+		return 0;
+	}
+
+#ifdef CONFIG_SYS_DDRCDR_VALUE
+	/*
+	 * Adjust DDR II IO voltage biasing.  It just makes it work.
+	 */
+	if(spd.mem_type == SPD_MEMTYPE_DDR2) {
+		immap->sysconf.ddrcdr = CONFIG_SYS_DDRCDR_VALUE;
+	}
+	udelay(50000);
+#endif
+
+	/*
+	 * ODT configuration recommendation from DDR Controller Chapter.
+	 */
+	odt_rd_cfg = 0;			/* Never assert ODT */
+	odt_wr_cfg = 0;			/* Never assert ODT */
+	if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+		odt_wr_cfg = 1;		/* Assert ODT on writes to CSn */
+	}
+
+	/* Setup DDR chip select register */
+#ifdef CONFIG_SYS_83XX_DDR_USES_CS0
+	ddr->csbnds[0].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+	ddr->cs_config[0] = ( 1 << 31
+			    | (odt_rd_cfg << 20)
+			    | (odt_wr_cfg << 16)
+			    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+			    | ((spd.nrow_addr - 12) << 8)
+			    | (spd.ncol_addr - 8) );
+	debug("\n");
+	debug("cs0_bnds = 0x%08x\n",ddr->csbnds[0].csbnds);
+	debug("cs0_config = 0x%08x\n",ddr->cs_config[0]);
+
+	if (n_ranks == 2) {
+		ddr->csbnds[1].csbnds = ( (banksize(spd.row_dens) >> 8)
+				  | ((banksize(spd.row_dens) >> 23) - 1) );
+		ddr->cs_config[1] = ( 1<<31
+				    | (odt_rd_cfg << 20)
+				    | (odt_wr_cfg << 16)
+				    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+				    | ((spd.nrow_addr - 12) << 8)
+				    | (spd.ncol_addr - 8) );
+		debug("cs1_bnds = 0x%08x\n",ddr->csbnds[1].csbnds);
+		debug("cs1_config = 0x%08x\n",ddr->cs_config[1]);
+	}
+
+#else
+	ddr->csbnds[2].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+	ddr->cs_config[2] = ( 1 << 31
+			    | (odt_rd_cfg << 20)
+			    | (odt_wr_cfg << 16)
+			    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+			    | ((spd.nrow_addr - 12) << 8)
+			    | (spd.ncol_addr - 8) );
+	debug("\n");
+	debug("cs2_bnds = 0x%08x\n",ddr->csbnds[2].csbnds);
+	debug("cs2_config = 0x%08x\n",ddr->cs_config[2]);
+
+	if (n_ranks == 2) {
+		ddr->csbnds[3].csbnds = ( (banksize(spd.row_dens) >> 8)
+				  | ((banksize(spd.row_dens) >> 23) - 1) );
+		ddr->cs_config[3] = ( 1<<31
+				    | (odt_rd_cfg << 20)
+				    | (odt_wr_cfg << 16)
+				    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+				    | ((spd.nrow_addr - 12) << 8)
+				    | (spd.ncol_addr - 8) );
+		debug("cs3_bnds = 0x%08x\n",ddr->csbnds[3].csbnds);
+		debug("cs3_config = 0x%08x\n",ddr->cs_config[3]);
+	}
+#endif
+
+	/*
+	 * Figure out memory size in Megabytes.
+	 */
+	memsize = n_ranks * banksize(spd.row_dens) / 0x100000;
+
+	/*
+	 * First supported LAW size is 16M, at LAWAR_SIZE_16M == 23.
+	 */
+	law_size = 19 + __ilog2(memsize);
+
+	/*
+	 * Set up LAWBAR for all of DDR.
+	 */
+	ecm->bar = CONFIG_SYS_DDR_SDRAM_BASE & 0xfffff000;
+	ecm->ar  = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & law_size));
+	debug("DDR:bar=0x%08x\n", ecm->bar);
+	debug("DDR:ar=0x%08x\n", ecm->ar);
+
+	/*
+	 * Find the largest CAS by locating the highest 1 bit
+	 * in the spd.cas_lat field.  Translate it to a DDR
+	 * controller field value:
+	 *
+	 *	CAS Lat	DDR I	DDR II	Ctrl
+	 *	Clocks	SPD Bit	SPD Bit	Value
+	 *	-------	-------	-------	-----
+	 *	1.0	0		0001
+	 *	1.5	1		0010
+	 *	2.0	2	2	0011
+	 *	2.5	3		0100
+	 *	3.0	4	3	0101
+	 *	3.5	5		0110
+	 *	4.0	6	4	0111
+	 *	4.5			1000
+	 *	5.0		5	1001
+	 */
+	caslat = __ilog2(spd.cas_lat);
+	if ((spd.mem_type == SPD_MEMTYPE_DDR)
+	    && (caslat > 6)) {
+		printf("DDR I: Invalid SPD CAS Latency: 0x%x.\n", spd.cas_lat);
+		return 0;
+	} else if (spd.mem_type == SPD_MEMTYPE_DDR2
+		   && (caslat < 2 || caslat > 5)) {
+		printf("DDR II: Invalid SPD CAS Latency: 0x%x.\n",
+		       spd.cas_lat);
+		return 0;
+	}
+	debug("DDR: caslat SPD bit is %d\n", caslat);
+
+	max_bus_clk = 1000 *10 / (((spd.clk_cycle & 0xF0) >> 4) * 10
+			+ (spd.clk_cycle & 0x0f));
+	max_data_rate = max_bus_clk * 2;
+
+	debug("DDR:Module maximum data rate is: %d MHz\n", max_data_rate);
+
+	ddrc_clk = gd->mem_clk / 1000000;
+	effective_data_rate = 0;
+
+	if (max_data_rate >= 460) { /* it is DDR2-800, 667, 533 */
+		if (spd.cas_lat & 0x08)
+			caslat = 3;
+		else
+			caslat = 4;
+		if (ddrc_clk <= 460 && ddrc_clk > 350)
+			effective_data_rate = 400;
+		else if (ddrc_clk <=350 && ddrc_clk > 280)
+			effective_data_rate = 333;
+		else if (ddrc_clk <= 280 && ddrc_clk > 230)
+			effective_data_rate = 266;
+		else
+			effective_data_rate = 200;
+	} else if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
+		if (ddrc_clk <= 460 && ddrc_clk > 350) {
+			/* DDR controller clk at 350~460 */
+			effective_data_rate = 400; /* 5ns */
+			caslat = caslat;
+		} else if (ddrc_clk <= 350 && ddrc_clk > 280) {
+			/* DDR controller clk at 280~350 */
+			effective_data_rate = 333; /* 6ns */
+			if (spd.clk_cycle2 == 0x60)
+				caslat = caslat - 1;
+			else
+				caslat = caslat;
+		} else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+			/* DDR controller clk at 230~280 */
+			effective_data_rate = 266; /* 7.5ns */
+			if (spd.clk_cycle3 == 0x75)
+				caslat = caslat - 2;
+			else if (spd.clk_cycle2 == 0x75)
+				caslat = caslat - 1;
+			else
+				caslat = caslat;
+		} else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+			/* DDR controller clk at 90~230 */
+			effective_data_rate = 200; /* 10ns */
+			if (spd.clk_cycle3 == 0xa0)
+				caslat = caslat - 2;
+			else if (spd.clk_cycle2 == 0xa0)
+				caslat = caslat - 1;
+			else
+				caslat = caslat;
+		}
+	} else if (max_data_rate >= 323) { /* it is DDR 333 */
+		if (ddrc_clk <= 350 && ddrc_clk > 280) {
+			/* DDR controller clk at 280~350 */
+			effective_data_rate = 333; /* 6ns */
+			caslat = caslat;
+		} else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+			/* DDR controller clk at 230~280 */
+			effective_data_rate = 266; /* 7.5ns */
+			if (spd.clk_cycle2 == 0x75)
+				caslat = caslat - 1;
+			else
+				caslat = caslat;
+		} else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+			/* DDR controller clk at 90~230 */
+			effective_data_rate = 200; /* 10ns */
+			if (spd.clk_cycle3 == 0xa0)
+				caslat = caslat - 2;
+			else if (spd.clk_cycle2 == 0xa0)
+				caslat = caslat - 1;
+			else
+				caslat = caslat;
+		}
+	} else if (max_data_rate >= 256) { /* it is DDR 266 */
+		if (ddrc_clk <= 350 && ddrc_clk > 280) {
+			/* DDR controller clk at 280~350 */
+			printf("DDR: DDR controller freq is more than "
+				"max data rate of the module\n");
+			return 0;
+		} else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+			/* DDR controller clk at 230~280 */
+			effective_data_rate = 266; /* 7.5ns */
+			caslat = caslat;
+		} else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+			/* DDR controller clk at 90~230 */
+			effective_data_rate = 200; /* 10ns */
+			if (spd.clk_cycle2 == 0xa0)
+				caslat = caslat - 1;
+		}
+	} else if (max_data_rate >= 190) { /* it is DDR 200 */
+		if (ddrc_clk <= 350 && ddrc_clk > 230) {
+			/* DDR controller clk at 230~350 */
+			printf("DDR: DDR controller freq is more than "
+				"max data rate of the module\n");
+			return 0;
+		} else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+			/* DDR controller clk at 90~230 */
+			effective_data_rate = 200; /* 10ns */
+			caslat = caslat;
+		}
+	}
+
+	debug("DDR:Effective data rate is: %dMHz\n", effective_data_rate);
+	debug("DDR:The MSB 1 of CAS Latency is: %d\n", caslat);
+
+	/*
+	 * Errata DDR6 work around: input enable 2 cycles earlier.
+	 * including MPC834x Rev1.0/1.1 and MPC8360 Rev1.1/1.2.
+	 */
+	if(PVR_MAJ(pvr) <= 1 && spd.mem_type == SPD_MEMTYPE_DDR){
+		if (caslat == 2)
+			ddr->debug_reg = 0x201c0000; /* CL=2 */
+		else if (caslat == 3)
+			ddr->debug_reg = 0x202c0000; /* CL=2.5 */
+		else if (caslat == 4)
+			ddr->debug_reg = 0x202c0000; /* CL=3.0 */
+
+		__asm__ __volatile__ ("sync");
+
+		debug("Errata DDR6 (debug_reg=0x%08x)\n", ddr->debug_reg);
+	}
+
+	/*
+	 * Convert caslat clocks to DDR controller value.
+	 * Force caslat_ctrl to be DDR Controller field-sized.
+	 */
+	if (spd.mem_type == SPD_MEMTYPE_DDR) {
+		caslat_ctrl = (caslat + 1) & 0x07;
+	} else {
+		caslat_ctrl =  (2 * caslat - 1) & 0x0f;
+	}
+
+	debug("DDR: effective data rate is %d MHz\n", effective_data_rate);
+	debug("DDR: caslat SPD bit is %d, controller field is 0x%x\n",
+	      caslat, caslat_ctrl);
+
+	/*
+	 * Timing Config 0.
+	 * Avoid writing for DDR I.
+	 */
+	if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+		unsigned char taxpd_clk = 8;		/* By the book. */
+		unsigned char tmrd_clk = 2;		/* By the book. */
+		unsigned char act_pd_exit = 2;		/* Empirical? */
+		unsigned char pre_pd_exit = 6;		/* Empirical? */
+
+		ddr->timing_cfg_0 = (0
+			| ((act_pd_exit & 0x7) << 20)	/* ACT_PD_EXIT */
+			| ((pre_pd_exit & 0x7) << 16)	/* PRE_PD_EXIT */
+			| ((taxpd_clk & 0xf) << 8)	/* ODT_PD_EXIT */
+			| ((tmrd_clk & 0xf) << 0)	/* MRS_CYC */
+			);
+		debug("DDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
+	}
+
+	/*
+	 * For DDR I, WRREC(Twr) and WRTORD(Twtr) are not in SPD,
+	 * use conservative value.
+	 * For DDR II, they are bytes 36 and 37, in quarter nanos.
+	 */
+
+	if (spd.mem_type == SPD_MEMTYPE_DDR) {
+		twr_clk = 3;	/* Clocks */
+		twtr_clk = 1;	/* Clocks */
+	} else {
+		twr_clk = picos_to_clk(spd.twr * 250);
+		twtr_clk = picos_to_clk(spd.twtr * 250);
+		if (twtr_clk < 2)
+			twtr_clk = 2;
+	}
+
+	/*
+	 * Calculate Trfc, in picos.
+	 * DDR I:  Byte 42 straight up in ns.
+	 * DDR II: Byte 40 and 42 swizzled some, in ns.
+	 */
+	if (spd.mem_type == SPD_MEMTYPE_DDR) {
+		trfc = spd.trfc * 1000;		/* up to ps */
+	} else {
+		unsigned int byte40_table_ps[8] = {
+			0,
+			250,
+			330,
+			500,
+			660,
+			750,
+			0,
+			0
+		};
+
+		trfc = (((spd.trctrfc_ext & 0x1) * 256) + spd.trfc) * 1000
+			+ byte40_table_ps[(spd.trctrfc_ext >> 1) & 0x7];
+	}
+	trfc_clk = picos_to_clk(trfc);
+
+	/*
+	 * Trcd, Byte 29, from quarter nanos to ps and clocks.
+	 */
+	trcd_clk = picos_to_clk(spd.trcd * 250) & 0x7;
+
+	/*
+	 * Convert trfc_clk to DDR controller fields.  DDR I should
+	 * fit in the REFREC field (16-19) of TIMING_CFG_1, but the
+	 * 83xx controller has an extended REFREC field of three bits.
+	 * The controller automatically adds 8 clocks to this value,
+	 * so preadjust it down 8 first before splitting it up.
+	 */
+	trfc_low = (trfc_clk - 8) & 0xf;
+	trfc_high = ((trfc_clk - 8) >> 4) & 0x3;
+
+	ddr->timing_cfg_1 =
+	    (((picos_to_clk(spd.trp * 250) & 0x07) << 28 ) |	/* PRETOACT */
+	     ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24 ) | /* ACTTOPRE */
+	     (trcd_clk << 20 ) |				/* ACTTORW */
+	     (caslat_ctrl << 16 ) |				/* CASLAT */
+	     (trfc_low << 12 ) |				/* REFEC */
+	     ((twr_clk & 0x07) << 8) |				/* WRRREC */
+	     ((picos_to_clk(spd.trrd * 250) & 0x07) << 4) |	/* ACTTOACT */
+	     ((twtr_clk & 0x07) << 0)				/* WRTORD */
+	    );
+
+	/*
+	 * Additive Latency
+	 * For DDR I, 0.
+	 * For DDR II, with ODT enabled, use "a value" less than ACTTORW,
+	 * which comes from Trcd, and also note that:
+	 *	add_lat + caslat must be >= 4
+	 */
+	add_lat = 0;
+	if (spd.mem_type == SPD_MEMTYPE_DDR2
+	    && (odt_wr_cfg || odt_rd_cfg)
+	    && (caslat < 4)) {
+		add_lat = 4 - caslat;
+		if ((add_lat + caslat) < 4) {
+			add_lat = 0;
+		}
+	}
+
+	/*
+	 * Write Data Delay
+	 * Historically 0x2 == 4/8 clock delay.
+	 * Empirically, 0x3 == 6/8 clock delay is suggested for DDR I 266.
+	 */
+	wr_data_delay = 2;
+
+	/*
+	 * Write Latency
+	 * Read to Precharge
+	 * Minimum CKE Pulse Width.
+	 * Four Activate Window
+	 */
+	if (spd.mem_type == SPD_MEMTYPE_DDR) {
+		/*
+		 * This is a lie.  It should really be 1, but if it is
+		 * set to 1, bits overlap into the old controller's
+		 * otherwise unused ACSM field.  If we leave it 0, then
+		 * the HW will magically treat it as 1 for DDR 1.  Oh Yea.
+		 */
+		wr_lat = 0;
+
+		trtp_clk = 2;		/* By the book. */
+		cke_min_clk = 1;	/* By the book. */
+		four_act = 1;		/* By the book. */
+
+	} else {
+		wr_lat = caslat - 1;
+
+		/* Convert SPD value from quarter nanos to picos. */
+		trtp_clk = picos_to_clk(spd.trtp * 250);
+		if (trtp_clk < 2)
+			trtp_clk = 2;
+		trtp_clk += add_lat;
+
+		cke_min_clk = 3;	/* By the book. */
+		four_act = picos_to_clk(37500);	/* By the book. 1k pages? */
+	}
+
+	/*
+	 * Empirically set ~MCAS-to-preamble override for DDR 2.
+	 * Your milage will vary.
+	 */
+	cpo = 0;
+	if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+		if (effective_data_rate == 266) {
+			cpo = 0x4;		/* READ_LAT + 1/2 */
+		} else if (effective_data_rate == 333) {
+			cpo = 0x6;		/* READ_LAT + 1 */
+		} else if (effective_data_rate == 400) {
+			cpo = 0x7;		/* READ_LAT + 5/4 */
+		} else {
+			/* Automatic calibration */
+			cpo = 0x1f;
+		}
+	}
+
+	ddr->timing_cfg_2 = (0
+		| ((add_lat & 0x7) << 28)		/* ADD_LAT */
+		| ((cpo & 0x1f) << 23)			/* CPO */
+		| ((wr_lat & 0x7) << 19)		/* WR_LAT */
+		| ((trtp_clk & 0x7) << 13)		/* RD_TO_PRE */
+		| ((wr_data_delay & 0x7) << 10)		/* WR_DATA_DELAY */
+		| ((cke_min_clk & 0x7) << 6)		/* CKE_PLS */
+		| ((four_act & 0x1f) << 0)		/* FOUR_ACT */
+		);
+
+	debug("DDR:timing_cfg_1=0x%08x\n", ddr->timing_cfg_1);
+	debug("DDR:timing_cfg_2=0x%08x\n", ddr->timing_cfg_2);
+
+	/* Check DIMM data bus width */
+	if (spd.dataw_lsb < 64) {
+		if (spd.mem_type == SPD_MEMTYPE_DDR)
+			burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
+		else
+			burstlen = 0x02; /* 32 bit data bus, burst len is 4 */
+		debug("\n   DDR DIMM: data bus width is 32 bit");
+	} else {
+		burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */
+		debug("\n   DDR DIMM: data bus width is 64 bit");
+	}
+
+	/* Is this an ECC DDR chip? */
+	if (spd.config == 0x02)
+		debug(" with ECC\n");
+	else
+		debug(" without ECC\n");
+
+	/* Burst length is always 4 for 64 bit data bus, 8 for 32 bit data bus,
+	   Burst type is sequential
+	 */
+	if (spd.mem_type == SPD_MEMTYPE_DDR) {
+		switch (caslat) {
+		case 1:
+			ddr->sdram_mode = 0x50 | burstlen; /* CL=1.5 */
+			break;
+		case 2:
+			ddr->sdram_mode = 0x20 | burstlen; /* CL=2.0 */
+			break;
+		case 3:
+			ddr->sdram_mode = 0x60 | burstlen; /* CL=2.5 */
+			break;
+		case 4:
+			ddr->sdram_mode = 0x30 | burstlen; /* CL=3.0 */
+			break;
+		default:
+			printf("DDR:only CL 1.5, 2.0, 2.5, 3.0 is supported\n");
+			return 0;
+		}
+	} else {
+		mode_odt_enable = 0x0;                  /* Default disabled */
+		if (odt_wr_cfg || odt_rd_cfg) {
+			/*
+			 * Bits 6 and 2 in Extended MRS(1)
+			 * Bit 2 == 0x04 == 75 Ohm, with 2 DIMM modules.
+			 * Bit 6 == 0x40 == 150 Ohm, with 1 DIMM module.
+			 */
+			mode_odt_enable = 0x40;         /* 150 Ohm */
+		}
+
+		ddr->sdram_mode =
+			(0
+			 | (1 << (16 + 10))             /* DQS Differential disable */
+			 | (add_lat << (16 + 3))        /* Additive Latency in EMRS1 */
+			 | (mode_odt_enable << 16)      /* ODT Enable in EMRS1 */
+			 | ((twr_clk - 1) << 9)         /* Write Recovery Autopre */
+			 | (caslat << 4)                /* caslat */
+			 | (burstlen << 0)              /* Burst length */
+			);
+	}
+	debug("DDR:sdram_mode=0x%08x\n", ddr->sdram_mode);
+
+	/*
+	 * Clear EMRS2 and EMRS3.
+	 */
+	ddr->sdram_mode2 = 0;
+	debug("DDR: sdram_mode2 = 0x%08x\n", ddr->sdram_mode2);
+
+	switch (spd.refresh) {
+		case 0x00:
+		case 0x80:
+			refresh_clk = picos_to_clk(15625000);
+			break;
+		case 0x01:
+		case 0x81:
+			refresh_clk = picos_to_clk(3900000);
+			break;
+		case 0x02:
+		case 0x82:
+			refresh_clk = picos_to_clk(7800000);
+			break;
+		case 0x03:
+		case 0x83:
+			refresh_clk = picos_to_clk(31300000);
+			break;
+		case 0x04:
+		case 0x84:
+			refresh_clk = picos_to_clk(62500000);
+			break;
+		case 0x05:
+		case 0x85:
+			refresh_clk = picos_to_clk(125000000);
+			break;
+		default:
+			refresh_clk = 0x512;
+			break;
+	}
+
+	/*
+	 * Set BSTOPRE to 0x100 for page mode
+	 * If auto-charge is used, set BSTOPRE = 0
+	 */
+	ddr->sdram_interval = ((refresh_clk & 0x3fff) << 16) | 0x100;
+	debug("DDR:sdram_interval=0x%08x\n", ddr->sdram_interval);
+
+	/*
+	 * SDRAM Cfg 2
+	 */
+	odt_cfg = 0;
+#ifndef CONFIG_NEVER_ASSERT_ODT_TO_CPU
+	if (odt_rd_cfg | odt_wr_cfg) {
+		odt_cfg = 0x2;		/* ODT to IOs during reads */
+	}
+#endif
+	if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+		ddr->sdram_cfg2 = (0
+			    | (0 << 26)	/* True DQS */
+			    | (odt_cfg << 21)	/* ODT only read */
+			    | (1 << 12)	/* 1 refresh at a time */
+			    );
+
+		debug("DDR: sdram_cfg2  = 0x%08x\n", ddr->sdram_cfg2);
+	}
+
+#ifdef CONFIG_SYS_DDR_SDRAM_CLK_CNTL	/* Optional platform specific value */
+	ddr->sdram_clk_cntl = CONFIG_SYS_DDR_SDRAM_CLK_CNTL;
+#endif
+	debug("DDR:sdram_clk_cntl=0x%08x\n", ddr->sdram_clk_cntl);
+
+	asm("sync;isync");
+
+	udelay(600);
+
+	/*
+	 * Figure out the settings for the sdram_cfg register. Build up
+	 * the value in 'sdram_cfg' before writing since the write into
+	 * the register will actually enable the memory controller, and all
+	 * settings must be done before enabling.
+	 *
+	 * sdram_cfg[0]   = 1 (ddr sdram logic enable)
+	 * sdram_cfg[1]   = 1 (self-refresh-enable)
+	 * sdram_cfg[5:7] = (SDRAM type = DDR SDRAM)
+	 *			010 DDR 1 SDRAM
+	 *			011 DDR 2 SDRAM
+	 * sdram_cfg[12] = 0 (32_BE =0 , 64 bit bus mode)
+	 * sdram_cfg[13] = 0 (8_BE =0, 4-beat bursts)
+	 */
+	if (spd.mem_type == SPD_MEMTYPE_DDR)
+		sdram_type = SDRAM_CFG_SDRAM_TYPE_DDR1;
+	else
+		sdram_type = SDRAM_CFG_SDRAM_TYPE_DDR2;
+
+	sdram_cfg = (0
+		     | SDRAM_CFG_MEM_EN		/* DDR enable */
+		     | SDRAM_CFG_SREN		/* Self refresh */
+		     | sdram_type		/* SDRAM type */
+		     );
+
+	/* sdram_cfg[3] = RD_EN - registered DIMM enable */
+	if (spd.mod_attr & 0x02)
+		sdram_cfg |= SDRAM_CFG_RD_EN;
+
+	/* The DIMM is 32bit width */
+	if (spd.dataw_lsb < 64) {
+		if (spd.mem_type == SPD_MEMTYPE_DDR)
+			sdram_cfg |= SDRAM_CFG_32_BE | SDRAM_CFG_8_BE;
+		if (spd.mem_type == SPD_MEMTYPE_DDR2)
+			sdram_cfg |= SDRAM_CFG_32_BE;
+	}
+
+	ddrc_ecc_enable = 0;
+
+#if defined(CONFIG_DDR_ECC)
+	/* Enable ECC with sdram_cfg[2] */
+	if (spd.config == 0x02) {
+		sdram_cfg |= 0x20000000;
+		ddrc_ecc_enable = 1;
+		/* disable error detection */
+		ddr->err_disable = ~ECC_ERROR_ENABLE;
+		/* set single bit error threshold to maximum value,
+		 * reset counter to zero */
+		ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) |
+				(0 << ECC_ERROR_MAN_SBEC_SHIFT);
+	}
+
+	debug("DDR:err_disable=0x%08x\n", ddr->err_disable);
+	debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe);
+#endif
+	debug("   DDRC ECC mode: %s\n", ddrc_ecc_enable ? "ON":"OFF");
+
+#if defined(CONFIG_DDR_2T_TIMING)
+	/*
+	 * Enable 2T timing by setting sdram_cfg[16].
+	 */
+	sdram_cfg |= SDRAM_CFG_2T_EN;
+#endif
+	/* Enable controller, and GO! */
+	ddr->sdram_cfg = sdram_cfg;
+	asm("sync;isync");
+	udelay(500);
+
+	debug("DDR:sdram_cfg=0x%08x\n", ddr->sdram_cfg);
+	return memsize; /*in MBytes*/
+}
+#endif /* CONFIG_SPD_EEPROM */
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+/*
+ * Use timebase counter, get_timer() is not availabe
+ * at this point of initialization yet.
+ */
+static __inline__ unsigned long get_tbms (void)
+{
+	unsigned long tbl;
+	unsigned long tbu1, tbu2;
+	unsigned long ms;
+	unsigned long long tmp;
+
+	ulong tbclk = get_tbclk();
+
+	/* get the timebase ticks */
+	do {
+		asm volatile ("mftbu %0":"=r" (tbu1):);
+		asm volatile ("mftb %0":"=r" (tbl):);
+		asm volatile ("mftbu %0":"=r" (tbu2):);
+	} while (tbu1 != tbu2);
+
+	/* convert ticks to ms */
+	tmp = (unsigned long long)(tbu1);
+	tmp = (tmp << 32);
+	tmp += (unsigned long long)(tbl);
+	ms = tmp/(tbclk/1000);
+
+	return ms;
+}
+
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+void ddr_enable_ecc(unsigned int dram_size)
+{
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ddr83xx_t *ddr= &immap->ddr;
+	unsigned long t_start, t_end;
+	register u64 *p;
+	register uint size;
+	unsigned int pattern[2];
+
+	icache_enable();
+	t_start = get_tbms();
+	pattern[0] = 0xdeadbeef;
+	pattern[1] = 0xdeadbeef;
+
+#if defined(CONFIG_DDR_ECC_INIT_VIA_DMA)
+	dma_meminit(pattern[0], dram_size);
+#else
+	debug("ddr init: CPU FP write method\n");
+	size = dram_size;
+	for (p = 0; p < (u64*)(size); p++) {
+		ppcDWstore((u32*)p, pattern);
+	}
+	__asm__ __volatile__ ("sync");
+#endif
+
+	t_end = get_tbms();
+	icache_disable();
+
+	debug("\nREADY!!\n");
+	debug("ddr init duration: %ld ms\n", t_end - t_start);
+
+	/* Clear All ECC Errors */
+	if ((ddr->err_detect & ECC_ERROR_DETECT_MME) == ECC_ERROR_DETECT_MME)
+		ddr->err_detect |= ECC_ERROR_DETECT_MME;
+	if ((ddr->err_detect & ECC_ERROR_DETECT_MBE) == ECC_ERROR_DETECT_MBE)
+		ddr->err_detect |= ECC_ERROR_DETECT_MBE;
+	if ((ddr->err_detect & ECC_ERROR_DETECT_SBE) == ECC_ERROR_DETECT_SBE)
+		ddr->err_detect |= ECC_ERROR_DETECT_SBE;
+	if ((ddr->err_detect & ECC_ERROR_DETECT_MSE) == ECC_ERROR_DETECT_MSE)
+		ddr->err_detect |= ECC_ERROR_DETECT_MSE;
+
+	/* Disable ECC-Interrupts */
+	ddr->err_int_en &= ECC_ERR_INT_DISABLE;
+
+	/* Enable errors for ECC */
+	ddr->err_disable &= ECC_ERROR_ENABLE;
+
+	__asm__ __volatile__ ("sync");
+	__asm__ __volatile__ ("isync");
+}
+#endif	/* CONFIG_DDR_ECC */
diff --git a/arch/ppc/cpu/mpc83xx/speed.c b/arch/ppc/cpu/mpc83xx/speed.c
new file mode 100644
index 0000000..bde7e92
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/speed.c
@@ -0,0 +1,549 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <command.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ----------------------------------------------------------------- */
+
+typedef enum {
+	_unk,
+	_off,
+	_byp,
+	_x8,
+	_x4,
+	_x2,
+	_x1,
+	_1x,
+	_1_5x,
+	_2x,
+	_2_5x,
+	_3x
+} mult_t;
+
+typedef struct {
+	mult_t core_csb_ratio;
+	mult_t vco_divider;
+} corecnf_t;
+
+corecnf_t corecnf_tab[] = {
+	{_byp, _byp},		/* 0x00 */
+	{_byp, _byp},		/* 0x01 */
+	{_byp, _byp},		/* 0x02 */
+	{_byp, _byp},		/* 0x03 */
+	{_byp, _byp},		/* 0x04 */
+	{_byp, _byp},		/* 0x05 */
+	{_byp, _byp},		/* 0x06 */
+	{_byp, _byp},		/* 0x07 */
+	{_1x, _x2},		/* 0x08 */
+	{_1x, _x4},		/* 0x09 */
+	{_1x, _x8},		/* 0x0A */
+	{_1x, _x8},		/* 0x0B */
+	{_1_5x, _x2},		/* 0x0C */
+	{_1_5x, _x4},		/* 0x0D */
+	{_1_5x, _x8},		/* 0x0E */
+	{_1_5x, _x8},		/* 0x0F */
+	{_2x, _x2},		/* 0x10 */
+	{_2x, _x4},		/* 0x11 */
+	{_2x, _x8},		/* 0x12 */
+	{_2x, _x8},		/* 0x13 */
+	{_2_5x, _x2},		/* 0x14 */
+	{_2_5x, _x4},		/* 0x15 */
+	{_2_5x, _x8},		/* 0x16 */
+	{_2_5x, _x8},		/* 0x17 */
+	{_3x, _x2},		/* 0x18 */
+	{_3x, _x4},		/* 0x19 */
+	{_3x, _x8},		/* 0x1A */
+	{_3x, _x8},		/* 0x1B */
+};
+
+/* ----------------------------------------------------------------- */
+
+/*
+ *
+ */
+int get_clocks(void)
+{
+	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+	u32 pci_sync_in;
+	u8 spmf;
+	u8 clkin_div;
+	u32 sccr;
+	u32 corecnf_tab_index;
+	u8 corepll;
+	u32 lcrr;
+
+	u32 csb_clk;
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+	u32 tsec1_clk;
+	u32 tsec2_clk;
+	u32 usbdr_clk;
+#endif
+#ifdef CONFIG_MPC834x
+	u32 usbmph_clk;
+#endif
+	u32 core_clk;
+	u32 i2c1_clk;
+#if !defined(CONFIG_MPC832x)
+	u32 i2c2_clk;
+#endif
+#if defined(CONFIG_MPC8315)
+	u32 tdm_clk;
+#endif
+#if defined(CONFIG_MPC837x)
+	u32 sdhc_clk;
+#endif
+	u32 enc_clk;
+	u32 lbiu_clk;
+	u32 lclk_clk;
+	u32 mem_clk;
+#if defined(CONFIG_MPC8360)
+	u32 mem_sec_clk;
+#endif
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+	u32 qepmf;
+	u32 qepdf;
+	u32 qe_clk;
+	u32 brg_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC831x)
+	u32 pciexp1_clk;
+	u32 pciexp2_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+	u32 sata_clk;
+#endif
+
+	if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32) im)
+		return -1;
+
+	clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT);
+
+	if (im->reset.rcwh & HRCWH_PCI_HOST) {
+#if defined(CONFIG_83XX_CLKIN)
+		pci_sync_in = CONFIG_83XX_CLKIN / (1 + clkin_div);
+#else
+		pci_sync_in = 0xDEADBEEF;
+#endif
+	} else {
+#if defined(CONFIG_83XX_PCICLK)
+		pci_sync_in = CONFIG_83XX_PCICLK;
+#else
+		pci_sync_in = 0xDEADBEEF;
+#endif
+	}
+
+	spmf = ((im->reset.rcwl & HRCWL_SPMF) >> HRCWL_SPMF_SHIFT);
+	csb_clk = pci_sync_in * (1 + clkin_div) * spmf;
+
+	sccr = im->clk.sccr;
+
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+	switch ((sccr & SCCR_TSEC1CM) >> SCCR_TSEC1CM_SHIFT) {
+	case 0:
+		tsec1_clk = 0;
+		break;
+	case 1:
+		tsec1_clk = csb_clk;
+		break;
+	case 2:
+		tsec1_clk = csb_clk / 2;
+		break;
+	case 3:
+		tsec1_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_TSEC1CM value */
+		return -2;
+	}
+
+	switch ((sccr & SCCR_USBDRCM) >> SCCR_USBDRCM_SHIFT) {
+	case 0:
+		usbdr_clk = 0;
+		break;
+	case 1:
+		usbdr_clk = csb_clk;
+		break;
+	case 2:
+		usbdr_clk = csb_clk / 2;
+		break;
+	case 3:
+		usbdr_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_USBDRCM value */
+		return -3;
+	}
+#endif
+
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+	switch ((sccr & SCCR_TSEC2CM) >> SCCR_TSEC2CM_SHIFT) {
+	case 0:
+		tsec2_clk = 0;
+		break;
+	case 1:
+		tsec2_clk = csb_clk;
+		break;
+	case 2:
+		tsec2_clk = csb_clk / 2;
+		break;
+	case 3:
+		tsec2_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_TSEC2CM value */
+		return -4;
+	}
+#elif defined(CONFIG_MPC8313)
+	tsec2_clk = tsec1_clk;
+
+	if (!(sccr & SCCR_TSEC1ON))
+		tsec1_clk = 0;
+	if (!(sccr & SCCR_TSEC2ON))
+		tsec2_clk = 0;
+#endif
+
+#if defined(CONFIG_MPC834x)
+	switch ((sccr & SCCR_USBMPHCM) >> SCCR_USBMPHCM_SHIFT) {
+	case 0:
+		usbmph_clk = 0;
+		break;
+	case 1:
+		usbmph_clk = csb_clk;
+		break;
+	case 2:
+		usbmph_clk = csb_clk / 2;
+		break;
+	case 3:
+		usbmph_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_USBMPHCM value */
+		return -5;
+	}
+
+	if (usbmph_clk != 0 && usbdr_clk != 0 && usbmph_clk != usbdr_clk) {
+		/* if USB MPH clock is not disabled and
+		 * USB DR clock is not disabled then
+		 * USB MPH & USB DR must have the same rate
+		 */
+		return -6;
+	}
+#endif
+	switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) {
+	case 0:
+		enc_clk = 0;
+		break;
+	case 1:
+		enc_clk = csb_clk;
+		break;
+	case 2:
+		enc_clk = csb_clk / 2;
+		break;
+	case 3:
+		enc_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_ENCCM value */
+		return -7;
+	}
+
+#if defined(CONFIG_MPC837x)
+	switch ((sccr & SCCR_SDHCCM) >> SCCR_SDHCCM_SHIFT) {
+	case 0:
+		sdhc_clk = 0;
+		break;
+	case 1:
+		sdhc_clk = csb_clk;
+		break;
+	case 2:
+		sdhc_clk = csb_clk / 2;
+		break;
+	case 3:
+		sdhc_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_SDHCCM value */
+		return -8;
+	}
+#endif
+#if defined(CONFIG_MPC8315)
+	switch ((sccr & SCCR_TDMCM) >> SCCR_TDMCM_SHIFT) {
+	case 0:
+		tdm_clk = 0;
+		break;
+	case 1:
+		tdm_clk = csb_clk;
+		break;
+	case 2:
+		tdm_clk = csb_clk / 2;
+		break;
+	case 3:
+		tdm_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_TDMCM value */
+		return -8;
+	}
+#endif
+
+#if defined(CONFIG_MPC834x)
+	i2c1_clk = tsec2_clk;
+#elif defined(CONFIG_MPC8360)
+	i2c1_clk = csb_clk;
+#elif defined(CONFIG_MPC832x)
+	i2c1_clk = enc_clk;
+#elif defined(CONFIG_MPC831x)
+	i2c1_clk = enc_clk;
+#elif defined(CONFIG_MPC837x)
+	i2c1_clk = sdhc_clk;
+#endif
+#if !defined(CONFIG_MPC832x)
+	i2c2_clk = csb_clk; /* i2c-2 clk is equal to csb clk */
+#endif
+
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC831x)
+	switch ((sccr & SCCR_PCIEXP1CM) >> SCCR_PCIEXP1CM_SHIFT) {
+	case 0:
+		pciexp1_clk = 0;
+		break;
+	case 1:
+		pciexp1_clk = csb_clk;
+		break;
+	case 2:
+		pciexp1_clk = csb_clk / 2;
+		break;
+	case 3:
+		pciexp1_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_PCIEXP1CM value */
+		return -9;
+	}
+
+	switch ((sccr & SCCR_PCIEXP2CM) >> SCCR_PCIEXP2CM_SHIFT) {
+	case 0:
+		pciexp2_clk = 0;
+		break;
+	case 1:
+		pciexp2_clk = csb_clk;
+		break;
+	case 2:
+		pciexp2_clk = csb_clk / 2;
+		break;
+	case 3:
+		pciexp2_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_PCIEXP2CM value */
+		return -10;
+	}
+#endif
+
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+	switch ((sccr & SCCR_SATA1CM) >> SCCR_SATA1CM_SHIFT) {
+	case 0:
+		sata_clk = 0;
+		break;
+	case 1:
+		sata_clk = csb_clk;
+		break;
+	case 2:
+		sata_clk = csb_clk / 2;
+		break;
+	case 3:
+		sata_clk = csb_clk / 3;
+		break;
+	default:
+		/* unkown SCCR_SATACM value */
+		return -11;
+	}
+#endif
+
+	lbiu_clk = csb_clk *
+	           (1 + ((im->reset.rcwl & HRCWL_LBIUCM) >> HRCWL_LBIUCM_SHIFT));
+	lcrr = (im->lbus.lcrr & LCRR_CLKDIV) >> LCRR_CLKDIV_SHIFT;
+	switch (lcrr) {
+	case 2:
+	case 4:
+	case 8:
+		lclk_clk = lbiu_clk / lcrr;
+		break;
+	default:
+		/* unknown lcrr */
+		return -12;
+	}
+
+	mem_clk = csb_clk *
+		  (1 + ((im->reset.rcwl & HRCWL_DDRCM) >> HRCWL_DDRCM_SHIFT));
+	corepll = (im->reset.rcwl & HRCWL_COREPLL) >> HRCWL_COREPLL_SHIFT;
+#if defined(CONFIG_MPC8360)
+	mem_sec_clk = csb_clk * (1 +
+		       ((im->reset.rcwl & HRCWL_LBIUCM) >> HRCWL_LBIUCM_SHIFT));
+#endif
+
+	corecnf_tab_index = ((corepll & 0x1F) << 2) | ((corepll & 0x60) >> 5);
+	if (corecnf_tab_index > (sizeof(corecnf_tab) / sizeof(corecnf_t))) {
+		/* corecnf_tab_index is too high, possibly worng value */
+		return -11;
+	}
+	switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) {
+	case _byp:
+	case _x1:
+	case _1x:
+		core_clk = csb_clk;
+		break;
+	case _1_5x:
+		core_clk = (3 * csb_clk) / 2;
+		break;
+	case _2x:
+		core_clk = 2 * csb_clk;
+		break;
+	case _2_5x:
+		core_clk = (5 * csb_clk) / 2;
+		break;
+	case _3x:
+		core_clk = 3 * csb_clk;
+		break;
+	default:
+		/* unkown core to csb ratio */
+		return -13;
+	}
+
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+	qepmf = (im->reset.rcwl & HRCWL_CEPMF) >> HRCWL_CEPMF_SHIFT;
+	qepdf = (im->reset.rcwl & HRCWL_CEPDF) >> HRCWL_CEPDF_SHIFT;
+	qe_clk = (pci_sync_in * qepmf) / (1 + qepdf);
+	brg_clk = qe_clk / 2;
+#endif
+
+	gd->csb_clk = csb_clk;
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+	gd->tsec1_clk = tsec1_clk;
+	gd->tsec2_clk = tsec2_clk;
+	gd->usbdr_clk = usbdr_clk;
+#endif
+#if defined(CONFIG_MPC834x)
+	gd->usbmph_clk = usbmph_clk;
+#endif
+#if defined(CONFIG_MPC8315)
+	gd->tdm_clk = tdm_clk;
+#endif
+#if defined(CONFIG_MPC837x)
+	gd->sdhc_clk = sdhc_clk;
+#endif
+	gd->core_clk = core_clk;
+	gd->i2c1_clk = i2c1_clk;
+#if !defined(CONFIG_MPC832x)
+	gd->i2c2_clk = i2c2_clk;
+#endif
+	gd->enc_clk = enc_clk;
+	gd->lbiu_clk = lbiu_clk;
+	gd->lclk_clk = lclk_clk;
+	gd->mem_clk = mem_clk;
+#if defined(CONFIG_MPC8360)
+	gd->mem_sec_clk = mem_sec_clk;
+#endif
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+	gd->qe_clk = qe_clk;
+	gd->brg_clk = brg_clk;
+#endif
+#if defined(CONFIG_MPC837x)
+	gd->pciexp1_clk = pciexp1_clk;
+	gd->pciexp2_clk = pciexp2_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+	gd->sata_clk = sata_clk;
+#endif
+	gd->pci_clk = pci_sync_in;
+	gd->cpu_clk = gd->core_clk;
+	gd->bus_clk = gd->csb_clk;
+	return 0;
+
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq(ulong dummy)
+{
+	return gd->csb_clk;
+}
+
+int do_clocks (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	char buf[32];
+
+	printf("Clock configuration:\n");
+	printf("  Core:                %-4s MHz\n", strmhz(buf, gd->core_clk));
+	printf("  Coherent System Bus: %-4s MHz\n", strmhz(buf, gd->csb_clk));
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x)
+	printf("  QE:                  %-4s MHz\n", strmhz(buf, gd->qe_clk));
+	printf("  BRG:                 %-4s MHz\n", strmhz(buf, gd->brg_clk));
+#endif
+	printf("  Local Bus Controller:%-4s MHz\n", strmhz(buf, gd->lbiu_clk));
+	printf("  Local Bus:           %-4s MHz\n", strmhz(buf, gd->lclk_clk));
+	printf("  DDR:                 %-4s MHz\n", strmhz(buf, gd->mem_clk));
+#if defined(CONFIG_MPC8360)
+	printf("  DDR Secondary:       %-4s MHz\n", strmhz(buf, gd->mem_sec_clk));
+#endif
+	printf("  SEC:                 %-4s MHz\n", strmhz(buf, gd->enc_clk));
+	printf("  I2C1:                %-4s MHz\n", strmhz(buf, gd->i2c1_clk));
+#if !defined(CONFIG_MPC832x)
+	printf("  I2C2:                %-4s MHz\n", strmhz(buf, gd->i2c2_clk));
+#endif
+#if defined(CONFIG_MPC8315)
+	printf("  TDM:                 %-4s MHz\n", strmhz(buf, gd->tdm_clk));
+#endif
+#if defined(CONFIG_MPC837x)
+	printf("  SDHC:                %-4s MHz\n", strmhz(buf, gd->sdhc_clk));
+#endif
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x)
+	printf("  TSEC1:               %-4s MHz\n", strmhz(buf, gd->tsec1_clk));
+	printf("  TSEC2:               %-4s MHz\n", strmhz(buf, gd->tsec2_clk));
+	printf("  USB DR:              %-4s MHz\n", strmhz(buf, gd->usbdr_clk));
+#endif
+#if defined(CONFIG_MPC834x)
+	printf("  USB MPH:             %-4s MHz\n", strmhz(buf, gd->usbmph_clk));
+#endif
+#if defined(CONFIG_MPC837x)
+	printf("  PCIEXP1:             %-4s MHz\n", strmhz(buf, gd->pciexp1_clk));
+	printf("  PCIEXP2:             %-4s MHz\n", strmhz(buf, gd->pciexp2_clk));
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+	printf("  SATA:                %-4s MHz\n", strmhz(buf, gd->sata_clk));
+#endif
+	return 0;
+}
+
+U_BOOT_CMD(clocks, 1, 0, do_clocks,
+	"print clock configuration",
+	"    clocks"
+);
diff --git a/arch/ppc/cpu/mpc83xx/start.S b/arch/ppc/cpu/mpc83xx/start.S
new file mode 100644
index 0000000..68bb620
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/start.S
@@ -0,0 +1,1207 @@
+/*
+ * Copyright (C) 1998  Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999  Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
+ * Copyright Freescale Semiconductor, Inc. 2004, 2006, 2008.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ *  U-Boot - Startup Code for MPC83xx PowerPC based Embedded Boards
+ */
+
+#include <config.h>
+#include <mpc83xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_83XX	1		/* needed for Linux kernel header files*/
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING "MPC83XX"
+#endif
+
+/* We don't want the  MMU yet.
+ */
+#undef	MSR_KERNEL
+
+/*
+ * Floating Point enable, Machine Check and Recoverable Interr.
+ */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SYS_RAMBOOT)
+#define CONFIG_SYS_FLASHBOOT
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(__bss_start)
+	GOT_ENTRY(_end)
+
+#ifndef CONFIG_NAND_SPL
+	GOT_ENTRY(_FIXUP_TABLE_)
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+#endif
+	END_GOT
+
+/*
+ * The Hard Reset Configuration Word (HRCW) table is in the first 64
+ * (0x40) bytes of flash.  It has 8 bytes, but each byte is repeated 8
+ * times so the processor can fetch it out of flash whether the flash
+ * is 8, 16, 32, or 64 bits wide (hardware trickery).
+ */
+	.text
+#define _HRCW_TABLE_ENTRY(w)		\
+	.fill	8,1,(((w)>>24)&0xff);	\
+	.fill	8,1,(((w)>>16)&0xff);	\
+	.fill	8,1,(((w)>> 8)&0xff);	\
+	.fill	8,1,(((w)    )&0xff)
+
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_LOW)
+	_HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_HIGH)
+
+/*
+ * Magic number and version string - put it after the HRCW since it
+ * cannot be first in flash like it is in many other processors.
+ */
+	.long	0x27051956		/* U-Boot Magic Number */
+
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii " ", CONFIG_IDENT_STRING, "\0"
+
+	.align 2
+
+	.globl enable_addr_trans
+enable_addr_trans:
+	/* enable address translation */
+	mfmsr	r5
+	ori	r5, r5, (MSR_IR | MSR_DR)
+	mtmsr	r5
+	isync
+	blr
+
+	.globl disable_addr_trans
+disable_addr_trans:
+	/* disable address translation */
+	mflr	r4
+	mfmsr	r3
+	andi.	r0, r3, (MSR_IR | MSR_DR)
+	beqlr
+	andc	r3, r3, r0
+	mtspr	SRR0, r4
+	mtspr	SRR1, r3
+	rfi
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+	.globl	ppcDWstore
+ppcDWstore:
+	lfd	1, 0(r4)
+	stfd	1, 0(r3)
+	blr
+
+	.globl	ppcDWload
+ppcDWload:
+	lfd	1, 0(r3)
+	stfd	1, 0(r4)
+	blr
+
+#ifndef CONFIG_DEFAULT_IMMR
+#error CONFIG_DEFAULT_IMMR must be defined
+#endif /* CONFIG_SYS_DEFAULT_IMMR */
+#ifndef CONFIG_SYS_IMMR
+#define CONFIG_SYS_IMMR CONFIG_DEFAULT_IMMR
+#endif /* CONFIG_SYS_IMMR */
+
+/*
+ * After configuration, a system reset exception is executed using the
+ * vector at offset 0x100 relative to the base set by MSR[IP]. If
+ * MSR[IP] is 0, the base address is 0x00000000. If MSR[IP] is 1, the
+ * base address is 0xfff00000. In the case of a Power On Reset or Hard
+ * Reset, the value of MSR[IP] is determined by the CIP field in the
+ * HRCW.
+ *
+ * Other bits in the HRCW set up the Base Address and Port Size in BR0.
+ * This determines the location of the boot ROM (flash or EPROM) in the
+ * processor's address space at boot time. As long as the HRCW is set up
+ * so that we eventually end up executing the code below when the
+ * processor executes the reset exception, the actual values used should
+ * not matter.
+ *
+ * Once we have got here, the address mask in OR0 is cleared so that the
+ * bottom 32K of the boot ROM is effectively repeated all throughout the
+ * processor's address space, after which we can jump to the absolute
+ * address at which the boot ROM was linked at compile time, and proceed
+ * to initialise the memory controller without worrying if the rug will
+ * be pulled out from under us, so to speak (it will be fine as long as
+ * we configure BR0 with the same boot ROM link address).
+ */
+	. = EXC_OFF_SYS_RESET
+
+	.globl	_start
+_start: /* time t 0 */
+	li	r21, BOOTFLAG_COLD  /* Normal Power-On: Boot from FLASH*/
+	nop
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM	/* Software reboot	*/
+	b	boot_warm
+
+
+boot_cold: /* time t 3 */
+	lis	r4, CONFIG_DEFAULT_IMMR@h
+	nop
+boot_warm: /* time t 5 */
+	mfmsr	r5			/* save msr contents	*/
+
+	/* 83xx manuals prescribe a specific sequence for updating IMMRBAR. */
+	bl	1f
+1:	mflr	r7
+
+	lis	r3, CONFIG_SYS_IMMR@h
+	ori	r3, r3, CONFIG_SYS_IMMR@l
+
+	lwz	r6, IMMRBAR(r4)
+	isync
+
+	stw	r3, IMMRBAR(r4)
+	lwz	r6, 0(r7)		/* Arbitrary external load */
+	isync
+
+	lwz	r6, IMMRBAR(r3)
+	isync
+
+	/* Initialise the E300 processor core		*/
+	/*------------------------------------------*/
+
+#ifdef CONFIG_NAND_SPL
+	/* The FCM begins execution after only the first page
+	 * is loaded.  Wait for the rest before branching
+	 * to another flash page.
+	 */
+1:	lwz	r6, 0x50b0(r3)
+	andi.	r6, r6, 1
+	beq	1b
+#endif
+
+	bl	init_e300_core
+
+#ifdef CONFIG_SYS_FLASHBOOT
+
+	/* Inflate flash location so it appears everywhere, calculate */
+	/* the absolute address in final location of the FLASH, jump  */
+	/* there and deflate the flash size back to minimal size      */
+	/*------------------------------------------------------------*/
+	bl map_flash_by_law1
+	lis r4, (CONFIG_SYS_MONITOR_BASE)@h
+	ori r4, r4, (CONFIG_SYS_MONITOR_BASE)@l
+	addi r5, r4, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr r5
+	blr
+in_flash:
+#if 1 /* Remapping flash with LAW0. */
+	bl remap_flash_by_law0
+#endif
+#endif	/* CONFIG_SYS_FLASHBOOT */
+
+	/* setup the bats */
+	bl	setup_bats
+	sync
+
+	/*
+	 * Cache must be enabled here for stack-in-cache trick.
+	 * This means we need to enable the BATS.
+	 * This means:
+	 *   1) for the EVB, original gt regs need to be mapped
+	 *   2) need to have an IBAT for the 0xf region,
+	 *      we are running there!
+	 * Cache should be turned on after BATs, since by default
+	 * everything is write-through.
+	 * The init-mem BAT can be reused after reloc. The old
+	 * gt-regs BAT can be reused after board_init_f calls
+	 * board_early_init_f (EVB only).
+	 */
+	/* enable address translation */
+	bl	enable_addr_trans
+	sync
+
+	/* enable the data cache */
+	bl	dcache_enable
+	sync
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+	bl	lock_ram_in_cache
+	sync
+#endif
+
+	/* set up the stack pointer in our newly created
+	 * cache-ram (r1) */
+	lis	r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+	li	r0, 0		/* Make room for stack frame header and	*/
+	stwu	r0, -4(r1)	/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/
+
+
+	/* let the C-code set up the rest	                    */
+	/*				                            */
+	/* Be careful to keep code relocatable & stack humble   */
+	/*------------------------------------------------------*/
+
+	GET_GOT			/* initialize GOT access	*/
+
+	/* r3: IMMR */
+	lis	r3, CONFIG_SYS_IMMR@h
+	/* run low-level CPU init code (in Flash)*/
+	bl	cpu_init_f
+
+	/* r3: BOOTFLAG */
+	mr	r3, r21
+	/* run 1st part of board init code (in Flash)*/
+	bl	board_init_f
+
+#ifndef CONFIG_NAND_SPL
+/*
+ * Vector Table
+ */
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+#ifndef FIXME
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+#endif
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+	. = 0x1300
+	/*
+	 * This exception occurs when the program counter matches the
+	 * Instruction Address Breakpoint Register (IABR).
+	 *
+	 * I want the cpu to halt if this occurs so I can hunt around
+	 * with the debugger and look at things.
+	 *
+	 * When DEBUG is defined, both machine check enable (in the MSR)
+	 * and checkstop reset enable (in the reset mode register) are
+	 * turned off and so a checkstop condition will result in the cpu
+	 * halting.
+	 *
+	 * I force the cpu into a checkstop condition by putting an illegal
+	 * instruction here (at least this is the theory).
+	 *
+	 * well - that didnt work, so just do an infinite loop!
+	 */
+1:	b	1b
+#else
+	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+	STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+	STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+#endif /* !CONFIG_NAND_SPL */
+
+/*
+ * This code initialises the E300 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+	.globl	init_e300_core
+init_e300_core: /* time t 10 */
+	/* Initialize machine status; enable machine check interrupt */
+	/*-----------------------------------------------------------*/
+
+	li	r3, MSR_KERNEL			/* Set ME and RI flags */
+	rlwimi	r3, r5, 0, 25, 25	/* preserve IP bit set by HRCW */
+#ifdef DEBUG
+	rlwimi	r3, r5, 0, 21, 22   /* debugger might set SE & BE bits */
+#endif
+	SYNC						/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+	mtspr	SRR1, r3			/* Make SRR1 match MSR */
+
+
+	lis	r3, CONFIG_SYS_IMMR@h
+#if defined(CONFIG_WATCHDOG)
+	/* Initialise the Wathcdog values and reset it (if req) */
+	/*------------------------------------------------------*/
+	lis r4, CONFIG_SYS_WATCHDOG_VALUE
+	ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)
+	stw r4, SWCRR(r3)
+
+	/* and reset it */
+
+	li	r4, 0x556C
+	sth	r4, SWSRR@l(r3)
+	li	r4, -0x55C7
+	sth	r4, SWSRR@l(r3)
+#else
+	/* Disable Wathcdog  */
+	/*-------------------*/
+	lwz r4, SWCRR(r3)
+	/* Check to see if its enabled for disabling
+	   once disabled by SW you can't re-enable */
+	andi. r4, r4, 0x4
+	beq 1f
+	xor r4, r4, r4
+	stw r4, SWCRR(r3)
+1:
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_MASK_AER_AO)
+	/* Write the Arbiter Event Enable to mask Address Only traps. */
+	/* This prevents the dcbz instruction from being trapped when */
+	/* HID0_ABE Address Broadcast Enable is set and the MEMORY    */
+	/* COHERENCY bit is set in the WIMG bits, which is often      */
+	/* needed for PCI operation.                                  */
+	lwz	r4, 0x0808(r3)
+	rlwinm	r0, r4, 0, ~AER_AO
+	stw	r0, 0x0808(r3)
+#endif /* CONFIG_MASK_AER_AO */
+
+	/* Initialize the Hardware Implementation-dependent Registers */
+	/* HID0 also contains cache control			*/
+	/* - force invalidation of data and instruction caches  */
+	/*------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_HID0_INIT@h
+	ori	r3, r3, (CONFIG_SYS_HID0_INIT | HID0_ICFI | HID0_DCFI)@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID0_FINAL@h
+	ori	r3, r3, (CONFIG_SYS_HID0_FINAL & ~(HID0_ICFI | HID0_DCFI))@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CONFIG_SYS_HID2@h
+	ori	r3, r3, CONFIG_SYS_HID2@l
+	SYNC
+	mtspr	HID2, r3
+
+	/* Done!						*/
+	/*------------------------------*/
+	blr
+
+	/* setup_bats - set them up to some initial state */
+	.globl	setup_bats
+setup_bats:
+	addis	r0, r0, 0x0000
+
+	/* IBAT 0 */
+	addis	r4, r0, CONFIG_SYS_IBAT0L@h
+	ori	r4, r4, CONFIG_SYS_IBAT0L@l
+	addis	r3, r0, CONFIG_SYS_IBAT0U@h
+	ori	r3, r3, CONFIG_SYS_IBAT0U@l
+	mtspr	IBAT0L, r4
+	mtspr	IBAT0U, r3
+
+	/* DBAT 0 */
+	addis	r4, r0, CONFIG_SYS_DBAT0L@h
+	ori	r4, r4, CONFIG_SYS_DBAT0L@l
+	addis	r3, r0, CONFIG_SYS_DBAT0U@h
+	ori	r3, r3, CONFIG_SYS_DBAT0U@l
+	mtspr	DBAT0L, r4
+	mtspr	DBAT0U, r3
+
+	/* IBAT 1 */
+	addis	r4, r0, CONFIG_SYS_IBAT1L@h
+	ori	r4, r4, CONFIG_SYS_IBAT1L@l
+	addis	r3, r0, CONFIG_SYS_IBAT1U@h
+	ori	r3, r3, CONFIG_SYS_IBAT1U@l
+	mtspr	IBAT1L, r4
+	mtspr	IBAT1U, r3
+
+	/* DBAT 1 */
+	addis	r4, r0, CONFIG_SYS_DBAT1L@h
+	ori	r4, r4, CONFIG_SYS_DBAT1L@l
+	addis	r3, r0, CONFIG_SYS_DBAT1U@h
+	ori	r3, r3, CONFIG_SYS_DBAT1U@l
+	mtspr	DBAT1L, r4
+	mtspr	DBAT1U, r3
+
+	/* IBAT 2 */
+	addis	r4, r0, CONFIG_SYS_IBAT2L@h
+	ori	r4, r4, CONFIG_SYS_IBAT2L@l
+	addis	r3, r0, CONFIG_SYS_IBAT2U@h
+	ori	r3, r3, CONFIG_SYS_IBAT2U@l
+	mtspr	IBAT2L, r4
+	mtspr	IBAT2U, r3
+
+	/* DBAT 2 */
+	addis	r4, r0, CONFIG_SYS_DBAT2L@h
+	ori	r4, r4, CONFIG_SYS_DBAT2L@l
+	addis	r3, r0, CONFIG_SYS_DBAT2U@h
+	ori	r3, r3, CONFIG_SYS_DBAT2U@l
+	mtspr	DBAT2L, r4
+	mtspr	DBAT2U, r3
+
+	/* IBAT 3 */
+	addis	r4, r0, CONFIG_SYS_IBAT3L@h
+	ori	r4, r4, CONFIG_SYS_IBAT3L@l
+	addis	r3, r0, CONFIG_SYS_IBAT3U@h
+	ori	r3, r3, CONFIG_SYS_IBAT3U@l
+	mtspr	IBAT3L, r4
+	mtspr	IBAT3U, r3
+
+	/* DBAT 3 */
+	addis	r4, r0, CONFIG_SYS_DBAT3L@h
+	ori	r4, r4, CONFIG_SYS_DBAT3L@l
+	addis	r3, r0, CONFIG_SYS_DBAT3U@h
+	ori	r3, r3, CONFIG_SYS_DBAT3U@l
+	mtspr	DBAT3L, r4
+	mtspr	DBAT3U, r3
+
+#ifdef CONFIG_HIGH_BATS
+	/* IBAT 4 */
+	addis   r4, r0, CONFIG_SYS_IBAT4L@h
+	ori     r4, r4, CONFIG_SYS_IBAT4L@l
+	addis   r3, r0, CONFIG_SYS_IBAT4U@h
+	ori     r3, r3, CONFIG_SYS_IBAT4U@l
+	mtspr   IBAT4L, r4
+	mtspr   IBAT4U, r3
+
+	/* DBAT 4 */
+	addis   r4, r0, CONFIG_SYS_DBAT4L@h
+	ori     r4, r4, CONFIG_SYS_DBAT4L@l
+	addis   r3, r0, CONFIG_SYS_DBAT4U@h
+	ori     r3, r3, CONFIG_SYS_DBAT4U@l
+	mtspr   DBAT4L, r4
+	mtspr   DBAT4U, r3
+
+	/* IBAT 5 */
+	addis   r4, r0, CONFIG_SYS_IBAT5L@h
+	ori     r4, r4, CONFIG_SYS_IBAT5L@l
+	addis   r3, r0, CONFIG_SYS_IBAT5U@h
+	ori     r3, r3, CONFIG_SYS_IBAT5U@l
+	mtspr   IBAT5L, r4
+	mtspr   IBAT5U, r3
+
+	/* DBAT 5 */
+	addis   r4, r0, CONFIG_SYS_DBAT5L@h
+	ori     r4, r4, CONFIG_SYS_DBAT5L@l
+	addis   r3, r0, CONFIG_SYS_DBAT5U@h
+	ori     r3, r3, CONFIG_SYS_DBAT5U@l
+	mtspr   DBAT5L, r4
+	mtspr   DBAT5U, r3
+
+	/* IBAT 6 */
+	addis   r4, r0, CONFIG_SYS_IBAT6L@h
+	ori     r4, r4, CONFIG_SYS_IBAT6L@l
+	addis   r3, r0, CONFIG_SYS_IBAT6U@h
+	ori     r3, r3, CONFIG_SYS_IBAT6U@l
+	mtspr   IBAT6L, r4
+	mtspr   IBAT6U, r3
+
+	/* DBAT 6 */
+	addis   r4, r0, CONFIG_SYS_DBAT6L@h
+	ori     r4, r4, CONFIG_SYS_DBAT6L@l
+	addis   r3, r0, CONFIG_SYS_DBAT6U@h
+	ori     r3, r3, CONFIG_SYS_DBAT6U@l
+	mtspr   DBAT6L, r4
+	mtspr   DBAT6U, r3
+
+	/* IBAT 7 */
+	addis   r4, r0, CONFIG_SYS_IBAT7L@h
+	ori     r4, r4, CONFIG_SYS_IBAT7L@l
+	addis   r3, r0, CONFIG_SYS_IBAT7U@h
+	ori     r3, r3, CONFIG_SYS_IBAT7U@l
+	mtspr   IBAT7L, r4
+	mtspr   IBAT7U, r3
+
+	/* DBAT 7 */
+	addis   r4, r0, CONFIG_SYS_DBAT7L@h
+	ori     r4, r4, CONFIG_SYS_DBAT7L@l
+	addis   r3, r0, CONFIG_SYS_DBAT7U@h
+	ori     r3, r3, CONFIG_SYS_DBAT7U@l
+	mtspr   DBAT7L, r4
+	mtspr   DBAT7U, r3
+#endif
+
+	isync
+
+	/* invalidate all tlb's
+	 *
+	 * From the 603e User Manual: "The 603e provides the ability to
+	 * invalidate a TLB entry. The TLB Invalidate Entry (tlbie)
+	 * instruction invalidates the TLB entry indexed by the EA, and
+	 * operates on both the instruction and data TLBs simultaneously
+	 * invalidating four TLB entries (both sets in each TLB). The
+	 * index corresponds to bits 15-19 of the EA. To invalidate all
+	 * entries within both TLBs, 32 tlbie instructions should be
+	 * issued, incrementing this field by one each time."
+	 *
+	 * "Note that the tlbia instruction is not implemented on the
+	 * 603e."
+	 *
+	 * bits 15-19 correspond to addresses 0x00000000 to 0x0001F000
+	 * incrementing by 0x1000 each time. The code below is sort of
+	 * based on code in "flush_tlbs" from arch/ppc/kernel/head.S
+	 *
+	 */
+	lis	r3, 0
+	lis	r5, 2
+
+1:
+	tlbie	r3
+	addi	r3, r3, 0x1000
+	cmp	0, 0, r3, r5
+	blt	1b
+
+	blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+	.globl	icache_enable
+icache_enable:
+	mfspr	r3, HID0
+	ori	r3, r3, HID0_ICE
+	li	r4, HID0_ICFI|HID0_ILOCK
+	andc	r3, r3, r4
+	ori	r4, r3, HID0_ICFI
+	isync
+	mtspr	HID0, r4    /* sets enable and invalidate, clears lock */
+	isync
+	mtspr	HID0, r3	/* clears invalidate */
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r3, HID0
+	lis	r4, 0
+	ori	r4, r4, HID0_ICE|HID0_ICFI|HID0_ILOCK
+	andc	r3, r3, r4
+	isync
+	mtspr	HID0, r3	/* clears invalidate, enable and lock */
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	ori	r3, r3, HID0_DCE
+	sync
+	mtspr	HID0, r3		/* enable, no invalidate */
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mflr	r4
+	bl	flush_dcache		/* uses r3 and r5 */
+	mfspr	r3, HID0
+	li	r5, HID0_DCE|HID0_DLOCK
+	andc	r3, r3, r5
+	ori	r5, r3, HID0_DCFI
+	sync
+	mtspr	HID0, r5	/* sets invalidate, clears enable and lock */
+	sync
+	mtspr	HID0, r3	/* clears invalidate */
+	mtlr	r4
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31
+	blr
+
+	.globl	flush_dcache
+flush_dcache:
+	lis	r3, 0
+	lis	r5, CONFIG_SYS_CACHELINE_SIZE
+1:	cmp	0, 1, r3, r5
+	bge	2f
+	lwz	r5, 0(r3)
+	lis	r5, CONFIG_SYS_CACHELINE_SIZE
+	addi	r3, r3, 0x4
+	b	1b
+2:	blr
+
+/*-------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3		/* Set new stack pointer	*/
+	mr	r9,  r4		/* Save copy of Global Data pointer */
+	mr	r10, r5		/* Save copy of Destination Address */
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address */
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address */
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__bss_start)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size */
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE)
+	 *		+ Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary */
+	beq	7f		/* Protect against 0 count	  */
+	mtctr	r0
+	bge	cr1,2f
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+
+	/* copy */
+1:	lwzu	r0,4(r8)
+	stwu	r0,4(r7)
+	bdnz	1b
+
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	mtctr	r0
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+
+	/* and compare */
+20:	lwzu	r20,4(r8)
+	lwzu	r21,4(r7)
+	xor. r22, r20, r21
+	bne  30f
+	bdnz	20b
+	b 4f
+
+	/* compare failed */
+30:	li r3, 0
+	blr
+
+2:	slwi	r0,r0,2 /* re copy in reverse order ... y do we needed it? */
+	add	r8,r4,r0
+	add	r7,r3,r0
+3:	lwzu	r0,-4(r8)
+	stwu	r0,-4(r7)
+	bdnz	3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4:	cmpwi	r6,0
+	add	r5,r3,r5
+	beq	7f		/* Always flush prefetch queue in any case */
+	subi	r0,r6,1
+	andc	r3,r3,r0
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+#ifndef CONFIG_NAND_SPL
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+#endif
+
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+#if defined(CONFIG_HYMOD)
+	/*
+	 * For HYMOD - the environment is the very last item in flash.
+	 * The real .bss stops just before environment starts, so only
+	 * clear up to that point.
+	 *
+	 * taken from mods for FADS board
+	 */
+	lwz	r4,GOT(environment)
+#else
+	lwz	r4,GOT(_end)
+#endif
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+#ifndef CONFIG_NAND_SPL
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4		/* save link register */
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100	/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr			/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	4b
+
+	mfmsr	r3			/* now that the vectors have */
+	lis	r7, MSR_IP@h		/* relocated into low memory */
+	ori	r7, r7, MSR_IP@l	/* MSR[IP] can be turned off */
+	andc	r3, r3, r7		/* (if it was on) */
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r3
+	SYNC
+
+	mtlr	r4			/* restore link register    */
+	blr
+
+#endif /* !CONFIG_NAND_SPL */
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+	/* Allocate Initial RAM in data cache.
+	 */
+	lis	r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+	ori	r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+	li	r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+		     (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+	mtctr	r4
+1:
+	dcbz	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+
+	/* Lock the data cache */
+	mfspr	r0, HID0
+	ori	r0, r0, HID0_DLOCK
+	sync
+	mtspr	HID0, r0
+	sync
+	blr
+
+#ifndef CONFIG_NAND_SPL
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+	/* invalidate the INIT_RAM section */
+	lis	r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+	ori	r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+	li	r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+		     (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+	mtctr	r4
+1:	icbi	r0, r3
+	dcbi	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+	/* Unlock the data cache and invalidate it */
+	mfspr   r3, HID0
+	li	r5, HID0_DLOCK|HID0_DCFI
+	andc	r3, r3, r5		/* no invalidate, unlock */
+	ori	r5, r3, HID0_DCFI	/* invalidate, unlock */
+	sync
+	mtspr	HID0, r5		/* invalidate, unlock */
+	sync
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	blr
+#endif /* !CONFIG_NAND_SPL */
+#endif /* CONFIG_SYS_INIT_RAM_LOCK */
+
+#ifdef CONFIG_SYS_FLASHBOOT
+map_flash_by_law1:
+	/* When booting from ROM (Flash or EPROM), clear the  */
+	/* Address Mask in OR0 so ROM appears everywhere      */
+	/*----------------------------------------------------*/
+	lis	r3, (CONFIG_SYS_IMMR)@h  /* r3 <= CONFIG_SYS_IMMR    */
+	lwz	r4, OR0@l(r3)
+	li	r5, 0x7fff        /* r5 <= 0x00007FFFF */
+	and	r4, r4, r5
+	stw	r4, OR0@l(r3)     /* OR0 <= OR0 & 0x00007FFFF */
+
+	/* As MPC8349E User's Manual presented, when RCW[BMS] is set to 0,
+	 * system will boot from 0x0000_0100, and the LBLAWBAR0[BASE_ADDR]
+	 * reset value is 0x00000; when RCW[BMS] is set to 1, system will boot
+	 * from 0xFFF0_0100, and the LBLAWBAR0[BASE_ADDR] reset value is
+	 * 0xFF800.  From the hard resetting to here, the processor fetched and
+	 * executed the instructions one by one.  There is not absolutely
+	 * jumping happened.  Laterly, the u-boot code has to do an absolutely
+	 * jumping to tell the CPU instruction fetching component what the
+	 * u-boot TEXT base address is.  Because the TEXT base resides in the
+	 * boot ROM memory space, to garantee the code can run smoothly after
+	 * that jumping, we must map in the entire boot ROM by Local Access
+	 * Window.  Sometimes, we desire an non-0x00000 or non-0xFF800 starting
+	 * address for boot ROM, such as 0xFE000000.  In this case, the default
+	 * LBIU Local Access Widow 0 will not cover this memory space.  So, we
+	 * need another window to map in it.
+	 */
+	lis r4, (CONFIG_SYS_FLASH_BASE)@h
+	ori r4, r4, (CONFIG_SYS_FLASH_BASE)@l
+	stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CONFIG_SYS_FLASH_BASE */
+
+	/* Store 0x80000012 + log2(CONFIG_SYS_FLASH_SIZE) into LBLAWAR1 */
+	lis r4, (0x80000012)@h
+	ori r4, r4, (0x80000012)@l
+	li r5, CONFIG_SYS_FLASH_SIZE
+1:	srawi. r5, r5, 1	/* r5 = r5 >> 1 */
+	addi r4, r4, 1
+	bne 1b
+
+	stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 8MB Flash Size */
+	blr
+
+	/* Though all the LBIU Local Access Windows and LBC Banks will be
+	 * initialized in the C code, we'd better configure boot ROM's
+	 * window 0 and bank 0 correctly at here.
+	 */
+remap_flash_by_law0:
+	/* Initialize the BR0 with the boot ROM starting address. */
+	lwz r4, BR0(r3)
+	li  r5, 0x7FFF
+	and r4, r4, r5
+	lis r5, (CONFIG_SYS_FLASH_BASE & 0xFFFF8000)@h
+	ori r5, r5, (CONFIG_SYS_FLASH_BASE & 0xFFFF8000)@l
+	or  r5, r5, r4
+	stw r5, BR0(r3) /* r5 <= (CONFIG_SYS_FLASH_BASE & 0xFFFF8000) | (BR0 & 0x00007FFF) */
+
+	lwz r4, OR0(r3)
+	lis r5, ~((CONFIG_SYS_FLASH_SIZE << 4) - 1)
+	or r4, r4, r5
+	stw r4, OR0(r3)
+
+	lis r4, (CONFIG_SYS_FLASH_BASE)@h
+	ori r4, r4, (CONFIG_SYS_FLASH_BASE)@l
+	stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CONFIG_SYS_FLASH_BASE */
+
+	/* Store 0x80000012 + log2(CONFIG_SYS_FLASH_SIZE) into LBLAWAR0 */
+	lis r4, (0x80000012)@h
+	ori r4, r4, (0x80000012)@l
+	li r5, CONFIG_SYS_FLASH_SIZE
+1:	srawi. r5, r5, 1 /* r5 = r5 >> 1 */
+	addi r4, r4, 1
+	bne 1b
+	stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= Flash Size */
+
+
+	xor r4, r4, r4
+	stw r4, LBLAWBAR1(r3)
+	stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */
+	blr
+#endif /* CONFIG_SYS_FLASHBOOT */
diff --git a/arch/ppc/cpu/mpc83xx/traps.c b/arch/ppc/cpu/mpc83xx/traps.c
new file mode 100644
index 0000000..9d71b8b
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/traps.c
@@ -0,0 +1,266 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware
+ * exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+#include <asm/mpc8349_pci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+#define END_OF_MEM	(gd->bd->bi_memstart + gd->bd->bi_memsize)
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	puts ("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			putc ('\n');
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	putc ('\n');
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	putc ('\n');
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0) {
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			putc ('\n');
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+#ifdef CONFIG_PCI
+void dump_pci (void)
+{
+/*
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	printf ("PCI: err status %x err mask %x err ctrl %x\n",
+		le32_to_cpu (immap->im_pci.pci_esr),
+		le32_to_cpu (immap->im_pci.pci_emr),
+		le32_to_cpu (immap->im_pci.pci_ecr));
+	printf ("     error address %x error data %x ctrl %x\n",
+		le32_to_cpu (immap->im_pci.pci_eacr),
+		le32_to_cpu (immap->im_pci.pci_edcr),
+		le32_to_cpu (immap->im_pci.pci_eccr));
+*/
+}
+#endif
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+#ifdef CONFIG_PCI
+#if 0
+	volatile immap_t *immap  = (immap_t *)CONFIG_SYS_IMMR;
+#ifdef DEBUG
+	dump_pci();
+#endif
+	/* clear the error in the error status register */
+	if(immap->im_pci.pci_esr & cpu_to_le32(PCI_ERROR_PCI_NO_RSP)) {
+		immap->im_pci.pci_esr = cpu_to_le32(PCI_ERROR_PCI_NO_RSP);
+		return;
+	}
+#endif
+#endif /* CONFIG_PCI */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	puts ("Machine check in kernel mode.\n"
+		"Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		puts ("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13):
+		puts ("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		puts ("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		puts ("Address parity signal\n");
+		break;
+	default:
+		puts ("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_PCI
+	dump_pci();
+#endif
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+	printf("Debugger trap at @ %lx\n", regs->nip );
+	show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+	do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc83xx/u-boot.lds b/arch/ppc/cpu/mpc83xx/u-boot.lds
new file mode 100644
index 0000000..157cef6
--- /dev/null
+++ b/arch/ppc/cpu/mpc83xx/u-boot.lds
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    arch/ppc/cpu/mpc83xx/start.o	(.text)
+    *(.text)
+    *(.got1)
+    . = ALIGN(16);
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(4);
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+ENTRY(_start)
diff --git a/arch/ppc/cpu/mpc85xx/Makefile b/arch/ppc/cpu/mpc85xx/Makefile
new file mode 100644
index 0000000..f064fee
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/Makefile
@@ -0,0 +1,95 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao,X.Xiao@motorola.com
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o resetvec.o
+SOBJS-$(CONFIG_MP)	+= release.o
+SOBJS	= $(SOBJS-y)
+
+COBJS-$(CONFIG_CPM2)	+= commproc.o
+
+# supports ddr1
+COBJS-$(CONFIG_MPC8540) += ddr-gen1.o
+COBJS-$(CONFIG_MPC8560) += ddr-gen1.o
+COBJS-$(CONFIG_MPC8541) += ddr-gen1.o
+COBJS-$(CONFIG_MPC8555) += ddr-gen1.o
+
+# supports ddr1/2
+COBJS-$(CONFIG_MPC8548) += ddr-gen2.o
+COBJS-$(CONFIG_MPC8568) += ddr-gen2.o
+COBJS-$(CONFIG_MPC8544) += ddr-gen2.o
+
+# supports ddr1/2/3
+COBJS-$(CONFIG_MPC8572) += ddr-gen3.o
+COBJS-$(CONFIG_MPC8536) += ddr-gen3.o
+COBJS-$(CONFIG_MPC8569)	+= ddr-gen3.o
+COBJS-$(CONFIG_P1011)	+= ddr-gen3.o
+COBJS-$(CONFIG_P1012)	+= ddr-gen3.o
+COBJS-$(CONFIG_P1013)	+= ddr-gen3.o
+COBJS-$(CONFIG_P1020)	+= ddr-gen3.o
+COBJS-$(CONFIG_P1021)	+= ddr-gen3.o
+COBJS-$(CONFIG_P1022)	+= ddr-gen3.o
+COBJS-$(CONFIG_P2010)	+= ddr-gen3.o
+COBJS-$(CONFIG_P2020)	+= ddr-gen3.o
+COBJS-$(CONFIG_PPC_P4080)	+= ddr-gen3.o
+
+COBJS-$(CONFIG_CPM2)	+= ether_fcc.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-$(CONFIG_MP)	+= mp.o
+COBJS-$(CONFIG_MPC8536) += mpc8536_serdes.o
+COBJS-$(CONFIG_PCI)	+= pci.o
+COBJS-$(CONFIG_QE)	+= qe_io.o
+COBJS-$(CONFIG_CPM2)	+= serial_scc.o
+
+COBJS	= $(COBJS-y)
+COBJS	+= cpu.o
+COBJS	+= cpu_init.o
+COBJS	+= cpu_init_early.o
+COBJS	+= interrupts.o
+COBJS	+= speed.o
+COBJS	+= tlb.o
+COBJS	+= traps.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc85xx/commproc.c b/arch/ppc/cpu/mpc85xx/commproc.c
new file mode 100644
index 0000000..594aace
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/commproc.c
@@ -0,0 +1,205 @@
+/*
+ * Adapted for Motorola MPC8560 chips
+ * Xianghua Xiao <x.xiao@motorola.com>
+ *
+ * This file is based on "arch/ppc/8260_io/commproc.c" - here is it's
+ * copyright notice:
+ *
+ * General Purpose functions for the global management of the
+ * 8220 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ *	2.3.99 Updates
+ * Copyright (c) 2003 Motorola,Inc.
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ */
+#include <common.h>
+#include <asm/cpm_85xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * because we have stack and init data in dual port ram
+ * we must reduce the size
+ */
+#undef	CPM_DATAONLY_SIZE
+#define CPM_DATAONLY_SIZE	((uint)(8 * 1024) - CPM_DATAONLY_BASE)
+
+void
+m8560_cpm_reset(void)
+{
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	volatile ulong count;
+
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Reclaim the DP memory for our use.
+	*/
+	gd->dp_alloc_base = CPM_DATAONLY_BASE;
+	gd->dp_alloc_top = gd->dp_alloc_base + CPM_DATAONLY_SIZE;
+
+	/*
+	 * Reset CPM
+	 */
+	cpm->im_cpm_cp.cpcr = CPM_CR_RST;
+	count = 0;
+	do {			/* Spin until command processed		*/
+		__asm__ __volatile__ ("eieio");
+	} while ((cpm->im_cpm_cp.cpcr & CPM_CR_FLG) && ++count < 1000000);
+}
+
+/* Allocate some memory from the dual ported ram.
+ * To help protocols with object alignment restrictions, we do that
+ * if they ask.
+ */
+uint
+m8560_cpm_dpalloc(uint size, uint align)
+{
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	uint	retloc;
+	uint	align_mask, off;
+	uint	savebase;
+
+	align_mask = align - 1;
+	savebase = gd->dp_alloc_base;
+
+	if ((off = (gd->dp_alloc_base & align_mask)) != 0)
+		gd->dp_alloc_base += (align - off);
+
+	if ((off = size & align_mask) != 0)
+		size += align - off;
+
+	if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top) {
+		gd->dp_alloc_base = savebase;
+		panic("m8560_cpm_dpalloc: ran out of dual port ram!");
+	}
+
+	retloc = gd->dp_alloc_base;
+	gd->dp_alloc_base += size;
+
+	memset((void *)&(cpm->im_dprambase[retloc]), 0, size);
+
+	return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8560_cpm_hostalloc(uint size, uint align)
+{
+	/* the host might not even have RAM yet - just use dual port RAM */
+	return (m8560_cpm_dpalloc(size, align));
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks.  The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers).  Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK	gd->brg_clk
+#define BRG_UART_CLK	((BRG_INT_CLK + 15) / 16)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+m8560_cpm_setbrg(uint brg, uint rate)
+{
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	if (brg < 4) {
+		bp = (uint *)&(cpm->im_cpm_brg1.brgc1);
+	}
+	else {
+		bp = (uint *)&(cpm->im_cpm_brg2.brgc5);
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = (((((BRG_UART_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+m8560_cpm_fastbrg(uint brg, uint rate, int div16)
+{
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	if (brg < 4) {
+		bp = (uint *)&(cpm->im_cpm_brg1.brgc1);
+	}
+	else {
+		bp = (uint *)&(cpm->im_cpm_brg2.brgc5);
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+	if (div16)
+		*bp |= CPM_BRG_DIV16;
+}
+
+/* This function is used to set baud rate generators using an external
+ * clock source and 16x oversampling.
+ */
+
+void
+m8560_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel)
+{
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	volatile uint	*bp;
+
+	if (brg < 4) {
+		bp = (uint *)&(cpm->im_cpm_brg1.brgc1);
+	}
+	else {
+		bp = (uint *)&(cpm->im_cpm_brg2.brgc5);
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+	if (pinsel == 0)
+		*bp |= CPM_BRG_EXTC_CLK3_9;
+	else
+		*bp |= CPM_BRG_EXTC_CLK5_15;
+}
+
+#ifdef CONFIG_POST
+
+void post_word_store (ulong a)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_POST_WORD_ADDR);
+
+	*save_addr = a;
+}
+
+ulong post_word_load (void)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_POST_WORD_ADDR);
+
+	return *save_addr;
+}
+
+#endif	/* CONFIG_POST */
diff --git a/arch/ppc/cpu/mpc85xx/config.mk b/arch/ppc/cpu/mpc85xx/config.mk
new file mode 100644
index 0000000..ffb813d
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/config.mk
@@ -0,0 +1,35 @@
+#
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao, X.Xiao@motorola.com
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -ffixed-r2 -Wa,-me500 -msoft-float -mno-string
+
+# -mspe=yes is needed to have -mno-spe accepted by a buggy GCC;
+# see "[PATCH,rs6000] make -mno-spe work as expected" on
+# http://gcc.gnu.org/ml/gcc-patches/2008-04/msg00311.html
+PLATFORM_CPPFLAGS +=$(call cc-option,-mspe=yes)
+PLATFORM_CPPFLAGS +=$(call cc-option,-mno-spe)
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/mpc85xx/u-boot.lds
diff --git a/arch/ppc/cpu/mpc85xx/cpu.c b/arch/ppc/cpu/mpc85xx/cpu.c
new file mode 100644
index 0000000..0cc6e03
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/cpu.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2004,2007-2009 Freescale Semiconductor, Inc.
+ * (C) Copyright 2002, 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * (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 <config.h>
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <fsl_esdhc.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+	sys_info_t sysinfo;
+	uint pvr, svr;
+	uint fam;
+	uint ver;
+	uint major, minor;
+	struct cpu_type *cpu;
+	char buf1[32], buf2[32];
+#ifdef CONFIG_DDR_CLK_FREQ
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#ifdef CONFIG_FSL_CORENET
+	u32 ddr_sync = ((gur->rcwsr[5]) & FSL_CORENET_RCWSR5_DDR_SYNC)
+		>> FSL_CORENET_RCWSR5_DDR_SYNC_SHIFT;
+#else
+	u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO)
+		>> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT;
+#endif
+#else
+#ifdef CONFIG_FSL_CORENET
+	u32 ddr_sync = 0;
+#else
+	u32 ddr_ratio = 0;
+#endif
+#endif /* CONFIG_DDR_CLK_FREQ */
+	int i;
+
+	svr = get_svr();
+	major = SVR_MAJ(svr);
+#ifdef CONFIG_MPC8536
+	major &= 0x7; /* the msb of this nibble is a mfg code */
+#endif
+	minor = SVR_MIN(svr);
+
+	if (cpu_numcores() > 1) {
+#ifndef CONFIG_MP
+		puts("Unicore software on multiprocessor system!!\n"
+		     "To enable mutlticore build define CONFIG_MP\n");
+#endif
+		volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
+		printf("CPU%d:  ", pic->whoami);
+	} else {
+		puts("CPU:   ");
+	}
+
+	cpu = gd->cpu;
+
+	puts(cpu->name);
+	if (IS_E_PROCESSOR(svr))
+		puts("E");
+
+	printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
+
+	pvr = get_pvr();
+	fam = PVR_FAM(pvr);
+	ver = PVR_VER(pvr);
+	major = PVR_MAJ(pvr);
+	minor = PVR_MIN(pvr);
+
+	printf("Core:  ");
+	switch (fam) {
+	case PVR_FAM(PVR_85xx):
+	    puts("E500");
+	    break;
+	default:
+	    puts("Unknown");
+	    break;
+	}
+
+	if (PVR_MEM(pvr) == 0x03)
+		puts("MC");
+
+	printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr);
+
+	get_sys_info(&sysinfo);
+
+	puts("Clock Configuration:");
+	for (i = 0; i < cpu_numcores(); i++) {
+		if (!(i & 3))
+			printf ("\n       ");
+		printf("CPU%d:%-4s MHz, ",
+				i,strmhz(buf1, sysinfo.freqProcessor[i]));
+	}
+	printf("\n       CCB:%-4s MHz,\n", strmhz(buf1, sysinfo.freqSystemBus));
+
+#ifdef CONFIG_FSL_CORENET
+	if (ddr_sync == 1) {
+		printf("       DDR:%-4s MHz (%s MT/s data rate) "
+			"(Synchronous), ",
+			strmhz(buf1, sysinfo.freqDDRBus/2),
+			strmhz(buf2, sysinfo.freqDDRBus));
+	} else {
+		printf("       DDR:%-4s MHz (%s MT/s data rate) "
+			"(Asynchronous), ",
+			strmhz(buf1, sysinfo.freqDDRBus/2),
+			strmhz(buf2, sysinfo.freqDDRBus));
+	}
+#else
+	switch (ddr_ratio) {
+	case 0x0:
+		printf("       DDR:%-4s MHz (%s MT/s data rate), ",
+			strmhz(buf1, sysinfo.freqDDRBus/2),
+			strmhz(buf2, sysinfo.freqDDRBus));
+		break;
+	case 0x7:
+		printf("       DDR:%-4s MHz (%s MT/s data rate) "
+			"(Synchronous), ",
+			strmhz(buf1, sysinfo.freqDDRBus/2),
+			strmhz(buf2, sysinfo.freqDDRBus));
+		break;
+	default:
+		printf("       DDR:%-4s MHz (%s MT/s data rate) "
+			"(Asynchronous), ",
+			strmhz(buf1, sysinfo.freqDDRBus/2),
+			strmhz(buf2, sysinfo.freqDDRBus));
+		break;
+	}
+#endif
+
+	if (sysinfo.freqLocalBus > LCRR_CLKDIV) {
+		printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freqLocalBus));
+	} else {
+		printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n",
+		       sysinfo.freqLocalBus);
+	}
+
+#ifdef CONFIG_CPM2
+	printf("CPM:   %s MHz\n", strmhz(buf1, sysinfo.freqSystemBus));
+#endif
+
+#ifdef CONFIG_QE
+	printf("       QE:%-4s MHz\n", strmhz(buf1, sysinfo.freqQE));
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+	for (i = 0; i < CONFIG_SYS_NUM_FMAN; i++) {
+		printf("       FMAN%d: %s MHz\n", i,
+			strmhz(buf1, sysinfo.freqFMan[i]));
+	}
+#endif
+
+#ifdef CONFIG_SYS_DPAA_PME
+	printf("       PME:   %s MHz\n", strmhz(buf1, sysinfo.freqPME));
+#endif
+
+	puts("L1:    D-cache 32 kB enabled\n       I-cache 32 kB enabled\n");
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+/* Everything after the first generation of PQ3 parts has RSTCR */
+#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
+    defined(CONFIG_MPC8555) || defined(CONFIG_MPC8560)
+	unsigned long val, msr;
+
+	/*
+	 * Initiate hard reset in debug control register DBCR0
+	 * Make sure MSR[DE] = 1.  This only resets the core.
+	 */
+	msr = mfmsr ();
+	msr |= MSR_DE;
+	mtmsr (msr);
+
+	val = mfspr(DBCR0);
+	val |= 0x70000000;
+	mtspr(DBCR0,val);
+#else
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	out_be32(&gur->rstcr, 0x2);	/* HRESET_REQ */
+	udelay(100);
+#endif
+
+	return 1;
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+#ifdef CONFIG_FSL_CORENET
+	return (gd->bus_clk + 8) / 16;
+#else
+	return (gd->bus_clk + 4UL)/8UL;
+#endif
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+watchdog_reset(void)
+{
+	int re_enable = disable_interrupts();
+	reset_85xx_watchdog();
+	if (re_enable) enable_interrupts();
+}
+
+void
+reset_85xx_watchdog(void)
+{
+	/*
+	 * Clear TSR(WIS) bit by writing 1
+	 */
+	unsigned long val;
+	val = mfspr(SPRN_TSR);
+	val |= TSR_WIS;
+	mtspr(SPRN_TSR, val);
+}
+#endif	/* CONFIG_WATCHDOG */
+
+/*
+ * Configures a UPM. The function requires the respective MxMR to be set
+ * before calling this function. "size" is the number or entries, not a sizeof.
+ */
+void upmconfig (uint upm, uint * table, uint size)
+{
+	int i, mdr, mad, old_mad = 0;
+	volatile u32 *mxmr;
+	volatile ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR);
+	volatile u32 *brp,*orp;
+	volatile u8* dummy = NULL;
+	int upmmask;
+
+	switch (upm) {
+	case UPMA:
+		mxmr = &lbc->mamr;
+		upmmask = BR_MS_UPMA;
+		break;
+	case UPMB:
+		mxmr = &lbc->mbmr;
+		upmmask = BR_MS_UPMB;
+		break;
+	case UPMC:
+		mxmr = &lbc->mcmr;
+		upmmask = BR_MS_UPMC;
+		break;
+	default:
+		printf("%s: Bad UPM index %d to configure\n", __FUNCTION__, upm);
+		hang();
+	}
+
+	/* Find the address for the dummy write transaction */
+	for (brp = &lbc->br0, orp = &lbc->or0, i = 0; i < 8;
+		 i++, brp += 2, orp += 2) {
+
+		/* Look for a valid BR with selected UPM */
+		if ((in_be32(brp) & (BR_V | BR_MSEL)) == (BR_V | upmmask)) {
+			dummy = (volatile u8*)(in_be32(brp) & BR_BA);
+			break;
+		}
+	}
+
+	if (i == 8) {
+		printf("Error: %s() could not find matching BR\n", __FUNCTION__);
+		hang();
+	}
+
+	for (i = 0; i < size; i++) {
+		/* 1 */
+		out_be32(mxmr,  (in_be32(mxmr) & 0x4fffffc0) | MxMR_OP_WARR | i);
+		/* 2 */
+		out_be32(&lbc->mdr, table[i]);
+		/* 3 */
+		mdr = in_be32(&lbc->mdr);
+		/* 4 */
+		*(volatile u8 *)dummy = 0;
+		/* 5 */
+		do {
+			mad = in_be32(mxmr) & MxMR_MAD_MSK;
+		} while (mad <= old_mad && !(!mad && i == (size-1)));
+		old_mad = mad;
+	}
+	out_be32(mxmr, (in_be32(mxmr) & 0x4fffffc0) | MxMR_OP_NORM);
+}
+
+/*
+ * Initializes on-chip MMC controllers.
+ * to override, implement board_mmc_init()
+ */
+int cpu_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FSL_ESDHC
+	return fsl_esdhc_mmc_init(bis);
+#else
+	return 0;
+#endif
+}
diff --git a/arch/ppc/cpu/mpc85xx/cpu_init.c b/arch/ppc/cpu/mpc85xx/cpu_init.c
new file mode 100644
index 0000000..e0126d3
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/cpu_init.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2003 Motorola Inc.
+ * Modified by Xianghua Xiao, X.Xiao@motorola.com
+ *
+ * (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 <watchdog.h>
+#include <asm/processor.h>
+#include <ioports.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include "mp.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_MPC8536
+extern void fsl_serdes_init(void);
+#endif
+
+#ifdef CONFIG_QE
+extern qe_iop_conf_t qe_iop_conf_tab[];
+extern void qe_config_iopin(u8 port, u8 pin, int dir,
+				int open_drain, int assign);
+extern void qe_init(uint qe_base);
+extern void qe_reset(void);
+
+static void config_qe_ioports(void)
+{
+	u8      port, pin;
+	int     dir, open_drain, assign;
+	int     i;
+
+	for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) {
+		port		= qe_iop_conf_tab[i].port;
+		pin		= qe_iop_conf_tab[i].pin;
+		dir		= qe_iop_conf_tab[i].dir;
+		open_drain	= qe_iop_conf_tab[i].open_drain;
+		assign		= qe_iop_conf_tab[i].assign;
+		qe_config_iopin(port, pin, dir, open_drain, assign);
+	}
+}
+#endif
+
+#ifdef CONFIG_CPM2
+void config_8560_ioports (volatile ccsr_cpm_t * cpm)
+{
+	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 (cpm, 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->podr = (iop->podr & tpmsk) | podr;
+			iop->pdat = (iop->pdat & tpmsk) | pdat;
+			iop->pdir = (iop->pdir & tpmsk) | pdir;
+			iop->ppar |= ppar;
+		}
+	}
+}
+#endif
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map
+ * initialize a bunch of registers
+ */
+
+#ifdef CONFIG_FSL_CORENET
+static void corenet_tb_init(void)
+{
+	volatile ccsr_rcpm_t *rcpm =
+		(void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
+	volatile ccsr_pic_t *pic =
+		(void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
+	u32 whoami = in_be32(&pic->whoami);
+
+	/* Enable the timebase register for this core */
+	out_be32(&rcpm->ctbenrl, (1 << whoami));
+}
+#endif
+
+void cpu_init_f (void)
+{
+	volatile ccsr_lbc_t *memctl = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR);
+	extern void m8560_cpm_reset (void);
+#ifdef CONFIG_MPC8548
+	ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
+	uint svr = get_svr();
+
+	/*
+	 * CPU2 errata workaround: A core hang possible while executing
+	 * a msync instruction and a snoopable transaction from an I/O
+	 * master tagged to make quick forward progress is present.
+	 * Fixed in silicon rev 2.1.
+	 */
+	if ((SVR_MAJ(svr) == 1) || ((SVR_MAJ(svr) == 2 && SVR_MIN(svr) == 0x0)))
+		out_be32(&ecm->eebpcr, in_be32(&ecm->eebpcr) | (1 << 16));
+#endif
+
+	disable_tlb(14);
+	disable_tlb(15);
+
+#ifdef CONFIG_CPM2
+	config_8560_ioports((ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR);
+#endif
+
+	/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+	 * addresses - these have to be modified later when FLASH size
+	 * has been determined
+	 */
+#if defined(CONFIG_SYS_OR0_REMAP)
+	memctl->or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+	memctl->or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+
+	/* now restrict to preliminary range */
+	/* if cs1 is already set via debugger, leave cs0/cs1 alone */
+	if (! memctl->br1 & 1) {
+#if defined(CONFIG_SYS_BR0_PRELIM) && defined(CONFIG_SYS_OR0_PRELIM)
+		memctl->br0 = CONFIG_SYS_BR0_PRELIM;
+		memctl->or0 = CONFIG_SYS_OR0_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+		memctl->or1 = CONFIG_SYS_OR1_PRELIM;
+		memctl->br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+	}
+
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+	memctl->or2 = CONFIG_SYS_OR2_PRELIM;
+	memctl->br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+	memctl->or3 = CONFIG_SYS_OR3_PRELIM;
+	memctl->br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+	memctl->or4 = CONFIG_SYS_OR4_PRELIM;
+	memctl->br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+	memctl->or5 = CONFIG_SYS_OR5_PRELIM;
+	memctl->br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+	memctl->or6 = CONFIG_SYS_OR6_PRELIM;
+	memctl->br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+	memctl->or7 = CONFIG_SYS_OR7_PRELIM;
+	memctl->br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+#if defined(CONFIG_CPM2)
+	m8560_cpm_reset();
+#endif
+#ifdef CONFIG_QE
+	/* Config QE ioports */
+	config_qe_ioports();
+#endif
+#if defined(CONFIG_MPC8536)
+	fsl_serdes_init();
+#endif
+#if defined(CONFIG_FSL_DMA)
+	dma_init();
+#endif
+#ifdef CONFIG_FSL_CORENET
+	corenet_tb_init();
+#endif
+	init_used_tlb_cams();
+}
+
+
+/*
+ * Initialize L2 as cache.
+ *
+ * The newer 8548, etc, parts have twice as much cache, but
+ * use the same bit-encoding as the older 8555, etc, parts.
+ *
+ */
+
+int cpu_init_r(void)
+{
+	puts ("L2:    ");
+
+#if defined(CONFIG_L2_CACHE)
+	volatile ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
+	volatile uint cache_ctl;
+	uint svr, ver;
+	uint l2srbar;
+	u32 l2siz_field;
+
+	svr = get_svr();
+	ver = SVR_SOC_VER(svr);
+
+	asm("msync;isync");
+	cache_ctl = l2cache->l2ctl;
+
+#if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L2_ADDR)
+	if (cache_ctl & MPC85xx_L2CTL_L2E) {
+		/* Clear L2 SRAM memory-mapped base address */
+		out_be32(&l2cache->l2srbar0, 0x0);
+		out_be32(&l2cache->l2srbar1, 0x0);
+
+		/* set MBECCDIS=0, SBECCDIS=0 */
+		clrbits_be32(&l2cache->l2errdis,
+				(MPC85xx_L2ERRDIS_MBECC |
+				 MPC85xx_L2ERRDIS_SBECC));
+
+		/* set L2E=0, L2SRAM=0 */
+		clrbits_be32(&l2cache->l2ctl,
+				(MPC85xx_L2CTL_L2E |
+				 MPC85xx_L2CTL_L2SRAM_ENTIRE));
+	}
+#endif
+
+	l2siz_field = (cache_ctl >> 28) & 0x3;
+
+	switch (l2siz_field) {
+	case 0x0:
+		printf(" unknown size (0x%08x)\n", cache_ctl);
+		return -1;
+		break;
+	case 0x1:
+		if (ver == SVR_8540 || ver == SVR_8560   ||
+		    ver == SVR_8541 || ver == SVR_8541_E ||
+		    ver == SVR_8555 || ver == SVR_8555_E) {
+			puts("128 KB ");
+			/* set L2E=1, L2I=1, & L2BLKSZ=1 (128 Kbyte) */
+			cache_ctl = 0xc4000000;
+		} else {
+			puts("256 KB ");
+			cache_ctl = 0xc0000000; /* set L2E=1, L2I=1, & L2SRAM=0 */
+		}
+		break;
+	case 0x2:
+		if (ver == SVR_8540 || ver == SVR_8560   ||
+		    ver == SVR_8541 || ver == SVR_8541_E ||
+		    ver == SVR_8555 || ver == SVR_8555_E) {
+			puts("256 KB ");
+			/* set L2E=1, L2I=1, & L2BLKSZ=2 (256 Kbyte) */
+			cache_ctl = 0xc8000000;
+		} else {
+			puts ("512 KB ");
+			/* set L2E=1, L2I=1, & L2SRAM=0 */
+			cache_ctl = 0xc0000000;
+		}
+		break;
+	case 0x3:
+		puts("1024 KB ");
+		/* set L2E=1, L2I=1, & L2SRAM=0 */
+		cache_ctl = 0xc0000000;
+		break;
+	}
+
+	if (l2cache->l2ctl & MPC85xx_L2CTL_L2E) {
+		puts("already enabled");
+		l2srbar = l2cache->l2srbar0;
+#ifdef CONFIG_SYS_INIT_L2_ADDR
+		if (l2cache->l2ctl & MPC85xx_L2CTL_L2SRAM_ENTIRE
+				&& l2srbar >= CONFIG_SYS_FLASH_BASE) {
+			l2srbar = CONFIG_SYS_INIT_L2_ADDR;
+			l2cache->l2srbar0 = l2srbar;
+			printf("moving to 0x%08x", CONFIG_SYS_INIT_L2_ADDR);
+		}
+#endif /* CONFIG_SYS_INIT_L2_ADDR */
+		puts("\n");
+	} else {
+		asm("msync;isync");
+		l2cache->l2ctl = cache_ctl; /* invalidate & enable */
+		asm("msync;isync");
+		puts("enabled\n");
+	}
+#elif defined(CONFIG_BACKSIDE_L2_CACHE)
+	u32 l2cfg0 = mfspr(SPRN_L2CFG0);
+
+	/* invalidate the L2 cache */
+	mtspr(SPRN_L2CSR0, (L2CSR0_L2FI|L2CSR0_L2LFC));
+	while (mfspr(SPRN_L2CSR0) & (L2CSR0_L2FI|L2CSR0_L2LFC))
+		;
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+	/* set stash id to (coreID) * 2 + 32 + L2 (1) */
+	mtspr(SPRN_L2CSR1, (32 + 1));
+#endif
+
+	/* enable the cache */
+	mtspr(SPRN_L2CSR0, CONFIG_SYS_INIT_L2CSR0);
+
+	if (CONFIG_SYS_INIT_L2CSR0 & L2CSR0_L2E) {
+		while (!(mfspr(SPRN_L2CSR0) & L2CSR0_L2E))
+			;
+		printf("%d KB enabled\n", (l2cfg0 & 0x3fff) * 64);
+	}
+#else
+	puts("disabled\n");
+#endif
+#ifdef CONFIG_QE
+	uint qe_base = CONFIG_SYS_IMMR + 0x00080000; /* QE immr base */
+	qe_init(qe_base);
+	qe_reset();
+#endif
+
+#if defined(CONFIG_MP)
+	setup_mp();
+#endif
+	return 0;
+}
+
+extern void setup_ivors(void);
+
+void arch_preboot_os(void)
+{
+	u32 msr;
+
+	/*
+	 * We are changing interrupt offsets and are about to boot the OS so
+	 * we need to make sure we disable all async interrupts. EE is already
+	 * disabled by the time we get called.
+	 */
+	msr = mfmsr();
+	msr &= ~(MSR_ME|MSR_CE|MSR_DE);
+	mtmsr(msr);
+
+	setup_ivors();
+}
diff --git a/arch/ppc/cpu/mpc85xx/cpu_init_early.c b/arch/ppc/cpu/mpc85xx/cpu_init_early.c
new file mode 100644
index 0000000..32aa94b
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/cpu_init_early.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR_PHYS)
+#ifdef CONFIG_FSL_CORENET
+static void setup_ccsrbar(void)
+{
+	u32 temp;
+	volatile u32 *ccsr_virt = (volatile u32 *)(CONFIG_SYS_CCSRBAR + 0x1000);
+	volatile ccsr_local_t *ccm;
+
+	/*
+	 * We can't call set_law() because we haven't moved
+	 * CCSR yet.
+	 */
+	ccm = (void *)ccsr_virt;
+
+	out_be32(&ccm->law[0].lawbarh,
+		(u64)CONFIG_SYS_CCSRBAR_PHYS >> 32);
+	out_be32(&ccm->law[0].lawbarl, (u32)CONFIG_SYS_CCSRBAR_PHYS);
+	out_be32(&ccm->law[0].lawar,
+		LAW_EN | (0x1e << 20) | LAW_SIZE_4K);
+
+	in_be32((u32 *)(ccsr_virt + 0));
+	in_be32((u32 *)(ccsr_virt + 1));
+	isync();
+
+	ccm = (void *)CONFIG_SYS_CCSRBAR;
+	/* Now use the temporary LAW to move CCSR */
+	out_be32(&ccm->ccsrbarh, (u64)CONFIG_SYS_CCSRBAR_PHYS >> 32);
+	out_be32(&ccm->ccsrbarl, (u32)CONFIG_SYS_CCSRBAR_PHYS);
+	out_be32(&ccm->ccsrar, CCSRAR_C);
+	temp = in_be32(&ccm->ccsrar);
+	disable_law(0);
+}
+#else
+static void setup_ccsrbar(void)
+{
+	u32 temp;
+	volatile u32 *ccsr_virt = (volatile u32 *)(CONFIG_SYS_CCSRBAR + 0x1000);
+
+	temp = in_be32(ccsr_virt);
+	out_be32(ccsr_virt, CONFIG_SYS_CCSRBAR_PHYS >> 12);
+	temp = in_be32((volatile u32 *)CONFIG_SYS_CCSRBAR);
+}
+#endif
+#endif
+
+/* We run cpu_init_early_f in AS = 1 */
+void cpu_init_early_f(void)
+{
+	u32 mas0, mas1, mas2, mas3, mas7;
+	int i;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/*
+	 * Clear initial global data
+	 *   we don't use memset so we can share this code with NAND_SPL
+	 */
+	for (i = 0; i < sizeof(gd_t); i++)
+		((char *)gd)[i] = 0;
+
+	mas0 = MAS0_TLBSEL(0) | MAS0_ESEL(0);
+	mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_4K);
+	mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G);
+	mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS, 0, MAS3_SW|MAS3_SR);
+	mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_PHYS);
+
+	write_tlb(mas0, mas1, mas2, mas3, mas7);
+
+	/* set up CCSR if we want it moved */
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR_PHYS)
+	mas0 = MAS0_TLBSEL(0) | MAS0_ESEL(1);
+	/* mas1 is the same as above */
+	mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR + 0x1000, MAS2_I|MAS2_G);
+	mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_DEFAULT, 0, MAS3_SW|MAS3_SR);
+	mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_DEFAULT);
+
+	write_tlb(mas0, mas1, mas2, mas3, mas7);
+
+	setup_ccsrbar();
+#endif
+
+	init_laws();
+	invalidate_tlb(0);
+	init_tlbs();
+}
diff --git a/arch/ppc/cpu/mpc85xx/cpu_init_nand.c b/arch/ppc/cpu/mpc85xx/cpu_init_nand.c
new file mode 100644
index 0000000..184cca4
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/cpu_init_nand.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+void cpu_init_f(void)
+{
+	ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR);
+
+	/*
+	 * LCRR - Clock Ratio Register - set up local bus timing
+	 * when needed
+	 */
+	out_be32(&lbc->lcrr, LCRR_DBYP | LCRR_CLKDIV_8);
+
+#if defined(CONFIG_NAND_BR_PRELIM) && defined(CONFIG_NAND_OR_PRELIM)
+	out_be32(&lbc->br0, CONFIG_NAND_BR_PRELIM);
+	out_be32(&lbc->or0, CONFIG_NAND_OR_PRELIM);
+#else
+#error  CONFIG_NAND_BR_PRELIM, CONFIG_NAND_OR_PRELIM must be defined
+#endif
+
+#if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L2_ADDR)
+	ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
+	char *l2srbar;
+	int i;
+
+	out_be32(&l2cache->l2srbar0, CONFIG_SYS_INIT_L2_ADDR);
+
+	/* set MBECCDIS=1, SBECCDIS=1 */
+	out_be32(&l2cache->l2errdis,
+		(MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC));
+
+	/* set L2E=1 & L2SRAM=001 */
+	out_be32(&l2cache->l2ctl,
+		(MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE));
+
+	/* Initialize L2 SRAM to zero */
+	l2srbar = (char *)CONFIG_SYS_INIT_L2_ADDR;
+	for (i = 0; i < CONFIG_SYS_L2_SIZE; i++)
+		l2srbar[i] = 0;
+#endif
+}
diff --git a/arch/ppc/cpu/mpc85xx/ddr-gen1.c b/arch/ppc/cpu/mpc85xx/ddr-gen1.c
new file mode 100644
index 0000000..54437dd
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/ddr-gen1.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+			     unsigned int ctrl_num)
+{
+	unsigned int i;
+	volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR;
+
+	if (ctrl_num != 0) {
+		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+		return;
+	}
+
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		if (i == 0) {
+			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs0_config, regs->cs[i].config);
+
+		} else if (i == 1) {
+			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs1_config, regs->cs[i].config);
+
+		} else if (i == 2) {
+			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs2_config, regs->cs[i].config);
+
+		} else if (i == 3) {
+			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs3_config, regs->cs[i].config);
+		}
+	}
+
+	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+#if defined(CONFIG_MPC8555) || defined(CONFIG_MPC8541)
+	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+#endif
+
+	/*
+	 * 200 painful micro-seconds must elapse between
+	 * the DDR clock setup and the DDR config enable.
+	 */
+	udelay(200);
+	asm volatile("sync;isync");
+
+	out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
+
+	asm("sync;isync;msync");
+	udelay(500);
+}
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+
+void
+ddr_enable_ecc(unsigned int dram_size)
+{
+	volatile ccsr_ddr_t *ddr= (void *)(CONFIG_SYS_MPC85xx_DDR_ADDR);
+
+	dma_meminit(CONFIG_MEM_INIT_VALUE, dram_size);
+
+	/*
+	 * Enable errors for ECC.
+	 */
+	debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable);
+	ddr->err_disable = 0x00000000;
+	asm("sync;isync;msync");
+	debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable);
+}
+
+#endif	/* CONFIG_DDR_ECC  && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */
diff --git a/arch/ppc/cpu/mpc85xx/ddr-gen2.c b/arch/ppc/cpu/mpc85xx/ddr-gen2.c
new file mode 100644
index 0000000..655f99c
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/ddr-gen2.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+			     unsigned int ctrl_num)
+{
+	unsigned int i;
+	volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR;
+
+	if (ctrl_num) {
+		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+		return;
+	}
+
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		if (i == 0) {
+			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs0_config, regs->cs[i].config);
+
+		} else if (i == 1) {
+			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs1_config, regs->cs[i].config);
+
+		} else if (i == 2) {
+			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs2_config, regs->cs[i].config);
+
+		} else if (i == 3) {
+			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs3_config, regs->cs[i].config);
+		}
+	}
+
+	out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
+	out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
+	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+	out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+	out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+	out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
+	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+	out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
+	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+	out_be32(&ddr->init_addr, regs->ddr_init_addr);
+	out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+
+	/*
+	 * 200 painful micro-seconds must elapse between
+	 * the DDR clock setup and the DDR config enable.
+	 */
+	udelay(200);
+	asm volatile("sync;isync");
+
+	out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
+
+	/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done.  */
+	while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
+		udelay(10000);		/* throttle polling rate */
+	}
+}
diff --git a/arch/ppc/cpu/mpc85xx/ddr-gen3.c b/arch/ppc/cpu/mpc85xx/ddr-gen3.c
new file mode 100644
index 0000000..0691ca4
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/ddr-gen3.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+			     unsigned int ctrl_num)
+{
+	unsigned int i;
+	volatile ccsr_ddr_t *ddr;
+	u32 temp_sdram_cfg;
+
+	switch (ctrl_num) {
+	case 0:
+		ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR;
+		break;
+	case 1:
+		ddr = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR;
+		break;
+	default:
+		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+		return;
+	}
+
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		if (i == 0) {
+			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs0_config, regs->cs[i].config);
+			out_be32(&ddr->cs0_config_2, regs->cs[i].config_2);
+
+		} else if (i == 1) {
+			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs1_config, regs->cs[i].config);
+			out_be32(&ddr->cs1_config_2, regs->cs[i].config_2);
+
+		} else if (i == 2) {
+			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs2_config, regs->cs[i].config);
+			out_be32(&ddr->cs2_config_2, regs->cs[i].config_2);
+
+		} else if (i == 3) {
+			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs3_config, regs->cs[i].config);
+			out_be32(&ddr->cs3_config_2, regs->cs[i].config_2);
+		}
+	}
+
+	out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
+	out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
+	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+	out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+	out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+	out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
+	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+	out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
+	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+	out_be32(&ddr->init_addr, regs->ddr_init_addr);
+	out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+
+	out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4);
+	out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5);
+	out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
+	out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
+	out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
+	out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
+	out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
+
+	/* Set, but do not enable the memory */
+	temp_sdram_cfg = regs->ddr_sdram_cfg;
+	temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
+	out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+	/*
+	 * For 8572 DDR1 erratum - DDR controller may enter illegal state
+	 * when operatiing in 32-bit bus mode with 4-beat bursts,
+	 * This erratum does not affect DDR3 mode, only for DDR2 mode.
+	 */
+#ifdef CONFIG_MPC8572
+	if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2)
+	    && in_be32(&ddr->sdram_cfg) & 0x80000) {
+		/* set DEBUG_1[31] */
+		u32 temp = in_be32(&ddr->debug_1);
+		out_be32(&ddr->debug_1, temp | 1);
+	}
+#endif
+
+	/*
+	 * 500 painful micro-seconds must elapse between
+	 * the DDR clock setup and the DDR config enable.
+	 * DDR2 need 200 us, and DDR3 need 500 us from spec,
+	 * we choose the max, that is 500 us for all of case.
+	 */
+	udelay(500);
+	asm volatile("sync;isync");
+
+	/* Let the controller go */
+	temp_sdram_cfg = in_be32(&ddr->sdram_cfg);
+	out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
+
+	/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done.  */
+	while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
+		udelay(10000);		/* throttle polling rate */
+	}
+}
diff --git a/arch/ppc/cpu/mpc85xx/ether_fcc.c b/arch/ppc/cpu/mpc85xx/ether_fcc.c
new file mode 100644
index 0000000..5f1414d
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/ether_fcc.c
@@ -0,0 +1,469 @@
+/*
+ * MPC8560 FCC Fast Ethernet
+ * Copyright (c) 2003 Motorola,Inc.
+ * Xianghua Xiao, (X.Xiao@motorola.com)
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
+ *
+ * (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
+ */
+
+/*
+ * MPC8560 FCC Fast Ethernet
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * This code will not perform the IO port configuration. This should be
+ * done in the iop_conf_t structure specific for the board.
+ *
+ * TODO:
+ * add a PHY driver to do the negotiation
+ * reflect negotiation results in FPSMR
+ * look for ways to configure the board specific stuff elsewhere, eg.
+ *    config_xxx.h or the board directory
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/cpm_85xx.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET) && \
+	defined(CONFIG_NET_MULTI)
+
+static struct ether_fcc_info_s
+{
+	int ether_index;
+	int proff_enet;
+	ulong cpm_cr_enet_sblock;
+	ulong cpm_cr_enet_page;
+	ulong cmxfcr_mask;
+	ulong cmxfcr_value;
+}
+	ether_fcc_info[] =
+{
+#ifdef CONFIG_ETHER_ON_FCC1
+{
+	0,
+	PROFF_FCC1,
+	CPM_CR_FCC1_SBLOCK,
+	CPM_CR_FCC1_PAGE,
+	CONFIG_SYS_CMXFCR_MASK1,
+	CONFIG_SYS_CMXFCR_VALUE1
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC2
+{
+	1,
+	PROFF_FCC2,
+	CPM_CR_FCC2_SBLOCK,
+	CPM_CR_FCC2_PAGE,
+	CONFIG_SYS_CMXFCR_MASK2,
+	CONFIG_SYS_CMXFCR_VALUE2
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC3
+{
+	2,
+	PROFF_FCC3,
+	CPM_CR_FCC3_SBLOCK,
+	CPM_CR_FCC3_PAGE,
+	CONFIG_SYS_CMXFCR_MASK3,
+	CONFIG_SYS_CMXFCR_VALUE3
+},
+#endif
+};
+
+/*---------------------------------------------------------------------*/
+
+/* Maximum input DMA size.  Must be a should(?) be a multiple of 4. */
+#define PKT_MAXDMA_SIZE         1520
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets. */
+#define PKT_MAXBUF_SIZE         1518
+#define PKT_MINBUF_SIZE         64
+
+/* Maximum input buffer size.  Must be a multiple of 32. */
+#define PKT_MAXBLR_SIZE         1536
+
+#define TOUT_LOOP 1000000
+
+#define TX_BUF_CNT 2
+
+static uint rxIdx;	/* index of the current RX buffer */
+static uint txIdx;	/* index of the current TX buffer */
+
+/*
+ * FCC Ethernet Tx and Rx buffer descriptors.
+ * Provide for Double Buffering
+ * Note: PKTBUFSRX is defined in net.h
+ */
+
+typedef volatile struct rtxbd {
+    cbd_t rxbd[PKTBUFSRX];
+    cbd_t txbd[TX_BUF_CNT];
+} RTXBD;
+
+/*  Good news: the FCC supports external BDs! */
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+#undef ET_DEBUG
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length)
+{
+    int i = 0;
+    int result = 0;
+
+    if (length <= 0) {
+	printf("fec: bad packet size: %d\n", length);
+	goto out;
+    }
+
+    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+	if (i >= TOUT_LOOP) {
+	    printf("fec: tx buffer not ready\n");
+	    goto out;
+	}
+    }
+
+    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 | \
+			       BD_ENET_TX_TC | BD_ENET_TX_PAD);
+
+    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+	if (i >= TOUT_LOOP) {
+	    printf("fec: tx error\n");
+	    goto out;
+	}
+    }
+
+#ifdef ET_DEBUG
+    printf("cycles: 0x%x txIdx=0x%04x status: 0x%04x\n", i, txIdx,rtx.txbd[txIdx].cbd_sc);
+    printf("packets at 0x%08x, length_in_bytes=0x%x\n",(uint)packet,length);
+    for(i=0;i<(length/16 + 1);i++) {
+	 printf("%08x %08x %08x %08x\n",*((uint *)rtx.txbd[txIdx].cbd_bufaddr+i*4),\
+    *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 1),*((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 2), \
+    *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 3));
+    }
+#endif
+
+    /* return only status bits */
+    result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+    txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+out:
+    return result;
+}
+
+static int fec_recv(struct eth_device* dev)
+{
+    int length;
+
+    for (;;)
+    {
+	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) {
+	    printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
+	}
+	else {
+	    /* Pass the packet up to the protocol layers. */
+	    NetReceive(NetRxPackets[rxIdx], length - 4);
+	}
+
+
+	/* Give the buffer back to the FCC. */
+	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++;
+	}
+    }
+    return length;
+}
+
+
+static int fec_init(struct eth_device* dev, bd_t *bis)
+{
+    struct ether_fcc_info_s * info = dev->priv;
+    int i;
+    volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+    volatile ccsr_cpm_cp_t *cp = &(cpm->im_cpm_cp);
+    fcc_enet_t *pram_ptr;
+    unsigned long mem_addr;
+
+#if 0
+    mii_discover_phy();
+#endif
+
+    /* 28.9 - (1-2): ioports have been set up already */
+
+    /* 28.9 - (3): connect FCC's tx and rx clocks */
+    cpm->im_cpm_mux.cmxuar = 0; /* ATM */
+    cpm->im_cpm_mux.cmxfcr = (cpm->im_cpm_mux.cmxfcr & ~info->cmxfcr_mask) |
+							info->cmxfcr_value;
+
+    /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, set Mode Ethernet */
+    if(info->ether_index == 0) {
+	cpm->im_cpm_fcc1.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+    } else if (info->ether_index == 1) {
+	cpm->im_cpm_fcc2.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+    } else if (info->ether_index == 2) {
+	cpm->im_cpm_fcc3.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+    }
+
+    /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet,MII */
+    if(info->ether_index == 0) {
+	cpm->im_cpm_fcc1.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+    } else if (info->ether_index == 1){
+	cpm->im_cpm_fcc2.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+    } else if (info->ether_index == 2){
+	cpm->im_cpm_fcc3.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+    }
+
+    /* 28.9 - (6): FDSR: Ethernet Syn */
+    if(info->ether_index == 0) {
+	cpm->im_cpm_fcc1.fdsr = 0xD555;
+    } else if (info->ether_index == 1) {
+	cpm->im_cpm_fcc2.fdsr = 0xD555;
+    } else if (info->ether_index == 2) {
+	cpm->im_cpm_fcc3.fdsr = 0xD555;
+    }
+
+    /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
+    rxIdx = 0;
+    txIdx = 0;
+
+    /* Setup Receiver Buffer Descriptors */
+    for (i = 0; i < PKTBUFSRX; i++)
+    {
+      rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+      rtx.rxbd[i].cbd_datlen = 0;
+      rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+    }
+    rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+    /* Setup Ethernet Transmitter Buffer Descriptors */
+    for (i = 0; i < TX_BUF_CNT; i++)
+    {
+      rtx.txbd[i].cbd_sc = 0;
+      rtx.txbd[i].cbd_datlen = 0;
+      rtx.txbd[i].cbd_bufaddr = 0;
+    }
+    rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+    /* 28.9 - (7): initialize parameter ram */
+    pram_ptr = (fcc_enet_t *)&(cpm->im_dprambase[info->proff_enet]);
+
+    /* clear whole structure to make sure all reserved fields are zero */
+    memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
+
+    /*
+     * common Parameter RAM area
+     *
+     * Allocate space in the reserved FCC area of DPRAM for the
+     * internal buffers.  No one uses this space (yet), so we
+     * can do this.  Later, we will add resource management for
+     * this area.
+     * CPM_FCC_SPECIAL_BASE:	0xB000 for MPC8540, MPC8560
+     *				0x9000 for MPC8541, MPC8555
+     */
+    mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64);
+    pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
+    pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
+    /*
+     * Set maximum bytes per receive buffer.
+     * It must be a multiple of 32.
+     */
+    pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; /* 1536 */
+    /* localbus SDRAM should be preferred */
+    pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
+				       CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+    pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+    pram_ptr->fen_genfcc.fcc_rbdstat = 0;
+    pram_ptr->fen_genfcc.fcc_rbdlen = 0;
+    pram_ptr->fen_genfcc.fcc_rdptr = 0;
+    /* localbus SDRAM should be preferred */
+    pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
+				       CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+    pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
+    pram_ptr->fen_genfcc.fcc_tbdstat = 0;
+    pram_ptr->fen_genfcc.fcc_tbdlen = 0;
+    pram_ptr->fen_genfcc.fcc_tdptr = 0;
+
+    /* protocol-specific area */
+    pram_ptr->fen_statbuf = 0x0;
+    pram_ptr->fen_cmask = 0xdebb20e3;	/* CRC mask */
+    pram_ptr->fen_cpres = 0xffffffff;	/* CRC preset */
+    pram_ptr->fen_crcec = 0;
+    pram_ptr->fen_alec = 0;
+    pram_ptr->fen_disfc = 0;
+    pram_ptr->fen_retlim = 15;		/* Retry limit threshold */
+    pram_ptr->fen_retcnt = 0;
+    pram_ptr->fen_pper = 0;
+    pram_ptr->fen_boffcnt = 0;
+    pram_ptr->fen_gaddrh = 0;
+    pram_ptr->fen_gaddrl = 0;
+    pram_ptr->fen_mflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */
+    /*
+     * Set Ethernet station address.
+     *
+     * This is supplied in the board information structure, so we
+     * copy that into the controller.
+     * So far we have only been given one Ethernet address. We make
+     * it unique by setting a few bits in the upper byte of the
+     * non-static part of the address.
+     */
+#define ea eth_get_dev()->enetaddr
+    pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
+    pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
+    pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+    pram_ptr->fen_ibdcount = 0;
+    pram_ptr->fen_ibdstart = 0;
+    pram_ptr->fen_ibdend = 0;
+    pram_ptr->fen_txlen = 0;
+    pram_ptr->fen_iaddrh = 0;  /* disable hash */
+    pram_ptr->fen_iaddrl = 0;
+    pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register: 64 */
+    /* pad pointer. use tiptr since we don't need a specific padding char */
+    pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
+    pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE;	/* maximum DMA1 length:1520 */
+    pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE;	/* maximum DMA2 length:1520 */
+
+#if defined(ET_DEBUG)
+    printf("parm_ptr(0xff788500) = %p\n",pram_ptr);
+    printf("pram_ptr->fen_genfcc.fcc_rbase %08x\n",
+	pram_ptr->fen_genfcc.fcc_rbase);
+    printf("pram_ptr->fen_genfcc.fcc_tbase %08x\n",
+	pram_ptr->fen_genfcc.fcc_tbase);
+#endif
+
+    /* 28.9 - (8)(9): clear out events in FCCE */
+    /* 28.9 - (9): FCCM: mask all events */
+    if(info->ether_index == 0) {
+	cpm->im_cpm_fcc1.fcce = ~0x0;
+	cpm->im_cpm_fcc1.fccm = 0;
+    } else if (info->ether_index == 1) {
+	cpm->im_cpm_fcc2.fcce = ~0x0;
+	cpm->im_cpm_fcc2.fccm = 0;
+    } else if (info->ether_index == 2) {
+	cpm->im_cpm_fcc3.fcce = ~0x0;
+	cpm->im_cpm_fcc3.fccm = 0;
+    }
+
+    /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+    /* 28.9 - (13)
+     *
+     * Let's re-initialize the channel now.  We have to do it later
+     * than the manual describes because we have just now finished
+     * the BD initialization.
+     */
+    cp->cpcr = mk_cr_cmd(info->cpm_cr_enet_page,
+			    info->cpm_cr_enet_sblock,
+			    0x0c,
+			    CPM_CR_INIT_TRX) | CPM_CR_FLG;
+    do {
+	__asm__ __volatile__ ("eieio");
+    } while (cp->cpcr & CPM_CR_FLG);
+
+    /* 28.9 - (14): enable tx/rx in gfmr */
+    if(info->ether_index == 0) {
+	cpm->im_cpm_fcc1.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+    } else if (info->ether_index == 1) {
+	cpm->im_cpm_fcc2.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+    } else if (info->ether_index == 2) {
+	cpm->im_cpm_fcc3.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+    }
+
+    return 1;
+}
+
+static void fec_halt(struct eth_device* dev)
+{
+    struct ether_fcc_info_s * info = dev->priv;
+    volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+
+    /* write GFMR: disable tx/rx */
+    if(info->ether_index == 0) {
+	cpm->im_cpm_fcc1.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+    } else if(info->ether_index == 1) {
+	cpm->im_cpm_fcc2.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+    } else if(info->ether_index == 2) {
+	cpm->im_cpm_fcc3.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+    }
+}
+
+int fec_initialize(bd_t *bis)
+{
+	struct eth_device* dev;
+	int i;
+
+	for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+	{
+		dev = (struct eth_device*) malloc(sizeof *dev);
+		memset(dev, 0, sizeof *dev);
+
+		sprintf(dev->name, "FCC%d ETHERNET",
+			ether_fcc_info[i].ether_index + 1);
+		dev->priv   = &ether_fcc_info[i];
+		dev->init   = fec_init;
+		dev->halt   = fec_halt;
+		dev->send   = fec_send;
+		dev->recv   = fec_recv;
+
+		eth_register(dev);
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \
+		&& defined(CONFIG_BITBANGMII)
+		miiphy_register(dev->name,
+				bb_miiphy_read,	bb_miiphy_write);
+#endif
+	}
+
+	return 1;
+}
+
+#endif
diff --git a/arch/ppc/cpu/mpc85xx/fdt.c b/arch/ppc/cpu/mpc85xx/fdt.c
new file mode 100644
index 0000000..1d11ab4
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/fdt.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/processor.h>
+#include <linux/ctype.h>
+#ifdef CONFIG_FSL_ESDHC
+#include <fsl_esdhc.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void ft_qe_setup(void *blob);
+extern void ft_fixup_num_cores(void *blob);
+
+#ifdef CONFIG_MP
+#include "mp.h"
+
+void ft_fixup_cpu(void *blob, u64 memory_limit)
+{
+	int off;
+	ulong spin_tbl_addr = get_spin_phys_addr();
+	u32 bootpg = determine_mp_bootpg();
+	u32 id = get_my_id();
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	while (off != -FDT_ERR_NOTFOUND) {
+		u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+
+		if (reg) {
+			if (*reg == id) {
+				fdt_setprop_string(blob, off, "status", "okay");
+			} else {
+				u64 val = *reg * SIZE_BOOT_ENTRY + spin_tbl_addr;
+				val = cpu_to_fdt32(val);
+				fdt_setprop_string(blob, off, "status",
+								"disabled");
+				fdt_setprop_string(blob, off, "enable-method",
+								"spin-table");
+				fdt_setprop(blob, off, "cpu-release-addr",
+						&val, sizeof(val));
+			}
+		} else {
+			printf ("cpu NULL\n");
+		}
+		off = fdt_node_offset_by_prop_value(blob, off,
+				"device_type", "cpu", 4);
+	}
+
+	/* Reserve the boot page so OSes dont use it */
+	if ((u64)bootpg < memory_limit) {
+		off = fdt_add_mem_rsv(blob, bootpg, (u64)4096);
+		if (off < 0)
+			printf("%s: %s\n", __FUNCTION__, fdt_strerror(off));
+	}
+}
+#endif
+
+#define ft_fixup_l3cache(x, y)
+
+#if defined(CONFIG_L2_CACHE)
+/* return size in kilobytes */
+static inline u32 l2cache_size(void)
+{
+	volatile ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
+	volatile u32 l2siz_field = (l2cache->l2ctl >> 28) & 0x3;
+	u32 ver = SVR_SOC_VER(get_svr());
+
+	switch (l2siz_field) {
+	case 0x0:
+		break;
+	case 0x1:
+		if (ver == SVR_8540 || ver == SVR_8560   ||
+		    ver == SVR_8541 || ver == SVR_8541_E ||
+		    ver == SVR_8555 || ver == SVR_8555_E)
+			return 128;
+		else
+			return 256;
+		break;
+	case 0x2:
+		if (ver == SVR_8540 || ver == SVR_8560   ||
+		    ver == SVR_8541 || ver == SVR_8541_E ||
+		    ver == SVR_8555 || ver == SVR_8555_E)
+			return 256;
+		else
+			return 512;
+		break;
+	case 0x3:
+		return 1024;
+		break;
+	}
+
+	return 0;
+}
+
+static inline void ft_fixup_l2cache(void *blob)
+{
+	int len, off;
+	u32 *ph;
+	struct cpu_type *cpu = identify_cpu(SVR_SOC_VER(get_svr()));
+	char compat_buf[38];
+
+	const u32 line_size = 32;
+	const u32 num_ways = 8;
+	const u32 size = l2cache_size() * 1024;
+	const u32 num_sets = size / (line_size * num_ways);
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	if (off < 0) {
+		debug("no cpu node fount\n");
+		return;
+	}
+
+	ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0);
+
+	if (ph == NULL) {
+		debug("no next-level-cache property\n");
+		return ;
+	}
+
+	off = fdt_node_offset_by_phandle(blob, *ph);
+	if (off < 0) {
+		printf("%s: %s\n", __func__, fdt_strerror(off));
+		return ;
+	}
+
+	if (cpu) {
+		if (isdigit(cpu->name[0]))
+			len = sprintf(compat_buf,
+				"fsl,mpc%s-l2-cache-controller", cpu->name);
+		else
+			len = sprintf(compat_buf,
+				"fsl,%c%s-l2-cache-controller",
+				tolower(cpu->name[0]), cpu->name + 1);
+
+		sprintf(&compat_buf[len + 1], "cache");
+	}
+	fdt_setprop(blob, off, "cache-unified", NULL, 0);
+	fdt_setprop_cell(blob, off, "cache-block-size", line_size);
+	fdt_setprop_cell(blob, off, "cache-size", size);
+	fdt_setprop_cell(blob, off, "cache-sets", num_sets);
+	fdt_setprop_cell(blob, off, "cache-level", 2);
+	fdt_setprop(blob, off, "compatible", compat_buf, sizeof(compat_buf));
+
+	/* we dont bother w/L3 since no platform of this type has one */
+}
+#elif defined(CONFIG_BACKSIDE_L2_CACHE)
+static inline void ft_fixup_l2cache(void *blob)
+{
+	int off, l2_off, l3_off = -1;
+	u32 *ph;
+	u32 l2cfg0 = mfspr(SPRN_L2CFG0);
+	u32 size, line_size, num_ways, num_sets;
+
+	size = (l2cfg0 & 0x3fff) * 64 * 1024;
+	num_ways = ((l2cfg0 >> 14) & 0x1f) + 1;
+	line_size = (((l2cfg0 >> 23) & 0x3) + 1) * 32;
+	num_sets = size / (line_size * num_ways);
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+
+	while (off != -FDT_ERR_NOTFOUND) {
+		ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0);
+
+		if (ph == NULL) {
+			debug("no next-level-cache property\n");
+			goto next;
+		}
+
+		l2_off = fdt_node_offset_by_phandle(blob, *ph);
+		if (l2_off < 0) {
+			printf("%s: %s\n", __func__, fdt_strerror(off));
+			goto next;
+		}
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+		{
+			u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+			if (reg)
+				fdt_setprop_cell(blob, l2_off, "cache-stash-id",
+					 (*reg * 2) + 32 + 1);
+		}
+#endif
+
+		fdt_setprop(blob, l2_off, "cache-unified", NULL, 0);
+		fdt_setprop_cell(blob, l2_off, "cache-block-size", line_size);
+		fdt_setprop_cell(blob, l2_off, "cache-size", size);
+		fdt_setprop_cell(blob, l2_off, "cache-sets", num_sets);
+		fdt_setprop_cell(blob, l2_off, "cache-level", 2);
+		fdt_setprop(blob, l2_off, "compatible", "cache", 6);
+
+		if (l3_off < 0) {
+			ph = (u32 *)fdt_getprop(blob, l2_off, "next-level-cache", 0);
+
+			if (ph == NULL) {
+				debug("no next-level-cache property\n");
+				goto next;
+			}
+			l3_off = *ph;
+		}
+next:
+		off = fdt_node_offset_by_prop_value(blob, off,
+				"device_type", "cpu", 4);
+	}
+	if (l3_off > 0) {
+		l3_off = fdt_node_offset_by_phandle(blob, l3_off);
+		if (l3_off < 0) {
+			printf("%s: %s\n", __func__, fdt_strerror(off));
+			return ;
+		}
+		ft_fixup_l3cache(blob, l3_off);
+	}
+}
+#else
+#define ft_fixup_l2cache(x)
+#endif
+
+static inline void ft_fixup_cache(void *blob)
+{
+	int off;
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+
+	while (off != -FDT_ERR_NOTFOUND) {
+		u32 l1cfg0 = mfspr(SPRN_L1CFG0);
+		u32 l1cfg1 = mfspr(SPRN_L1CFG1);
+		u32 isize, iline_size, inum_sets, inum_ways;
+		u32 dsize, dline_size, dnum_sets, dnum_ways;
+
+		/* d-side config */
+		dsize = (l1cfg0 & 0x7ff) * 1024;
+		dnum_ways = ((l1cfg0 >> 11) & 0xff) + 1;
+		dline_size = (((l1cfg0 >> 23) & 0x3) + 1) * 32;
+		dnum_sets = dsize / (dline_size * dnum_ways);
+
+		fdt_setprop_cell(blob, off, "d-cache-block-size", dline_size);
+		fdt_setprop_cell(blob, off, "d-cache-size", dsize);
+		fdt_setprop_cell(blob, off, "d-cache-sets", dnum_sets);
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+		{
+			u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+			if (reg)
+				fdt_setprop_cell(blob, off, "cache-stash-id",
+					 (*reg * 2) + 32 + 0);
+		}
+#endif
+
+		/* i-side config */
+		isize = (l1cfg1 & 0x7ff) * 1024;
+		inum_ways = ((l1cfg1 >> 11) & 0xff) + 1;
+		iline_size = (((l1cfg1 >> 23) & 0x3) + 1) * 32;
+		inum_sets = isize / (iline_size * inum_ways);
+
+		fdt_setprop_cell(blob, off, "i-cache-block-size", iline_size);
+		fdt_setprop_cell(blob, off, "i-cache-size", isize);
+		fdt_setprop_cell(blob, off, "i-cache-sets", inum_sets);
+
+		off = fdt_node_offset_by_prop_value(blob, off,
+				"device_type", "cpu", 4);
+	}
+
+	ft_fixup_l2cache(blob);
+}
+
+
+void fdt_add_enet_stashing(void *fdt)
+{
+	do_fixup_by_compat(fdt, "gianfar", "bd-stash", NULL, 0, 1);
+
+	do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-len", 96, 1);
+
+	do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-idx", 0, 1);
+}
+
+#if defined(CONFIG_SYS_DPAA_FMAN) || defined(CONFIG_SYS_DPAA_PME)
+static void ft_fixup_clks(void *blob, const char *alias, unsigned long freq)
+{
+	const char *path = fdt_get_alias(blob, alias);
+
+	int off = fdt_path_offset(blob, path);
+
+	if (off >= 0) {
+		off = fdt_setprop_cell(blob, off, "clock-frequency", freq);
+		if (off > 0)
+			printf("WARNING enable to set clock-frequency "
+				"for %s: %s\n", alias, fdt_strerror(off));
+	}
+}
+
+static void ft_fixup_dpaa_clks(void *blob)
+{
+	sys_info_t sysinfo;
+
+	get_sys_info(&sysinfo);
+	ft_fixup_clks(blob, "fman0", sysinfo.freqFMan[0]);
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+	ft_fixup_clks(blob, "fman1", sysinfo.freqFMan[1]);
+#endif
+
+#ifdef CONFIG_SYS_DPAA_PME
+	ft_fixup_clks(blob, "pme", sysinfo.freqPME);
+#endif
+}
+#else
+#define ft_fixup_dpaa_clks(x)
+#endif
+
+#ifdef CONFIG_QE
+static void ft_fixup_qe_snum(void *blob)
+{
+	unsigned int svr;
+
+	svr = mfspr(SPRN_SVR);
+	if (SVR_SOC_VER(svr) == SVR_8569_E) {
+		if(IS_SVR_REV(svr, 1, 0))
+			do_fixup_by_compat_u32(blob, "fsl,qe",
+				"fsl,qe-num-snums", 46, 1);
+		else
+			do_fixup_by_compat_u32(blob, "fsl,qe",
+				"fsl,qe-num-snums", 76, 1);
+	}
+}
+#endif
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	int off;
+	int val;
+	sys_info_t sysinfo;
+
+	/* delete crypto node if not on an E-processor */
+	if (!IS_E_PROCESSOR(get_svr()))
+		fdt_fixup_crypto_node(blob, 0);
+
+	fdt_fixup_ethernet(blob);
+
+	fdt_add_enet_stashing(blob);
+
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"timebase-frequency", get_tbclk(), 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+	get_sys_info(&sysinfo);
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	while (off != -FDT_ERR_NOTFOUND) {
+		u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+		val = cpu_to_fdt32(sysinfo.freqProcessor[*reg]);
+		fdt_setprop(blob, off, "clock-frequency", &val, 4);
+		off = fdt_node_offset_by_prop_value(blob, off, "device_type",
+							"cpu", 4);
+	}
+	do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+
+	do_fixup_by_compat_u32(blob, "fsl,pq3-localbus",
+		"bus-frequency", gd->lbc_clk, 1);
+	do_fixup_by_compat_u32(blob, "fsl,elbc",
+		"bus-frequency", gd->lbc_clk, 1);
+#ifdef CONFIG_QE
+	ft_qe_setup(blob);
+	ft_fixup_qe_snum(blob);
+#endif
+
+#ifdef CONFIG_SYS_NS16550
+	do_fixup_by_compat_u32(blob, "ns16550",
+		"clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+#ifdef CONFIG_CPM2
+	do_fixup_by_compat_u32(blob, "fsl,cpm2-scc-uart",
+		"current-speed", bd->bi_baudrate, 1);
+
+	do_fixup_by_compat_u32(blob, "fsl,cpm2-brg",
+		"clock-frequency", bd->bi_brgfreq, 1);
+#endif
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#ifdef CONFIG_MP
+	ft_fixup_cpu(blob, (u64)bd->bi_memstart + (u64)bd->bi_memsize);
+#endif
+	ft_fixup_num_cores(blob);
+
+	ft_fixup_cache(blob);
+
+#if defined(CONFIG_FSL_ESDHC)
+	fdt_fixup_esdhc(blob, bd);
+#endif
+
+	ft_fixup_dpaa_clks(blob);
+}
diff --git a/arch/ppc/cpu/mpc85xx/fixed_ivor.S b/arch/ppc/cpu/mpc85xx/fixed_ivor.S
new file mode 100644
index 0000000..320cae3
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/fixed_ivor.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Kumar Gala <kumar.gala@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* This file is intended to be included by other asm code since
+ * we will want to execute this on both the primary core when
+ * it does a bootm and the secondary core's that get released
+ * out of the spin table */
+
+#define SET_IVOR(vector_number, vector_offset)	\
+	li	r3,vector_offset@l; 		\
+	mtspr	SPRN_IVOR##vector_number,r3;
+
+#define SET_GIVOR(vector_number, vector_offset)	\
+	li	r3,vector_offset@l; 		\
+	mtspr	SPRN_GIVOR##vector_number,r3;
+
+	SET_IVOR(0, 0x020) /* Critical Input */
+	SET_IVOR(1, 0x000) /* Machine Check */
+	SET_IVOR(2, 0x060) /* Data Storage */
+	SET_IVOR(3, 0x080) /* Instruction Storage */
+	SET_IVOR(4, 0x0a0) /* External Input */
+	SET_IVOR(5, 0x0c0) /* Alignment */
+	SET_IVOR(6, 0x0e0) /* Program */
+	SET_IVOR(7, 0x100) /* FP Unavailable */
+	SET_IVOR(8, 0x120) /* System Call */
+	SET_IVOR(9, 0x140) /* Auxiliary Processor Unavailable */
+	SET_IVOR(10, 0x160) /* Decrementer */
+	SET_IVOR(11, 0x180) /* Fixed Interval Timer */
+	SET_IVOR(12, 0x1a0) /* Watchdog Timer */
+	SET_IVOR(13, 0x1c0) /* Data TLB Error */
+	SET_IVOR(14, 0x1e0) /* Instruction TLB Error */
+	SET_IVOR(15, 0x040) /* Debug */
+
+/* e500v1 & e500v2 only */
+#ifndef CONFIG_E500MC
+	SET_IVOR(32, 0x200) /* SPE Unavailable */
+	SET_IVOR(33, 0x220) /* Embedded FP Data */
+	SET_IVOR(34, 0x240) /* Embedded FP Round */
+#endif
+
+	SET_IVOR(35, 0x260) /* Performance monitor */
+
+/* e500mc only */
+#ifdef CONFIG_E500MC
+	SET_IVOR(36, 0x280) /* Processor doorbell */
+	SET_IVOR(37, 0x2a0) /* Processor doorbell critical */
+	SET_IVOR(38, 0x2c0) /* Guest Processor doorbell */
+	SET_IVOR(39, 0x2e0) /* Guest Processor critical & machine check */
+	SET_IVOR(40, 0x300) /* Hypervisor system call */
+	SET_IVOR(41, 0x320) /* Hypervisor Priviledge */
+
+	SET_GIVOR(2, 0x060) /* Guest Data Storage */
+	SET_GIVOR(3, 0x080) /* Guest Instruction Storage */
+	SET_GIVOR(4, 0x0a0) /* Guest External Input */
+	SET_GIVOR(8, 0x120) /* Guest System Call */
+	SET_GIVOR(13, 0x1c0) /* Guest Data TLB Error */
+	SET_GIVOR(14, 0x1e0) /* Guest Instruction TLB Error */
+#endif
diff --git a/arch/ppc/cpu/mpc85xx/interrupts.c b/arch/ppc/cpu/mpc85xx/interrupts.c
new file mode 100644
index 0000000..409367d
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/interrupts.c
@@ -0,0 +1,110 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 Motorola Inc. (MPC85xx port)
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+int interrupt_init_cpu(unsigned int *decrementer_count)
+{
+	ccsr_pic_t __iomem *pic = (void *)CONFIG_SYS_MPC85xx_PIC_ADDR;
+
+	out_be32(&pic->gcr, MPC85xx_PICGCR_RST);
+	while (in_be32(&pic->gcr) & MPC85xx_PICGCR_RST)
+		;
+	out_be32(&pic->gcr, MPC85xx_PICGCR_M);
+	in_be32(&pic->gcr);
+
+	*decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+
+	/* PIE is same as DIE, dec interrupt enable */
+	mtspr(SPRN_TCR, TCR_PIE);
+
+#ifdef CONFIG_INTERRUPTS
+	pic->iivpr1 = 0x810001;	/* 50220 enable ecm interrupts */
+	debug("iivpr1@%x = %x\n", (uint)&pic->iivpr1, pic->iivpr1);
+
+	pic->iivpr2 = 0x810002;	/* 50240 enable ddr interrupts */
+	debug("iivpr2@%x = %x\n", (uint)&pic->iivpr2, pic->iivpr2);
+
+	pic->iivpr3 = 0x810003;	/* 50260 enable lbc interrupts */
+	debug("iivpr3@%x = %x\n", (uint)&pic->iivpr3, pic->iivpr3);
+
+#ifdef CONFIG_PCI1
+	pic->iivpr8 = 0x810008;	/* enable pci1 interrupts */
+	debug("iivpr8@%x = %x\n", (uint)&pic->iivpr8, pic->iivpr8);
+#endif
+#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2)
+	pic->iivpr9 = 0x810009;	/* enable pci1 interrupts */
+	debug("iivpr9@%x = %x\n", (uint)&pic->iivpr9, pic->iivpr9);
+#endif
+#ifdef CONFIG_PCIE1
+	pic->iivpr10 = 0x81000a;	/* enable pcie1 interrupts */
+	debug("iivpr10@%x = %x\n", (uint)&pic->iivpr10, pic->iivpr10);
+#endif
+#ifdef CONFIG_PCIE3
+	pic->iivpr11 = 0x81000b;	/* enable pcie3 interrupts */
+	debug("iivpr11@%x = %x\n", (uint)&pic->iivpr11, pic->iivpr11);
+#endif
+
+	pic->ctpr=0;		/* 40080 clear current task priority register */
+#endif
+
+	return (0);
+}
+
+/* Install and free a interrupt handler. Not implemented yet. */
+
+void
+irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+	return;
+}
+
+void
+irq_free_handler(int vec)
+{
+	return;
+}
+
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+	/* PIS is same as DIS, dec interrupt status */
+	mtspr(SPRN_TSR, TSR_PIS);
+}
+
+#if defined(CONFIG_CMD_IRQ)
+/* irqinfo - print information about PCI devices,not implemented. */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	return 0;
+}
+#endif
diff --git a/arch/ppc/cpu/mpc85xx/mp.c b/arch/ppc/cpu/mpc85xx/mp.c
new file mode 100644
index 0000000..826bf32
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/mp.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ioports.h>
+#include <lmb.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include "mp.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+u32 get_my_id()
+{
+	return mfspr(SPRN_PIR);
+}
+
+int cpu_reset(int nr)
+{
+	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
+	out_be32(&pic->pir, 1 << nr);
+	/* the dummy read works around an errata on early 85xx MP PICs */
+	(void)in_be32(&pic->pir);
+	out_be32(&pic->pir, 0x0);
+
+	return 0;
+}
+
+int cpu_status(int nr)
+{
+	u32 *table, id = get_my_id();
+
+	if (nr == id) {
+		table = (u32 *)get_spin_virt_addr();
+		printf("table base @ 0x%p\n", table);
+	} else {
+		table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
+		printf("Running on cpu %d\n", id);
+		printf("\n");
+		printf("table @ 0x%p\n", table);
+		printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]);
+		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);
+		printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
+		printf("   r6   - 0x%08x\n", table[BOOT_ENTRY_R6_LOWER]);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_FSL_CORENET
+int cpu_disable(int nr)
+{
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+	setbits_be32(&gur->coredisrl, 1 << nr);
+
+	return 0;
+}
+#else
+int cpu_disable(int nr)
+{
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+	switch (nr) {
+	case 0:
+		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
+		break;
+	case 1:
+		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
+		break;
+	default:
+		printf("Invalid cpu number for disable %d\n", nr);
+		return 1;
+	}
+
+	return 0;
+}
+#endif
+
+static u8 boot_entry_map[4] = {
+	0,
+	BOOT_ENTRY_PIR,
+	BOOT_ENTRY_R3_LOWER,
+	BOOT_ENTRY_R6_LOWER,
+};
+
+int cpu_release(int nr, int argc, char *argv[])
+{
+	u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
+	u64 boot_addr;
+
+	if (nr == get_my_id()) {
+		printf("Invalid to release the boot core.\n\n");
+		return 1;
+	}
+
+	if (argc != 4) {
+		printf("Invalid number of arguments to release.\n\n");
+		return 1;
+	}
+
+	boot_addr = simple_strtoull(argv[0], NULL, 16);
+
+	/* handle pir, r3, r6 */
+	for (i = 1; i < 4; i++) {
+		if (argv[i][0] != '-') {
+			u8 entry = boot_entry_map[i];
+			val = simple_strtoul(argv[i], NULL, 16);
+			table[entry] = val;
+		}
+	}
+
+	table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32);
+
+	/* ensure all table updates complete before final address write */
+	eieio();
+
+	table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff);
+
+	return 0;
+}
+
+u32 determine_mp_bootpg(void)
+{
+	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */
+	if ((u64)gd->ram_size > 0xfffff000)
+		return (0xfffff000);
+
+	return (gd->ram_size - 4096);
+}
+
+ulong get_spin_phys_addr(void)
+{
+	extern ulong __secondary_start_page;
+	extern ulong __spin_table;
+
+	return (determine_mp_bootpg() +
+		(ulong)&__spin_table - (ulong)&__secondary_start_page);
+}
+
+ulong get_spin_virt_addr(void)
+{
+	extern ulong __secondary_start_page;
+	extern ulong __spin_table;
+
+	return (CONFIG_BPTR_VIRT_ADDR +
+		(ulong)&__spin_table - (ulong)&__secondary_start_page);
+}
+
+#ifdef CONFIG_FSL_CORENET
+static void plat_mp_up(unsigned long bootpg)
+{
+	u32 up, cpu_up_mask, whoami;
+	u32 *table = (u32 *)get_spin_virt_addr();
+	volatile ccsr_gur_t *gur;
+	volatile ccsr_local_t *ccm;
+	volatile ccsr_rcpm_t *rcpm;
+	volatile ccsr_pic_t *pic;
+	int timeout = 10;
+	u32 nr_cpus;
+	struct law_entry e;
+
+	gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
+	rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
+	pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
+
+	nr_cpus = ((in_be32(&pic->frr) >> 8) & 0xff) + 1;
+
+	whoami = in_be32(&pic->whoami);
+	cpu_up_mask = 1 << whoami;
+	out_be32(&ccm->bstrl, bootpg);
+
+	e = find_law(bootpg);
+	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | LAW_SIZE_4K);
+
+	/* readback to sync write */
+	in_be32(&ccm->bstrar);
+
+	/* disable time base at the platform */
+	out_be32(&rcpm->ctbenrl, cpu_up_mask);
+
+	/* release the hounds */
+	up = ((1 << nr_cpus) - 1);
+	out_be32(&gur->brrl, up);
+
+	/* wait for everyone */
+	while (timeout) {
+		int i;
+		for (i = 0; i < nr_cpus; i++) {
+			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
+				cpu_up_mask |= (1 << i);
+		};
+
+		if ((cpu_up_mask & up) == up)
+			break;
+
+		udelay(100);
+		timeout--;
+	}
+
+	if (timeout == 0)
+		printf("CPU up timeout. CPU up mask is %x should be %x\n",
+			cpu_up_mask, up);
+
+	/* enable time base at the platform */
+	out_be32(&rcpm->ctbenrl, 0);
+	mtspr(SPRN_TBWU, 0);
+	mtspr(SPRN_TBWL, 0);
+	out_be32(&rcpm->ctbenrl, (1 << nr_cpus) - 1);
+
+#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
+	/*
+	 * Disabling Boot Page Translation allows the memory region 0xfffff000
+	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
+	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
+	 * unusable for normal operation but it does allow OSes to easily
+	 * reset a processor core to put it back into U-Boot's spinloop.
+	 */
+	clrbits_be32(&ecm->bptr, 0x80000000);
+#endif
+}
+#else
+static void plat_mp_up(unsigned long bootpg)
+{
+	u32 up, cpu_up_mask, whoami;
+	u32 *table = (u32 *)get_spin_virt_addr();
+	volatile u32 bpcr;
+	volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
+	u32 devdisr;
+	int timeout = 10;
+
+	whoami = in_be32(&pic->whoami);
+	out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
+
+	/* disable time base at the platform */
+	devdisr = in_be32(&gur->devdisr);
+	if (whoami)
+		devdisr |= MPC85xx_DEVDISR_TB0;
+	else
+		devdisr |= MPC85xx_DEVDISR_TB1;
+	out_be32(&gur->devdisr, devdisr);
+
+	/* release the hounds */
+	up = ((1 << cpu_numcores()) - 1);
+	bpcr = in_be32(&ecm->eebpcr);
+	bpcr |= (up << 24);
+	out_be32(&ecm->eebpcr, bpcr);
+	asm("sync; isync; msync");
+
+	cpu_up_mask = 1 << whoami;
+	/* wait for everyone */
+	while (timeout) {
+		int i;
+		for (i = 0; i < cpu_numcores(); i++) {
+			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
+				cpu_up_mask |= (1 << i);
+		};
+
+		if ((cpu_up_mask & up) == up)
+			break;
+
+		udelay(100);
+		timeout--;
+	}
+
+	if (timeout == 0)
+		printf("CPU up timeout. CPU up mask is %x should be %x\n",
+			cpu_up_mask, up);
+
+	/* enable time base at the platform */
+	if (whoami)
+		devdisr |= MPC85xx_DEVDISR_TB1;
+	else
+		devdisr |= MPC85xx_DEVDISR_TB0;
+	out_be32(&gur->devdisr, devdisr);
+	mtspr(SPRN_TBWU, 0);
+	mtspr(SPRN_TBWL, 0);
+
+	devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
+	out_be32(&gur->devdisr, devdisr);
+
+#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
+	/*
+	 * Disabling Boot Page Translation allows the memory region 0xfffff000
+	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation
+	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region
+	 * unusable for normal operation but it does allow OSes to easily
+	 * reset a processor core to put it back into U-Boot's spinloop.
+	 */
+	clrbits_be32(&ecm->bptr, 0x80000000);
+#endif
+}
+#endif
+
+void cpu_mp_lmb_reserve(struct lmb *lmb)
+{
+	u32 bootpg = determine_mp_bootpg();
+
+	lmb_reserve(lmb, bootpg, 4096);
+}
+
+void setup_mp(void)
+{
+	extern ulong __secondary_start_page;
+	extern ulong __bootpg_addr;
+	ulong fixup = (ulong)&__secondary_start_page;
+	u32 bootpg = determine_mp_bootpg();
+
+	/* Store the bootpg's SDRAM address for use by secondary CPU cores */
+	__bootpg_addr = bootpg;
+
+	/* look for the tlb covering the reset page, there better be one */
+	int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);
+
+	/* we found a match */
+	if (i != -1) {
+		/* map reset page to bootpg so we can copy code there */
+		disable_tlb(i);
+
+		set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
+			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
+			0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
+
+		memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096);
+
+		plat_mp_up(bootpg);
+	} else {
+		puts("WARNING: No reset page TLB. "
+			"Skipping secondary core setup\n");
+	}
+}
diff --git a/arch/ppc/cpu/mpc85xx/mp.h b/arch/ppc/cpu/mpc85xx/mp.h
new file mode 100644
index 0000000..3422cc1
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/mp.h
@@ -0,0 +1,21 @@
+#ifndef __MPC85XX_MP_H_
+#define __MPC85XX_MP_H_
+
+#include <asm/mp.h>
+
+ulong get_spin_phys_addr(void);
+ulong get_spin_virt_addr(void);
+u32 get_my_id(void);
+
+#define BOOT_ENTRY_ADDR_UPPER	0
+#define BOOT_ENTRY_ADDR_LOWER	1
+#define BOOT_ENTRY_R3_UPPER	2
+#define BOOT_ENTRY_R3_LOWER	3
+#define BOOT_ENTRY_RESV		4
+#define BOOT_ENTRY_PIR		5
+#define BOOT_ENTRY_R6_UPPER	6
+#define BOOT_ENTRY_R6_LOWER	7
+#define NUM_BOOT_ENTRY		8
+#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
+
+#endif
diff --git a/arch/ppc/cpu/mpc85xx/mpc8536_serdes.c b/arch/ppc/cpu/mpc85xx/mpc8536_serdes.c
new file mode 100644
index 0000000..cb6a6f0
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/mpc8536_serdes.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008 Freescale Semicondutor, Inc.
+ *	Dave Liu <daveliu@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+
+/* PORDEVSR register */
+#define GUTS_PORDEVSR_OFFS		0xc
+#define GUTS_PORDEVSR_SERDES2_IO_SEL	0x38000000
+#define GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT	27
+
+/* SerDes CR0 register */
+#define	FSL_SRDSCR0_OFFS	0x0
+#define FSL_SRDSCR0_TXEQA_MASK	0x00007000
+#define FSL_SRDSCR0_TXEQA_SGMII	0x00004000
+#define FSL_SRDSCR0_TXEQA_SATA	0x00001000
+#define FSL_SRDSCR0_TXEQE_MASK	0x00000700
+#define FSL_SRDSCR0_TXEQE_SGMII	0x00000400
+#define FSL_SRDSCR0_TXEQE_SATA	0x00000100
+
+/* SerDes CR1 register */
+#define FSL_SRDSCR1_OFFS	0x4
+#define FSL_SRDSCR1_LANEA_MASK	0x80200000
+#define FSL_SRDSCR1_LANEA_OFF	0x80200000
+#define FSL_SRDSCR1_LANEE_MASK	0x08020000
+#define FSL_SRDSCR1_LANEE_OFF	0x08020000
+
+/* SerDes CR2 register */
+#define FSL_SRDSCR2_OFFS	0x8
+#define FSL_SRDSCR2_EICA_MASK	0x00001f00
+#define FSL_SRDSCR2_EICA_SGMII	0x00000400
+#define FSL_SRDSCR2_EICA_SATA	0x00001400
+#define FSL_SRDSCR2_EICE_MASK	0x0000001f
+#define FSL_SRDSCR2_EICE_SGMII	0x00000004
+#define FSL_SRDSCR2_EICE_SATA	0x00000014
+
+/* SerDes CR3 register */
+#define FSL_SRDSCR3_OFFS	0xc
+#define FSL_SRDSCR3_LANEA_MASK	0x3f000700
+#define FSL_SRDSCR3_LANEA_SGMII	0x00000000
+#define FSL_SRDSCR3_LANEA_SATA	0x15000500
+#define FSL_SRDSCR3_LANEE_MASK	0x003f0007
+#define FSL_SRDSCR3_LANEE_SGMII	0x00000000
+#define FSL_SRDSCR3_LANEE_SATA	0x00150005
+
+void fsl_serdes_init(void)
+{
+	void *guts = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	void *sd = (void *)CONFIG_SYS_MPC85xx_SERDES2_ADDR;
+	u32 pordevsr = in_be32(guts + GUTS_PORDEVSR_OFFS);
+	u32 srds2_io_sel;
+	u32 tmp;
+
+	/* parse the SRDS2_IO_SEL of PORDEVSR */
+	srds2_io_sel = (pordevsr & GUTS_PORDEVSR_SERDES2_IO_SEL)
+		       >> GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT;
+
+	switch (srds2_io_sel) {
+	case 1:	/* Lane A - SATA1, Lane E - SATA2 */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SATA;
+		tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
+		tmp |= FSL_SRDSCR0_TXEQE_SATA;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SATA;
+		tmp &= ~FSL_SRDSCR2_EICE_MASK;
+		tmp |= FSL_SRDSCR2_EICE_SATA;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SATA;
+		tmp &= ~FSL_SRDSCR3_LANEE_MASK;
+		tmp |= FSL_SRDSCR3_LANEE_SATA;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 3: /* Lane A - SATA1, Lane E - disabled */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SATA;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		tmp |= FSL_SRDSCR1_LANEE_OFF;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SATA;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SATA;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 4: /* Lane A - eTSEC1 SGMII, Lane E - eTSEC3 SGMII */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SGMII;
+		tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
+		tmp |= FSL_SRDSCR0_TXEQE_SGMII;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SGMII;
+		tmp &= ~FSL_SRDSCR2_EICE_MASK;
+		tmp |= FSL_SRDSCR2_EICE_SGMII;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SGMII;
+		tmp &= ~FSL_SRDSCR3_LANEE_MASK;
+		tmp |= FSL_SRDSCR3_LANEE_SGMII;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 6: /* Lane A - eTSEC1 SGMII, Lane E - disabled */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SGMII;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		tmp |= FSL_SRDSCR1_LANEE_OFF;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SGMII;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SGMII;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 7: /* Lane A - disabled, Lane E - disabled */
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+		tmp |= FSL_SRDSCR1_LANEA_OFF;
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		tmp |= FSL_SRDSCR1_LANEE_OFF;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/arch/ppc/cpu/mpc85xx/pci.c b/arch/ppc/cpu/mpc85xx/pci.c
new file mode 100644
index 0000000..75d2716
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/pci.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Copyright (C) 2003 Motorola Inc.
+ * Xianghua Xiao (x.xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI Configuration space access support for MPC85xx PCI Bridge
+ */
+#include <common.h>
+#include <asm/cpm_85xx.h>
+#include <pci.h>
+
+#if !defined(CONFIG_FSL_PCI_INIT)
+
+#ifndef CONFIG_SYS_PCI1_MEM_BUS
+#define CONFIG_SYS_PCI1_MEM_BUS CONFIG_SYS_PCI1_MEM_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI1_IO_BUS
+#define CONFIG_SYS_PCI1_IO_BUS CONFIG_SYS_PCI1_IO_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI2_MEM_BUS
+#define CONFIG_SYS_PCI2_MEM_BUS CONFIG_SYS_PCI2_MEM_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI2_IO_BUS
+#define CONFIG_SYS_PCI2_IO_BUS CONFIG_SYS_PCI2_IO_BASE
+#endif
+
+static struct pci_controller *pci_hose;
+
+void
+pci_mpc85xx_init(struct pci_controller *board_hose)
+{
+	u16 reg16;
+	u32 dev;
+
+	volatile ccsr_pcix_t *pcix = (void *)(CONFIG_SYS_MPC85xx_PCIX_ADDR);
+#ifdef CONFIG_MPC85XX_PCI2
+	volatile ccsr_pcix_t *pcix2 = (void *)(CONFIG_SYS_MPC85xx_PCIX2_ADDR);
+#endif
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	struct pci_controller * hose;
+
+	pci_hose = board_hose;
+
+	hose = &pci_hose[0];
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_setup_indirect(hose,
+			   (CONFIG_SYS_IMMR+0x8000),
+			   (CONFIG_SYS_IMMR+0x8004));
+
+	/*
+	 * Hose scan.
+	 */
+	dev = PCI_BDF(hose->first_busno, 0, 0);
+	pci_hose_read_config_word (hose, dev, PCI_COMMAND, &reg16);
+	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+	/*
+	 * Clear non-reserved bits in status register.
+	 */
+	pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+
+	if (!(gur->pordevsr & MPC85xx_PORDEVSR_PCI1)) {
+		/* PCI-X init */
+		if (CONFIG_SYS_CLK_FREQ < 66000000)
+			printf("PCI-X will only work at 66 MHz\n");
+
+		reg16 = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
+			| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
+		pci_hose_write_config_word(hose, dev, PCIX_COMMAND, reg16);
+	}
+
+	pcix->potar1   = (CONFIG_SYS_PCI1_MEM_BUS >> 12) & 0x000fffff;
+	pcix->potear1  = 0x00000000;
+	pcix->powbar1  = (CONFIG_SYS_PCI1_MEM_PHYS >> 12) & 0x000fffff;
+	pcix->powbear1 = 0x00000000;
+	pcix->powar1 = (POWAR_EN | POWAR_MEM_READ |
+			POWAR_MEM_WRITE | (__ilog2(CONFIG_SYS_PCI1_MEM_SIZE) - 1));
+
+	pcix->potar2  = (CONFIG_SYS_PCI1_IO_BUS >> 12) & 0x000fffff;
+	pcix->potear2  = 0x00000000;
+	pcix->powbar2  = (CONFIG_SYS_PCI1_IO_PHYS >> 12) & 0x000fffff;
+	pcix->powbear2 = 0x00000000;
+	pcix->powar2 = (POWAR_EN | POWAR_IO_READ |
+			POWAR_IO_WRITE | (__ilog2(CONFIG_SYS_PCI1_IO_SIZE) - 1));
+
+	pcix->pitar1 = 0x00000000;
+	pcix->piwbar1 = 0x00000000;
+	pcix->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G);
+
+	pcix->powar3 = 0;
+	pcix->powar4 = 0;
+	pcix->piwar2 = 0;
+	pcix->piwar3 = 0;
+
+	pci_set_region(hose->regions + 0,
+		       CONFIG_SYS_PCI1_MEM_BUS,
+		       CONFIG_SYS_PCI1_MEM_PHYS,
+		       CONFIG_SYS_PCI1_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	pci_set_region(hose->regions + 1,
+		       CONFIG_SYS_PCI1_IO_BUS,
+		       CONFIG_SYS_PCI1_IO_PHYS,
+		       CONFIG_SYS_PCI1_IO_SIZE,
+		       PCI_REGION_IO);
+
+	hose->region_count = 2;
+
+	pci_register_hose(hose);
+
+#if defined(CONFIG_MPC8555CDS) || defined(CONFIG_MPC8541CDS)
+	/*
+	 * This is a SW workaround for an apparent HW problem
+	 * in the PCI controller on the MPC85555/41 CDS boards.
+	 * The first config cycle must be to a valid, known
+	 * device on the PCI bus in order to trick the PCI
+	 * controller state machine into a known valid state.
+	 * Without this, the first config cycle has the chance
+	 * of hanging the controller permanently, just leaving
+	 * it in a semi-working state, or leaving it working.
+	 *
+	 * Pick on the Tundra, Device 17, to get it right.
+	 */
+	{
+		u8 header_type;
+
+		pci_hose_read_config_byte(hose,
+					  PCI_BDF(0,BRIDGE_ID,0),
+					  PCI_HEADER_TYPE,
+					  &header_type);
+	}
+#endif
+
+	hose->last_busno = pci_hose_scan(hose);
+
+#ifdef CONFIG_MPC85XX_PCI2
+	hose = &pci_hose[1];
+
+	hose->first_busno = pci_hose[0].last_busno + 1;
+	hose->last_busno = 0xff;
+
+	pci_setup_indirect(hose,
+			   (CONFIG_SYS_IMMR+0x9000),
+			   (CONFIG_SYS_IMMR+0x9004));
+
+	dev = PCI_BDF(hose->first_busno, 0, 0);
+	pci_hose_read_config_word (hose, dev, PCI_COMMAND, &reg16);
+	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+	/*
+	 * Clear non-reserved bits in status register.
+	 */
+	pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+
+	pcix2->potar1   = (CONFIG_SYS_PCI2_MEM_BUS >> 12) & 0x000fffff;
+	pcix2->potear1  = 0x00000000;
+	pcix2->powbar1  = (CONFIG_SYS_PCI2_MEM_PHYS >> 12) & 0x000fffff;
+	pcix2->powbear1 = 0x00000000;
+	pcix2->powar1 = (POWAR_EN | POWAR_MEM_READ |
+			POWAR_MEM_WRITE | (__ilog2(CONFIG_SYS_PCI2_MEM_SIZE) - 1));
+
+	pcix2->potar2  = (CONFIG_SYS_PCI2_IO_BUS >> 12) & 0x000fffff;
+	pcix2->potear2  = 0x00000000;
+	pcix2->powbar2  = (CONFIG_SYS_PCI2_IO_PHYS >> 12) & 0x000fffff;
+	pcix2->powbear2 = 0x00000000;
+	pcix2->powar2 = (POWAR_EN | POWAR_IO_READ |
+			POWAR_IO_WRITE | (__ilog2(CONFIG_SYS_PCI2_IO_SIZE) - 1));
+
+	pcix2->pitar1 = 0x00000000;
+	pcix2->piwbar1 = 0x00000000;
+	pcix2->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G);
+
+	pcix2->powar3 = 0;
+	pcix2->powar4 = 0;
+	pcix2->piwar2 = 0;
+	pcix2->piwar3 = 0;
+
+	pci_set_region(hose->regions + 0,
+		       CONFIG_SYS_PCI2_MEM_BUS,
+		       CONFIG_SYS_PCI2_MEM_PHYS,
+		       CONFIG_SYS_PCI2_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	pci_set_region(hose->regions + 1,
+		       CONFIG_SYS_PCI2_IO_BUS,
+		       CONFIG_SYS_PCI2_IO_PHYS,
+		       CONFIG_SYS_PCI2_IO_SIZE,
+		       PCI_REGION_IO);
+
+	hose->region_count = 2;
+
+	/*
+	 * Hose scan.
+	 */
+	pci_register_hose(hose);
+
+	hose->last_busno = pci_hose_scan(hose);
+#endif
+}
+#endif /* !CONFIG_FSL_PCI_INIT */
diff --git a/arch/ppc/cpu/mpc85xx/qe_io.c b/arch/ppc/cpu/mpc85xx/qe_io.c
new file mode 100644
index 0000000..72a29b7
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/qe_io.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "common.h"
+#include "asm/errno.h"
+#include "asm/io.h"
+#include "asm/immap_85xx.h"
+
+#if defined(CONFIG_QE)
+#define	NUM_OF_PINS	32
+void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
+{
+	u32			pin_2bit_mask;
+	u32			pin_2bit_dir;
+	u32			pin_2bit_assign;
+	u32			pin_1bit_mask;
+	u32			tmp_val;
+	volatile ccsr_gur_t	*gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	volatile par_io_t	*par_io = (volatile par_io_t *)
+						&(gur->qe_par_io);
+
+	/* Caculate pin location and 2bit mask and dir */
+	pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+	pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+
+	/* Setup the direction */
+	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \
+		in_be32(&par_io[port].cpdir2) :
+		in_be32(&par_io[port].cpdir1);
+
+	if (pin > (NUM_OF_PINS/2) -1) {
+		out_be32(&par_io[port].cpdir2, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io[port].cpdir2, pin_2bit_dir | tmp_val);
+	} else {
+		out_be32(&par_io[port].cpdir1, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io[port].cpdir1, pin_2bit_dir | tmp_val);
+	}
+
+	/* Calculate pin location for 1bit mask */
+	pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1)));
+
+	/* Setup the open drain */
+	tmp_val = in_be32(&par_io[port].cpodr);
+	if (open_drain)
+		out_be32(&par_io[port].cpodr, pin_1bit_mask | tmp_val);
+	else
+		out_be32(&par_io[port].cpodr, ~pin_1bit_mask & tmp_val);
+
+	/* Setup the assignment */
+	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ?
+		in_be32(&par_io[port].cppar2):
+		in_be32(&par_io[port].cppar1);
+	pin_2bit_assign = (u32)(assign
+				<< (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2));
+
+	/* Clear and set 2 bits mask */
+	if (pin > (NUM_OF_PINS/2) - 1) {
+		out_be32(&par_io[port].cppar2, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io[port].cppar2, pin_2bit_assign | tmp_val);
+	} else {
+		out_be32(&par_io[port].cppar1, ~pin_2bit_mask & tmp_val);
+		out_be32(&par_io[port].cppar1, pin_2bit_assign | tmp_val);
+	}
+}
+
+#endif /* CONFIG_QE */
diff --git a/arch/ppc/cpu/mpc85xx/release.S b/arch/ppc/cpu/mpc85xx/release.S
new file mode 100644
index 0000000..0b5b9da
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/release.S
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Kumar Gala <kumar.gala@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <mpc85xx.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>
+
+/* To boot secondary cpus, we need a place for them to start up.
+ * Normally, they start at 0xfffffffc, but that's usually the
+ * firmware, and we don't want to have to run the firmware again.
+ * Instead, the primary cpu will set the BPTR to point here to
+ * this page.  We then set up the core, and head to
+ * start_secondary.  Note that this means that the code below
+ * must never exceed 1023 instructions (the branch at the end
+ * would then be the 1024th).
+ */
+	.globl	__secondary_start_page
+	.align	12
+__secondary_start_page:
+/* First do some preliminary setup */
+	lis	r3, HID0_EMCP@h		/* enable machine check */
+#ifndef CONFIG_E500MC
+	ori	r3,r3,HID0_TBEN@l	/* enable Timebase */
+#endif
+#ifdef CONFIG_PHYS_64BIT
+	ori	r3,r3,HID0_ENMAS7@l	/* enable MAS7 updates */
+#endif
+	mtspr	SPRN_HID0,r3
+
+#ifndef CONFIG_E500MC
+	li	r3,(HID1_ASTME|HID1_ABE)@l	/* Addr streaming & broadcast */
+	mfspr   r0,PVR
+	andi.	r0,r0,0xff
+	cmpwi	r0,0x50@l	/* if we are rev 5.0 or greater set MBDD */
+	blt 1f
+	/* Set MBDD bit also */
+	ori r3, r3, HID1_MBDD@l
+1:
+	mtspr	SPRN_HID1,r3
+#endif
+
+	/* Enable branch prediction */
+	lis	r3,BUCSR_ENABLE@h
+	ori	r3,r3,BUCSR_ENABLE@l
+	mtspr	SPRN_BUCSR,r3
+
+	/* Ensure TB is 0 */
+	li	r3,0
+	mttbl	r3
+	mttbu	r3
+
+	/* Enable/invalidate the I-Cache */
+	lis	r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h
+	ori	r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l
+	mtspr	SPRN_L1CSR1,r2
+1:
+	mfspr	r3,SPRN_L1CSR1
+	and.	r1,r3,r2
+	bne	1b
+
+	lis	r3,(L1CSR1_CPE|L1CSR1_ICE)@h
+	ori	r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l
+	mtspr	SPRN_L1CSR1,r3
+	isync
+2:
+	mfspr	r3,SPRN_L1CSR1
+	andi.	r1,r3,L1CSR1_ICE@l
+	beq	2b
+
+	/* Enable/invalidate the D-Cache */
+	lis	r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h
+	ori	r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l
+	mtspr	SPRN_L1CSR0,r2
+1:
+	mfspr	r3,SPRN_L1CSR0
+	and.	r1,r3,r2
+	bne	1b
+
+	lis	r3,(L1CSR0_CPE|L1CSR0_DCE)@h
+	ori	r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l
+	mtspr	SPRN_L1CSR0,r3
+	isync
+2:
+	mfspr	r3,SPRN_L1CSR0
+	andi.	r1,r3,L1CSR0_DCE@l
+	beq	2b
+
+#define toreset(x) (x - __secondary_start_page + 0xfffff000)
+
+	/* get our PIR to figure out our table entry */
+	lis	r3,toreset(__spin_table)@h
+	ori	r3,r3,toreset(__spin_table)@l
+
+	/* r10 has the base address for the entry */
+	mfspr	r0,SPRN_PIR
+#ifdef CONFIG_E500MC
+	rlwinm	r4,r0,27,27,31
+#else
+	mr	r4,r0
+#endif
+	slwi	r8,r4,5
+	add	r10,r3,r8
+
+#if defined(CONFIG_E500MC) && defined(CONFIG_SYS_CACHE_STASHING)
+	/* set stash id to (coreID) * 2 + 32 + L1 CT (0) */
+	slwi	r8,r4,1
+	addi	r8,r8,32
+	mtspr	L1CSR2,r8
+#endif
+
+#ifdef CONFIG_BACKSIDE_L2_CACHE
+	/* Enable/invalidate the L2 cache */
+	msync
+	lis	r2,(L2CSR0_L2FI|L2CSR0_L2LFC)@h
+	ori	r2,r2,(L2CSR0_L2FI|L2CSR0_L2LFC)@l
+	mtspr	SPRN_L2CSR0,r2
+1:
+	mfspr	r3,SPRN_L2CSR0
+	and.	r1,r3,r2
+	bne	1b
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+	/* set stash id to (coreID) * 2 + 32 + L2 (1) */
+	addi	r3,r8,1
+	mtspr	SPRN_L2CSR1,r3
+#endif
+
+	lis	r3,CONFIG_SYS_INIT_L2CSR0@h
+	ori	r3,r3,CONFIG_SYS_INIT_L2CSR0@l
+	mtspr	SPRN_L2CSR0,r3
+	isync
+2:
+	mfspr	r3,SPRN_L2CSR0
+	andis.	r1,r3,L2CSR0_L2E@h
+	beq	2b
+#endif
+
+#define EPAPR_MAGIC		(0x45504150)
+#define ENTRY_ADDR_UPPER	0
+#define ENTRY_ADDR_LOWER	4
+#define ENTRY_R3_UPPER		8
+#define ENTRY_R3_LOWER		12
+#define ENTRY_RESV		16
+#define ENTRY_PIR		20
+#define ENTRY_R6_UPPER		24
+#define ENTRY_R6_LOWER		28
+#define ENTRY_SIZE		32
+
+	/* setup the entry */
+	li	r3,0
+	li	r8,1
+	stw	r0,ENTRY_PIR(r10)
+	stw	r3,ENTRY_ADDR_UPPER(r10)
+	stw	r8,ENTRY_ADDR_LOWER(r10)
+	stw	r3,ENTRY_R3_UPPER(r10)
+	stw	r4,ENTRY_R3_LOWER(r10)
+	stw	r3,ENTRY_R6_UPPER(r10)
+	stw	r3,ENTRY_R6_LOWER(r10)
+
+	/* load r13 with the address of the 'bootpg' in SDRAM */
+	lis	r13,toreset(__bootpg_addr)@h
+	ori	r13,r13,toreset(__bootpg_addr)@l
+	lwz	r13,0(r13)
+
+	/* setup mapping for AS = 1, and jump there */
+	lis	r11,(MAS0_TLBSEL(1)|MAS0_ESEL(1))@h
+	mtspr	SPRN_MAS0,r11
+	lis	r11,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r11,r11,(MAS1_TS|MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
+	mtspr	SPRN_MAS1,r11
+	oris	r11,r13,(MAS2_I|MAS2_G)@h
+	ori	r11,r13,(MAS2_I|MAS2_G)@l
+	mtspr	SPRN_MAS2,r11
+	oris	r11,r13,(MAS3_SX|MAS3_SW|MAS3_SR)@h
+	ori	r11,r13,(MAS3_SX|MAS3_SW|MAS3_SR)@l
+	mtspr	SPRN_MAS3,r11
+	tlbwe
+
+	bl	1f
+1:	mflr	r11
+	/*
+	 * OR in 0xfff to create a mask of the bootpg SDRAM address.  We use
+	 * this mask to fixup the cpu spin table and the address that we want
+	 * to jump to, eg change them from 0xfffffxxx to 0x7ffffxxx if the
+	 * bootpg is at 0x7ffff000 in SDRAM.
+	 */
+	ori	r13,r13,0xfff
+	and	r11, r11, r13
+	and	r10, r10, r13
+
+	addi	r11,r11,(2f-1b)
+	mfmsr	r13
+	ori	r12,r13,MSR_IS|MSR_DS@l
+
+	mtspr	SPRN_SRR0,r11
+	mtspr	SPRN_SRR1,r12
+	rfi
+
+	/* spin waiting for addr */
+2:
+	lwz	r4,ENTRY_ADDR_LOWER(r10)
+	andi.	r11,r4,1
+	bne	2b
+	isync
+
+	/* setup IVORs to match fixed offsets */
+#include "fixed_ivor.S"
+
+	/* get the upper bits of the addr */
+	lwz	r11,ENTRY_ADDR_UPPER(r10)
+
+	/* setup branch addr */
+	mtspr	SPRN_SRR0,r4
+
+	/* mark the entry as released */
+	li	r8,3
+	stw	r8,ENTRY_ADDR_LOWER(r10)
+
+	/* mask by ~64M to setup our tlb we will jump to */
+	rlwinm	r12,r4,0,0,5
+
+	/* setup r3, r4, r5, r6, r7, r8, r9 */
+	lwz	r3,ENTRY_R3_LOWER(r10)
+	li	r4,0
+	li	r5,0
+	lwz	r6,ENTRY_R6_LOWER(r10)
+	lis	r7,(64*1024*1024)@h
+	li	r8,0
+	li	r9,0
+
+	/* load up the pir */
+	lwz	r0,ENTRY_PIR(r10)
+	mtspr	SPRN_PIR,r0
+	mfspr	r0,SPRN_PIR
+	stw	r0,ENTRY_PIR(r10)
+
+	mtspr	IVPR,r12
+/*
+ * Coming here, we know the cpu has one TLB mapping in TLB1[0]
+ * which maps 0xfffff000-0xffffffff one-to-one.  We set up a
+ * second mapping that maps addr 1:1 for 64M, and then we jump to
+ * addr
+ */
+	lis	r10,(MAS0_TLBSEL(1)|MAS0_ESEL(0))@h
+	mtspr	SPRN_MAS0,r10
+	lis	r10,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r10,r10,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
+	mtspr	SPRN_MAS1,r10
+	/* WIMGE = 0b00000 for now */
+	mtspr	SPRN_MAS2,r12
+	ori	r12,r12,(MAS3_SX|MAS3_SW|MAS3_SR)
+	mtspr	SPRN_MAS3,r12
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+	mtspr	SPRN_MAS7,r11
+#endif
+	tlbwe
+
+/* Now we have another mapping for this page, so we jump to that
+ * mapping
+ */
+	mtspr	SPRN_SRR1,r13
+	rfi
+
+	/*
+	 * Allocate some space for the SDRAM address of the bootpg.
+	 * This variable has to be in the boot page so that it can
+	 * be accessed by secondary cores when they come out of reset.
+	 */
+	.globl __bootpg_addr
+__bootpg_addr:
+	.long	0
+
+	.align L1_CACHE_SHIFT
+	.globl __spin_table
+__spin_table:
+	.space CONFIG_MAX_CPUS*ENTRY_SIZE
+
+	/* Fill in the empty space.  The actual reset vector is
+	 * the last word of the page */
+__secondary_start_code_end:
+	.space 4092 - (__secondary_start_code_end - __secondary_start_page)
+__secondary_reset_vector:
+	b	__secondary_start_page
diff --git a/arch/ppc/cpu/mpc85xx/resetvec.S b/arch/ppc/cpu/mpc85xx/resetvec.S
new file mode 100644
index 0000000..29555d4
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/resetvec.S
@@ -0,0 +1,2 @@
+	.section .resetvec,"ax"
+	b _start_e500
diff --git a/arch/ppc/cpu/mpc85xx/serial_scc.c b/arch/ppc/cpu/mpc85xx/serial_scc.c
new file mode 100644
index 0000000..2dab212
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/serial_scc.c
@@ -0,0 +1,268 @@
+/*
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ * Modified based on 8260 for 8560.
+ *
+ * (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
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00.
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SCC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <asm/cpm_85xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_ON_SCC)
+
+#if CONFIG_CONS_INDEX == 1	/* Console on SCC1 */
+
+#define SCC_INDEX		0
+#define PROFF_SCC		PROFF_SCC1
+#define CMXSCR_MASK		(CMXSCR_GR1|CMXSCR_SC1|\
+					CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC1_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 2	/* Console on SCC2 */
+
+#define SCC_INDEX		1
+#define PROFF_SCC		PROFF_SCC2
+#define CMXSCR_MASK		(CMXSCR_GR2|CMXSCR_SC2|\
+					CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC2_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 3	/* Console on SCC3 */
+
+#define SCC_INDEX		2
+#define PROFF_SCC		PROFF_SCC3
+#define CMXSCR_MASK		(CMXSCR_GR3|CMXSCR_SC3|\
+					CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC3_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 4	/* Console on SCC4 */
+
+#define SCC_INDEX		3
+#define PROFF_SCC		PROFF_SCC4
+#define CMXSCR_MASK		(CMXSCR_GR4|CMXSCR_SC4|\
+					CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define CMXSCR_VALUE		(CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define CPM_CR_SCC_PAGE		CPM_CR_SCC4_PAGE
+#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+int serial_init (void)
+{
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	volatile ccsr_cpm_scc_t *sp;
+	volatile scc_uart_t *up;
+	volatile cbd_t *tbdf, *rbdf;
+	volatile ccsr_cpm_cp_t *cp = &(cpm->im_cpm_cp);
+	uint	dpaddr;
+
+	/* initialize pointers to SCC */
+
+	sp = (ccsr_cpm_scc_t *) &(cpm->im_cpm_scc[SCC_INDEX]);
+	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+
+	/* Disable transmitter/receiver.
+	*/
+	sp->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* put the SCC channel into NMSI (non multiplexd serial interface)
+	 * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+	 */
+	cpm->im_cpm_mux.cmxscr = \
+		(cpm->im_cpm_mux.cmxscr&~CMXSCR_MASK)|CMXSCR_VALUE;
+
+	/* Set up the baud rate generator.
+	*/
+	serial_setbrg ();
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	dpaddr = m8560_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rbdf = (cbd_t *)&(cpm->im_dprambase[dpaddr]);
+	rbdf->cbd_bufaddr = (uint) (rbdf+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+	tbdf->cbd_sc = BD_SC_WRAP;
+
+	/* Set up the uart parameters in the parameter ram.
+	*/
+	up->scc_genscc.scc_rbase = dpaddr;
+	up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+	up->scc_genscc.scc_rfcr = CPMFCR_EB;
+	up->scc_genscc.scc_tfcr = CPMFCR_EB;
+	up->scc_genscc.scc_mrblr = 1;
+	up->scc_maxidl = 0;
+	up->scc_brkcr = 1;
+	up->scc_parec = 0;
+	up->scc_frmec = 0;
+	up->scc_nosec = 0;
+	up->scc_brkec = 0;
+	up->scc_uaddr1 = 0;
+	up->scc_uaddr2 = 0;
+	up->scc_toseq = 0;
+	up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+	up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+	up->scc_rccm = 0xc0ff;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->sccm = 0;
+	sp->scce = 0xffff;
+
+	/* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+	*/
+	sp->gsmrh = SCC_GSMRH_RFW;	/* 8 bit FIFO */
+	sp->gsmrl = \
+		SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+	/* Set CTS no flow control, 1 stop bit, 8 bit character length,
+	 * normal async UART mode, no parity
+	 */
+	sp->psmr = SCU_PSMR_CL;
+
+	/* execute the "Init Rx and Tx params" CP command.
+	*/
+
+	while (cp->cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
+					0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver.
+	*/
+	sp->gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+	return (0);
+}
+
+void
+serial_setbrg (void)
+{
+#if defined(CONFIG_CONS_USE_EXTC)
+	m8560_cpm_extcbrg(SCC_INDEX, gd->baudrate,
+		CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+	m8560_cpm_setbrg(SCC_INDEX, gd->baudrate);
+#endif
+}
+
+void
+serial_putc(const char c)
+{
+	volatile scc_uart_t	*up;
+	volatile cbd_t		*tbdf;
+	volatile ccsr_cpm_t	*cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+	tbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_tbase]);
+
+	/* Wait for last character to go.
+	 */
+	while (tbdf->cbd_sc & BD_SC_READY)
+		;
+
+	/* Load the character into the transmit buffer.
+	 */
+	*(volatile char *)tbdf->cbd_bufaddr = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int
+serial_getc(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile ccsr_cpm_t	*cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	unsigned char		c;
+
+	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+	rbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_rbase]);
+
+	/* Wait for character to show up.
+	 */
+	while (rbdf->cbd_sc & BD_SC_EMPTY)
+		;
+
+	/* Grab the char and clear the buffer again.
+	 */
+	c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return (c);
+}
+
+int
+serial_tstc()
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile ccsr_cpm_t	*cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+
+	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+	rbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_rbase]);
+
+	return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0);
+}
+
+#endif	/* CONFIG_CONS_ON_SCC */
diff --git a/arch/ppc/cpu/mpc85xx/speed.c b/arch/ppc/cpu/mpc85xx/speed.c
new file mode 100644
index 0000000..268edbc
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/speed.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2004, 2007-2009 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao, (X.Xiao@motorola.com)
+ *
+ * (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 <asm/processor.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* --------------------------------------------------------------- */
+
+void get_sys_info (sys_info_t * sysInfo)
+{
+	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#ifdef CONFIG_FSL_CORENET
+	volatile ccsr_clk_t *clk = (void *)(CONFIG_SYS_FSL_CORENET_CLK_ADDR);
+
+	const u8 core_cplx_PLL[16] = {
+		[ 0] = 0,	/* CC1 PPL / 1 */
+		[ 1] = 0,	/* CC1 PPL / 2 */
+		[ 2] = 0,	/* CC1 PPL / 4 */
+		[ 4] = 1,	/* CC2 PPL / 1 */
+		[ 5] = 1,	/* CC2 PPL / 2 */
+		[ 6] = 1,	/* CC2 PPL / 4 */
+		[ 8] = 2,	/* CC3 PPL / 1 */
+		[ 9] = 2,	/* CC3 PPL / 2 */
+		[10] = 2,	/* CC3 PPL / 4 */
+		[12] = 3,	/* CC4 PPL / 1 */
+		[13] = 3,	/* CC4 PPL / 2 */
+		[14] = 3,	/* CC4 PPL / 4 */
+	};
+
+	const u8 core_cplx_PLL_div[16] = {
+		[ 0] = 1,	/* CC1 PPL / 1 */
+		[ 1] = 2,	/* CC1 PPL / 2 */
+		[ 2] = 4,	/* CC1 PPL / 4 */
+		[ 4] = 1,	/* CC2 PPL / 1 */
+		[ 5] = 2,	/* CC2 PPL / 2 */
+		[ 6] = 4,	/* CC2 PPL / 4 */
+		[ 8] = 1,	/* CC3 PPL / 1 */
+		[ 9] = 2,	/* CC3 PPL / 2 */
+		[10] = 4,	/* CC3 PPL / 4 */
+		[12] = 1,	/* CC4 PPL / 1 */
+		[13] = 2,	/* CC4 PPL / 2 */
+		[14] = 4,	/* CC4 PPL / 4 */
+	};
+	uint lcrr_div, i, freqCC_PLL[4], rcw_tmp;
+	unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
+
+	sysInfo->freqSystemBus = sysclk;
+	sysInfo->freqDDRBus = sysclk;
+	freqCC_PLL[0] = sysclk;
+	freqCC_PLL[1] = sysclk;
+	freqCC_PLL[2] = sysclk;
+	freqCC_PLL[3] = sysclk;
+
+	sysInfo->freqSystemBus *= (in_be32(&gur->rcwsr[0]) >> 25) & 0x1f;
+	sysInfo->freqDDRBus *= ((in_be32(&gur->rcwsr[0]) >> 17) & 0x1f);
+	freqCC_PLL[0] *= (in_be32(&clk->pllc1gsr) >> 1) & 0x3f;
+	freqCC_PLL[1] *= (in_be32(&clk->pllc2gsr) >> 1) & 0x3f;
+	freqCC_PLL[2] *= (in_be32(&clk->pllc3gsr) >> 1) & 0x3f;
+	freqCC_PLL[3] *= (in_be32(&clk->pllc4gsr) >> 1) & 0x3f;
+
+	rcw_tmp = in_be32(&gur->rcwsr[3]);
+	for (i = 0; i < cpu_numcores(); i++) {
+		u32 c_pll_sel = (in_be32(&clk->clkc0csr + i*8) >> 27) & 0xf;
+		u32 cplx_pll = core_cplx_PLL[c_pll_sel];
+
+		sysInfo->freqProcessor[i] =
+			 freqCC_PLL[cplx_pll] / core_cplx_PLL_div[c_pll_sel];
+	}
+
+#define PME_CLK_SEL	0x80000000
+#define FM1_CLK_SEL	0x40000000
+#define FM2_CLK_SEL	0x20000000
+	rcw_tmp = in_be32(&gur->rcwsr[7]);
+
+#ifdef CONFIG_SYS_DPAA_PME
+	if (rcw_tmp & PME_CLK_SEL)
+		sysInfo->freqPME = freqCC_PLL[2] / 2;
+	else
+		sysInfo->freqPME = sysInfo->freqSystemBus / 2;
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+	if (rcw_tmp & FM1_CLK_SEL)
+		sysInfo->freqFMan[0] = freqCC_PLL[2] / 2;
+	else
+		sysInfo->freqFMan[0] = sysInfo->freqSystemBus / 2;
+#if (CONFIG_SYS_NUM_FMAN) == 2
+	if (rcw_tmp & FM2_CLK_SEL)
+		sysInfo->freqFMan[1] = freqCC_PLL[2] / 2;
+	else
+		sysInfo->freqFMan[1] = sysInfo->freqSystemBus / 2;
+#endif
+#endif
+
+#else
+	uint plat_ratio,e500_ratio,half_freqSystemBus;
+	uint lcrr_div;
+	int i;
+#ifdef CONFIG_QE
+	u32 qe_ratio;
+#endif
+
+	plat_ratio = (gur->porpllsr) & 0x0000003e;
+	plat_ratio >>= 1;
+	sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ;
+
+	/* Divide before multiply to avoid integer
+	 * overflow for processor speeds above 2GHz */
+	half_freqSystemBus = sysInfo->freqSystemBus/2;
+	for (i = 0; i < cpu_numcores(); i++) {
+		e500_ratio = ((gur->porpllsr) >> (i * 8 + 16)) & 0x3f;
+		sysInfo->freqProcessor[i] = e500_ratio * half_freqSystemBus;
+	}
+
+	/* Note: freqDDRBus is the MCLK frequency, not the data rate. */
+	sysInfo->freqDDRBus = sysInfo->freqSystemBus;
+
+#ifdef CONFIG_DDR_CLK_FREQ
+	{
+		u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO)
+			>> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT;
+		if (ddr_ratio != 0x7)
+			sysInfo->freqDDRBus = ddr_ratio * CONFIG_DDR_CLK_FREQ;
+	}
+#endif
+#endif
+
+#ifdef CONFIG_QE
+	qe_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_QE_RATIO)
+			>> MPC85xx_PORPLLSR_QE_RATIO_SHIFT;
+	sysInfo->freqQE = qe_ratio * CONFIG_SYS_CLK_FREQ;
+#endif
+
+#if defined(CONFIG_SYS_LBC_LCRR)
+	/* We will program LCRR to this value later */
+	lcrr_div = CONFIG_SYS_LBC_LCRR & LCRR_CLKDIV;
+#else
+	{
+	    volatile ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR);
+	    lcrr_div = in_be32(&lbc->lcrr) & LCRR_CLKDIV;
+	}
+#endif
+	if (lcrr_div == 2 || lcrr_div == 4 || lcrr_div == 8) {
+#if defined(CONFIG_FSL_CORENET)
+		/* If this is corenet based SoC, bit-representation
+		 * for four times the clock divider values.
+		 */
+		lcrr_div *= 4;
+#elif !defined(CONFIG_MPC8540) && !defined(CONFIG_MPC8541) && \
+    !defined(CONFIG_MPC8555) && !defined(CONFIG_MPC8560)
+		/*
+		 * Yes, the entire PQ38 family use the same
+		 * bit-representation for twice the clock divider values.
+		 */
+		lcrr_div *= 2;
+#endif
+		sysInfo->freqLocalBus = sysInfo->freqSystemBus / lcrr_div;
+	} else {
+		/* In case anyone cares what the unknown value is */
+		sysInfo->freqLocalBus = lcrr_div;
+	}
+}
+
+
+int get_clocks (void)
+{
+	sys_info_t sys_info;
+#ifdef CONFIG_MPC8544
+	volatile ccsr_gur_t *gur = (void *) CONFIG_SYS_MPC85xx_GUTS_ADDR;
+#endif
+#if defined(CONFIG_CPM2)
+	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+	uint sccr, dfbrg;
+
+	/* set VCO = 4 * BRG */
+	cpm->im_cpm_intctl.sccr &= 0xfffffffc;
+	sccr = cpm->im_cpm_intctl.sccr;
+	dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+#endif
+	get_sys_info (&sys_info);
+	gd->cpu_clk = sys_info.freqProcessor[0];
+	gd->bus_clk = sys_info.freqSystemBus;
+	gd->mem_clk = sys_info.freqDDRBus;
+	gd->lbc_clk = sys_info.freqLocalBus;
+
+#ifdef CONFIG_QE
+	gd->qe_clk = sys_info.freqQE;
+	gd->brg_clk = gd->qe_clk / 2;
+#endif
+	/*
+	 * The base clock for I2C depends on the actual SOC.  Unfortunately,
+	 * there is no pattern that can be used to determine the frequency, so
+	 * the only choice is to look up the actual SOC number and use the value
+	 * for that SOC. This information is taken from application note
+	 * AN2919.
+	 */
+#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
+	defined(CONFIG_MPC8560) || defined(CONFIG_MPC8555)
+	gd->i2c1_clk = sys_info.freqSystemBus;
+#elif defined(CONFIG_MPC8544)
+	/*
+	 * On the 8544, the I2C clock is the same as the SEC clock.  This can be
+	 * either CCB/2 or CCB/3, depending on the value of cfg_sec_freq. See
+	 * 4.4.3.3 of the 8544 RM.  Note that this might actually work for all
+	 * 85xx, but only the 8544 has cfg_sec_freq, so it's unknown if the
+	 * PORDEVSR2_SEC_CFG bit is 0 on all 85xx boards that are not an 8544.
+	 */
+	if (gur->pordevsr2 & MPC85xx_PORDEVSR2_SEC_CFG)
+		gd->i2c1_clk = sys_info.freqSystemBus / 3;
+	else
+		gd->i2c1_clk = sys_info.freqSystemBus / 2;
+#else
+	/* Most 85xx SOCs use CCB/2, so this is the default behavior. */
+	gd->i2c1_clk = sys_info.freqSystemBus / 2;
+#endif
+	gd->i2c2_clk = gd->i2c1_clk;
+
+#if defined(CONFIG_FSL_ESDHC)
+#ifdef CONFIG_MPC8569
+	gd->sdhc_clk = gd->bus_clk;
+#else
+	gd->sdhc_clk = gd->bus_clk / 2;
+#endif
+#endif /* defined(CONFIG_FSL_ESDHC) */
+
+#if defined(CONFIG_CPM2)
+	gd->vco_out = 2*sys_info.freqSystemBus;
+	gd->cpm_clk = gd->vco_out / 2;
+	gd->scc_clk = gd->vco_out / 4;
+	gd->brg_clk = gd->vco_out / (1 << (2 * (dfbrg + 1)));
+#endif
+
+	if(gd->cpu_clk != 0) return (0);
+	else return (1);
+}
+
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+	return gd->bus_clk;
+}
+
+/********************************************
+ * get_ddr_freq
+ * return ddr bus freq in Hz
+ *********************************************/
+ulong get_ddr_freq (ulong dummy)
+{
+	return gd->mem_clk;
+}
diff --git a/arch/ppc/cpu/mpc85xx/start.S b/arch/ppc/cpu/mpc85xx/start.S
new file mode 100644
index 0000000..b3cb56a
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/start.S
@@ -0,0 +1,1195 @@
+/*
+ * Copyright 2004, 2007-2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2003  Motorola,Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot Startup Code for Motorola 85xx PowerPC based Embedded Boards
+ *
+ * The processor starts at 0xfffffffc and the code is first executed in the
+ * last 4K page(0xfffff000-0xffffffff) in flash/rom.
+ *
+ */
+
+#include <config.h>
+#include <mpc85xx.h>
+#include <timestamp.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
+
+#undef	MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME )	/* Machine Check */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+#ifndef CONFIG_NAND_SPL
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+#endif
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * e500 Startup -- after reset only the last 4KB of the effective
+ * address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg
+ * section is located at THIS LAST page and basically does three
+ * things: clear some registers, set up exception tables and
+ * add more TLB entries for 'larger spaces'(e.g. the boot rom) to
+ * continue the boot procedure.
+
+ * Once the boot rom is mapped by TLB entries we can proceed
+ * with normal startup.
+ *
+ */
+
+	.section .bootpg,"ax"
+	.globl _start_e500
+
+_start_e500:
+
+/* clear registers/arrays not reset by hardware */
+
+	/* L1 */
+	li	r0,2
+	mtspr	L1CSR0,r0	/* invalidate d-cache */
+	mtspr	L1CSR1,r0	/* invalidate i-cache */
+
+	mfspr	r1,DBSR
+	mtspr	DBSR,r1		/* Clear all valid bits */
+
+	/*
+	 *	Enable L1 Caches early
+	 *
+	 */
+
+#if defined(CONFIG_E500MC) && defined(CONFIG_SYS_CACHE_STASHING)
+	/* set stash id to (coreID) * 2 + 32 + L1 CT (0) */
+	li	r2,(32 + 0)
+	mtspr	L1CSR2,r2
+#endif
+
+	/* Enable/invalidate the I-Cache */
+	lis	r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h
+	ori	r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l
+	mtspr	SPRN_L1CSR1,r2
+1:
+	mfspr	r3,SPRN_L1CSR1
+	and.	r1,r3,r2
+	bne	1b
+
+	lis	r3,(L1CSR1_CPE|L1CSR1_ICE)@h
+	ori	r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l
+	mtspr	SPRN_L1CSR1,r3
+	isync
+2:
+	mfspr	r3,SPRN_L1CSR1
+	andi.	r1,r3,L1CSR1_ICE@l
+	beq	2b
+
+	/* Enable/invalidate the D-Cache */
+	lis	r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h
+	ori	r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l
+	mtspr	SPRN_L1CSR0,r2
+1:
+	mfspr	r3,SPRN_L1CSR0
+	and.	r1,r3,r2
+	bne	1b
+
+	lis	r3,(L1CSR0_CPE|L1CSR0_DCE)@h
+	ori	r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l
+	mtspr	SPRN_L1CSR0,r3
+	isync
+2:
+	mfspr	r3,SPRN_L1CSR0
+	andi.	r1,r3,L1CSR0_DCE@l
+	beq	2b
+
+	/* Setup interrupt vectors */
+	lis	r1,TEXT_BASE@h
+	mtspr	IVPR,r1
+
+	li	r1,0x0100
+	mtspr	IVOR0,r1	/* 0: Critical input */
+	li	r1,0x0200
+	mtspr	IVOR1,r1	/* 1: Machine check */
+	li	r1,0x0300
+	mtspr	IVOR2,r1	/* 2: Data storage */
+	li	r1,0x0400
+	mtspr	IVOR3,r1	/* 3: Instruction storage */
+	li	r1,0x0500
+	mtspr	IVOR4,r1	/* 4: External interrupt */
+	li	r1,0x0600
+	mtspr	IVOR5,r1	/* 5: Alignment */
+	li	r1,0x0700
+	mtspr	IVOR6,r1	/* 6: Program check */
+	li	r1,0x0800
+	mtspr	IVOR7,r1	/* 7: floating point unavailable */
+	li	r1,0x0900
+	mtspr	IVOR8,r1	/* 8: System call */
+	/* 9: Auxiliary processor unavailable(unsupported) */
+	li	r1,0x0a00
+	mtspr	IVOR10,r1	/* 10: Decrementer */
+	li	r1,0x0b00
+	mtspr	IVOR11,r1	/* 11: Interval timer */
+	li	r1,0x0c00
+	mtspr	IVOR12,r1	/* 12: Watchdog timer */
+	li	r1,0x0d00
+	mtspr	IVOR13,r1	/* 13: Data TLB error */
+	li	r1,0x0e00
+	mtspr	IVOR14,r1	/* 14: Instruction TLB error */
+	li	r1,0x0f00
+	mtspr	IVOR15,r1	/* 15: Debug */
+
+	/* Clear and set up some registers. */
+	li      r0,0x0000
+	lis	r1,0xffff
+	mtspr	DEC,r0			/* prevent dec exceptions */
+	mttbl	r0			/* prevent fit & wdt exceptions */
+	mttbu	r0
+	mtspr	TSR,r1			/* clear all timer exception status */
+	mtspr	TCR,r0			/* disable all */
+	mtspr	ESR,r0			/* clear exception syndrome register */
+	mtspr	MCSR,r0			/* machine check syndrome register */
+	mtxer	r0			/* clear integer exception register */
+
+#ifdef CONFIG_SYS_BOOK3E_HV
+	mtspr	MAS8,r0			/* make sure MAS8 is clear */
+#endif
+
+	/* Enable Time Base and Select Time Base Clock */
+	lis	r0,HID0_EMCP@h		/* Enable machine check */
+#if defined(CONFIG_ENABLE_36BIT_PHYS)
+	ori	r0,r0,HID0_ENMAS7@l	/* Enable MAS7 */
+#endif
+#ifndef CONFIG_E500MC
+	ori	r0,r0,HID0_TBEN@l	/* Enable Timebase */
+#endif
+	mtspr	HID0,r0
+
+#ifndef CONFIG_E500MC
+	li	r0,(HID1_ASTME|HID1_ABE)@l	/* Addr streaming & broadcast */
+	mfspr	r3,PVR
+	andi.	r3,r3, 0xff
+	cmpwi	r3,0x50@l	/* if we are rev 5.0 or greater set MBDD */
+	blt 1f
+	/* Set MBDD bit also */
+	ori r0, r0, HID1_MBDD@l
+1:
+	mtspr	HID1,r0
+#endif
+
+	/* Enable Branch Prediction */
+#if defined(CONFIG_BTB)
+	lis	r0,BUCSR_ENABLE@h
+	ori	r0,r0,BUCSR_ENABLE@l
+	mtspr	SPRN_BUCSR,r0
+#endif
+
+#if defined(CONFIG_SYS_INIT_DBCR)
+	lis	r1,0xffff
+	ori	r1,r1,0xffff
+	mtspr	DBSR,r1			/* Clear all status bits */
+	lis	r0,CONFIG_SYS_INIT_DBCR@h	/* DBCR0[IDM] must be set */
+	ori	r0,r0,CONFIG_SYS_INIT_DBCR@l
+	mtspr	DBCR0,r0
+#endif
+
+#ifdef CONFIG_MPC8569
+#define CONFIG_SYS_LBC_ADDR (CONFIG_SYS_CCSRBAR_DEFAULT + 0x5000)
+#define CONFIG_SYS_LBCR_ADDR (CONFIG_SYS_LBC_ADDR + 0xd0)
+
+	/* MPC8569 Rev.0 silcon needs to set bit 13 of LBCR to allow elBC to
+	 * use address space which is more than 12bits, and it must be done in
+	 * the 4K boot page. So we set this bit here.
+	 */
+
+	/* create a temp mapping TLB0[0] for LBCR  */
+	lis     r6,FSL_BOOKE_MAS0(0, 0, 0)@h
+	ori     r6,r6,FSL_BOOKE_MAS0(0, 0, 0)@l
+
+	lis     r7,FSL_BOOKE_MAS1(1, 0, 0, 0, BOOKE_PAGESZ_4K)@h
+	ori     r7,r7,FSL_BOOKE_MAS1(1, 0, 0, 0, BOOKE_PAGESZ_4K)@l
+
+	lis     r8,FSL_BOOKE_MAS2(CONFIG_SYS_LBC_ADDR, MAS2_I|MAS2_G)@h
+	ori     r8,r8,FSL_BOOKE_MAS2(CONFIG_SYS_LBC_ADDR, MAS2_I|MAS2_G)@l
+
+	lis     r9,FSL_BOOKE_MAS3(CONFIG_SYS_LBC_ADDR, 0,
+						(MAS3_SX|MAS3_SW|MAS3_SR))@h
+	ori     r9,r9,FSL_BOOKE_MAS3(CONFIG_SYS_LBC_ADDR, 0,
+						(MAS3_SX|MAS3_SW|MAS3_SR))@l
+
+	mtspr   MAS0,r6
+	mtspr   MAS1,r7
+	mtspr   MAS2,r8
+	mtspr   MAS3,r9
+	isync
+	msync
+	tlbwe
+
+	/* Set LBCR register */
+	lis     r4,CONFIG_SYS_LBCR_ADDR@h
+	ori     r4,r4,CONFIG_SYS_LBCR_ADDR@l
+
+	lis     r5,CONFIG_SYS_LBC_LBCR@h
+	ori     r5,r5,CONFIG_SYS_LBC_LBCR@l
+	stw     r5,0(r4)
+	isync
+
+	/* invalidate this temp TLB */
+	lis	r4,CONFIG_SYS_LBC_ADDR@h
+	ori	r4,r4,CONFIG_SYS_LBC_ADDR@l
+	tlbivax	0,r4
+	isync
+
+#endif /* CONFIG_MPC8569 */
+
+	lis     r6,FSL_BOOKE_MAS0(1, 15, 0)@h
+	ori     r6,r6,FSL_BOOKE_MAS0(1, 15, 0)@l
+
+#ifndef CONFIG_SYS_RAMBOOT
+	/* create a temp mapping in AS=1 to the 4M boot window */
+	lis     r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_4M)@h
+	ori     r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_4M)@l
+
+	lis     r8,FSL_BOOKE_MAS2(TEXT_BASE & 0xffc00000, (MAS2_I|MAS2_G))@h
+	ori     r8,r8,FSL_BOOKE_MAS2(TEXT_BASE & 0xffc00000, (MAS2_I|MAS2_G))@l
+
+	/* The 85xx has the default boot window 0xff800000 - 0xffffffff */
+	lis     r9,FSL_BOOKE_MAS3(0xffc00000, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h
+	ori     r9,r9,FSL_BOOKE_MAS3(0xffc00000, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@l
+#else
+	/*
+	 * create a temp mapping in AS=1 to the 1M TEXT_BASE space, the main
+	 * image has been relocated to TEXT_BASE on the second stage.
+	 */
+	lis     r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_1M)@h
+	ori     r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_1M)@l
+
+	lis     r8,FSL_BOOKE_MAS2(TEXT_BASE, (MAS2_I|MAS2_G))@h
+	ori     r8,r8,FSL_BOOKE_MAS2(TEXT_BASE, (MAS2_I|MAS2_G))@l
+
+	lis     r9,FSL_BOOKE_MAS3(TEXT_BASE, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h
+	ori     r9,r9,FSL_BOOKE_MAS3(TEXT_BASE, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@l
+#endif
+
+	mtspr   MAS0,r6
+	mtspr   MAS1,r7
+	mtspr   MAS2,r8
+	mtspr   MAS3,r9
+	isync
+	msync
+	tlbwe
+
+	/* create a temp mapping in AS=1 to the stack */
+	lis     r6,FSL_BOOKE_MAS0(1, 14, 0)@h
+	ori     r6,r6,FSL_BOOKE_MAS0(1, 14, 0)@l
+
+	lis     r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_16K)@h
+	ori     r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_16K)@l
+
+	lis     r8,FSL_BOOKE_MAS2(CONFIG_SYS_INIT_RAM_ADDR, 0)@h
+	ori     r8,r8,FSL_BOOKE_MAS2(CONFIG_SYS_INIT_RAM_ADDR, 0)@l
+
+	lis     r9,FSL_BOOKE_MAS3(CONFIG_SYS_INIT_RAM_ADDR, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h
+	ori     r9,r9,FSL_BOOKE_MAS3(CONFIG_SYS_INIT_RAM_ADDR, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@l
+
+	mtspr   MAS0,r6
+	mtspr   MAS1,r7
+	mtspr   MAS2,r8
+	mtspr   MAS3,r9
+	isync
+	msync
+	tlbwe
+
+	lis	r6,MSR_IS|MSR_DS@h
+	ori	r6,r6,MSR_IS|MSR_DS@l
+	lis	r7,switch_as@h
+	ori	r7,r7,switch_as@l
+
+	mtspr	SPRN_SRR0,r7
+	mtspr	SPRN_SRR1,r6
+	rfi
+
+switch_as:
+/* L1 DCache is used for initial RAM */
+
+	/* Allocate Initial RAM in data cache.
+	 */
+	lis	r3,CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
+	mfspr	r2, L1CFG0
+	andi.	r2, r2, 0x1ff
+	/* cache size * 1024 / (2 * L1 line size) */
+	slwi	r2, r2, (10 - 1 - L1_CACHE_SHIFT)
+	mtctr	r2
+	li	r0,0
+1:
+	dcbz	r0,r3
+	dcbtls	0,r0,r3
+	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	1b
+
+	/* Jump out the last 4K page and continue to 'normal' start */
+#ifdef CONFIG_SYS_RAMBOOT
+	b	_start_cont
+#else
+	/* Calculate absolute address in FLASH and jump there		*/
+	/*--------------------------------------------------------------*/
+	lis	r3,CONFIG_SYS_MONITOR_BASE@h
+	ori	r3,r3,CONFIG_SYS_MONITOR_BASE@l
+	addi	r3,r3,_start_cont - _start + _START_OFFSET
+	mtlr	r3
+	blr
+#endif
+
+	.text
+	.globl	_start
+_start:
+	.long	0x27051956		/* U-BOOT Magic Number */
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+	.align	4
+	.globl	_start_cont
+_start_cont:
+	/* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache*/
+	lis	r1,CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r1,r1,CONFIG_SYS_INIT_SP_OFFSET@l
+
+	li	r0,0
+	stwu	r0,-4(r1)
+	stwu	r0,-4(r1)		/* Terminate call chain */
+
+	stwu	r1,-8(r1)		/* Save back chain and move SP */
+	lis	r0,RESET_VECTOR@h	/* Address of reset vector */
+	ori	r0,r0,RESET_VECTOR@l
+	stwu	r1,-8(r1)		/* Save back chain and move SP */
+	stw	r0,+12(r1)		/* Save return addr (underflow vect) */
+
+	GET_GOT
+	bl	cpu_init_early_f
+
+	/* switch back to AS = 0 */
+	lis	r3,(MSR_CE|MSR_ME|MSR_DE)@h
+	ori	r3,r3,(MSR_CE|MSR_ME|MSR_DE)@l
+	mtmsr	r3
+	isync
+
+	bl	cpu_init_f
+	bl	board_init_f
+	isync
+
+#ifndef CONFIG_NAND_SPL
+	. = EXC_OFF_SYS_RESET
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Critical input. */
+	CRIT_EXCEPTION(0x0100, CriticalInput, CritcalInputException)
+
+/* Machine check */
+	MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x0300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x0400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x0500, ExtInterrupt, ExtIntException)
+
+/* Alignment exception. */
+	. = 0x0600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x0700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	/* No FPU on MPC85xx.  This exception is not supposed to happen.
+	*/
+	STD_EXCEPTION(0x0800, FPUnavailable, UnknownException)
+
+	. = 0x0900
+/*
+ * 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	r20,0xd00-4	/* Get stack pointer */
+	lwz	r12,0(r20)
+	subi	r12,r12,12	/* Adjust stack pointer */
+	li	r0,0xc00+_end_back-SystemCall
+	cmplw	0,r0,r12	/* Check stack overflow */
+	bgt	1f
+	stw	r12,0(r20)
+
+	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		/* restore regs */
+	lwz	r12,0(r12)
+
+	lwz	r11,0(r12)
+	mtlr	r11
+	lwz	r11,4(r12)
+	mtspr	SRR0,r11
+	lwz	r11,8(r12)
+	mtspr	SRR1,r11
+
+	addi	r12,r12,12		/* Adjust stack pointer */
+	li	r20,0xd00-4
+	stw	r12,0(r20)
+
+	SYNC
+	rfi
+_end_back:
+
+	STD_EXCEPTION(0x0a00, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0x0b00, IntervalTimer, UnknownException)
+	STD_EXCEPTION(0x0c00, WatchdogTimer, UnknownException)
+
+	STD_EXCEPTION(0x0d00, DataTLBError, UnknownException)
+	STD_EXCEPTION(0x0e00, InstructionTLBError, UnknownException)
+
+	CRIT_EXCEPTION(0x0f00, DebugBreakpoint, DebugException )
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+
+	. = . + (0x100 - ( . & 0xff ))	/* align for debug */
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+crit_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	SPRN_CSRR0,r2
+	mtspr	SPRN_CSRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfci
+
+mck_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	SPRN_MCSRR0,r2
+	mtspr	SPRN_MCSRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfmci
+
+/* Cache functions.
+*/
+.globl invalidate_icache
+invalidate_icache:
+	mfspr	r0,L1CSR1
+	ori	r0,r0,L1CSR1_ICFI
+	msync
+	isync
+	mtspr	L1CSR1,r0
+	isync
+	blr				/* entire I cache */
+
+.globl invalidate_dcache
+invalidate_dcache:
+	mfspr	r0,L1CSR0
+	ori	r0,r0,L1CSR0_DCFI
+	msync
+	isync
+	mtspr	L1CSR0,r0
+	isync
+	blr
+
+	.globl	icache_enable
+icache_enable:
+	mflr	r8
+	bl	invalidate_icache
+	mtlr	r8
+	isync
+	mfspr	r4,L1CSR1
+	ori	r4,r4,0x0001
+	oris	r4,r4,0x0001
+	mtspr	L1CSR1,r4
+	isync
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r0,L1CSR1
+	lis	r3,0
+	ori	r3,r3,L1CSR1_ICE
+	andc	r0,r0,r3
+	mtspr	L1CSR1,r0
+	isync
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3,L1CSR1
+	andi.	r3,r3,L1CSR1_ICE
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mflr	r8
+	bl	invalidate_dcache
+	mtlr	r8
+	isync
+	mfspr	r0,L1CSR0
+	ori	r0,r0,0x0001
+	oris	r0,r0,0x0001
+	msync
+	isync
+	mtspr	L1CSR0,r0
+	isync
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r3,L1CSR0
+	lis	r4,0
+	ori	r4,r4,L1CSR0_DCE
+	andc	r3,r3,r4
+	mtspr	L1CSR0,r0
+	isync
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3,L1CSR0
+	andi.	r3,r3,L1CSR0_DCE
+	blr
+
+	.globl get_pir
+get_pir:
+	mfspr	r3,PIR
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3,PVR
+	blr
+
+	.globl get_svr
+get_svr:
+	mfspr	r3,SVR
+	blr
+
+	.globl wr_tcr
+wr_tcr:
+	mtspr	TCR,r3
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in8 */
+/* Description:	 Input 8 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	in8
+in8:
+	lbz	r3,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out8 */
+/* Description:	 Output 8 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out8
+out8:
+	stb	r4,0x0000(r3)
+	sync
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out16 */
+/* Description:	 Output 16 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out16
+out16:
+	sth	r4,0x0000(r3)
+	sync
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out16r */
+/* Description:	 Byte reverse and output 16 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out16r
+out16r:
+	sthbrx	r4,r0,r3
+	sync
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out32 */
+/* Description:	 Output 32 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out32
+out32:
+	stw	r4,0x0000(r3)
+	sync
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out32r */
+/* Description:	 Byte reverse and output 32 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out32r
+out32r:
+	stwbrx	r4,r0,r3
+	sync
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in16 */
+/* Description:	 Input 16 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	in16
+in16:
+	lhz	r3,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in16r */
+/* Description:	 Input 16 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+	.globl	in16r
+in16r:
+	lhbrx	r3,r0,r3
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in32 */
+/* Description:	 Input 32 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	in32
+in32:
+	lwz	3,0x0000(3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in32r */
+/* Description:	 Input 32 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+	.globl	in32r
+in32r:
+	lwbrx	r3,r0,r3
+	blr
+#endif  /* !CONFIG_NAND_SPL */
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void write_tlb(mas0, mas1, mas2, mas3, mas7)
+ */
+	.globl	write_tlb
+write_tlb:
+	mtspr	MAS0,r3
+	mtspr	MAS1,r4
+	mtspr	MAS2,r5
+	mtspr	MAS3,r6
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+	mtspr	MAS7,r7
+#endif
+	li	r3,0
+#ifdef CONFIG_SYS_BOOK3E_HV
+	mtspr	MAS8,r3
+#endif
+	isync
+	tlbwe
+	msync
+	isync
+	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 Init Data pointer	*/
+	mr	r10,r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,r5				/* Destination Address	*/
+	lis	r4,CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4,r4,CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5,GOT(__init_end)
+	sub	r5,r5,r4
+	li	r6,CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15,r10,r4
+
+	/* First our own GOT */
+	add	r12,r12,r15
+	/* 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
+
+	/*
+	 * Re-point the IVPR at RAM
+	 */
+	mtspr	IVPR,r10
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0,r10,in_ram - _start + _START_OFFSET
+	mtlr	r0
+	blr				/* NEVER RETURNS! */
+	.globl	in_ram
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0,r3,r4
+	beq	6f
+
+	li	r0,0
+5:
+	stw	r0,0(r3)
+	addi	r3,r3,4
+	cmplw	0,r3,r4
+	bne	5b
+6:
+
+	mr	r3,r9		/* Init Data pointer		*/
+	mr	r4,r10		/* Destination Address		*/
+	bl	board_init_r
+
+#ifndef CONFIG_NAND_SPL
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7,GOT(_start_of_vectors)
+	lwz	r8,GOT(_end_of_vectors)
+
+	li	r9,0x100		/* reset vector always at 0x100 */
+
+	cmplw	0,r7,r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0,0(r7)
+	stw	r0,0(r9)
+	addi	r7,r7,4
+	addi	r9,r9,4
+	cmplw	0,r7,r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7,.L_CriticalInput - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_MachineCheck - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_DataStorage - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_InstStorage - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_ExtInterrupt - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_Alignment - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_ProgramCheck - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_FPUnavailable - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_Decrementer - _start + _START_OFFSET
+	bl	trap_reloc
+	li	r7,.L_IntervalTimer - _start + _START_OFFSET
+	li	r8,_end_of_vectors - _start + _START_OFFSET
+2:
+	bl	trap_reloc
+	addi	r7,r7,0x100		/* next exception vector	*/
+	cmplw	0,r7,r8
+	blt	2b
+
+	lis	r7,0x0
+	mtspr	IVPR,r7
+
+	mtlr	r4			/* restore link register	*/
+	blr
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+	/* invalidate the INIT_RAM section */
+	lis	r3,(CONFIG_SYS_INIT_RAM_ADDR & ~(CONFIG_SYS_CACHELINE_SIZE-1))@h
+	ori	r3,r3,(CONFIG_SYS_INIT_RAM_ADDR & ~(CONFIG_SYS_CACHELINE_SIZE-1))@l
+	mfspr	r4,L1CFG0
+	andi.	r4,r4,0x1ff
+	slwi	r4,r4,(10 - 1 - L1_CACHE_SHIFT)
+	mtctr	r4
+1:	dcbi	r0,r3
+	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	1b
+	sync
+
+	/* Invalidate the TLB entries for the cache */
+	lis	r3,CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
+	tlbivax	0,r3
+	addi	r3,r3,0x1000
+	tlbivax	0,r3
+	addi	r3,r3,0x1000
+	tlbivax	0,r3
+	addi	r3,r3,0x1000
+	tlbivax	0,r3
+	isync
+	blr
+
+.globl flush_dcache
+flush_dcache:
+	mfspr	r3,SPRN_L1CFG0
+
+	rlwinm	r5,r3,9,3	/* Extract cache block size */
+	twlgti	r5,1		/* Only 32 and 64 byte cache blocks
+				 * are currently defined.
+				 */
+	li	r4,32
+	subfic	r6,r5,2		/* r6 = log2(1KiB / cache block size) -
+				 *      log2(number of ways)
+				 */
+	slw	r5,r4,r5	/* r5 = cache block size */
+
+	rlwinm	r7,r3,0,0xff	/* Extract number of KiB in the cache */
+	mulli	r7,r7,13	/* An 8-way cache will require 13
+				 * loads per set.
+				 */
+	slw	r7,r7,r6
+
+	/* save off HID0 and set DCFA */
+	mfspr	r8,SPRN_HID0
+	ori	r9,r8,HID0_DCFA@l
+	mtspr	SPRN_HID0,r9
+	isync
+
+	lis	r4,0
+	mtctr	r7
+
+1:	lwz	r3,0(r4)	/* Load... */
+	add	r4,r4,r5
+	bdnz	1b
+
+	msync
+	lis	r4,0
+	mtctr	r7
+
+1:	dcbf	0,r4		/* ...and flush. */
+	add	r4,r4,r5
+	bdnz	1b
+
+	/* restore HID0 */
+	mtspr	SPRN_HID0,r8
+	isync
+
+	blr
+
+.globl setup_ivors
+setup_ivors:
+
+#include "fixed_ivor.S"
+	blr
+#endif /* !CONFIG_NAND_SPL */
diff --git a/arch/ppc/cpu/mpc85xx/tlb.c b/arch/ppc/cpu/mpc85xx/tlb.c
new file mode 100644
index 0000000..b3037ac
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/tlb.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_ADDR_MAP
+#include <addr_map.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void invalidate_tlb(u8 tlb)
+{
+	if (tlb == 0)
+		mtspr(MMUCSR0, 0x4);
+	if (tlb == 1)
+		mtspr(MMUCSR0, 0x2);
+}
+
+void init_tlbs(void)
+{
+	int i;
+
+	for (i = 0; i < num_tlb_entries; i++) {
+		write_tlb(tlb_table[i].mas0,
+			  tlb_table[i].mas1,
+			  tlb_table[i].mas2,
+			  tlb_table[i].mas3,
+			  tlb_table[i].mas7);
+	}
+
+	return ;
+}
+
+#ifndef CONFIG_NAND_SPL
+static inline void use_tlb_cam(u8 idx)
+{
+	int i = idx / 32;
+	int bit = idx % 32;
+
+	gd->used_tlb_cams[i] |= (1 << bit);
+}
+
+static inline void free_tlb_cam(u8 idx)
+{
+	int i = idx / 32;
+	int bit = idx % 32;
+
+	gd->used_tlb_cams[i] &= ~(1 << bit);
+}
+
+void init_used_tlb_cams(void)
+{
+	int i;
+	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
+
+	for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++)
+		gd->used_tlb_cams[i] = 0;
+
+	/* walk all the entries */
+	for (i = 0; i < num_cam; i++) {
+		u32 _mas1;
+
+		mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0));
+
+		asm volatile("tlbre;isync");
+		_mas1 = mfspr(MAS1);
+
+		/* if the entry isn't valid skip it */
+		if ((_mas1 & MAS1_VALID))
+			use_tlb_cam(i);
+	}
+}
+
+int find_free_tlbcam(void)
+{
+	int i;
+	u32 idx;
+
+	for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) {
+		idx = ffz(gd->used_tlb_cams[i]);
+
+		if (idx != 32)
+			break;
+	}
+
+	idx += i * 32;
+
+	if (idx >= CONFIG_SYS_NUM_TLBCAMS)
+		return -1;
+
+	return idx;
+}
+
+void set_tlb(u8 tlb, u32 epn, u64 rpn,
+	     u8 perms, u8 wimge,
+	     u8 ts, u8 esel, u8 tsize, u8 iprot)
+{
+	u32 _mas0, _mas1, _mas2, _mas3, _mas7;
+
+	if (tlb == 1)
+		use_tlb_cam(esel);
+
+	_mas0 = FSL_BOOKE_MAS0(tlb, esel, 0);
+	_mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize);
+	_mas2 = FSL_BOOKE_MAS2(epn, wimge);
+	_mas3 = FSL_BOOKE_MAS3(rpn, 0, perms);
+	_mas7 = FSL_BOOKE_MAS7(rpn);
+
+	write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7);
+
+#ifdef CONFIG_ADDR_MAP
+	if ((tlb == 1) && (gd->flags & GD_FLG_RELOC))
+		addrmap_set_entry(epn, rpn, (1UL << ((tsize * 2) + 10)), esel);
+#endif
+}
+
+void disable_tlb(u8 esel)
+{
+	u32 _mas0, _mas1, _mas2, _mas3, _mas7;
+
+	free_tlb_cam(esel);
+
+	_mas0 = FSL_BOOKE_MAS0(1, esel, 0);
+	_mas1 = 0;
+	_mas2 = 0;
+	_mas3 = 0;
+	_mas7 = 0;
+
+	mtspr(MAS0, _mas0);
+	mtspr(MAS1, _mas1);
+	mtspr(MAS2, _mas2);
+	mtspr(MAS3, _mas3);
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+	mtspr(MAS7, _mas7);
+#endif
+	asm volatile("isync;msync;tlbwe;isync");
+
+#ifdef CONFIG_ADDR_MAP
+	if (gd->flags & GD_FLG_RELOC)
+		addrmap_set_entry(0, 0, 0, esel);
+#endif
+}
+
+static void tlbsx (const volatile unsigned *addr)
+{
+	__asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr));
+}
+
+/* return -1 if we didn't find anything */
+int find_tlb_idx(void *addr, u8 tlbsel)
+{
+	u32 _mas0, _mas1;
+
+	/* zero out Search PID, AS */
+	mtspr(MAS6, 0);
+
+	tlbsx(addr);
+
+	_mas0 = mfspr(MAS0);
+	_mas1 = mfspr(MAS1);
+
+	/* we found something, and its in the TLB we expect */
+	if ((MAS1_VALID & _mas1) &&
+		(MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) {
+		return ((_mas0 & MAS0_ESEL_MSK) >> 16);
+	}
+
+	return -1;
+}
+
+#ifdef CONFIG_ADDR_MAP
+void init_addr_map(void)
+{
+	int i;
+	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
+
+	/* walk all the entries */
+	for (i = 0; i < num_cam; i++) {
+		unsigned long epn;
+		u32 tsize, _mas1;
+		phys_addr_t rpn;
+
+		mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0));
+
+		asm volatile("tlbre;isync");
+		_mas1 = mfspr(MAS1);
+
+		/* if the entry isn't valid skip it */
+		if (!(_mas1 & MAS1_VALID))
+			continue;
+
+		tsize = (_mas1 >> 8) & 0xf;
+		epn = mfspr(MAS2) & MAS2_EPN;
+		rpn = mfspr(MAS3) & MAS3_RPN;
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+		rpn |= ((phys_addr_t)mfspr(MAS7)) << 32;
+#endif
+
+		addrmap_set_entry(epn, rpn, (1UL << ((tsize * 2) + 10)), i);
+	}
+
+	return ;
+}
+#endif
+
+unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg)
+{
+	int i;
+	unsigned int tlb_size;
+	unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE;
+	unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf;
+	u64 size, memsize = (u64)memsize_in_meg << 20;
+
+	size = min(memsize, CONFIG_MAX_MEM_MAPPED);
+
+	/* Convert (4^max) kB to (2^max) bytes */
+	max_cam = max_cam * 2 + 10;
+
+	for (i = 0; size && i < 8; i++) {
+		int ram_tlb_index = find_free_tlbcam();
+		u32 camsize = __ilog2_u64(size) & ~1U;
+		u32 align = __ilog2(ram_tlb_address) & ~1U;
+
+		if (ram_tlb_index == -1)
+			break;
+
+		if (align == -2) align = max_cam;
+		if (camsize > align)
+			camsize = align;
+
+		if (camsize > max_cam)
+			camsize = max_cam;
+
+		tlb_size = (camsize - 10) / 2;
+
+		set_tlb(1, ram_tlb_address, ram_tlb_address,
+			MAS3_SX|MAS3_SW|MAS3_SR, 0,
+			0, ram_tlb_index, tlb_size, 1);
+
+		size -= 1ULL << camsize;
+		memsize -= 1ULL << camsize;
+		ram_tlb_address += 1UL << camsize;
+	}
+
+	if (memsize)
+		print_size(memsize, " left unmapped\n");
+
+	/*
+	 * Confirm that the requested amount of memory was mapped.
+	 */
+	return memsize_in_meg;
+}
+#endif /* !CONFIG_NAND_SPL */
diff --git a/arch/ppc/cpu/mpc85xx/traps.c b/arch/ppc/cpu/mpc85xx/traps.c
new file mode 100644
index 0000000..10108d8
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/traps.c
@@ -0,0 +1,325 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright 2007 Freescale Semiconductor.
+ * Copyright (C) 2003 Motorola
+ * Modified by Xianghua Xiao(x.xiao@motorola.com)
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * End of addressable memory.  This may be less than the actual
+ * amount of memory on the system if we're unable to keep all
+ * the memory mapped in.
+ */
+extern ulong get_effective_memsize(void);
+#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize())
+
+static __inline__ void set_tsr(unsigned long val)
+{
+	asm volatile("mtspr 0x150, %0" : : "r" (val));
+}
+
+static __inline__ unsigned long get_esr(void)
+{
+	unsigned long val;
+	asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+	return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0)
+		{
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7)
+		{
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+CritcalInputException(struct pt_regs *regs)
+{
+	panic("Critical Input Exception");
+}
+
+int machinecheck_count = 0;
+int machinecheck_error = 0;
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+	unsigned int mcsr, mcsrr0, mcsrr1, mcar;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+	mcsrr0 = mfspr(SPRN_MCSRR0);
+	mcsrr1 = mfspr(SPRN_MCSRR1);
+	mcsr = mfspr(SPRN_MCSR);
+	mcar = mfspr(SPRN_MCAR);
+
+	machinecheck_count++;
+	machinecheck_error=1;
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from mcsr): ");
+	printf("mcsr = 0x%08x\n", mcsr);
+	if (mcsr & 0x80000000)
+		printf("Machine check input pin\n");
+	if (mcsr & 0x40000000)
+		printf("Instruction cache parity error\n");
+	if (mcsr & 0x20000000)
+		printf("Data cache push parity error\n");
+	if (mcsr & 0x10000000)
+		printf("Data cache parity error\n");
+	if (mcsr & 0x00000080)
+		printf("Bus instruction address error\n");
+	if (mcsr & 0x00000040)
+		printf("Bus Read address error\n");
+	if (mcsr & 0x00000020)
+		printf("Bus Write address error\n");
+	if (mcsr & 0x00000010)
+		printf("Bus Instruction data bus error\n");
+	if (mcsr & 0x00000008)
+		printf("Bus Read data bus error\n");
+	if (mcsr & 0x00000004)
+		printf("Bus Write bus error\n");
+	if (mcsr & 0x00000002)
+		printf("Bus Instruction parity error\n");
+	if (mcsr & 0x00000001)
+		printf("Bus Read parity error\n");
+
+	show_regs(regs);
+	printf("MCSR=0x%08x \tMCSRR0=0x%08x \nMCSRR1=0x%08x \tMCAR=0x%08x\n",
+	       mcsr, mcsrr0, mcsrr1, mcar);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	if (machinecheck_count > 10) {
+		panic("machine check count too high\n");
+	}
+
+	if (machinecheck_count > 1) {
+		regs->nip += 4; /* skip offending instruction */
+		printf("Skipping current instr, Returning to 0x%08lx\n",
+		       regs->nip);
+	} else {
+		printf("Returning back to 0x%08lx\n",regs->nip);
+	}
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	long esr_val;
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	show_regs(regs);
+
+	esr_val = get_esr();
+	if( esr_val & ESR_PIL )
+		printf( "** Illegal Instruction **\n" );
+	else if( esr_val & ESR_PPR )
+		printf( "** Privileged Instruction **\n" );
+	else if( esr_val & ESR_PTR )
+		printf( "** Trap Instruction **\n" );
+
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+PITException(struct pt_regs *regs)
+{
+	/*
+	 * Reset PIT interrupt
+	 */
+	set_tsr(0x0c000000);
+
+	/*
+	 * Call timer_interrupt routine in interrupts.c
+	 */
+	timer_interrupt(NULL);
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+void
+ExtIntException(struct pt_regs *regs)
+{
+	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
+
+	uint vect;
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("External Interrupt Exception at PC: %lx, SR: %lx, vector=%lx",
+	       regs->nip, regs->msr, regs->trap);
+	vect = pic->iack0;
+	printf(" irq IACK0@%05x=%d\n",(int)&pic->iack0,vect);
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+	printf("Debugger trap at @ %lx\n", regs->nip );
+	show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+	do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.	 If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc85xx/u-boot-nand.lds b/arch/ppc/cpu/mpc85xx/u-boot-nand.lds
new file mode 100644
index 0000000..b9240f2
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/u-boot-nand.lds
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+PHDRS
+{
+  text PT_LOAD;
+  bss PT_LOAD;
+}
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.got1)
+   } :text
+    _etext = .;
+    PROVIDE (etext = .);
+    .rodata    :
+   {
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  } :text
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x00FF) & 0xFFFFFF00;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(256);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(256);
+  __init_end = .;
+
+  .bootpg ADDR(.text) - 0x1000 :
+  {
+    arch/ppc/cpu/mpc85xx/start.o	(.bootpg)
+  } :text = 0xffff
+
+  . = ADDR(.text) + 0x80000;
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  } :bss
+
+  . = ALIGN(4);
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc85xx/u-boot-nand_spl.lds b/arch/ppc/cpu/mpc85xx/u-boot-nand_spl.lds
new file mode 100644
index 0000000..fef3e42
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/u-boot-nand_spl.lds
@@ -0,0 +1,67 @@
+/*
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de
+ *
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+	. = 0xfff00000;
+	.text : {
+		*(.text)
+  	}
+	_etext = .;
+
+	.reloc : {
+		_GOT2_TABLE_ = .;
+		*(.got2)
+		_FIXUP_TABLE_ = .;
+		*(.fixup)
+	}
+	__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+	__fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+	. = ALIGN(8);
+	.data : {
+		*(.rodata*)
+		*(.data*)
+		*(.sdata*)
+	}
+	_edata  =  .;
+
+	. = ALIGN(8);
+	__init_begin = .;
+	__init_end = .;
+
+	.resetvec ADDR(.text) + 0xffc : {
+		*(.resetvec)
+	} = 0xffff
+
+	__bss_start = .;
+	.bss : {
+		*(.sbss)
+		*(.bss)
+	}
+	_end = .;
+}
+ASSERT(__init_end <= 0xfff00ffc, "NAND bootstrap too big");
diff --git a/arch/ppc/cpu/mpc85xx/u-boot.lds b/arch/ppc/cpu/mpc85xx/u-boot.lds
new file mode 100644
index 0000000..9698bf4
--- /dev/null
+++ b/arch/ppc/cpu/mpc85xx/u-boot.lds
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef RESET_VECTOR_ADDRESS
+#define RESET_VECTOR_ADDRESS	0xfffffffc
+#endif
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+PHDRS
+{
+  text PT_LOAD;
+  bss PT_LOAD;
+}
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.got1)
+   } :text
+    _etext = .;
+    PROVIDE (etext = .);
+    .rodata    :
+   {
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  } :text
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x00FF) & 0xFFFFFF00;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(256);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(256);
+  __init_end = .;
+
+  .bootpg RESET_VECTOR_ADDRESS - 0xffc :
+  {
+    arch/ppc/cpu/mpc85xx/start.o	(.bootpg)
+  } :text = 0xffff
+
+  .resetvec RESET_VECTOR_ADDRESS :
+  {
+    *(.resetvec)
+  } :text = 0xffff
+
+  . = RESET_VECTOR_ADDRESS + 0x4;
+
+  /*
+   * Make sure that the bss segment isn't linked at 0x0, otherwise its
+   * address won't be updated during relocation fixups.  Note that
+   * this is a temporary fix.  Code to dynamically the fixup the bss
+   * location will be added in the future.  When the bss relocation
+   * fixup code is present this workaround should be removed.
+   */
+#if (RESET_VECTOR_ADDRESS == 0xfffffffc)
+  . |= 0x10;
+#endif
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  } :bss
+
+  . = ALIGN(4);
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/mpc86xx/Makefile b/arch/ppc/cpu/mpc86xx/Makefile
new file mode 100644
index 0000000..daca79a
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright 2007 Freescale Semiconductor, Inc.
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao,X.Xiao@motorola.com
+#
+# (C) Copyright 2004 Freescale Semiconductor. (MC86xx Port)
+# Jeff Brown
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	= start.o
+
+SOBJS-y += cache.o
+SOBJS-$(CONFIG_MP) += release.o
+
+COBJS-y	+= cpu.o
+COBJS-y	+= cpu_init.o
+# 8610 & 8641 are identical w/regards to DDR
+COBJS-$(CONFIG_MPC8610) += ddr-8641.o
+COBJS-$(CONFIG_MPC8641) += ddr-8641.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-y	+= interrupts.o
+COBJS-$(CONFIG_MP) += mp.o
+COBJS-y	+= speed.o
+COBJS-y	+= traps.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(ASOBJS) $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc86xx/cache.S b/arch/ppc/cpu/mpc86xx/cache.S
new file mode 100644
index 0000000..0bb058b
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/cache.S
@@ -0,0 +1,378 @@
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE L1_CACHE_BYTES
+#endif
+
+#if CACHE_LINE_SIZE == 128
+#define LG_CACHE_LINE_SIZE 7
+#elif CACHE_LINE_SIZE == 32
+#define LG_CACHE_LINE_SIZE 5
+#elif CACHE_LINE_SIZE == 16
+#define LG_CACHE_LINE_SIZE 4
+#elif CACHE_LINE_SIZE == 8
+#define LG_CACHE_LINE_SIZE 3
+#else
+# error "Invalid cache line size!"
+#endif
+
+/*
+ * Most of this code is taken from 74xx_7xx/cache.S
+ * and then cleaned up a bit
+ */
+
+/*
+ * Invalidate L1 instruction cache.
+ */
+_GLOBAL(invalidate_l1_instruction_cache)
+	/* use invalidate-all bit in HID0 */
+	mfspr	r3,HID0
+	ori	r3,r3,HID0_ICFI
+	mtspr	HID0,r3
+	isync
+	blr
+
+/*
+ * Invalidate L1 data cache.
+ */
+_GLOBAL(invalidate_l1_data_cache)
+	mfspr	r3,HID0
+	ori	r3,r3,HID0_DCFI
+	mtspr	HID0,r3
+	isync
+	blr
+
+/*
+ * Flush data cache.
+ */
+_GLOBAL(flush_dcache)
+	lis	r3,0
+	lis	r5,CACHE_LINE_SIZE
+flush:
+	cmp	0,1,r3,r5
+	bge	done
+	lwz	r5,0(r3)
+	lis	r5,CACHE_LINE_SIZE
+	addi	r3,r3,0x4
+	b	flush
+done:
+	blr
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,CACHE_LINE_SIZE
+	bdnz	2b
+	sync				/* additional sync needed on g4 */
+	isync
+	blr
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5	/* align r3 down to cache line */
+	subf	r4,r3,r4	/* r4 = offset of stop from start of cache line */
+	add	r4,r4,r5	/* r4 += cache_line_size-1 */
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE  /* r4 = number of cache lines to flush */
+	beqlr				  /* if r4 == 0 return */
+	mtctr	r4			  /* ctr = r4 */
+
+	sync
+1:	dcbst	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+	sync
+1:	dcbf	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbf's to get to ram */
+	blr
+
+/*
+ * Like above, but invalidate the D-cache.  This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+	sync
+1:	dcbi	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbi's to get to ram */
+	blr
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ *	void __flush_page_to_ram(void *page)
+ */
+_GLOBAL(__flush_page_to_ram)
+	rlwinm	r3,r3,0,0,19		/* Get page base address */
+	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
+	mtctr	r4
+	mr	r6,r3
+0:	dcbst	0,r3			/* Write line to ram */
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	0b
+	sync
+	mtctr	r4
+1:	icbi	0,r6
+	addi	r6,r6,CACHE_LINE_SIZE
+	bdnz	1b
+	sync
+	isync
+	blr
+
+/*
+ * Flush a particular page from the instruction cache.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ *	void __flush_icache_page(void *page)
+ */
+_GLOBAL(__flush_icache_page)
+	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
+	mtctr	r4
+1:	icbi	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync
+	isync
+	blr
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced).  This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+1:	dcbz	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	blr
+
+/*
+ * Enable L1 Instruction cache
+ */
+_GLOBAL(icache_enable)
+	mfspr	r3, HID0
+	li	r5, HID0_ICFI|HID0_ILOCK
+	andc	r3, r3, r5
+	ori	r3, r3, HID0_ICE
+	ori	r5, r3, HID0_ICFI
+	mtspr	HID0, r5
+	mtspr	HID0, r3
+	isync
+	blr
+
+/*
+ * Disable L1 Instruction cache
+ */
+_GLOBAL(icache_disable)
+	mflr	r4
+	bl	invalidate_l1_instruction_cache		/* uses r3 */
+	sync
+	mtlr	r4
+	mfspr	r3, HID0
+	li	r5, 0
+	ori	r5, r5, HID0_ICE
+	andc	r3, r3, r5
+	mtspr	HID0, r3
+	isync
+	blr
+
+/*
+ * Is instruction cache enabled?
+ */
+_GLOBAL(icache_status)
+	mfspr	r3, HID0
+	andi.	r3, r3, HID0_ICE
+	blr
+
+
+_GLOBAL(l1dcache_enable)
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	ori	r3, r3, HID0_DCE
+	ori	r5, r3, HID0_DCFI
+	mtspr	HID0, r5		/* enable + invalidate */
+	mtspr	HID0, r3		/* enable */
+	sync
+	blr
+
+/*
+ * Enable data cache(s) - L1 and optionally L2
+ * Calls l2cache_enable. LR saved in r5
+ */
+_GLOBAL(dcache_enable)
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	ori	r3, r3, HID0_DCE
+	ori	r5, r3, HID0_DCFI
+	mtspr	HID0, r5		/* enable + invalidate */
+	mtspr	HID0, r3		/* enable */
+	sync
+#ifdef CONFIG_SYS_L2
+	mflr	r5
+	bl	l2cache_enable		/* uses r3 and r4 */
+	sync
+	mtlr	r5
+#endif
+	blr
+
+
+/*
+ * Disable data cache(s) - L1 and optionally L2
+ * Calls flush_dcache and l2cache_disable_no_flush.
+ * LR saved in r4
+ */
+_GLOBAL(dcache_disable)
+	mflr	r4			/* save link register */
+	bl	flush_dcache	/* uses r3 and r5 */
+	sync
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	li	r5, HID0_DCE|HID0_DCFI
+	andc	r3, r3, r5		/* no enable, no invalidate */
+	mtspr	HID0, r3
+	sync
+#ifdef CONFIG_SYS_L2
+	bl	l2cache_disable_no_flush /* uses r3 */
+#endif
+	mtlr	r4			/* restore link register */
+	blr
+
+/*
+ * Is data cache enabled?
+ */
+_GLOBAL(dcache_status)
+	mfspr	r3, HID0
+	andi.	r3, r3, HID0_DCE
+	blr
+
+/*
+ * Invalidate L2 cache using L2I, assume L2 is enabled
+ */
+_GLOBAL(l2cache_invalidate)
+	mfspr	r3, l2cr
+	rlwinm.	r3, r3, 0, 0, 0
+	beq	1f
+
+	mfspr	r3, l2cr
+	rlwinm	r3, r3, 0, 1, 31
+
+#ifdef	CONFIG_ALTIVEC
+	dssall
+#endif
+	sync
+	mtspr	l2cr, r3
+	sync
+1:	mfspr	r3, l2cr
+	oris	r3, r3, L2CR_L2I@h
+	mtspr	l2cr, r3
+
+invl2:
+	mfspr	r3, l2cr
+	andis.	r3, r3, L2CR_L2I@h
+	bne	invl2
+	blr
+
+/*
+ * Enable L2 cache
+ * Calls l2cache_invalidate. LR is saved in r4
+ */
+_GLOBAL(l2cache_enable)
+	mflr	r4			/* save link register */
+	bl	l2cache_invalidate	/* uses r3 */
+	sync
+	lis	r3, L2_ENABLE@h
+	ori	r3, r3, L2_ENABLE@l
+	mtspr	l2cr, r3
+	isync
+	mtlr	r4			/* restore link register */
+	blr
+
+/*
+ * Disable L2 cache
+ * Calls flush_dcache. LR is saved in r4
+ */
+_GLOBAL(l2cache_disable)
+	mflr	r4			/* save link register */
+	bl	flush_dcache		/* uses r3 and r5 */
+	sync
+	mtlr	r4			/* restore link register */
+l2cache_disable_no_flush:		/* provide way to disable L2 w/o flushing */
+	lis	r3, L2_INIT@h
+	ori	r3, r3, L2_INIT@l
+	mtspr	l2cr, r3
+	isync
+	blr
diff --git a/arch/ppc/cpu/mpc86xx/config.mk b/arch/ppc/cpu/mpc86xx/config.mk
new file mode 100644
index 0000000..ca2f837
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/config.mk
@@ -0,0 +1,27 @@
+#
+# (C) Copyright 2004 Freescale Semiconductor.
+# Jeff Brown
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -ffixed-r2 -mstring
+PLATFORM_CPPFLAGS += -maltivec -mabi=altivec -msoft-float
diff --git a/arch/ppc/cpu/mpc86xx/cpu.c b/arch/ppc/cpu/mpc86xx/cpu.c
new file mode 100644
index 0000000..1887575
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/cpu.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2006,2009-2010 Freescale Semiconductor, Inc.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <mpc86xx.h>
+#include <asm/fsl_law.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Default board reset function
+ */
+static void
+__board_reset(void)
+{
+	/* Do nothing */
+}
+void board_reset(void) __attribute__((weak, alias("__board_reset")));
+
+
+int
+checkcpu(void)
+{
+	sys_info_t sysinfo;
+	uint pvr, svr;
+	uint ver;
+	uint major, minor;
+	char buf1[32], buf2[32];
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile ccsr_gur_t *gur = &immap->im_gur;
+	struct cpu_type *cpu;
+	uint msscr0 = mfspr(MSSCR0);
+
+	svr = get_svr();
+	ver = SVR_SOC_VER(svr);
+	major = SVR_MAJ(svr);
+	minor = SVR_MIN(svr);
+
+	if (cpu_numcores() > 1) {
+#ifndef CONFIG_MP
+		puts("Unicore software on multiprocessor system!!\n"
+		     "To enable mutlticore build define CONFIG_MP\n");
+#endif
+	}
+	puts("CPU:   ");
+
+	cpu = gd->cpu;
+
+	puts(cpu->name);
+
+	printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
+	puts("Core:  ");
+
+	pvr = get_pvr();
+	ver = PVR_E600_VER(pvr);
+	major = PVR_E600_MAJ(pvr);
+	minor = PVR_E600_MIN(pvr);
+
+	printf("E600 Core %d", (msscr0 & 0x20) ? 1 : 0 );
+	if (gur->pordevsr & MPC86xx_PORDEVSR_CORE1TE)
+		puts("\n    Core1Translation Enabled");
+	debug(" (MSSCR0=%x, PORDEVSR=%x)", msscr0, gur->pordevsr);
+
+	printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr);
+
+	get_sys_info(&sysinfo);
+
+	puts("Clock Configuration:\n");
+	printf("       CPU:%-4s MHz, ", strmhz(buf1, sysinfo.freqProcessor));
+	printf("MPX:%-4s MHz\n", strmhz(buf1, sysinfo.freqSystemBus));
+	printf("       DDR:%-4s MHz (%s MT/s data rate), ",
+		strmhz(buf1, sysinfo.freqSystemBus / 2),
+		strmhz(buf2, sysinfo.freqSystemBus));
+
+	if (sysinfo.freqLocalBus > LCRR_CLKDIV) {
+		printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freqLocalBus));
+	} else {
+		printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n",
+		       sysinfo.freqLocalBus);
+	}
+
+	puts("L1:    D-cache 32 KB enabled\n");
+	puts("       I-cache 32 KB enabled\n");
+
+	puts("L2:    ");
+	if (get_l2cr() & 0x80000000) {
+#if defined(CONFIG_MPC8610)
+		puts("256");
+#elif defined(CONFIG_MPC8641)
+		puts("512");
+#endif
+		puts(" KB enabled\n");
+	} else {
+		puts("Disabled\n");
+	}
+
+	return 0;
+}
+
+
+void
+do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ccsr_gur_t *gur = &immap->im_gur;
+
+	/* Attempt board-specific reset */
+	board_reset();
+
+	/* Next try asserting HRESET_REQ */
+	out_be32(&gur->rstcr, MPC86xx_RSTCR_HRST_REQ);
+
+	while (1)
+		;
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long
+get_tbclk(void)
+{
+	sys_info_t sys_info;
+
+	get_sys_info(&sys_info);
+	return (sys_info.freqSystemBus + 3L) / 4L;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+watchdog_reset(void)
+{
+#if defined(CONFIG_MPC8610)
+	/*
+	 * This actually feed the hard enabled watchdog.
+	 */
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ccsr_wdt_t *wdt = &immap->im_wdt;
+	volatile ccsr_gur_t *gur = &immap->im_gur;
+	u32 tmp = gur->pordevsr;
+
+	if (tmp & 0x4000) {
+		wdt->swsrr = 0x556c;
+		wdt->swsrr = 0xaa39;
+	}
+#endif
+}
+#endif	/* CONFIG_WATCHDOG */
+
+/*
+ * Print out the state of various machine registers.
+ * Currently prints out LAWs, BR0/OR0, and BATs
+ */
+void mpc86xx_reginfo(void)
+{
+	immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+	ccsr_lbc_t *lbc = &immap->im_lbc;
+
+	print_bats();
+	print_laws();
+
+	printf ("Local Bus Controller Registers\n"
+		"\tBR0\t0x%08X\tOR0\t0x%08X \n", in_be32(&lbc->br0), in_be32(&lbc->or0));
+	printf("\tBR1\t0x%08X\tOR1\t0x%08X \n", in_be32(&lbc->br1), in_be32(&lbc->or1));
+	printf("\tBR2\t0x%08X\tOR2\t0x%08X \n", in_be32(&lbc->br2), in_be32(&lbc->or2));
+	printf("\tBR3\t0x%08X\tOR3\t0x%08X \n", in_be32(&lbc->br3), in_be32(&lbc->or3));
+	printf("\tBR4\t0x%08X\tOR4\t0x%08X \n", in_be32(&lbc->br4), in_be32(&lbc->or4));
+	printf("\tBR5\t0x%08X\tOR5\t0x%08X \n", in_be32(&lbc->br5), in_be32(&lbc->or5));
+	printf("\tBR6\t0x%08X\tOR6\t0x%08X \n", in_be32(&lbc->br6), in_be32(&lbc->or6));
+	printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", in_be32(&lbc->br7), in_be32(&lbc->or7));
+
+}
+
+/*
+ * Set the DDR BATs to reflect the actual size of DDR.
+ *
+ * dram_size is the actual size of DDR, in bytes
+ *
+ * Note: we assume that CONFIG_MAX_MEM_MAPPED is 2G or smaller as we only
+ * are using a single BAT to cover DDR.
+ *
+ * If this is not true, (e.g. CONFIG_MAX_MEM_MAPPED is 2GB but HID0_XBSEN
+ * is not defined) then we might have a situation where U-Boot will attempt
+ * to relocated itself outside of the region mapped by DBAT0.
+ * This will cause a machine check.
+ *
+ * Currently we are limited to power of two sized DDR since we only use a
+ * single bat.  If a non-power of two size is used that is less than
+ * CONFIG_MAX_MEM_MAPPED u-boot will crash.
+ *
+ */
+void setup_ddr_bat(phys_addr_t dram_size)
+{
+	unsigned long batu, bl;
+
+	bl = TO_BATU_BL(min(dram_size, CONFIG_MAX_MEM_MAPPED));
+
+	if (BATU_SIZE(bl) != dram_size) {
+		u64 sz = (u64)dram_size - BATU_SIZE(bl);
+		print_size(sz, " left unmapped\n");
+	}
+
+	batu = bl | BATU_VS | BATU_VP;
+	write_bat(DBAT0, batu, CONFIG_SYS_DBAT0L);
+	write_bat(IBAT0, batu, CONFIG_SYS_IBAT0L);
+}
diff --git a/arch/ppc/cpu/mpc86xx/cpu_init.c b/arch/ppc/cpu/mpc86xx/cpu_init.c
new file mode 100644
index 0000000..b4f047d
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/cpu_init.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2004,2009 Freescale Semiconductor, Inc.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cpu_init.c - low level cpu init
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mpc86xx.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include <asm/mp.h>
+
+void setup_bats(void);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map
+ * initialize a bunch of registers
+ */
+
+void cpu_init_f(void)
+{
+	volatile immap_t    *immap = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ccsr_lbc_t *memctl = &immap->im_lbc;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	memset ((void *) gd, 0, sizeof (gd_t));
+
+#ifdef CONFIG_FSL_LAW
+	init_laws();
+#endif
+
+	setup_bats();
+
+	/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+	 * addresses - these have to be modified later when FLASH size
+	 * has been determined
+	 */
+
+#if defined(CONFIG_SYS_OR0_REMAP)
+	memctl->or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+	memctl->or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+
+	/* now restrict to preliminary range */
+#if defined(CONFIG_SYS_BR0_PRELIM) && defined(CONFIG_SYS_OR0_PRELIM)
+	memctl->br0 = CONFIG_SYS_BR0_PRELIM;
+	memctl->or0 = CONFIG_SYS_OR0_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+	memctl->or1 = CONFIG_SYS_OR1_PRELIM;
+	memctl->br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+	memctl->or2 = CONFIG_SYS_OR2_PRELIM;
+	memctl->br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+	memctl->or3 = CONFIG_SYS_OR3_PRELIM;
+	memctl->br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+	memctl->or4 = CONFIG_SYS_OR4_PRELIM;
+	memctl->br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+	memctl->or5 = CONFIG_SYS_OR5_PRELIM;
+	memctl->br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+	memctl->or6 = CONFIG_SYS_OR6_PRELIM;
+	memctl->br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+	memctl->or7 = CONFIG_SYS_OR7_PRELIM;
+	memctl->br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+#if defined(CONFIG_FSL_DMA)
+	dma_init();
+#endif
+
+	/* enable the timebase bit in HID0 */
+	set_hid0(get_hid0() | 0x4000000);
+
+	/* enable EMCP, SYNCBE | ABE bits in HID1 */
+	set_hid1(get_hid1() | 0x80000C00);
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r(void)
+{
+#if defined(CONFIG_MP)
+	setup_mp();
+#endif
+	return 0;
+}
+
+/* Set up BAT registers */
+void setup_bats(void)
+{
+#if defined(CONFIG_SYS_DBAT0U) && defined(CONFIG_SYS_DBAT0L)
+	write_bat(DBAT0, CONFIG_SYS_DBAT0U, CONFIG_SYS_DBAT0L);
+#endif
+#if defined(CONFIG_SYS_IBAT0U) && defined(CONFIG_SYS_IBAT0L)
+	write_bat(IBAT0, CONFIG_SYS_IBAT0U, CONFIG_SYS_IBAT0L);
+#endif
+	write_bat(DBAT1, CONFIG_SYS_DBAT1U, CONFIG_SYS_DBAT1L);
+	write_bat(IBAT1, CONFIG_SYS_IBAT1U, CONFIG_SYS_IBAT1L);
+	write_bat(DBAT2, CONFIG_SYS_DBAT2U, CONFIG_SYS_DBAT2L);
+	write_bat(IBAT2, CONFIG_SYS_IBAT2U, CONFIG_SYS_IBAT2L);
+	write_bat(DBAT3, CONFIG_SYS_DBAT3U, CONFIG_SYS_DBAT3L);
+	write_bat(IBAT3, CONFIG_SYS_IBAT3U, CONFIG_SYS_IBAT3L);
+	write_bat(DBAT4, CONFIG_SYS_DBAT4U, CONFIG_SYS_DBAT4L);
+	write_bat(IBAT4, CONFIG_SYS_IBAT4U, CONFIG_SYS_IBAT4L);
+	write_bat(DBAT5, CONFIG_SYS_DBAT5U, CONFIG_SYS_DBAT5L);
+	write_bat(IBAT5, CONFIG_SYS_IBAT5U, CONFIG_SYS_IBAT5L);
+	write_bat(DBAT6, CONFIG_SYS_DBAT6U, CONFIG_SYS_DBAT6L);
+	write_bat(IBAT6, CONFIG_SYS_IBAT6U, CONFIG_SYS_IBAT6L);
+	write_bat(DBAT7, CONFIG_SYS_DBAT7U, CONFIG_SYS_DBAT7L);
+	write_bat(IBAT7, CONFIG_SYS_IBAT7U, CONFIG_SYS_IBAT7L);
+
+	return;
+}
+
+#ifdef CONFIG_ADDR_MAP
+/* Initialize address mapping array */
+void init_addr_map(void)
+{
+	int i;
+	ppc_bat_t bat = DBAT0;
+	phys_size_t size;
+	unsigned long upper, lower;
+
+	for (i = 0; i < CONFIG_SYS_NUM_ADDR_MAP; i++, bat++) {
+		if (read_bat(bat, &upper, &lower) != -1) {
+			if (!BATU_VALID(upper))
+				size = 0;
+			else
+				size = BATU_SIZE(upper);
+			addrmap_set_entry(BATU_VADDR(upper), BATL_PADDR(lower),
+					  size, i);
+		}
+#ifdef CONFIG_HIGH_BATS
+		/* High bats are not contiguous with low BAT numbers */
+		if (bat == DBAT3)
+			bat = DBAT4 - 1;
+#endif
+	}
+}
+#endif
diff --git a/arch/ppc/cpu/mpc86xx/ddr-8641.c b/arch/ppc/cpu/mpc86xx/ddr-8641.c
new file mode 100644
index 0000000..b8f2c93
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/ddr-8641.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+			     unsigned int ctrl_num)
+{
+	unsigned int i;
+	volatile ccsr_ddr_t *ddr;
+
+	switch (ctrl_num) {
+	case 0:
+		ddr = (void *)CONFIG_SYS_MPC86xx_DDR_ADDR;
+		break;
+	case 1:
+		ddr = (void *)CONFIG_SYS_MPC86xx_DDR2_ADDR;
+		break;
+	default:
+		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+		return;
+	}
+
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		if (i == 0) {
+			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs0_config, regs->cs[i].config);
+
+		} else if (i == 1) {
+			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs1_config, regs->cs[i].config);
+
+		} else if (i == 2) {
+			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs2_config, regs->cs[i].config);
+
+		} else if (i == 3) {
+			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+			out_be32(&ddr->cs3_config, regs->cs[i].config);
+		}
+	}
+
+	out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
+	out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
+	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+	out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+	out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+	out_be32(&ddr->sdram_mode_cntl, regs->ddr_sdram_md_cntl);
+	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+	out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
+	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+	out_be32(&ddr->init_addr, regs->ddr_init_addr);
+	out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+
+	debug("before go\n");
+
+	/*
+	 * 200 painful micro-seconds must elapse between
+	 * the DDR clock setup and the DDR config enable.
+	 */
+	udelay(200);
+	asm volatile("sync;isync");
+
+	out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
+
+	/*
+	 * Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done
+	 */
+	while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
+		udelay(10000);		/* throttle polling rate */
+	}
+}
diff --git a/arch/ppc/cpu/mpc86xx/fdt.c b/arch/ppc/cpu/mpc86xx/fdt.c
new file mode 100644
index 0000000..51f3f4c
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/fdt.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/mp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void ft_fixup_num_cores(void *blob);
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_MP
+	int off;
+	u32 bootpg = determine_mp_bootpg();
+#endif
+
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+			     "timebase-frequency", bd->bi_busfreq / 4, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+			     "bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+			     "clock-frequency", bd->bi_intfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+			     "bus-frequency", bd->bi_busfreq, 1);
+
+#if defined(CONFIG_MPC8641)
+	do_fixup_by_compat_u32(blob, "fsl,mpc8641-localbus",
+			       "bus-frequency", gd->lbc_clk, 1);
+#endif
+	do_fixup_by_compat_u32(blob, "fsl,elbc",
+			       "bus-frequency", gd->lbc_clk, 1);
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) \
+    || defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
+	fdt_fixup_ethernet(blob);
+#endif
+
+#ifdef CONFIG_SYS_NS16550
+	do_fixup_by_compat_u32(blob, "ns16550",
+			       "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+#ifdef CONFIG_MP
+	/* Reserve the boot page so OSes dont use it */
+	off = fdt_add_mem_rsv(blob, bootpg, (u64)4096);
+	if (off < 0)
+		printf("%s: %s\n", __FUNCTION__, fdt_strerror(off));
+#endif
+	ft_fixup_num_cores(blob);
+}
diff --git a/arch/ppc/cpu/mpc86xx/interrupts.c b/arch/ppc/cpu/mpc86xx/interrupts.c
new file mode 100644
index 0000000..c78fc72
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/interrupts.c
@@ -0,0 +1,115 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 Motorola Inc. (MPC85xx port)
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * (C) Copyright 2004, 2007 Freescale Semiconductor. (MPC86xx Port)
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc86xx.h>
+#include <command.h>
+#include <asm/processor.h>
+
+int interrupt_init_cpu(unsigned long *decrementer_count)
+{
+	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	volatile ccsr_pic_t *pic = &immr->im_pic;
+
+	pic->gcr = MPC86xx_PICGCR_RST;
+	while (pic->gcr & MPC86xx_PICGCR_RST)
+		;
+	pic->gcr = MPC86xx_PICGCR_MODE;
+
+	*decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+	debug("interrupt init: tbclk() = %d MHz, decrementer_count = %ld\n",
+	      (get_tbclk() / 1000000),
+	      *decrementer_count);
+
+#ifdef CONFIG_INTERRUPTS
+
+	pic->iivpr1 = 0x810001;	/* 50220 enable mcm interrupts */
+	debug("iivpr1@%x = %x\n", &pic->iivpr1, pic->iivpr1);
+
+	pic->iivpr2 = 0x810002;	/* 50240 enable ddr interrupts */
+	debug("iivpr2@%x = %x\n", &pic->iivpr2, pic->iivpr2);
+
+	pic->iivpr3 = 0x810003;	/* 50260 enable lbc interrupts */
+	debug("iivpr3@%x = %x\n", &pic->iivpr3, pic->iivpr3);
+
+#if defined(CONFIG_PCI1) || defined(CONFIG_PCIE1)
+	pic->iivpr8 = 0x810008;	/* enable pcie1 interrupts */
+	debug("iivpr8@%x = %x\n", &pic->iivpr8, pic->iivpr8);
+#endif
+#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2)
+	pic->iivpr9 = 0x810009;	/* enable pcie2 interrupts */
+	debug("iivpr9@%x = %x\n", &pic->iivpr9, pic->iivpr9);
+#endif
+
+	pic->ctpr = 0;	/* 40080 clear current task priority register */
+#endif
+
+	return 0;
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+	/* nothing to do here */
+}
+
+/*
+ * Install and free a interrupt handler. Not implemented yet.
+ */
+void irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+}
+
+void irq_free_handler(int vec)
+{
+}
+
+/*
+ * irqinfo - print information about PCI devices,not implemented.
+ */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	return 0;
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+	puts("external_interrupt (oops!)\n");
+}
diff --git a/arch/ppc/cpu/mpc86xx/mp.c b/arch/ppc/cpu/mpc86xx/mp.c
new file mode 100644
index 0000000..b4a0faa
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/mp.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <ioports.h>
+#include <lmb.h>
+#include <asm/io.h>
+#include <asm/mp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cpu_reset(int nr)
+{
+	/* dummy function so common/cmd_mp.c will build
+	 * should be implemented in the future, when cpu_release()
+	 * is supported.  Be aware there may be a similiar bug
+	 * as exists on MPC85xx w/its PIC having a timing window
+	 * associated to resetting the core */
+	return 1;
+}
+
+int cpu_status(int nr)
+{
+	/* dummy function so common/cmd_mp.c will build */
+	return 0;
+}
+
+int cpu_disable(int nr)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR;
+	volatile ccsr_gur_t *gur = &immap->im_gur;
+
+	switch (nr) {
+	case 0:
+		setbits_be32(&gur->devdisr, MPC86xx_DEVDISR_CPU0);
+		break;
+	case 1:
+		setbits_be32(&gur->devdisr, MPC86xx_DEVDISR_CPU1);
+		break;
+	default:
+		printf("Invalid cpu number for disable %d\n", nr);
+		return 1;
+	}
+
+	return 0;
+}
+
+int cpu_release(int nr, int argc, char *argv[])
+{
+	/* dummy function so common/cmd_mp.c will build
+	 * should be implemented in the future */
+	return 1;
+}
+
+u32 determine_mp_bootpg(void)
+{
+	/* if we have 4G or more of memory, put the boot page at 4Gb-1M */
+	if ((u64)gd->ram_size > 0xfffff000)
+		return (0xfff00000);
+
+	return (gd->ram_size - (1024 * 1024));
+}
+
+void cpu_mp_lmb_reserve(struct lmb *lmb)
+{
+	u32 bootpg = determine_mp_bootpg();
+
+	/* tell u-boot we stole a page */
+	lmb_reserve(lmb, bootpg, 4096);
+}
+
+/*
+ * Copy the code for other cpus to execute into an
+ * aligned location accessible via BPTR
+ */
+void setup_mp(void)
+{
+	extern ulong __secondary_start_page;
+	ulong fixup = (ulong)&__secondary_start_page;
+	u32 bootpg = determine_mp_bootpg();
+	u32 bootpg_va;
+
+	if (bootpg >= CONFIG_SYS_MAX_DDR_BAT_SIZE) {
+		/* We're not covered by the DDR mapping, set up BAT  */
+		write_bat(DBAT7, CONFIG_SYS_SCRATCH_VA | BATU_BL_128K |
+			  BATU_VS | BATU_VP,
+			  bootpg | BATL_PP_RW | BATL_MEMCOHERENCE);
+		bootpg_va = CONFIG_SYS_SCRATCH_VA;
+	} else {
+		bootpg_va = bootpg;
+	}
+
+	memcpy((void *)bootpg_va, (void *)fixup, 4096);
+	flush_cache(bootpg_va, 4096);
+
+	/* remove the temporary BAT mapping */
+	if (bootpg >= CONFIG_SYS_MAX_DDR_BAT_SIZE)
+		write_bat(DBAT7, 0, 0);
+
+	/* If the physical location of bootpg is not at fff00000, set BPTR */
+	if (bootpg != 0xfff00000)
+		out_be32((uint *)(CONFIG_SYS_CCSRBAR + 0x20), 0x80000000 |
+			 (bootpg >> 12));
+}
diff --git a/arch/ppc/cpu/mpc86xx/release.S b/arch/ppc/cpu/mpc86xx/release.S
new file mode 100644
index 0000000..67a6f2b
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/release.S
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2004, 2007, 2008 Freescale Semiconductor.
+ * Srikanth Srinivasan <srikanth.srinivaan@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/* If this is a multi-cpu system then we need to handle the
+ * 2nd cpu.  The assumption is that the 2nd cpu is being
+ * held in boot holdoff mode until the 1st cpu unlocks it
+ * from Linux.	We'll do some basic cpu init and then pass
+ * it to the Linux Reset Vector.
+ * Sri:	 Much of this initialization is not required. Linux
+ * rewrites the bats, and the sprs and also enables the L1 cache.
+ *
+ * Core 0 must copy this to a 1M aligned region and set BPTR
+ * to point to it.
+ */
+	.align 12
+.globl __secondary_start_page
+__secondary_start_page:
+	.space 0x100	/* space over to reset vector loc */
+	mfspr	r0, MSSCR0
+	andi.	r0, r0, 0x0020
+	rlwinm	r0,r0,27,31,31
+	mtspr	PIR, r0
+
+	/* Invalidate BATs */
+	li	r0, 0
+	mtspr	IBAT0U, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT3U, r0
+	mtspr	IBAT4U, r0
+	mtspr	IBAT5U, r0
+	mtspr	IBAT6U, r0
+	mtspr	IBAT7U, r0
+	isync
+	mtspr	DBAT0U, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT3U, r0
+	mtspr	DBAT4U, r0
+	mtspr	DBAT5U, r0
+	mtspr	DBAT6U, r0
+	mtspr	DBAT7U, r0
+	isync
+	sync
+
+	/* enable extended addressing */
+	mfspr	r0, HID0
+	lis	r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h
+	ori	r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l
+	mtspr	HID0, r0
+	sync
+	isync
+
+#ifdef CONFIG_SYS_L2
+	/* init the L2 cache */
+	addis	r3, r0, L2_INIT@h
+	ori	r3, r3, L2_INIT@l
+	sync
+	mtspr	l2cr, r3
+#ifdef CONFIG_ALTIVEC
+	dssall
+#endif
+	/* invalidate the L2 cache */
+	mfspr	r3, l2cr
+	rlwinm.	r3, r3, 0, 0, 0
+	beq	1f
+
+	mfspr	r3, l2cr
+	rlwinm	r3, r3, 0, 1, 31
+
+#ifdef	CONFIG_ALTIVEC
+	dssall
+#endif
+	sync
+	mtspr	l2cr, r3
+	sync
+1:	mfspr	r3, l2cr
+	oris	r3, r3, L2CR_L2I@h
+	mtspr	l2cr, r3
+
+invl2:
+	mfspr	r3, l2cr
+	andis.	r3, r3, L2CR_L2I@h
+	bne	invl2
+	sync
+#endif
+
+	/* enable and invalidate the data cache */
+	mfspr	r3, HID0
+	li	r5, HID0_DCFI|HID0_DLOCK
+	andc	r3, r3, r5
+	mtspr	HID0, r3		/* no invalidate, unlock */
+	ori	r3, r3, HID0_DCE
+	ori	r5, r3, HID0_DCFI
+	mtspr	HID0, r5		/* enable + invalidate */
+	mtspr	HID0, r3		/* enable */
+	sync
+#ifdef CONFIG_SYS_L2
+	sync
+	lis	r3, L2_ENABLE@h
+	ori	r3, r3, L2_ENABLE@l
+	mtspr	l2cr, r3
+	isync
+	sync
+#endif
+
+	/* enable and invalidate the instruction cache*/
+	mfspr	r3, HID0
+	li	r5, HID0_ICFI|HID0_ILOCK
+	andc	r3, r3, r5
+	ori	r3, r3, HID0_ICE
+	ori	r5, r3, HID0_ICFI
+	mtspr	HID0, r5
+	mtspr	HID0, r3
+	isync
+	sync
+
+	/* TBEN in HID0 */
+	mfspr	r4, HID0
+	oris	r4, r4, 0x0400
+	mtspr	HID0, r4
+	sync
+	isync
+
+	/* MCP|SYNCBE|ABE in HID1 */
+	mfspr	r4, HID1
+	oris	r4, r4, 0x8000
+	ori	r4, r4, 0x0C00
+	mtspr	HID1, r4
+	sync
+	isync
+
+	lis	r3, CONFIG_LINUX_RESET_VEC@h
+	ori	r3, r3, CONFIG_LINUX_RESET_VEC@l
+	mtlr	r3
+	blr
+
+	/* Never Returns, Running in Linux Now */
diff --git a/arch/ppc/cpu/mpc86xx/speed.c b/arch/ppc/cpu/mpc86xx/speed.c
new file mode 100644
index 0000000..64a3479
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/speed.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc86xx.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* used in some defintiions of CONFIG_SYS_CLK_FREQ */
+extern unsigned long get_board_sys_clk(unsigned long dummy);
+
+void get_sys_info(sys_info_t *sysInfo)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile ccsr_gur_t *gur = &immap->im_gur;
+	uint plat_ratio, e600_ratio;
+	uint lcrr_div;
+
+	plat_ratio = (gur->porpllsr) & 0x0000003e;
+	plat_ratio >>= 1;
+
+	switch (plat_ratio) {
+	case 0x0:
+		sysInfo->freqSystemBus = 16 * CONFIG_SYS_CLK_FREQ;
+		break;
+	case 0x02:
+	case 0x03:
+	case 0x04:
+	case 0x05:
+	case 0x06:
+	case 0x08:
+	case 0x09:
+	case 0x0a:
+	case 0x0c:
+	case 0x10:
+		sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ;
+		break;
+	default:
+		sysInfo->freqSystemBus = 0;
+		break;
+	}
+
+	e600_ratio = (gur->porpllsr) & 0x003f0000;
+	e600_ratio >>= 16;
+
+	switch (e600_ratio) {
+	case 0x10:
+		sysInfo->freqProcessor = 2 * sysInfo->freqSystemBus;
+		break;
+	case 0x19:
+		sysInfo->freqProcessor = 5 * sysInfo->freqSystemBus / 2;
+		break;
+	case 0x20:
+		sysInfo->freqProcessor = 3 * sysInfo->freqSystemBus;
+		break;
+	case 0x39:
+		sysInfo->freqProcessor = 7 * sysInfo->freqSystemBus / 2;
+		break;
+	case 0x28:
+		sysInfo->freqProcessor = 4 * sysInfo->freqSystemBus;
+		break;
+	case 0x1d:
+		sysInfo->freqProcessor = 9 * sysInfo->freqSystemBus / 2;
+		break;
+	default:
+		sysInfo->freqProcessor = e600_ratio + sysInfo->freqSystemBus;
+		break;
+	}
+
+#if defined(CONFIG_SYS_LBC_LCRR)
+	/* We will program LCRR to this value later */
+	lcrr_div = CONFIG_SYS_LBC_LCRR & LCRR_CLKDIV;
+#else
+	{
+		volatile ccsr_lbc_t *lbc = &immap->im_lbc;
+		lcrr_div = in_be32(&lbc->lcrr) & LCRR_CLKDIV;
+	}
+#endif
+	if (lcrr_div == 2 || lcrr_div == 4 || lcrr_div == 8) {
+		sysInfo->freqLocalBus = sysInfo->freqSystemBus / (lcrr_div * 2);
+	} else {
+		/* In case anyone cares what the unknown value is */
+		sysInfo->freqLocalBus = lcrr_div;
+	}
+}
+
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ * (Approx. GCLK frequency in Hz)
+ */
+
+int get_clocks(void)
+{
+	sys_info_t sys_info;
+
+	get_sys_info(&sys_info);
+	gd->cpu_clk = sys_info.freqProcessor;
+	gd->bus_clk = sys_info.freqSystemBus;
+	gd->lbc_clk = sys_info.freqLocalBus;
+
+	/*
+	 * The base clock for I2C depends on the actual SOC.  Unfortunately,
+	 * there is no pattern that can be used to determine the frequency, so
+	 * the only choice is to look up the actual SOC number and use the value
+	 * for that SOC. This information is taken from application note
+	 * AN2919.
+	 */
+#ifdef CONFIG_MPC8610
+	gd->i2c1_clk = sys_info.freqSystemBus;
+#else
+	gd->i2c1_clk = sys_info.freqSystemBus / 2;
+#endif
+	gd->i2c2_clk = gd->i2c1_clk;
+
+	if (gd->cpu_clk != 0)
+		return 0;
+	else
+		return 1;
+}
+
+
+/*
+ * get_bus_freq
+ *	Return system bus freq in Hz
+ */
+
+ulong get_bus_freq(ulong dummy)
+{
+	ulong val;
+	sys_info_t sys_info;
+
+	get_sys_info(&sys_info);
+	val = sys_info.freqSystemBus;
+
+	return val;
+}
diff --git a/arch/ppc/cpu/mpc86xx/start.S b/arch/ppc/cpu/mpc86xx/start.S
new file mode 100644
index 0000000..ed1e4ca
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/start.S
@@ -0,0 +1,957 @@
+/*
+ * Copyright 2004, 2007 Freescale Semiconductor.
+ * Srikanth Srinivasan <srikanth.srinivaan@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*  U-Boot - Startup Code for 86xx PowerPC based Embedded Boards
+ *
+ *
+ *  The processor starts at 0xfff00100 and the code is executed
+ *  from flash. The code is organized to be at an other address
+ *  in memory, but as long we don't jump around before relocating.
+ *  board_init lies at a quite high address and when the cpu has
+ *  jumped there, everything is ok.
+ */
+#include <config.h>
+#include <mpc86xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef	CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING ""
+#endif
+
+/*
+ * Need MSR_DR | MSR_IR enabled to access I/O (printf) in exceptions
+ */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+	.text
+	.long	0x27051956		/* U-Boot Magic Number */
+	.globl	version_string
+version_string:
+	.ascii	U_BOOT_VERSION
+	.ascii	" (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii	CONFIG_IDENT_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH */
+	b	boot_cold
+	sync
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM	/* Software reboot */
+	b	boot_warm
+	sync
+
+	/* the boot code is located below the exception table */
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+	STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+	STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+	STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+	STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+	STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+	STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+	STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+	STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+	STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+	STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x2000
+
+boot_cold:
+boot_warm:
+	/*
+	 * NOTE: Only Cpu 0 will ever come here.  Other cores go to an
+	 * address specified by the BPTR
+	 */
+1:
+#ifdef CONFIG_SYS_RAMBOOT
+	/* disable everything */
+	li	r0, 0
+	mtspr	HID0, r0
+	sync
+	mtmsr	0
+#endif
+
+	/* Invalidate BATs */
+	bl	invalidate_bats
+	sync
+	/* Invalidate all of TLB before MMU turn on */
+	bl      clear_tlbs
+	sync
+
+#ifdef CONFIG_SYS_L2
+	/* init the L2 cache */
+	lis	r3, L2_INIT@h
+	ori	r3, r3, L2_INIT@l
+	mtspr	l2cr, r3
+	/* invalidate the L2 cache */
+	bl	l2cache_invalidate
+	sync
+#endif
+
+	/*
+	 * Calculate absolute address in FLASH and jump there
+	 *------------------------------------------------------*/
+	lis	r3, CONFIG_SYS_MONITOR_BASE_EARLY@h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE_EARLY@l
+	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r3
+	blr
+
+in_flash:
+	/* let the C-code set up the rest			*/
+	/*							*/
+	/* Be careful to keep code relocatable !		*/
+	/*------------------------------------------------------*/
+	/* perform low-level init */
+
+	/* enable extended addressing */
+	bl	enable_ext_addr
+
+	/* setup the bats */
+	bl	early_bats
+
+	/*
+	 * Cache must be enabled here for stack-in-cache trick.
+	 * This means we need to enable the BATS.
+	 * Cache should be turned on after BATs, since by default
+	 * everything is write-through.
+	 */
+
+	/* enable address translation */
+	mfmsr	r5
+	ori	r5, r5, (MSR_IR | MSR_DR)
+	lis	r3,addr_trans_enabled@h
+	ori	r3, r3, addr_trans_enabled@l
+	mtspr	SPRN_SRR0,r3
+	mtspr	SPRN_SRR1,r5
+	rfi
+
+addr_trans_enabled:
+	/* enable and invalidate the data cache */
+/*	bl	l1dcache_enable */
+	bl	dcache_enable
+	sync
+
+#if 1
+	bl	icache_enable
+#endif
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+	bl	lock_ram_in_cache
+	sync
+#endif
+
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
+	bl      setup_ccsrbar
+#endif
+
+	/* set up the stack pointer in our newly created
+	 * cache-ram (r1) */
+	lis	r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+	li	r0, 0		/* Make room for stack frame header and */
+	stwu	r0, -4(r1)	/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/
+
+	GET_GOT			/* initialize GOT access	*/
+
+	/* run low-level CPU init code	   (from Flash) */
+	bl	cpu_init_f
+	sync
+
+#ifdef	RUN_DIAG
+
+	/* Load PX_AUX register address in r4 */
+	lis	r4, PIXIS_BASE@h
+	ori	r4, r4, 0x6
+	/* Load contents of PX_AUX in r3 bits 24 to 31*/
+	lbz	r3, 0(r4)
+
+	/* Mask and obtain the bit in r3 */
+	rlwinm. r3, r3, 0, 24, 24
+	/* If not zero, jump and continue with u-boot */
+	bne	diag_done
+
+	/* Load back contents of PX_AUX in r3 bits 24 to 31 */
+	lbz	r3, 0(r4)
+	/* Set the MSB of the register value */
+	ori	r3, r3, 0x80
+	/* Write value in r3 back to PX_AUX */
+	stb	r3, 0(r4)
+
+	/* Get the address to jump to in r3*/
+	lis	r3, CONFIG_SYS_DIAG_ADDR@h
+	ori	r3, r3, CONFIG_SYS_DIAG_ADDR@l
+
+	/* Load the LR with the branch address */
+	mtlr	r3
+
+	/* Branch to diagnostic */
+	blr
+
+diag_done:
+#endif
+
+/*	bl	l2cache_enable */
+	mr	r3, r21
+
+	/* r3: BOOTFLAG */
+	/* run 1st part of board init code (from Flash)	  */
+	bl	board_init_f
+	sync
+
+	/* NOTREACHED */
+
+	.globl	invalidate_bats
+invalidate_bats:
+
+	li	r0, 0
+	/* invalidate BATs */
+	mtspr	IBAT0U, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT3U, r0
+	mtspr	IBAT4U, r0
+	mtspr	IBAT5U, r0
+	mtspr	IBAT6U, r0
+	mtspr	IBAT7U, r0
+
+	isync
+	mtspr	DBAT0U, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT3U, r0
+	mtspr	DBAT4U, r0
+	mtspr	DBAT5U, r0
+	mtspr	DBAT6U, r0
+	mtspr	DBAT7U, r0
+
+	isync
+	sync
+	blr
+
+/*
+ * early_bats:
+ *
+ * Set up bats needed early on - this is usually the BAT for the
+ * stack-in-cache, the Flash, and CCSR space
+ */
+	.globl  early_bats
+early_bats:
+	/* IBAT 3 */
+	lis	r4, CONFIG_SYS_IBAT3L@h
+	ori     r4, r4, CONFIG_SYS_IBAT3L@l
+	lis	r3, CONFIG_SYS_IBAT3U@h
+	ori     r3, r3, CONFIG_SYS_IBAT3U@l
+	mtspr   IBAT3L, r4
+	mtspr   IBAT3U, r3
+	isync
+
+	/* DBAT 3 */
+	lis	r4, CONFIG_SYS_DBAT3L@h
+	ori     r4, r4, CONFIG_SYS_DBAT3L@l
+	lis	r3, CONFIG_SYS_DBAT3U@h
+	ori     r3, r3, CONFIG_SYS_DBAT3U@l
+	mtspr   DBAT3L, r4
+	mtspr   DBAT3U, r3
+	isync
+
+	/* IBAT 5 */
+	lis	r4, CONFIG_SYS_IBAT5L@h
+	ori     r4, r4, CONFIG_SYS_IBAT5L@l
+	lis	r3, CONFIG_SYS_IBAT5U@h
+	ori     r3, r3, CONFIG_SYS_IBAT5U@l
+	mtspr   IBAT5L, r4
+	mtspr   IBAT5U, r3
+	isync
+
+	/* DBAT 5 */
+	lis	r4, CONFIG_SYS_DBAT5L@h
+	ori     r4, r4, CONFIG_SYS_DBAT5L@l
+	lis	r3, CONFIG_SYS_DBAT5U@h
+	ori     r3, r3, CONFIG_SYS_DBAT5U@l
+	mtspr   DBAT5L, r4
+	mtspr   DBAT5U, r3
+	isync
+
+	/* IBAT 6 */
+	lis	r4, CONFIG_SYS_IBAT6L_EARLY@h
+	ori     r4, r4, CONFIG_SYS_IBAT6L_EARLY@l
+	lis	r3, CONFIG_SYS_IBAT6U_EARLY@h
+	ori     r3, r3, CONFIG_SYS_IBAT6U_EARLY@l
+	mtspr   IBAT6L, r4
+	mtspr   IBAT6U, r3
+	isync
+
+	/* DBAT 6 */
+	lis	r4, CONFIG_SYS_DBAT6L_EARLY@h
+	ori     r4, r4, CONFIG_SYS_DBAT6L_EARLY@l
+	lis	r3, CONFIG_SYS_DBAT6U_EARLY@h
+	ori     r3, r3, CONFIG_SYS_DBAT6U_EARLY@l
+	mtspr   DBAT6L, r4
+	mtspr   DBAT6U, r3
+	isync
+
+#if(CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
+	/* IBAT 7 */
+	lis	r4, CONFIG_SYS_CCSR_DEFAULT_IBATL@h
+	ori     r4, r4, CONFIG_SYS_CCSR_DEFAULT_IBATL@l
+	lis	r3, CONFIG_SYS_CCSR_DEFAULT_IBATU@h
+	ori     r3, r3, CONFIG_SYS_CCSR_DEFAULT_IBATU@l
+	mtspr   IBAT7L, r4
+	mtspr   IBAT7U, r3
+	isync
+
+	/* DBAT 7 */
+	lis	r4, CONFIG_SYS_CCSR_DEFAULT_DBATL@h
+	ori     r4, r4, CONFIG_SYS_CCSR_DEFAULT_DBATL@l
+	lis	r3, CONFIG_SYS_CCSR_DEFAULT_DBATU@h
+	ori     r3, r3, CONFIG_SYS_CCSR_DEFAULT_DBATU@l
+	mtspr   DBAT7L, r4
+	mtspr   DBAT7U, r3
+	isync
+#endif
+	blr
+
+	.globl clear_tlbs
+clear_tlbs:
+	addis   r3, 0, 0x0000
+	addis   r5, 0, 0x4
+	isync
+tlblp:
+	tlbie   r3
+	sync
+	addi    r3, r3, 0x1000
+	cmp     0, 0, r3, r5
+	blt tlblp
+	blr
+
+	.globl disable_addr_trans
+disable_addr_trans:
+	/* disable address translation */
+	mflr	r4
+	mfmsr	r3
+	andi.	r0, r3, (MSR_IR | MSR_DR)
+	beqlr
+	andc	r3, r3, r0
+	mtspr	SRR0, r4
+	mtspr	SRR1, r3
+	rfi
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+	.globl	dc_read
+dc_read:
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+	.globl get_svr
+get_svr:
+	mfspr	r3, SVR
+	blr
+
+
+/*
+ * Function:	in8
+ * Description:	Input 8 bits
+ */
+	.globl	in8
+in8:
+	lbz	r3,0x0000(r3)
+	blr
+
+/*
+ * Function:	out8
+ * Description:	Output 8 bits
+ */
+	.globl	out8
+out8:
+	stb	r4,0x0000(r3)
+	blr
+
+/*
+ * Function:	out16
+ * Description:	Output 16 bits
+ */
+	.globl	out16
+out16:
+	sth	r4,0x0000(r3)
+	blr
+
+/*
+ * Function:	out16r
+ * Description:	Byte reverse and output 16 bits
+ */
+	.globl	out16r
+out16r:
+	sthbrx	r4,r0,r3
+	blr
+
+/*
+ * Function:	out32
+ * Description:	Output 32 bits
+ */
+	.globl	out32
+out32:
+	stw	r4,0x0000(r3)
+	blr
+
+/*
+ * Function:	out32r
+ * Description:	Byte reverse and output 32 bits
+ */
+	.globl	out32r
+out32r:
+	stwbrx	r4,r0,r3
+	blr
+
+/*
+ * Function:	in16
+ * Description:	Input 16 bits
+ */
+	.globl	in16
+in16:
+	lhz	r3,0x0000(r3)
+	blr
+
+/*
+ * Function:	in16r
+ * Description:	Input 16 bits and byte reverse
+ */
+	.globl	in16r
+in16r:
+	lhbrx	r3,r0,r3
+	blr
+
+/*
+ * Function:	in32
+ * Description:	Input 32 bits
+ */
+	.globl	in32
+in32:
+	lwz	3,0x0000(3)
+	blr
+
+/*
+ * Function:	in32r
+ * Description:	Input 32 bits and byte reverse
+ */
+	.globl	in32r
+in32r:
+	lwbrx	r3,r0,r3
+	blr
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+
+	mr	r1,  r3		/* Set new stack pointer		*/
+	mr	r9,  r4		/* Save copy of Global Data pointer	*/
+	mr	r10, r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+/* clear_bss: */
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+	mr	r3, r9		/* Init Date pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/* not reached - end relocate_code */
+/*-----------------------------------------------------------------------*/
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	/* enable execptions from RAM vectors */
+	mfmsr	r7
+	li	r8,MSR_IP
+	andc	r7,r7,r8
+	ori	r7,r7,MSR_ME		/* Enable Machine Check */
+	mtmsr	r7
+
+	mtlr	r4			/* restore link register	*/
+	blr
+
+.globl enable_ext_addr
+enable_ext_addr:
+	mfspr	r0, HID0
+	lis	r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h
+	ori	r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l
+	mtspr	HID0, r0
+	sync
+	isync
+	blr
+
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
+.globl setup_ccsrbar
+setup_ccsrbar:
+	/* Special sequence needed to update CCSRBAR itself */
+	lis	r4, CONFIG_SYS_CCSRBAR_DEFAULT@h
+	ori	r4, r4, CONFIG_SYS_CCSRBAR_DEFAULT@l
+
+	lis	r5, CONFIG_SYS_CCSRBAR_PHYS_LOW@h
+	ori	r5, r5, CONFIG_SYS_CCSRBAR_PHYS_LOW@l
+	srwi	r5,r5,12
+	li	r6, CONFIG_SYS_CCSRBAR_PHYS_HIGH@l
+	rlwimi	r5,r6,20,8,11
+	stw	r5, 0(r4) /* Store physical value of CCSR */
+	isync
+
+	lis	r5, TEXT_BASE@h
+	ori	r5,r5,TEXT_BASE@l
+	lwz	r5, 0(r5)
+	isync
+
+	/* Use VA of CCSR to do read */
+	lis	r3, CONFIG_SYS_CCSRBAR@h
+	lwz	r5, CONFIG_SYS_CCSRBAR@l(r3)
+	isync
+
+	blr
+#endif
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+	/* Allocate Initial RAM in data cache.
+	 */
+	lis	r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+	ori	r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+	li	r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+		     (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+	mtctr	r4
+1:
+	dcbz	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+#if 1
+/* Lock the data cache */
+	mfspr	r0, HID0
+	ori	r0, r0, 0x1000
+	sync
+	mtspr	HID0, r0
+	sync
+	blr
+#endif
+#if 0
+	/* Lock the first way of the data cache */
+	mfspr	r0, LDSTCR
+	ori	r0, r0, 0x0080
+#if defined(CONFIG_ALTIVEC)
+	dssall
+#endif
+	sync
+	mtspr	LDSTCR, r0
+	sync
+	isync
+	blr
+#endif
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+	/* invalidate the INIT_RAM section */
+	lis	r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+	ori	r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+	li	r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
+		     (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+	mtctr	r4
+1:	icbi	r0, r3
+	addi	r3, r3, 32
+	bdnz	1b
+	sync			/* Wait for all icbi to complete on bus */
+	isync
+#if 1
+/* Unlock the data cache and invalidate it */
+	mfspr	r0, HID0
+	li	r3,0x1000
+	andc	r0,r0,r3
+	li	r3,0x0400
+	or	r0,r0,r3
+	sync
+	mtspr	HID0, r0
+	sync
+	blr
+#endif
+#if 0
+	/* Unlock the first way of the data cache */
+	mfspr	r0, LDSTCR
+	li	r3,0x0080
+	andc	r0,r0,r3
+#ifdef CONFIG_ALTIVEC
+	dssall
+#endif
+	sync
+	mtspr	LDSTCR, r0
+	sync
+	isync
+	li	r3,0x0400
+	or	r0,r0,r3
+	sync
+	mtspr	HID0, r0
+	sync
+	blr
+#endif
+#endif
diff --git a/arch/ppc/cpu/mpc86xx/traps.c b/arch/ppc/cpu/mpc86xx/traps.c
new file mode 100644
index 0000000..406403e
--- /dev/null
+++ b/arch/ppc/cpu/mpc86xx/traps.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * End of addressable memory.  This may be less than the actual
+ * amount of memory on the system if we're unable to keep all
+ * the memory mapped in.
+ */
+extern ulong get_effective_memsize(void);
+#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize())
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint) sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32)
+			break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void
+show_regs(struct pt_regs *regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+	       " %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP:"
+	       " %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr & MSR_EE ? 1 : 0,
+	       regs->msr & MSR_PR ? 1 : 0, regs->msr & MSR_FP ? 1 : 0,
+	       regs->msr & MSR_ME ? 1 : 0, regs->msr & MSR_IR ? 1 : 0,
+	       regs->msr & MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0; i < 32; i++) {
+		if ((i % 8) == 0) {
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d", regs->nip, signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+		return;
+#endif
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ", regs);
+	switch ( regs->msr & 0x001F0000) {
+	case (0x80000000>>11):
+		printf("MSS error. MSSSR0: %08x\n", mfspr(SPRN_MSSSR0));
+		break;
+	case (0x80000000>>12):
+		printf("Machine check signal - probably due to mm fault\n"
+		       "with mmu off\n");
+		break;
+	case (0x80000000 >> 13):
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000 >> 14):
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000 >> 15):
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL;
+	int i, j;
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs(regs);
+
+	p = (unsigned char *)((unsigned long)p & 0xFFFFFFE0);
+	p -= 32;
+	for (i = 0; i < 256; i += 16) {
+		printf("%08x: ", (unsigned int)p + i);
+		for (j = 0; j < 16; j++) {
+			printf("%02x ", p[i + j]);
+		}
+		printf("\n");
+	}
+
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	printf("UnknownException regs@%lx\n", (ulong)regs);
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+/*
+ * Probe an address by reading.
+ * If not present, return -1,
+ * otherwise return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xx/Makefile b/arch/ppc/cpu/mpc8xx/Makefile
new file mode 100644
index 0000000..5f70459
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/Makefile
@@ -0,0 +1,66 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+# CFLAGS += -DET_DEBUG
+
+LIB	= $(obj)lib$(CPU).a
+
+START-y	+= start.o
+START-y	+= kgdb.o
+COBJS-y	+= bedbug_860.o
+COBJS-y	+= commproc.o
+COBJS-y	+= cpu.o
+COBJS-y	+= cpu_init.o
+COBJS-y	+= fec.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-y	+= i2c.o
+COBJS-y	+= interrupts.o
+COBJS-y	+= lcd.o
+COBJS-y	+= scc.o
+COBJS-y	+= serial.o
+COBJS-y	+= speed.o
+COBJS-y	+= spi.o
+COBJS-y	+= traps.o
+COBJS-y	+= upatch.o
+COBJS-y	+= video.o
+SOBJS-y	+= plprcr_write.o
+
+SRCS	:= $(START-y:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START	:= $(addprefix $(obj),$(START-y))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS) $(obj)kgdb.o
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/mpc8xx/bedbug_860.c b/arch/ppc/cpu/mpc8xx/bedbug_860.c
new file mode 100644
index 0000000..0308bbb
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/bedbug_860.c
@@ -0,0 +1,316 @@
+/*
+ * Bedbug Functions specific to the MPC860 chip
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+#include <bedbug/type.h>
+
+#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_8xx)
+
+#define MAX_BREAK_POINTS 2
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug860_init __P((void));
+void bedbug860_do_break __P((cmd_tbl_t*,int,int,char*[]));
+void bedbug860_break_isr __P((struct pt_regs*));
+int  bedbug860_find_empty __P((void));
+int  bedbug860_set __P((int,unsigned long));
+int  bedbug860_clear __P((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the MPC860.  Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug860_init( void )
+{
+  int	i;
+  /* -------------------------------------------------- */
+
+  bug_ctx.hw_debug_enabled = 0;
+  bug_ctx.stopped = 0;
+  bug_ctx.current_bp = 0;
+  bug_ctx.regs = NULL;
+
+  bug_ctx.do_break   = bedbug860_do_break;
+  bug_ctx.break_isr  = bedbug860_break_isr;
+  bug_ctx.find_empty = bedbug860_find_empty;
+  bug_ctx.set        = bedbug860_set;
+  bug_ctx.clear      = bedbug860_clear;
+
+  for( i = 1; i <= MAX_BREAK_POINTS; ++i )
+    (*bug_ctx.clear)( i );
+
+  puts ("BEDBUG:ready\n");
+  return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show one of the hardware breakpoints for the 860.  The "off"
+ * string will disable a specific breakpoint.  The "show" string will
+ * display the current breakpoints.  Otherwise an address will set a
+ * breakpoint at that address.  Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug860_do_break (cmd_tbl_t *cmdtp, int flag, int argc,
+			 char *argv[])
+{
+  long		addr = 0;       /* Address to break at  */
+  int		which_bp;       /* Breakpoint number    */
+  /* -------------------------------------------------- */
+
+  if (argc < 2)
+  {
+    cmd_usage(cmdtp);
+    return;
+  }
+
+  /* Turn off a breakpoint */
+
+  if( strcmp( argv[ 1 ], "off" ) == 0 )
+  {
+    if( bug_ctx.hw_debug_enabled == 0 )
+    {
+      printf( "No breakpoints enabled\n" );
+      return;
+    }
+
+    which_bp = simple_strtoul( argv[ 2 ], NULL, 10 );
+
+    if( bug_ctx.clear )
+      (*bug_ctx.clear)( which_bp );
+
+    printf( "Breakpoint %d removed\n", which_bp );
+    return;
+  }
+
+  /* Show a list of breakpoints */
+
+  if( strcmp( argv[ 1 ], "show" ) == 0 )
+  {
+    for( which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp )
+    {
+
+      switch( which_bp )
+      {
+      case 1: addr = GET_CMPA(); break;
+      case 2: addr = GET_CMPB(); break;
+      case 3: addr = GET_CMPC(); break;
+      case 4: addr = GET_CMPD(); break;
+      }
+
+      printf( "Breakpoint [%d]: ", which_bp );
+      if( addr == 0 )
+	printf( "NOT SET\n" );
+      else
+	disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+    }
+    return;
+  }
+
+  /* Set a breakpoint at the address */
+
+  if( !isdigit( argv[ 1 ][ 0 ]))
+  {
+    cmd_usage(cmdtp);
+    return;
+  }
+
+  addr = simple_strtoul( argv[ 1 ], NULL, 16 ) & 0xfffffffc;
+
+  if(( bug_ctx.set ) && ( which_bp = (*bug_ctx.set)( 0, addr )) > 0 )
+  {
+    printf( "Breakpoint [%d]: ", which_bp );
+    disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+  }
+
+  return;
+} /* bedbug860_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint.  First determine which breakpoint was hit by
+ * looking at the DeBug Status Register (DBSR), clear the breakpoint
+ * and enter a mini main loop.  Stay in the loop until the stopped flag
+ * in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug860_break_isr( struct pt_regs *regs )
+{
+  unsigned long	addr;     /* Address stopped at   */
+  unsigned long	cause;     /* Address stopped at   */
+  /* -------------------------------------------------- */
+
+  cause = GET_ICR();
+
+  if( !(cause & 0x00000004)) {
+    printf( "Not an instruction breakpoint (ICR 0x%08lx)\n", cause );
+    return;
+  }
+
+  addr = regs->nip;
+
+  if( addr == GET_CMPA() )
+  {
+    bug_ctx.current_bp = 1;
+  }
+  else if( addr == GET_CMPB() )
+  {
+    bug_ctx.current_bp = 2;
+  }
+  else if( addr == GET_CMPC() )
+  {
+    bug_ctx.current_bp = 3;
+  }
+  else if( addr == GET_CMPD() )
+  {
+    bug_ctx.current_bp = 4;
+  }
+
+  bedbug_main_loop( addr, regs );
+  return;
+} /* bedbug860_break_isr */
+
+
+
+/* ======================================================================
+ * Look through all of the hardware breakpoints available to see if one
+ * is unused.
+ * ====================================================================== */
+
+int bedbug860_find_empty( void )
+{
+  /* -------------------------------------------------- */
+
+  if( GET_CMPA() == 0 )
+    return 1;
+
+  if( GET_CMPB() == 0 )
+    return 2;
+
+  if( GET_CMPC() == 0 )
+    return 3;
+
+  if( GET_CMPD() == 0 )
+    return 4;
+
+  return 0;
+} /* bedbug860_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint.  If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint.  If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0.  Set the break
+ * address in the appropriate IACx register and enable proper address
+ * beakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug860_set( int which_bp, unsigned long addr )
+{
+  /* -------------------------------------------------- */
+
+  /* Only look if which_bp == 0, else use which_bp */
+  if(( bug_ctx.find_empty ) && ( !which_bp ) &&
+     ( which_bp = (*bug_ctx.find_empty)()) == 0 )
+  {
+    printf( "All breakpoints in use\n" );
+    return 0;
+  }
+
+  if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+  {
+    printf( "Invalid break point # %d\n", which_bp );
+    return 0;
+  }
+
+  if( ! bug_ctx.hw_debug_enabled )
+  {
+    bug_ctx.hw_debug_enabled = 1;
+    SET_DER( GET_DER() | 0x00000004 );
+  }
+
+  switch( which_bp )
+  {
+  case 1:
+    SET_CMPA( addr );
+    SET_ICTRL( GET_ICTRL() | 0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */
+    break;
+
+  case 2:
+    SET_CMPB( addr );
+    SET_ICTRL( GET_ICTRL() | 0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */
+    break;
+
+  case 3:
+    SET_CMPC( addr );
+    SET_ICTRL( GET_ICTRL() | 0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */
+    break;
+
+  case 4:
+    SET_CMPD( addr );
+    SET_ICTRL( GET_ICTRL() | 0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */
+    break;
+  }
+
+  return which_bp;
+} /* bedbug860_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the appropriate IACx register
+ * to zero and claring the instruction address breakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug860_clear( int which_bp )
+{
+  /* -------------------------------------------------- */
+
+  if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+  {
+    printf( "Invalid break point # (%d)\n", which_bp );
+    return -1;
+  }
+
+  switch( which_bp )
+  {
+  case 1:
+    SET_CMPA( 0 );
+    SET_ICTRL( GET_ICTRL() & ~0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */
+    break;
+
+  case 2:
+    SET_CMPB( 0 );
+    SET_ICTRL( GET_ICTRL() & ~0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */
+    break;
+
+  case 3:
+    SET_CMPC( 0 );
+    SET_ICTRL( GET_ICTRL() & ~0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */
+    break;
+
+  case 4:
+    SET_CMPD( 0 );
+    SET_ICTRL( GET_ICTRL() & ~0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */
+    break;
+  }
+
+  return 0;
+} /* bedbug860_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/ppc/cpu/mpc8xx/commproc.c b/arch/ppc/cpu/mpc8xx/commproc.c
new file mode 100644
index 0000000..a87a0dc
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/commproc.c
@@ -0,0 +1,131 @@
+/*
+ * (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 <commproc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+
+int dpram_init (void)
+{
+	/* Reclaim the DP memory for our use. */
+	gd->dp_alloc_base = CPM_DATAONLY_BASE;
+	gd->dp_alloc_top  = CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE;
+
+	return (0);
+}
+
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint dpram_alloc (uint size)
+{
+	uint addr = gd->dp_alloc_base;
+
+	if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top)
+		return (CPM_DP_NOSPACE);
+
+	gd->dp_alloc_base += size;
+
+	return addr;
+}
+
+uint dpram_base (void)
+{
+	return gd->dp_alloc_base;
+}
+
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint dpram_alloc_align (uint size, uint align)
+{
+	uint addr, mask = align - 1;
+
+	addr = (gd->dp_alloc_base + mask) & ~mask;
+
+	if ((addr + size) >= gd->dp_alloc_top)
+		return (CPM_DP_NOSPACE);
+
+	gd->dp_alloc_base = addr + size;
+
+	return addr;
+}
+
+uint dpram_base_align (uint align)
+{
+	uint mask = align - 1;
+
+	return (gd->dp_alloc_base + mask) & ~mask;
+}
+#endif	/* CONFIG_SYS_ALLOC_DPRAM */
+
+#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
+
+void post_word_store (ulong a)
+{
+	volatile void *save_addr =
+		((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem + CPM_POST_WORD_ADDR;
+
+	*(volatile ulong *) save_addr = a;
+}
+
+ulong post_word_load (void)
+{
+	volatile void *save_addr =
+		((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem + CPM_POST_WORD_ADDR;
+
+	return *(volatile ulong *) save_addr;
+}
+
+#endif	/* CONFIG_POST || CONFIG_LOGBUFFER*/
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+void bootcount_store (ulong a)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)( ((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem +
+		                    CPM_BOOTCOUNT_ADDR );
+
+	save_addr[0] = a;
+	save_addr[1] = BOOTCOUNT_MAGIC;
+}
+
+ulong bootcount_load (void)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)( ((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem +
+		                    CPM_BOOTCOUNT_ADDR );
+
+	if (save_addr[1] != BOOTCOUNT_MAGIC)
+		return 0;
+	else
+		return save_addr[0];
+}
+
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/arch/ppc/cpu/mpc8xx/config.mk b/arch/ppc/cpu/mpc8xx/config.mk
new file mode 100644
index 0000000..5540d65
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (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
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_8xx -ffixed-r2 -mstring -mcpu=860 -msoft-float
diff --git a/arch/ppc/cpu/mpc8xx/cpu.c b/arch/ppc/cpu/mpc8xx/cpu.c
new file mode 100644
index 0000000..2eb848b
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/cpu.c
@@ -0,0 +1,654 @@
+/*
+ * (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 <commproc.h>
+#include <netdev.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char *cpu_warning = "\n         " \
+	"*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***";
+
+#if ((defined(CONFIG_MPC86x) || defined(CONFIG_MPC855)) && \
+     !defined(CONFIG_MPC862))
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+	char *id_str =
+# if defined(CONFIG_MPC855)
+	"PC855";
+# elif defined(CONFIG_MPC860P)
+	"PC860P";
+# else
+	NULL;
+# endif
+	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;
+	suf = "";
+
+	/*
+	 * Some boards use sockets so different CPUs can be used.
+	 * We have to check chip version in run time.
+	 */
+	switch (k) {
+	case 0x00020001: pre = 'P'; break;
+	case 0x00030001: 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;
+		/* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */
+	case 0x08010004:		/* Rev. A.0 */
+		suf = "A";
+		/* fall through */
+	case 0x08000003:		/* Rev. 0.3 */
+		pre = 'M'; m = 1;
+		if (id_str == NULL)
+			id_str =
+# if defined(CONFIG_MPC852T)
+		"PC852T";
+# elif defined(CONFIG_MPC859T)
+		"PC859T";
+# elif defined(CONFIG_MPC859DSL)
+		"PC859DSL";
+# elif defined(CONFIG_MPC866T)
+		"PC866T";
+# else
+		"PC866x"; /* Unknown chip from MPC866 family */
+# endif
+		break;
+	case 0x09000000: pre = 'M'; mid = suf = ""; m = 1;
+		if (id_str == NULL)
+			id_str = "PC885"; /* 870/875/880/885 */
+		break;
+
+	default: suf = NULL; break;
+	}
+
+	if (id_str == NULL)
+		id_str = "PC86x";	/* Unknown 86x chip */
+	if (suf)
+		printf ("%c%s%sZPnn%s", pre, id_str, mid, suf);
+	else
+		printf ("unknown M%s (0x%08x)", id_str, k);
+
+
+#if defined(CONFIG_SYS_8xx_CPUCLK_MIN) && defined(CONFIG_SYS_8xx_CPUCLK_MAX)
+	printf (" at %s MHz [%d.%d...%d.%d MHz]\n       ",
+		strmhz (buf, clock),
+		CONFIG_SYS_8xx_CPUCLK_MIN / 1000000,
+		((CONFIG_SYS_8xx_CPUCLK_MIN % 1000000) + 50000) / 100000,
+		CONFIG_SYS_8xx_CPUCLK_MAX / 1000000,
+		((CONFIG_SYS_8xx_CPUCLK_MAX % 1000000) + 50000) / 100000
+	);
+#else
+	printf (" at %s MHz: ", strmhz (buf, clock));
+#endif
+	printf ("%u kB I-Cache %u kB D-Cache",
+		checkicache () >> 10,
+		checkdcache () >> 10
+	);
+
+	/* do we have a FEC (860T/P or 852/859/866/885)? */
+
+	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');
+
+#ifdef DEBUG
+	if(clock != measure_gclk()) {
+	    printf ("clock %ldHz != %dHz\n", clock, measure_gclk());
+	}
+#endif
+
+	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;
+	}
+
+#ifndef CONFIG_MPC857
+	if (suf)
+		printf ("%cPC862%sZPnn%s", pre, mid, suf);
+	else
+		printf ("unknown MPC862 (0x%08x)", k);
+#else
+	if (suf)
+		printf ("%cPC857TZPnn%s", pre, suf); /* only 857T tested right now! */
+	else
+		printf ("unknown MPC857 (0x%08x)", k);
+#endif
+
+	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)
+{
+	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 *) CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	u32 cacheon = rd_ic_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP86x
+	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 *) CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	u32 cacheon = rd_dc_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP86x
+	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 *) CONFIG_SYS_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++;
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef CONFIG_LWMON
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	ulong msr, addr;
+
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_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 CONFIG_SYS_RESET_ADDRESS
+	addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
+	 * - sizeof (ulong) is usually a valid address. Better pick an address
+	 * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+	 * "(ulong)-1" used to be a good choice for many systems...
+	 */
+	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+	((void (*)(void)) addr) ();
+	return 1;
+}
+
+#else	/* CONFIG_LWMON */
+
+/*
+ * On the LWMON board, the MCLR reset input of the PIC's on the board
+ * uses a 47K/1n RC combination which has a 47us time  constant.  The
+ * low  signal on the HRESET pin of the CPU is only 512 clocks = 8 us
+ * and thus too short to reset the external hardware. So we  use  the
+ * watchdog to reset the board.
+ */
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	/* prevent triggering the watchdog */
+	disable_interrupts ();
+
+	/* make sure the watchdog is running */
+	reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+
+	/* wait for watchdog reset */
+	while (1) {};
+
+	/* NOTREACHED */
+	return 1;
+}
+
+#endif	/* CONFIG_LWMON */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ * See sections 14.2 and 14.6 of the User's Manual
+ */
+unsigned long get_tbclk (void)
+{
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	volatile immap_t *immap = (volatile immap_t *)(immr & 0xFFFF0000);
+	ulong oscclk, factor, pll;
+
+	if (immap->im_clkrst.car_sccr & SCCR_TBS) {
+		return (gd->cpu_clk / 16);
+	}
+
+	pll = immap->im_clkrst.car_plprcr;
+
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+
+	/*
+	 * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication
+	 * factor is calculated as follows:
+	 *
+	 *		     MFN
+	 *	     MFI + -------
+	 *		   MFD + 1
+	 * factor =  -----------------
+	 *	     (PDF + 1) * 2^S
+	 *
+	 * For older chips, it's just MF field of PLPRCR plus one.
+	 */
+	if ((immr & 0x0FFF) >= MPC8xx_NEW_CLK) { /* MPC866/87x/88x series */
+		factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN)/(PLPRCR_val(MFD)+1))/
+			(PLPRCR_val(PDF)+1) / (1<<PLPRCR_val(S));
+	} else {
+		factor = PLPRCR_val(MF)+1;
+	}
+
+	oscclk = gd->cpu_clk / factor;
+
+	if ((immap->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 *) CONFIG_SYS_IMMR);
+	if (re_enable)
+		enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_LWMON)
+
+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   */
+# elif defined(CONFIG_KUP4K) || defined(CONFIG_KUP4X)
+	/*
+	 * The KUP4 boards uses a TPS3705 Watchdog
+	 * with the trigger pin connected to port PA.5
+	 */
+# define WATCHDOG_BIT	0x0400
+	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 */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(SCC_ENET) && defined(CONFIG_CMD_NET)
+	scc_initialize(bis);
+#endif
+#if defined(FEC_ENET)
+	fec_initialize(bis);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xx/cpu_init.c b/arch/ppc/cpu/mpc8xx/cpu_init.c
new file mode 100644
index 0000000..eb0091b
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/cpu_init.c
@@ -0,0 +1,285 @@
+/*
+ * (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 <watchdog.h>
+
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#if defined(CONFIG_SYS_RTCSC) || defined(CONFIG_SYS_RMDS)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+    defined(CONFIG_SYS_SMC_UCODE_PATCH)
+void cpm_load_patch (volatile immap_t * immr);
+#endif
+
+/*
+ * 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)
+{
+#ifndef CONFIG_MBX
+	volatile memctl8xx_t *memctl = &immr->im_memctl;
+# ifdef CONFIG_SYS_PLPRCR
+	ulong mfmask;
+# endif
+#endif
+	ulong reg;
+
+	/* SYPCR - contains watchdog control (11-9) */
+
+	immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+	reset_8xx_watchdog (immr);
+#endif /* CONFIG_WATCHDOG */
+
+	/* SIUMCR - contains debug pin configuration (11-6) */
+#ifndef CONFIG_SVM_SC8xx
+	immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR;
+#else
+	immr->im_siu_conf.sc_siumcr = CONFIG_SYS_SIUMCR;
+#endif
+	/* initialize timebase status and control register (11-26) */
+	/* unlock TBSCRK */
+
+	immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+	immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR;
+
+	/* initialize the PIT (11-31) */
+
+	immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+	immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+	/* System integration timers. Don't change EBDF! (15-27) */
+
+	immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+	reg = immr->im_clkrst.car_sccr;
+	reg &= SCCR_MASK;
+	reg |= CONFIG_SYS_SCCR;
+	immr->im_clkrst.car_sccr = reg;
+
+	/* PLL (CPU clock) settings (15-30) */
+
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+#ifndef CONFIG_MBX		/* MBX board does things different */
+
+	/* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
+	 * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
+	 * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the current MF
+	 * field value.
+	 *
+	 * For newer (starting MPC866) chips PLPRCR layout is different.
+	 */
+#ifdef CONFIG_SYS_PLPRCR
+	if (get_immr(0xFFFF) >= MPC8xx_NEW_CLK)
+	   mfmask = PLPRCR_MFACT_MSK;
+	else
+	   mfmask = PLPRCR_MF_MSK;
+
+	if ((CONFIG_SYS_PLPRCR & mfmask) != 0)
+	   reg = CONFIG_SYS_PLPRCR;			/* reset control bits   */
+	else {
+	   reg = immr->im_clkrst.car_plprcr;
+	   reg &= mfmask;			/* isolate MF-related fields */
+	   reg |= CONFIG_SYS_PLPRCR;			/* reset control bits   */
+	}
+	immr->im_clkrst.car_plprcr = reg;
+#endif
+
+	/*
+	 * Memory Controller:
+	 */
+
+	/* perform BR0 reset that MPC850 Rev. A can't guarantee */
+	reg = memctl->memc_br0;
+	reg &= BR_PS_MSK;	/* Clear everything except Port Size bits */
+	reg |= BR_V;		/* then add just the "Bank Valid" bit     */
+	memctl->memc_br0 = reg;
+
+	/* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
+	 * preliminary addresses - these have to be modified later
+	 * when FLASH size has been determined
+	 *
+	 * Depending on the size of the memory region defined by
+	 * CONFIG_SYS_OR0_REMAP some boards (wide address mask) allow to map the
+	 * CONFIG_SYS_MONITOR_BASE, while others (narrower address mask) can't
+	 * map CONFIG_SYS_MONITOR_BASE.
+	 *
+	 * For example, for CONFIG_IVMS8, the CONFIG_SYS_MONITOR_BASE is
+	 * 0xff000000, but CONFIG_SYS_OR0_REMAP's address mask is 0xfff80000.
+	 *
+	 * If BR0 wasn't loaded with address base 0xff000000, then BR0's
+	 * base address remains as 0x00000000. However, the address mask
+	 * have been narrowed to 512Kb, so CONFIG_SYS_MONITOR_BASE wasn't mapped
+	 * into the Bank0.
+	 *
+	 * This is why CONFIG_IVMS8 and similar boards must load BR0 with
+	 * CONFIG_SYS_BR0_PRELIM in advance.
+	 *
+	 * [Thanks to Michael Liao for this explanation.
+	 *  I owe him a free beer. - wd]
+	 */
+
+#if defined(CONFIG_GTH)	        || \
+    defined(CONFIG_HERMES)	|| \
+    defined(CONFIG_ICU862)	|| \
+    defined(CONFIG_IP860)	|| \
+    defined(CONFIG_IVML24)	|| \
+    defined(CONFIG_IVMS8)	|| \
+    defined(CONFIG_LWMON)	|| \
+    defined(CONFIG_MHPC)	|| \
+    defined(CONFIG_PCU_E)	|| \
+    defined(CONFIG_R360MPI)	|| \
+    defined(CONFIG_RMU)		|| \
+    defined(CONFIG_RPXCLASSIC)	|| \
+    defined(CONFIG_RPXLITE)	|| \
+    defined(CONFIG_SPC1920)	|| \
+    defined(CONFIG_SPD823TS)
+
+	memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR0_REMAP)
+	memctl->memc_or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+	memctl->memc_or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR5_REMAP)
+	memctl->memc_or5 = CONFIG_SYS_OR5_REMAP;
+#endif
+
+	/* now restrict to preliminary range */
+	memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+	memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
+	memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+	memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_IP860) /* disable CS0 now that Flash is mapped on CS1 */
+	memctl->memc_br0 = 0;
+#endif
+
+#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
+	memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+	memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
+	memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+	memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR4_PRELIM) && defined(CONFIG_SYS_BR4_PRELIM)
+	memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
+	memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR5_PRELIM) && defined(CONFIG_SYS_BR5_PRELIM)
+	memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
+	memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR6_PRELIM) && defined(CONFIG_SYS_BR6_PRELIM)
+	memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
+	memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR7_PRELIM) && defined(CONFIG_SYS_BR7_PRELIM)
+	memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
+	memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+#endif /* ! CONFIG_MBX */
+
+	/*
+	 * Reset CPM
+	 */
+	immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG;
+	do {			/* Spin until command processed     */
+		__asm__ ("eieio");
+	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+#ifdef CONFIG_MBX
+	/*
+	 * on the MBX, things are a little bit different:
+	 * - we need to read the VPD to get board information
+	 * - the plprcr is set up dynamically
+	 * - the memory controller is set up dynamically
+	 */
+	mbx_init ();
+#endif /* CONFIG_MBX */
+
+#ifdef CONFIG_RPXCLASSIC
+	rpxclassic_init ();
+#endif
+
+#if defined(CONFIG_RPXLITE) && defined(CONFIG_ENV_IS_IN_NVRAM)
+	rpxlite_init ();
+#endif
+
+#ifdef CONFIG_SYS_RCCR			/* must be done before cpm_load_patch() */
+	/* write config value */
+	immr->im_cpm.cp_rccr = CONFIG_SYS_RCCR;
+#endif
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+    defined(CONFIG_SYS_SMC_UCODE_PATCH)
+	cpm_load_patch (immr);	/* load mpc8xx  microcode patch */
+#endif
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CONFIG_SYS_RTCSC) || defined(CONFIG_SYS_RMDS)
+	bd_t *bd = gd->bd;
+	volatile immap_t *immr = (volatile immap_t *) (bd->bi_immr_base);
+#endif
+
+#ifdef CONFIG_SYS_RTCSC
+	/* Unlock RTSC register */
+	immr->im_sitk.sitk_rtcsck = KAPWR_KEY;
+	/* write config value */
+	immr->im_sit.sit_rtcsc = CONFIG_SYS_RTCSC;
+#endif
+
+#ifdef CONFIG_SYS_RMDS
+	/* write config value */
+	immr->im_cpm.cp_rmds = CONFIG_SYS_RMDS;
+#endif
+	return (0);
+}
diff --git a/arch/ppc/cpu/mpc8xx/fdt.c b/arch/ppc/cpu/mpc8xx/fdt.c
new file mode 100644
index 0000000..7130983
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/fdt.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 (C) Bryan O'Donoghue
+ *
+ * Code copied & edited from Freescale mpc85xx stuff.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"timebase-frequency", get_tbclk(), 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"clock-frequency", bd->bi_intfreq, 1);
+	do_fixup_by_compat_u32(blob, "fsl,cpm-brg", "clock-frequency",
+		gd->brg_clk, 1);
+
+	/* Fixup ethernet MAC addresses */
+	fdt_fixup_ethernet(blob);
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
diff --git a/arch/ppc/cpu/mpc8xx/fec.c b/arch/ppc/cpu/mpc8xx/fec.c
new file mode 100644
index 0000000..89c1ff9
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/fec.c
@@ -0,0 +1,1026 @@
+/*
+ * (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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#undef	ET_DEBUG
+
+#if defined(CONFIG_CMD_NET) && \
+	(defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2))
+
+/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */
+#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2)
+#define CONFIG_ETHER_ON_FEC1 1
+#endif
+
+/* define WANT_MII when MII support is required */
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY)
+#define WANT_MII
+#else
+#undef WANT_MII
+#endif
+
+#if defined(WANT_MII)
+#include <miiphy.h>
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#endif
+
+#if defined(CONFIG_RMII) && !defined(WANT_MII)
+#error RMII support is unusable without a working PHY.
+#endif
+
+#ifdef CONFIG_SYS_DISCOVER_PHY
+static int mii_discover_phy(struct eth_device *dev);
+#endif
+
+int fec8xx_miiphy_read(char *devname, unsigned char addr,
+		unsigned char  reg, unsigned short *value);
+int fec8xx_miiphy_write(char *devname, unsigned char  addr,
+		unsigned char  reg, unsigned short value);
+
+static struct ether_fcc_info_s
+{
+	int ether_index;
+	int fecp_offset;
+	int phy_addr;
+	int actual_phy_addr;
+	int initialized;
+}
+	ether_fcc_info[] = {
+#if defined(CONFIG_ETHER_ON_FEC1)
+	{
+		0,
+		offsetof(immap_t, im_cpm.cp_fec1),
+#if defined(CONFIG_FEC1_PHY)
+		CONFIG_FEC1_PHY,
+#else
+		-1,	/* discover */
+#endif
+		-1,
+		0,
+
+	},
+#endif
+#if defined(CONFIG_ETHER_ON_FEC2)
+	{
+		1,
+		offsetof(immap_t, im_cpm.cp_fec2),
+#if defined(CONFIG_FEC2_PHY)
+		CONFIG_FEC2_PHY,
+#else
+		-1,
+#endif
+		-1,
+		0,
+	},
+#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
+
+#ifdef __GNUC__
+static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8)));
+#else
+#error txbuf must be aligned.
+#endif
+
+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);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static void __mii_init(void);
+#endif
+
+int fec_initialize(bd_t *bis)
+{
+	struct eth_device* dev;
+	struct ether_fcc_info_s *efis;
+	int             i;
+
+	for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) {
+
+		dev = malloc(sizeof(*dev));
+		if (dev == NULL)
+			hang();
+
+		memset(dev, 0, sizeof(*dev));
+
+		/* for FEC1 make sure that the name of the interface is the same
+		   as the old one for compatibility reasons */
+		if (i == 0) {
+			sprintf (dev->name, "FEC ETHERNET");
+		} else {
+			sprintf (dev->name, "FEC%d ETHERNET",
+				ether_fcc_info[i].ether_index + 1);
+		}
+
+		efis = &ether_fcc_info[i];
+
+		/*
+		 * reset actual phy addr
+		 */
+		efis->actual_phy_addr = -1;
+
+		dev->priv = efis;
+		dev->init = fec_init;
+		dev->halt = fec_halt;
+		dev->send = fec_send;
+		dev->recv = fec_recv;
+
+		eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+		miiphy_register(dev->name,
+			fec8xx_miiphy_read, fec8xx_miiphy_write);
+#endif
+	}
+	return 1;
+}
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length)
+{
+	int j, rc;
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+	/* 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)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp =
+		(volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+	int length;
+
+	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 {
+			volatile uchar *rx = NetRxPackets[rxIdx];
+
+			length -= 4;
+
+#if defined(CONFIG_CMD_CDP)
+			if ((rx[0] & 1) != 0
+			    && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0
+			    && memcmp ((uchar *) rx, NetCDPAddr, 6) != 0)
+				rx = NULL;
+#endif
+			/*
+			 * Pass the packet up to the protocol layers.
+			 */
+			if (rx != NULL)
+				NetReceive (rx, length);
+		}
+
+		/* 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
+
+#if defined(CONFIG_RMII)
+
+static inline void fec_10Mbps(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	int fecidx = efis->ether_index;
+	uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+	if ((unsigned int)fecidx >= 2)
+		hang();
+
+	((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr |=  mask;
+}
+
+static inline void fec_100Mbps(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	int fecidx = efis->ether_index;
+	uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+	if ((unsigned int)fecidx >= 2)
+		hang();
+
+	((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr &= ~mask;
+}
+
+#endif
+
+static inline void fec_full_duplex(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+	fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT;
+	fecp->fec_x_cntrl |=  FEC_TCNTRL_FDEN;	/* FD enable */
+}
+
+static inline void fec_half_duplex(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+	fecp->fec_r_cntrl |=  FEC_RCNTRL_DRT;
+	fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN;	/* FD disable */
+}
+
+static void fec_pin_init(int fecidx)
+{
+	bd_t           *bd = gd->bd;
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile fec_t *fecp;
+
+	/*
+	 * only two FECs please
+	 */
+	if ((unsigned int)fecidx >= 2)
+		hang();
+
+	if (fecidx == 0)
+		fecp = &immr->im_cpm.cp_fec1;
+	else
+		fecp = &immr->im_cpm.cp_fec2;
+
+	/*
+	 * 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.
+	 *
+	 * All MII configuration is done via FEC1 registers:
+	 */
+	immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
+
+#if defined(CONFIG_NETTA) || defined(CONFIG_NETPHONE) || defined(CONFIG_NETTA2)
+	/* our PHYs are the limit at 2.5 MHz */
+	fecp->fec_mii_speed <<= 1;
+#endif
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII)
+	/* use MDC for MII */
+	immr->im_ioport.iop_pdpar |=  0x0080;
+	immr->im_ioport.iop_pddir &= ~0x0080;
+#endif
+
+	if (fecidx == 0) {
+#if defined(CONFIG_ETHER_ON_FEC1)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+
+		immr->im_ioport.iop_papar |=  0xf830;
+		immr->im_ioport.iop_padir |=  0x0830;
+		immr->im_ioport.iop_padir &= ~0xf000;
+
+		immr->im_cpm.cp_pbpar     |=  0x00001001;
+		immr->im_cpm.cp_pbdir     &= ~0x00001001;
+
+		immr->im_ioport.iop_pcpar |=  0x000c;
+		immr->im_ioport.iop_pcdir &= ~0x000c;
+
+		immr->im_cpm.cp_pepar     |=  0x00000003;
+		immr->im_cpm.cp_pedir     |=  0x00000003;
+		immr->im_cpm.cp_peso      &= ~0x00000003;
+
+		immr->im_cpm.cp_cptr      &= ~0x00000100;
+
+#else
+
+#if !defined(CONFIG_FEC1_PHY_NORXERR)
+		immr->im_ioport.iop_papar |=  0x1000;
+		immr->im_ioport.iop_padir &= ~0x1000;
+#endif
+		immr->im_ioport.iop_papar |=  0xe810;
+		immr->im_ioport.iop_padir |=  0x0810;
+		immr->im_ioport.iop_padir &= ~0xe000;
+
+		immr->im_cpm.cp_pbpar     |=  0x00000001;
+		immr->im_cpm.cp_pbdir     &= ~0x00000001;
+
+		immr->im_cpm.cp_cptr      |=  0x00000100;
+		immr->im_cpm.cp_cptr      &= ~0x00000050;
+
+#endif /* !CONFIG_RMII */
+
+#elif !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(CONFIG_SYS_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) */
+
+#endif	/* CONFIG_ETHER_ON_FEC1 */
+	} else if (fecidx == 1) {
+
+#if defined(CONFIG_ETHER_ON_FEC2)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+		immr->im_cpm.cp_pepar     |=  0x0003fffc;
+		immr->im_cpm.cp_pedir     |=  0x0003fffc;
+		immr->im_cpm.cp_peso      &= ~0x000087fc;
+		immr->im_cpm.cp_peso      |=  0x00037800;
+
+		immr->im_cpm.cp_cptr      &= ~0x00000080;
+#else
+
+#if !defined(CONFIG_FEC2_PHY_NORXERR)
+		immr->im_cpm.cp_pepar     |=  0x00000010;
+		immr->im_cpm.cp_pedir     |=  0x00000010;
+		immr->im_cpm.cp_peso      &= ~0x00000010;
+#endif
+		immr->im_cpm.cp_pepar     |=  0x00039620;
+		immr->im_cpm.cp_pedir     |=  0x00039620;
+		immr->im_cpm.cp_peso      |=  0x00031000;
+		immr->im_cpm.cp_peso      &= ~0x00008620;
+
+		immr->im_cpm.cp_cptr      |=  0x00000080;
+		immr->im_cpm.cp_cptr      &= ~0x00000028;
+#endif /* CONFIG_RMII */
+
+#endif /* CONFIG_MPC885_FAMILY */
+
+#endif /* CONFIG_ETHER_ON_FEC2 */
+
+	}
+}
+
+static int fec_reset(volatile fec_t *fecp)
+{
+	int i;
+
+	/* 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)
+		return -1;
+
+	return 0;
+}
+
+static int fec_init (struct eth_device *dev, bd_t * bd)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile fec_t *fecp =
+		(volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+	int i;
+
+	if (efis->ether_index == 0) {
+#if defined(CONFIG_FADS)	/* FADS family uses FPGA (BCSR) to control PHYs */
+#if defined(CONFIG_MPC885ADS)
+		*(vu_char *) BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST);
+#else
+		/* 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 /* CONFIG_MPC885ADS */
+#endif /* CONFIG_FADS */
+	}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	/* the MII interface is connected to FEC1
+	 * so for the miiphy_xxx function to work we must
+	 * call mii_init since fec_halt messes the thing up
+	 */
+	if (efis->ether_index != 0)
+		__mii_init();
+#endif
+
+	if (fec_reset(fecp) < 0)
+		printf ("FEC_RESET_DELAY timeout\n");
+
+	/* 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 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
+
+#if defined(CONFIG_CMD_CDP)
+	/*
+	 * Turn on multicast address hash table
+	 */
+	fecp->fec_hash_table_high = 0xffffffff;
+	fecp->fec_hash_table_low = 0xffffffff;
+#else
+	/* Clear multicast address hash table
+	 */
+	fecp->fec_hash_table_high = 0;
+	fecp->fec_hash_table_low = 0;
+#endif
+
+	/* 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 CONFIG_SYS_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;
+
+	/*
+	 * Setup the pin configuration of the FEC
+	 */
+	fec_pin_init (efis->ether_index);
+
+	rxIdx = 0;
+	txIdx = 0;
+
+	/*
+	 * Now enable the transmit and receive processing
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+
+	if (efis->phy_addr == -1) {
+#ifdef CONFIG_SYS_DISCOVER_PHY
+		/*
+		 * wait for the PHY to wake up after reset
+		 */
+		efis->actual_phy_addr = mii_discover_phy (dev);
+
+		if (efis->actual_phy_addr == -1) {
+			printf ("Unable to discover phy!\n");
+			return -1;
+		}
+#else
+		efis->actual_phy_addr = -1;
+#endif
+	} else {
+		efis->actual_phy_addr = efis->phy_addr;
+	}
+
+#if defined(CONFIG_MII) && defined(CONFIG_RMII)
+	/*
+	 * adapt the RMII speed to the speed of the phy
+	 */
+	if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) {
+		fec_100Mbps (dev);
+	} else {
+		fec_10Mbps (dev);
+	}
+#endif
+
+#if defined(CONFIG_MII)
+	/*
+	 * adapt to the half/full speed settings
+	 */
+	if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) {
+		fec_full_duplex (dev);
+	} else {
+		fec_half_duplex (dev);
+	}
+#endif
+
+	/* And last, try to fill Rx Buffer Descriptors */
+	fecp->fec_r_des_active = 0x01000000;	/* Descriptor polling active    */
+
+	efis->initialized = 1;
+
+	return 0;
+}
+
+
+static void fec_halt(struct eth_device* dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+	int i;
+
+	/* avoid halt if initialized; mii gets stuck otherwise */
+	if (!efis->initialized)
+		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;
+	}
+
+	efis->initialized = 0;
+}
+
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+/* 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 */
+#define PHY_ID_DM9161		0x0181B880	/* Davicom DM9161 */
+#define PHY_ID_KSM8995M		0x00221450	/* MICREL KS8995MA */
+
+/* send command to phy using mii, wait for result */
+static uint
+mii_send(uint mii_cmd)
+{
+	uint mii_reply;
+	volatile fec_t	*ep;
+	int cnt;
+
+	ep = &(((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_fec);
+
+	ep->fec_mii_data = mii_cmd;	/* command to phy */
+
+	/* wait for mii complete */
+	cnt = 0;
+	while (!(ep->fec_ievent & FEC_ENET_MII)) {
+		if (++cnt > 1000) {
+			printf("mii_send STUCK!\n");
+			break;
+		}
+	}
+	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
+
+#if defined(CONFIG_SYS_DISCOVER_PHY)
+static int mii_discover_phy(struct eth_device *dev)
+{
+#define MAX_PHY_PASSES 11
+	uint phyno;
+	int  pass;
+	uint phytype;
+	int phyaddr;
+
+	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_PHYIDR2));
+#ifdef ET_DEBUG
+			printf("PHY type 0x%x pass %d type ", phytype, pass);
+#endif
+			if (phytype != 0xffff) {
+				phyaddr = phyno;
+				phytype |= mii_send(mk_mii_read(phyno,
+								PHY_PHYIDR1)) << 16;
+
+#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;
+				case PHY_ID_DM9161:
+					printf("Davicom DM9161\n");
+					break;
+				case PHY_ID_KSM8995M:
+					printf("MICREL KS8995M\n");
+					break;
+				default:
+					printf("0x%08x\n", phytype);
+					break;
+				}
+#endif
+			}
+		}
+	}
+	if (phyaddr < 0) {
+		printf("No PHY device found.\n");
+	}
+	return phyaddr;
+}
+#endif	/* CONFIG_SYS_DISCOVER_PHY */
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
+
+/****************************************************************************
+ * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet
+ * This function is a subset of eth_init
+ ****************************************************************************
+ */
+static void __mii_init(void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+	if (fec_reset(fecp) < 0)
+		printf ("FEC_RESET_DELAY timeout\n");
+
+	/* We use strictly polling mode only
+	 */
+	fecp->fec_imask = 0;
+
+	/* Clear any pending interrupt
+	 */
+	fecp->fec_ievent = 0xffc0;
+
+	/* Now enable the transmit and receive processing
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+}
+
+void mii_init (void)
+{
+	int i;
+
+	__mii_init();
+
+	/* Setup the pin configuration of the FEC(s)
+	*/
+	for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+		fec_pin_init(ether_fcc_info[i].ether_index);
+}
+
+/*****************************************************************************
+ * 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 fec8xx_miiphy_read(char *devname, 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 fec8xx_miiphy_write(char *devname, 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
+
+#endif
diff --git a/arch/ppc/cpu/mpc8xx/fec.h b/arch/ppc/cpu/mpc8xx/fec.h
new file mode 100644
index 0000000..a49417c
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/fec.h
@@ -0,0 +1,28 @@
+/*
+ * (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
+ */
+
+#ifndef	_FEC_H_
+#define	_FEC_H_
+
+
+#endif	/* _FEC_H_ */
diff --git a/arch/ppc/cpu/mpc8xx/i2c.c b/arch/ppc/cpu/mpc8xx/i2c.c
new file mode 100644
index 0000000..338caba
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/i2c.c
@@ -0,0 +1,707 @@
+/*
+ * (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
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_HARD_I2C
+
+#include <commproc.h>
+#include <i2c.h>
+#ifdef CONFIG_LWMON
+#include <watchdog.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* define to enable debug messages */
+#undef	DEBUG_I2C
+
+/* tx/rx timeout (we need the i2c early, so we don't use get_timer()) */
+#define TOUT_LOOP 1000000
+
+#define NUM_RX_BDS 4
+#define NUM_TX_BDS 4
+#define MAX_TX_SPACE 256
+#define I2C_RXTX_LEN 128	/* maximum tx/rx buffer length */
+
+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
+
+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		*/
+
+#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 + 1) / 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;
+
+    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 *) CONFIG_SYS_IMMR;
+	volatile i2c8xx_t *i2c = (i2c8xx_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 slaveaddr)
+{
+	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
+	volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+	volatile i2c8xx_t *i2c	= (i2c8xx_t *)&immap->im_i2c;
+	volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+	ulong rbase, tbase;
+	volatile I2C_BD *rxbd, *txbd;
+	uint dpaddr;
+
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+	/* call board specific i2c bus reset routine before accessing the   */
+	/* environment, which might be in a chip on that bus. For details   */
+	/* about this problem see doc/I2C_Edge_Conditions.                  */
+	i2c_init_board();
+#endif
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+	iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#else
+	/* Disable relocation */
+	iip->iic_rpbase = 0;
+#endif
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+	dpaddr = iip->iic_rbase;
+	if (dpaddr == 0) {
+	    /* need to allocate dual port ram */
+	    dpaddr = dpram_alloc_align(
+		(NUM_RX_BDS * sizeof(I2C_BD)) + (NUM_TX_BDS * sizeof(I2C_BD)) +
+		MAX_TX_SPACE, 8);
+	}
+#else
+	dpaddr = CPM_I2C_BASE;
+#endif
+
+	/*
+	 * initialise data in dual port ram:
+	 *
+	 * dpaddr->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)
+	 */
+
+	rbase = dpaddr;
+	tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
+
+	/* Initialize Port B I2C pins. */
+	cp->cp_pbpar |= 0x00000030;
+	cp->cp_pbdir |= 0x00000030;
+	cp->cp_pbodr |= 0x00000030;
+
+	/* Disable interrupts */
+	i2c->i2c_i2mod = 0x00;
+	i2c->i2c_i2cmr = 0x00;
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2add = slaveaddr;
+
+	/*
+	 * 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->cpu_clk, CONFIG_SYS_I2C_SPEED) ;
+
+	/* Set I2C controller in master mode */
+	i2c->i2c_i2com = 0x01;
+
+	/* Set SDMA bus arbitration level to 5 (SDCR) */
+	immap->im_siu_conf.sc_sdcr = 0x0001 ;
+
+	/* Initialize Tx/Rx parameters */
+	iip->iic_rbase = rbase;
+	iip->iic_tbase = tbase;
+	rxbd = (I2C_BD *)((unsigned char *)&cp->cp_dpmem[iip->iic_rbase]);
+	txbd = (I2C_BD *)((unsigned char *)&cp->cp_dpmem[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;
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+	/*
+	 *  Initialize required parameters if using microcode patch.
+	 */
+	iip->iic_rbptr  = iip->iic_rbase;
+	iip->iic_tbptr  = iip->iic_tbase;
+	iip->iic_rstate = 0;
+	iip->iic_tstate = 0;
+#else
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	do {
+		__asm__ __volatile__ ("eieio");
+	} while (cp->cp_cpcr & CPM_CR_FLG);
+#endif
+
+	/* 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 *)CONFIG_SYS_IMMR ;
+	volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+	volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+	PRINTD(("[I2C] i2c_newio\n"));
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+	iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+	state->rx_idx = 0;
+	state->tx_idx = 0;
+	state->rxbd = (void*)&cp->cp_dpmem[iip->iic_rbase];
+	state->txbd = (void*)&cp->cp_dpmem[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 msg + dest addr */
+			txbd->addr[0] = address << 1;
+			txbd->addr[1] = secondary_address;
+			i = 2;
+		} else {
+			txbd->length = size + 1;  /* Length of msg + dest addr */
+			txbd->addr[0] = address << 1;  /* Write dest addr 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 *)CONFIG_SYS_IMMR ;
+	volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+	volatile i2c8xx_t *i2c	= (i2c8xx_t *)&immap->im_i2c;
+	volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+	volatile I2C_BD *txbd, *rxbd;
+	volatile int j = 0;
+
+	PRINTD(("[I2C] i2c_doio\n"));
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+	iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+
+	if (state->tx_idx <= 0 && state->rx_idx <= 0) {
+		PRINTD(("[I2C] No I/O is queued\n"));
+		return I2CERR_QUEUE_EMPTY;
+	}
+
+	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 */
+
+	if (state->tx_idx > 0) {
+		txbd = ((I2C_BD*)state->txbd) - 1;
+		PRINTD(("[I2C] Transmitting...(txbd=0x%08lx)\n", (ulong)txbd));
+		while((txbd->status & BD_SC_READY) && (j++ < TOUT_LOOP)) {
+			if (ctrlc()) {
+				return (-1);
+			}
+			__asm__ __volatile__ ("eieio");
+		}
+	}
+
+	if ((state->rx_idx > 0) && (j < TOUT_LOOP)) {
+		rxbd = ((I2C_BD*)state->rxbd) - 1;
+		PRINTD(("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong)rxbd));
+		while((rxbd->status & BD_SC_EMPTY) && (j++ < TOUT_LOOP)) {
+			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 >= TOUT_LOOP)
+			(*state->err_cb)(I2CECB_TIMEOUT, 0);
+	}
+
+	return (j >= TOUT_LOOP) ? I2CERR_TIMEOUT : 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_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	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;
+
+#ifdef CONFIG_LWMON
+	WATCHDOG_RESET();
+#endif
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >>  8) & 0xFF;
+	xaddr[3] =  addr        & 0xFF;
+
+#ifdef CONFIG_SYS_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)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+	i2c_newio(&state);
+
+	rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, &xaddr[4-alen]);
+	if (rc != 0) {
+		if (gd->have_console)
+			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) {
+		if (gd->have_console)
+			printf("i2c_read: i2c_receive failed (%d)\n", rc);
+		return 1;
+	}
+
+	rc = i2c_doio(&state);
+	if (rc != 0) {
+		if (gd->have_console)
+			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 CONFIG_SYS_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)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+	i2c_newio(&state);
+
+	rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, &xaddr[4-alen]);
+	if (rc != 0) {
+		if (gd->have_console)
+			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) {
+		if (gd->have_console)
+			printf("i2c_write: second i2c_send failed (%d)\n", rc);
+		return 1;
+	}
+
+	rc = i2c_doio(&state);
+	if (rc != 0) {
+		if (gd->have_console)
+			printf("i2c_write: i2c_doio failed (%d)\n", rc);
+		return 1;
+	}
+	return 0;
+}
+
+#endif	/* CONFIG_HARD_I2C */
diff --git a/arch/ppc/cpu/mpc8xx/interrupts.c b/arch/ppc/cpu/mpc8xx/interrupts.c
new file mode 100644
index 0000000..5daa6b2
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/interrupts.c
@@ -0,0 +1,294 @@
+/*
+ * (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 <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <asm/processor.h>
+#include <commproc.h>
+
+/************************************************************************/
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct interrupt_action {
+	interrupt_handler_t *handler;
+	void *arg;
+};
+
+static struct interrupt_action cpm_vecs[CPMVEC_NR];
+static struct interrupt_action irq_vecs[NR_IRQS];
+
+static void cpm_interrupt_init (void);
+static void cpm_interrupt (void *regs);
+
+/************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+	/* disable all interrupts */
+	immr->im_siu_conf.sc_simask = 0;
+
+	/* Configure CPM interrupts */
+	cpm_interrupt_init ();
+
+	return (0);
+}
+
+/************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int irq;
+	ulong simask, newmask;
+	ulong vec, v_bit;
+
+	/*
+	 * read the SIVEC register and shift the bits down
+	 * to get the irq number
+	 */
+	vec = immr->im_siu_conf.sc_sivec;
+	irq = vec >> 26;
+	v_bit = 0x80000000UL >> irq;
+
+	/*
+	 * Read Interrupt Mask Register and Mask Interrupts
+	 */
+	simask = immr->im_siu_conf.sc_simask;
+	newmask = simask & (~(0xFFFF0000 >> irq));
+	immr->im_siu_conf.sc_simask = newmask;
+
+	if (!(irq & 0x1)) {		/* External Interrupt ?     */
+		ulong siel;
+
+		/*
+		 * Read Interrupt Edge/Level Register
+		 */
+		siel = immr->im_siu_conf.sc_siel;
+
+		if (siel & v_bit) {	/* edge triggered interrupt ?   */
+			/*
+			 * Rewrite SIPEND Register to clear interrupt
+			 */
+			immr->im_siu_conf.sc_sipend = v_bit;
+		}
+	}
+
+	if (irq_vecs[irq].handler != NULL) {
+		irq_vecs[irq].handler (irq_vecs[irq].arg);
+	} else {
+		printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+				irq, vec);
+		/* turn off the bogus interrupt to avoid it from now */
+		simask &= ~v_bit;
+	}
+	/*
+	 * Re-Enable old Interrupt Mask
+	 */
+	immr->im_siu_conf.sc_simask = simask;
+}
+
+/************************************************************************/
+
+/*
+ * CPM interrupt handler
+ */
+static void cpm_interrupt (void *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	uint vec;
+
+	/*
+	 * Get the vector by setting the ACK bit
+	 * and then reading the register.
+	 */
+	immr->im_cpic.cpic_civr = 1;
+	vec = immr->im_cpic.cpic_civr;
+	vec >>= 11;
+
+	if (cpm_vecs[vec].handler != NULL) {
+		(*cpm_vecs[vec].handler) (cpm_vecs[vec].arg);
+	} else {
+		immr->im_cpic.cpic_cimr &= ~(1 << vec);
+		printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
+	}
+	/*
+	 * After servicing the interrupt,
+	 * we have to remove the status indicator.
+	 */
+	immr->im_cpic.cpic_cisr |= (1 << vec);
+}
+
+/*
+ * The CPM can generate the error interrupt when there is a race
+ * condition between generating and masking interrupts. All we have
+ * to do is ACK it and return. This is a no-op function so we don't
+ * need any special tests in the interrupt handler.
+ */
+static void cpm_error_interrupt (void *dummy)
+{
+}
+
+/************************************************************************/
+/*
+ * Install and free an interrupt handler
+ */
+void irq_install_handler (int vec, interrupt_handler_t * handler,
+						  void *arg)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	if ((vec & CPMVEC_OFFSET) != 0) {
+		/* CPM interrupt */
+		vec &= 0xffff;
+		if (cpm_vecs[vec].handler != NULL) {
+			printf ("CPM interrupt 0x%x replacing 0x%x\n",
+				(uint) handler,
+				(uint) cpm_vecs[vec].handler);
+		}
+		cpm_vecs[vec].handler = handler;
+		cpm_vecs[vec].arg = arg;
+		immr->im_cpic.cpic_cimr |= (1 << vec);
+#if 0
+		printf ("Install CPM interrupt for vector %d ==> %p\n",
+			vec, handler);
+#endif
+	} else {
+		/* SIU interrupt */
+		if (irq_vecs[vec].handler != NULL) {
+			printf ("SIU interrupt %d 0x%x replacing 0x%x\n",
+				vec,
+				(uint) handler,
+				(uint) cpm_vecs[vec].handler);
+		}
+		irq_vecs[vec].handler = handler;
+		irq_vecs[vec].arg = arg;
+		immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
+#if 0
+		printf ("Install SIU interrupt for vector %d ==> %p\n",
+			vec, handler);
+#endif
+	}
+}
+
+void irq_free_handler (int vec)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	if ((vec & CPMVEC_OFFSET) != 0) {
+		/* CPM interrupt */
+		vec &= 0xffff;
+#if 0
+		printf ("Free CPM interrupt for vector %d ==> %p\n",
+			vec, cpm_vecs[vec].handler);
+#endif
+		immr->im_cpic.cpic_cimr &= ~(1 << vec);
+		cpm_vecs[vec].handler = NULL;
+		cpm_vecs[vec].arg = NULL;
+	} else {
+		/* SIU interrupt */
+#if 0
+		printf ("Free CPM interrupt for vector %d ==> %p\n",
+			vec, cpm_vecs[vec].handler);
+#endif
+		immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
+		irq_vecs[vec].handler = NULL;
+		irq_vecs[vec].arg = NULL;
+	}
+}
+
+/************************************************************************/
+
+static void cpm_interrupt_init (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	/*
+	 * Initialize the CPM interrupt controller.
+	 */
+
+	immr->im_cpic.cpic_cicr =
+		(CICR_SCD_SCC4 |
+		 CICR_SCC_SCC3 |
+		 CICR_SCB_SCC2 |
+		 CICR_SCA_SCC1) | ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK;
+
+	immr->im_cpic.cpic_cimr = 0;
+
+	/*
+	 * Install the error handler.
+	 */
+	irq_install_handler (CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+	immr->im_cpic.cpic_cicr |= CICR_IEN;
+
+	/*
+	 * Install the cpm interrupt handler
+	 */
+	irq_install_handler (CPM_INTERRUPT, cpm_interrupt, NULL);
+}
+
+/************************************************************************/
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if 0
+	printf ("*** Timer Interrupt *** ");
+#endif
+	/* Reset Timer Expired and Timers Interrupt Status */
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+	__asm__ ("nop");
+	/*
+	  Clear TEXPS (and TMIST on older chips). SPLSS (on older
+	  chips) is cleared too.
+
+	  Bitwise OR is a read-modify-write operation so ALL bits
+	  which are cleared by writing `1' would be cleared by
+	  operations like
+
+	  immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
+
+	  The same can be achieved by simple writing of the PLPRCR
+	  to itself. If a bit value should be preserved, read the
+	  register, ZERO the bit and write, not OR, the result back.
+	*/
+	immr->im_clkrst.car_plprcr = immr->im_clkrst.car_plprcr;
+}
+
+/************************************************************************/
diff --git a/arch/ppc/cpu/mpc8xx/kgdb.S b/arch/ppc/cpu/mpc8xx/kgdb.S
new file mode 100644
index 0000000..2cc8fe6
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/kgdb.S
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (C) 2000	Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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 <command.h>
+#include <mpc8xx.h>
+#include <version.h>
+
+#define CONFIG_8xx 1		/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+
+ /*
+ * cache flushing routines for kgdb
+ */
+
+	.globl	kgdb_flush_cache_all
+kgdb_flush_cache_all:
+	lis	r3, IDC_INVALL@h
+	mtspr	DC_CST, r3
+	sync
+	lis	r3, IDC_INVALL@h
+	mtspr	IC_CST, r3
+	SYNC
+	blr
+
+	.globl	kgdb_flush_cache_range
+kgdb_flush_cache_range:
+	li	r5,CONFIG_SYS_CACHELINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,CONFIG_SYS_CACHELINE_SHIFT
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,CONFIG_SYS_CACHELINE_SIZE
+	bdnz	2b
+	SYNC
+	blr
+
+#endif
diff --git a/arch/ppc/cpu/mpc8xx/lcd.c b/arch/ppc/cpu/mpc8xx/lcd.c
new file mode 100644
index 0000000..4b88b21
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/lcd.c
@@ -0,0 +1,621 @@
+/*
+ * (C) Copyright 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
+ */
+
+/************************************************************************/
+/* ** HEADER FILES							*/
+/************************************************************************/
+
+/* #define DEBUG */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <watchdog.h>
+#include <version.h>
+#include <stdarg.h>
+#include <lcdvideo.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+#if defined(CONFIG_POST)
+#include <post.h>
+#endif
+#include <lcd.h>
+
+#ifdef CONFIG_LCD
+
+/************************************************************************/
+/* ** CONFIG STUFF -- should be moved to board config file		*/
+/************************************************************************/
+#ifndef CONFIG_LCD_INFO
+#define CONFIG_LCD_INFO		/* Display Logo, (C) and system info	*/
+#endif
+
+#if defined(CONFIG_V37) || defined(CONFIG_EDT32F10)
+#undef CONFIG_LCD_LOGO
+#undef CONFIG_LCD_INFO
+#endif
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_KYOCERA_KCS057QV1AJ
+/*
+ *  Kyocera KCS057QV1AJ-G23. Passive, color, single scan.
+ */
+#define LCD_BPP	LCD_COLOR4
+
+vidinfo_t panel_info = {
+    640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+    LCD_BPP, 1, 0, 1, 0,  5, 0, 0, 0
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_KYOCERA_KCS057QV1AJ */
+/*----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_HITACHI_SP19X001_Z1A
+/*
+ *  Hitachi SP19X001-. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 154, 116, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+    LCD_COLOR8, 1, 0, 1, 0, 0, 0, 0, 0
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_HITACHI_SP19X001_Z1A */
+/*----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_NEC_NL6448AC33
+/*
+ *  NEC NL6448AC33-18. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 144, 2, 0, 33
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_NEC_NL6448AC33 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_NEC_NL6448BC20
+/*
+ *  NEC NL6448BC20-08.  6.5", 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 144, 2, 0, 33
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_NEC_NL6448BC20 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_NEC_NL6448BC33_54
+/*
+ *  NEC NL6448BC33-54. 10.4", 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 212, 158, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 144, 2, 0, 33
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_NEC_NL6448BC33_54 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_LQ104V7DS01
+/*
+ *  SHARP LQ104V7DS01. 6.5", 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_LOW,
+    3, 0, 0, 1, 1, 25, 1, 0, 33
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_SHARP_LQ104V7DS01 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_16x9
+/*
+ * Sharp 320x240. Active, color, single scan.  It isn't 16x9, and I am
+ * not sure what it is.......
+ */
+vidinfo_t panel_info = {
+    320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 15, 4, 0, 3
+};
+#endif /* CONFIG_SHARP_16x9 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_LQ057Q3DC02
+/*
+ * Sharp LQ057Q3DC02 display. Active, color, single scan.
+ */
+#undef LCD_DF
+#define LCD_DF 12
+
+vidinfo_t panel_info = {
+    320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 15, 4, 0, 3
+		/* wbl, vpw, lcdac, wbf */
+};
+#define CONFIG_LCD_INFO_BELOW_LOGO
+#endif /* CONFIG_SHARP_LQ057Q3DC02 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_LQ64D341
+/*
+ * Sharp LQ64D341 display, 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 128, 16, 0, 32
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_SHARP_LQ64D341 */
+
+#ifdef CONFIG_SHARP_LQ065T9DR51U
+/*
+ * Sharp LQ065T9DR51U display, 400x240. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    400, 240, 143, 79, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 248, 4, 0, 35
+		/* wbl, vpw, lcdac, wbf */
+};
+#define CONFIG_LCD_INFO_BELOW_LOGO
+#endif /* CONFIG_SHARP_LQ065T9DR51U */
+
+#ifdef CONFIG_SHARP_LQ084V1DG21
+/*
+ * Sharp LQ084V1DG21 display, 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 171, 129, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_LOW,
+    3, 0, 0, 1, 1, 160, 3, 0, 48
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_SHARP_LQ084V1DG21 */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_HLD1045
+/*
+ * HLD1045 display, 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+    640, 480, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 160, 3, 0, 48
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_HLD1045 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_PRIMEVIEW_V16C6448AC
+/*
+ * Prime View V16C6448AC
+ */
+vidinfo_t panel_info = {
+    640, 480, 130, 98, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+    3, 0, 0, 1, 1, 144, 2, 0, 35
+		/* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_PRIMEVIEW_V16C6448AC */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_OPTREX_BW
+/*
+ * Optrex   CBL50840-2 NF-FW 99 22 M5
+ * or
+ * Hitachi  LMG6912RPFC-00T
+ * or
+ * Hitachi  SP14Q002
+ *
+ * 320x240. Black & white.
+ */
+#define OPTREX_BPP	0	/* 0 - monochrome,     1 bpp */
+				/* 1 -  4 grey levels, 2 bpp */
+				/* 2 - 16 grey levels, 4 bpp */
+vidinfo_t panel_info = {
+    320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW,
+    OPTREX_BPP, 0, 0, 0, 0, 0, 0, 0, 0, 4
+};
+#endif /* CONFIG_OPTREX_BW */
+
+/*-----------------------------------------------------------------*/
+#ifdef CONFIG_EDT32F10
+/*
+ * Emerging Display Technologies 320x240. Passive, monochrome, single scan.
+ */
+#define LCD_BPP		LCD_MONOCHROME
+#define LCD_DF		10
+
+vidinfo_t panel_info = {
+    320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW,
+    LCD_BPP,  0, 0, 0, 0, 33, 0, 0, 0
+};
+#endif
+/*----------------------------------------------------------------------*/
+
+
+int lcd_line_length;
+
+int lcd_color_fg;
+int lcd_color_bg;
+
+/*
+ * Frame buffer memory information
+ */
+void *lcd_base;			/* Start of framebuffer memory	*/
+void *lcd_console_address;	/* Start of console buffer	*/
+
+short console_col;
+short console_row;
+
+/************************************************************************/
+
+void lcd_ctrl_init (void *lcdbase);
+void lcd_enable (void);
+#if LCD_BPP == LCD_COLOR8
+void lcd_setcolreg (ushort regno,
+				ushort red, ushort green, ushort blue);
+#endif
+#if LCD_BPP == LCD_MONOCHROME
+void lcd_initcolregs (void);
+#endif
+
+#if defined(CONFIG_RBC823)
+void lcd_disable (void);
+#endif
+
+/************************************************************************/
+
+/************************************************************************/
+/* ----------------- chipset specific functions ----------------------- */
+/************************************************************************/
+
+/*
+ * Calculate fb size for VIDEOLFB_ATAG.
+ */
+ulong calc_fbsize (void)
+{
+	ulong size;
+	int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+
+	size = line_length * panel_info.vl_row;
+
+	return size;
+}
+
+void lcd_ctrl_init (void *lcdbase)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile lcd823_t *lcdp = &immr->im_lcd;
+
+	uint lccrtmp;
+	uint lchcr_hpc_tmp;
+
+	/* Initialize the LCD control register according to the LCD
+	 * parameters defined.  We do everything here but enable
+	 * the controller.
+	 */
+
+#ifdef CONFIG_RPXLITE
+	/* This is special for RPXlite_DW Software Development Platform **[Sam]** */
+	panel_info.vl_dp = CONFIG_SYS_LOW;
+#endif
+
+	lccrtmp  = LCDBIT (LCCR_BNUM_BIT,
+		   (((panel_info.vl_row * panel_info.vl_col) * (1 << LCD_BPP)) / 128));
+
+	lccrtmp |= LCDBIT (LCCR_CLKP_BIT, panel_info.vl_clkp)	|
+		   LCDBIT (LCCR_OEP_BIT,  panel_info.vl_oep)	|
+		   LCDBIT (LCCR_HSP_BIT,  panel_info.vl_hsp)	|
+		   LCDBIT (LCCR_VSP_BIT,  panel_info.vl_vsp)	|
+		   LCDBIT (LCCR_DP_BIT,   panel_info.vl_dp)	|
+		   LCDBIT (LCCR_BPIX_BIT, panel_info.vl_bpix)	|
+		   LCDBIT (LCCR_LBW_BIT,  panel_info.vl_lbw)	|
+		   LCDBIT (LCCR_SPLT_BIT, panel_info.vl_splt)	|
+		   LCDBIT (LCCR_CLOR_BIT, panel_info.vl_clor)	|
+		   LCDBIT (LCCR_TFT_BIT,  panel_info.vl_tft);
+
+#if 0
+	lccrtmp |= ((SIU_LEVEL5 / 2) << 12);
+	lccrtmp |= LCCR_EIEN;
+#endif
+
+	lcdp->lcd_lccr = lccrtmp;
+	lcdp->lcd_lcsr = 0xFF;		/* Clear pending interrupts */
+
+	/* Initialize LCD controller bus priorities.
+	 */
+#ifdef CONFIG_RBC823
+	immr->im_siu_conf.sc_sdcr = (immr->im_siu_conf.sc_sdcr & ~0x0f) | 1;	/* RAID = 01, LAID = 00 */
+#else
+	immr->im_siu_conf.sc_sdcr &= ~0x0f;	/* RAID = LAID = 0 */
+
+	/* set SHFT/CLOCK division factor 4
+	 * This needs to be set based upon display type and processor
+	 * speed.  The TFT displays run about 20 to 30 MHz.
+	 * I was running 64 MHz processor speed.
+	 * The value for this divider must be chosen so the result is
+	 * an integer of the processor speed (i.e., divide by 3 with
+	 * 64 MHz would be bad).
+	 */
+	immr->im_clkrst.car_sccr &= ~0x1F;
+	immr->im_clkrst.car_sccr |= LCD_DF;	/* was 8 */
+
+#endif /* CONFIG_RBC823 */
+
+#if defined(CONFIG_RBC823)
+	/* Enable LCD on port D.
+	 */
+	immr->im_ioport.iop_pddat &= 0x0300;
+	immr->im_ioport.iop_pdpar |= 0x1CFF;
+	immr->im_ioport.iop_pddir |= 0x1CFF;
+
+	/* Configure LCD_ON, VEE_ON, CCFL_ON on port B.
+	 */
+	immr->im_cpm.cp_pbdat &= ~0x00005001;
+	immr->im_cpm.cp_pbpar &= ~0x00005001;
+	immr->im_cpm.cp_pbdir |=  0x00005001;
+#elif !defined(CONFIG_EDT32F10)
+	/* Enable LCD on port D.
+	 */
+	immr->im_ioport.iop_pdpar |= 0x1FFF;
+	immr->im_ioport.iop_pddir |= 0x1FFF;
+
+	/* Enable LCD_A/B/C on port B.
+	 */
+	immr->im_cpm.cp_pbpar |= 0x00005001;
+	immr->im_cpm.cp_pbdir |= 0x00005001;
+#else
+	/* Enable LCD on port D.
+	 */
+	immr->im_ioport.iop_pdpar |= 0x1DFF;
+	immr->im_ioport.iop_pdpar &= ~0x0200;
+	immr->im_ioport.iop_pddir |= 0x1FFF;
+	immr->im_ioport.iop_pddat |= 0x0200;
+#endif
+
+	/* Load the physical address of the linear frame buffer
+	 * into the LCD controller.
+	 * BIG NOTE:  This has to be modified to load A and B depending
+	 * upon the split mode of the LCD.
+	 */
+	lcdp->lcd_lcfaa = (ulong)lcd_base;
+	lcdp->lcd_lcfba = (ulong)lcd_base;
+
+	/* MORE HACKS...This must be updated according to 823 manual
+	 * for different panels.
+	 * Udi Finkelstein - done - see below:
+	 * Note: You better not try unsupported combinations such as
+	 * 4-bit wide passive dual scan LCD at 4/8 Bit color.
+	 */
+	lchcr_hpc_tmp =
+		(panel_info.vl_col *
+		 (panel_info.vl_tft ? 8 :
+			(((2 - panel_info.vl_lbw) << /* 4 bit=2, 8-bit = 1 */
+			 /* use << to mult by: single scan = 1, dual scan = 2 */
+			  panel_info.vl_splt) *
+			 (panel_info.vl_bpix | 1)))) >> 3; /* 2/4 BPP = 1, 8/16 BPP = 3 */
+
+	lcdp->lcd_lchcr = LCHCR_BO |
+			  LCDBIT (LCHCR_AT_BIT, 4) |
+			  LCDBIT (LCHCR_HPC_BIT, lchcr_hpc_tmp) |
+			  panel_info.vl_wbl;
+
+	lcdp->lcd_lcvcr = LCDBIT (LCVCR_VPW_BIT, panel_info.vl_vpw) |
+			  LCDBIT (LCVCR_LCD_AC_BIT, panel_info.vl_lcdac) |
+			  LCDBIT (LCVCR_VPC_BIT, panel_info.vl_row) |
+			  panel_info.vl_wbf;
+
+}
+
+/*----------------------------------------------------------------------*/
+
+#ifdef	NOT_USED_SO_FAR
+static void
+lcd_getcolreg (ushort regno, ushort *red, ushort *green, ushort *blue)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(immr->im_cpm);
+	unsigned short colreg, *cmap_ptr;
+
+	cmap_ptr = (unsigned short *)&cp->lcd_cmap[regno * 2];
+
+	colreg = *cmap_ptr;
+#ifdef	CONFIG_SYS_INVERT_COLORS
+	colreg ^= 0x0FFF;
+#endif
+
+	*red   = (colreg >> 8) & 0x0F;
+	*green = (colreg >> 4) & 0x0F;
+	*blue  =  colreg       & 0x0F;
+}
+#endif	/* NOT_USED_SO_FAR */
+
+/*----------------------------------------------------------------------*/
+
+#if LCD_BPP == LCD_COLOR8
+void
+lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(immr->im_cpm);
+	unsigned short colreg, *cmap_ptr;
+
+	cmap_ptr = (unsigned short *)&cp->lcd_cmap[regno * 2];
+
+	colreg = ((red   & 0x0F) << 8) |
+		 ((green & 0x0F) << 4) |
+		  (blue  & 0x0F) ;
+#ifdef	CONFIG_SYS_INVERT_COLORS
+	colreg ^= 0x0FFF;
+#endif
+	*cmap_ptr = colreg;
+
+	debug ("setcolreg: reg %2d @ %p: R=%02X G=%02X B=%02X => %02X%02X\n",
+		regno, &(cp->lcd_cmap[regno * 2]),
+		red, green, blue,
+		cp->lcd_cmap[ regno * 2 ], cp->lcd_cmap[(regno * 2) + 1]);
+}
+#endif	/* LCD_COLOR8 */
+
+/*----------------------------------------------------------------------*/
+
+#if LCD_BPP == LCD_MONOCHROME
+static
+void lcd_initcolregs (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(immr->im_cpm);
+	ushort regno;
+
+	for (regno = 0; regno < 16; regno++) {
+		cp->lcd_cmap[regno * 2] = 0;
+		cp->lcd_cmap[(regno * 2) + 1] = regno & 0x0f;
+	}
+}
+#endif
+
+/*----------------------------------------------------------------------*/
+
+void lcd_enable (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile lcd823_t *lcdp = &immr->im_lcd;
+
+	/* Enable the LCD panel */
+#ifndef CONFIG_RBC823
+	immr->im_siu_conf.sc_sdcr |= (1 << (31 - 25));		/* LAM = 1 */
+#endif
+	lcdp->lcd_lccr |= LCCR_PON;
+
+#ifdef CONFIG_V37
+	/* Turn on display backlight */
+	immr->im_cpm.cp_pbpar |= 0x00008000;
+	immr->im_cpm.cp_pbdir |= 0x00008000;
+#elif defined(CONFIG_RBC823)
+	/* Turn on display backlight */
+	immr->im_cpm.cp_pbdat |= 0x00004000;
+#endif
+
+#if defined(CONFIG_LWMON)
+    {	uchar c = pic_read (0x60);
+#if defined(CONFIG_LCD) && defined(CONFIG_LWMON) && (CONFIG_POST & CONFIG_SYS_POST_SYSMON)
+	/* Enable LCD later in sysmon test, only if temperature is OK */
+#else
+	c |= 0x07;	/* Power on CCFL, Enable CCFL, Chip Enable LCD */
+#endif
+	pic_write (0x60, c);
+    }
+#endif /* CONFIG_LWMON */
+
+#if defined(CONFIG_R360MPI)
+    {
+	extern void r360_i2c_lcd_write (uchar data0, uchar data1);
+	unsigned long bgi, ctr;
+	char *p;
+
+	if ((p = getenv("lcdbgi")) != NULL) {
+		bgi = simple_strtoul (p, 0, 10) & 0xFFF;
+	} else {
+		bgi = 0xFFF;
+	}
+
+	if ((p = getenv("lcdctr")) != NULL) {
+		ctr = simple_strtoul (p, 0, 10) & 0xFFF;
+	} else {
+		ctr=0x7FF;
+	}
+
+	r360_i2c_lcd_write(0x10, 0x01);
+	r360_i2c_lcd_write(0x20, 0x01);
+	r360_i2c_lcd_write(0x30 | ((bgi>>8) & 0xF), bgi & 0xFF);
+	r360_i2c_lcd_write(0x40 | ((ctr>>8) & 0xF), ctr & 0xFF);
+    }
+#endif /* CONFIG_R360MPI */
+#ifdef CONFIG_RBC823
+	udelay(200000); /* wait 200ms */
+	/* Turn VEE_ON first */
+	immr->im_cpm.cp_pbdat |= 0x00000001;
+	udelay(200000); /* wait 200ms */
+	/* Now turn on LCD_ON */
+	immr->im_cpm.cp_pbdat |= 0x00001000;
+#endif
+#ifdef CONFIG_RRVISION
+	debug ("PC4->Output(1): enable LVDS\n");
+	debug ("PC5->Output(0): disable PAL clock\n");
+	immr->im_ioport.iop_pddir |=  0x1000;
+	immr->im_ioport.iop_pcpar &= ~(0x0C00);
+	immr->im_ioport.iop_pcdir |=   0x0C00 ;
+	immr->im_ioport.iop_pcdat |=   0x0800 ;
+	immr->im_ioport.iop_pcdat &= ~(0x0400);
+	debug ("PDPAR=0x%04X PDDIR=0x%04X PDDAT=0x%04X\n",
+	       immr->im_ioport.iop_pdpar,
+	       immr->im_ioport.iop_pddir,
+	       immr->im_ioport.iop_pddat);
+	debug ("PCPAR=0x%04X PCDIR=0x%04X PCDAT=0x%04X\n",
+	       immr->im_ioport.iop_pcpar,
+	       immr->im_ioport.iop_pcdir,
+	       immr->im_ioport.iop_pcdat);
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+
+#if defined (CONFIG_RBC823)
+void lcd_disable (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile lcd823_t *lcdp = &immr->im_lcd;
+
+#if defined(CONFIG_LWMON)
+    {	uchar c = pic_read (0x60);
+	c &= ~0x07;	/* Power off CCFL, Disable CCFL, Chip Disable LCD */
+	pic_write (0x60, c);
+    }
+#elif defined(CONFIG_R360MPI)
+    {
+	extern void r360_i2c_lcd_write (uchar data0, uchar data1);
+
+	r360_i2c_lcd_write(0x10, 0x00);
+	r360_i2c_lcd_write(0x20, 0x00);
+	r360_i2c_lcd_write(0x30, 0x00);
+	r360_i2c_lcd_write(0x40, 0x00);
+    }
+#endif /* CONFIG_LWMON */
+	/* Disable the LCD panel */
+	lcdp->lcd_lccr &= ~LCCR_PON;
+#ifdef CONFIG_RBC823
+	/* Turn off display backlight, VEE and LCD_ON */
+	immr->im_cpm.cp_pbdat &= ~0x00005001;
+#else
+	immr->im_siu_conf.sc_sdcr &= ~(1 << (31 - 25));	/* LAM = 0 */
+#endif /* CONFIG_RBC823 */
+}
+#endif	/* NOT_USED_SO_FAR || CONFIG_RBC823 */
+
+
+/************************************************************************/
+
+#endif /* CONFIG_LCD */
diff --git a/arch/ppc/cpu/mpc8xx/plprcr_write.S b/arch/ppc/cpu/mpc8xx/plprcr_write.S
new file mode 100644
index 0000000..e325671
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/plprcr_write.S
@@ -0,0 +1,135 @@
+/*
+ * (C) Copyright 2004
+ * 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 <mpc8xx.h>
+#include <ppc_asm.tmpl>
+#include <asm/cache.h>
+
+#define CACHE_CMD_ENABLE	0x02000000
+#define CACHE_CMD_DISABLE	0x04000000
+#define CACHE_CMD_LOAD_LOCK	0x06000000
+#define CACHE_CMD_UNLOCK_LINE	0x08000000
+#define CACHE_CMD_UNLOCK_ALL	0x0A000000
+#define CACHE_CMD_INVALIDATE	0x0C000000
+#define SPEED_PLPRCR_WAIT_5CYC	150
+#define _CACHE_ALIGN_SIZE	16
+
+
+	.text
+	.align 2
+	.globl plprcr_write_866
+
+/*
+ * void plprcr_write_866 (long plprcr)
+ * Write PLPRCR, including workaround for device errata SIU4 and SIU9.
+ */
+
+plprcr_write_866:
+	mfspr	r10, LR		/* save the Link Register value */
+
+	/* turn instruction cache on (no MMU required for instructions)
+	 */
+	lis	r4, CACHE_CMD_ENABLE@h
+	ori	r4, r4, CACHE_CMD_ENABLE@l
+	mtspr	IC_CST, r4
+	isync
+
+	/* clear IC_CST error bits
+	 */
+	mfspr	r4, IC_CST
+
+	bl	plprcr_here
+
+plprcr_here:
+	mflr	r5
+
+	/* calculate relocation offset
+	 */
+	lis	r4, plprcr_here@h
+	ori	r4, r4, plprcr_here@l
+	sub	r5, r5, r4
+
+	/* calculate first address of this function
+	 */
+	lis	r6, plprcr_write_866@h
+	ori	r6, r6, plprcr_write_866@l
+	add	r6, r6, r5
+
+	/* calculate end address of this function
+	 */
+	lis	r7, plprcr_end@h
+	ori	r7, r7, plprcr_end@l
+	add	r7, r7, r5
+
+	/* load and lock code addresses
+	 */
+	mr	r5, r6
+
+plprcr_loop:
+	mtspr	IC_ADR, r5
+	addi	r5, r5, _CACHE_ALIGN_SIZE	/* increment by one line */
+
+	lis	r4, CACHE_CMD_LOAD_LOCK@h
+	ori	r4, r4, CACHE_CMD_LOAD_LOCK@l
+	mtspr	IC_CST, r4
+	isync
+
+	cmpw	r5, r7
+	blt	plprcr_loop
+
+	/* IC_CST error bits not evaluated
+	 */
+
+	/* switch PLPRCR
+	 */
+	mfspr	r4, IMMR		/* read IMMR */
+	rlwinm	r4, r4, 0, 0, 15	/* only high 16 bits count */
+
+	/* write sequence according to MPC866 Errata
+	 */
+	stw	r3, PLPRCR(r4)
+	isync
+
+	lis	r3, SPEED_PLPRCR_WAIT_5CYC@h
+	ori	r3, r3, SPEED_PLPRCR_WAIT_5CYC@l
+
+plprcr_wait:
+	cmpwi	r3, 0
+	beq	plprcr_wait_end
+	nop
+	subi	r3, r3, 1
+	b	plprcr_wait
+
+plprcr_wait_end:
+
+	/* unlock instruction cache but leave it enabled
+	 */
+	lis	r4, CACHE_CMD_UNLOCK_ALL@h
+	ori	r4, r4, CACHE_CMD_UNLOCK_ALL@l
+	mtspr	IC_CST, r4
+	isync
+
+	mtspr	LR, r10		/* restore original Link Register value */
+	blr
+
+plprcr_end:
diff --git a/arch/ppc/cpu/mpc8xx/scc.c b/arch/ppc/cpu/mpc8xx/scc.c
new file mode 100644
index 0000000..effb967
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/scc.c
@@ -0,0 +1,572 @@
+/*
+ * File:  scc.c
+ * Description:
+ *	Basic ET HW initialization and packet RX/TX routines
+ *
+ * NOTE  <<<IMPORTANT:  PLEASE READ>>>:
+ *     Do not cache Rx/Tx buffers!
+ */
+
+/*
+ * MPC823 <-> MC68160 Connections:
+ *
+ * Setup MPC823 to work with MC68160 Enhanced Ethernet
+ * Serial Tranceiver as follows:
+ *
+ * MPC823 Signal                MC68160  Comments
+ * ------ ------                -------  --------
+ * PA-12 ETHTX    -------->   TX       Eth. Port Transmit Data
+ * PB-18 E_TENA   -------->   TENA     Eth. Transmit Port Enable
+ * PA-5 ETHTCK    <--------   TCLK     Eth. Port Transmit Clock
+ * PA-13 ETHRX    <--------   RX       Eth. Port Receive Data
+ * PC-8 E_RENA    <--------   RENA     Eth. Receive Enable
+ * PA-6 ETHRCK    <--------   RCLK     Eth. Port Receive Clock
+ * PC-9 E_CLSN    <--------   CLSN     Eth. Port Collision Indication
+ *
+ * FADS Board Signal              MC68160  Comments
+ * -----------------              -------  --------
+ * (BCSR1) ETHEN*     -------->  CS2      Eth. Port Enable
+ * (BSCR4) TPSQEL*    -------->  TPSQEL   Twisted Pair Signal Quality Error Test Enable
+ * (BCSR4) TPFLDL*    -------->  TPFLDL   Twisted Pair Full-Duplex
+ * (BCSR4) ETHLOOP    -------->  LOOP     Eth. Port Diagnostic Loop-Back
+ *
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+#if defined(CONFIG_CMD_NET) && defined(SCC_ENET)
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH  1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 10000	/* 10 ms to have a packet sent */
+
+static char txbuf[DBUF_LENGTH];
+
+static uint rxIdx;	/* index of the current RX buffer */
+static uint txIdx;	/* index of the current TX buffer */
+
+/*
+  * SCC 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;
+
+static int scc_send(struct eth_device* dev, volatile void *packet, int length);
+static int scc_recv(struct eth_device* dev);
+static int scc_init (struct eth_device* dev, bd_t * bd);
+static void scc_halt(struct eth_device* dev);
+
+int scc_initialize(bd_t *bis)
+{
+	struct eth_device* dev;
+
+	dev = (struct eth_device*) malloc(sizeof *dev);
+	memset(dev, 0, sizeof *dev);
+
+	sprintf(dev->name, "SCC ETHERNET");
+	dev->iobase = 0;
+	dev->priv   = 0;
+	dev->init   = scc_init;
+	dev->halt   = scc_halt;
+	dev->send   = scc_send;
+	dev->recv   = scc_recv;
+
+	eth_register(dev);
+
+	return 1;
+}
+
+static int scc_send(struct eth_device* dev, volatile void *packet, int length)
+{
+	int i, j=0;
+#if 0
+	volatile char *in, *out;
+#endif
+
+	/* section 16.9.23.3
+	 * Wait for ready
+	 */
+#if 0
+	while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY);
+	out = (char *)(rtx->txbd[txIdx].cbd_bufaddr);
+	in = packet;
+	for(i = 0; i < length; i++) {
+		*out++ = *in++;
+	}
+	rtx->txbd[txIdx].cbd_datlen = length;
+	rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST);
+	while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) j++;
+
+#ifdef ET_DEBUG
+	printf("cycles: %d    status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
+#endif
+	i = (rtx->txbd[txIdx++].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
+
+	/* wrap around buffer index when necessary */
+	if (txIdx >= TX_BUF_CNT) txIdx = 0;
+#endif
+
+	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+		udelay (1);	/* will also trigger Wd if needed */
+		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 |BD_ENET_TX_WRAP);
+	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+		udelay (1);	/* will also trigger Wd if needed */
+		j++;
+	}
+	if (j>=TOUT_LOOP) printf("TX timeout\n");
+#ifdef ET_DEBUG
+	printf("cycles: %d    status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
+#endif
+	i = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
+	return i;
+}
+
+static int scc_recv (struct eth_device *dev)
+{
+	int length;
+
+	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 ("err: %x\n", 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 SCC. */
+		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++;
+		}
+	}
+	return length;
+}
+
+/**************************************************************
+  *
+  * SCC Ethernet Initialization Routine
+  *
+  *************************************************************/
+
+static int scc_init (struct eth_device *dev, bd_t * bis)
+{
+
+	int i;
+	scc_enet_t *pram_ptr;
+
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_LWMON)
+	reset_phy();
+#endif
+
+#ifdef CONFIG_FADS
+#if defined(CONFIG_MPC86xADS) || defined(CONFIG_MPC860T)
+	/* The MPC86xADS/FADS860T don't use the MODEM_EN or DATA_VOICE signals. */
+	*((uint *) BCSR4) &= ~BCSR4_ETHLOOP;
+	*((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL;
+	*((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#else
+	*((uint *) BCSR4) &= ~(BCSR4_ETHLOOP | BCSR4_MODEM_EN);
+	*((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL | BCSR4_DATA_VOICE;
+	*((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#endif
+#endif
+
+	pram_ptr = (scc_enet_t *) & (immr->im_cpm.cp_dparam[PROFF_ENET]);
+
+	rxIdx = 0;
+	txIdx = 0;
+
+	if (!rtx) {
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+		rtx = (RTXBD *) (immr->im_cpm.cp_dpmem +
+				 dpram_alloc_align (sizeof (RTXBD), 8));
+#else
+		rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_SCC_BASE);
+#endif
+	}
+
+#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD))
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	immr->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
+	immr->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
+	immr->im_ioport.iop_paodr &= ~PA_ENET_TXD;
+#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD))
+	/* Configure port B pins for Txd and Rxd.
+	 */
+	immr->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD);
+	immr->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD);
+	immr->im_cpm.cp_pbodr &= ~PB_ENET_TXD;
+#else
+#error Configuration Error: exactly ONE of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined
+#endif
+
+#if defined(PC_ENET_LBK)
+	/* Configure port C pins to disable External Loopback
+	 */
+	immr->im_ioport.iop_pcpar &= ~PC_ENET_LBK;
+	immr->im_ioport.iop_pcdir |= PC_ENET_LBK;
+	immr->im_ioport.iop_pcso &= ~PC_ENET_LBK;
+	immr->im_ioport.iop_pcdat &= ~PC_ENET_LBK;	/* Disable Loopback */
+#endif /* PC_ENET_LBK */
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	immr->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+	immr->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+	immr->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
+
+	/* Configure port A for TCLK and RCLK.
+	 */
+	immr->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
+	immr->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
+
+	/*
+	 * Configure Serial Interface clock routing -- see section 16.7.5.3
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+
+	immr->im_cpm.cp_sicr &= ~SICR_ENET_MASK;
+	immr->im_cpm.cp_sicr |= SICR_ENET_CLKRT;
+
+
+	/*
+	 * Initialize SDCR -- see section 16.9.23.7
+	 * SDMA configuration register
+	 */
+	immr->im_siu_conf.sc_sdcr = 0x01;
+
+
+	/*
+	 * Setup SCC Ethernet Parameter RAM
+	 */
+
+	pram_ptr->sen_genscc.scc_rfcr = 0x18;	/* Normal Operation and Mot byte ordering */
+	pram_ptr->sen_genscc.scc_tfcr = 0x18;	/* Mot byte ordering, Normal access */
+
+	pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH;	/* max. ET package len 1520 */
+
+	pram_ptr->sen_genscc.scc_rbase = (unsigned int) (&rtx->rxbd[0]);	/* Set RXBD tbl start at Dual Port */
+	pram_ptr->sen_genscc.scc_tbase = (unsigned int) (&rtx->txbd[0]);	/* Set TXBD tbl start at Dual Port */
+
+	/*
+	 * 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:
+	 *    Add PADs to Short FRAMES, Wrap, Last, Tx CRC
+	 */
+
+	for (i = 0; i < TX_BUF_CNT; i++) {
+		rtx->txbd[i].cbd_sc =
+			(BD_ENET_TX_PAD | 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;
+
+	/*
+	 * Enter Command:  Initialize Rx Params for SCC
+	 */
+
+	do {			/* Spin until ready to issue command    */
+		__asm__ ("eieio");
+	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+	/* Issue command */
+	immr->im_cpm.cp_cpcr =
+		((CPM_CR_INIT_RX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
+	do {			/* Spin until command processed         */
+		__asm__ ("eieio");
+	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+	/*
+	 * Ethernet Specific Parameter RAM
+	 *     see table 13-16, pg. 660,
+	 *     pg. 681 (example with suggested settings)
+	 */
+
+	pram_ptr->sen_cpres = ~(0x0);	/* Preset CRC */
+	pram_ptr->sen_cmask = 0xdebb20e3;	/* Constant Mask for CRC */
+	pram_ptr->sen_crcec = 0x0;	/* Error Counter CRC (unused) */
+	pram_ptr->sen_alec = 0x0;	/* Alignment Error Counter (unused) */
+	pram_ptr->sen_disfc = 0x0;	/* Discard Frame Counter (unused) */
+	pram_ptr->sen_pads = 0x8888;	/* Short Frame PAD Characters */
+
+	pram_ptr->sen_retlim = 15;	/* Retry Limit Threshold */
+	pram_ptr->sen_maxflr = 1518;	/* MAX Frame Length Register */
+	pram_ptr->sen_minflr = 64;	/* MIN Frame Length Register */
+
+	pram_ptr->sen_maxd1 = DBUF_LENGTH;	/* MAX DMA1 Length Register */
+	pram_ptr->sen_maxd2 = DBUF_LENGTH;	/* MAX DMA2 Length Register */
+
+	pram_ptr->sen_gaddr1 = 0x0;	/* Group Address Filter 1 (unused) */
+	pram_ptr->sen_gaddr2 = 0x0;	/* Group Address Filter 2 (unused) */
+	pram_ptr->sen_gaddr3 = 0x0;	/* Group Address Filter 3 (unused) */
+	pram_ptr->sen_gaddr4 = 0x0;	/* Group Address Filter 4 (unused) */
+
+#define ea eth_get_dev()->enetaddr
+	pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
+	pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
+	pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+
+	pram_ptr->sen_pper = 0x0;	/* Persistence (unused) */
+	pram_ptr->sen_iaddr1 = 0x0;	/* Individual Address Filter 1 (unused) */
+	pram_ptr->sen_iaddr2 = 0x0;	/* Individual Address Filter 2 (unused) */
+	pram_ptr->sen_iaddr3 = 0x0;	/* Individual Address Filter 3 (unused) */
+	pram_ptr->sen_iaddr4 = 0x0;	/* Individual Address Filter 4 (unused) */
+	pram_ptr->sen_taddrh = 0x0;	/* Tmp Address (MSB) (unused) */
+	pram_ptr->sen_taddrm = 0x0;	/* Tmp Address (unused) */
+	pram_ptr->sen_taddrl = 0x0;	/* Tmp Address (LSB) (unused) */
+
+	/*
+	 * Enter Command:  Initialize Tx Params for SCC
+	 */
+
+	do {			/* Spin until ready to issue command    */
+		__asm__ ("eieio");
+	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+	/* Issue command */
+	immr->im_cpm.cp_cpcr =
+		((CPM_CR_INIT_TX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
+	do {			/* Spin until command processed         */
+		__asm__ ("eieio");
+	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+	/*
+	 * Mask all Events in SCCM - we use polling mode
+	 */
+	immr->im_cpm.cp_scc[SCC_ENET].scc_sccm = 0;
+
+	/*
+	 * Clear Events in SCCE -- Clear bits by writing 1's
+	 */
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_scce = ~(0x0);
+
+
+	/*
+	 * Initialize GSMR High 32-Bits
+	 * Settings:  Normal Mode
+	 */
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrh = 0;
+
+	/*
+	 * Initialize GSMR Low 32-Bits, but do not Enable Transmit/Receive
+	 * Settings:
+	 *     TCI = Invert
+	 *     TPL =  48 bits
+	 *     TPP = Repeating 10's
+	 *     MODE = Ethernet
+	 */
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl = (SCC_GSMRL_TCI |
+						   SCC_GSMRL_TPL_48 |
+						   SCC_GSMRL_TPP_10 |
+						   SCC_GSMRL_MODE_ENET);
+
+	/*
+	 * Initialize the DSR -- see section 13.14.4 (pg. 513) v0.4
+	 */
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_dsr = 0xd555;
+
+	/*
+	 * Initialize the PSMR
+	 * Settings:
+	 *  CRC = 32-Bit CCITT
+	 *  NIB = Begin searching for SFD 22 bits after RENA
+	 *  FDE = Full Duplex Enable
+	 *  LPB = Loopback Enable (Needed when FDE is set)
+	 *  BRO = Reject broadcast packets
+	 *  PROMISCOUS = Catch all packets regardless of dest. MAC adress
+	 */
+	immr->im_cpm.cp_scc[SCC_ENET].scc_psmr = SCC_PSMR_ENCRC |
+		SCC_PSMR_NIB22 |
+#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
+		SCC_PSMR_FDE | SCC_PSMR_LPB |
+#endif
+#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
+		SCC_PSMR_BRO |
+#endif
+#if defined(CONFIG_SCC_ENET_PROMISCOUS)
+		SCC_PSMR_PRO |
+#endif
+		0;
+
+	/*
+	 * Configure Ethernet TENA Signal
+	 */
+
+#if (defined(PC_ENET_TENA) && !defined(PB_ENET_TENA))
+	immr->im_ioport.iop_pcpar |= PC_ENET_TENA;
+	immr->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+#elif (defined(PB_ENET_TENA) && !defined(PC_ENET_TENA))
+	immr->im_cpm.cp_pbpar |= PB_ENET_TENA;
+	immr->im_cpm.cp_pbdir |= PB_ENET_TENA;
+#else
+#error Configuration Error: exactly ONE of PB_ENET_TENA, PC_ENET_TENA must be defined
+#endif
+
+#if defined(CONFIG_ADS) && defined(CONFIG_MPC860)
+	/*
+	 * Port C is used to control the PHY,MC68160.
+	 */
+	immr->im_ioport.iop_pcdir |=
+		(PC_ENET_ETHLOOP | PC_ENET_TPFLDL | PC_ENET_TPSQEL);
+
+	immr->im_ioport.iop_pcdat |= PC_ENET_TPFLDL;
+	immr->im_ioport.iop_pcdat &= ~(PC_ENET_ETHLOOP | PC_ENET_TPSQEL);
+	*((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#endif /* MPC860ADS */
+
+#if defined(CONFIG_AMX860)
+	/*
+	 * Port B is used to control the PHY,MC68160.
+	 */
+	immr->im_cpm.cp_pbdir |=
+		(PB_ENET_ETHLOOP | PB_ENET_TPFLDL | PB_ENET_TPSQEL);
+
+	immr->im_cpm.cp_pbdat |= PB_ENET_TPFLDL;
+	immr->im_cpm.cp_pbdat &= ~(PB_ENET_ETHLOOP | PB_ENET_TPSQEL);
+
+	immr->im_ioport.iop_pddir |= PD_ENET_ETH_EN;
+	immr->im_ioport.iop_pddat &= ~PD_ENET_ETH_EN;
+#endif /* AMX860 */
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uchar *) BCSR0) &= ~BCSR0_ETHLPBK;
+	*((uchar *) BCSR0) |= (BCSR0_ETHEN | BCSR0_COLTEST | BCSR0_FULLDPLX);
+#endif
+
+#ifdef CONFIG_RPXLITE
+	*((uchar *) BCSR0) |= BCSR0_ETHEN;
+#endif
+
+#if defined(CONFIG_QS860T)
+	/*
+	 * PB27=FDE-, set output low for full duplex
+	 * PB26=Link Test Enable, normally high output
+	 */
+	immr->im_cpm.cp_pbdir |= 0x00000030;
+	immr->im_cpm.cp_pbdat |= 0x00000020;
+	immr->im_cpm.cp_pbdat &= ~0x00000010;
+#endif /* QS860T */
+
+#ifdef CONFIG_MBX
+	board_ether_init ();
+#endif
+
+#if defined(CONFIG_NETVIA)
+#if defined(PA_ENET_PDN)
+	immr->im_ioport.iop_papar &= ~PA_ENET_PDN;
+	immr->im_ioport.iop_padir |= PA_ENET_PDN;
+	immr->im_ioport.iop_padat |= PA_ENET_PDN;
+#elif defined(PB_ENET_PDN)
+	immr->im_cpm.cp_pbpar &= ~PB_ENET_PDN;
+	immr->im_cpm.cp_pbdir |= PB_ENET_PDN;
+	immr->im_cpm.cp_pbdat |= PB_ENET_PDN;
+#elif defined(PC_ENET_PDN)
+	immr->im_ioport.iop_pcpar &= ~PC_ENET_PDN;
+	immr->im_ioport.iop_pcdir |= PC_ENET_PDN;
+	immr->im_ioport.iop_pcdat |= PC_ENET_PDN;
+#elif defined(PD_ENET_PDN)
+	immr->im_ioport.iop_pdpar &= ~PD_ENET_PDN;
+	immr->im_ioport.iop_pddir |= PD_ENET_PDN;
+	immr->im_ioport.iop_pddat |= PD_ENET_PDN;
+#endif
+#endif
+
+	/*
+	 * Set the ENT/ENR bits in the GSMR Low -- Enable Transmit/Receive
+	 */
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
+		(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/*
+	 * Work around transmit problem with first eth packet
+	 */
+#if defined (CONFIG_FADS)
+	udelay (10000);		/* wait 10 ms */
+#elif defined (CONFIG_AMX860) || defined(CONFIG_RPXCLASSIC)
+	udelay (100000);	/* wait 100 ms */
+#endif
+
+	return 1;
+}
+
+
+static void scc_halt (struct eth_device *dev)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &=
+		~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	immr->im_ioport.iop_pcso  &=  ~(PC_ENET_CLSN | PC_ENET_RENA);
+}
+
+#if 0
+void restart (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
+		(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+#endif
+#endif
diff --git a/arch/ppc/cpu/mpc8xx/serial.c b/arch/ppc/cpu/mpc8xx/serial.c
new file mode 100644
index 0000000..664db65
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/serial.c
@@ -0,0 +1,745 @@
+/*
+ * (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 <commproc.h>
+#include <command.h>
+#include <serial.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CONS_NONE)	/* No Console at all */
+
+#if defined(CONFIG_8xx_CONS_SMC1)	/* Console on SMC1 */
+#define	SMC_INDEX	0
+#define PROFF_SMC	PROFF_SMC1
+#define CPM_CR_CH_SMC	CPM_CR_CH_SMC1
+
+#elif defined(CONFIG_8xx_CONS_SMC2)	/* Console on SMC2 */
+#define SMC_INDEX	1
+#define PROFF_SMC	PROFF_SMC2
+#define CPM_CR_CH_SMC	CPM_CR_CH_SMC2
+
+#endif /* CONFIG_8xx_CONS_SMCx */
+
+#if defined(CONFIG_8xx_CONS_SCC1)	/* Console on SCC1 */
+#define SCC_INDEX	0
+#define PROFF_SCC	PROFF_SCC1
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC1
+
+#elif defined(CONFIG_8xx_CONS_SCC2)	/* Console on SCC2 */
+#define SCC_INDEX	1
+#define PROFF_SCC	PROFF_SCC2
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC2
+
+#elif defined(CONFIG_8xx_CONS_SCC3)	/* Console on SCC3 */
+#define SCC_INDEX	2
+#define PROFF_SCC	PROFF_SCC3
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC3
+
+#elif defined(CONFIG_8xx_CONS_SCC4)	/* Console on SCC4 */
+#define SCC_INDEX	3
+#define PROFF_SCC	PROFF_SCC4
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC4
+
+#endif /* CONFIG_8xx_CONS_SCCx */
+
+#if !defined(CONFIG_SYS_SMC_RXBUFLEN)
+#define CONFIG_SYS_SMC_RXBUFLEN	1
+#define CONFIG_SYS_MAXIDLE	0
+#else
+#if !defined(CONFIG_SYS_MAXIDLE)
+#error "you must define CONFIG_SYS_MAXIDLE"
+#endif
+#endif
+
+typedef volatile struct serialbuffer {
+	cbd_t	rxbd;		/* Rx BD */
+	cbd_t	txbd;		/* Tx BD */
+	uint	rxindex;	/* index for next character to read */
+	volatile uchar	rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
+	volatile uchar	txbuf;	/* tx buffers */
+} serialbuffer_t;
+
+static void serial_setdivisor(volatile cpm8xx_t *cp)
+{
+	int divisor=(gd->cpu_clk + 8*gd->baudrate)/16/gd->baudrate;
+
+	if(divisor/16>0x1000) {
+		/* bad divisor, assume 50MHz clock and 9600 baud */
+		divisor=(50*1000*1000 + 8*9600)/16/9600;
+	}
+
+#ifdef CONFIG_SYS_BRGCLK_PRESCALE
+	divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
+#endif
+
+	if(divisor<=0x1000) {
+		cp->cp_brgc1=((divisor-1)<<1) | CPM_BRG_EN;
+	} else {
+		cp->cp_brgc1=((divisor/16-1)<<1) | CPM_BRG_EN | CPM_BRG_DIV16;
+	}
+}
+
+#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2))
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+static void smc_setbrg (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+
+	/* Set up the baud rate generator.
+	 * See 8xx_io/commproc.c for details.
+	 *
+	 * Wire BRG1 to SMCx
+	 */
+
+	cp->cp_simode = 0x00000000;
+
+	serial_setdivisor(cp);
+}
+
+static int smc_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile smc_t *sp;
+	volatile smc_uart_t *up;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+#if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) || defined(CONFIG_MPC850))
+	volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+	uint	dpaddr;
+	volatile serialbuffer_t *rtx;
+
+	/* initialize pointers to SMC */
+
+	sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]);
+	up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+	up = (smc_uart_t *) &cp->cp_dpmem[up->smc_rpbase];
+#else
+	/* Disable relocation */
+	up->smc_rpbase = 0;
+#endif
+
+	/* Disable transmitter/receiver. */
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+	/* Enable SDMA. */
+	im->im_siu_conf.sc_sdcr = 1;
+
+	/* clear error conditions */
+#ifdef	CONFIG_SYS_SDSR
+	im->im_sdma.sdma_sdsr = CONFIG_SYS_SDSR;
+#else
+	im->im_sdma.sdma_sdsr = 0x83;
+#endif
+
+	/* clear SDMA interrupt mask */
+#ifdef	CONFIG_SYS_SDMR
+	im->im_sdma.sdma_sdmr = CONFIG_SYS_SDMR;
+#else
+	im->im_sdma.sdma_sdmr = 0x00;
+#endif
+
+#if defined(CONFIG_8xx_CONS_SMC1)
+	/* Use Port B for SMC1 instead of other functions. */
+	cp->cp_pbpar |=  0x000000c0;
+	cp->cp_pbdir &= ~0x000000c0;
+	cp->cp_pbodr &= ~0x000000c0;
+#else	/* CONFIG_8xx_CONS_SMC2 */
+# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850)
+	/* Use Port A for SMC2 instead of other functions. */
+	ip->iop_papar |=  0x00c0;
+	ip->iop_padir &= ~0x00c0;
+	ip->iop_paodr &= ~0x00c0;
+# else	/* must be a 860 then */
+	/* Use Port B for SMC2 instead of other functions.
+	 */
+	cp->cp_pbpar |=  0x00000c00;
+	cp->cp_pbdir &= ~0x00000c00;
+	cp->cp_pbodr &= ~0x00000c00;
+# endif
+#endif
+
+#if defined(CONFIG_FADS) || defined(CONFIG_ADS)
+	/* Enable RS232 */
+#if defined(CONFIG_8xx_CONS_SMC1)
+	*((uint *) BCSR1) &= ~BCSR1_RS232EN_1;
+#else
+	*((uint *) BCSR1) &= ~BCSR1_RS232EN_2;
+#endif
+#endif	/* CONFIG_FADS */
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+	/* Enable Monitor Port Transceiver */
+	*((uchar *) BCSR0) |= BCSR0_ENMONXCVR ;
+#endif /* CONFIG_RPXLITE */
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+	/* allocate
+	 * size of struct serialbuffer with bd rx/tx, buffer rx/tx and rx index
+	 */
+	dpaddr = dpram_alloc_align((sizeof(serialbuffer_t)), 8);
+#else
+	dpaddr = CPM_SERIAL_BASE ;
+#endif
+
+	rtx = (serialbuffer_t *)&cp->cp_dpmem[dpaddr];
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * For now, this address seems OK, but it may have to
+	 * change with newer versions of the firmware.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
+	rtx->rxbd.cbd_sc      = 0;
+
+	rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
+	rtx->txbd.cbd_sc      = 0;
+
+	/* Set up the uart parameters in the parameter ram. */
+	up->smc_rbase = dpaddr;
+	up->smc_tbase = dpaddr+sizeof(cbd_t);
+	up->smc_rfcr = SMC_EB;
+	up->smc_tfcr = SMC_EB;
+#if defined (CONFIG_SYS_SMC_UCODE_PATCH)
+	up->smc_rbptr = up->smc_rbase;
+	up->smc_tbptr = up->smc_tbase;
+	up->smc_rstate = 0;
+	up->smc_tstate = 0;
+#endif
+
+#if defined(CONFIG_MBX)
+	board_serial_init();
+#endif	/* CONFIG_MBX */
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->smc_smcm = 0;
+	sp->smc_smce = 0xff;
+
+#ifdef CONFIG_SYS_SPC1920_SMC1_CLK4
+	/* clock source is PLD */
+
+	/* set freq to 19200 Baud */
+	*((volatile uchar *) CONFIG_SYS_SPC1920_PLD_BASE+6) = 0x3;
+	/* configure clk4 as input */
+	im->im_ioport.iop_pdpar |= 0x800;
+	im->im_ioport.iop_pddir &= ~0x800;
+
+	cp->cp_simode = ((cp->cp_simode & ~0xf000) | 0x7000);
+#else
+	/* Set up the baud rate generator */
+	smc_setbrg ();
+#endif
+
+	/* Make the first buffer the only buffer. */
+	rtx->txbd.cbd_sc |= BD_SC_WRAP;
+	rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* single/multi character receive. */
+	up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN;
+	up->smc_maxidl = CONFIG_SYS_MAXIDLE;
+	rtx->rxindex = 0;
+
+	/* Initialize Tx/Rx parameters.	*/
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver.	*/
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+	return (0);
+}
+
+static void
+smc_putc(const char c)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	volatile serialbuffer_t	*rtx;
+
+#ifdef CONFIG_MODEM_SUPPORT
+	if (gd->be_quiet)
+		return;
+#endif
+
+	if (c == '\n')
+		smc_putc ('\r');
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+	up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+
+	rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	/* Wait for last character to go. */
+	rtx->txbuf = c;
+	rtx->txbd.cbd_datlen = 1;
+	rtx->txbd.cbd_sc |= BD_SC_READY;
+	__asm__("eieio");
+
+	while (rtx->txbd.cbd_sc & BD_SC_READY) {
+		WATCHDOG_RESET ();
+		__asm__("eieio");
+	}
+}
+
+static void
+smc_puts (const char *s)
+{
+	while (*s) {
+		smc_putc (*s++);
+	}
+}
+
+static int
+smc_getc(void)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	volatile serialbuffer_t	*rtx;
+	unsigned char  c;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+	up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+	rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	/* Wait for character to show up. */
+	while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
+		WATCHDOG_RESET ();
+
+	/* the characters are read one by one,
+	 * use the rxindex to know the next char to deliver
+	 */
+	c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr+rtx->rxindex);
+	rtx->rxindex++;
+
+	/* check if all char are readout, then make prepare for next receive */
+	if (rtx->rxindex >= rtx->rxbd.cbd_datlen) {
+		rtx->rxindex = 0;
+		rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+	}
+	return(c);
+}
+
+static int
+smc_tstc(void)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	volatile serialbuffer_t	*rtx;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+	up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+
+	rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
+}
+
+struct serial_device serial_smc_device =
+{
+	"serial_smc",
+	"SMC",
+	smc_init,
+	smc_setbrg,
+	smc_getc,
+	smc_tstc,
+	smc_putc,
+	smc_puts,
+};
+
+#endif /* CONFIG_8xx_CONS_SMC1 || CONFIG_8xx_CONS_SMC2 */
+
+#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
+    defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+
+static void
+scc_setbrg (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+
+	/* Set up the baud rate generator.
+	 * See 8xx_io/commproc.c for details.
+	 *
+	 * Wire BRG1 to SCCx
+	 */
+
+	cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX));
+
+	serial_setdivisor(cp);
+}
+
+static int scc_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile scc_t *sp;
+	volatile scc_uart_t *up;
+	volatile cbd_t *tbdf, *rbdf;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+	uint	 dpaddr;
+#if (SCC_INDEX != 2) || !defined(CONFIG_MPC850)
+	volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+
+	/* initialize pointers to SCC */
+
+	sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]);
+	up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC];
+
+#if defined(CONFIG_LWMON) && defined(CONFIG_8xx_CONS_SCC2)
+    {	/* Disable Ethernet, enable Serial */
+	uchar c;
+
+	c = pic_read  (0x61);
+	c &= ~0x40;	/* enable COM3 */
+	c |=  0x80;	/* disable Ethernet */
+	pic_write (0x61, c);
+
+	/* enable RTS2 */
+	cp->cp_pbpar |=  0x2000;
+	cp->cp_pbdat |=  0x2000;
+	cp->cp_pbdir |=  0x2000;
+    }
+#endif	/* CONFIG_LWMON */
+
+	/* Disable transmitter/receiver. */
+	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+#if (SCC_INDEX == 2) && defined(CONFIG_MPC850)
+	/*
+	 * The MPC850 has SCC3 on Port B
+	 */
+	cp->cp_pbpar |=  0x06;
+	cp->cp_pbdir &= ~0x06;
+	cp->cp_pbodr &= ~0x06;
+
+#elif (SCC_INDEX < 2) || !defined(CONFIG_IP860)
+	/*
+	 * Standard configuration for SCC's is on Part A
+	 */
+	ip->iop_papar |=  ((3 << (2 * SCC_INDEX)));
+	ip->iop_padir &= ~((3 << (2 * SCC_INDEX)));
+	ip->iop_paodr &= ~((3 << (2 * SCC_INDEX)));
+#else
+	/*
+	 * The IP860 has SCC3 and SCC4 on Port D
+	 */
+	ip->iop_pdpar |=  ((3 << (2 * SCC_INDEX)));
+#endif
+
+	/* Allocate space for two buffer descriptors in the DP ram. */
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+	dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ;
+#else
+	dpaddr = CPM_SERIAL2_BASE ;
+#endif
+
+	/* Enable SDMA.	*/
+	im->im_siu_conf.sc_sdcr = 0x0001;
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+
+	rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+	rbdf->cbd_bufaddr = (uint) (rbdf+2);
+	rbdf->cbd_sc = 0;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+	tbdf->cbd_sc = 0;
+
+	/* Set up the baud rate generator. */
+	scc_setbrg ();
+
+	/* Set up the uart parameters in the parameter ram. */
+	up->scc_genscc.scc_rbase = dpaddr;
+	up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+
+	/* Initialize Tx/Rx parameters. */
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+		;
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+		;
+
+	up->scc_genscc.scc_rfcr  = SCC_EB | 0x05;
+	up->scc_genscc.scc_tfcr  = SCC_EB | 0x05;
+
+	up->scc_genscc.scc_mrblr = 1;	/* Single character receive */
+	up->scc_maxidl = 0;		/* disable max idle */
+	up->scc_brkcr  = 1;		/* send one break character on stop TX */
+	up->scc_parec  = 0;
+	up->scc_frmec  = 0;
+	up->scc_nosec  = 0;
+	up->scc_brkec  = 0;
+	up->scc_uaddr1 = 0;
+	up->scc_uaddr2 = 0;
+	up->scc_toseq  = 0;
+	up->scc_char1  = 0x8000;
+	up->scc_char2  = 0x8000;
+	up->scc_char3  = 0x8000;
+	up->scc_char4  = 0x8000;
+	up->scc_char5  = 0x8000;
+	up->scc_char6  = 0x8000;
+	up->scc_char7  = 0x8000;
+	up->scc_char8  = 0x8000;
+	up->scc_rccm   = 0xc0ff;
+
+	/* Set low latency / small fifo. */
+	sp->scc_gsmrh = SCC_GSMRH_RFW;
+
+	/* Set SCC(x) clock mode to 16x
+	 * See 8xx_io/commproc.c for details.
+	 *
+	 * Wire BRG1 to SCCn
+	 */
+
+	/* Set UART mode, clock divider 16 on Tx and Rx */
+	sp->scc_gsmrl &= ~0xF;
+	sp->scc_gsmrl |=
+		(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+	sp->scc_psmr  = 0;
+	sp->scc_psmr  |= SCU_PSMR_CL;
+
+	/* Mask all interrupts and remove anything pending. */
+	sp->scc_sccm = 0;
+	sp->scc_scce = 0xffff;
+	sp->scc_dsr  = 0x7e7e;
+	sp->scc_psmr = 0x3000;
+
+	/* Make the first buffer the only buffer. */
+	tbdf->cbd_sc |= BD_SC_WRAP;
+	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* Enable transmitter/receiver.	*/
+	sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	return (0);
+}
+
+static void
+scc_putc(const char c)
+{
+	volatile cbd_t		*tbdf;
+	volatile char		*buf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+
+#ifdef CONFIG_MODEM_SUPPORT
+	if (gd->be_quiet)
+		return;
+#endif
+
+	if (c == '\n')
+		scc_putc ('\r');
+
+	up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+	tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase];
+
+	/* Wait for last character to go. */
+
+	buf = (char *)tbdf->cbd_bufaddr;
+
+	*buf = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+	__asm__("eieio");
+
+	while (tbdf->cbd_sc & BD_SC_READY) {
+		__asm__("eieio");
+		WATCHDOG_RESET ();
+	}
+}
+
+static void
+scc_puts (const char *s)
+{
+	while (*s) {
+		scc_putc (*s++);
+	}
+}
+
+static int
+scc_getc(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile unsigned char	*buf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	unsigned char		c;
+
+	up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+	rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+	/* Wait for character to show up. */
+	buf = (unsigned char *)rbdf->cbd_bufaddr;
+
+	while (rbdf->cbd_sc & BD_SC_EMPTY)
+		WATCHDOG_RESET ();
+
+	c = *buf;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return(c);
+}
+
+static int
+scc_tstc(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+
+	up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+	rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+struct serial_device serial_scc_device =
+{
+	"serial_scc",
+	"SCC",
+	scc_init,
+	scc_setbrg,
+	scc_getc,
+	scc_tstc,
+	scc_putc,
+	scc_puts,
+};
+
+#endif	/* CONFIG_8xx_CONS_SCCx */
+
+#ifdef CONFIG_MODEM_SUPPORT
+void disable_putc(void)
+{
+	gd->be_quiet = 1;
+}
+
+void enable_putc(void)
+{
+	gd->be_quiet = 0;
+}
+#endif
+
+#if defined(CONFIG_CMD_KGDB)
+
+void
+kgdb_serial_init(void)
+{
+	int i = -1;
+
+	if (strcmp(default_serial_console()->ctlr, "SMC") == 0)
+	{
+#if defined(CONFIG_8xx_CONS_SMC1)
+		i = 1;
+#elif defined(CONFIG_8xx_CONS_SMC2)
+		i = 2;
+#endif
+	}
+	else if (strcmp(default_serial_console()->ctlr, "SMC") == 0)
+	{
+#if defined(CONFIG_8xx_CONS_SCC1)
+		i = 1;
+#elif defined(CONFIG_8xx_CONS_SCC2)
+		i = 2;
+#elif defined(CONFIG_8xx_CONS_SCC3)
+		i = 3;
+#elif defined(CONFIG_8xx_CONS_SCC4)
+		i = 4;
+#endif
+	}
+
+	if (i >= 0)
+	{
+		serial_printf("[on %s%d] ", default_serial_console()->ctlr, i);
+	}
+}
+
+void
+putDebugChar (int c)
+{
+	serial_putc (c);
+}
+
+void
+putDebugStr (const char *str)
+{
+	serial_puts (str);
+}
+
+int
+getDebugChar (void)
+{
+	return serial_getc();
+}
+
+void
+kgdb_interruptible (int yes)
+{
+	return;
+}
+#endif
+
+#endif	/* CONFIG_8xx_CONS_NONE */
diff --git a/arch/ppc/cpu/mpc8xx/speed.c b/arch/ppc/cpu/mpc8xx/speed.c
new file mode 100644
index 0000000..f309f29
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/speed.c
@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 2000-2004
+ * 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 <mpc8xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CPUCLK_DEFAULT) || defined(CONFIG_SYS_MEASURE_CPUCLK) || defined(DEBUG)
+
+#define PITC_SHIFT 16
+#define PITR_SHIFT 16
+/* pitc values to time for 58/8192 seconds (about 70.8 milliseconds) */
+#define SPEED_PIT_COUNTS 58
+#define SPEED_PITC	 ((SPEED_PIT_COUNTS - 1) << PITC_SHIFT)
+#define SPEED_PITC_INIT	 ((SPEED_PIT_COUNTS + 1) << PITC_SHIFT)
+
+/* Access functions for the Machine State Register */
+static __inline__ unsigned long get_msr(void)
+{
+	unsigned long msr;
+
+	asm volatile("mfmsr %0" : "=r" (msr) :);
+	return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+	asm volatile("mtmsr %0" : : "r" (msr));
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2),
+ * also determine bus clock speed (checking bus divider factor)
+ *
+ * (Approx. GCLK frequency in Hz)
+ *
+ * Initializes timer 2 and PIT, but disables them before return.
+ * [Use timer 2, because MPC823 CPUs mask 0.x do not have timers 3 and 4]
+ *
+ * When measuring the CPU clock against the PIT, we count cpu clocks
+ * for 58/8192 seconds with a prescale divide by 177 for the cpu clock.
+ * These strange values for the timing interval and prescaling are used
+ * because the formula for the CPU clock is:
+ *
+ *    CPU clock = count * (177 * (8192 / 58))
+ *
+ *		= count * 24999.7241
+ *
+ *    which is very close to
+ *
+ *		= count * 25000
+ *
+ * Since the count gives the CPU clock divided by 25000, we can get
+ * the CPU clock rounded to the nearest 0.1 MHz by
+ *
+ *    CPU clock = ((count + 2) / 4) * 100000;
+ *
+ * The rounding is important since the measurement is sometimes going
+ * to be high or low by 0.025 MHz, depending on exactly how the clocks
+ * and counters interact. By rounding we get the exact answer for any
+ * CPU clock that is an even multiple of 0.1 MHz.
+ */
+
+unsigned long measure_gclk(void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile cpmtimer8xx_t *timerp = &immr->im_cpmtimer;
+	ulong timer2_val;
+	ulong msr_val;
+
+#ifdef CONFIG_SYS_8XX_XIN
+	/* dont use OSCM, only use EXTCLK/512 */
+	immr->im_clkrst.car_sccr |= SCCR_RTSEL | SCCR_RTDIV;
+#else
+	immr->im_clkrst.car_sccr &= ~(SCCR_RTSEL | SCCR_RTDIV);
+#endif
+
+	/* Reset + Stop Timer 2, no cascading
+	 */
+	timerp->cpmt_tgcr &= ~(TGCR_CAS2 | TGCR_RST2);
+
+	/* Keep stopped, halt in debug mode
+	 */
+	timerp->cpmt_tgcr |= (TGCR_FRZ2 | TGCR_STP2);
+
+	/* Timer 2 setup:
+	 * Output ref. interrupt disable, int. clock
+	 * Prescale by 177. Note that prescaler divides by value + 1
+	 * so we must subtract 1 here.
+	 */
+	timerp->cpmt_tmr2 = ((177 - 1) << TMR_PS_SHIFT) | TMR_ICLK_IN_GEN;
+
+	timerp->cpmt_tcn2 = 0;		/* reset state		*/
+	timerp->cpmt_tgcr |= TGCR_RST2;	/* enable timer 2	*/
+
+	/*
+	 * PIT setup:
+	 *
+	 * We want to time for SPEED_PITC_COUNTS counts (of 8192 Hz),
+	 * so the count value would be SPEED_PITC_COUNTS - 1.
+	 * But there would be an uncertainty in the start time of 1/4
+	 * count since when we enable the PIT the count is not
+	 * synchronized to the 32768 Hz oscillator. The trick here is
+	 * to start the count higher and wait until the PIT count
+	 * changes to the required value before starting timer 2.
+	 *
+	 * One count high should be enough, but occasionally the start
+	 * is off by 1 or 2 counts of 32768 Hz. With the start value
+	 * set two counts high it seems very reliable.
+	 */
+
+	immr->im_sitk.sitk_pitck = KAPWR_KEY;	/* PIT initialization */
+	immr->im_sit.sit_pitc = SPEED_PITC_INIT;
+
+	immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+	immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+	/*
+	 * Start measurement - disable interrupts, just in case
+	 */
+	msr_val = get_msr ();
+	set_msr (msr_val & ~MSR_EE);
+
+	immr->im_sit.sit_piscr |= PISCR_PTE;
+
+	/* spin until get exact count when we want to start */
+	while (immr->im_sit.sit_pitr > SPEED_PITC);
+
+	timerp->cpmt_tgcr &= ~TGCR_STP2;	/* Start Timer 2	*/
+	while ((immr->im_sit.sit_piscr & PISCR_PS) == 0);
+	timerp->cpmt_tgcr |= TGCR_STP2;		/* Stop  Timer 2	*/
+
+	/* re-enable external interrupts if they were on */
+	set_msr (msr_val);
+
+	/* Disable timer and PIT
+	 */
+	timer2_val = timerp->cpmt_tcn2;		/* save before reset timer */
+
+	timerp->cpmt_tgcr &= ~(TGCR_RST2 | TGCR_FRZ2 | TGCR_STP2);
+	immr->im_sit.sit_piscr &= ~PISCR_PTE;
+
+#if defined(CONFIG_SYS_8XX_XIN)
+	/* not using OSCM, using XIN, so scale appropriately */
+	return (((timer2_val + 2) / 4) * (CONFIG_SYS_8XX_XIN/512))/8192 * 100000L;
+#else
+	return ((timer2_val + 2) / 4) * 100000L;	/* convert to Hz	*/
+#endif
+}
+
+#endif
+
+void get_brgclk(uint sccr)
+{
+	uint divider = 0;
+
+	switch((sccr&SCCR_DFBRG11)>>11){
+		case 0:
+			divider = 1;
+			break;
+		case 1:
+			divider = 4;
+			break;
+		case 2:
+			divider = 16;
+			break;
+		case 3:
+			divider = 64;
+			break;
+	}
+	gd->brg_clk = gd->cpu_clk/divider;
+}
+
+#if !defined(CONFIG_8xx_CPUCLK_DEFAULT)
+
+/*
+ * get_clocks() fills in gd->cpu_clock depending on CONFIG_8xx_GCLK_FREQ
+ * or (if it is not defined) measure_gclk() (which uses the ref clock)
+ * from above.
+ */
+int get_clocks (void)
+{
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint sccr = immap->im_clkrst.car_sccr;
+	/*
+	 * If for some reason measuring the gclk frequency won't
+	 * work, we return the hardwired value.
+	 * (For example, the cogent CMA286-60 CPU module has no
+	 * separate oscillator for PITRTCLK)
+	 */
+#if defined(CONFIG_8xx_GCLK_FREQ)
+	gd->cpu_clk = CONFIG_8xx_GCLK_FREQ;
+#elif defined(CONFIG_8xx_OSCLK)
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+	uint pll = immap->im_clkrst.car_plprcr;
+	uint clk;
+
+	if ((immr & 0x0FFF) >= MPC8xx_NEW_CLK) { /* MPC866/87x/88x series */
+		clk = ((CONFIG_8xx_OSCLK / (PLPRCR_val(PDF)+1)) *
+		       (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD)+1))) /
+			(1<<PLPRCR_val(S));
+	} else {
+		clk = CONFIG_8xx_OSCLK * (PLPRCR_val(MF)+1);
+	}
+	if (pll & PLPRCR_CSRC) {	/* Low frequency division factor is used  */
+		gd->cpu_clk = clk / (2 << ((sccr >> 8) & 7));
+	} else {			/* High frequency division factor is used */
+		gd->cpu_clk = clk / (1 << ((sccr >> 5) & 7));
+	}
+#else
+	gd->cpu_clk = measure_gclk();
+#endif /* CONFIG_8xx_GCLK_FREQ */
+
+	if ((sccr & SCCR_EBDF11) == 0) {
+		/* No Bus Divider active */
+		gd->bus_clk = gd->cpu_clk;
+	} else {
+		/* The MPC8xx has only one BDF: half clock speed */
+		gd->bus_clk = gd->cpu_clk / 2;
+	}
+
+	get_brgclk(sccr);
+
+	return (0);
+}
+
+#else /* CONFIG_8xx_CPUCLK_DEFAULT defined, use dynamic clock setting */
+
+static long init_pll_866 (long clk);
+
+/* This function sets up PLL (init_pll_866() is called) and
+ * fills gd->cpu_clk and gd->bus_clk according to the environment
+ * variable 'cpuclk' or to CONFIG_8xx_CPUCLK_DEFAULT (if 'cpuclk'
+ * contains invalid value).
+ * This functions requires an MPC866 or newer series CPU.
+ */
+int get_clocks_866 (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	char		  tmp[64];
+	long		  cpuclk = 0;
+	long		  sccr_reg;
+
+	if (getenv_r ("cpuclk", tmp, sizeof (tmp)) > 0)
+		cpuclk = simple_strtoul (tmp, NULL, 10) * 1000000;
+
+	if ((CONFIG_SYS_8xx_CPUCLK_MIN > cpuclk) || (CONFIG_SYS_8xx_CPUCLK_MAX < cpuclk))
+		cpuclk = CONFIG_8xx_CPUCLK_DEFAULT;
+
+	gd->cpu_clk = init_pll_866 (cpuclk);
+#if defined(CONFIG_SYS_MEASURE_CPUCLK)
+	gd->cpu_clk = measure_gclk ();
+#endif
+
+	get_brgclk(immr->im_clkrst.car_sccr);
+
+	/* if cpu clock <= 66 MHz then set bus division factor to 1,
+	 * otherwise set it to 2
+	 */
+	sccr_reg = immr->im_clkrst.car_sccr;
+	sccr_reg &= ~SCCR_EBDF11;
+
+	if (gd->cpu_clk <= 66000000) {
+		sccr_reg |= SCCR_EBDF00;	/* bus division factor = 1 */
+		gd->bus_clk = gd->cpu_clk;
+	} else {
+		sccr_reg |= SCCR_EBDF01;	/* bus division factor = 2 */
+		gd->bus_clk = gd->cpu_clk / 2;
+	}
+	immr->im_clkrst.car_sccr = sccr_reg;
+
+	return (0);
+}
+
+/* Adjust sdram refresh rate to actual CPU clock.
+ */
+int sdram_adjust_866 (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	long		  mamr;
+
+	mamr = immr->im_memctl.memc_mamr;
+	mamr &= ~MAMR_PTA_MSK;
+	mamr |= ((gd->cpu_clk / CONFIG_SYS_PTA_PER_CLK) << MAMR_PTA_SHIFT);
+	immr->im_memctl.memc_mamr = mamr;
+
+	return (0);
+}
+
+/* Configure PLL for MPC866/859/885 CPU series
+ * PLL multiplication factor is set to the value nearest to the desired clk,
+ * assuming a oscclk of 10 MHz.
+ */
+static long init_pll_866 (long clk)
+{
+	extern void plprcr_write_866 (long);
+
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	long		  n, plprcr;
+	char		  mfi, mfn, mfd, s, pdf;
+	long		  step_mfi, step_mfn;
+
+	if (clk < 20000000) {
+		clk *= 2;
+		pdf = 1;
+	} else {
+		pdf = 0;
+	}
+
+	if (clk < 40000000) {
+		s = 2;
+		step_mfi = CONFIG_8xx_OSCLK / 4;
+		mfd = 7;
+		step_mfn = CONFIG_8xx_OSCLK / 30;
+	} else if (clk < 80000000) {
+		s = 1;
+		step_mfi = CONFIG_8xx_OSCLK / 2;
+		mfd = 14;
+		step_mfn = CONFIG_8xx_OSCLK / 30;
+	} else {
+		s = 0;
+		step_mfi = CONFIG_8xx_OSCLK;
+		mfd = 29;
+		step_mfn = CONFIG_8xx_OSCLK / 30;
+	}
+
+	/* Calculate integer part of multiplication factor
+	 */
+	n = clk / step_mfi;
+	mfi = (char)n;
+
+	/* Calculate numerator of fractional part of multiplication factor
+	 */
+	n = clk - (n * step_mfi);
+	mfn = (char)(n / step_mfn);
+
+	/* Calculate effective clk
+	 */
+	n = ((mfi * step_mfi) + (mfn * step_mfn)) / (pdf + 1);
+
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+	plprcr = (immr->im_clkrst.car_plprcr & ~(PLPRCR_MFN_MSK
+			| PLPRCR_MFD_MSK | PLPRCR_S_MSK
+			| PLPRCR_MFI_MSK | PLPRCR_DBRMO
+			| PLPRCR_PDF_MSK))
+			| (mfn << PLPRCR_MFN_SHIFT)
+			| (mfd << PLPRCR_MFD_SHIFT)
+			| (s << PLPRCR_S_SHIFT)
+			| (mfi << PLPRCR_MFI_SHIFT)
+			| (pdf << PLPRCR_PDF_SHIFT);
+
+	if( (mfn > 0) && ((mfd / mfn) > 10) )
+		plprcr |= PLPRCR_DBRMO;
+
+	plprcr_write_866 (plprcr);		/* set value using SIU4/9 workaround */
+	immr->im_clkrstk.cark_plprcrk = 0x00000000;
+
+	return (n);
+}
+
+#endif /* CONFIG_8xx_CPUCLK_DEFAULT */
+
+#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
+    && !defined(CONFIG_TQM885D)
+/*
+ * Adjust sdram refresh rate to actual CPU clock
+ * and set timebase source according to actual CPU clock
+ */
+int adjust_sdram_tbs_8xx (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	long		  mamr;
+	long              sccr;
+
+	mamr = immr->im_memctl.memc_mamr;
+	mamr &= ~MAMR_PTA_MSK;
+	mamr |= ((gd->cpu_clk / CONFIG_SYS_PTA_PER_CLK) << MAMR_PTA_SHIFT);
+	immr->im_memctl.memc_mamr = mamr;
+
+	if (gd->cpu_clk < 67000000) {
+		sccr = immr->im_clkrst.car_sccr;
+		sccr |= SCCR_TBS;
+		immr->im_clkrst.car_sccr = sccr;
+	}
+
+	return (0);
+}
+#endif /* CONFIG_TQM8xxL/M, !TQM866M, !TQM885D */
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/ppc/cpu/mpc8xx/spi.c b/arch/ppc/cpu/mpc8xx/spi.c
new file mode 100644
index 0000000..b2ac23e
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/spi.c
@@ -0,0 +1,560 @@
+/*
+ * 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 <serial.h>
+
+#if (defined(CONFIG_SPI)) || (CONFIG_POST & CONFIG_SYS_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	CONFIG_SYS_SPI_INIT_OFFSET
+#define	CONFIG_SYS_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 *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+			[CONFIG_SYS_SPI_INIT_OFFSET];
+static uchar *txbuf =
+  (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+			[CONFIG_SYS_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 *)  CONFIG_SYS_IMMR;
+	cpi  = (cpic8xx_t *)&immr->im_cpic;
+	iop  = (iop8xx_t *) &immr->im_ioport;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_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 CONFIG_SYS_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 CONFIG_SYS_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	/* CONFIG_SYS_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 *)  CONFIG_SYS_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_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 *) CONFIG_SYS_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_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 & CONFIG_SYS_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 & CONFIG_SYS_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)
+{
+	int res = -1;
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_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 ((char *)txbuf, l);
+
+			spi_xfer (l);
+
+			if (packet_check ((char *)rxbuf, l) < 0) {
+				goto Done;
+			}
+		}
+	}
+
+	res = 0;
+
+      Done:
+
+	cp->cp_spmode &= ~SPMODE_LOOP;
+
+	/*
+	 * SCC2 parameter RAM space overlaps
+	 * the SPI parameter RAM space. So we need to restore
+	 * the SCC2 configuration if it is used by UART.
+	 */
+
+#if !defined(CONFIG_8xx_CONS_NONE)
+	serial_reinit_all ();
+#endif
+
+	if (res != 0) {
+		post_log ("SPI test failed\n");
+	}
+
+	return res;
+}
+#endif	/* CONFIG_POST & CONFIG_SYS_POST_SPI */
diff --git a/arch/ppc/cpu/mpc8xx/start.S b/arch/ppc/cpu/mpc8xx/start.S
new file mode 100644
index 0000000..7cf602f
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/start.S
@@ -0,0 +1,684 @@
+/*
+ *  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 memory map.
+ *
+ *  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 <mpc8xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_8xx 1		/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef  CONFIG_IDENT_STRING
+#define  CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI )	/* Machine Check and Recoverable Interr. */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+	.text
+	.long	0x27051956		/* U-Boot Magic Number			*/
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	lis	r3, CONFIG_SYS_IMMR@h		/* position IMMR */
+	mtspr	638, r3
+	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 ME, RI flags */
+	mtmsr	r3
+	mtspr	SRR1, r3		/* Make SRR1 match MSR */
+
+	mfspr	r3, ICR			/* clear Interrupt Cause Register */
+
+	/* Initialize debug port registers					*/
+	/*----------------------------------------------------------------------*/
+	xor	r0, r0, r0		/* Clear R0 */
+	mtspr	LCTRL1, r0		/* Initialize debug port regs */
+	mtspr	LCTRL2, r0
+	mtspr	COUNTA, r0
+	mtspr	COUNTB, r0
+
+	/* Reset the caches							*/
+	/*----------------------------------------------------------------------*/
+
+	mfspr	r3, IC_CST		/* Clear error bits */
+	mfspr	r3, DC_CST
+
+	lis	r3, IDC_UNALL@h		/* Unlock all */
+	mtspr	IC_CST, r3
+	mtspr	DC_CST, r3
+
+	lis	r3, IDC_INVALL@h	/* Invalidate all */
+	mtspr	IC_CST, r3
+	mtspr	DC_CST, r3
+
+	lis	r3, IDC_DISABLE@h	/* Disable data cache */
+	mtspr	DC_CST, r3
+
+#if !defined(CONFIG_SYS_DELAYED_ICACHE)
+					/* On IP860 and PCU E,
+					 * we cannot enable IC yet
+					 */
+	lis	r3, IDC_ENABLE@h	/* Enable instruction cache */
+#endif
+	mtspr	IC_CST, r3
+
+	/* invalidate all tlb's							*/
+	/*----------------------------------------------------------------------*/
+
+	tlbia
+	isync
+
+	/*
+	 * Calculate absolute address in FLASH and jump there
+	 *----------------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_MONITOR_BASE@h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE@l
+	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r3
+	blr
+
+in_flash:
+
+	/* initialize some SPRs that are hard to access from C			*/
+	/*----------------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_IMMR@h		/* pass IMMR as arg1 to C routine */
+	ori	r1, r3, CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in internal DPRAM */
+	/* Note: R0 is still 0 here */
+	stwu	r0, -4(r1)		/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)		/* stack backtraces terminate cleanly	*/
+
+	/*
+	 * Disable serialized ifetch and show cycles
+	 * (i.e. set processor to normal mode).
+	 * This is also a silicon bug workaround, see errata
+	 */
+
+	li	r2, 0x0007
+	mtspr	ICTRL, r2
+
+	/* Set up debug mode entry */
+
+	lis	r2, CONFIG_SYS_DER@h
+	ori	r2, r2, CONFIG_SYS_DER@l
+	mtspr	DER, r2
+
+	/* 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(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	/* No FPU on MPC8xx.  This exception is not supposed to happen.
+	*/
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	/* On the MPC8xx, this is a software emulation interrupt.  It occurs
+	 * for all unimplemented and illegal instructions.
+	 */
+	STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+	STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+	STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+	STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+	STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+	STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+	STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+	STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+	STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+	STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
+	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+
+	. = 0x2000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28			/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)		/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+/* Cache functions.
+*/
+	.globl	icache_enable
+icache_enable:
+	SYNC
+	lis	r3, IDC_INVALL@h
+	mtspr	IC_CST, r3
+	lis	r3, IDC_ENABLE@h
+	mtspr	IC_CST, r3
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	SYNC
+	lis	r3, IDC_DISABLE@h
+	mtspr	IC_CST, r3
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, IC_CST
+	srwi	r3, r3, 31	/* >>31 => select bit 0 */
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+#if 0
+	SYNC
+#endif
+#if 1
+	lis	r3, 0x0400		/* Set cache mode with MMU off */
+	mtspr	MD_CTR, r3
+#endif
+
+	lis	r3, IDC_INVALL@h
+	mtspr	DC_CST, r3
+#if 0
+	lis	r3, DC_SFWT@h
+	mtspr	DC_CST, r3
+#endif
+	lis	r3, IDC_ENABLE@h
+	mtspr	DC_CST, r3
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	SYNC
+	lis	r3, IDC_DISABLE@h
+	mtspr	DC_CST, r3
+	lis	r3, IDC_INVALL@h
+	mtspr	DC_CST, r3
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, DC_CST
+	srwi	r3, r3, 31	/* >>31 => select bit 0 */
+	blr
+
+	.globl	dc_read
+dc_read:
+	mtspr	DC_ADR, r3
+	mfspr	r3, DC_DAT
+	blr
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+	.globl	get_immr
+get_immr:
+	mr	r4,r3		/* save mask */
+	mfspr	r3, IMMR	/* IMMR */
+	cmpwi	0,r4,0		/* mask != 0 ? */
+	beq	4f
+	and	r3,r3,r4	/* IMMR & mask */
+4:
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+
+	.globl wr_ic_cst
+wr_ic_cst:
+	mtspr	IC_CST, r3
+	blr
+
+	.globl rd_ic_cst
+rd_ic_cst:
+	mfspr	r3, IC_CST
+	blr
+
+	.globl wr_ic_adr
+wr_ic_adr:
+	mtspr	IC_ADR, r3
+	blr
+
+
+	.globl wr_dc_cst
+wr_dc_cst:
+	mtspr	DC_CST, r3
+	blr
+
+	.globl rd_dc_cst
+rd_dc_cst:
+	mfspr	r3, DC_CST
+	blr
+
+	.globl wr_dc_adr
+wr_dc_adr:
+	mtspr	DC_ADR, r3
+	blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3		/* Set new stack pointer		*/
+	mr	r9,  r4		/* Save copy of Global Data pointer	*/
+	mr	r10, r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	mtlr	r4			/* restore link register	*/
+	blr
diff --git a/arch/ppc/cpu/mpc8xx/traps.c b/arch/ppc/cpu/mpc8xx/traps.c
new file mode 100644
index 0000000..6efe8e0
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/traps.c
@@ -0,0 +1,241 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM	0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0)
+		{
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7)
+		{
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		printf("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13):
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+  do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xx/upatch.c b/arch/ppc/cpu/mpc8xx/upatch.c
new file mode 100644
index 0000000..a8cb735
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/upatch.c
@@ -0,0 +1,194 @@
+#include <common.h>
+#include <commproc.h>
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+    defined(CONFIG_SYS_SMC_UCODE_PATCH)
+
+static void UcodeCopy (volatile cpm8xx_t *cpm);
+
+void cpm_load_patch (volatile immap_t *immr)
+{
+	immr->im_cpm.cp_rccr &= ~0x0003;	/* Disable microcode program area */
+
+	UcodeCopy ((cpm8xx_t *)&immr->im_cpm);	/* Copy ucode patch to DPRAM   */
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+    {
+	volatile spi_t *spi = (spi_t *) & immr->im_cpm.cp_dparam[PROFF_SPI];
+	/* Activate the microcode per the instructions in the microcode manual */
+	/* NOTE:  We're only relocating the SPI parameters (not I2C).          */
+	immr->im_cpm.cp_cpmcr1 = 0x802a;	/* Write Trap register 1 value */
+	immr->im_cpm.cp_cpmcr2 = 0x8028;	/* Write Trap register 2 value */
+	spi->spi_rpbase = CONFIG_SYS_SPI_DPMEM_OFFSET;	/* Where to relocte SPI params */
+    }
+#endif
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+    {
+	volatile iic_t *iip = (iic_t *) & immr->im_cpm.cp_dparam[PROFF_IIC];
+	/* Activate the microcode per the instructions in the microcode manual */
+	/* NOTE:  We're only relocating the I2C parameters (not SPI).          */
+	immr->im_cpm.cp_cpmcr3 = 0x802e;	/* Write Trap register 3 value */
+	immr->im_cpm.cp_cpmcr4 = 0x802c;	/* Write Trap register 4 value */
+	iip->iic_rpbase = CONFIG_SYS_I2C_DPMEM_OFFSET;	/* Where to relocte I2C params */
+    }
+#endif
+
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+    {
+	volatile smc_uart_t *up = (smc_uart_t *) & immr->im_cpm.cp_dparam[PROFF_SMC1];
+	/* Activate the microcode per the instructions in the microcode manual */
+	/* NOTE:  We're only relocating the SMC parameters.                    */
+	immr->im_cpm.cp_cpmcr1 = 0x8080;	/* Write Trap register 1 value */
+	immr->im_cpm.cp_cpmcr2 = 0x8088;	/* Write Trap register 2 value */
+	up->smc_rpbase = CONFIG_SYS_SMC_DPMEM_OFFSET;	/* Where to relocte SMC params */
+    }
+#endif
+
+	/*
+	 * Enable DPRAM microcode to execute from the first 512 bytes
+	 * and a 256 byte extension of DPRAM.
+	 */
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+	immr->im_cpm.cp_rccr |= 0x0002;
+#else
+	immr->im_cpm.cp_rccr |= 0x0001;
+#endif
+}
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCh)
+static ulong patch_2000[] = {
+	0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
+	0x5FEFADF7, 0x5F88ADF7, 0x5FEFAFF7, 0x5F88AFF7,
+	0x3A9CFBC8, 0x77CAE1BB, 0xF4DE7FAD, 0xABAE9330,
+	0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF, 0xFDAFF9CF,
+	0xABF88DC8, 0xAB5879F7, 0xB0927383, 0xDFD079F7,
+	0xB090E6BB, 0xE5BBE74F, 0xB3FA6F0F, 0x6FFB76CE,
+	0xEE0CF9CF, 0x2BFBEFEF, 0xCFEEF9CF, 0x76CEAD23,
+	0x90B3DF99, 0x7FDDD0C1, 0x4BF847FD, 0x7CCF76CE,
+	0xCFEF77CA, 0x7EAF7FAD, 0x7DFDF0B7, 0xEF7A7FCA,
+	0x77CAFBC8, 0x6079E722, 0xFBC85FFF, 0xDFFF5FB3,
+	0xFFFBFBC8, 0xF3C894A5, 0xE7C9EDF9, 0x7F9A7FAD,
+	0x5F36AFE8, 0x5F5BFFDF, 0xDF95CB9E, 0xAF7D5FC3,
+	0xAFED8C1B, 0x5FC3AFDD, 0x5FC5DF99, 0x7EFDB0B3,
+	0x5FB3FFFE, 0xABAE5FB3, 0xFFFE5FD0, 0x600BE6BB,
+	0x600B5FD0, 0xDFC827FB, 0xEFDF5FCA, 0xCFDE3A9C,
+	0xE7C9EDF9, 0xF3C87F9E, 0x54CA7FED, 0x2D3A3637,
+	0x756F7E9A, 0xF1CE37EF, 0x2E677FEE, 0x10EBADF8,
+	0xEFDECFEA, 0xE52F7D9F, 0xE12BF1CE, 0x5F647E9A,
+	0x4DF8CFEA, 0x5F717D9B, 0xEFEECFEA, 0x5F73E522,
+	0xEFDE5F73, 0xCFDA0B61, 0x7385DF61, 0xE7C9EDF9,
+	0x7E9A30D5, 0x1458BFFF, 0xF3C85FFF, 0xDFFFA7F8,
+	0x5F5BBFFE, 0x7F7D10D0, 0x144D5F33, 0xBFFFAF78,
+	0x5F5BBFFD, 0xA7F85F33, 0xBFFE77FD, 0x30BD4E08,
+	0xFDCFE5FF, 0x6E0FAFF8, 0x7EEF7E9F, 0xFDEFF1CF,
+	0x5F17ABF8, 0x0D5B5F5B, 0xFFEF79F7, 0x309EAFDD,
+	0x5F3147F8, 0x5F31AFED, 0x7FDD50AF, 0x497847FD,
+	0x7F9E7FED, 0x7DFD70A9, 0xEF7E7ECE, 0x6BA07F9E,
+	0x2D227EFD, 0x30DB5F5B, 0xFFFD5F5B, 0xFFEF5F5B,
+	0xFFDF0C9C, 0xAFED0A9A, 0xAFDD0C37, 0x5F37AFBD,
+	0x7FBDB081, 0x5F8147F8,
+};
+
+static ulong patch_2F00[] = {
+	0x3E303430, 0x34343737, 0xABBF9B99, 0x4B4FBDBD,
+	0x59949334, 0x9FFF37FB, 0x9B177DD9, 0x936956BB,
+	0xFBDD697B, 0xDD2FD113, 0x1DB9F7BB, 0x36313963,
+	0x79373369, 0x3193137F, 0x7331737A, 0xF7BB9B99,
+	0x9BB19795, 0x77FDFD3D, 0x573B773F, 0x737933F7,
+	0xB991D115, 0x31699315, 0x31531694, 0xBF4FBDBD,
+	0x35931497, 0x35376956, 0xBD697B9D, 0x96931313,
+	0x19797937, 0x69350000,
+};
+#else
+
+static ulong patch_2000[] = {
+	0x3fff0000, 0x3ffd0000, 0x3ffb0000, 0x3ff90000,
+	0x5fefeff8, 0x5f91eff8, 0x3ff30000, 0x3ff10000,
+	0x3a11e710, 0xedf0ccb9, 0xf318ed66, 0x7f0e5fe2,
+	0x7fedbb38, 0x3afe7468, 0x7fedf4d8, 0x8ffbb92d,
+	0xb83b77fd, 0xb0bb5eb9, 0xdfda7fed, 0x90bde74d,
+	0x6f0dcbd3, 0xe7decfed, 0xcb50cfed, 0xcfeddf6d,
+	0x914d4f74, 0x5eaedfcb, 0x9ee0e7df, 0xefbb6ffb,
+	0xe7ef7f0e, 0x9ee57fed, 0xebb7effa, 0xeb30affb,
+	0x7fea90b3, 0x7e0cf09f, 0xbffff318, 0x5fffdfff,
+	0xac35efea, 0x7fce1fc1, 0xe2ff5fbd, 0xaffbe2ff,
+	0x5fbfaffb, 0xf9a87d0f, 0xaef8770f, 0x7d0fb0a2,
+	0xeffbbfff, 0xcfef5fba, 0x7d0fbfff, 0x5fba4cf8,
+	0x7fddd09b, 0x49f847fd, 0x7efdf097, 0x7fedfffd,
+	0x7dfdf093, 0xef7e7e1e, 0x5fba7f0e, 0x3a11e710,
+	0xedf0cc87, 0xfb18ad0a, 0x1f85bbb8, 0x74283b7e,
+	0x7375e4bb, 0x2ab64fb8, 0x5c7de4bb, 0x32fdffbf,
+	0x5f0843f8, 0x7ce3e1bb, 0xe74f7ded, 0x6f0f4fe8,
+	0xc7ba32be, 0x73f2efeb, 0x600b4f78, 0xe5bb760b,
+	0x5388aef8, 0x4ef80b6a, 0xcfef9ee5, 0xabf8751f,
+	0xefef5b88, 0x741f4fe8, 0x751e760d, 0x7fdb70dd,
+	0x741cafce, 0xefcc7fce, 0x751e7088, 0x741ce7bb,
+	0x334ecfed, 0xafdbefeb, 0xe5bb760b, 0x53ceaef8,
+	0xafe8e7eb, 0x4bf8771e, 0x7e007fed, 0x4fcbe2cc,
+	0x7fbc3085, 0x7b0f7a0f, 0x34b177fd, 0xb0e75e93,
+	0xdf313e3b, 0xaf78741f, 0x741f30cc, 0xcfef5f08,
+	0x741f3e88, 0xafb8771e, 0x5f437fed, 0x0bafe2cc,
+	0x741ccfec, 0xe5ca53a9, 0x6fcb4f74, 0x5e89df27,
+	0x2a923d14, 0x4b8fdf0c, 0x751f741c, 0x6c1eeffa,
+	0xefea7fce, 0x6ffc309a, 0xefec3fca, 0x308fdf0a,
+	0xadf85e7a, 0xaf7daefd, 0x5e7adf0a, 0x5e7aafdd,
+	0x761f1088, 0x1e7c7efd, 0x3089fffe, 0x4908fb18,
+	0x5fffdfff, 0xafbbf0f7, 0x4ef85f43, 0xadf81489,
+	0x7a0f7089, 0xcfef5089, 0x7a0fdf0c, 0x5e7cafed,
+	0xbc6e780f, 0xefef780f, 0xefef790f, 0xa7f85eeb,
+	0xffef790f, 0xefef790f, 0x1489df0a, 0x5e7aadfd,
+	0x5f09fffb, 0xe79aded9, 0xeff96079, 0x607ae79a,
+	0xded8eff9, 0x60795edb, 0x607acfef, 0xefefefdf,
+	0xefbfef7f, 0xeeffedff, 0xebffe7ff, 0xafefafdf,
+	0xafbfaf7f, 0xaeffadff, 0xabffa7ff, 0x6fef6fdf,
+	0x6fbf6f7f, 0x6eff6dff, 0x6bff67ff, 0x2fef2fdf,
+	0x2fbf2f7f, 0x2eff2dff, 0x2bff27ff, 0x4e08fd1f,
+	0xe5ff6e0f, 0xaff87eef, 0x7e0ffdef, 0xf11f6079,
+	0xabf8f51e, 0x7e0af11c, 0x37cfae16, 0x7fec909a,
+	0xadf8efdc, 0xcfeae52f, 0x7d0fe12b, 0xf11c6079,
+	0x7e0a4df8, 0xcfea5ea0, 0x7d0befec, 0xcfea5ea2,
+	0xe522efdc, 0x5ea2cfda, 0x4e08fd1f, 0x6e0faff8,
+	0x7c1f761f, 0xfdeff91f, 0x6079abf8, 0x761cee00,
+	0xf91f2bfb, 0xefefcfec, 0xf91f6079, 0x761c27fb,
+	0xefdf5e83, 0xcfdc7fdd, 0x50f84bf8, 0x47fd7c1f,
+	0x761ccfcf, 0x7eef7fed, 0x7dfd70ef, 0xef7e7f1e,
+	0x771efb18, 0x6079e722, 0xe6bbe5bb, 0x2e66e5bb,
+	0x600b2ee1, 0xe2bbe2bb, 0xe2bbe2bb, 0x2f5ee2bb,
+	0xe2bb2ff9, 0x6079e2bb,
+};
+
+static ulong patch_2F00[] = {
+	0x30303030, 0x3e3e3030, 0xaf79b9b3, 0xbaa3b979,
+	0x9693369f, 0x79f79777, 0x97333fff, 0xfb3b9e9f,
+	0x79b91d11, 0x9e13f3ff, 0x3f9b6bd9, 0xe173d136,
+	0x695669d1, 0x697b3daf, 0x79b93a3a, 0x3f979f91,
+	0x379ff976, 0xf99777fd, 0x9779737d, 0xe9d6bbf9,
+	0xbfffd9df, 0x97f7fd97, 0x6f7b9bff, 0xf9bd9683,
+	0x397db973, 0xd97b3b9f, 0xd7f9f733, 0x9993bb9e,
+	0xe1f9ef93, 0x73773337, 0xb936917d, 0x11f87379,
+	0xb979d336, 0x8b7ded73, 0x1b7d9337, 0x31f3f22f,
+	0x3f2327ee, 0xeeeeeeee, 0xeeeeeeee, 0xeeeeeeee,
+	0xeeeeee4b, 0xf4fbdbd2, 0x58bb1878, 0x577fdfd2,
+	0xd573b773, 0xf7374b4f, 0xbdbd25b8, 0xb177d2d1,
+	0x7376856b, 0xbfdd687b, 0xdd2fff8f, 0x78ffff8f,
+	0xf22f0000,
+};
+#endif
+
+static void UcodeCopy (volatile cpm8xx_t *cpm)
+{
+	vu_long *p;
+	int i;
+
+	p = (vu_long *)&(cpm->cp_dpmem[0x0000]);
+	for (i=0; i < sizeof(patch_2000)/4; ++i) {
+		p[i] = patch_2000[i];
+	}
+
+	p = (vu_long *)&(cpm->cp_dpmem[0x0F00]);
+	for (i=0; i < sizeof(patch_2F00)/4; ++i) {
+		p[i] = patch_2F00[i];
+	}
+}
+
+#endif	/* CONFIG_SYS_I2C_UCODE_PATCH, CONFIG_SYS_SPI_UCODE_PATCH */
diff --git a/arch/ppc/cpu/mpc8xx/video.c b/arch/ppc/cpu/mpc8xx/video.c
new file mode 100644
index 0000000..c79c499
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/video.c
@@ -0,0 +1,1331 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ * (C) Copyright 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
+ */
+
+/* #define DEBUG */
+
+/************************************************************************/
+/* ** HEADER FILES							*/
+/************************************************************************/
+
+#include <stdarg.h>
+#include <common.h>
+#include <config.h>
+#include <version.h>
+#include <timestamp.h>
+#include <i2c.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+
+#ifdef CONFIG_VIDEO
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/************************************************************************/
+/* ** DEBUG SETTINGS							*/
+/************************************************************************/
+
+#if 0
+#define VIDEO_DEBUG_COLORBARS	/* Force colorbars output */
+#endif
+
+/************************************************************************/
+/* ** VIDEO MODE SETTINGS						*/
+/************************************************************************/
+
+#if 0
+#define VIDEO_MODE_EXTENDED		/* Allow screen size bigger than visible area */
+#define VIDEO_MODE_NTSC
+#endif
+
+#define VIDEO_MODE_PAL
+
+#if 0
+#define VIDEO_BLINK			/* This enables cursor blinking (under construction) */
+#endif
+
+#define VIDEO_INFO			/* Show U-Boot information */
+#define VIDEO_INFO_X		VIDEO_LOGO_WIDTH+8
+#define VIDEO_INFO_Y		16
+
+/************************************************************************/
+/* ** VIDEO ENCODER CONSTANTS						*/
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7176
+
+#include <video_ad7176.h>	/* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C		1
+#define VIDEO_I2C_ADDR		CONFIG_VIDEO_ENCODER_AD7176_ADDR
+#endif
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7177
+
+#include <video_ad7177.h>	/* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C		1
+#define VIDEO_I2C_ADDR		CONFIG_VIDEO_ENCODER_AD7177_ADDR
+#endif
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7179
+
+#include <video_ad7179.h>	/* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C		1
+#define VIDEO_I2C_ADDR		CONFIG_VIDEO_ENCODER_AD7179_ADDR
+#endif
+
+/************************************************************************/
+/* ** VIDEO MODE CONSTANTS						*/
+/************************************************************************/
+
+#ifdef VIDEO_MODE_EXTENDED
+#define VIDEO_COLS	VIDEO_ACTIVE_COLS
+#define VIDEO_ROWS	VIDEO_ACTIVE_ROWS
+#else
+#define VIDEO_COLS	VIDEO_VISIBLE_COLS
+#define VIDEO_ROWS	VIDEO_VISIBLE_ROWS
+#endif
+
+#define VIDEO_PIXEL_SIZE	(VIDEO_MODE_BPP/8)
+#define VIDEO_SIZE		(VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE)	/* Total size of buffer */
+#define VIDEO_PIX_BLOCKS	(VIDEO_SIZE >> 2)	/* Number of ints */
+#define VIDEO_LINE_LEN		(VIDEO_COLS*VIDEO_PIXEL_SIZE)	/* Number of bytes per line */
+#define VIDEO_BURST_LEN		(VIDEO_COLS/8)
+
+#ifdef VIDEO_MODE_YUYV
+#define VIDEO_BG_COL	0x80D880D8	/* Background color in YUYV format */
+#else
+#define VIDEO_BG_COL	0xF8F8F8F8	/* Background color in RGB format */
+#endif
+
+/************************************************************************/
+/* ** FONT AND LOGO DATA						*/
+/************************************************************************/
+
+#include <video_font.h>			/* Get font data, width and height */
+
+#ifdef CONFIG_VIDEO_LOGO
+#include <video_logo.h>			/* Get logo data, width and height */
+
+#define VIDEO_LOGO_WIDTH	DEF_U_BOOT_LOGO_WIDTH
+#define VIDEO_LOGO_HEIGHT	DEF_U_BOOT_LOGO_HEIGHT
+#define VIDEO_LOGO_ADDR		&u_boot_logo
+#endif
+
+/************************************************************************/
+/* ** VIDEO CONTROLLER CONSTANTS					*/
+/************************************************************************/
+
+/* VCCR - VIDEO CONTROLLER CONFIGURATION REGISTER */
+
+#define VIDEO_VCCR_VON	0		/* Video controller ON */
+#define VIDEO_VCCR_CSRC	1		/* Clock source */
+#define VIDEO_VCCR_PDF	13		/* Pixel display format */
+#define VIDEO_VCCR_IEN	11		/* Interrupt enable */
+
+/* VSR - VIDEO STATUS REGISTER */
+
+#define VIDEO_VSR_CAS	6		/* Active set */
+#define VIDEO_VSR_EOF	0		/* End of frame */
+
+/* VCMR - VIDEO COMMAND REGISTER */
+
+#define VIDEO_VCMR_BD	0		/* Blank display */
+#define VIDEO_VCMR_ASEL	1		/* Active set selection */
+
+/* VBCB - VIDEO BACKGROUND COLOR BUFFER REGISTER */
+
+#define VIDEO_BCSR4_RESET_BIT	21	/* BCSR4 - Extern video encoder reset */
+#define VIDEO_BCSR4_EXTCLK_BIT	22	/* BCSR4 - Extern clock enable */
+#define VIDEO_BCSR4_VIDLED_BIT	23	/* BCSR4 - Video led disable */
+
+/************************************************************************/
+/* ** CONSOLE CONSTANTS							*/
+/************************************************************************/
+
+#ifdef	CONFIG_VIDEO_LOGO
+#define CONSOLE_ROWS		((VIDEO_ROWS - VIDEO_LOGO_HEIGHT) / VIDEO_FONT_HEIGHT)
+#define VIDEO_LOGO_SKIP		(VIDEO_COLS - VIDEO_LOGO_WIDTH)
+#else
+#define CONSOLE_ROWS		(VIDEO_ROWS / VIDEO_FONT_HEIGHT)
+#endif
+
+#define CONSOLE_COLS		(VIDEO_COLS / VIDEO_FONT_WIDTH)
+#define CONSOLE_ROW_SIZE	(VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
+#define CONSOLE_ROW_FIRST	(video_console_address)
+#define CONSOLE_ROW_SECOND	(video_console_address + CONSOLE_ROW_SIZE)
+#define CONSOLE_ROW_LAST	(video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+#define CONSOLE_SIZE		(CONSOLE_ROW_SIZE * CONSOLE_ROWS)
+#define CONSOLE_SCROLL_SIZE	(CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+
+/*
+ * Simple color definitions
+ */
+#define CONSOLE_COLOR_BLACK	 0
+#define CONSOLE_COLOR_RED	 1
+#define CONSOLE_COLOR_GREEN	 2
+#define CONSOLE_COLOR_YELLOW	 3
+#define CONSOLE_COLOR_BLUE	 4
+#define CONSOLE_COLOR_MAGENTA	 5
+#define CONSOLE_COLOR_CYAN	 6
+#define CONSOLE_COLOR_GREY	13
+#define CONSOLE_COLOR_GREY2	14
+#define CONSOLE_COLOR_WHITE	15	/* Must remain last / highest */
+
+/************************************************************************/
+/* ** BITOPS MACROS							*/
+/************************************************************************/
+
+#define HISHORT(i)	((i >> 16)&0xffff)
+#define LOSHORT(i)	(i & 0xffff)
+#define HICHAR(s)	((i >> 8)&0xff)
+#define LOCHAR(s)	(i & 0xff)
+#define HI(c)		((c >> 4)&0xf)
+#define LO(c)		(c & 0xf)
+#define SWAPINT(i)	(HISHORT(i) | (LOSHORT(i) << 16))
+#define SWAPSHORT(s)	(HICHAR(s) | (LOCHAR(s) << 8))
+#define SWAPCHAR(c)	(HI(c) | (LO(c) << 4))
+#define BITMASK(b)	(1 << (b))
+#define GETBIT(v,b)	(((v) & BITMASK(b)) > 0)
+#define SETBIT(v,b,d)	(v = (((d)>0) ? (v) | BITMASK(b): (v) & ~BITMASK(b)))
+
+/************************************************************************/
+/* ** STRUCTURES							*/
+/************************************************************************/
+
+typedef struct {
+	unsigned char V, Y1, U, Y2;
+} tYUYV;
+
+/* This structure is based on the Video Ram in the MPC823. */
+typedef struct VRAM {
+	unsigned	hx:2,		/* Horizontal sync */
+			vx:2,		/* Vertical sync */
+			fx:2,		/* Frame */
+			bx:2,		/* Blank */
+			res1:6,		/* Reserved */
+			vds:2,		/* Video Data Select */
+			inter:1,	/* Interrupt */
+			res2:2,		/* Reserved */
+			lcyc:11,	/* Loop/video cycles */
+			lp:1,		/* Loop start/end */
+			lst:1;		/* Last entry */
+} VRAM;
+
+/************************************************************************/
+/* ** VARIABLES								*/
+/************************************************************************/
+
+static int
+	video_panning_range_x = 0,	/* Video mode invisible pixels x range */
+	video_panning_range_y = 0,	/* Video mode invisible pixels y range */
+	video_panning_value_x = 0,	/* Video mode x panning value (absolute) */
+	video_panning_value_y = 0,	/* Video mode y panning value (absolute) */
+	video_panning_factor_x = 0,	/* Video mode x panning value (-127 +127) */
+	video_panning_factor_y = 0,	/* Video mode y panning value (-127 +127) */
+	console_col = 0,		/* Cursor col */
+	console_row = 0,		/* Cursor row */
+	video_palette[16];		/* Our palette */
+
+static const int video_font_draw_table[] =
+	{ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff };
+
+static char
+	video_color_fg = 0,		/* Current fg color index (0-15) */
+	video_color_bg = 0,		/* Current bg color index (0-15) */
+	video_enable = 0;		/* Video has been initialized? */
+
+static void
+	*video_fb_address,		/* Frame buffer address */
+	*video_console_address;		/* Console frame buffer start address */
+
+/************************************************************************/
+/* ** MEMORY FUNCTIONS (32bit)						*/
+/************************************************************************/
+
+static void memsetl (int *p, int c, int v)
+{
+	while (c--)
+		*(p++) = v;
+}
+
+static void memcpyl (int *d, int *s, int c)
+{
+	while (c--)
+		*(d++) = *(s++);
+}
+
+/************************************************************************/
+/* ** VIDEO DRAWING AND COLOR FUNCTIONS					*/
+/************************************************************************/
+
+static int video_maprgb (int r, int g, int b)
+{
+#ifdef VIDEO_MODE_YUYV
+	unsigned int pR, pG, pB;
+	tYUYV YUYV;
+	unsigned int *ret = (unsigned int *) &YUYV;
+
+	/* Transform (0-255) components to (0-100) */
+
+	pR = r * 100 / 255;
+	pG = g * 100 / 255;
+	pB = b * 100 / 255;
+
+	/* Calculate YUV values (0-255) from RGB beetween 0-100 */
+
+	YUYV.Y1 = YUYV.Y2 = 209 * (pR + pG + pB) / 300 + 16;
+	YUYV.U	= pR - (pG * 3 / 4) - (pB / 4) + 128;
+	YUYV.V	= pB - (pR / 4) - (pG * 3 / 4) + 128;
+	return *ret;
+#endif
+#ifdef VIDEO_MODE_RGB
+	return ((r >> 3) << 11) | ((g > 2) << 6) | (b >> 3);
+#endif
+}
+
+static void video_setpalette (int color, int r, int g, int b)
+{
+	color &= 0xf;
+
+	video_palette[color] = video_maprgb (r, g, b);
+
+	/* Swap values if our panning offset is odd */
+	if (video_panning_value_x & 1)
+		video_palette[color] = SWAPINT (video_palette[color]);
+}
+
+static void video_fill (int color)
+{
+	memsetl (video_fb_address, VIDEO_PIX_BLOCKS, color);
+}
+
+static void video_setfgcolor (int i)
+{
+	video_color_fg = i & 0xf;
+}
+
+static void video_setbgcolor (int i)
+{
+	video_color_bg = i & 0xf;
+}
+
+static int video_pickcolor (int i)
+{
+	return video_palette[i & 0xf];
+}
+
+/* Absolute console plotting functions */
+
+#ifdef VIDEO_BLINK
+static void video_revchar (int xx, int yy)
+{
+	int rows;
+	u8 *dest;
+
+	dest = video_fb_address + yy * VIDEO_LINE_LEN + xx * 2;
+
+	for (rows = VIDEO_FONT_HEIGHT; rows--; dest += VIDEO_LINE_LEN) {
+		switch (VIDEO_FONT_WIDTH) {
+		case 16:
+			((u32 *) dest)[6] ^= 0xffffffff;
+			((u32 *) dest)[7] ^= 0xffffffff;
+			/* FALL THROUGH */
+		case 12:
+			((u32 *) dest)[4] ^= 0xffffffff;
+			((u32 *) dest)[5] ^= 0xffffffff;
+			/* FALL THROUGH */
+		case 8:
+			((u32 *) dest)[2] ^= 0xffffffff;
+			((u32 *) dest)[3] ^= 0xffffffff;
+			/* FALL THROUGH */
+		case 4:
+			((u32 *) dest)[0] ^= 0xffffffff;
+			((u32 *) dest)[1] ^= 0xffffffff;
+		}
+	}
+}
+#endif
+
+static void video_drawchars (int xx, int yy, unsigned char *s, int count)
+{
+	u8 *cdat, *dest, *dest0;
+	int rows, offset, c;
+	u32 eorx, fgx, bgx;
+
+	offset = yy * VIDEO_LINE_LEN + xx * 2;
+	dest0 = video_fb_address + offset;
+
+	fgx = video_pickcolor (video_color_fg);
+	bgx = video_pickcolor (video_color_bg);
+
+	if (xx & 1) {
+		fgx = SWAPINT (fgx);
+		bgx = SWAPINT (bgx);
+	}
+
+	eorx = fgx ^ bgx;
+
+	switch (VIDEO_FONT_WIDTH) {
+	case 4:
+	case 8:
+		while (count--) {
+			c = *s;
+			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
+			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
+			     rows--;
+			     dest += VIDEO_LINE_LEN) {
+				u8 bits = *cdat++;
+
+				((u32 *) dest)[0] =
+					(video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+				((u32 *) dest)[1] =
+					(video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+				if (VIDEO_FONT_WIDTH == 8) {
+					((u32 *) dest)[2] =
+						(video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+					((u32 *) dest)[3] =
+						(video_font_draw_table[bits & 3] & eorx) ^ bgx;
+				}
+			}
+			dest0 += VIDEO_FONT_WIDTH * 2;
+			s++;
+		}
+		break;
+	case 12:
+	case 16:
+		while (count--) {
+			cdat = video_fontdata + (*s) * (VIDEO_FONT_HEIGHT << 1);
+			for (rows = VIDEO_FONT_HEIGHT, dest = dest0; rows--;
+				 dest += VIDEO_LINE_LEN) {
+				u8 bits = *cdat++;
+
+				((u32 *) dest)[0] =
+					(video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+				((u32 *) dest)[1] =
+					(video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+				((u32 *) dest)[2] =
+					(video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+				((u32 *) dest)[3] =
+					(video_font_draw_table[bits & 3] & eorx) ^ bgx;
+				bits = *cdat++;
+				((u32 *) dest)[4] =
+					(video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+				((u32 *) dest)[5] =
+					(video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+				if (VIDEO_FONT_WIDTH == 16) {
+					((u32 *) dest)[6] =
+						(video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+					((u32 *) dest)[7] =
+						(video_font_draw_table[bits & 3] & eorx) ^ bgx;
+				}
+			}
+			s++;
+			dest0 += VIDEO_FONT_WIDTH * 2;
+		}
+		break;
+	}
+}
+
+static inline void video_drawstring (int xx, int yy, char *s)
+{
+	video_drawchars (xx, yy, (unsigned char *)s, strlen (s));
+}
+
+/* Relative to console plotting functions */
+
+static void video_putchars (int xx, int yy, unsigned char *s, int count)
+{
+#ifdef CONFIG_VIDEO_LOGO
+	video_drawchars (xx, yy + VIDEO_LOGO_HEIGHT, s, count);
+#else
+	video_drawchars (xx, yy, s, count);
+#endif
+}
+
+static void video_putchar (int xx, int yy, unsigned char c)
+{
+#ifdef CONFIG_VIDEO_LOGO
+	video_drawchars (xx, yy + VIDEO_LOGO_HEIGHT, &c, 1);
+#else
+	video_drawchars (xx, yy, &c, 1);
+#endif
+}
+
+static inline void video_putstring (int xx, int yy, unsigned char *s)
+{
+	video_putchars (xx, yy, (unsigned char *)s, strlen ((char *)s));
+}
+
+/************************************************************************/
+/* ** VIDEO CONTROLLER LOW-LEVEL FUNCTIONS				*/
+/************************************************************************/
+
+#if !defined(CONFIG_RRVISION)
+static void video_mode_dupefield (VRAM * source, VRAM * dest, int entries)
+{
+	int i;
+
+	for (i = 0; i < entries; i++) {
+		dest[i] = source[i];	/* Copy the entire record */
+		dest[i].fx = (!dest[i].fx) * 3;	/* Negate field bit */
+	}
+
+	dest[0].lcyc++;			/* Add a cycle to the first entry */
+	dest[entries - 1].lst = 1;	/* Set end of ram entries */
+}
+#endif
+
+static void inline video_mode_addentry (VRAM * vr,
+	int Hx, int Vx, int Fx, int Bx,
+	int VDS, int INT, int LCYC, int LP, int LST)
+{
+	vr->hx = Hx;
+	vr->vx = Vx;
+	vr->fx = Fx;
+	vr->bx = Bx;
+	vr->vds = VDS;
+	vr->inter = INT;
+	vr->lcyc = LCYC;
+	vr->lp = LP;
+	vr->lst = LST;
+}
+
+#define ADDENTRY(a,b,c,d,e,f,g,h,i)	video_mode_addentry(&vr[entry++],a,b,c,d,e,f,g,h,i)
+
+static int video_mode_generate (void)
+{
+	immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	VRAM *vr = (VRAM *) (((void *) immap) + 0xb00);	/* Pointer to the VRAM table */
+	int DX, X1, X2, DY, Y1, Y2, entry = 0, fifo;
+
+	/* CHECKING PARAMETERS */
+
+	if (video_panning_factor_y < -128)
+		video_panning_factor_y = -128;
+
+	if (video_panning_factor_y > 128)
+		video_panning_factor_y = 128;
+
+	if (video_panning_factor_x < -128)
+		video_panning_factor_x = -128;
+
+	if (video_panning_factor_x > 128)
+		video_panning_factor_x = 128;
+
+	/* Setting panning */
+
+	DX = video_panning_range_x = (VIDEO_ACTIVE_COLS - VIDEO_COLS) * 2;
+	DY = video_panning_range_y = (VIDEO_ACTIVE_ROWS - VIDEO_ROWS) / 2;
+
+	video_panning_value_x = (video_panning_factor_x + 128) * DX / 256;
+	video_panning_value_y = (video_panning_factor_y + 128) * DY / 256;
+
+	/* We assume these are burst units (multiplied by 2, we need it pari) */
+	X1 = video_panning_value_x & 0xfffe;
+	X2 = DX - X1;
+
+	/* We assume these are field line units (divided by 2, we need it pari) */
+	Y1 = video_panning_value_y & 0xfffe;
+	Y2 = DY - Y1;
+
+	debug("X1=%d, X2=%d, Y1=%d, Y2=%d, DX=%d, DY=%d VIDEO_COLS=%d \n",
+	      X1, X2, Y1, Y2, DX, DY, VIDEO_COLS);
+
+#ifdef VIDEO_MODE_NTSC
+/*
+ *	     Hx Vx Fx Bx VDS INT LCYC LP LST
+ *
+ * Retrace blanking
+ */
+	ADDENTRY (0, 0, 3, 0, 1, 0, 3, 1, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Vertical blanking
+ */
+	ADDENTRY (0, 0, 0, 0, 1, 0, 18, 1, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 243, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+/*
+ * Odd field active area (TOP)
+ */
+	if (Y1 > 0) {
+		ADDENTRY (0, 0, 0, 0, 1, 0, Y1, 1, 0);
+		ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+		ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+		ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+	}
+/*
+ * Odd field active area
+ */
+	ADDENTRY (0, 0, 0, 0, 1, 0, 240 - DY, 1, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 1, 0, 8 + X1, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+	if (X2 > 0)
+		ADDENTRY (3, 0, 0, 3, 1, 0, X2, 0, 0);
+
+	ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+
+/*
+ * Odd field active area (BOTTOM)
+ */
+	if (Y1 > 0) {
+		ADDENTRY (0, 0, 0, 0, 1, 0, Y2, 1, 0);
+		ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+		ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+		ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+	}
+/*
+ * Vertical blanking
+ */
+	ADDENTRY (0, 0, 0, 0, 1, 0, 4, 1, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 243, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+/*
+ * Vertical blanking
+ */
+	ADDENTRY (0, 0, 3, 0, 1, 0, 19, 1, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Even field active area (TOP)
+ */
+	if (Y1 > 0) {
+		ADDENTRY (0, 0, 3, 0, 1, 0, Y1, 1, 0);
+		ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+		ADDENTRY (3, 0, 3, 3, 1, 0, 1448, 0, 0);
+		ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+	}
+/*
+ * Even field active area (CENTER)
+ */
+	ADDENTRY (0, 0, 3, 0, 1, 0, 240 - DY, 1, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+	ADDENTRY (3, 0, 3, 3, 1, 0, 8 + X1, 0, 0);
+	ADDENTRY (3, 0, 3, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+	if (X2 > 0)
+		ADDENTRY (3, 0, 3, 3, 1, 0, X2, 0, 0);
+
+	ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Even field active area (BOTTOM)
+ */
+	if (Y1 > 0) {
+		ADDENTRY (0, 0, 3, 0, 1, 0, Y2, 1, 0);
+		ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+		ADDENTRY (3, 0, 3, 3, 1, 0, 1448, 0, 0);
+		ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+	}
+/*
+ * Vertical blanking
+ */
+	ADDENTRY (0, 0, 3, 0, 1, 0, 1, 1, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 3, 0, 1, 1, 32, 1, 1);
+#endif
+
+#ifdef VIDEO_MODE_PAL
+
+#if defined(CONFIG_RRVISION)
+
+#define HPW   160  /* horizontal pulse width (was 139)	*/
+#define VPW	2  /* vertical pulse width		*/
+#define HBP   104  /* horizontal back porch (was 112)	*/
+#define VBP    19  /* vertical back porch (was 19)	*/
+#define VID_R 240  /* number of rows			*/
+
+	debug ("[VIDEO CTRL] Starting to add controller entries...");
+/*
+ * Even field
+ */
+	ADDENTRY (0, 3, 0, 3, 1, 0, 2, 0, 0);
+	ADDENTRY (0, 0, 0, 3, 1, 0, HPW, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 0, 0);
+
+	ADDENTRY (0, 0, 0, 3, 1, 0, VPW, 1, 0);
+	ADDENTRY (0, 0, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+
+	ADDENTRY (0, 3, 0, 3, 1, 0, VBP, 1, 0);
+	ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+/*
+ * Active area
+ */
+	ADDENTRY (0, 3, 0, 3, 1, 0, VID_R , 1, 0);
+	ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, HBP, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 0, 0, VIDEO_COLS*2, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, 72, 1, 1);
+
+	ADDENTRY (0, 3, 0, 3, 1, 0, 51, 1, 0);
+	ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, HBP +(VIDEO_COLS * 2) + 72 , 1, 0);
+/*
+ * Odd field
+ */
+	ADDENTRY (0, 3, 0, 3, 1, 0, 2, 0, 0);
+	ADDENTRY (0, 0, 0, 3, 1, 0, HPW, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 0, 0);
+
+	ADDENTRY (0, 0, 0, 3, 1, 0, VPW+1, 1, 0);
+	ADDENTRY (0, 0, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+
+	ADDENTRY (0, 3, 0, 3, 1, 0, VBP, 1, 0);
+	ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+/*
+ * Active area
+ */
+	ADDENTRY (0, 3, 0, 3, 1, 0, VID_R , 1, 0);
+	ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, HBP, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 0, 0, VIDEO_COLS*2, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, 72, 1, 1);
+
+	ADDENTRY (0, 3, 0, 3, 1, 0, 51, 1, 0);
+	ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+	ADDENTRY (3, 3, 0, 3, 1, 0, HBP +(VIDEO_COLS * 2) + 72 , 1, 0);
+
+	debug ("done\n");
+
+#else  /* !CONFIG_RRVISION */
+
+/*
+ *	Hx Vx Fx Bx VDS INT LCYC LP LST
+ *
+ * vertical; blanking
+ */
+	ADDENTRY (0, 0, 0, 0, 1, 0, 22, 1, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 263, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * active area (TOP)
+ */
+	if (Y1 > 0) {
+		ADDENTRY (0, 0, 0, 0, 1, 0, Y1, 1, 0);	/* 11? */
+		ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+		ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+		ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+	}
+/*
+ * field active area (CENTER)
+ */
+	ADDENTRY (0, 0, 0, 0, 1, 0, 288 - DY, 1, 0);	/* 265? */
+	ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 1, 0, 8 + X1, 0, 0);
+	ADDENTRY (3, 0, 0, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+	if (X2 > 0)
+		ADDENTRY (3, 0, 0, 1, 1, 0, X2, 0, 0);
+
+	ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * field active area (BOTTOM)
+ */
+	if (Y2 > 0) {
+		ADDENTRY (0, 0, 0, 0, 1, 0, Y2, 1, 0);	/* 12? */
+		ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+		ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+		ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+	}
+/*
+ * field vertical; blanking
+ */
+	ADDENTRY (0, 0, 0, 0, 1, 0, 2, 1, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 263, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+	ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * Create the other field (like this, but whit other field selected,
+ * one more cycle loop and a last identifier)
+ */
+	video_mode_dupefield (vr, &vr[entry], entry);
+#endif /* CONFIG_RRVISION */
+
+#endif /* VIDEO_MODE_PAL */
+
+	/* See what FIFO are we using */
+	fifo = GETBIT (immap->im_vid.vid_vsr, VIDEO_VSR_CAS);
+
+	/* Set number of lines and burst (only one frame for now) */
+	if (fifo) {
+		immap->im_vid.vid_vfcr0 = VIDEO_BURST_LEN |
+			(VIDEO_BURST_LEN << 8) | ((VIDEO_ROWS / 2) << 19);
+	} else {
+		immap->im_vid.vid_vfcr1 = VIDEO_BURST_LEN |
+			(VIDEO_BURST_LEN << 8) | ((VIDEO_ROWS / 2) << 19);
+	}
+
+	SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_ASEL, !fifo);
+
+/*
+ * Wait until changes are applied (not done)
+ * while (GETBIT(immap->im_vid.vid_vsr, VIDEO_VSR_CAS) == fifo) ;
+ */
+
+	/* Return number of VRAM entries */
+	return entry * 2;
+}
+
+static void video_encoder_init (void)
+{
+#ifdef VIDEO_I2C
+	int rc;
+
+	/* Initialize the I2C */
+	debug ("[VIDEO ENCODER] Initializing I2C bus...\n");
+	i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+#ifdef CONFIG_FADS
+	/* Reset ADV7176 chip */
+	debug ("[VIDEO ENCODER] Resetting encoder...\n");
+	(*(int *) BCSR4) &= ~(1 << 21);
+
+	/* Wait for 5 ms inside the reset */
+	debug ("[VIDEO ENCODER] Waiting for encoder reset...\n");
+	udelay (5000);
+
+	/* Take ADV7176 out of reset */
+	(*(int *) BCSR4) |= 1 << 21;
+
+	/* Wait for 5 ms after the reset */
+	udelay (5000);
+#endif	/* CONFIG_FADS */
+
+	/* Send configuration */
+#ifdef DEBUG
+	{
+		int i;
+
+		puts ("[VIDEO ENCODER] Configuring the encoder...\n");
+
+		printf ("Sending %zu bytes (@ %08lX) to I2C 0x%lX:\n   ",
+			sizeof(video_encoder_data),
+			(ulong)video_encoder_data,
+			(ulong)VIDEO_I2C_ADDR);
+		for (i=0; i<sizeof(video_encoder_data); ++i) {
+			printf(" %02X", video_encoder_data[i]);
+		}
+		putc ('\n');
+	}
+#endif	/* DEBUG */
+
+	if ((rc = i2c_write (VIDEO_I2C_ADDR, 0, 1,
+			 video_encoder_data,
+			 sizeof(video_encoder_data))) != 0) {
+		printf ("i2c_send error: rc=%d\n", rc);
+		return;
+	}
+#endif	/* VIDEO_I2C */
+	return;
+}
+
+static void video_ctrl_init (void *memptr)
+{
+	immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	video_fb_address = memptr;
+
+	/* Set background */
+	debug ("[VIDEO CTRL] Setting background color...\n");
+	immap->im_vid.vid_vbcb = VIDEO_BG_COL;
+
+	/* Show the background */
+	debug ("[VIDEO CTRL] Forcing background...\n");
+	SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_BD, 1);
+
+	/* Turn off video controller */
+	debug ("[VIDEO CTRL] Turning off video controller...\n");
+	SETBIT (immap->im_vid.vid_vccr, VIDEO_VCCR_VON, 0);
+
+#ifdef CONFIG_FADS
+	/* Turn on Video Port LED */
+	debug ("[VIDEO CTRL] Turning off video port led...\n");
+	SETBIT (*(int *) BCSR4, VIDEO_BCSR4_VIDLED_BIT, 1);
+
+	/* Disable internal clock */
+	debug ("[VIDEO CTRL] Disabling internal clock...\n");
+	SETBIT (*(int *) BCSR4, VIDEO_BCSR4_EXTCLK_BIT, 0);
+#endif
+
+	/* Generate and make active a new video mode */
+	debug ("[VIDEO CTRL] Generating video mode...\n");
+	video_mode_generate ();
+
+	/* Start of frame buffer (even and odd frame, to make it working with */
+	/* any selected active set) */
+	debug ("[VIDEO CTRL] Setting frame buffer address...\n");
+	immap->im_vid.vid_vfaa1 =
+		immap->im_vid.vid_vfaa0 = (u32) video_fb_address;
+	immap->im_vid.vid_vfba1 =
+	immap->im_vid.vid_vfba0 =
+		(u32) video_fb_address + VIDEO_LINE_LEN;
+
+	/* YUV, Big endian, SHIFT/CLK/CLK input (BEFORE ENABLING 27MHZ EXT CLOCK) */
+	debug ("[VIDEO CTRL] Setting pixel mode and clocks...\n");
+	immap->im_vid.vid_vccr = 0x2042;
+
+	/* Configure port pins */
+	debug ("[VIDEO CTRL] Configuring input/output pins...\n");
+	immap->im_ioport.iop_pdpar = 0x1fff;
+	immap->im_ioport.iop_pddir = 0x0000;
+
+#ifdef CONFIG_FADS
+	/* Turn on Video Port Clock - ONLY AFTER SET VCCR TO ENABLE EXTERNAL CLOCK */
+	debug ("[VIDEO CTRL] Turning on video clock...\n");
+	SETBIT (*(int *) BCSR4, VIDEO_BCSR4_EXTCLK_BIT, 1);
+
+	/* Turn on Video Port LED */
+	debug ("[VIDEO CTRL] Turning on video port led...\n");
+	SETBIT (*(int *) BCSR4, VIDEO_BCSR4_VIDLED_BIT, 0);
+#endif
+#ifdef CONFIG_RRVISION
+	debug ("PC5->Output(1): enable PAL clock");
+	immap->im_ioport.iop_pcpar &= ~(0x0400);
+	immap->im_ioport.iop_pcdir |=   0x0400 ;
+	immap->im_ioport.iop_pcdat |=   0x0400 ;
+	debug ("PDPAR=0x%04X PDDIR=0x%04X PDDAT=0x%04X\n",
+	       immap->im_ioport.iop_pdpar,
+	       immap->im_ioport.iop_pddir,
+	       immap->im_ioport.iop_pddat);
+	debug ("PCPAR=0x%04X PCDIR=0x%04X PCDAT=0x%04X\n",
+	       immap->im_ioport.iop_pcpar,
+	       immap->im_ioport.iop_pcdir,
+	       immap->im_ioport.iop_pcdat);
+#endif	/* CONFIG_RRVISION */
+
+	/* Blanking the screen. */
+	debug ("[VIDEO CTRL] Blanking the screen...\n");
+	video_fill (VIDEO_BG_COL);
+
+	/*
+	 * Turns on Aggressive Mode. Normally, turning on the caches
+	 * will cause the screen to flicker when the caches try to
+	 * fill. This gives the FIFO's for the Video Controller
+	 * higher priority and prevents flickering because of
+	 * underrun. This may still be an issue when using FLASH,
+	 * since accessing data from Flash is so slow.
+	 */
+	debug ("[VIDEO CTRL] Turning on aggressive mode...\n");
+	immap->im_siu_conf.sc_sdcr = 0x40;
+
+	/* Turn on video controller */
+	debug ("[VIDEO CTRL] Turning on video controller...\n");
+	SETBIT (immap->im_vid.vid_vccr, VIDEO_VCCR_VON, 1);
+
+	/* Show the display */
+	debug ("[VIDEO CTRL] Enabling the video...\n");
+	SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_BD, 0);
+}
+
+/************************************************************************/
+/* ** CONSOLE FUNCTIONS							*/
+/************************************************************************/
+
+static void console_scrollup (void)
+{
+	/* Copy up rows ignoring the first one */
+	memcpyl (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE >> 2);
+
+	/* Clear the last one */
+	memsetl (CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, VIDEO_BG_COL);
+}
+
+static inline void console_back (void)
+{
+	console_col--;
+
+	if (console_col < 0) {
+		console_col = CONSOLE_COLS - 1;
+		console_row--;
+		if (console_row < 0)
+			console_row = 0;
+	}
+
+	video_putchar ( console_col * VIDEO_FONT_WIDTH,
+			console_row * VIDEO_FONT_HEIGHT, ' ');
+}
+
+static inline void console_newline (void)
+{
+	console_row++;
+	console_col = 0;
+
+	/* Check if we need to scroll the terminal */
+	if (console_row >= CONSOLE_ROWS) {
+		/* Scroll everything up */
+		console_scrollup ();
+
+		/* Decrement row number */
+		console_row--;
+	}
+}
+
+void video_putc (const char c)
+{
+	if (!video_enable) {
+		serial_putc (c);
+		return;
+	}
+
+	switch (c) {
+	case 13:			/* Simply ignore this */
+		break;
+
+	case '\n':			/* Next line, please */
+		console_newline ();
+		break;
+
+	case 9:				/* Tab (8 chars alignment) */
+		console_col |= 0x0008;	/* Next 8 chars boundary */
+		console_col &= ~0x0007;	/* Set this bit to zero */
+
+		if (console_col >= CONSOLE_COLS)
+			console_newline ();
+		break;
+
+	case 8:				/* Eat last character */
+		console_back ();
+		break;
+
+	default:			/* Add to the console */
+		video_putchar ( console_col * VIDEO_FONT_WIDTH,
+				console_row * VIDEO_FONT_HEIGHT, c);
+		console_col++;
+		/* Check if we need to go to next row */
+		if (console_col >= CONSOLE_COLS)
+			console_newline ();
+	}
+}
+
+void video_puts (const char *s)
+{
+	int count = strlen (s);
+
+	if (!video_enable)
+		while (count--)
+			serial_putc (*s++);
+	else
+		while (count--)
+			video_putc (*s++);
+}
+
+/************************************************************************/
+/* ** CURSOR BLINKING FUNCTIONS						*/
+/************************************************************************/
+
+#ifdef VIDEO_BLINK
+
+#define BLINK_TIMER_ID		0
+#define BLINK_TIMER_HZ		2
+
+static unsigned char blink_enabled = 0;
+static timer_t blink_timer;
+
+static void blink_update (void)
+{
+	static int blink_row = -1, blink_col = -1, blink_old = 0;
+
+	/* Check if we have a new position to invert */
+	if ((console_row != blink_row) || (console_col != blink_col)) {
+		/* Check if we need to reverse last character */
+		if (blink_old)
+			video_revchar ( blink_col * VIDEO_FONT_WIDTH,
+					(blink_row
+#ifdef CONFIG_VIDEO_LOGO
+					 + VIDEO_LOGO_HEIGHT
+#endif
+					) * VIDEO_FONT_HEIGHT);
+
+		/* Update values */
+		blink_row = console_row;
+		blink_col = console_col;
+		blink_old = 0;
+	}
+
+/* Reverse this character */
+	blink_old = !blink_old;
+	video_revchar ( console_col * VIDEO_FONT_WIDTH,
+			(console_row
+#ifdef CONFIG_VIDEO_LOGO
+			+ VIDEO_LOGO_HEIGHT
+#endif
+			) * VIDEO_FONT_HEIGHT);
+
+}
+
+/*
+ * Handler for blinking cursor
+ */
+static void blink_handler (void *arg)
+{
+/* Blink */
+	blink_update ();
+/* Ack the timer */
+	timer_ack (&blink_timer);
+}
+
+int blink_set (int blink)
+{
+	int ret = blink_enabled;
+
+	if (blink)
+		timer_enable (&blink_timer);
+	else
+		timer_disable (&blink_timer);
+
+	blink_enabled = blink;
+
+	return ret;
+}
+
+static inline void blink_close (void)
+{
+	timer_close (&blink_timer);
+}
+
+static inline void blink_init (void)
+{
+	timer_init (&blink_timer,
+			BLINK_TIMER_ID, BLINK_TIMER_HZ,
+			blink_handler);
+}
+#endif
+
+/************************************************************************/
+/* ** LOGO PLOTTING FUNCTIONS						*/
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_LOGO
+void easylogo_plot (fastimage_t * image, void *screen, int width, int x,
+					int y)
+{
+	int skip = width - image->width, xcount, ycount = image->height;
+
+#ifdef VIDEO_MODE_YUYV
+	ushort *source = (ushort *) image->data;
+	ushort *dest   = (ushort *) screen + y * width + x;
+
+	while (ycount--) {
+		xcount = image->width;
+		while (xcount--)
+			*dest++ = *source++;
+		dest += skip;
+	}
+#endif
+#ifdef VIDEO_MODE_RGB
+	unsigned char
+	*source = (unsigned short *) image->data,
+			*dest = (unsigned short *) screen + ((y * width) + x) * 3;
+
+	while (ycount--) {
+		xcount = image->width * 3;
+		memcpy (dest, source, xcount);
+		source += xcount;
+		dest += ycount;
+	}
+#endif
+}
+
+static void *video_logo (void)
+{
+	u16 *screen = video_fb_address, width = VIDEO_COLS;
+#ifdef VIDEO_INFO
+# ifndef CONFIG_FADS
+	char temp[32];
+# endif
+	char info[80];
+#endif /* VIDEO_INFO */
+
+	easylogo_plot (VIDEO_LOGO_ADDR, screen, width, 0, 0);
+
+#ifdef VIDEO_INFO
+	sprintf (info, "%s (%s - %s) ",
+		 U_BOOT_VERSION, U_BOOT_DATE, U_BOOT_TIME);
+	video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, info);
+
+	sprintf (info, "(C) 2002 DENX Software Engineering");
+	video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
+					info);
+
+	sprintf (info, "    Wolfgang DENK, wd@denx.de");
+	video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 2,
+					info);
+#ifndef CONFIG_FADS		/* all normal boards */
+	/* leave one blank line */
+
+	sprintf (info, "MPC823 CPU at %s MHz, %ld MB RAM, %ld MB Flash",
+		strmhz(temp, gd->cpu_clk),
+		gd->ram_size >> 20,
+		gd->bd->bi_flashsize >> 20 );
+	video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 4,
+					info);
+#else				/* FADS :-( */
+	sprintf (info, "MPC823 CPU at 50 MHz on FADS823 board");
+	video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
+					  info);
+
+	sprintf (info, "2MB FLASH - 8MB DRAM - 4MB SRAM");
+	video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 2,
+					  info);
+#endif
+#endif
+
+	return video_fb_address + VIDEO_LOGO_HEIGHT * VIDEO_LINE_LEN;
+}
+#endif
+
+/************************************************************************/
+/* ** VIDEO HIGH-LEVEL FUNCTIONS					*/
+/************************************************************************/
+
+static int video_init (void *videobase)
+{
+	/* Initialize the encoder */
+	debug ("[VIDEO] Initializing video encoder...\n");
+	video_encoder_init ();
+
+	/* Initialize the video controller */
+	debug ("[VIDEO] Initializing video controller at %08x...\n",
+		   (int) videobase);
+	video_ctrl_init (videobase);
+
+	/* Setting the palette */
+	video_setpalette  (CONSOLE_COLOR_BLACK,	     0,	   0,	 0);
+	video_setpalette  (CONSOLE_COLOR_RED,	  0xFF,	   0,	 0);
+	video_setpalette  (CONSOLE_COLOR_GREEN,	     0, 0xFF,	 0);
+	video_setpalette  (CONSOLE_COLOR_YELLOW,  0xFF, 0xFF,	 0);
+	video_setpalette  (CONSOLE_COLOR_BLUE,	     0,	   0, 0xFF);
+	video_setpalette  (CONSOLE_COLOR_MAGENTA, 0xFF,	   0, 0xFF);
+	video_setpalette  (CONSOLE_COLOR_CYAN,	     0, 0xFF, 0xFF);
+	video_setpalette  (CONSOLE_COLOR_GREY,	  0xAA, 0xAA, 0xAA);
+	video_setpalette  (CONSOLE_COLOR_GREY2,	  0xF8, 0xF8, 0xF8);
+	video_setpalette  (CONSOLE_COLOR_WHITE,	  0xFF, 0xFF, 0xFF);
+
+#ifndef CONFIG_SYS_WHITE_ON_BLACK
+	video_setfgcolor (CONSOLE_COLOR_BLACK);
+	video_setbgcolor (CONSOLE_COLOR_GREY2);
+#else
+	video_setfgcolor (CONSOLE_COLOR_GREY2);
+	video_setbgcolor (CONSOLE_COLOR_BLACK);
+#endif	/* CONFIG_SYS_WHITE_ON_BLACK */
+
+#ifdef CONFIG_VIDEO_LOGO
+	/* Paint the logo and retrieve tv base address */
+	debug ("[VIDEO] Drawing the logo...\n");
+	video_console_address = video_logo ();
+#else
+	video_console_address = video_fb_address;
+#endif
+
+#ifdef VIDEO_BLINK
+	/* Enable the blinking (under construction) */
+	blink_init ();
+	blink_set (0);				/* To Fix! */
+#endif
+
+	/* Initialize the console */
+	console_col = 0;
+	console_row = 0;
+	video_enable = 1;
+
+#ifdef VIDEO_MODE_PAL
+# define VIDEO_MODE_TMP1	"PAL"
+#endif
+#ifdef VIDEO_MODE_NTSC
+# define VIDEO_MODE_TMP1	"NTSC"
+#endif
+#ifdef VIDEO_MODE_YUYV
+# define VIDEO_MODE_TMP2	"YCbYCr"
+#endif
+#ifdef VIDEO_MODE_RGB
+# define VIDEO_MODE_TMP2	"RGB"
+#endif
+	debug ( VIDEO_MODE_TMP1
+		" %dx%dx%d (" VIDEO_MODE_TMP2 ") on %s - console %dx%d\n",
+			VIDEO_COLS, VIDEO_ROWS, VIDEO_MODE_BPP,
+			VIDEO_ENCODER_NAME, CONSOLE_COLS, CONSOLE_ROWS);
+	return 0;
+}
+
+int drv_video_init (void)
+{
+	int error, devices = 1;
+
+	struct stdio_dev videodev;
+
+	video_init ((void *)(gd->fb_base));	/* Video initialization */
+
+/* Device initialization */
+
+	memset (&videodev, 0, sizeof (videodev));
+
+	strcpy (videodev.name, "video");
+	videodev.ext = DEV_EXT_VIDEO;	/* Video extensions */
+	videodev.flags = DEV_FLAGS_OUTPUT;	/* Output only */
+	videodev.putc = video_putc;	/* 'putc' function */
+	videodev.puts = video_puts;	/* 'puts' function */
+
+	error = stdio_register (&videodev);
+
+	return (error == 0) ? devices : error;
+}
+
+/************************************************************************/
+/* ** ROM capable initialization part - needed to reserve FB memory	*/
+/************************************************************************/
+
+/*
+ * This is called early in the system initialization to grab memory
+ * for the video controller.
+ * Returns new address for monitor, after reserving video buffer memory
+ *
+ * Note that this is running from ROM, so no write access to global data.
+ */
+ulong video_setmem (ulong addr)
+{
+	/* Allocate pages for the frame buffer. */
+	addr -= VIDEO_SIZE;
+
+	debug ("Reserving %dk for Video Framebuffer at: %08lx\n",
+		VIDEO_SIZE>>10, addr);
+
+	return (addr);
+}
+
+#endif
diff --git a/arch/ppc/cpu/mpc8xx/wlkbd.c b/arch/ppc/cpu/mpc8xx/wlkbd.c
new file mode 100644
index 0000000..13009e2
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xx/wlkbd.c
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * 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 <config.h>
+
+#ifdef CONFIG_WL_4PPM_KEYBOARD
+
+/* WIP: Wireless keyboard on SMC
+ */
+int	drv_wlkbd_init (void)
+{
+    return 0 ;
+}
+
+#endif	/* CONFIG_WL_4PPM_KEYBOARD */
diff --git a/arch/ppc/cpu/mpc8xxx/Makefile b/arch/ppc/cpu/mpc8xxx/Makefile
new file mode 100644
index 0000000..481f9e5
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/Makefile
@@ -0,0 +1,27 @@
+#
+# Copyright 2009 Freescale Semiconductor, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# Version 2 as published by the Free Software Foundation.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib8xxx.a
+
+COBJS-y	+= cpu.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-$(CONFIG_PCI)	+= pci_cfg.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/arch/ppc/cpu/mpc8xxx/cpu.c b/arch/ppc/cpu/mpc8xxx/cpu.c
new file mode 100644
index 0000000..fef062b
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/cpu.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is derived from arch/ppc/cpu/mpc85xx/cpu.c and
+ * arch/ppc/cpu/mpc86xx/cpu.c. Basically this file contains
+ * cpu specific common code for 85xx/86xx processors.
+ * 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 <common.h>
+#include <command.h>
+#include <tsec.h>
+#include <netdev.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct cpu_type cpu_type_list [] = {
+#if defined(CONFIG_MPC85xx)
+	CPU_TYPE_ENTRY(8533, 8533, 1),
+	CPU_TYPE_ENTRY(8533, 8533_E, 1),
+	CPU_TYPE_ENTRY(8535, 8535, 1),
+	CPU_TYPE_ENTRY(8535, 8535_E, 1),
+	CPU_TYPE_ENTRY(8536, 8536, 1),
+	CPU_TYPE_ENTRY(8536, 8536_E, 1),
+	CPU_TYPE_ENTRY(8540, 8540, 1),
+	CPU_TYPE_ENTRY(8541, 8541, 1),
+	CPU_TYPE_ENTRY(8541, 8541_E, 1),
+	CPU_TYPE_ENTRY(8543, 8543, 1),
+	CPU_TYPE_ENTRY(8543, 8543_E, 1),
+	CPU_TYPE_ENTRY(8544, 8544, 1),
+	CPU_TYPE_ENTRY(8544, 8544_E, 1),
+	CPU_TYPE_ENTRY(8545, 8545, 1),
+	CPU_TYPE_ENTRY(8545, 8545_E, 1),
+	CPU_TYPE_ENTRY(8547, 8547_E, 1),
+	CPU_TYPE_ENTRY(8548, 8548, 1),
+	CPU_TYPE_ENTRY(8548, 8548_E, 1),
+	CPU_TYPE_ENTRY(8555, 8555, 1),
+	CPU_TYPE_ENTRY(8555, 8555_E, 1),
+	CPU_TYPE_ENTRY(8560, 8560, 1),
+	CPU_TYPE_ENTRY(8567, 8567, 1),
+	CPU_TYPE_ENTRY(8567, 8567_E, 1),
+	CPU_TYPE_ENTRY(8568, 8568, 1),
+	CPU_TYPE_ENTRY(8568, 8568_E, 1),
+	CPU_TYPE_ENTRY(8569, 8569, 1),
+	CPU_TYPE_ENTRY(8569, 8569_E, 1),
+	CPU_TYPE_ENTRY(8572, 8572, 2),
+	CPU_TYPE_ENTRY(8572, 8572_E, 2),
+	CPU_TYPE_ENTRY(P1011, P1011, 1),
+	CPU_TYPE_ENTRY(P1011, P1011_E, 1),
+	CPU_TYPE_ENTRY(P1012, P1012, 1),
+	CPU_TYPE_ENTRY(P1012, P1012_E, 1),
+	CPU_TYPE_ENTRY(P1013, P1013, 1),
+	CPU_TYPE_ENTRY(P1013, P1013_E, 1),
+	CPU_TYPE_ENTRY(P1020, P1020, 2),
+	CPU_TYPE_ENTRY(P1020, P1020_E, 2),
+	CPU_TYPE_ENTRY(P1021, P1021, 2),
+	CPU_TYPE_ENTRY(P1021, P1021_E, 2),
+	CPU_TYPE_ENTRY(P1022, P1022, 2),
+	CPU_TYPE_ENTRY(P1022, P1022_E, 2),
+	CPU_TYPE_ENTRY(P2010, P2010, 1),
+	CPU_TYPE_ENTRY(P2010, P2010_E, 1),
+	CPU_TYPE_ENTRY(P2020, P2020, 2),
+	CPU_TYPE_ENTRY(P2020, P2020_E, 2),
+	CPU_TYPE_ENTRY(P4040, P4040, 4),
+	CPU_TYPE_ENTRY(P4040, P4040_E, 4),
+	CPU_TYPE_ENTRY(P4080, P4080, 8),
+	CPU_TYPE_ENTRY(P4080, P4080_E, 8),
+#elif defined(CONFIG_MPC86xx)
+	CPU_TYPE_ENTRY(8610, 8610, 1),
+	CPU_TYPE_ENTRY(8641, 8641, 2),
+	CPU_TYPE_ENTRY(8641D, 8641D, 2),
+#endif
+};
+
+struct cpu_type cpu_type_unknown = CPU_TYPE_ENTRY(Unknown, Unknown, 1);
+
+struct cpu_type *identify_cpu(u32 ver)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++) {
+		if (cpu_type_list[i].soc_ver == ver)
+			return &cpu_type_list[i];
+	}
+	return &cpu_type_unknown;
+}
+
+int cpu_numcores() {
+	struct cpu_type *cpu;
+	cpu = gd->cpu;
+	return cpu->num_cores;
+}
+
+int probecpu (void)
+{
+	uint svr;
+	uint ver;
+
+	svr = get_svr();
+	ver = SVR_SOC_VER(svr);
+
+	gd->cpu = identify_cpu(ver);
+
+	return 0;
+}
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_ETHER_ON_FCC)
+	fec_initialize(bis);
+#endif
+
+#if defined(CONFIG_UEC_ETH)
+	uec_standard_init(bis);
+#endif
+
+#if defined(CONFIG_TSEC_ENET) || defined(CONFIG_MPC85XX_FEC)
+	tsec_standard_init(bis);
+#endif
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/Makefile b/arch/ppc/cpu/mpc8xxx/ddr/Makefile
new file mode 100644
index 0000000..cb7f856
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/Makefile
@@ -0,0 +1,35 @@
+#
+# Copyright 2008 Freescale Semiconductor, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# Version 2 as published by the Free Software Foundation.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)libddr.a
+
+COBJS-$(CONFIG_FSL_DDR1)	+= main.o util.o ctrl_regs.o options.o \
+				   lc_common_dimm_params.o
+COBJS-$(CONFIG_FSL_DDR1)	+= ddr1_dimm_params.o
+
+COBJS-$(CONFIG_FSL_DDR2)	+= main.o util.o ctrl_regs.o options.o \
+				   lc_common_dimm_params.o
+COBJS-$(CONFIG_FSL_DDR2)	+= ddr2_dimm_params.o
+
+COBJS-$(CONFIG_FSL_DDR3)	+= main.o util.o ctrl_regs.o options.o \
+				   lc_common_dimm_params.o
+COBJS-$(CONFIG_FSL_DDR3)	+= ddr3_dimm_params.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/common_timing_params.h b/arch/ppc/cpu/mpc8xxx/ddr/common_timing_params.h
new file mode 100644
index 0000000..5aea517
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/common_timing_params.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef COMMON_TIMING_PARAMS_H
+#define COMMON_TIMING_PARAMS_H
+
+typedef struct {
+	/* parameters to constrict */
+
+	unsigned int tCKmin_X_ps;
+	unsigned int tCKmax_ps;
+	unsigned int tCKmax_max_ps;
+	unsigned int tRCD_ps;
+	unsigned int tRP_ps;
+	unsigned int tRAS_ps;
+
+	unsigned int tWR_ps;	/* maximum = 63750 ps */
+	unsigned int tWTR_ps;	/* maximum = 63750 ps */
+	unsigned int tRFC_ps;	/* maximum = 255 ns + 256 ns + .75 ns
+					   = 511750 ps */
+
+	unsigned int tRRD_ps;	/* maximum = 63750 ps */
+	unsigned int tRC_ps;	/* maximum = 254 ns + .75 ns = 254750 ps */
+
+	unsigned int refresh_rate_ps;
+
+	unsigned int tIS_ps;	/* byte 32, spd->ca_setup */
+	unsigned int tIH_ps;	/* byte 33, spd->ca_hold */
+	unsigned int tDS_ps;	/* byte 34, spd->data_setup */
+	unsigned int tDH_ps;	/* byte 35, spd->data_hold */
+	unsigned int tRTP_ps;	/* byte 38, spd->trtp */
+	unsigned int tDQSQ_max_ps;	/* byte 44, spd->tdqsq */
+	unsigned int tQHS_ps;	/* byte 45, spd->tqhs */
+
+	unsigned int ndimms_present;
+	unsigned int lowest_common_SPD_caslat;
+	unsigned int highest_common_derated_caslat;
+	unsigned int additive_latency;
+	unsigned int all_DIMMs_burst_lengths_bitmask;
+	unsigned int all_DIMMs_registered;
+	unsigned int all_DIMMs_unbuffered;
+	unsigned int all_DIMMs_ECC_capable;
+
+	unsigned long long total_mem;
+	unsigned long long base_address;
+} common_timing_params_t;
+
+#endif
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/ppc/cpu/mpc8xxx/ddr/ctrl_regs.c
new file mode 100644
index 0000000..03f9c43
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -0,0 +1,1366 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, 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.
+ */
+
+/*
+ * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+extern unsigned int picos_to_mclk(unsigned int picos);
+/*
+ * Determine Rtt value.
+ *
+ * This should likely be either board or controller specific.
+ *
+ * Rtt(nominal) - DDR2:
+ *	0 = Rtt disabled
+ *	1 = 75 ohm
+ *	2 = 150 ohm
+ *	3 = 50 ohm
+ * Rtt(nominal) - DDR3:
+ *	0 = Rtt disabled
+ *	1 = 60 ohm
+ *	2 = 120 ohm
+ *	3 = 40 ohm
+ *	4 = 20 ohm
+ *	5 = 30 ohm
+ *
+ * FIXME: Apparently 8641 needs a value of 2
+ * FIXME: Old code seys if 667 MHz or higher, use 3 on 8572
+ *
+ * FIXME: There was some effort down this line earlier:
+ *
+ *	unsigned int i;
+ *	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL/2; i++) {
+ *		if (popts->dimmslot[i].num_valid_cs
+ *		    && (popts->cs_local_opts[2*i].odt_rd_cfg
+ *			|| popts->cs_local_opts[2*i].odt_wr_cfg)) {
+ *			rtt = 2;
+ *			break;
+ *		}
+ *	}
+ */
+static inline int fsl_ddr_get_rtt(void)
+{
+	int rtt;
+
+#if defined(CONFIG_FSL_DDR1)
+	rtt = 0;
+#elif defined(CONFIG_FSL_DDR2)
+	rtt = 3;
+#else
+	rtt = 0;
+#endif
+
+	return rtt;
+}
+
+/*
+ * compute the CAS write latency according to DDR3 spec
+ * CWL = 5 if tCK >= 2.5ns
+ *       6 if 2.5ns > tCK >= 1.875ns
+ *       7 if 1.875ns > tCK >= 1.5ns
+ *       8 if 1.5ns > tCK >= 1.25ns
+ */
+static inline unsigned int compute_cas_write_latency(void)
+{
+	unsigned int cwl;
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+
+	if (mclk_ps >= 2500)
+		cwl = 5;
+	else if (mclk_ps >= 1875)
+		cwl = 6;
+	else if (mclk_ps >= 1500)
+		cwl = 7;
+	else if (mclk_ps >= 1250)
+		cwl = 8;
+	else
+		cwl = 8;
+	return cwl;
+}
+
+/* Chip Select Configuration (CSn_CONFIG) */
+static void set_csn_config(int i, fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const dimm_params_t *dimm_params)
+{
+	unsigned int cs_n_en = 0; /* Chip Select enable */
+	unsigned int intlv_en = 0; /* Memory controller interleave enable */
+	unsigned int intlv_ctl = 0; /* Interleaving control */
+	unsigned int ap_n_en = 0; /* Chip select n auto-precharge enable */
+	unsigned int odt_rd_cfg = 0; /* ODT for reads configuration */
+	unsigned int odt_wr_cfg = 0; /* ODT for writes configuration */
+	unsigned int ba_bits_cs_n = 0; /* Num of bank bits for SDRAM on CSn */
+	unsigned int row_bits_cs_n = 0; /* Num of row bits for SDRAM on CSn */
+	unsigned int col_bits_cs_n = 0; /* Num of ocl bits for SDRAM on CSn */
+
+	/* Compute CS_CONFIG only for existing ranks of each DIMM.  */
+	if ((((i&1) == 0)
+	    && (dimm_params[i/2].n_ranks == 1))
+	    || (dimm_params[i/2].n_ranks == 2)) {
+		unsigned int n_banks_per_sdram_device;
+		cs_n_en = 1;
+		if (i == 0) {
+			/* These fields only available in CS0_CONFIG */
+			intlv_en = popts->memctl_interleaving;
+			intlv_ctl = popts->memctl_interleaving_mode;
+		}
+		ap_n_en = popts->cs_local_opts[i].auto_precharge;
+		odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg;
+		odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg;
+		n_banks_per_sdram_device
+			= dimm_params[i/2].n_banks_per_sdram_device;
+		ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2;
+		row_bits_cs_n = dimm_params[i/2].n_row_addr - 12;
+		col_bits_cs_n = dimm_params[i/2].n_col_addr - 8;
+	}
+
+	ddr->cs[i].config = (0
+		| ((cs_n_en & 0x1) << 31)
+		| ((intlv_en & 0x3) << 29)
+		| ((intlv_ctl & 0xf) << 24)
+		| ((ap_n_en & 0x1) << 23)
+
+		/* XXX: some implementation only have 1 bit starting at left */
+		| ((odt_rd_cfg & 0x7) << 20)
+
+		/* XXX: Some implementation only have 1 bit starting at left */
+		| ((odt_wr_cfg & 0x7) << 16)
+
+		| ((ba_bits_cs_n & 0x3) << 14)
+		| ((row_bits_cs_n & 0x7) << 8)
+		| ((col_bits_cs_n & 0x7) << 0)
+		);
+	debug("FSLDDR: cs[%d]_config = 0x%08x\n", i,ddr->cs[i].config);
+}
+
+/* Chip Select Configuration 2 (CSn_CONFIG_2) */
+/* FIXME: 8572 */
+static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int pasr_cfg = 0;	/* Partial array self refresh config */
+
+	ddr->cs[i].config_2 = ((pasr_cfg & 7) << 24);
+	debug("FSLDDR: cs[%d]_config_2 = 0x%08x\n", i, ddr->cs[i].config_2);
+}
+
+/* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */
+
+#if !defined(CONFIG_FSL_DDR1)
+/*
+ * DDR SDRAM Timing Configuration 0 (TIMING_CFG_0)
+ *
+ * Avoid writing for DDR I.  The new PQ38 DDR controller
+ * dreams up non-zero default values to be backwards compatible.
+ */
+static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned char trwt_mclk = 0;   /* Read-to-write turnaround */
+	unsigned char twrt_mclk = 0;   /* Write-to-read turnaround */
+	/* 7.5 ns on -3E; 0 means WL - CL + BL/2 + 1 */
+	unsigned char trrt_mclk = 0;   /* Read-to-read turnaround */
+	unsigned char twwt_mclk = 0;   /* Write-to-write turnaround */
+
+	/* Active powerdown exit timing (tXARD and tXARDS). */
+	unsigned char act_pd_exit_mclk;
+	/* Precharge powerdown exit timing (tXP). */
+	unsigned char pre_pd_exit_mclk;
+	/* Precharge powerdown exit timing (tAXPD). */
+	unsigned char taxpd_mclk;
+	/* Mode register set cycle time (tMRD). */
+	unsigned char tmrd_mclk;
+
+#if defined(CONFIG_FSL_DDR3)
+	/*
+	 * (tXARD and tXARDS). Empirical?
+	 * The DDR3 spec has not tXARD,
+	 * we use the tXP instead of it.
+	 * tXP=max(3nCK, 7.5ns) for DDR3.
+	 * spec has not the tAXPD, we use
+	 * tAXPD=8, need design to confirm.
+	 */
+	int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */
+	act_pd_exit_mclk = picos_to_mclk(tXP);
+	/* Mode register MR0[A12] is '1' - fast exit */
+	pre_pd_exit_mclk = act_pd_exit_mclk;
+	taxpd_mclk = 8;
+	tmrd_mclk = 4;
+#else /* CONFIG_FSL_DDR2 */
+	/*
+	 * (tXARD and tXARDS). Empirical?
+	 * tXARD = 2 for DDR2
+	 * tXP=2
+	 * tAXPD=8
+	 */
+	act_pd_exit_mclk = 2;
+	pre_pd_exit_mclk = 2;
+	taxpd_mclk = 8;
+	tmrd_mclk = 2;
+#endif
+
+	ddr->timing_cfg_0 = (0
+		| ((trwt_mclk & 0x3) << 30)	/* RWT */
+		| ((twrt_mclk & 0x3) << 28)	/* WRT */
+		| ((trrt_mclk & 0x3) << 26)	/* RRT */
+		| ((twwt_mclk & 0x3) << 24)	/* WWT */
+		| ((act_pd_exit_mclk & 0x7) << 20)  /* ACT_PD_EXIT */
+		| ((pre_pd_exit_mclk & 0xF) << 16)  /* PRE_PD_EXIT */
+		| ((taxpd_mclk & 0xf) << 8)	/* ODT_PD_EXIT */
+		| ((tmrd_mclk & 0xf) << 0)	/* MRS_CYC */
+		);
+	debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
+}
+#endif	/* defined(CONFIG_FSL_DDR2) */
+
+/* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */
+static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
+			       const common_timing_params_t *common_dimm,
+			       unsigned int cas_latency)
+{
+	/* Extended Activate to precharge interval (tRAS) */
+	unsigned int ext_acttopre = 0;
+	unsigned int ext_refrec; /* Extended refresh recovery time (tRFC) */
+	unsigned int ext_caslat = 0; /* Extended MCAS latency from READ cmd */
+	unsigned int cntl_adj = 0; /* Control Adjust */
+
+	/* If the tRAS > 19 MCLK, we use the ext mode */
+	if (picos_to_mclk(common_dimm->tRAS_ps) > 0x13)
+		ext_acttopre = 1;
+
+	ext_refrec = (picos_to_mclk(common_dimm->tRFC_ps) - 8) >> 4;
+
+	/* If the CAS latency more than 8, use the ext mode */
+	if (cas_latency > 8)
+		ext_caslat = 1;
+
+	ddr->timing_cfg_3 = (0
+		| ((ext_acttopre & 0x1) << 24)
+		| ((ext_refrec & 0xF) << 16)
+		| ((ext_caslat & 0x1) << 12)
+		| ((cntl_adj & 0x7) << 0)
+		);
+	debug("FSLDDR: timing_cfg_3 = 0x%08x\n", ddr->timing_cfg_3);
+}
+
+/* DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) */
+static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const common_timing_params_t *common_dimm,
+			       unsigned int cas_latency)
+{
+	/* Precharge-to-activate interval (tRP) */
+	unsigned char pretoact_mclk;
+	/* Activate to precharge interval (tRAS) */
+	unsigned char acttopre_mclk;
+	/*  Activate to read/write interval (tRCD) */
+	unsigned char acttorw_mclk;
+	/* CASLAT */
+	unsigned char caslat_ctrl;
+	/*  Refresh recovery time (tRFC) ; trfc_low */
+	unsigned char refrec_ctrl;
+	/* Last data to precharge minimum interval (tWR) */
+	unsigned char wrrec_mclk;
+	/* Activate-to-activate interval (tRRD) */
+	unsigned char acttoact_mclk;
+	/* Last write data pair to read command issue interval (tWTR) */
+	unsigned char wrtord_mclk;
+
+	pretoact_mclk = picos_to_mclk(common_dimm->tRP_ps);
+	acttopre_mclk = picos_to_mclk(common_dimm->tRAS_ps);
+	acttorw_mclk = picos_to_mclk(common_dimm->tRCD_ps);
+
+	/*
+	 * Translate CAS Latency to a DDR controller field value:
+	 *
+	 *      CAS Lat DDR I   DDR II  Ctrl
+	 *      Clocks  SPD Bit SPD Bit Value
+	 *      ------- ------- ------- -----
+	 *      1.0     0               0001
+	 *      1.5     1               0010
+	 *      2.0     2       2       0011
+	 *      2.5     3               0100
+	 *      3.0     4       3       0101
+	 *      3.5     5               0110
+	 *      4.0             4       0111
+	 *      4.5                     1000
+	 *      5.0             5       1001
+	 */
+#if defined(CONFIG_FSL_DDR1)
+	caslat_ctrl = (cas_latency + 1) & 0x07;
+#elif defined(CONFIG_FSL_DDR2)
+	caslat_ctrl = 2 * cas_latency - 1;
+#else
+	/*
+	 * if the CAS latency more than 8 cycle,
+	 * we need set extend bit for it at
+	 * TIMING_CFG_3[EXT_CASLAT]
+	 */
+	if (cas_latency > 8)
+		cas_latency -= 8;
+	caslat_ctrl = 2 * cas_latency - 1;
+#endif
+
+	refrec_ctrl = picos_to_mclk(common_dimm->tRFC_ps) - 8;
+	wrrec_mclk = picos_to_mclk(common_dimm->tWR_ps);
+	if (popts->OTF_burst_chop_en)
+		wrrec_mclk += 2;
+
+	acttoact_mclk = picos_to_mclk(common_dimm->tRRD_ps);
+	/*
+	 * JEDEC has min requirement for tRRD
+	 */
+#if defined(CONFIG_FSL_DDR3)
+	if (acttoact_mclk < 4)
+		acttoact_mclk = 4;
+#endif
+	wrtord_mclk = picos_to_mclk(common_dimm->tWTR_ps);
+	/*
+	 * JEDEC has some min requirements for tWTR
+	 */
+#if defined(CONFIG_FSL_DDR2)
+	if (wrtord_mclk < 2)
+		wrtord_mclk = 2;
+#elif defined(CONFIG_FSL_DDR3)
+	if (wrtord_mclk < 4)
+		wrtord_mclk = 4;
+#endif
+	if (popts->OTF_burst_chop_en)
+		wrtord_mclk += 2;
+
+	ddr->timing_cfg_1 = (0
+		| ((pretoact_mclk & 0x0F) << 28)
+		| ((acttopre_mclk & 0x0F) << 24)
+		| ((acttorw_mclk & 0xF) << 20)
+		| ((caslat_ctrl & 0xF) << 16)
+		| ((refrec_ctrl & 0xF) << 12)
+		| ((wrrec_mclk & 0x0F) << 8)
+		| ((acttoact_mclk & 0x07) << 4)
+		| ((wrtord_mclk & 0x07) << 0)
+		);
+	debug("FSLDDR: timing_cfg_1 = 0x%08x\n", ddr->timing_cfg_1);
+}
+
+/* DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) */
+static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const common_timing_params_t *common_dimm,
+			       unsigned int cas_latency,
+			       unsigned int additive_latency)
+{
+	/* Additive latency */
+	unsigned char add_lat_mclk;
+	/* CAS-to-preamble override */
+	unsigned short cpo;
+	/* Write latency */
+	unsigned char wr_lat;
+	/*  Read to precharge (tRTP) */
+	unsigned char rd_to_pre;
+	/* Write command to write data strobe timing adjustment */
+	unsigned char wr_data_delay;
+	/* Minimum CKE pulse width (tCKE) */
+	unsigned char cke_pls;
+	/* Window for four activates (tFAW) */
+	unsigned short four_act;
+
+	/* FIXME add check that this must be less than acttorw_mclk */
+	add_lat_mclk = additive_latency;
+	cpo = popts->cpo_override;
+
+#if defined(CONFIG_FSL_DDR1)
+	/*
+	 * This is a lie.  It should really be 1, but if it is
+	 * set to 1, bits overlap into the old controller's
+	 * otherwise unused ACSM field.  If we leave it 0, then
+	 * the HW will magically treat it as 1 for DDR 1.  Oh Yea.
+	 */
+	wr_lat = 0;
+#elif defined(CONFIG_FSL_DDR2)
+	wr_lat = cas_latency - 1;
+#else
+	wr_lat = compute_cas_write_latency();
+#endif
+
+	rd_to_pre = picos_to_mclk(common_dimm->tRTP_ps);
+	/*
+	 * JEDEC has some min requirements for tRTP
+	 */
+#if defined(CONFIG_FSL_DDR2)
+	if (rd_to_pre  < 2)
+		rd_to_pre  = 2;
+#elif defined(CONFIG_FSL_DDR3)
+	if (rd_to_pre < 4)
+		rd_to_pre = 4;
+#endif
+	if (additive_latency)
+		rd_to_pre += additive_latency;
+	if (popts->OTF_burst_chop_en)
+		rd_to_pre += 2; /* according to UM */
+
+	wr_data_delay = popts->write_data_delay;
+	cke_pls = picos_to_mclk(popts->tCKE_clock_pulse_width_ps);
+	four_act = picos_to_mclk(popts->tFAW_window_four_activates_ps);
+
+	ddr->timing_cfg_2 = (0
+		| ((add_lat_mclk & 0xf) << 28)
+		| ((cpo & 0x1f) << 23)
+		| ((wr_lat & 0xf) << 19)
+		| ((rd_to_pre & RD_TO_PRE_MASK) << RD_TO_PRE_SHIFT)
+		| ((wr_data_delay & WR_DATA_DELAY_MASK) << WR_DATA_DELAY_SHIFT)
+		| ((cke_pls & 0x7) << 6)
+		| ((four_act & 0x3f) << 0)
+		);
+	debug("FSLDDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2);
+}
+
+/* DDR SDRAM control configuration (DDR_SDRAM_CFG) */
+static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const common_timing_params_t *common_dimm)
+{
+	unsigned int mem_en;		/* DDR SDRAM interface logic enable */
+	unsigned int sren;		/* Self refresh enable (during sleep) */
+	unsigned int ecc_en;		/* ECC enable. */
+	unsigned int rd_en;		/* Registered DIMM enable */
+	unsigned int sdram_type;	/* Type of SDRAM */
+	unsigned int dyn_pwr;		/* Dynamic power management mode */
+	unsigned int dbw;		/* DRAM dta bus width */
+	unsigned int eight_be = 0;	/* 8-beat burst enable, DDR2 is zero */
+	unsigned int ncap = 0;		/* Non-concurrent auto-precharge */
+	unsigned int threeT_en;		/* Enable 3T timing */
+	unsigned int twoT_en;		/* Enable 2T timing */
+	unsigned int ba_intlv_ctl;	/* Bank (CS) interleaving control */
+	unsigned int x32_en = 0;	/* x32 enable */
+	unsigned int pchb8 = 0;		/* precharge bit 8 enable */
+	unsigned int hse;		/* Global half strength override */
+	unsigned int mem_halt = 0;	/* memory controller halt */
+	unsigned int bi = 0;		/* Bypass initialization */
+
+	mem_en = 1;
+	sren = popts->self_refresh_in_sleep;
+	if (common_dimm->all_DIMMs_ECC_capable) {
+		/* Allow setting of ECC only if all DIMMs are ECC. */
+		ecc_en = popts->ECC_mode;
+	} else {
+		ecc_en = 0;
+	}
+
+	rd_en = (common_dimm->all_DIMMs_registered
+		 && !common_dimm->all_DIMMs_unbuffered);
+
+	sdram_type = CONFIG_FSL_SDRAM_TYPE;
+
+	dyn_pwr = popts->dynamic_power;
+	dbw = popts->data_bus_width;
+	/* 8-beat burst enable DDR-III case
+	 * we must clear it when use the on-the-fly mode,
+	 * must set it when use the 32-bits bus mode.
+	 */
+	if (sdram_type == SDRAM_TYPE_DDR3) {
+		if (popts->burst_length == DDR_BL8)
+			eight_be = 1;
+		if (popts->burst_length == DDR_OTF)
+			eight_be = 0;
+		if (dbw == 0x1)
+			eight_be = 1;
+	}
+
+	threeT_en = popts->threeT_en;
+	twoT_en = popts->twoT_en;
+	ba_intlv_ctl = popts->ba_intlv_ctl;
+	hse = popts->half_strength_driver_enable;
+
+	ddr->ddr_sdram_cfg = (0
+			| ((mem_en & 0x1) << 31)
+			| ((sren & 0x1) << 30)
+			| ((ecc_en & 0x1) << 29)
+			| ((rd_en & 0x1) << 28)
+			| ((sdram_type & 0x7) << 24)
+			| ((dyn_pwr & 0x1) << 21)
+			| ((dbw & 0x3) << 19)
+			| ((eight_be & 0x1) << 18)
+			| ((ncap & 0x1) << 17)
+			| ((threeT_en & 0x1) << 16)
+			| ((twoT_en & 0x1) << 15)
+			| ((ba_intlv_ctl & 0x7F) << 8)
+			| ((x32_en & 0x1) << 5)
+			| ((pchb8 & 0x1) << 4)
+			| ((hse & 0x1) << 3)
+			| ((mem_halt & 0x1) << 1)
+			| ((bi & 0x1) << 0)
+			);
+	debug("FSLDDR: ddr_sdram_cfg = 0x%08x\n", ddr->ddr_sdram_cfg);
+}
+
+/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */
+static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts)
+{
+	unsigned int frc_sr = 0;	/* Force self refresh */
+	unsigned int sr_ie = 0;		/* Self-refresh interrupt enable */
+	unsigned int dll_rst_dis;	/* DLL reset disable */
+	unsigned int dqs_cfg;		/* DQS configuration */
+	unsigned int odt_cfg;		/* ODT configuration */
+	unsigned int num_pr;		/* Number of posted refreshes */
+	unsigned int obc_cfg;		/* On-The-Fly Burst Chop Cfg */
+	unsigned int ap_en;		/* Address Parity Enable */
+	unsigned int d_init;		/* DRAM data initialization */
+	unsigned int rcw_en = 0;	/* Register Control Word Enable */
+	unsigned int md_en = 0;		/* Mirrored DIMM Enable */
+
+	dll_rst_dis = 1;	/* Make this configurable */
+	dqs_cfg = popts->DQS_config;
+	if (popts->cs_local_opts[0].odt_rd_cfg
+	    || popts->cs_local_opts[0].odt_wr_cfg) {
+		/* FIXME */
+		odt_cfg = 2;
+	} else {
+		odt_cfg = 0;
+	}
+
+	num_pr = 1;	/* Make this configurable */
+
+	/*
+	 * 8572 manual says
+	 *     {TIMING_CFG_1[PRETOACT]
+	 *      + [DDR_SDRAM_CFG_2[NUM_PR]
+	 *        * ({EXT_REFREC || REFREC} + 8 + 2)]}
+	 *      << DDR_SDRAM_INTERVAL[REFINT]
+	 */
+#if defined(CONFIG_FSL_DDR3)
+	obc_cfg = popts->OTF_burst_chop_en;
+#else
+	obc_cfg = 0;
+#endif
+
+	ap_en = 0;	/* Make this configurable? */
+
+#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+	/* Use the DDR controller to auto initialize memory. */
+	d_init = 1;
+	ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE;
+	debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init);
+#else
+	/* Memory will be initialized via DMA, or not at all. */
+	d_init = 0;
+#endif
+
+#if defined(CONFIG_FSL_DDR3)
+	md_en = popts->mirrored_dimm;
+#endif
+	ddr->ddr_sdram_cfg_2 = (0
+		| ((frc_sr & 0x1) << 31)
+		| ((sr_ie & 0x1) << 30)
+		| ((dll_rst_dis & 0x1) << 29)
+		| ((dqs_cfg & 0x3) << 26)
+		| ((odt_cfg & 0x3) << 21)
+		| ((num_pr & 0xf) << 12)
+		| ((obc_cfg & 0x1) << 6)
+		| ((ap_en & 0x1) << 5)
+		| ((d_init & 0x1) << 4)
+		| ((rcw_en & 0x1) << 2)
+		| ((md_en & 0x1) << 0)
+		);
+	debug("FSLDDR: ddr_sdram_cfg_2 = 0x%08x\n", ddr->ddr_sdram_cfg_2);
+}
+
+/* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */
+static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
+				const memctl_options_t *popts)
+{
+	unsigned short esdmode2 = 0;	/* Extended SDRAM mode 2 */
+	unsigned short esdmode3 = 0;	/* Extended SDRAM mode 3 */
+
+#if defined(CONFIG_FSL_DDR3)
+	unsigned int rtt_wr = 0;	/* Rtt_WR - dynamic ODT off */
+	unsigned int srt = 0;	/* self-refresh temerature, normal range */
+	unsigned int asr = 0;	/* auto self-refresh disable */
+	unsigned int cwl = compute_cas_write_latency() - 5;
+	unsigned int pasr = 0;	/* partial array self refresh disable */
+
+	if (popts->rtt_override)
+		rtt_wr = popts->rtt_wr_override_value;
+
+	esdmode2 = (0
+		| ((rtt_wr & 0x3) << 9)
+		| ((srt & 0x1) << 7)
+		| ((asr & 0x1) << 6)
+		| ((cwl & 0x7) << 3)
+		| ((pasr & 0x7) << 0));
+#endif
+	ddr->ddr_sdram_mode_2 = (0
+				 | ((esdmode2 & 0xFFFF) << 16)
+				 | ((esdmode3 & 0xFFFF) << 0)
+				 );
+	debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2);
+}
+
+/* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */
+static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const common_timing_params_t *common_dimm)
+{
+	unsigned int refint;	/* Refresh interval */
+	unsigned int bstopre;	/* Precharge interval */
+
+	refint = picos_to_mclk(common_dimm->refresh_rate_ps);
+
+	bstopre = popts->bstopre;
+
+	/* refint field used 0x3FFF in earlier controllers */
+	ddr->ddr_sdram_interval = (0
+				   | ((refint & 0xFFFF) << 16)
+				   | ((bstopre & 0x3FFF) << 0)
+				   );
+	debug("FSLDDR: ddr_sdram_interval = 0x%08x\n", ddr->ddr_sdram_interval);
+}
+
+#if defined(CONFIG_FSL_DDR3)
+/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
+static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const common_timing_params_t *common_dimm,
+			       unsigned int cas_latency,
+			       unsigned int additive_latency)
+{
+	unsigned short esdmode;		/* Extended SDRAM mode */
+	unsigned short sdmode;		/* SDRAM mode */
+
+	/* Mode Register - MR1 */
+	unsigned int qoff = 0;		/* Output buffer enable 0=yes, 1=no */
+	unsigned int tdqs_en = 0;	/* TDQS Enable: 0=no, 1=yes */
+	unsigned int rtt;
+	unsigned int wrlvl_en = 0;	/* Write level enable: 0=no, 1=yes */
+	unsigned int al = 0;		/* Posted CAS# additive latency (AL) */
+	unsigned int dic = 1;		/* Output driver impedance, 34ohm */
+	unsigned int dll_en = 0;	/* DLL Enable  0=Enable (Normal),
+						       1=Disable (Test/Debug) */
+
+	/* Mode Register - MR0 */
+	unsigned int dll_on;	/* DLL control for precharge PD, 0=off, 1=on */
+	unsigned int wr;	/* Write Recovery */
+	unsigned int dll_rst;	/* DLL Reset */
+	unsigned int mode;	/* Normal=0 or Test=1 */
+	unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */
+	/* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */
+	unsigned int bt;
+	unsigned int bl;	/* BL: Burst Length */
+
+	unsigned int wr_mclk;
+
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+
+	rtt = fsl_ddr_get_rtt();
+	if (popts->rtt_override)
+		rtt = popts->rtt_override_value;
+
+	if (additive_latency == (cas_latency - 1))
+		al = 1;
+	if (additive_latency == (cas_latency - 2))
+		al = 2;
+
+	/*
+	 * The esdmode value will also be used for writing
+	 * MR1 during write leveling for DDR3, although the
+	 * bits specifically related to the write leveling
+	 * scheme will be handled automatically by the DDR
+	 * controller. so we set the wrlvl_en = 0 here.
+	 */
+	esdmode = (0
+		| ((qoff & 0x1) << 12)
+		| ((tdqs_en & 0x1) << 11)
+		| ((rtt & 0x4) << 7)   /* rtt field is split */
+		| ((wrlvl_en & 0x1) << 7)
+		| ((rtt & 0x2) << 5)   /* rtt field is split */
+		| ((dic & 0x2) << 4)   /* DIC field is split */
+		| ((al & 0x3) << 3)
+		| ((rtt & 0x1) << 2)  /* rtt field is split */
+		| ((dic & 0x1) << 1)   /* DIC field is split */
+		| ((dll_en & 0x1) << 0)
+		);
+
+	/*
+	 * DLL control for precharge PD
+	 * 0=slow exit DLL off (tXPDLL)
+	 * 1=fast exit DLL on (tXP)
+	 */
+	dll_on = 1;
+	wr_mclk = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps;
+	if (wr_mclk >= 12)
+		wr = 6;
+	else if (wr_mclk >= 9)
+		wr = 5;
+	else
+		wr = wr_mclk - 4;
+	dll_rst = 0;	/* dll no reset */
+	mode = 0;	/* normal mode */
+
+	/* look up table to get the cas latency bits */
+	if (cas_latency >= 5 && cas_latency <= 11) {
+		unsigned char cas_latency_table[7] = {
+			0x2,	/* 5 clocks */
+			0x4,	/* 6 clocks */
+			0x6,	/* 7 clocks */
+			0x8,	/* 8 clocks */
+			0xa,	/* 9 clocks */
+			0xc,	/* 10 clocks */
+			0xe	/* 11 clocks */
+		};
+		caslat = cas_latency_table[cas_latency - 5];
+	}
+	bt = 0;	/* Nibble sequential */
+
+	switch (popts->burst_length) {
+	case DDR_BL8:
+		bl = 0;
+		break;
+	case DDR_OTF:
+		bl = 1;
+		break;
+	case DDR_BC4:
+		bl = 2;
+		break;
+	default:
+		printf("Error: invalid burst length of %u specified. "
+			" Defaulting to on-the-fly BC4 or BL8 beats.\n",
+			popts->burst_length);
+		bl = 1;
+		break;
+	}
+
+	sdmode = (0
+		  | ((dll_on & 0x1) << 12)
+		  | ((wr & 0x7) << 9)
+		  | ((dll_rst & 0x1) << 8)
+		  | ((mode & 0x1) << 7)
+		  | (((caslat >> 1) & 0x7) << 4)
+		  | ((bt & 0x1) << 3)
+		  | ((bl & 0x3) << 0)
+		  );
+
+	ddr->ddr_sdram_mode = (0
+			       | ((esdmode & 0xFFFF) << 16)
+			       | ((sdmode & 0xFFFF) << 0)
+			       );
+
+	debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode);
+}
+
+#else /* !CONFIG_FSL_DDR3 */
+
+/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
+static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
+			       const common_timing_params_t *common_dimm,
+			       unsigned int cas_latency,
+			       unsigned int additive_latency)
+{
+	unsigned short esdmode;		/* Extended SDRAM mode */
+	unsigned short sdmode;		/* SDRAM mode */
+
+	/*
+	 * FIXME: This ought to be pre-calculated in a
+	 * technology-specific routine,
+	 * e.g. compute_DDR2_mode_register(), and then the
+	 * sdmode and esdmode passed in as part of common_dimm.
+	 */
+
+	/* Extended Mode Register */
+	unsigned int mrs = 0;		/* Mode Register Set */
+	unsigned int outputs = 0;	/* 0=Enabled, 1=Disabled */
+	unsigned int rdqs_en = 0;	/* RDQS Enable: 0=no, 1=yes */
+	unsigned int dqs_en = 0;	/* DQS# Enable: 0=enable, 1=disable */
+	unsigned int ocd = 0;		/* 0x0=OCD not supported,
+					   0x7=OCD default state */
+	unsigned int rtt;
+	unsigned int al;		/* Posted CAS# additive latency (AL) */
+	unsigned int ods = 0;		/* Output Drive Strength:
+						0 = Full strength (18ohm)
+						1 = Reduced strength (4ohm) */
+	unsigned int dll_en = 0;	/* DLL Enable  0=Enable (Normal),
+						       1=Disable (Test/Debug) */
+
+	/* Mode Register (MR) */
+	unsigned int mr;	/* Mode Register Definition */
+	unsigned int pd;	/* Power-Down Mode */
+	unsigned int wr;	/* Write Recovery */
+	unsigned int dll_res;	/* DLL Reset */
+	unsigned int mode;	/* Normal=0 or Test=1 */
+	unsigned int caslat = 0;/* CAS# latency */
+	/* BT: Burst Type (0=Sequential, 1=Interleaved) */
+	unsigned int bt;
+	unsigned int bl;	/* BL: Burst Length */
+
+#if defined(CONFIG_FSL_DDR2)
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+#endif
+
+	rtt = fsl_ddr_get_rtt();
+
+	al = additive_latency;
+
+	esdmode = (0
+		| ((mrs & 0x3) << 14)
+		| ((outputs & 0x1) << 12)
+		| ((rdqs_en & 0x1) << 11)
+		| ((dqs_en & 0x1) << 10)
+		| ((ocd & 0x7) << 7)
+		| ((rtt & 0x2) << 5)   /* rtt field is split */
+		| ((al & 0x7) << 3)
+		| ((rtt & 0x1) << 2)   /* rtt field is split */
+		| ((ods & 0x1) << 1)
+		| ((dll_en & 0x1) << 0)
+		);
+
+	mr = 0;		 /* FIXME: CHECKME */
+
+	/*
+	 * 0 = Fast Exit (Normal)
+	 * 1 = Slow Exit (Low Power)
+	 */
+	pd = 0;
+
+#if defined(CONFIG_FSL_DDR1)
+	wr = 0;       /* Historical */
+#elif defined(CONFIG_FSL_DDR2)
+	wr = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps - 1;
+#endif
+	dll_res = 0;
+	mode = 0;
+
+#if defined(CONFIG_FSL_DDR1)
+	if (1 <= cas_latency && cas_latency <= 4) {
+		unsigned char mode_caslat_table[4] = {
+			0x5,	/* 1.5 clocks */
+			0x2,	/* 2.0 clocks */
+			0x6,	/* 2.5 clocks */
+			0x3	/* 3.0 clocks */
+		};
+		caslat = mode_caslat_table[cas_latency - 1];
+	} else {
+		printf("Warning: unknown cas_latency %d\n", cas_latency);
+	}
+#elif defined(CONFIG_FSL_DDR2)
+	caslat = cas_latency;
+#endif
+	bt = 0;
+
+	switch (popts->burst_length) {
+	case DDR_BL4:
+		bl = 2;
+		break;
+	case DDR_BL8:
+		bl = 3;
+		break;
+	default:
+		printf("Error: invalid burst length of %u specified. "
+			" Defaulting to 4 beats.\n",
+			popts->burst_length);
+		bl = 2;
+		break;
+	}
+
+	sdmode = (0
+		  | ((mr & 0x3) << 14)
+		  | ((pd & 0x1) << 12)
+		  | ((wr & 0x7) << 9)
+		  | ((dll_res & 0x1) << 8)
+		  | ((mode & 0x1) << 7)
+		  | ((caslat & 0x7) << 4)
+		  | ((bt & 0x1) << 3)
+		  | ((bl & 0x7) << 0)
+		  );
+
+	ddr->ddr_sdram_mode = (0
+			       | ((esdmode & 0xFFFF) << 16)
+			       | ((sdmode & 0xFFFF) << 0)
+			       );
+	debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode);
+}
+#endif
+
+/* DDR SDRAM Data Initialization (DDR_DATA_INIT) */
+static void set_ddr_data_init(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int init_value;	/* Initialization value */
+
+	init_value = 0xDEADBEEF;
+	ddr->ddr_data_init = init_value;
+}
+
+/*
+ * DDR SDRAM Clock Control (DDR_SDRAM_CLK_CNTL)
+ * The old controller on the 8540/60 doesn't have this register.
+ * Hope it's OK to set it (to 0) anyway.
+ */
+static void set_ddr_sdram_clk_cntl(fsl_ddr_cfg_regs_t *ddr,
+					 const memctl_options_t *popts)
+{
+	unsigned int clk_adjust;	/* Clock adjust */
+
+	clk_adjust = popts->clk_adjust;
+	ddr->ddr_sdram_clk_cntl = (clk_adjust & 0xF) << 23;
+}
+
+/* DDR Initialization Address (DDR_INIT_ADDR) */
+static void set_ddr_init_addr(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int init_addr = 0;	/* Initialization address */
+
+	ddr->ddr_init_addr = init_addr;
+}
+
+/* DDR Initialization Address (DDR_INIT_EXT_ADDR) */
+static void set_ddr_init_ext_addr(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int uia = 0;	/* Use initialization address */
+	unsigned int init_ext_addr = 0;	/* Initialization address */
+
+	ddr->ddr_init_ext_addr = (0
+				  | ((uia & 0x1) << 31)
+				  | (init_ext_addr & 0xF)
+				  );
+}
+
+/* DDR SDRAM Timing Configuration 4 (TIMING_CFG_4) */
+static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr,
+				const memctl_options_t *popts)
+{
+	unsigned int rwt = 0; /* Read-to-write turnaround for same CS */
+	unsigned int wrt = 0; /* Write-to-read turnaround for same CS */
+	unsigned int rrt = 0; /* Read-to-read turnaround for same CS */
+	unsigned int wwt = 0; /* Write-to-write turnaround for same CS */
+	unsigned int dll_lock = 0; /* DDR SDRAM DLL Lock Time */
+
+#if defined(CONFIG_FSL_DDR3)
+	if (popts->burst_length == DDR_BL8) {
+		/* We set BL/2 for fixed BL8 */
+		rrt = 0;	/* BL/2 clocks */
+		wwt = 0;	/* BL/2 clocks */
+	} else {
+		/* We need to set BL/2 + 2 to BC4 and OTF */
+		rrt = 2;	/* BL/2 + 2 clocks */
+		wwt = 2;	/* BL/2 + 2 clocks */
+	}
+	dll_lock = 1;	/* tDLLK = 512 clocks from spec */
+#endif
+	ddr->timing_cfg_4 = (0
+			     | ((rwt & 0xf) << 28)
+			     | ((wrt & 0xf) << 24)
+			     | ((rrt & 0xf) << 20)
+			     | ((wwt & 0xf) << 16)
+			     | (dll_lock & 0x3)
+			     );
+	debug("FSLDDR: timing_cfg_4 = 0x%08x\n", ddr->timing_cfg_4);
+}
+
+/* DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) */
+static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int rodt_on = 0;	/* Read to ODT on */
+	unsigned int rodt_off = 0;	/* Read to ODT off */
+	unsigned int wodt_on = 0;	/* Write to ODT on */
+	unsigned int wodt_off = 0;	/* Write to ODT off */
+
+#if defined(CONFIG_FSL_DDR3)
+	rodt_on = 3;	/*  2 clocks */
+	rodt_off = 4;	/*  4 clocks */
+	wodt_on = 2;	/*  1 clocks */
+	wodt_off = 4;	/*  4 clocks */
+#endif
+
+	ddr->timing_cfg_5 = (0
+			     | ((rodt_on & 0x1f) << 24)
+			     | ((rodt_off & 0x7) << 20)
+			     | ((wodt_on & 0x1f) << 12)
+			     | ((wodt_off & 0x7) << 8)
+			     );
+	debug("FSLDDR: timing_cfg_5 = 0x%08x\n", ddr->timing_cfg_5);
+}
+
+/* DDR ZQ Calibration Control (DDR_ZQ_CNTL) */
+static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en)
+{
+	unsigned int zqinit = 0;/* POR ZQ Calibration Time (tZQinit) */
+	/* Normal Operation Full Calibration Time (tZQoper) */
+	unsigned int zqoper = 0;
+	/* Normal Operation Short Calibration Time (tZQCS) */
+	unsigned int zqcs = 0;
+
+	if (zq_en) {
+		zqinit = 9;	/* 512 clocks */
+		zqoper = 8;	/* 256 clocks */
+		zqcs = 6;	/* 64 clocks */
+	}
+
+	ddr->ddr_zq_cntl = (0
+			    | ((zq_en & 0x1) << 31)
+			    | ((zqinit & 0xF) << 24)
+			    | ((zqoper & 0xF) << 16)
+			    | ((zqcs & 0xF) << 8)
+			    );
+}
+
+/* DDR Write Leveling Control (DDR_WRLVL_CNTL) */
+static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en,
+				const memctl_options_t *popts)
+{
+	/*
+	 * First DQS pulse rising edge after margining mode
+	 * is programmed (tWL_MRD)
+	 */
+	unsigned int wrlvl_mrd = 0;
+	/* ODT delay after margining mode is programmed (tWL_ODTEN) */
+	unsigned int wrlvl_odten = 0;
+	/* DQS/DQS_ delay after margining mode is programmed (tWL_DQSEN) */
+	unsigned int wrlvl_dqsen = 0;
+	/* WRLVL_SMPL: Write leveling sample time */
+	unsigned int wrlvl_smpl = 0;
+	/* WRLVL_WLR: Write leveling repeition time */
+	unsigned int wrlvl_wlr = 0;
+	/* WRLVL_START: Write leveling start time */
+	unsigned int wrlvl_start = 0;
+
+	/* suggest enable write leveling for DDR3 due to fly-by topology */
+	if (wrlvl_en) {
+		/* tWL_MRD min = 40 nCK, we set it 64 */
+		wrlvl_mrd = 0x6;
+		/* tWL_ODTEN 128 */
+		wrlvl_odten = 0x7;
+		/* tWL_DQSEN min = 25 nCK, we set it 32 */
+		wrlvl_dqsen = 0x5;
+		/*
+		 * Write leveling sample time at least need 6 clocks
+		 * higher than tWLO to allow enough time for progagation
+		 * delay and sampling the prime data bits.
+		 */
+		wrlvl_smpl = 0xf;
+		/*
+		 * Write leveling repetition time
+		 * at least tWLO + 6 clocks clocks
+		 * we set it 32
+		 */
+		wrlvl_wlr = 0x5;
+		/*
+		 * Write leveling start time
+		 * The value use for the DQS_ADJUST for the first sample
+		 * when write leveling is enabled.
+		 */
+		wrlvl_start = 0x8;
+		/*
+		 * Override the write leveling sample and start time
+		 * according to specific board
+		 */
+		if (popts->wrlvl_override) {
+			wrlvl_smpl = popts->wrlvl_sample;
+			wrlvl_start = popts->wrlvl_start;
+		}
+	}
+
+	ddr->ddr_wrlvl_cntl = (0
+			       | ((wrlvl_en & 0x1) << 31)
+			       | ((wrlvl_mrd & 0x7) << 24)
+			       | ((wrlvl_odten & 0x7) << 20)
+			       | ((wrlvl_dqsen & 0x7) << 16)
+			       | ((wrlvl_smpl & 0xf) << 12)
+			       | ((wrlvl_wlr & 0x7) << 8)
+			       | ((wrlvl_start & 0x1F) << 0)
+			       );
+}
+
+/* DDR Self Refresh Counter (DDR_SR_CNTR) */
+static void set_ddr_sr_cntr(fsl_ddr_cfg_regs_t *ddr, unsigned int sr_it)
+{
+	/* Self Refresh Idle Threshold */
+	ddr->ddr_sr_cntr = (sr_it & 0xF) << 16;
+}
+
+/* DDR SDRAM Register Control Word 1 (DDR_SDRAM_RCW_1) */
+static void set_ddr_sdram_rcw_1(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int rcw0 = 0;	/* RCW0: Register Control Word 0 */
+	unsigned int rcw1 = 0;	/* RCW1: Register Control Word 1 */
+	unsigned int rcw2 = 0;	/* RCW2: Register Control Word 2 */
+	unsigned int rcw3 = 0;	/* RCW3: Register Control Word 3 */
+	unsigned int rcw4 = 0;	/* RCW4: Register Control Word 4 */
+	unsigned int rcw5 = 0;	/* RCW5: Register Control Word 5 */
+	unsigned int rcw6 = 0;	/* RCW6: Register Control Word 6 */
+	unsigned int rcw7 = 0;	/* RCW7: Register Control Word 7 */
+
+	ddr->ddr_sdram_rcw_1 = (0
+				| ((rcw0 & 0xF) << 28)
+				| ((rcw1 & 0xF) << 24)
+				| ((rcw2 & 0xF) << 20)
+				| ((rcw3 & 0xF) << 16)
+				| ((rcw4 & 0xF) << 12)
+				| ((rcw5 & 0xF) << 8)
+				| ((rcw6 & 0xF) << 4)
+				| ((rcw7 & 0xF) << 0)
+				);
+}
+
+/* DDR SDRAM Register Control Word 2 (DDR_SDRAM_RCW_2) */
+static void set_ddr_sdram_rcw_2(fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int rcw8 = 0;	/* RCW0: Register Control Word 8 */
+	unsigned int rcw9 = 0;	/* RCW1: Register Control Word 9 */
+	unsigned int rcw10 = 0;	/* RCW2: Register Control Word 10 */
+	unsigned int rcw11 = 0;	/* RCW3: Register Control Word 11 */
+	unsigned int rcw12 = 0;	/* RCW4: Register Control Word 12 */
+	unsigned int rcw13 = 0;	/* RCW5: Register Control Word 13 */
+	unsigned int rcw14 = 0;	/* RCW6: Register Control Word 14 */
+	unsigned int rcw15 = 0;	/* RCW7: Register Control Word 15 */
+
+	ddr->ddr_sdram_rcw_2 = (0
+				| ((rcw8 & 0xF) << 28)
+				| ((rcw9 & 0xF) << 24)
+				| ((rcw10 & 0xF) << 20)
+				| ((rcw11 & 0xF) << 16)
+				| ((rcw12 & 0xF) << 12)
+				| ((rcw13 & 0xF) << 8)
+				| ((rcw14 & 0xF) << 4)
+				| ((rcw15 & 0xF) << 0)
+				);
+}
+
+unsigned int
+check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int res = 0;
+
+	/*
+	 * Check that DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] are
+	 * not set at the same time.
+	 */
+	if (ddr->ddr_sdram_cfg & 0x10000000
+	    && ddr->ddr_sdram_cfg & 0x00008000) {
+		printf("Error: DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] "
+				" should not be set at the same time.\n");
+		res++;
+	}
+
+	return res;
+}
+
+unsigned int
+compute_fsl_memctl_config_regs(const memctl_options_t *popts,
+			       fsl_ddr_cfg_regs_t *ddr,
+			       const common_timing_params_t *common_dimm,
+			       const dimm_params_t *dimm_params,
+			       unsigned int dbw_cap_adj)
+{
+	unsigned int i;
+	unsigned int cas_latency;
+	unsigned int additive_latency;
+	unsigned int sr_it;
+	unsigned int zq_en;
+	unsigned int wrlvl_en;
+
+	memset(ddr, 0, sizeof(fsl_ddr_cfg_regs_t));
+
+	if (common_dimm == NULL) {
+		printf("Error: subset DIMM params struct null pointer\n");
+		return 1;
+	}
+
+	/*
+	 * Process overrides first.
+	 *
+	 * FIXME: somehow add dereated caslat to this
+	 */
+	cas_latency = (popts->cas_latency_override)
+		? popts->cas_latency_override_value
+		: common_dimm->lowest_common_SPD_caslat;
+
+	additive_latency = (popts->additive_latency_override)
+		? popts->additive_latency_override_value
+		: common_dimm->additive_latency;
+
+	sr_it = (popts->auto_self_refresh_en)
+		? popts->sr_it
+		: 0;
+	/* ZQ calibration */
+	zq_en = (popts->zq_en) ? 1 : 0;
+	/* write leveling */
+	wrlvl_en = (popts->wrlvl_en) ? 1 : 0;
+
+	/* Chip Select Memory Bounds (CSn_BNDS) */
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		unsigned long long ea = 0, sa = 0;
+
+		if (popts->ba_intlv_ctl && (i > 0) &&
+			((popts->ba_intlv_ctl & 0x60) != FSL_DDR_CS2_CS3 )) {
+			/* Don't set up boundaries for other CS
+			 * other than CS0, if bank interleaving
+			 * is enabled and not CS2+CS3 interleaved.
+			 * But we need to set the ODT_RD_CFG and
+			 * ODT_WR_CFG for CS1_CONFIG here.
+			 */
+			set_csn_config(i, ddr, popts, dimm_params);
+			break;
+		}
+
+		if (dimm_params[i/2].n_ranks == 0) {
+			debug("Skipping setup of CS%u "
+				"because n_ranks on DIMM %u is 0\n", i, i/2);
+			continue;
+		}
+		if (popts->memctl_interleaving && popts->ba_intlv_ctl) {
+			/*
+			 * This works superbank 2CS
+			 * There are 2 memory controllers configured
+			 * identically, memory is interleaved between them,
+			 * and each controller uses rank interleaving within
+			 * itself. Therefore the starting and ending address
+			 * on each controller is twice the amount present on
+			 * each controller.
+			 */
+			unsigned long long rank_density
+					= dimm_params[0].capacity;
+			ea = (2 * (rank_density >> dbw_cap_adj)) - 1;
+		}
+		else if (!popts->memctl_interleaving && popts->ba_intlv_ctl) {
+			/*
+			 * If memory interleaving between controllers is NOT
+			 * enabled, the starting address for each memory
+			 * controller is distinct.  However, because rank
+			 * interleaving is enabled, the starting and ending
+			 * addresses of the total memory on that memory
+			 * controller needs to be programmed into its
+			 * respective CS0_BNDS.
+			 */
+			unsigned long long rank_density
+						= dimm_params[i/2].rank_density;
+			switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+			case FSL_DDR_CS0_CS1_CS2_CS3:
+				/* CS0+CS1+CS2+CS3 interleaving, only CS0_CNDS
+				 * needs to be set.
+				 */
+				sa = common_dimm->base_address;
+				ea = sa + (4 * (rank_density >> dbw_cap_adj))-1;
+				break;
+			case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+				/* CS0+CS1 and CS2+CS3 interleaving, CS0_CNDS
+				 * and CS2_CNDS need to be set.
+				 */
+				if (!(i&1)) {
+					sa = dimm_params[i/2].base_address;
+					ea = sa + (i * (rank_density >>
+						dbw_cap_adj)) - 1;
+				}
+				break;
+			case FSL_DDR_CS0_CS1:
+				/* CS0+CS1 interleaving, CS0_CNDS needs
+				 * to be set
+				 */
+				sa = common_dimm->base_address;
+				ea = sa + (2 * (rank_density >> dbw_cap_adj))-1;
+				break;
+			case FSL_DDR_CS2_CS3:
+				/* CS2+CS3 interleaving*/
+				if (i == 2) {
+					sa = dimm_params[i/2].base_address;
+					ea = sa + (2 * (rank_density >>
+						dbw_cap_adj)) - 1;
+				}
+				break;
+			default:  /* No bank(chip-select) interleaving */
+				break;
+			}
+		}
+		else if (popts->memctl_interleaving && !popts->ba_intlv_ctl) {
+			/*
+			 * Only the rank on CS0 of each memory controller may
+			 * be used if memory controller interleaving is used
+			 * without rank interleaving within each memory
+			 * controller.  However, the ending address programmed
+			 * into each CS0 must be the sum of the amount of
+			 * memory in the two CS0 ranks.
+			 */
+			if (i == 0) {
+				unsigned long long rank_density
+						= dimm_params[0].rank_density;
+				ea = (2 * (rank_density >> dbw_cap_adj)) - 1;
+			}
+
+		}
+		else if (!popts->memctl_interleaving && !popts->ba_intlv_ctl) {
+			/*
+			 * No rank interleaving and no memory controller
+			 * interleaving.
+			 */
+			unsigned long long rank_density
+						= dimm_params[i/2].rank_density;
+			sa = dimm_params[i/2].base_address;
+			ea = sa + (rank_density >> dbw_cap_adj) - 1;
+			if (i&1) {
+				if ((dimm_params[i/2].n_ranks == 1)) {
+					/* Odd chip select, single-rank dimm */
+					sa = 0;
+					ea = 0;
+				} else {
+					/* Odd chip select, dual-rank DIMM */
+					sa += rank_density >> dbw_cap_adj;
+					ea += rank_density >> dbw_cap_adj;
+				}
+			}
+		}
+
+		sa >>= 24;
+		ea >>= 24;
+
+		ddr->cs[i].bnds = (0
+			| ((sa & 0xFFF) << 16)	/* starting address MSB */
+			| ((ea & 0xFFF) << 0)	/* ending address MSB */
+			);
+
+		debug("FSLDDR: cs[%d]_bnds = 0x%08x\n", i, ddr->cs[i].bnds);
+		set_csn_config(i, ddr, popts, dimm_params);
+		set_csn_config_2(i, ddr);
+	}
+
+#if !defined(CONFIG_FSL_DDR1)
+	set_timing_cfg_0(ddr);
+#endif
+
+	set_timing_cfg_3(ddr, common_dimm, cas_latency);
+	set_timing_cfg_1(ddr, popts, common_dimm, cas_latency);
+	set_timing_cfg_2(ddr, popts, common_dimm,
+				cas_latency, additive_latency);
+
+	set_ddr_sdram_cfg(ddr, popts, common_dimm);
+
+	set_ddr_sdram_cfg_2(ddr, popts);
+	set_ddr_sdram_mode(ddr, popts, common_dimm,
+				cas_latency, additive_latency);
+	set_ddr_sdram_mode_2(ddr, popts);
+	set_ddr_sdram_interval(ddr, popts, common_dimm);
+	set_ddr_data_init(ddr);
+	set_ddr_sdram_clk_cntl(ddr, popts);
+	set_ddr_init_addr(ddr);
+	set_ddr_init_ext_addr(ddr);
+	set_timing_cfg_4(ddr, popts);
+	set_timing_cfg_5(ddr);
+
+	set_ddr_zq_cntl(ddr, zq_en);
+	set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts);
+
+	set_ddr_sr_cntr(ddr, sr_it);
+
+	set_ddr_sdram_rcw_1(ddr);
+	set_ddr_sdram_rcw_2(ddr);
+
+	return check_fsl_memctl_config_regs(ddr);
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/ddr.h b/arch/ppc/cpu/mpc8xxx/ddr/ddr.h
new file mode 100644
index 0000000..f122075
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/ddr.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef FSL_DDR_MAIN_H
+#define FSL_DDR_MAIN_H
+
+#include <asm/fsl_ddr_sdram.h>
+#include <asm/fsl_ddr_dimm_params.h>
+
+#include "common_timing_params.h"
+
+/*
+ * Bind the main DDR setup driver's generic names
+ * to this specific DDR technology.
+ */
+static __inline__ int
+compute_dimm_parameters(const generic_spd_eeprom_t *spd,
+			dimm_params_t *pdimm,
+			unsigned int dimm_number)
+{
+	return ddr_compute_dimm_parameters(spd, pdimm, dimm_number);
+}
+
+/*
+ * Data Structures
+ *
+ * All data structures have to be on the stack
+ */
+#define CONFIG_SYS_NUM_DDR_CTLRS CONFIG_NUM_DDR_CONTROLLERS
+#define CONFIG_SYS_DIMM_SLOTS_PER_CTLR CONFIG_DIMM_SLOTS_PER_CTLR
+
+typedef struct {
+	generic_spd_eeprom_t
+	   spd_installed_dimms[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_SYS_DIMM_SLOTS_PER_CTLR];
+	struct dimm_params_s
+	   dimm_params[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_SYS_DIMM_SLOTS_PER_CTLR];
+	memctl_options_t memctl_opts[CONFIG_SYS_NUM_DDR_CTLRS];
+	common_timing_params_t common_timing_params[CONFIG_SYS_NUM_DDR_CTLRS];
+	fsl_ddr_cfg_regs_t fsl_ddr_config_reg[CONFIG_SYS_NUM_DDR_CTLRS];
+} fsl_ddr_info_t;
+
+/* Compute steps */
+#define STEP_GET_SPD                 (1 << 0)
+#define STEP_COMPUTE_DIMM_PARMS      (1 << 1)
+#define STEP_COMPUTE_COMMON_PARMS    (1 << 2)
+#define STEP_GATHER_OPTS             (1 << 3)
+#define STEP_ASSIGN_ADDRESSES        (1 << 4)
+#define STEP_COMPUTE_REGS            (1 << 5)
+#define STEP_PROGRAM_REGS            (1 << 6)
+#define STEP_ALL                     0xFFF
+
+extern unsigned long long
+fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step);
+
+extern const char * step_to_string(unsigned int step);
+
+extern unsigned int
+compute_fsl_memctl_config_regs(const memctl_options_t *popts,
+			       fsl_ddr_cfg_regs_t *ddr,
+			       const common_timing_params_t *common_dimm,
+			       const dimm_params_t *dimm_parameters,
+			       unsigned int dbw_capacity_adjust);
+extern unsigned int
+compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
+				      common_timing_params_t *outpdimm,
+				      unsigned int number_of_dimms);
+extern unsigned int populate_memctl_options(int all_DIMMs_registered,
+				memctl_options_t *popts,
+				dimm_params_t *pdimm,
+				unsigned int ctrl_num);
+
+extern unsigned int mclk_to_picos(unsigned int mclk);
+extern unsigned int get_memory_clk_period_ps(void);
+extern unsigned int picos_to_mclk(unsigned int picos);
+
+#endif
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c b/arch/ppc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c
new file mode 100644
index 0000000..9184764
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ *		DDR I	DDR II
+ *	Bit	Size	Size
+ *	---	-----	------
+ *	7 high	512MB	512MB
+ *	6	256MB	256MB
+ *	5	128MB	128MB
+ *	4	 64MB	 16GB
+ *	3	 32MB	  8GB
+ *	2	 16MB	  4GB
+ *	1	  2GB	  2GB
+ *	0 low	  1GB	  1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ */
+
+static unsigned long long
+compute_ranksize(unsigned int mem_type, unsigned char row_dens)
+{
+	unsigned long long bsize;
+
+	/* Bottom 2 bits up to the top. */
+	bsize = ((row_dens >> 2) | ((row_dens & 3) << 6));
+	bsize <<= 24ULL;
+	debug("DDR: DDR I rank density = 0x%08x\n", bsize);
+
+	return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II.  No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+static unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+	/* Table look up the lower nibble, allow DDR I & II. */
+	unsigned int tenths_ps[16] = {
+		0,
+		100,
+		200,
+		300,
+		400,
+		500,
+		600,
+		700,
+		800,
+		900,
+		250,	/* This and the next 3 entries valid ... */
+		330,	/* ...  only for tCK calculations. */
+		660,
+		750,
+		0,	/* undefined */
+		0	/* undefined */
+	};
+
+	unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+	unsigned int tenth_ns = spd_val & 0x0F;
+	unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+	return ps;
+}
+
+static unsigned int
+convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
+{
+	unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
+	unsigned int hundredth_ns = spd_val & 0x0F;
+	unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
+
+	return ps;
+}
+
+static unsigned int byte40_table_ps[8] = {
+	0,
+	250,
+	330,
+	500,
+	660,
+	750,
+	0,	/* supposed to be RFC, but not sure what that means */
+	0	/* Undefined */
+};
+
+static unsigned int
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+	unsigned int trfc_ps;
+
+	trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
+		+ byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+
+	return trfc_ps;
+}
+
+static unsigned int
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+	unsigned int trc_ps;
+
+	trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+
+	return trc_ps;
+}
+
+/*
+ * tCKmax from DDR I SPD Byte 43
+ *
+ * Bits 7:2 == whole ns
+ * Bits 1:0 == quarter ns
+ *    00    == 0.00 ns
+ *    01    == 0.25 ns
+ *    10    == 0.50 ns
+ *    11    == 0.75 ns
+ *
+ * Returns picoseconds.
+ */
+static unsigned int
+compute_tckmax_from_spd_ps(unsigned int byte43)
+{
+	return (byte43 >> 2) * 1000 + (byte43 & 0x3) * 250;
+}
+
+/*
+ * Determine Refresh Rate.  Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static unsigned int
+determine_refresh_rate_ps(const unsigned int spd_refresh)
+{
+	unsigned int refresh_time_ps[8] = {
+		15625000,	/* 0 Normal    1.00x */
+		3900000,	/* 1 Reduced    .25x */
+		7800000,	/* 2 Extended   .50x */
+		31300000,	/* 3 Extended  2.00x */
+		62500000,	/* 4 Extended  4.00x */
+		125000000,	/* 5 Extended  8.00x */
+		15625000,	/* 6 Normal    1.00x  filler */
+		15625000,	/* 7 Normal    1.00x  filler */
+	};
+
+	return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period.  The SPD only
+ * defines at most 3 CAS latencies.  Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can be.
+ * If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed bin table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD.  This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-E
+ * Table 11.
+ *
+ * ordinal 2, ddr1_speed_bins[1] contains tCK for CL=2
+ */
+				  /*   CL2.0 CL2.5 CL3.0  */
+unsigned short ddr1_speed_bins[] = {0, 7500, 6000, 5000 };
+
+unsigned int
+compute_derated_DDR1_CAS_latency(unsigned int mclk_ps)
+{
+	const unsigned int num_speed_bins = ARRAY_SIZE(ddr1_speed_bins);
+	unsigned int lowest_tCKmin_found = 0;
+	unsigned int lowest_tCKmin_CL = 0;
+	unsigned int i;
+
+	debug("mclk_ps = %u\n", mclk_ps);
+
+	for (i = 0; i < num_speed_bins; i++) {
+		unsigned int x = ddr1_speed_bins[i];
+		debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
+		      i, x, lowest_tCKmin_found);
+		if (x && lowest_tCKmin_found <= x && x <= mclk_ps) {
+			lowest_tCKmin_found = x;
+			lowest_tCKmin_CL = i + 1;
+		}
+	}
+
+	debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
+
+	return lowest_tCKmin_CL;
+}
+
+/*
+ * ddr_compute_dimm_parameters for DDR1 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the dimm_params_t structure pointed by pdimm.
+ *
+ * FIXME: use #define for the retvals
+ */
+unsigned int
+ddr_compute_dimm_parameters(const ddr1_spd_eeprom_t *spd,
+			     dimm_params_t *pdimm,
+			     unsigned int dimm_number)
+{
+	unsigned int retval;
+
+	if (spd->mem_type) {
+		if (spd->mem_type != SPD_MEMTYPE_DDR) {
+			printf("DIMM %u: is not a DDR1 SPD.\n", dimm_number);
+			return 1;
+		}
+	} else {
+		memset(pdimm, 0, sizeof(dimm_params_t));
+		return 1;
+	}
+
+	retval = ddr1_spd_check(spd);
+	if (retval) {
+		printf("DIMM %u: failed checksum\n", dimm_number);
+		return 2;
+	}
+
+	/*
+	 * The part name in ASCII in the SPD EEPROM is not null terminated.
+	 * Guarantee null termination here by presetting all bytes to 0
+	 * and copying the part name in ASCII from the SPD onto it
+	 */
+	memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+	memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+	/* DIMM organization parameters */
+	pdimm->n_ranks = spd->nrows;
+	pdimm->rank_density = compute_ranksize(spd->mem_type, spd->bank_dens);
+	pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+	pdimm->data_width = spd->dataw_lsb;
+	pdimm->primary_sdram_width = spd->primw;
+	pdimm->ec_sdram_width = spd->ecw;
+
+	/*
+	 * FIXME: Need to determine registered_dimm status.
+	 *     1 == register buffered
+	 *     0 == unbuffered
+	 */
+	pdimm->registered_dimm = 0;	/* unbuffered */
+
+	/* SDRAM device parameters */
+	pdimm->n_row_addr = spd->nrow_addr;
+	pdimm->n_col_addr = spd->ncol_addr;
+	pdimm->n_banks_per_sdram_device = spd->nbanks;
+	pdimm->edc_config = spd->config;
+	pdimm->burst_lengths_bitmask = spd->burstl;
+	pdimm->row_density = spd->bank_dens;
+
+	/*
+	 * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+	 * The SPD clk_cycle field (tCKmin) is measured in tenths of
+	 * nanoseconds and represented as BCD.
+	 */
+	pdimm->tCKmin_X_ps
+		= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+	pdimm->tCKmin_X_minus_1_ps
+		= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+	pdimm->tCKmin_X_minus_2_ps
+		= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+
+	pdimm->tCKmax_ps = compute_tckmax_from_spd_ps(spd->tckmax);
+
+	/*
+	 * Compute CAS latencies defined by SPD
+	 * The SPD caslat_X should have at least 1 and at most 3 bits set.
+	 *
+	 * If cas_lat after masking is 0, the __ilog2 function returns
+	 * 255 into the variable.   This behavior is abused once.
+	 */
+	pdimm->caslat_X  = __ilog2(spd->cas_lat);
+	pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat
+					  & ~(1 << pdimm->caslat_X));
+	pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat
+					  & ~(1 << pdimm->caslat_X)
+					  & ~(1 << pdimm->caslat_X_minus_1));
+
+	/* Compute CAS latencies below that defined by SPD */
+	pdimm->caslat_lowest_derated
+		= compute_derated_DDR1_CAS_latency(get_memory_clk_period_ps());
+
+	/* Compute timing parameters */
+	pdimm->tRCD_ps = spd->trcd * 250;
+	pdimm->tRP_ps = spd->trp * 250;
+	pdimm->tRAS_ps = spd->tras * 1000;
+
+	pdimm->tWR_ps = mclk_to_picos(3);
+	pdimm->tWTR_ps = mclk_to_picos(1);
+	pdimm->tRFC_ps = compute_trfc_ps_from_spd(0, spd->trfc);
+
+	pdimm->tRRD_ps = spd->trrd * 250;
+	pdimm->tRC_ps = compute_trc_ps_from_spd(0, spd->trc);
+
+	pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+
+	pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+	pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+	pdimm->tDS_ps
+		= convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+	pdimm->tDH_ps
+		= convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+
+	pdimm->tRTP_ps = mclk_to_picos(2);	/* By the book. */
+	pdimm->tDQSQ_max_ps = spd->tdqsq * 10;
+	pdimm->tQHS_ps = spd->tqhs * 10;
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c b/arch/ppc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c
new file mode 100644
index 0000000..d9d0fa7
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ *		DDR I	DDR II
+ *	Bit	Size	Size
+ *	---	-----	------
+ *	7 high	512MB	512MB
+ *	6	256MB	256MB
+ *	5	128MB	128MB
+ *	4	 64MB	 16GB
+ *	3	 32MB	  8GB
+ *	2	 16MB	  4GB
+ *	1	  2GB	  2GB
+ *	0 low	  1GB	  1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ *
+ */
+static unsigned long long
+compute_ranksize(unsigned int mem_type, unsigned char row_dens)
+{
+	unsigned long long bsize;
+
+	/* Bottom 5 bits up to the top. */
+	bsize = ((row_dens >> 5) | ((row_dens & 31) << 3));
+	bsize <<= 27ULL;
+	debug("DDR: DDR II rank density = 0x%08x\n", bsize);
+
+	return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II.  No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+static unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+	/* Table look up the lower nibble, allow DDR I & II. */
+	unsigned int tenths_ps[16] = {
+		0,
+		100,
+		200,
+		300,
+		400,
+		500,
+		600,
+		700,
+		800,
+		900,
+		250,	/* This and the next 3 entries valid ... */
+		330,	/* ...  only for tCK calculations. */
+		660,
+		750,
+		0,	/* undefined */
+		0	/* undefined */
+	};
+
+	unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+	unsigned int tenth_ns = spd_val & 0x0F;
+	unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+	return ps;
+}
+
+static unsigned int
+convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
+{
+	unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
+	unsigned int hundredth_ns = spd_val & 0x0F;
+	unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
+
+	return ps;
+}
+
+static unsigned int byte40_table_ps[8] = {
+	0,
+	250,
+	330,
+	500,
+	660,
+	750,
+	0,	/* supposed to be RFC, but not sure what that means */
+	0	/* Undefined */
+};
+
+static unsigned int
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+	unsigned int trfc_ps;
+
+	trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
+		+ byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+
+	return trfc_ps;
+}
+
+static unsigned int
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+	unsigned int trc_ps;
+
+	trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+
+	return trc_ps;
+}
+
+/*
+ * Determine Refresh Rate.  Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static unsigned int
+determine_refresh_rate_ps(const unsigned int spd_refresh)
+{
+	unsigned int refresh_time_ps[8] = {
+		15625000,	/* 0 Normal    1.00x */
+		3900000,	/* 1 Reduced    .25x */
+		7800000,	/* 2 Extended   .50x */
+		31300000,	/* 3 Extended  2.00x */
+		62500000,	/* 4 Extended  4.00x */
+		125000000,	/* 5 Extended  8.00x */
+		15625000,	/* 6 Normal    1.00x  filler */
+		15625000,	/* 7 Normal    1.00x  filler */
+	};
+
+	return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period.  The SPD only
+ * defines at most 3 CAS latencies.  Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can.
+ * be.  If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed bin table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD.  This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-2C
+ * Table 40, "DDR2 SDRAM stanadard speed bins and tCK, tRCD, tRP, tRAS,
+ * and tRC for corresponding bin"
+ *
+ * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3
+ * Not certain if any good value exists for CL=2
+ */
+				 /* CL2   CL3   CL4   CL5   CL6 */
+unsigned short ddr2_speed_bins[] = {   0, 5000, 3750, 3000, 2500 };
+
+unsigned int
+compute_derated_DDR2_CAS_latency(unsigned int mclk_ps)
+{
+	const unsigned int num_speed_bins = ARRAY_SIZE(ddr2_speed_bins);
+	unsigned int lowest_tCKmin_found = 0;
+	unsigned int lowest_tCKmin_CL = 0;
+	unsigned int i;
+
+	debug("mclk_ps = %u\n", mclk_ps);
+
+	for (i = 0; i < num_speed_bins; i++) {
+		unsigned int x = ddr2_speed_bins[i];
+		debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
+		      i, x, lowest_tCKmin_found);
+		if (x && x <= mclk_ps && x >= lowest_tCKmin_found ) {
+			lowest_tCKmin_found = x;
+			lowest_tCKmin_CL = i + 2;
+		}
+	}
+
+	debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
+
+	return lowest_tCKmin_CL;
+}
+
+/*
+ * ddr_compute_dimm_parameters for DDR2 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the dimm_params_t structure pointed by pdimm.
+ *
+ * FIXME: use #define for the retvals
+ */
+unsigned int
+ddr_compute_dimm_parameters(const ddr2_spd_eeprom_t *spd,
+			     dimm_params_t *pdimm,
+			     unsigned int dimm_number)
+{
+	unsigned int retval;
+
+	if (spd->mem_type) {
+		if (spd->mem_type != SPD_MEMTYPE_DDR2) {
+			printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number);
+			return 1;
+		}
+	} else {
+		memset(pdimm, 0, sizeof(dimm_params_t));
+		return 1;
+	}
+
+	retval = ddr2_spd_check(spd);
+	if (retval) {
+		printf("DIMM %u: failed checksum\n", dimm_number);
+		return 2;
+	}
+
+	/*
+	 * The part name in ASCII in the SPD EEPROM is not null terminated.
+	 * Guarantee null termination here by presetting all bytes to 0
+	 * and copying the part name in ASCII from the SPD onto it
+	 */
+	memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+	memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+	/* DIMM organization parameters */
+	pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1;
+	pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens);
+	pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+	pdimm->data_width = spd->dataw;
+	pdimm->primary_sdram_width = spd->primw;
+	pdimm->ec_sdram_width = spd->ecw;
+
+	/* FIXME: what about registered SO-DIMM? */
+	switch (spd->dimm_type) {
+	case 0x01:	/* RDIMM */
+	case 0x10:	/* Mini-RDIMM */
+		pdimm->registered_dimm = 1; /* register buffered */
+		break;
+
+	case 0x02:	/* UDIMM */
+	case 0x04:	/* SO-DIMM */
+	case 0x08:	/* Micro-DIMM */
+	case 0x20:	/* Mini-UDIMM */
+		pdimm->registered_dimm = 0;	/* unbuffered */
+		break;
+
+	default:
+		printf("unknown dimm_type 0x%02X\n", spd->dimm_type);
+		return 1;
+		break;
+	}
+
+	/* SDRAM device parameters */
+	pdimm->n_row_addr = spd->nrow_addr;
+	pdimm->n_col_addr = spd->ncol_addr;
+	pdimm->n_banks_per_sdram_device = spd->nbanks;
+	pdimm->edc_config = spd->config;
+	pdimm->burst_lengths_bitmask = spd->burstl;
+	pdimm->row_density = spd->rank_dens;
+
+	/*
+	 * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+	 * The SPD clk_cycle field (tCKmin) is measured in tenths of
+	 * nanoseconds and represented as BCD.
+	 */
+	pdimm->tCKmin_X_ps
+		= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+	pdimm->tCKmin_X_minus_1_ps
+		= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+	pdimm->tCKmin_X_minus_2_ps
+		= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+
+	pdimm->tCKmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax);
+
+	/*
+	 * Compute CAS latencies defined by SPD
+	 * The SPD caslat_X should have at least 1 and at most 3 bits set.
+	 *
+	 * If cas_lat after masking is 0, the __ilog2 function returns
+	 * 255 into the variable.   This behavior is abused once.
+	 */
+	pdimm->caslat_X  = __ilog2(spd->cas_lat);
+	pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat
+					  & ~(1 << pdimm->caslat_X));
+	pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat
+					  & ~(1 << pdimm->caslat_X)
+					  & ~(1 << pdimm->caslat_X_minus_1));
+
+	/* Compute CAS latencies below that defined by SPD */
+	pdimm->caslat_lowest_derated
+		= compute_derated_DDR2_CAS_latency(get_memory_clk_period_ps());
+
+	/* Compute timing parameters */
+	pdimm->tRCD_ps = spd->trcd * 250;
+	pdimm->tRP_ps = spd->trp * 250;
+	pdimm->tRAS_ps = spd->tras * 1000;
+
+	pdimm->tWR_ps = spd->twr * 250;
+	pdimm->tWTR_ps = spd->twtr * 250;
+	pdimm->tRFC_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc);
+
+	pdimm->tRRD_ps = spd->trrd * 250;
+	pdimm->tRC_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc);
+
+	pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+
+	pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+	pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+	pdimm->tDS_ps
+		= convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+	pdimm->tDH_ps
+		= convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+
+	pdimm->tRTP_ps = spd->trtp * 250;
+	pdimm->tDQSQ_max_ps = spd->tdqsq * 10;
+	pdimm->tQHS_ps = spd->tqhs * 10;
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c b/arch/ppc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
new file mode 100644
index 0000000..d4199ba
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *	Dave Liu <daveliu@freescale.com>
+ *
+ * calculate the organization and timing parameter
+ * from ddr3 spd, please refer to the spec
+ * JEDEC standard No.21-C 4_01_02_11R18.pdf
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * each rank size =
+ * sdram capacity(bit) / 8 * primary bus width / sdram width
+ *
+ * where: sdram capacity  = spd byte4[3:0]
+ *        primary bus width = spd byte8[2:0]
+ *        sdram width = spd byte7[2:0]
+ *
+ * SPD byte4 - sdram density and banks
+ *	bit[3:0]	size(bit)	size(byte)
+ *	0000		256Mb		32MB
+ *	0001		512Mb		64MB
+ *	0010		1Gb		128MB
+ *	0011		2Gb		256MB
+ *	0100		4Gb		512MB
+ *	0101		8Gb		1GB
+ *	0110		16Gb		2GB
+ *
+ * SPD byte8 - module memory bus width
+ * 	bit[2:0]	primary bus width
+ *	000		8bits
+ * 	001		16bits
+ * 	010		32bits
+ * 	011		64bits
+ *
+ * SPD byte7 - module organiztion
+ * 	bit[2:0]	sdram device width
+ * 	000		4bits
+ * 	001		8bits
+ * 	010		16bits
+ * 	011		32bits
+ *
+ */
+static unsigned long long
+compute_ranksize(const ddr3_spd_eeprom_t *spd)
+{
+	unsigned long long bsize;
+
+	int nbit_sdram_cap_bsize = 0;
+	int nbit_primary_bus_width = 0;
+	int nbit_sdram_width = 0;
+
+	if ((spd->density_banks & 0xf) < 7)
+		nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
+	if ((spd->bus_width & 0x7) < 4)
+		nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
+	if ((spd->organization & 0x7) < 4)
+		nbit_sdram_width = (spd->organization & 0x7) + 2;
+
+	bsize = 1ULL << (nbit_sdram_cap_bsize - 3
+		    + nbit_primary_bus_width - nbit_sdram_width);
+
+	debug("DDR: DDR III rank density = 0x%16lx\n", bsize);
+
+	return bsize;
+}
+
+/*
+ * ddr_compute_dimm_parameters for DDR3 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the dimm_params_t structure pointed by pdimm.
+ *
+ */
+unsigned int
+ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
+			     dimm_params_t *pdimm,
+			     unsigned int dimm_number)
+{
+	unsigned int retval;
+	unsigned int mtb_ps;
+
+	if (spd->mem_type) {
+		if (spd->mem_type != SPD_MEMTYPE_DDR3) {
+			printf("DIMM %u: is not a DDR3 SPD.\n", dimm_number);
+			return 1;
+		}
+	} else {
+		memset(pdimm, 0, sizeof(dimm_params_t));
+		return 1;
+	}
+
+	retval = ddr3_spd_check(spd);
+	if (retval) {
+		printf("DIMM %u: failed checksum\n", dimm_number);
+		return 2;
+	}
+
+	/*
+	 * The part name in ASCII in the SPD EEPROM is not null terminated.
+	 * Guarantee null termination here by presetting all bytes to 0
+	 * and copying the part name in ASCII from the SPD onto it
+	 */
+	memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+	memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+	/* DIMM organization parameters */
+	pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
+	pdimm->rank_density = compute_ranksize(spd);
+	pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+	pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
+	if ((spd->bus_width >> 3) & 0x3)
+		pdimm->ec_sdram_width = 8;
+	else
+		pdimm->ec_sdram_width = 0;
+	pdimm->data_width = pdimm->primary_sdram_width
+			  + pdimm->ec_sdram_width;
+
+	switch (spd->module_type & 0xf) {
+	case 0x01:	/* RDIMM */
+	case 0x05:	/* Mini-RDIMM */
+		pdimm->registered_dimm = 1; /* register buffered */
+		break;
+
+	case 0x02:	/* UDIMM */
+	case 0x03:	/* SO-DIMM */
+	case 0x04:	/* Micro-DIMM */
+	case 0x06:	/* Mini-UDIMM */
+		pdimm->registered_dimm = 0;	/* unbuffered */
+		break;
+
+	default:
+		printf("unknown dimm_type 0x%02X\n", spd->module_type);
+		return 1;
+	}
+
+	/* SDRAM device parameters */
+	pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
+	pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
+	pdimm->n_banks_per_sdram_device = 8 << ((spd->density_banks >> 4) & 0x7);
+
+	/*
+	 * The SPD spec has not the ECC bit,
+	 * We consider the DIMM as ECC capability
+	 * when the extension bus exist
+	 */
+	if (pdimm->ec_sdram_width)
+		pdimm->edc_config = 0x02;
+	else
+		pdimm->edc_config = 0x00;
+
+	/*
+	 * The SPD spec has not the burst length byte
+	 * but DDR3 spec has nature BL8 and BC4,
+	 * BL8 -bit3, BC4 -bit2
+	 */
+	pdimm->burst_lengths_bitmask = 0x0c;
+	pdimm->row_density = __ilog2(pdimm->rank_density);
+
+	/* MTB - medium timebase
+	 * The unit in the SPD spec is ns,
+	 * We convert it to ps.
+	 * eg: MTB = 0.125ns (125ps)
+	 */
+	mtb_ps = (spd->mtb_dividend * 1000) /spd->mtb_divisor;
+	pdimm->mtb_ps = mtb_ps;
+
+	/*
+	 * sdram minimum cycle time
+	 * we assume the MTB is 0.125ns
+	 * eg:
+	 * tCK_min=15 MTB (1.875ns) ->DDR3-1066
+	 *        =12 MTB (1.5ns) ->DDR3-1333
+	 *        =10 MTB (1.25ns) ->DDR3-1600
+	 */
+	pdimm->tCKmin_X_ps = spd->tCK_min * mtb_ps;
+
+	/*
+	 * CAS latency supported
+	 * bit4 - CL4
+	 * bit5 - CL5
+	 * bit18 - CL18
+	 */
+	pdimm->caslat_X  = ((spd->caslat_msb << 8) | spd->caslat_lsb) << 4;
+
+	/*
+	 * min CAS latency time
+	 * eg: tAA_min =
+	 * DDR3-800D	100 MTB (12.5ns)
+	 * DDR3-1066F	105 MTB (13.125ns)
+	 * DDR3-1333H	108 MTB (13.5ns)
+	 * DDR3-1600H	90 MTB (11.25ns)
+	 */
+	pdimm->tAA_ps = spd->tAA_min * mtb_ps;
+
+	/*
+	 * min write recovery time
+	 * eg:
+	 * tWR_min = 120 MTB (15ns) -> all speed grades.
+	 */
+	pdimm->tWR_ps = spd->tWR_min * mtb_ps;
+
+	/*
+	 * min RAS to CAS delay time
+	 * eg: tRCD_min =
+	 * DDR3-800	100 MTB (12.5ns)
+	 * DDR3-1066F	105 MTB (13.125ns)
+	 * DDR3-1333H	108 MTB (13.5ns)
+	 * DDR3-1600H	90 MTB (11.25)
+	 */
+	pdimm->tRCD_ps = spd->tRCD_min * mtb_ps;
+
+	/*
+	 * min row active to row active delay time
+	 * eg: tRRD_min =
+	 * DDR3-800(1KB page)	80 MTB (10ns)
+	 * DDR3-1333(1KB page)	48 MTB (6ns)
+	 */
+	pdimm->tRRD_ps = spd->tRRD_min * mtb_ps;
+
+	/*
+	 * min row precharge delay time
+	 * eg: tRP_min =
+	 * DDR3-800D	100 MTB (12.5ns)
+	 * DDR3-1066F	105 MTB (13.125ns)
+	 * DDR3-1333H	108 MTB (13.5ns)
+	 * DDR3-1600H	90 MTB (11.25ns)
+	 */
+	pdimm->tRP_ps = spd->tRP_min * mtb_ps;
+
+	/* min active to precharge delay time
+	 * eg: tRAS_min =
+	 * DDR3-800D	300 MTB (37.5ns)
+	 * DDR3-1066F	300 MTB (37.5ns)
+	 * DDR3-1333H	288 MTB (36ns)
+	 * DDR3-1600H	280 MTB (35ns)
+	 */
+	pdimm->tRAS_ps = (((spd->tRAS_tRC_ext & 0xf) << 8) | spd->tRAS_min_lsb)
+			* mtb_ps;
+	/*
+	 * min active to actice/refresh delay time
+	 * eg: tRC_min =
+	 * DDR3-800D	400 MTB (50ns)
+	 * DDR3-1066F	405 MTB (50.625ns)
+	 * DDR3-1333H	396 MTB (49.5ns)
+	 * DDR3-1600H	370 MTB (46.25ns)
+	 */
+	pdimm->tRC_ps = (((spd->tRAS_tRC_ext & 0xf0) << 4) | spd->tRC_min_lsb)
+			* mtb_ps;
+	/*
+	 * min refresh recovery delay time
+	 * eg: tRFC_min =
+	 * 512Mb	720 MTB (90ns)
+	 * 1Gb		880 MTB (110ns)
+	 * 2Gb		1280 MTB (160ns)
+	 */
+	pdimm->tRFC_ps = ((spd->tRFC_min_msb << 8) | spd->tRFC_min_lsb)
+			* mtb_ps;
+	/*
+	 * min internal write to read command delay time
+	 * eg: tWTR_min = 40 MTB (7.5ns) - all speed bins.
+	 * tWRT is at least 4 mclk independent of operating freq.
+	 */
+	pdimm->tWTR_ps = spd->tWTR_min * mtb_ps;
+
+	/*
+	 * min internal read to precharge command delay time
+	 * eg: tRTP_min = 40 MTB (7.5ns) - all speed bins.
+	 * tRTP is at least 4 mclk independent of operating freq.
+	 */
+	pdimm->tRTP_ps = spd->tRTP_min * mtb_ps;
+
+	/*
+	 * Average periodic refresh interval
+	 * tREFI = 7.8 us at normal temperature range
+	 *       = 3.9 us at ext temperature range
+	 */
+	pdimm->refresh_rate_ps = 7800000;
+
+	/*
+	 * min four active window delay time
+	 * eg: tFAW_min =
+	 * DDR3-800(1KB page)	320 MTB (40ns)
+	 * DDR3-1066(1KB page)	300 MTB (37.5ns)
+	 * DDR3-1333(1KB page)	240 MTB (30ns)
+	 * DDR3-1600(1KB page)	240 MTB (30ns)
+	 */
+	pdimm->tFAW_ps = (((spd->tFAW_msb & 0xf) << 8) | spd->tFAW_min)
+			* mtb_ps;
+
+	/*
+	 * We need check the address mirror for unbuffered DIMM
+	 * If SPD indicate the address map mirror, The DDR controller
+	 * need care it.
+	 */
+	if ((spd->module_type == SPD_MODULETYPE_UDIMM) ||
+	    (spd->module_type == SPD_MODULETYPE_SODIMM) ||
+	    (spd->module_type == SPD_MODULETYPE_MICRODIMM) ||
+	    (spd->module_type == SPD_MODULETYPE_MINIUDIMM))
+		pdimm->mirrored_dimm = spd->mod_section.unbuffered.addr_mapping & 0x1;
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c b/arch/ppc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
new file mode 100644
index 0000000..e888e3e
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+unsigned int
+compute_cas_latency_ddr3(const dimm_params_t *dimm_params,
+			 common_timing_params_t *outpdimm,
+			 unsigned int number_of_dimms)
+{
+	unsigned int i;
+	unsigned int tAAmin_ps = 0;
+	unsigned int tCKmin_X_ps = 0;
+	unsigned int common_caslat;
+	unsigned int caslat_actual;
+	unsigned int retry = 16;
+	unsigned int tmp;
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+
+	/* compute the common CAS latency supported between slots */
+	tmp = dimm_params[0].caslat_X;
+	for (i = 1; i < number_of_dimms; i++)
+		 tmp &= dimm_params[i].caslat_X;
+	common_caslat = tmp;
+
+	/* compute the max tAAmin tCKmin between slots */
+	for (i = 0; i < number_of_dimms; i++) {
+		tAAmin_ps = max(tAAmin_ps, dimm_params[i].tAA_ps);
+		tCKmin_X_ps = max(tCKmin_X_ps, dimm_params[i].tCKmin_X_ps);
+	}
+	/* validate if the memory clk is in the range of dimms */
+	if (mclk_ps < tCKmin_X_ps) {
+		printf("The DIMM max tCKmin is %d ps,"
+			"doesn't support the MCLK cycle %d ps\n",
+			tCKmin_X_ps, mclk_ps);
+		return 1;
+	}
+	/* determine the acutal cas latency */
+	caslat_actual = (tAAmin_ps + mclk_ps - 1) / mclk_ps;
+	/* check if the dimms support the CAS latency */
+	while (!(common_caslat & (1 << caslat_actual)) && retry > 0) {
+		caslat_actual++;
+		retry--;
+	}
+	/* once the caculation of caslat_actual is completed
+	 * we must verify that this CAS latency value does not
+	 * exceed tAAmax, which is 20 ns for all DDR3 speed grades
+	 */
+	if (caslat_actual * mclk_ps > 20000) {
+		printf("The choosen cas latency %d is too large\n",
+			caslat_actual);
+		return 1;
+	}
+	outpdimm->lowest_common_SPD_caslat = caslat_actual;
+
+	return 0;
+}
+
+/*
+ * compute_lowest_common_dimm_parameters()
+ *
+ * Determine the worst-case DIMM timing parameters from the set of DIMMs
+ * whose parameters have been computed into the array pointed to
+ * by dimm_params.
+ */
+unsigned int
+compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
+				      common_timing_params_t *outpdimm,
+				      unsigned int number_of_dimms)
+{
+	unsigned int i;
+
+	unsigned int tCKmin_X_ps = 0;
+	unsigned int tCKmax_ps = 0xFFFFFFFF;
+	unsigned int tCKmax_max_ps = 0;
+	unsigned int tRCD_ps = 0;
+	unsigned int tRP_ps = 0;
+	unsigned int tRAS_ps = 0;
+	unsigned int tWR_ps = 0;
+	unsigned int tWTR_ps = 0;
+	unsigned int tRFC_ps = 0;
+	unsigned int tRRD_ps = 0;
+	unsigned int tRC_ps = 0;
+	unsigned int refresh_rate_ps = 0;
+	unsigned int tIS_ps = 0;
+	unsigned int tIH_ps = 0;
+	unsigned int tDS_ps = 0;
+	unsigned int tDH_ps = 0;
+	unsigned int tRTP_ps = 0;
+	unsigned int tDQSQ_max_ps = 0;
+	unsigned int tQHS_ps = 0;
+
+	unsigned int temp1, temp2;
+	unsigned int additive_latency = 0;
+#if !defined(CONFIG_FSL_DDR3)
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+	unsigned int lowest_good_caslat;
+	unsigned int not_ok;
+
+	debug("using mclk_ps = %u\n", mclk_ps);
+#endif
+
+	temp1 = 0;
+	for (i = 0; i < number_of_dimms; i++) {
+		/*
+		 * If there are no ranks on this DIMM,
+		 * it probably doesn't exist, so skip it.
+		 */
+		if (dimm_params[i].n_ranks == 0) {
+			temp1++;
+			continue;
+		}
+
+		/*
+		 * Find minimum tCKmax_ps to find fastest slow speed,
+		 * i.e., this is the slowest the whole system can go.
+		 */
+		tCKmax_ps = min(tCKmax_ps, dimm_params[i].tCKmax_ps);
+
+		/* Either find maximum value to determine slowest
+		 * speed, delay, time, period, etc */
+		tCKmin_X_ps = max(tCKmin_X_ps, dimm_params[i].tCKmin_X_ps);
+		tCKmax_max_ps = max(tCKmax_max_ps, dimm_params[i].tCKmax_ps);
+		tRCD_ps = max(tRCD_ps, dimm_params[i].tRCD_ps);
+		tRP_ps = max(tRP_ps, dimm_params[i].tRP_ps);
+		tRAS_ps = max(tRAS_ps, dimm_params[i].tRAS_ps);
+		tWR_ps = max(tWR_ps, dimm_params[i].tWR_ps);
+		tWTR_ps = max(tWTR_ps, dimm_params[i].tWTR_ps);
+		tRFC_ps = max(tRFC_ps, dimm_params[i].tRFC_ps);
+		tRRD_ps = max(tRRD_ps, dimm_params[i].tRRD_ps);
+		tRC_ps = max(tRC_ps, dimm_params[i].tRC_ps);
+		tIS_ps = max(tIS_ps, dimm_params[i].tIS_ps);
+		tIH_ps = max(tIH_ps, dimm_params[i].tIH_ps);
+		tDS_ps = max(tDS_ps, dimm_params[i].tDS_ps);
+		tDH_ps = max(tDH_ps, dimm_params[i].tDH_ps);
+		tRTP_ps = max(tRTP_ps, dimm_params[i].tRTP_ps);
+		tQHS_ps = max(tQHS_ps, dimm_params[i].tQHS_ps);
+		refresh_rate_ps = max(refresh_rate_ps,
+				      dimm_params[i].refresh_rate_ps);
+
+		/*
+		 * Find maximum tDQSQ_max_ps to find slowest.
+		 *
+		 * FIXME: is finding the slowest value the correct
+		 * strategy for this parameter?
+		 */
+		tDQSQ_max_ps = max(tDQSQ_max_ps, dimm_params[i].tDQSQ_max_ps);
+	}
+
+	outpdimm->ndimms_present = number_of_dimms - temp1;
+
+	if (temp1 == number_of_dimms) {
+		debug("no dimms this memory controller\n");
+		return 0;
+	}
+
+	outpdimm->tCKmin_X_ps = tCKmin_X_ps;
+	outpdimm->tCKmax_ps = tCKmax_ps;
+	outpdimm->tCKmax_max_ps = tCKmax_max_ps;
+	outpdimm->tRCD_ps = tRCD_ps;
+	outpdimm->tRP_ps = tRP_ps;
+	outpdimm->tRAS_ps = tRAS_ps;
+	outpdimm->tWR_ps = tWR_ps;
+	outpdimm->tWTR_ps = tWTR_ps;
+	outpdimm->tRFC_ps = tRFC_ps;
+	outpdimm->tRRD_ps = tRRD_ps;
+	outpdimm->tRC_ps = tRC_ps;
+	outpdimm->refresh_rate_ps = refresh_rate_ps;
+	outpdimm->tIS_ps = tIS_ps;
+	outpdimm->tIH_ps = tIH_ps;
+	outpdimm->tDS_ps = tDS_ps;
+	outpdimm->tDH_ps = tDH_ps;
+	outpdimm->tRTP_ps = tRTP_ps;
+	outpdimm->tDQSQ_max_ps = tDQSQ_max_ps;
+	outpdimm->tQHS_ps = tQHS_ps;
+
+	/* Determine common burst length for all DIMMs. */
+	temp1 = 0xff;
+	for (i = 0; i < number_of_dimms; i++) {
+		if (dimm_params[i].n_ranks) {
+			temp1 &= dimm_params[i].burst_lengths_bitmask;
+		}
+	}
+	outpdimm->all_DIMMs_burst_lengths_bitmask = temp1;
+
+	/* Determine if all DIMMs registered buffered. */
+	temp1 = temp2 = 0;
+	for (i = 0; i < number_of_dimms; i++) {
+		if (dimm_params[i].n_ranks) {
+			if (dimm_params[i].registered_dimm)
+				temp1 = 1;
+			if (!dimm_params[i].registered_dimm)
+				temp2 = 1;
+		}
+	}
+
+	outpdimm->all_DIMMs_registered = 0;
+	if (temp1 && !temp2) {
+		outpdimm->all_DIMMs_registered = 1;
+	}
+
+	outpdimm->all_DIMMs_unbuffered = 0;
+	if (!temp1 && temp2) {
+		outpdimm->all_DIMMs_unbuffered = 1;
+	}
+
+	/* CHECKME: */
+	if (!outpdimm->all_DIMMs_registered
+	    && !outpdimm->all_DIMMs_unbuffered) {
+		printf("ERROR:  Mix of registered buffered and unbuffered "
+				"DIMMs detected!\n");
+	}
+
+#if defined(CONFIG_FSL_DDR3)
+	if (compute_cas_latency_ddr3(dimm_params, outpdimm, number_of_dimms))
+		return 1;
+#else
+	/*
+	 * Compute a CAS latency suitable for all DIMMs
+	 *
+	 * Strategy for SPD-defined latencies: compute only
+	 * CAS latency defined by all DIMMs.
+	 */
+
+	/*
+	 * Step 1: find CAS latency common to all DIMMs using bitwise
+	 * operation.
+	 */
+	temp1 = 0xFF;
+	for (i = 0; i < number_of_dimms; i++) {
+		if (dimm_params[i].n_ranks) {
+			temp2 = 0;
+			temp2 |= 1 << dimm_params[i].caslat_X;
+			temp2 |= 1 << dimm_params[i].caslat_X_minus_1;
+			temp2 |= 1 << dimm_params[i].caslat_X_minus_2;
+			/*
+			 * FIXME: If there was no entry for X-2 (X-1) in
+			 * the SPD, then caslat_X_minus_2
+			 * (caslat_X_minus_1) contains either 255 or
+			 * 0xFFFFFFFF because that's what the glorious
+			 * __ilog2 function returns for an input of 0.
+			 * On 32-bit PowerPC, left shift counts with bit
+			 * 26 set (that the value of 255 or 0xFFFFFFFF
+			 * will have), cause the destination register to
+			 * be 0.  That is why this works.
+			 */
+			temp1 &= temp2;
+		}
+	}
+
+	/*
+	 * Step 2: check each common CAS latency against tCK of each
+	 * DIMM's SPD.
+	 */
+	lowest_good_caslat = 0;
+	temp2 = 0;
+	while (temp1) {
+		not_ok = 0;
+		temp2 =  __ilog2(temp1);
+		debug("checking common caslat = %u\n", temp2);
+
+		/* Check if this CAS latency will work on all DIMMs at tCK. */
+		for (i = 0; i < number_of_dimms; i++) {
+			if (!dimm_params[i].n_ranks) {
+				continue;
+			}
+			if (dimm_params[i].caslat_X == temp2) {
+				if (mclk_ps >= dimm_params[i].tCKmin_X_ps) {
+					debug("CL = %u ok on DIMM %u at tCK=%u"
+					    " ps with its tCKmin_X_ps of %u\n",
+					       temp2, i, mclk_ps,
+					       dimm_params[i].tCKmin_X_ps);
+					continue;
+				} else {
+					not_ok++;
+				}
+			}
+
+			if (dimm_params[i].caslat_X_minus_1 == temp2) {
+				unsigned int tCKmin_X_minus_1_ps
+					= dimm_params[i].tCKmin_X_minus_1_ps;
+				if (mclk_ps >= tCKmin_X_minus_1_ps) {
+					debug("CL = %u ok on DIMM %u at "
+						"tCK=%u ps with its "
+						"tCKmin_X_minus_1_ps of %u\n",
+					       temp2, i, mclk_ps,
+					       tCKmin_X_minus_1_ps);
+					continue;
+				} else {
+					not_ok++;
+				}
+			}
+
+			if (dimm_params[i].caslat_X_minus_2 == temp2) {
+				unsigned int tCKmin_X_minus_2_ps
+					= dimm_params[i].tCKmin_X_minus_2_ps;
+				if (mclk_ps >= tCKmin_X_minus_2_ps) {
+					debug("CL = %u ok on DIMM %u at "
+						"tCK=%u ps with its "
+						"tCKmin_X_minus_2_ps of %u\n",
+					       temp2, i, mclk_ps,
+					       tCKmin_X_minus_2_ps);
+					continue;
+				} else {
+					not_ok++;
+				}
+			}
+		}
+
+		if (!not_ok) {
+			lowest_good_caslat = temp2;
+		}
+
+		temp1 &= ~(1 << temp2);
+	}
+
+	debug("lowest common SPD-defined CAS latency = %u\n",
+	       lowest_good_caslat);
+	outpdimm->lowest_common_SPD_caslat = lowest_good_caslat;
+
+
+	/*
+	 * Compute a common 'de-rated' CAS latency.
+	 *
+	 * The strategy here is to find the *highest* dereated cas latency
+	 * with the assumption that all of the DIMMs will support a dereated
+	 * CAS latency higher than or equal to their lowest dereated value.
+	 */
+	temp1 = 0;
+	for (i = 0; i < number_of_dimms; i++) {
+		temp1 = max(temp1, dimm_params[i].caslat_lowest_derated);
+	}
+	outpdimm->highest_common_derated_caslat = temp1;
+	debug("highest common dereated CAS latency = %u\n", temp1);
+#endif /* #if defined(CONFIG_FSL_DDR3) */
+
+	/* Determine if all DIMMs ECC capable. */
+	temp1 = 1;
+	for (i = 0; i < number_of_dimms; i++) {
+		if (dimm_params[i].n_ranks && dimm_params[i].edc_config != 2) {
+			temp1 = 0;
+			break;
+		}
+	}
+	if (temp1) {
+		debug("all DIMMs ECC capable\n");
+	} else {
+		debug("Warning: not all DIMMs ECC capable, cant enable ECC\n");
+	}
+	outpdimm->all_DIMMs_ECC_capable = temp1;
+
+#ifndef CONFIG_FSL_DDR3
+	/* FIXME: move to somewhere else to validate. */
+	if (mclk_ps > tCKmax_max_ps) {
+		printf("Warning: some of the installed DIMMs "
+				"can not operate this slowly.\n");
+		return 1;
+	}
+#endif
+	/*
+	 * Compute additive latency.
+	 *
+	 * For DDR1, additive latency should be 0.
+	 *
+	 * For DDR2, with ODT enabled, use "a value" less than ACTTORW,
+	 *	which comes from Trcd, and also note that:
+	 *	    add_lat + caslat must be >= 4
+	 *
+	 * For DDR3, we use the AL=0
+	 *
+	 * When to use additive latency for DDR2:
+	 *
+	 * I. Because you are using CL=3 and need to do ODT on writes and
+	 *    want functionality.
+	 *    1. Are you going to use ODT? (Does your board not have
+	 *      additional termination circuitry for DQ, DQS, DQS_,
+	 *      DM, RDQS, RDQS_ for x4/x8 configs?)
+	 *    2. If so, is your lowest supported CL going to be 3?
+	 *    3. If so, then you must set AL=1 because
+	 *
+	 *       WL >= 3 for ODT on writes
+	 *       RL = AL + CL
+	 *       WL = RL - 1
+	 *       ->
+	 *       WL = AL + CL - 1
+	 *       AL + CL - 1 >= 3
+	 *       AL + CL >= 4
+	 *  QED
+	 *
+	 *  RL >= 3 for ODT on reads
+	 *  RL = AL + CL
+	 *
+	 *  Since CL aren't usually less than 2, AL=0 is a minimum,
+	 *  so the WL-derived AL should be the  -- FIXME?
+	 *
+	 * II. Because you are using auto-precharge globally and want to
+	 *     use additive latency (posted CAS) to get more bandwidth.
+	 *     1. Are you going to use auto-precharge mode globally?
+	 *
+	 *        Use addtivie latency and compute AL to be 1 cycle less than
+	 *        tRCD, i.e. the READ or WRITE command is in the cycle
+	 *        immediately following the ACTIVATE command..
+	 *
+	 * III. Because you feel like it or want to do some sort of
+	 *      degraded-performance experiment.
+	 *     1.  Do you just want to use additive latency because you feel
+	 *         like it?
+	 *
+	 * Validation:  AL is less than tRCD, and within the other
+	 * read-to-precharge constraints.
+	 */
+
+	additive_latency = 0;
+
+#if defined(CONFIG_FSL_DDR2)
+	if (lowest_good_caslat < 4) {
+		additive_latency = picos_to_mclk(tRCD_ps) - lowest_good_caslat;
+		if (mclk_to_picos(additive_latency) > tRCD_ps) {
+			additive_latency = picos_to_mclk(tRCD_ps);
+			debug("setting additive_latency to %u because it was "
+				" greater than tRCD_ps\n", additive_latency);
+		}
+	}
+
+#elif defined(CONFIG_FSL_DDR3)
+	/*
+	 * The system will not use the global auto-precharge mode.
+	 * However, it uses the page mode, so we set AL=0
+	 */
+	additive_latency = 0;
+#endif
+
+	/*
+	 * Validate additive latency
+	 * FIXME: move to somewhere else to validate
+	 *
+	 * AL <= tRCD(min)
+	 */
+	if (mclk_to_picos(additive_latency) > tRCD_ps) {
+		printf("Error: invalid additive latency exceeds tRCD(min).\n");
+		return 1;
+	}
+
+	/*
+	 * RL = CL + AL;  RL >= 3 for ODT_RD_CFG to be enabled
+	 * WL = RL - 1;  WL >= 3 for ODT_WL_CFG to be enabled
+	 * ADD_LAT (the register) must be set to a value less
+	 * than ACTTORW if WL = 1, then AL must be set to 1
+	 * RD_TO_PRE (the register) must be set to a minimum
+	 * tRTP + AL if AL is nonzero
+	 */
+
+	/*
+	 * Additive latency will be applied only if the memctl option to
+	 * use it.
+	 */
+	outpdimm->additive_latency = additive_latency;
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/main.c b/arch/ppc/cpu/mpc8xxx/ddr/main.c
new file mode 100644
index 0000000..faa1af9
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/main.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+extern void fsl_ddr_set_lawbar(
+		const common_timing_params_t *memctl_common_params,
+		unsigned int memctl_interleaved,
+		unsigned int ctrl_num);
+
+/* processor specific function */
+extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+				   unsigned int ctrl_num);
+
+/* Board-specific functions defined in each board's ddr.c */
+extern void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+			   unsigned int ctrl_num);
+
+/*
+ * ASSUMPTIONS:
+ *    - Same number of CONFIG_DIMM_SLOTS_PER_CTLR on each controller
+ *    - Same memory data bus width on all controllers
+ *
+ * NOTES:
+ *
+ * The memory controller and associated documentation use confusing
+ * terminology when referring to the orgranization of DRAM.
+ *
+ * Here is a terminology translation table:
+ *
+ * memory controller/documention  |industry   |this code  |signals
+ * -------------------------------|-----------|-----------|-----------------
+ * physical bank/bank		  |rank       |rank	  |chip select (CS)
+ * logical bank/sub-bank	  |bank       |bank	  |bank address (BA)
+ * page/row			  |row	      |page	  |row address
+ * ???				  |column     |column	  |column address
+ *
+ * The naming confusion is further exacerbated by the descriptions of the
+ * memory controller interleaving feature, where accesses are interleaved
+ * _BETWEEN_ two seperate memory controllers.  This is configured only in
+ * CS0_CONFIG[INTLV_CTL] of each memory controller.
+ *
+ * memory controller documentation | number of chip selects
+ *				   | per memory controller supported
+ * --------------------------------|-----------------------------------------
+ * cache line interleaving	   | 1 (CS0 only)
+ * page interleaving		   | 1 (CS0 only)
+ * bank interleaving		   | 1 (CS0 only)
+ * superbank interleraving	   | depends on bank (chip select)
+ *				   |   interleraving [rank interleaving]
+ *				   |   mode used on every memory controller
+ *
+ * Even further confusing is the existence of the interleaving feature
+ * _WITHIN_ each memory controller.  The feature is referred to in
+ * documentation as chip select interleaving or bank interleaving,
+ * although it is configured in the DDR_SDRAM_CFG field.
+ *
+ * Name of field		| documentation name	| this code
+ * -----------------------------|-----------------------|------------------
+ * DDR_SDRAM_CFG[BA_INTLV_CTL]	| Bank (chip select)	| rank interleaving
+ *				|  interleaving
+ */
+
+#ifdef DEBUG
+const char *step_string_tbl[] = {
+	"STEP_GET_SPD",
+	"STEP_COMPUTE_DIMM_PARMS",
+	"STEP_COMPUTE_COMMON_PARMS",
+	"STEP_GATHER_OPTS",
+	"STEP_ASSIGN_ADDRESSES",
+	"STEP_COMPUTE_REGS",
+	"STEP_PROGRAM_REGS",
+	"STEP_ALL"
+};
+
+const char * step_to_string(unsigned int step) {
+
+	unsigned int s = __ilog2(step);
+
+	if ((1 << s) != step)
+		return step_string_tbl[7];
+
+	return step_string_tbl[s];
+}
+#endif
+
+int step_assign_addresses(fsl_ddr_info_t *pinfo,
+			  unsigned int dbw_cap_adj[],
+			  unsigned int *memctl_interleaving,
+			  unsigned int *rank_interleaving)
+{
+	int i, j;
+
+	/*
+	 * If a reduced data width is requested, but the SPD
+	 * specifies a physically wider device, adjust the
+	 * computed dimm capacities accordingly before
+	 * assigning addresses.
+	 */
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		unsigned int found = 0;
+
+		switch (pinfo->memctl_opts[i].data_bus_width) {
+		case 2:
+			/* 16-bit */
+			printf("can't handle 16-bit mode yet\n");
+			break;
+
+		case 1:
+			/* 32-bit */
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				unsigned int dw;
+				dw = pinfo->dimm_params[i][j].data_width;
+				if (pinfo->dimm_params[i][j].n_ranks
+				    && (dw == 72 || dw == 64)) {
+					/*
+					 * FIXME: can't really do it
+					 * like this because this just
+					 * further reduces the memory
+					 */
+					found = 1;
+					break;
+				}
+			}
+			if (found) {
+				dbw_cap_adj[i] = 1;
+			}
+			break;
+
+		case 0:
+			/* 64-bit */
+			break;
+
+		default:
+			printf("unexpected data bus width "
+				"specified controller %u\n", i);
+			return 1;
+		}
+	}
+
+	/*
+	 * Check if all controllers are configured for memory
+	 * controller interleaving.
+	 */
+	j = 0;
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		if (pinfo->memctl_opts[i].memctl_interleaving) {
+			j++;
+		}
+	}
+	if (j == 2)
+		*memctl_interleaving = 1;
+
+	/* Check that all controllers are rank interleaving. */
+	j = 0;
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		if (pinfo->memctl_opts[i].ba_intlv_ctl) {
+			j++;
+		}
+	}
+	if (j == 2)
+		*rank_interleaving = 1;
+
+	if (*memctl_interleaving) {
+		unsigned long long addr, total_mem_per_ctlr = 0;
+		/*
+		 * If interleaving between memory controllers,
+		 * make each controller start at a base address
+		 * of 0.
+		 *
+		 * Also, if bank interleaving (chip select
+		 * interleaving) is enabled on each memory
+		 * controller, CS0 needs to be programmed to
+		 * cover the entire memory range on that memory
+		 * controller
+		 *
+		 * Bank interleaving also implies that each
+		 * addressed chip select is identical in size.
+		 */
+
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			addr = 0;
+			pinfo->common_timing_params[i].base_address = 0ull;
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				unsigned long long cap
+					= pinfo->dimm_params[i][j].capacity;
+
+				pinfo->dimm_params[i][j].base_address = addr;
+				addr += cap >> dbw_cap_adj[i];
+				total_mem_per_ctlr += cap >> dbw_cap_adj[i];
+			}
+		}
+		pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr;
+	} else {
+		/*
+		 * Simple linear assignment if memory
+		 * controllers are not interleaved.
+		 */
+		unsigned long long cur_memsize = 0;
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			u64 total_mem_per_ctlr = 0;
+			pinfo->common_timing_params[i].base_address =
+						cur_memsize;
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				/* Compute DIMM base addresses. */
+				unsigned long long cap =
+					pinfo->dimm_params[i][j].capacity;
+				pinfo->dimm_params[i][j].base_address =
+					cur_memsize;
+				cur_memsize += cap >> dbw_cap_adj[i];
+				total_mem_per_ctlr += cap >> dbw_cap_adj[i];
+			}
+			pinfo->common_timing_params[i].total_mem =
+							total_mem_per_ctlr;
+		}
+	}
+
+	return 0;
+}
+
+unsigned long long
+fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step)
+{
+	unsigned int i, j;
+	unsigned int all_controllers_memctl_interleaving = 0;
+	unsigned int all_controllers_rank_interleaving = 0;
+	unsigned long long total_mem = 0;
+
+	fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
+	common_timing_params_t *timing_params = pinfo->common_timing_params;
+
+	/* data bus width capacity adjust shift amount */
+	unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
+
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		dbw_capacity_adjust[i] = 0;
+	}
+
+	debug("starting at step %u (%s)\n",
+	      start_step, step_to_string(start_step));
+
+	switch (start_step) {
+	case STEP_GET_SPD:
+		/* STEP 1:  Gather all DIMM SPD data */
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i);
+		}
+
+	case STEP_COMPUTE_DIMM_PARMS:
+		/* STEP 2:  Compute DIMM parameters from SPD data */
+
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				unsigned int retval;
+				generic_spd_eeprom_t *spd =
+					&(pinfo->spd_installed_dimms[i][j]);
+				dimm_params_t *pdimm =
+					&(pinfo->dimm_params[i][j]);
+
+				retval = compute_dimm_parameters(spd, pdimm, i);
+				if (retval == 2) {
+					printf("Error: compute_dimm_parameters"
+					" non-zero returned FATAL value "
+					"for memctl=%u dimm=%u\n", i, j);
+					return 0;
+				}
+				if (retval) {
+					debug("Warning: compute_dimm_parameters"
+					" non-zero return value for memctl=%u "
+					"dimm=%u\n", i, j);
+				}
+			}
+		}
+
+	case STEP_COMPUTE_COMMON_PARMS:
+		/*
+		 * STEP 3: Compute a common set of timing parameters
+		 * suitable for all of the DIMMs on each memory controller
+		 */
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			debug("Computing lowest common DIMM"
+				" parameters for memctl=%u\n", i);
+			compute_lowest_common_dimm_parameters(
+				pinfo->dimm_params[i],
+				&timing_params[i],
+				CONFIG_DIMM_SLOTS_PER_CTLR);
+		}
+
+	case STEP_GATHER_OPTS:
+		/* STEP 4:  Gather configuration requirements from user */
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			debug("Reloading memory controller "
+				"configuration options for memctl=%u\n", i);
+			/*
+			 * This "reloads" the memory controller options
+			 * to defaults.  If the user "edits" an option,
+			 * next_step points to the step after this,
+			 * which is currently STEP_ASSIGN_ADDRESSES.
+			 */
+			populate_memctl_options(
+					timing_params[i].all_DIMMs_registered,
+					&pinfo->memctl_opts[i],
+					pinfo->dimm_params[i], i);
+		}
+
+	case STEP_ASSIGN_ADDRESSES:
+		/* STEP 5:  Assign addresses to chip selects */
+		step_assign_addresses(pinfo,
+				dbw_capacity_adjust,
+				&all_controllers_memctl_interleaving,
+				&all_controllers_rank_interleaving);
+
+	case STEP_COMPUTE_REGS:
+		/* STEP 6:  compute controller register values */
+		debug("FSL Memory ctrl cg register computation\n");
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (timing_params[i].ndimms_present == 0) {
+				memset(&ddr_reg[i], 0,
+					sizeof(fsl_ddr_cfg_regs_t));
+				continue;
+			}
+
+			compute_fsl_memctl_config_regs(
+					&pinfo->memctl_opts[i],
+					&ddr_reg[i], &timing_params[i],
+					pinfo->dimm_params[i],
+					dbw_capacity_adjust[i]);
+		}
+
+	default:
+		break;
+	}
+
+	/* Compute the total amount of memory. */
+
+	/*
+	 * If bank interleaving but NOT memory controller interleaving
+	 * CS_BNDS describe the quantity of memory on each memory
+	 * controller, so the total is the sum across.
+	 */
+	if (!all_controllers_memctl_interleaving
+	    && all_controllers_rank_interleaving) {
+		total_mem = 0;
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			total_mem += timing_params[i].total_mem;
+		}
+
+	} else {
+		/*
+		 * Compute the amount of memory available just by
+		 * looking for the highest valid CSn_BNDS value.
+		 * This allows us to also experiment with using
+		 * only CS0 when using dual-rank DIMMs.
+		 */
+		unsigned int max_end = 0;
+
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) {
+				fsl_ddr_cfg_regs_t *reg = &ddr_reg[i];
+				if (reg->cs[j].config & 0x80000000) {
+					unsigned int end;
+					end = reg->cs[j].bnds & 0xFFF;
+					if (end > max_end) {
+						max_end = end;
+					}
+				}
+			}
+		}
+
+		total_mem = 1 + (((unsigned long long)max_end << 24ULL)
+				    | 0xFFFFFFULL);
+	}
+
+	return total_mem;
+}
+
+/*
+ * fsl_ddr_sdram() -- this is the main function to be called by
+ *	initdram() in the board file.
+ *
+ * It returns amount of memory configured in bytes.
+ */
+phys_size_t fsl_ddr_sdram(void)
+{
+	unsigned int i;
+	unsigned int memctl_interleaved;
+	unsigned long long total_memory;
+	fsl_ddr_info_t info;
+
+	/* Reset info structure. */
+	memset(&info, 0, sizeof(fsl_ddr_info_t));
+
+	/* Compute it once normally. */
+	total_memory = fsl_ddr_compute(&info, STEP_GET_SPD);
+
+	/* Check for memory controller interleaving. */
+	memctl_interleaved = 0;
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		memctl_interleaved +=
+			info.memctl_opts[i].memctl_interleaving;
+	}
+
+	if (memctl_interleaved) {
+		if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) {
+			debug("memctl interleaving\n");
+			/*
+			 * Change the meaning of memctl_interleaved
+			 * to be "boolean".
+			 */
+			memctl_interleaved = 1;
+		} else {
+			printf("Warning: memctl interleaving not "
+				"properly configured on all controllers\n");
+			memctl_interleaved = 0;
+			for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+				info.memctl_opts[i].memctl_interleaving = 0;
+			debug("Recomputing with memctl_interleaving off.\n");
+			total_memory = fsl_ddr_compute(&info,
+						       STEP_ASSIGN_ADDRESSES);
+		}
+	}
+
+	/* Program configuration registers. */
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		debug("Programming controller %u\n", i);
+		if (info.common_timing_params[i].ndimms_present == 0) {
+			debug("No dimms present on controller %u; "
+					"skipping programming\n", i);
+			continue;
+		}
+
+		fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i);
+	}
+
+	if (memctl_interleaved) {
+		const unsigned int ctrl_num = 0;
+
+		/* Only set LAWBAR1 if memory controller interleaving is on. */
+		fsl_ddr_set_lawbar(&info.common_timing_params[0],
+					 memctl_interleaved, ctrl_num);
+	} else {
+		/*
+		 * Memory controller interleaving is NOT on;
+		 * set each lawbar individually.
+		 */
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			fsl_ddr_set_lawbar(&info.common_timing_params[i],
+						 0, i);
+		}
+	}
+
+	debug("total_memory = %llu\n", total_memory);
+
+#if !defined(CONFIG_PHYS_64BIT)
+	/* Check for 4G or more.  Bad. */
+	if (total_memory >= (1ull << 32)) {
+		printf("Detected %lld MB of memory\n", total_memory >> 20);
+		printf("This U-Boot only supports < 4G of DDR\n");
+		printf("You could rebuild it with CONFIG_PHYS_64BIT\n");
+		total_memory = CONFIG_MAX_MEM_MAPPED;
+	}
+#endif
+
+	return total_memory;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/options.c b/arch/ppc/cpu/mpc8xxx/ddr/options.c
new file mode 100644
index 0000000..46731c8
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/options.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2008, 2010 Freescale Semiconductor, 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>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+/* Board-specific functions defined in each board's ddr.c */
+extern void fsl_ddr_board_options(memctl_options_t *popts,
+		dimm_params_t *pdimm,
+		unsigned int ctrl_num);
+
+unsigned int populate_memctl_options(int all_DIMMs_registered,
+			memctl_options_t *popts,
+			dimm_params_t *pdimm,
+			unsigned int ctrl_num)
+{
+	unsigned int i;
+	const char *p;
+
+	/* Chip select options. */
+
+	/* Pick chip-select local options. */
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		/* If not DDR2, odt_rd_cfg and odt_wr_cfg need to be 0. */
+
+		/* only for single CS? */
+		popts->cs_local_opts[i].odt_rd_cfg = 0;
+
+		popts->cs_local_opts[i].odt_wr_cfg = 1;
+		popts->cs_local_opts[i].auto_precharge = 0;
+	}
+
+	/* Pick interleaving mode. */
+
+	/*
+	 * 0 = no interleaving
+	 * 1 = interleaving between 2 controllers
+	 */
+	popts->memctl_interleaving = 0;
+
+	/*
+	 * 0 = cacheline
+	 * 1 = page
+	 * 2 = (logical) bank
+	 * 3 = superbank (only if CS interleaving is enabled)
+	 */
+	popts->memctl_interleaving_mode = 0;
+
+	/*
+	 * 0: cacheline: bit 30 of the 36-bit physical addr selects the memctl
+	 * 1: page:      bit to the left of the column bits selects the memctl
+	 * 2: bank:      bit to the left of the bank bits selects the memctl
+	 * 3: superbank: bit to the left of the chip select selects the memctl
+	 *
+	 * NOTE: ba_intlv (rank interleaving) is independent of memory
+	 * controller interleaving; it is only within a memory controller.
+	 * Must use superbank interleaving if rank interleaving is used and
+	 * memory controller interleaving is enabled.
+	 */
+
+	/*
+	 * 0 = no
+	 * 0x40 = CS0,CS1
+	 * 0x20 = CS2,CS3
+	 * 0x60 = CS0,CS1 + CS2,CS3
+	 * 0x04 = CS0,CS1,CS2,CS3
+	 */
+	popts->ba_intlv_ctl = 0;
+
+	/* Memory Organization Parameters */
+	popts->registered_dimm_en = all_DIMMs_registered;
+
+	/* Operational Mode Paramters */
+
+	/* Pick ECC modes */
+#ifdef CONFIG_DDR_ECC
+	popts->ECC_mode = 1;		  /* 0 = disabled, 1 = enabled */
+#else
+	popts->ECC_mode = 0;		  /* 0 = disabled, 1 = enabled */
+#endif
+	popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
+
+	/*
+	 * Choose DQS config
+	 * 0 for DDR1
+	 * 1 for DDR2
+	 */
+#if defined(CONFIG_FSL_DDR1)
+	popts->DQS_config = 0;
+#elif defined(CONFIG_FSL_DDR2) || defined(CONFIG_FSL_DDR3)
+	popts->DQS_config = 1;
+#endif
+
+	/* Choose self-refresh during sleep. */
+	popts->self_refresh_in_sleep = 1;
+
+	/* Choose dynamic power management mode. */
+	popts->dynamic_power = 0;
+
+	/* 0 = 64-bit, 1 = 32-bit, 2 = 16-bit */
+	popts->data_bus_width = 0;
+
+	/* Choose burst length. */
+#if defined(CONFIG_FSL_DDR3)
+#if defined(CONFIG_E500MC)
+	popts->OTF_burst_chop_en = 0;	/* on-the-fly burst chop disable */
+	popts->burst_length = DDR_BL8;	/* Fixed 8-beat burst len */
+#else
+	popts->OTF_burst_chop_en = 1;	/* on-the-fly burst chop */
+	popts->burst_length = DDR_OTF;	/* on-the-fly BC4 and BL8 */
+#endif
+#else
+	popts->burst_length = DDR_BL4;	/* has to be 4 for DDR2 */
+#endif
+
+	/* Choose ddr controller address mirror mode */
+#if defined(CONFIG_FSL_DDR3)
+	popts->mirrored_dimm = pdimm[0].mirrored_dimm;
+#endif
+
+	/* Global Timing Parameters. */
+	debug("mclk_ps = %u ps\n", get_memory_clk_period_ps());
+
+	/* Pick a caslat override. */
+	popts->cas_latency_override = 0;
+	popts->cas_latency_override_value = 3;
+	if (popts->cas_latency_override) {
+		debug("using caslat override value = %u\n",
+		       popts->cas_latency_override_value);
+	}
+
+	/* Decide whether to use the computed derated latency */
+	popts->use_derated_caslat = 0;
+
+	/* Choose an additive latency. */
+	popts->additive_latency_override = 0;
+	popts->additive_latency_override_value = 3;
+	if (popts->additive_latency_override) {
+		debug("using additive latency override value = %u\n",
+		       popts->additive_latency_override_value);
+	}
+
+	/*
+	 * 2T_EN setting
+	 *
+	 * Factors to consider for 2T_EN:
+	 *	- number of DIMMs installed
+	 *	- number of components, number of active ranks
+	 *	- how much time you want to spend playing around
+	 */
+	popts->twoT_en = 0;
+	popts->threeT_en = 0;
+
+	/*
+	 * BSTTOPRE precharge interval
+	 *
+	 * Set this to 0 for global auto precharge
+	 *
+	 * FIXME: Should this be configured in picoseconds?
+	 * Why it should be in ps:  better understanding of this
+	 * relative to actual DRAM timing parameters such as tRAS.
+	 * e.g. tRAS(min) = 40 ns
+	 */
+	popts->bstopre = 0x100;
+
+	/* Minimum CKE pulse width -- tCKE(MIN) */
+	popts->tCKE_clock_pulse_width_ps
+		= mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR);
+
+	/*
+	 * Window for four activates -- tFAW
+	 *
+	 * FIXME: UM: applies only to DDR2/DDR3 with eight logical banks only
+	 * FIXME: varies depending upon number of column addresses or data
+	 * FIXME: width, was considering looking at pdimm->primary_sdram_width
+	 */
+#if defined(CONFIG_FSL_DDR1)
+	popts->tFAW_window_four_activates_ps = mclk_to_picos(1);
+
+#elif defined(CONFIG_FSL_DDR2)
+	/*
+	 * x4/x8;  some datasheets have 35000
+	 * x16 wide columns only?  Use 50000?
+	 */
+	popts->tFAW_window_four_activates_ps = 37500;
+
+#elif defined(CONFIG_FSL_DDR3)
+	popts->tFAW_window_four_activates_ps = pdimm[0].tFAW_ps;
+#endif
+	popts->zq_en = 0;
+	popts->wrlvl_en = 0;
+#if defined(CONFIG_FSL_DDR3)
+	/*
+	 * due to ddr3 dimm is fly-by topology
+	 * we suggest to enable write leveling to
+	 * meet the tQDSS under different loading.
+	 */
+	popts->wrlvl_en = 1;
+	popts->wrlvl_override = 0;
+#endif
+
+	/*
+	 * Check interleaving configuration from environment.
+	 * Please refer to doc/README.fsl-ddr for the detail.
+	 *
+	 * If memory controller interleaving is enabled, then the data
+	 * bus widths must be programmed identically for the 2 memory
+	 * controllers.
+	 *
+	 * XXX: Attempt to set both controllers to the same chip select
+	 * interleaving mode. It will do a best effort to get the
+	 * requested ranks interleaved together such that the result
+	 * should be a subset of the requested configuration.
+	 */
+#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+	if ((p = getenv("memctl_intlv_ctl")) != NULL) {
+		if (pdimm[0].n_ranks == 0) {
+			printf("There is no rank on CS0. Because only rank on "
+				"CS0 and ranks chip-select interleaved with CS0"
+				" are controller interleaved, force non memory "
+				"controller interleaving\n");
+			popts->memctl_interleaving = 0;
+		} else {
+			popts->memctl_interleaving = 1;
+			if (strcmp(p, "cacheline") == 0)
+				popts->memctl_interleaving_mode =
+					FSL_DDR_CACHE_LINE_INTERLEAVING;
+			else if (strcmp(p, "page") == 0)
+				popts->memctl_interleaving_mode =
+					FSL_DDR_PAGE_INTERLEAVING;
+			else if (strcmp(p, "bank") == 0)
+				popts->memctl_interleaving_mode =
+					FSL_DDR_BANK_INTERLEAVING;
+			else if (strcmp(p, "superbank") == 0)
+				popts->memctl_interleaving_mode =
+					FSL_DDR_SUPERBANK_INTERLEAVING;
+			else
+				popts->memctl_interleaving_mode =
+						simple_strtoul(p, NULL, 0);
+		}
+	}
+#endif
+
+	if( ((p = getenv("ba_intlv_ctl")) != NULL) &&
+		(CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
+		if (strcmp(p, "cs0_cs1") == 0)
+			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
+		else if (strcmp(p, "cs2_cs3") == 0)
+			popts->ba_intlv_ctl = FSL_DDR_CS2_CS3;
+		else if (strcmp(p, "cs0_cs1_and_cs2_cs3") == 0)
+			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3;
+		else if (strcmp(p, "cs0_cs1_cs2_cs3") == 0)
+			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3;
+		else
+			popts->ba_intlv_ctl = simple_strtoul(p, NULL, 0);
+
+		switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+		case FSL_DDR_CS0_CS1_CS2_CS3:
+		case FSL_DDR_CS0_CS1:
+			if (pdimm[0].n_ranks != 2) {
+				popts->ba_intlv_ctl = 0;
+				printf("Not enough bank(chip-select) for "
+					"CS0+CS1, force non-interleaving!\n");
+			}
+			break;
+		case FSL_DDR_CS2_CS3:
+			if (pdimm[1].n_ranks !=2){
+				popts->ba_intlv_ctl = 0;
+				printf("Not enough bank(CS) for CS2+CS3, "
+					"force non-interleaving!\n");
+			}
+			break;
+		case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+			if ((pdimm[0].n_ranks != 2)||(pdimm[1].n_ranks != 2)) {
+				popts->ba_intlv_ctl = 0;
+				printf("Not enough bank(CS) for CS0+CS1 or "
+					"CS2+CS3, force non-interleaving!\n");
+			}
+			break;
+		default:
+			popts->ba_intlv_ctl = 0;
+			break;
+		}
+	}
+
+	fsl_ddr_board_options(popts, pdimm, ctrl_num);
+
+	return 0;
+}
diff --git a/arch/ppc/cpu/mpc8xxx/ddr/util.c b/arch/ppc/cpu/mpc8xxx/ddr/util.c
new file mode 100644
index 0000000..1e2d921
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/ddr/util.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_law.h>
+
+#include "ddr.h"
+
+unsigned int fsl_ddr_get_mem_data_rate(void);
+
+/*
+ * Round mclk_ps to nearest 10 ps in memory controller code.
+ *
+ * If an imprecise data rate is too high due to rounding error
+ * propagation, compute a suitably rounded mclk_ps to compute
+ * a working memory controller configuration.
+ */
+unsigned int get_memory_clk_period_ps(void)
+{
+	unsigned int mclk_ps;
+
+	mclk_ps = 2000000000000ULL / fsl_ddr_get_mem_data_rate();
+	/* round to nearest 10 ps */
+	return 10 * ((mclk_ps + 5) / 10);
+}
+
+/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */
+unsigned int picos_to_mclk(unsigned int picos)
+{
+	const unsigned long long ULL_2e12 = 2000000000000ULL;
+	const unsigned long long ULL_8Fs = 0xFFFFFFFFULL;
+	unsigned long long clks;
+	unsigned long long clks_temp;
+
+	if (!picos)
+		return 0;
+
+	clks = fsl_ddr_get_mem_data_rate() * (unsigned long long) picos;
+	clks_temp = clks;
+	clks = clks / ULL_2e12;
+	if (clks_temp % ULL_2e12) {
+		clks++;
+	}
+
+	if (clks > ULL_8Fs) {
+		clks = ULL_8Fs;
+	}
+
+	return (unsigned int) clks;
+}
+
+unsigned int mclk_to_picos(unsigned int mclk)
+{
+	return get_memory_clk_period_ps() * mclk;
+}
+
+void
+__fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
+			   unsigned int memctl_interleaved,
+			   unsigned int ctrl_num)
+{
+	unsigned long long base = memctl_common_params->base_address;
+	unsigned long long size = memctl_common_params->total_mem;
+
+	/*
+	 * If no DIMMs on this controller, do not proceed any further.
+	 */
+	if (!memctl_common_params->ndimms_present) {
+		return;
+	}
+
+#if !defined(CONFIG_PHYS_64BIT)
+	if (base >= CONFIG_MAX_MEM_MAPPED)
+		return;
+	if ((base + size) >= CONFIG_MAX_MEM_MAPPED)
+		size = CONFIG_MAX_MEM_MAPPED - base;
+#endif
+
+	if (ctrl_num == 0) {
+		/*
+		 * Set up LAW for DDR controller 1 space.
+		 */
+		unsigned int lawbar1_target_id = memctl_interleaved
+			? LAW_TRGT_IF_DDR_INTRLV : LAW_TRGT_IF_DDR_1;
+
+		if (set_ddr_laws(base, size, lawbar1_target_id) < 0) {
+			printf("%s: ERROR (ctrl #0, intrlv=%d)\n", __func__,
+				memctl_interleaved);
+			return ;
+		}
+	} else if (ctrl_num == 1) {
+		if (set_ddr_laws(base, size, LAW_TRGT_IF_DDR_2) < 0) {
+			printf("%s: ERROR (ctrl #1)\n", __func__);
+			return ;
+		}
+	} else {
+		printf("%s: unexpected DDR controller number (%u)\n", __func__,
+			ctrl_num);
+	}
+}
+
+__attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void
+fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
+			 unsigned int memctl_interleaved,
+			 unsigned int ctrl_num);
+
+void board_add_ram_info(int use_default)
+{
+#if defined(CONFIG_MPC85xx)
+	volatile ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_MPC85xx_DDR_ADDR);
+#elif defined(CONFIG_MPC86xx)
+	volatile ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_MPC86xx_DDR_ADDR);
+#endif
+#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+	uint32_t cs0_config = in_be32(&ddr->cs0_config);
+#endif
+	uint32_t sdram_cfg = in_be32(&ddr->sdram_cfg);
+	int cas_lat;
+
+	puts(" (DDR");
+	switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
+		SDRAM_CFG_SDRAM_TYPE_SHIFT) {
+	case SDRAM_TYPE_DDR1:
+		puts("1");
+		break;
+	case SDRAM_TYPE_DDR2:
+		puts("2");
+		break;
+	case SDRAM_TYPE_DDR3:
+		puts("3");
+		break;
+	default:
+		puts("?");
+		break;
+	}
+
+	if (sdram_cfg & SDRAM_CFG_32_BE)
+		puts(", 32-bit");
+	else
+		puts(", 64-bit");
+
+	/* Calculate CAS latency based on timing cfg values */
+	cas_lat = ((in_be32(&ddr->timing_cfg_1) >> 16) & 0xf) + 1;
+	if ((in_be32(&ddr->timing_cfg_3) >> 12) & 1)
+		cas_lat += (8 << 1);
+	printf(", CL=%d", cas_lat >> 1);
+	if (cas_lat & 0x1)
+		puts(".5");
+
+	if (sdram_cfg & SDRAM_CFG_ECC_EN)
+		puts(", ECC on)");
+	else
+		puts(", ECC off)");
+
+#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+	if (cs0_config & 0x20000000) {
+		puts("\n");
+		puts("       DDR Controller Interleaving Mode: ");
+
+		switch ((cs0_config >> 24) & 0xf) {
+		case FSL_DDR_CACHE_LINE_INTERLEAVING:
+			puts("cache line");
+			break;
+		case FSL_DDR_PAGE_INTERLEAVING:
+			puts("page");
+			break;
+		case FSL_DDR_BANK_INTERLEAVING:
+			puts("bank");
+			break;
+		case FSL_DDR_SUPERBANK_INTERLEAVING:
+			puts("super-bank");
+			break;
+		default:
+			puts("invalid");
+			break;
+		}
+	}
+#endif
+
+	if ((sdram_cfg >> 8) & 0x7f) {
+		puts("\n");
+		puts("       DDR Chip-Select Interleaving Mode: ");
+		switch(sdram_cfg >> 8 & 0x7f) {
+		case FSL_DDR_CS0_CS1_CS2_CS3:
+			puts("CS0+CS1+CS2+CS3");
+			break;
+		case FSL_DDR_CS0_CS1:
+			puts("CS0+CS1");
+			break;
+		case FSL_DDR_CS2_CS3:
+			puts("CS2+CS3");
+			break;
+		case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+			puts("CS0+CS1 and CS2+CS3");
+			break;
+		default:
+			puts("invalid");
+			break;
+		}
+	}
+}
diff --git a/arch/ppc/cpu/mpc8xxx/fdt.c b/arch/ppc/cpu/mpc8xxx/fdt.c
new file mode 100644
index 0000000..e68d6f3
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/fdt.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * This file is derived from arch/ppc/cpu/mpc85xx/cpu.c and
+ * arch/ppc/cpu/mpc86xx/cpu.c. Basically this file contains
+ * cpu specific common code for 85xx/86xx processors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+void ft_fixup_num_cores(void *blob) {
+	int off, num_cores, del_cores;
+
+	del_cores = 0;
+	num_cores = cpu_numcores();
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	while (off != -FDT_ERR_NOTFOUND) {
+		u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+
+		/* if we find a cpu node outside of what we expect delete it
+		 * and reset the offset back to the start since we can't
+		 * trust the offsets anymore
+		 */
+		if (*reg > num_cores-1) {
+			fdt_del_node(blob, off);
+			del_cores++;
+			off = -1;
+		}
+		off = fdt_node_offset_by_prop_value(blob, off,
+				"device_type", "cpu", 4);
+	}
+	debug ("%x core system found\n", num_cores);
+	debug ("deleted %d extra core entry entries from device tree\n",
+								del_cores);
+}
diff --git a/arch/ppc/cpu/mpc8xxx/pci_cfg.c b/arch/ppc/cpu/mpc8xxx/pci_cfg.c
new file mode 100644
index 0000000..9b7181d
--- /dev/null
+++ b/arch/ppc/cpu/mpc8xxx/pci_cfg.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_law.h>
+#include <pci.h>
+
+struct pci_info {
+	u32	cfg;
+};
+
+/* The cfg field is a bit mask in which each bit represents the value of
+ * cfg_IO_ports[] signal and the bit is set if the interface would be
+ * enabled based on the value of cfg_IO_ports[] signal
+ *
+ * On MPC86xx/PQ3 based systems:
+ *   we extract cfg_IO_ports from GUTS register PORDEVSR
+ *
+ * cfg_IO_ports only exist on systems w/PCIe (we set cfg 0 for systems
+ * without PCIe)
+ */
+
+#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8560)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI] = {
+		.cfg =   0,
+	},
+};
+#elif defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI] = {
+		.cfg =   0,
+	},
+};
+#elif defined(CONFIG_MPC8536)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI] = {
+		.cfg =   0,
+	},
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 2) | (1 << 3) | (1 << 5) | (1 << 7),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 5) | (1 << 7),
+	},
+	[LAW_TRGT_IF_PCIE_3] = {
+		.cfg =   (1 << 7),
+	},
+};
+#elif defined(CONFIG_MPC8544)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI] = {
+		.cfg =   0,
+	},
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) |
+			 (1 << 6) | (1 << 7),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
+	},
+	[LAW_TRGT_IF_PCIE_3] = {
+		.cfg =   (1 << 6) | (1 << 7),
+	},
+};
+#elif defined(CONFIG_MPC8548)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI_1] = {
+		.cfg =   0,
+	},
+	[LAW_TRGT_IF_PCI_2] = {
+		.cfg =   0,
+	},
+	/* PCI_2 is always host and we dont use iosel to determine enable/disable */
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 3) | (1 << 4) | (1 << 7),
+	},
+};
+#elif defined(CONFIG_MPC8568)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI] = {
+		.cfg =   0,
+	},
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 3) | (1 << 4) | (1 << 7),
+	},
+};
+#elif defined(CONFIG_MPC8569)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) |
+			 (1 << 8) | (1 << 0xc) | (1 << 0xf),
+	},
+};
+#elif defined(CONFIG_MPC8572)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 2) | (1 << 3) | (1 << 7) |
+			 (1 << 0xb) | (1 << 0xc) | (1 << 0xf),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 3) | (1 << 7),
+	},
+	[LAW_TRGT_IF_PCIE_3] = {
+		.cfg =   (1 << 7),
+	},
+};
+#elif defined(CONFIG_MPC8610)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCI_1] = {
+		.cfg =   0,
+	},
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 1) | (1 << 4),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 0) | (1 << 4),
+	},
+};
+#elif defined(CONFIG_MPC8641)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) |
+			 (1 << 7) | (1 << 0xe) | (1 << 0xf),
+	},
+};
+#elif defined(CONFIG_P1011) || defined(CONFIG_P1020) || \
+      defined(CONFIG_P1012) || defined(CONFIG_P1021)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 0) | (1 << 6) | (1 << 0xe) | (1 << 0xf),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 0xe),
+	},
+};
+#elif defined(CONFIG_P1013) || defined(CONFIG_P1022)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 6) | (1 << 7) | (1 << 9) | (1 << 0xa) |
+			 (1 << 0xb) | (1 << 0xd) | (1 << 0xe) |
+			 (1 << 0xf) | (1 << 0x15) | (1 << 0x16) |
+			 (1 << 0x17) | (1 << 0x18) | (1 << 0x19) |
+			 (1 << 0x1a) | (1 << 0x1b) | (1 << 0x1c) |
+			 (1 << 0x1d) | (1 << 0x1e) | (1 << 0x1f),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 0) | (1 << 1) | (1 << 6) | (1 << 7) |
+			 (1 << 9) | (1 << 0xa) | (1 << 0xb) | (1 << 0xd) |
+			 (1 << 0x15) | (1 << 0x16) | (1 << 0x17) |
+			 (1 << 0x18) | (1 << 0x1c),
+	},
+	[LAW_TRGT_IF_PCIE_3] = {
+		.cfg =   (1 << 6) | (1 << 7) | (1 << 9) | (1 << 0xd) |
+			 (1 << 0x15) | (1 << 0x16) | (1 << 0x17) | (1 << 0x18) |
+			 (1 << 0x19) | (1 << 0x1a) | (1 << 0x1b),
+	},
+};
+#elif defined(CONFIG_P2010) || defined(CONFIG_P2020)
+static struct pci_info pci_config_info[] =
+{
+	[LAW_TRGT_IF_PCIE_1] = {
+		.cfg =   (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) |
+			 (1 << 0xd) | (1 << 0xe) | (1 << 0xf),
+	},
+	[LAW_TRGT_IF_PCIE_2] = {
+		.cfg =   (1 << 2) | (1 << 0xe),
+	},
+	[LAW_TRGT_IF_PCIE_3] = {
+		.cfg =   (1 << 2) | (1 << 4),
+	},
+};
+#elif defined(CONFIG_FSL_CORENET)
+#else
+#error Need to define pci_config_info for processor
+#endif
+
+#ifndef CONFIG_FSL_CORENET
+int is_fsl_pci_cfg(enum law_trgt_if trgt, u32 io_sel)
+{
+	return ((1 << io_sel) & pci_config_info[trgt].cfg);
+}
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/40x_spd_sdram.c b/arch/ppc/cpu/ppc4xx/40x_spd_sdram.c
new file mode 100644
index 0000000..595d568
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/40x_spd_sdram.c
@@ -0,0 +1,464 @@
+/*
+ * arch/ppc/cpu/ppc4xx/40x_spd_sdram.c
+ * This SPD SDRAM detection code supports IBM/AMCC PPC44x cpu with a
+ * SDRAM controller. Those are all current 405 PPC's.
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * Based on code by:
+ *
+ * Kenneth Johansson ,Ericsson AB.
+ * kenneth.johansson@etx.ericsson.se
+ *
+ * hacked up by bill hunter. fixed so we could run before
+ * serial_init and console_init. previous version avoided this by
+ * running out of cache memory during serial/console init, then running
+ * this code later.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ * Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
+ *
+ * (C) Copyright 2005
+ * Stefan Roese, DENX Software Engineering, sr@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 <asm/processor.h>
+#include <i2c.h>
+#include <ppc4xx.h>
+
+#if defined(CONFIG_SPD_EEPROM) && !defined(CONFIG_440)
+
+/*
+ * Set default values
+ */
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED	50000
+#endif
+
+#define ONE_BILLION	1000000000
+
+#define	 SDRAM0_CFG_DCE		0x80000000
+#define	 SDRAM0_CFG_SRE		0x40000000
+#define	 SDRAM0_CFG_PME		0x20000000
+#define	 SDRAM0_CFG_MEMCHK	0x10000000
+#define	 SDRAM0_CFG_REGEN	0x08000000
+#define	 SDRAM0_CFG_ECCDD	0x00400000
+#define	 SDRAM0_CFG_EMDULR	0x00200000
+#define	 SDRAM0_CFG_DRW_SHIFT	(31-6)
+#define	 SDRAM0_CFG_BRPF_SHIFT	(31-8)
+
+#define	 SDRAM0_TR_CASL_SHIFT	(31-8)
+#define	 SDRAM0_TR_PTA_SHIFT	(31-13)
+#define	 SDRAM0_TR_CTP_SHIFT	(31-15)
+#define	 SDRAM0_TR_LDF_SHIFT	(31-17)
+#define	 SDRAM0_TR_RFTA_SHIFT	(31-29)
+#define	 SDRAM0_TR_RCD_SHIFT	(31-31)
+
+#define	 SDRAM0_RTR_SHIFT	(31-15)
+#define	 SDRAM0_ECCCFG_SHIFT	(31-11)
+
+/* SDRAM0_CFG enable macro  */
+#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT )
+
+#define SDRAM0_BXCR_SZ_MASK	0x000e0000
+#define SDRAM0_BXCR_AM_MASK	0x0000e000
+
+#define SDRAM0_BXCR_SZ_SHIFT	(31-14)
+#define SDRAM0_BXCR_AM_SHIFT	(31-18)
+
+#define SDRAM0_BXCR_SZ(x)	( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) )
+#define SDRAM0_BXCR_AM(x)	( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) )
+
+#ifdef CONFIG_SPDDRAM_SILENT
+# define SPD_ERR(x) do { return 0; } while (0)
+#else
+# define SPD_ERR(x) do { printf(x); return(0); } while (0)
+#endif
+
+#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
+
+/* function prototypes */
+int spd_read(uint addr);
+
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * Input: null for default I2C spd functions or a pointer to a custom function
+ * returning spd_data.
+ */
+
+long int spd_sdram(int(read_spd)(uint addr))
+{
+	int tmp,row,col;
+	int total_size,bank_size,bank_code;
+	int ecc_on;
+	int mode;
+	int bank_cnt;
+
+	int sdram0_pmit=0x07c00000;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+	int sdram0_besr0 = -1;
+	int sdram0_besr1 = -1;
+	int sdram0_eccesr = -1;
+#endif
+	int sdram0_ecccfg;
+
+	int sdram0_rtr=0;
+	int sdram0_tr=0;
+
+	int sdram0_b0cr;
+	int sdram0_b1cr;
+	int sdram0_b2cr;
+	int sdram0_b3cr;
+
+	int sdram0_cfg=0;
+
+	int t_rp;
+	int t_rcd;
+	int t_ras;
+	int t_rc;
+	int min_cas;
+
+	PPC4xx_SYS_INFO sys_info;
+	unsigned long bus_period_x_10;
+
+	/*
+	 * get the board info
+	 */
+	get_sys_info(&sys_info);
+	bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+	if (read_spd == 0){
+		read_spd=spd_read;
+		/*
+		 * Make sure I2C controller is initialized
+		 * before continuing.
+		 */
+		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+	}
+
+	/* Make shure we are using SDRAM */
+	if (read_spd(2) != 0x04) {
+		SPD_ERR("SDRAM - non SDRAM memory module found\n");
+	}
+
+	/* ------------------------------------------------------------------
+	 * configure memory timing register
+	 *
+	 * data from DIMM:
+	 * 27	IN Row Precharge Time ( t RP)
+	 * 29	MIN RAS to CAS Delay ( t RCD)
+	 * 127	 Component and Clock Detail ,clk0-clk3, junction temp, CAS
+	 * -------------------------------------------------------------------*/
+
+	/*
+	 * first figure out which cas latency mode to use
+	 * use the min supported mode
+	 */
+
+	tmp = read_spd(127) & 0x6;
+	if (tmp == 0x02) {		/* only cas = 2 supported */
+		min_cas = 2;
+/*		t_ck = read_spd(9); */
+/*		t_ac = read_spd(10); */
+	} else if (tmp == 0x04) {	/* only cas = 3 supported */
+		min_cas = 3;
+/*		t_ck = read_spd(9); */
+/*		t_ac = read_spd(10); */
+	} else if (tmp == 0x06) {	/* 2,3 supported, so use 2 */
+		min_cas = 2;
+/*		t_ck = read_spd(23); */
+/*		t_ac = read_spd(24); */
+	} else {
+		SPD_ERR("SDRAM - unsupported CAS latency \n");
+	}
+
+	/* get some timing values, t_rp,t_rcd,t_ras,t_rc
+	 */
+	t_rp = read_spd(27);
+	t_rcd = read_spd(29);
+	t_ras = read_spd(30);
+	t_rc = t_ras + t_rp;
+
+	/* The following timing calcs subtract 1 before deviding.
+	 * this has effect of using ceiling instead of floor rounding,
+	 * and also subtracting 1 to convert number to reg value
+	 */
+	/* set up CASL */
+	sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT;
+	/* set up PTA */
+	sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT;
+	/* set up CTP */
+	tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3;
+	if (tmp < 1)
+		tmp = 1;
+	sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT;
+	/* set LDF	= 2 cycles, reg value = 1 */
+	sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT;
+	/* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */
+	tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3;
+	if (tmp < 0)
+		tmp = 0;
+	if (tmp > 6)
+		tmp = 6;
+	sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT;
+	/* set RCD = t_rcd/bus_period*/
+	sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ;
+
+
+	/*------------------------------------------------------------------
+	 * configure RTR register
+	 * -------------------------------------------------------------------*/
+	row = read_spd(3);
+	col = read_spd(4);
+	tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */
+	switch (tmp) {
+	case 0x00:
+		tmp = 15625;
+		break;
+	case 0x01:
+		tmp = 15625 / 4;
+		break;
+	case 0x02:
+		tmp = 15625 / 2;
+		break;
+	case 0x03:
+		tmp = 15625 * 2;
+		break;
+	case 0x04:
+		tmp = 15625 * 4;
+		break;
+	case 0x05:
+		tmp = 15625 * 8;
+		break;
+	default:
+		SPD_ERR("SDRAM - Bad refresh period \n");
+	}
+	/* convert from nsec to bus cycles */
+	tmp = (tmp * 10) / bus_period_x_10;
+	sdram0_rtr = (tmp & 0x3ff8) <<	SDRAM0_RTR_SHIFT;
+
+	/*------------------------------------------------------------------
+	 * determine the number of banks used
+	 * -------------------------------------------------------------------*/
+	/* byte 7:6 is module data width */
+	if (read_spd(7) != 0)
+		SPD_ERR("SDRAM - unsupported module width\n");
+	tmp = read_spd(6);
+	if (tmp < 32)
+		SPD_ERR("SDRAM - unsupported module width\n");
+	else if (tmp < 64)
+		bank_cnt = 1;		/* one bank per sdram side */
+	else if (tmp < 73)
+		bank_cnt = 2;	/* need two banks per side */
+	else if (tmp < 161)
+		bank_cnt = 4;	/* need four banks per side */
+	else
+		SPD_ERR("SDRAM - unsupported module width\n");
+
+	/* byte 5 is the module row count (refered to as dimm "sides") */
+	tmp = read_spd(5);
+	if (tmp == 1)
+		;
+	else if (tmp==2)
+		bank_cnt *= 2;
+	else if (tmp==4)
+		bank_cnt *= 4;
+	else
+		bank_cnt = 8;		/* 8 is an error code */
+
+	if (bank_cnt > 4)	/* we only have 4 banks to work with */
+		SPD_ERR("SDRAM - unsupported module rows for this width\n");
+
+	/* now check for ECC ability of module. We only support ECC
+	 *   on 32 bit wide devices with 8 bit ECC.
+	 */
+	if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) {
+		sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT;
+		ecc_on = 1;
+	} else {
+		sdram0_ecccfg = 0;
+		ecc_on = 0;
+	}
+
+	/*------------------------------------------------------------------
+	 * calculate total size
+	 * -------------------------------------------------------------------*/
+	/* calculate total size and do sanity check */
+	tmp = read_spd(31);
+	total_size = 1 << 22;	/* total_size = 4MB */
+	/* now multiply 4M by the smallest device row density */
+	/* note that we don't support asymetric rows */
+	while (((tmp & 0x0001) == 0) && (tmp != 0)) {
+		total_size = total_size << 1;
+		tmp = tmp >> 1;
+	}
+	total_size *= read_spd(5);	/* mult by module rows (dimm sides) */
+
+	/*------------------------------------------------------------------
+	 * map	rows * cols * banks to a mode
+	 * -------------------------------------------------------------------*/
+
+	switch (row) {
+	case 11:
+		switch (col) {
+		case 8:
+			mode=4; /* mode 5 */
+			break;
+		case 9:
+		case 10:
+			mode=0; /* mode 1 */
+			break;
+		default:
+			SPD_ERR("SDRAM - unsupported mode\n");
+		}
+		break;
+	case 12:
+		switch (col) {
+		case 8:
+			mode=3; /* mode 4 */
+			break;
+		case 9:
+		case 10:
+			mode=1; /* mode 2 */
+			break;
+		default:
+			SPD_ERR("SDRAM - unsupported mode\n");
+		}
+		break;
+	case 13:
+		switch (col) {
+		case 8:
+			mode=5; /* mode 6 */
+			break;
+		case 9:
+		case 10:
+			if (read_spd(17) == 2)
+				mode = 6; /* mode 7 */
+			else
+				mode = 2; /* mode 3 */
+			break;
+		case 11:
+			mode = 2; /* mode 3 */
+			break;
+		default:
+			SPD_ERR("SDRAM - unsupported mode\n");
+		}
+		break;
+	default:
+		SPD_ERR("SDRAM - unsupported mode\n");
+	}
+
+	/*------------------------------------------------------------------
+	 * using the calculated values, compute the bank
+	 * config register values.
+	 * -------------------------------------------------------------------*/
+	sdram0_b1cr = 0;
+	sdram0_b2cr = 0;
+	sdram0_b3cr = 0;
+
+	/* compute the size of each bank */
+	bank_size = total_size / bank_cnt;
+	/* convert bank size to bank size code for ppc4xx
+	   by takeing log2(bank_size) - 22 */
+	tmp = bank_size;		/* start with tmp = bank_size */
+	bank_code = 0;			/* and bank_code = 0 */
+	while (tmp > 1) {		/* this takes log2 of tmp */
+		bank_code++;		/* and stores result in bank_code */
+		tmp = tmp >> 1;
+	}				/* bank_code is now log2(bank_size) */
+	bank_code -= 22;		/* subtract 22 to get the code */
+
+	tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1;
+	sdram0_b0cr = (bank_size * 0) | tmp;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+	if (bank_cnt > 1)
+		sdram0_b2cr = (bank_size * 1) | tmp;
+	if (bank_cnt > 2)
+		sdram0_b1cr = (bank_size * 2) | tmp;
+	if (bank_cnt > 3)
+		sdram0_b3cr = (bank_size * 3) | tmp;
+#else
+	/* PPC405EP chip only supports two SDRAM banks */
+	if (bank_cnt > 1)
+		sdram0_b1cr = (bank_size * 1) | tmp;
+	if (bank_cnt > 2)
+		total_size = 2 * bank_size;
+#endif
+
+	/*
+	 *   enable sdram controller DCE=1
+	 *  enable burst read prefetch to 32 bytes BRPF=2
+	 *  leave other functions off
+	 */
+
+	/*------------------------------------------------------------------
+	 * now that we've done our calculations, we are ready to
+	 * program all the registers.
+	 * -------------------------------------------------------------------*/
+
+	/* disable memcontroller so updates work */
+	mtsdram(SDRAM0_CFG, 0);
+
+#ifndef CONFIG_405EP /* not on PPC405EP */
+	mtsdram(SDRAM0_BESR0, sdram0_besr0);
+	mtsdram(SDRAM0_BESR1, sdram0_besr1);
+	mtsdram(SDRAM0_ECCCFG, sdram0_ecccfg);
+	mtsdram(SDRAM0_ECCESR, sdram0_eccesr);
+#endif
+	mtsdram(SDRAM0_RTR, sdram0_rtr);
+	mtsdram(SDRAM0_PMIT, sdram0_pmit);
+	mtsdram(SDRAM0_B0CR, sdram0_b0cr);
+	mtsdram(SDRAM0_B1CR, sdram0_b1cr);
+#ifndef CONFIG_405EP /* not on PPC405EP */
+	mtsdram(SDRAM0_B2CR, sdram0_b2cr);
+	mtsdram(SDRAM0_B3CR, sdram0_b3cr);
+#endif
+	mtsdram(SDRAM0_TR, sdram0_tr);
+
+	/* SDRAM have a power on delay,	 500 micro should do */
+	udelay(500);
+	sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR;
+	if (ecc_on)
+		sdram0_cfg |= SDRAM0_CFG_MEMCHK;
+	mtsdram(SDRAM0_CFG, sdram0_cfg);
+
+	return (total_size);
+}
+
+int spd_read(uint addr)
+{
+	uchar data[2];
+
+	if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0)
+		return (int)data[0];
+	else
+		return 0;
+}
+
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/arch/ppc/cpu/ppc4xx/44x_spd_ddr.c b/arch/ppc/cpu/ppc4xx/44x_spd_ddr.c
new file mode 100644
index 0000000..9d1994f
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/44x_spd_ddr.c
@@ -0,0 +1,1248 @@
+/*
+ * arch/ppc/cpu/ppc4xx/44x_spd_ddr.c
+ * This SPD DDR detection code supports IBM/AMCC PPC44x cpu with a
+ * DDR controller. Those are 440GP/GX/EP/GR.
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * Based on code by:
+ *
+ * Kenneth Johansson ,Ericsson AB.
+ * kenneth.johansson@etx.ericsson.se
+ *
+ * hacked up by bill hunter. fixed so we could run before
+ * serial_init and console_init. previous version avoided this by
+ * running out of cache memory during serial/console init, then running
+ * this code later.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ * Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
+ *
+ * (C) Copyright 2005-2007
+ * Stefan Roese, DENX Software Engineering, sr@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
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <asm/processor.h>
+#include <i2c.h>
+#include <ppc4xx.h>
+#include <asm/mmu.h>
+
+#include "ecc.h"
+
+#if defined(CONFIG_SPD_EEPROM) &&					\
+	(defined(CONFIG_440GP) || defined(CONFIG_440GX) ||		\
+	 defined(CONFIG_440EP) || defined(CONFIG_440GR))
+
+/*
+ * Set default values
+ */
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED	50000
+#endif
+
+#define ONE_BILLION	1000000000
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang (void)
+{
+	hang ();
+}
+void spd_ddr_init_hang (void) __attribute__((weak, alias("__spd_ddr_init_hang")));
+
+/*-----------------------------------------------------------------------------+
+  |  General Definition
+  +-----------------------------------------------------------------------------*/
+#define DEFAULT_SPD_ADDR1	0x53
+#define DEFAULT_SPD_ADDR2	0x52
+#define MAXBANKS		4		/* at most 4 dimm banks */
+#define MAX_SPD_BYTES		256
+#define NUMHALFCYCLES		4
+#define NUMMEMTESTS		8
+#define NUMMEMWORDS		8
+#define MAXBXCR			4
+#define TRUE			1
+#define FALSE			0
+
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory
+ * region. Right now the cache should still be disabled in U-Boot because of the
+ * EMAC driver, that need it's buffer descriptor to be located in non cached
+ * memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CONFIG_4xx_DCACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#ifdef CONFIG_4xx_DCACHE
+#define MY_TLB_WORD2_I_ENABLE	0			/* enable caching on SDRAM */
+#else
+#define MY_TLB_WORD2_I_ENABLE	TLB_WORD2_I_ENABLE	/* disable caching on SDRAM */
+#endif
+
+/* bank_parms is used to sort the bank sizes by descending order */
+struct bank_param {
+	unsigned long cr;
+	unsigned long bank_size_bytes;
+};
+
+typedef struct bank_param BANKPARMS;
+
+#ifdef CONFIG_SYS_SIMULATE_SPD_EEPROM
+extern const unsigned char cfg_simulate_spd_eeprom[128];
+#endif
+
+static unsigned char spd_read(uchar chip, uint addr);
+static void get_spd_info(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks);
+static void check_mem_type(unsigned long *dimm_populated,
+			   unsigned char *iic0_dimm_addr,
+			   unsigned long num_dimm_banks);
+static void check_volt_type(unsigned long *dimm_populated,
+			    unsigned char *iic0_dimm_addr,
+			    unsigned long num_dimm_banks);
+static void program_cfg0(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long  num_dimm_banks);
+static void program_cfg1(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks);
+static void program_rtr(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks);
+static void program_tr0(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks);
+static void program_tr1(void);
+
+static unsigned long program_bxcr(unsigned long *dimm_populated,
+				  unsigned char *iic0_dimm_addr,
+				  unsigned long num_dimm_banks);
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * BUG: Don't handle ECC memory
+ * BUG: A few values in the TR register is currently hardcoded
+ */
+long int spd_sdram(void) {
+	unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+	unsigned long dimm_populated[sizeof(iic0_dimm_addr)];
+	unsigned long total_size;
+	unsigned long cfg0;
+	unsigned long mcsts;
+	unsigned long num_dimm_banks;		    /* on board dimm banks */
+
+	num_dimm_banks = sizeof(iic0_dimm_addr);
+
+	/*
+	 * Make sure I2C controller is initialized
+	 * before continuing.
+	 */
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	/*
+	 * Read the SPD information using I2C interface. Check to see if the
+	 * DIMM slots are populated.
+	 */
+	get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*
+	 * Check the memory type for the dimms plugged.
+	 */
+	check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*
+	 * Check the voltage type for the dimms plugged.
+	 */
+	check_volt_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+	/*
+	 * Soft-reset SDRAM controller.
+	 */
+	mtsdr(SDR0_SRST, SDR0_SRST_DMC);
+	mtsdr(SDR0_SRST, 0x00000000);
+#endif
+
+	/*
+	 * program 440GP SDRAM controller options (SDRAM0_CFG0)
+	 */
+	program_cfg0(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*
+	 * program 440GP SDRAM controller options (SDRAM0_CFG1)
+	 */
+	program_cfg1(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*
+	 * program SDRAM refresh register (SDRAM0_RTR)
+	 */
+	program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*
+	 * program SDRAM Timing Register 0 (SDRAM0_TR0)
+	 */
+	program_tr0(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*
+	 * program the BxCR registers to find out total sdram installed
+	 */
+	total_size = program_bxcr(dimm_populated, iic0_dimm_addr,
+				  num_dimm_banks);
+
+#ifdef CONFIG_PROG_SDRAM_TLB /* this define should eventually be removed */
+	/* and program tlb entries for this size (dynamic) */
+	program_tlb(0, 0, total_size, MY_TLB_WORD2_I_ENABLE);
+#endif
+
+	/*
+	 * program SDRAM Clock Timing Register (SDRAM0_CLKTR)
+	 */
+	mtsdram(SDRAM0_CLKTR, 0x40000000);
+
+	/*
+	 * delay to ensure 200 usec has elapsed
+	 */
+	udelay(400);
+
+	/*
+	 * enable the memory controller
+	 */
+	mfsdram(SDRAM0_CFG0, cfg0);
+	mtsdram(SDRAM0_CFG0, cfg0 | SDRAM_CFG0_DCEN);
+
+	/*
+	 * wait for SDRAM_CFG0_DC_EN to complete
+	 */
+	while (1) {
+		mfsdram(SDRAM0_MCSTS, mcsts);
+		if ((mcsts & SDRAM_MCSTS_MRSC) != 0)
+			break;
+	}
+
+	/*
+	 * program SDRAM Timing Register 1, adding some delays
+	 */
+	program_tr1();
+
+#ifdef CONFIG_DDR_ECC
+	/*
+	 * If ecc is enabled, initialize the parity bits.
+	 */
+	ecc_init(CONFIG_SYS_SDRAM_BASE, total_size);
+#endif
+
+	return total_size;
+}
+
+static unsigned char spd_read(uchar chip, uint addr)
+{
+	unsigned char data[2];
+
+#ifdef CONFIG_SYS_SIMULATE_SPD_EEPROM
+	if (chip == CONFIG_SYS_SIMULATE_SPD_EEPROM) {
+		/*
+		 * Onboard spd eeprom requested -> simulate values
+		 */
+		return cfg_simulate_spd_eeprom[addr];
+	}
+#endif /* CONFIG_SYS_SIMULATE_SPD_EEPROM */
+
+	if (i2c_probe(chip) == 0) {
+		if (i2c_read(chip, addr, 1, data, 1) == 0) {
+			return data[0];
+		}
+	}
+
+	return 0;
+}
+
+static void get_spd_info(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long dimm_found;
+	unsigned char num_of_bytes;
+	unsigned char total_size;
+
+	dimm_found = FALSE;
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		num_of_bytes = 0;
+		total_size = 0;
+
+		num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+		total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+
+		if ((num_of_bytes != 0) && (total_size != 0)) {
+			dimm_populated[dimm_num] = TRUE;
+			dimm_found = TRUE;
+			debug("DIMM slot %lu: populated\n", dimm_num);
+		} else {
+			dimm_populated[dimm_num] = FALSE;
+			debug("DIMM slot %lu: Not populated\n", dimm_num);
+		}
+	}
+
+	if (dimm_found == FALSE) {
+		printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n");
+		spd_ddr_init_hang ();
+	}
+}
+
+static void check_mem_type(unsigned long *dimm_populated,
+			   unsigned char *iic0_dimm_addr,
+			   unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned char dimm_type;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2);
+			switch (dimm_type) {
+			case 7:
+				debug("DIMM slot %lu: DDR SDRAM detected\n", dimm_num);
+				break;
+			default:
+				printf("ERROR: Unsupported DIMM detected in slot %lu.\n",
+				       dimm_num);
+				printf("Only DDR SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			}
+		}
+	}
+}
+
+static void check_volt_type(unsigned long *dimm_populated,
+			    unsigned char *iic0_dimm_addr,
+			    unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long voltage_type;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+			if (voltage_type != 0x04) {
+				printf("ERROR: DIMM %lu with unsupported voltage level.\n",
+				       dimm_num);
+				spd_ddr_init_hang ();
+			} else {
+				debug("DIMM %lu voltage level supported.\n", dimm_num);
+			}
+			break;
+		}
+	}
+}
+
+static void program_cfg0(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long cfg0;
+	unsigned long ecc_enabled;
+	unsigned char ecc;
+	unsigned char attributes;
+	unsigned long data_width;
+	unsigned long dimm_32bit;
+	unsigned long dimm_64bit;
+
+	/*
+	 * get Memory Controller Options 0 data
+	 */
+	mfsdram(SDRAM0_CFG0, cfg0);
+
+	/*
+	 * clear bits
+	 */
+	cfg0 &= ~(SDRAM_CFG0_DCEN | SDRAM_CFG0_MCHK_MASK |
+		  SDRAM_CFG0_RDEN | SDRAM_CFG0_PMUD |
+		  SDRAM_CFG0_DMWD_MASK |
+		  SDRAM_CFG0_UIOS_MASK | SDRAM_CFG0_PDP);
+
+
+	/*
+	 * FIXME: assume the DDR SDRAMs in both banks are the same
+	 */
+	ecc_enabled = TRUE;
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			ecc = spd_read(iic0_dimm_addr[dimm_num], 11);
+			if (ecc != 0x02) {
+				ecc_enabled = FALSE;
+			}
+
+			/*
+			 * program Registered DIMM Enable
+			 */
+			attributes = spd_read(iic0_dimm_addr[dimm_num], 21);
+			if ((attributes & 0x02) != 0x00) {
+				cfg0 |= SDRAM_CFG0_RDEN;
+			}
+
+			/*
+			 * program DDR SDRAM Data Width
+			 */
+			data_width =
+				(unsigned long)spd_read(iic0_dimm_addr[dimm_num],6) +
+				(((unsigned long)spd_read(iic0_dimm_addr[dimm_num],7)) << 8);
+			if (data_width == 64 || data_width == 72) {
+				dimm_64bit = TRUE;
+				cfg0 |= SDRAM_CFG0_DMWD_64;
+			} else if (data_width == 32 || data_width == 40) {
+				dimm_32bit = TRUE;
+				cfg0 |= SDRAM_CFG0_DMWD_32;
+			} else {
+				printf("WARNING: DIMM with datawidth of %lu bits.\n",
+				       data_width);
+				printf("Only DIMMs with 32 or 64 bit datawidths supported.\n");
+				spd_ddr_init_hang ();
+			}
+			break;
+		}
+	}
+
+	/*
+	 * program Memory Data Error Checking
+	 */
+	if (ecc_enabled == TRUE) {
+		cfg0 |= SDRAM_CFG0_MCHK_GEN;
+	} else {
+		cfg0 |= SDRAM_CFG0_MCHK_NON;
+	}
+
+	/*
+	 * program Page Management Unit (0 == enabled)
+	 */
+	cfg0 &= ~SDRAM_CFG0_PMUD;
+
+	/*
+	 * program Memory Controller Options 0
+	 * Note: DCEN must be enabled after all DDR SDRAM controller
+	 * configuration registers get initialized.
+	 */
+	mtsdram(SDRAM0_CFG0, cfg0);
+}
+
+static void program_cfg1(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long cfg1;
+	mfsdram(SDRAM0_CFG1, cfg1);
+
+	/*
+	 * Self-refresh exit, disable PM
+	 */
+	cfg1 &= ~(SDRAM_CFG1_SRE | SDRAM_CFG1_PMEN);
+
+	/*
+	 * program Memory Controller Options 1
+	 */
+	mtsdram(SDRAM0_CFG1, cfg1);
+}
+
+static void program_rtr(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long bus_period_x_10;
+	unsigned long refresh_rate = 0;
+	unsigned char refresh_rate_type;
+	unsigned long refresh_interval;
+	unsigned long sdram_rtr;
+	PPC4xx_SYS_INFO sys_info;
+
+	/*
+	 * get the board info
+	 */
+	get_sys_info(&sys_info);
+	bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+	for (dimm_num = 0;  dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			refresh_rate_type = 0x7F & spd_read(iic0_dimm_addr[dimm_num], 12);
+			switch (refresh_rate_type) {
+			case 0x00:
+				refresh_rate = 15625;
+				break;
+			case 0x01:
+				refresh_rate = 15625/4;
+				break;
+			case 0x02:
+				refresh_rate = 15625/2;
+				break;
+			case 0x03:
+				refresh_rate = 15626*2;
+				break;
+			case 0x04:
+				refresh_rate = 15625*4;
+				break;
+			case 0x05:
+				refresh_rate = 15625*8;
+				break;
+			default:
+				printf("ERROR: DIMM %lu, unsupported refresh rate/type.\n",
+				       dimm_num);
+				printf("Replace the DIMM module with a supported DIMM.\n");
+				break;
+			}
+
+			break;
+		}
+	}
+
+	refresh_interval = refresh_rate * 10 / bus_period_x_10;
+	sdram_rtr = (refresh_interval & 0x3ff8) <<  16;
+
+	/*
+	 * program Refresh Timer Register (SDRAM0_RTR)
+	 */
+	mtsdram(SDRAM0_RTR, sdram_rtr);
+}
+
+static void program_tr0(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long tr0;
+	unsigned char wcsbc;
+	unsigned char t_rp_ns;
+	unsigned char t_rcd_ns;
+	unsigned char t_ras_ns;
+	unsigned long t_rp_clk;
+	unsigned long t_ras_rcd_clk;
+	unsigned long t_rcd_clk;
+	unsigned long t_rfc_clk;
+	unsigned long plb_check;
+	unsigned char cas_bit;
+	unsigned long cas_index;
+	unsigned char cas_2_0_available;
+	unsigned char cas_2_5_available;
+	unsigned char cas_3_0_available;
+	unsigned long cycle_time_ns_x_10[3];
+	unsigned long tcyc_3_0_ns_x_10;
+	unsigned long tcyc_2_5_ns_x_10;
+	unsigned long tcyc_2_0_ns_x_10;
+	unsigned long tcyc_reg;
+	unsigned long bus_period_x_10;
+	PPC4xx_SYS_INFO sys_info;
+	unsigned long residue;
+
+	/*
+	 * get the board info
+	 */
+	get_sys_info(&sys_info);
+	bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+	/*
+	 * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
+	 */
+	mfsdram(SDRAM0_TR0, tr0);
+	tr0 &= ~(SDRAM_TR0_SDWR_MASK | SDRAM_TR0_SDWD_MASK |
+		 SDRAM_TR0_SDCL_MASK | SDRAM_TR0_SDPA_MASK |
+		 SDRAM_TR0_SDCP_MASK | SDRAM_TR0_SDLD_MASK |
+		 SDRAM_TR0_SDRA_MASK | SDRAM_TR0_SDRD_MASK);
+
+	/*
+	 * initialization
+	 */
+	wcsbc = 0;
+	t_rp_ns = 0;
+	t_rcd_ns = 0;
+	t_ras_ns = 0;
+	cas_2_0_available = TRUE;
+	cas_2_5_available = TRUE;
+	cas_3_0_available = TRUE;
+	tcyc_2_0_ns_x_10 = 0;
+	tcyc_2_5_ns_x_10 = 0;
+	tcyc_3_0_ns_x_10 = 0;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			wcsbc = spd_read(iic0_dimm_addr[dimm_num], 15);
+			t_rp_ns	 = spd_read(iic0_dimm_addr[dimm_num], 27) >> 2;
+			t_rcd_ns = spd_read(iic0_dimm_addr[dimm_num], 29) >> 2;
+			t_ras_ns = spd_read(iic0_dimm_addr[dimm_num], 30);
+			cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+
+			for (cas_index = 0; cas_index < 3; cas_index++) {
+				switch (cas_index) {
+				case 0:
+					tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+					break;
+				case 1:
+					tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23);
+					break;
+				default:
+					tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25);
+					break;
+				}
+
+				if ((tcyc_reg & 0x0F) >= 10) {
+					printf("ERROR: Tcyc incorrect for DIMM in slot %lu\n",
+					       dimm_num);
+					spd_ddr_init_hang ();
+				}
+
+				cycle_time_ns_x_10[cas_index] =
+					(((tcyc_reg & 0xF0) >> 4) * 10) + (tcyc_reg & 0x0F);
+			}
+
+			cas_index = 0;
+
+			if ((cas_bit & 0x80) != 0) {
+				cas_index += 3;
+			} else if ((cas_bit & 0x40) != 0) {
+				cas_index += 2;
+			} else if ((cas_bit & 0x20) != 0) {
+				cas_index += 1;
+			}
+
+			if (((cas_bit & 0x10) != 0) && (cas_index < 3)) {
+				tcyc_3_0_ns_x_10 = cycle_time_ns_x_10[cas_index];
+				cas_index++;
+			} else {
+				if (cas_index != 0) {
+					cas_index++;
+				}
+				cas_3_0_available = FALSE;
+			}
+
+			if (((cas_bit & 0x08) != 0) || (cas_index < 3)) {
+				tcyc_2_5_ns_x_10 = cycle_time_ns_x_10[cas_index];
+				cas_index++;
+			} else {
+				if (cas_index != 0) {
+					cas_index++;
+				}
+				cas_2_5_available = FALSE;
+			}
+
+			if (((cas_bit & 0x04) != 0) || (cas_index < 3)) {
+				tcyc_2_0_ns_x_10 = cycle_time_ns_x_10[cas_index];
+				cas_index++;
+			} else {
+				if (cas_index != 0) {
+					cas_index++;
+				}
+				cas_2_0_available = FALSE;
+			}
+
+			break;
+		}
+	}
+
+	/*
+	 * Program SD_WR and SD_WCSBC fields
+	 */
+	tr0 |= SDRAM_TR0_SDWR_2_CLK;		    /* Write Recovery: 2 CLK */
+	switch (wcsbc) {
+	case 0:
+		tr0 |= SDRAM_TR0_SDWD_0_CLK;
+		break;
+	default:
+		tr0 |= SDRAM_TR0_SDWD_1_CLK;
+		break;
+	}
+
+	/*
+	 * Program SD_CASL field
+	 */
+	if ((cas_2_0_available == TRUE) &&
+	    (bus_period_x_10 >= tcyc_2_0_ns_x_10)) {
+		tr0 |= SDRAM_TR0_SDCL_2_0_CLK;
+	} else if ((cas_2_5_available == TRUE) &&
+		 (bus_period_x_10 >= tcyc_2_5_ns_x_10)) {
+		tr0 |= SDRAM_TR0_SDCL_2_5_CLK;
+	} else if ((cas_3_0_available == TRUE) &&
+		 (bus_period_x_10 >= tcyc_3_0_ns_x_10)) {
+		tr0 |= SDRAM_TR0_SDCL_3_0_CLK;
+	} else {
+		printf("ERROR: No supported CAS latency with the installed DIMMs.\n");
+		printf("Only CAS latencies of 2.0, 2.5, and 3.0 are supported.\n");
+		printf("Make sure the PLB speed is within the supported range.\n");
+		spd_ddr_init_hang ();
+	}
+
+	/*
+	 * Calculate Trp in clock cycles and round up if necessary
+	 * Program SD_PTA field
+	 */
+	t_rp_clk = sys_info.freqPLB * t_rp_ns / ONE_BILLION;
+	plb_check = ONE_BILLION * t_rp_clk / t_rp_ns;
+	if (sys_info.freqPLB != plb_check) {
+		t_rp_clk++;
+	}
+	switch ((unsigned long)t_rp_clk) {
+	case 0:
+	case 1:
+	case 2:
+		tr0 |= SDRAM_TR0_SDPA_2_CLK;
+		break;
+	case 3:
+		tr0 |= SDRAM_TR0_SDPA_3_CLK;
+		break;
+	default:
+		tr0 |= SDRAM_TR0_SDPA_4_CLK;
+		break;
+	}
+
+	/*
+	 * Program SD_CTP field
+	 */
+	t_ras_rcd_clk = sys_info.freqPLB * (t_ras_ns - t_rcd_ns) / ONE_BILLION;
+	plb_check = ONE_BILLION * t_ras_rcd_clk / (t_ras_ns - t_rcd_ns);
+	if (sys_info.freqPLB != plb_check) {
+		t_ras_rcd_clk++;
+	}
+	switch (t_ras_rcd_clk) {
+	case 0:
+	case 1:
+	case 2:
+		tr0 |= SDRAM_TR0_SDCP_2_CLK;
+		break;
+	case 3:
+		tr0 |= SDRAM_TR0_SDCP_3_CLK;
+		break;
+	case 4:
+		tr0 |= SDRAM_TR0_SDCP_4_CLK;
+		break;
+	default:
+		tr0 |= SDRAM_TR0_SDCP_5_CLK;
+		break;
+	}
+
+	/*
+	 * Program SD_LDF field
+	 */
+	tr0 |= SDRAM_TR0_SDLD_2_CLK;
+
+	/*
+	 * Program SD_RFTA field
+	 * FIXME tRFC hardcoded as 75 nanoseconds
+	 */
+	t_rfc_clk = sys_info.freqPLB / (ONE_BILLION / 75);
+	residue = sys_info.freqPLB % (ONE_BILLION / 75);
+	if (residue >= (ONE_BILLION / 150)) {
+		t_rfc_clk++;
+	}
+	switch (t_rfc_clk) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		tr0 |= SDRAM_TR0_SDRA_6_CLK;
+		break;
+	case 7:
+		tr0 |= SDRAM_TR0_SDRA_7_CLK;
+		break;
+	case 8:
+		tr0 |= SDRAM_TR0_SDRA_8_CLK;
+		break;
+	case 9:
+		tr0 |= SDRAM_TR0_SDRA_9_CLK;
+		break;
+	case 10:
+		tr0 |= SDRAM_TR0_SDRA_10_CLK;
+		break;
+	case 11:
+		tr0 |= SDRAM_TR0_SDRA_11_CLK;
+		break;
+	case 12:
+		tr0 |= SDRAM_TR0_SDRA_12_CLK;
+		break;
+	default:
+		tr0 |= SDRAM_TR0_SDRA_13_CLK;
+		break;
+	}
+
+	/*
+	 * Program SD_RCD field
+	 */
+	t_rcd_clk = sys_info.freqPLB * t_rcd_ns / ONE_BILLION;
+	plb_check = ONE_BILLION * t_rcd_clk / t_rcd_ns;
+	if (sys_info.freqPLB != plb_check) {
+		t_rcd_clk++;
+	}
+	switch (t_rcd_clk) {
+	case 0:
+	case 1:
+	case 2:
+		tr0 |= SDRAM_TR0_SDRD_2_CLK;
+		break;
+	case 3:
+		tr0 |= SDRAM_TR0_SDRD_3_CLK;
+		break;
+	default:
+		tr0 |= SDRAM_TR0_SDRD_4_CLK;
+		break;
+	}
+
+	debug("tr0: %x\n", tr0);
+	mtsdram(SDRAM0_TR0, tr0);
+}
+
+static int short_mem_test(void)
+{
+	unsigned long i, j;
+	unsigned long bxcr_num;
+	unsigned long *membase;
+	const unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
+		{0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+		{0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+		{0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+		{0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+		{0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+		{0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+		{0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+		{0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55}};
+
+	for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) {
+		mtdcr(SDRAM0_CFGADDR, SDRAM0_B0CR + (bxcr_num << 2));
+		if ((mfdcr(SDRAM0_CFGDATA) & SDRAM_BXCR_SDBE) == SDRAM_BXCR_SDBE) {
+			/* Bank is enabled */
+			membase = (unsigned long*)
+				(mfdcr(SDRAM0_CFGDATA) & SDRAM_BXCR_SDBA_MASK);
+
+			/*
+			 * Run the short memory test
+			 */
+			for (i = 0; i < NUMMEMTESTS; i++) {
+				for (j = 0; j < NUMMEMWORDS; j++) {
+					/* printf("bank enabled base:%x\n", &membase[j]); */
+					membase[j] = test[i][j];
+					ppcDcbf((unsigned long)&(membase[j]));
+				}
+
+				for (j = 0; j < NUMMEMWORDS; j++) {
+					if (membase[j] != test[i][j]) {
+						ppcDcbf((unsigned long)&(membase[j]));
+						return 0;
+					}
+					ppcDcbf((unsigned long)&(membase[j]));
+				}
+
+				if (j < NUMMEMWORDS)
+					return 0;
+			}
+
+			/*
+			 * see if the rdclt value passed
+			 */
+			if (i < NUMMEMTESTS)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+static void program_tr1(void)
+{
+	unsigned long tr0;
+	unsigned long tr1;
+	unsigned long cfg0;
+	unsigned long ecc_temp;
+	unsigned long dlycal;
+	unsigned long dly_val;
+	unsigned long k;
+	unsigned long max_pass_length;
+	unsigned long current_pass_length;
+	unsigned long current_fail_length;
+	unsigned long current_start;
+	unsigned long rdclt;
+	unsigned long rdclt_offset;
+	long max_start;
+	long max_end;
+	long rdclt_average;
+	unsigned char window_found;
+	unsigned char fail_found;
+	unsigned char pass_found;
+	PPC4xx_SYS_INFO sys_info;
+
+	/*
+	 * get the board info
+	 */
+	get_sys_info(&sys_info);
+
+	/*
+	 * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
+	 */
+	mfsdram(SDRAM0_TR1, tr1);
+	tr1 &= ~(SDRAM_TR1_RDSS_MASK | SDRAM_TR1_RDSL_MASK |
+		 SDRAM_TR1_RDCD_MASK | SDRAM_TR1_RDCT_MASK);
+
+	mfsdram(SDRAM0_TR0, tr0);
+	if (((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) &&
+	    (sys_info.freqPLB > 100000000)) {
+		tr1 |= SDRAM_TR1_RDSS_TR2;
+		tr1 |= SDRAM_TR1_RDSL_STAGE3;
+		tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
+	} else {
+		tr1 |= SDRAM_TR1_RDSS_TR1;
+		tr1 |= SDRAM_TR1_RDSL_STAGE2;
+		tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
+	}
+
+	/*
+	 * save CFG0 ECC setting to a temporary variable and turn ECC off
+	 */
+	mfsdram(SDRAM0_CFG0, cfg0);
+	ecc_temp = cfg0 & SDRAM_CFG0_MCHK_MASK;
+	mtsdram(SDRAM0_CFG0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_NON);
+
+	/*
+	 * get the delay line calibration register value
+	 */
+	mfsdram(SDRAM0_DLYCAL, dlycal);
+	dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
+
+	max_pass_length = 0;
+	max_start = 0;
+	max_end = 0;
+	current_pass_length = 0;
+	current_fail_length = 0;
+	current_start = 0;
+	rdclt_offset = 0;
+	window_found = FALSE;
+	fail_found = FALSE;
+	pass_found = FALSE;
+	debug("Starting memory test ");
+
+	for (k = 0; k < NUMHALFCYCLES; k++) {
+		for (rdclt = 0; rdclt < dly_val; rdclt++) {
+			/*
+			 * Set the timing reg for the test.
+			 */
+			mtsdram(SDRAM0_TR1, (tr1 | SDRAM_TR1_RDCT_ENCODE(rdclt)));
+
+			if (short_mem_test()) {
+				if (fail_found == TRUE) {
+					pass_found = TRUE;
+					if (current_pass_length == 0) {
+						current_start = rdclt_offset + rdclt;
+					}
+
+					current_fail_length = 0;
+					current_pass_length++;
+
+					if (current_pass_length > max_pass_length) {
+						max_pass_length = current_pass_length;
+						max_start = current_start;
+						max_end = rdclt_offset + rdclt;
+					}
+				}
+			} else {
+				current_pass_length = 0;
+				current_fail_length++;
+
+				if (current_fail_length >= (dly_val>>2)) {
+					if (fail_found == FALSE) {
+						fail_found = TRUE;
+					} else if (pass_found == TRUE) {
+						window_found = TRUE;
+						break;
+					}
+				}
+			}
+		}
+		debug(".");
+
+		if (window_found == TRUE) {
+			break;
+		}
+
+		tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
+		rdclt_offset += dly_val;
+	}
+	debug("\n");
+
+	/*
+	 * make sure we find the window
+	 */
+	if (window_found == FALSE) {
+		printf("ERROR: Cannot determine a common read delay.\n");
+		spd_ddr_init_hang ();
+	}
+
+	/*
+	 * restore the orignal ECC setting
+	 */
+	mtsdram(SDRAM0_CFG0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | ecc_temp);
+
+	/*
+	 * set the SDRAM TR1 RDCD value
+	 */
+	tr1 &= ~SDRAM_TR1_RDCD_MASK;
+	if ((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) {
+		tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
+	} else {
+		tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
+	}
+
+	/*
+	 * set the SDRAM TR1 RDCLT value
+	 */
+	tr1 &= ~SDRAM_TR1_RDCT_MASK;
+	while (max_end >= (dly_val << 1)) {
+		max_end -= (dly_val << 1);
+		max_start -= (dly_val << 1);
+	}
+
+	rdclt_average = ((max_start + max_end) >> 1);
+
+	if (rdclt_average < 0) {
+		rdclt_average = 0;
+	}
+
+	if (rdclt_average >= dly_val) {
+		rdclt_average -= dly_val;
+		tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
+	}
+	tr1 |= SDRAM_TR1_RDCT_ENCODE(rdclt_average);
+
+	debug("tr1: %x\n", tr1);
+
+	/*
+	 * program SDRAM Timing Register 1 TR1
+	 */
+	mtsdram(SDRAM0_TR1, tr1);
+}
+
+static unsigned long program_bxcr(unsigned long *dimm_populated,
+				  unsigned char *iic0_dimm_addr,
+				  unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long bank_base_addr;
+	unsigned long cr;
+	unsigned long i;
+	unsigned long j;
+	unsigned long temp;
+	unsigned char num_row_addr;
+	unsigned char num_col_addr;
+	unsigned char num_banks;
+	unsigned char bank_size_id;
+	unsigned long ctrl_bank_num[MAXBANKS];
+	unsigned long bx_cr_num;
+	unsigned long largest_size_index;
+	unsigned long largest_size;
+	unsigned long current_size_index;
+	BANKPARMS bank_parms[MAXBXCR];
+	unsigned long sorted_bank_num[MAXBXCR]; /* DDR Controller bank number table (sorted by size) */
+	unsigned long sorted_bank_size[MAXBXCR]; /* DDR Controller bank size table (sorted by size)*/
+
+	/*
+	 * Set the BxCR regs.  First, wipe out the bank config registers.
+	 */
+	for (bx_cr_num = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
+		mtdcr(SDRAM0_CFGADDR, SDRAM0_B0CR + (bx_cr_num << 2));
+		mtdcr(SDRAM0_CFGDATA, 0x00000000);
+		bank_parms[bx_cr_num].bank_size_bytes = 0;
+	}
+
+#ifdef CONFIG_BAMBOO
+	/*
+	 * This next section is hardware dependent and must be programmed
+	 * to match the hardware.  For bamboo, the following holds...
+	 * 1. SDRAM0_B0CR: Bank 0 of dimm 0 ctrl_bank_num : 0 (soldered onboard)
+	 * 2. SDRAM0_B1CR: Bank 0 of dimm 1 ctrl_bank_num : 1
+	 * 3. SDRAM0_B2CR: Bank 1 of dimm 1 ctrl_bank_num : 1
+	 * 4. SDRAM0_B3CR: Bank 0 of dimm 2 ctrl_bank_num : 3
+	 * ctrl_bank_num corresponds to the first usable DDR controller bank number by DIMM
+	 */
+	ctrl_bank_num[0] = 0;
+	ctrl_bank_num[1] = 1;
+	ctrl_bank_num[2] = 3;
+#else
+	/*
+	 * Ocotea, Ebony and the other IBM/AMCC eval boards have
+	 * 2 DIMM slots with each max 2 banks
+	 */
+	ctrl_bank_num[0] = 0;
+	ctrl_bank_num[1] = 2;
+#endif
+
+	/*
+	 * reset the bank_base address
+	 */
+	bank_base_addr = CONFIG_SYS_SDRAM_BASE;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			num_row_addr = spd_read(iic0_dimm_addr[dimm_num], 3);
+			num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
+			num_banks    = spd_read(iic0_dimm_addr[dimm_num], 5);
+			bank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
+			debug("DIMM%d: row=%d col=%d banks=%d\n", dimm_num,
+			      num_row_addr, num_col_addr, num_banks);
+
+			/*
+			 * Set the SDRAM0_BxCR regs
+			 */
+			cr = 0;
+			switch (bank_size_id) {
+			case 0x02:
+				cr |= SDRAM_BXCR_SDSZ_8;
+				break;
+			case 0x04:
+				cr |= SDRAM_BXCR_SDSZ_16;
+				break;
+			case 0x08:
+				cr |= SDRAM_BXCR_SDSZ_32;
+				break;
+			case 0x10:
+				cr |= SDRAM_BXCR_SDSZ_64;
+				break;
+			case 0x20:
+				cr |= SDRAM_BXCR_SDSZ_128;
+				break;
+			case 0x40:
+				cr |= SDRAM_BXCR_SDSZ_256;
+				break;
+			case 0x80:
+				cr |= SDRAM_BXCR_SDSZ_512;
+				break;
+			default:
+				printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
+				       dimm_num);
+				printf("ERROR: Unsupported value for the banksize: %d.\n",
+				       bank_size_id);
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+			}
+
+			switch (num_col_addr) {
+			case 0x08:
+				cr |= SDRAM_BXCR_SDAM_1;
+				break;
+			case 0x09:
+				cr |= SDRAM_BXCR_SDAM_2;
+				break;
+			case 0x0A:
+				cr |= SDRAM_BXCR_SDAM_3;
+				break;
+			case 0x0B:
+				cr |= SDRAM_BXCR_SDAM_4;
+				break;
+			default:
+				printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
+				       dimm_num);
+				printf("ERROR: Unsupported value for number of "
+				       "column addresses: %d.\n", num_col_addr);
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+			}
+
+			/*
+			 * enable the bank
+			 */
+			cr |= SDRAM_BXCR_SDBE;
+
+			for (i = 0; i < num_banks; i++) {
+				bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes =
+					(4 << 20) * bank_size_id;
+				bank_parms[ctrl_bank_num[dimm_num]+i].cr = cr;
+				debug("DIMM%d-bank %d (SDRAM0_B%dCR): bank_size_bytes=%d\n",
+				      dimm_num, i, ctrl_bank_num[dimm_num]+i,
+				      bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes);
+			}
+		}
+	}
+
+	/* Initialize sort tables */
+	for (i = 0; i < MAXBXCR; i++) {
+		sorted_bank_num[i] = i;
+		sorted_bank_size[i] = bank_parms[i].bank_size_bytes;
+	}
+
+	for (i = 0; i < MAXBXCR-1; i++) {
+		largest_size = sorted_bank_size[i];
+		largest_size_index = 255;
+
+		/* Find the largest remaining value */
+		for (j = i + 1; j < MAXBXCR; j++) {
+			if (sorted_bank_size[j] > largest_size) {
+				/* Save largest remaining value and its index */
+				largest_size = sorted_bank_size[j];
+				largest_size_index = j;
+			}
+		}
+
+		if (largest_size_index != 255) {
+			/* Swap the current and largest values */
+			current_size_index = sorted_bank_num[largest_size_index];
+			sorted_bank_size[largest_size_index] = sorted_bank_size[i];
+			sorted_bank_size[i] = largest_size;
+			sorted_bank_num[largest_size_index] = sorted_bank_num[i];
+			sorted_bank_num[i] = current_size_index;
+		}
+	}
+
+	/* Set the SDRAM0_BxCR regs thanks to sort tables */
+	for (bx_cr_num = 0, bank_base_addr = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
+		if (bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes) {
+			mtdcr(SDRAM0_CFGADDR, SDRAM0_B0CR + (sorted_bank_num[bx_cr_num] << 2));
+			temp = mfdcr(SDRAM0_CFGDATA) & ~(SDRAM_BXCR_SDBA_MASK | SDRAM_BXCR_SDSZ_MASK |
+						  SDRAM_BXCR_SDAM_MASK | SDRAM_BXCR_SDBE);
+			temp = temp | (bank_base_addr & SDRAM_BXCR_SDBA_MASK) |
+				bank_parms[sorted_bank_num[bx_cr_num]].cr;
+			mtdcr(SDRAM0_CFGDATA, temp);
+			bank_base_addr += bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes;
+			debug("SDRAM0_B%dCR=0x%08lx\n", sorted_bank_num[bx_cr_num], temp);
+		}
+	}
+
+	return(bank_base_addr);
+}
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/arch/ppc/cpu/ppc4xx/44x_spd_ddr2.c b/arch/ppc/cpu/ppc4xx/44x_spd_ddr2.c
new file mode 100644
index 0000000..ea6c2ac
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/44x_spd_ddr2.c
@@ -0,0 +1,3174 @@
+/*
+ * arch/ppc/cpu/ppc4xx/44x_spd_ddr2.c
+ * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a
+ * DDR2 controller (non Denali Core). Those currently are:
+ *
+ * 405:		405EX(r)
+ * 440/460:	440SP/440SPe/460EX/460GT
+ *
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ *   Grant Erickson <gerickson@nuovations.com>
+
+ * (C) Copyright 2007-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT   AMCC   CORPORATION 2004
+ *
+ * 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
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <command.h>
+#include <ppc4xx.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#include "ecc.h"
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+
+#define PPC4xx_IBM_DDR2_DUMP_REGISTER(mnemonic)				\
+	do {								\
+		u32 data;						\
+		mfsdram(SDRAM_##mnemonic, data);			\
+		printf("%20s[%02x] = 0x%08X\n",				\
+		       "SDRAM_" #mnemonic, SDRAM_##mnemonic, data);	\
+	} while (0)
+
+#define PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(mnemonic)			\
+	do {								\
+		u32 data;						\
+		data = mfdcr(SDRAM_##mnemonic);				\
+		printf("%20s[%02x] = 0x%08X\n",				\
+		       "SDRAM_" #mnemonic, SDRAM_##mnemonic, data);	\
+	} while (0)
+
+#if defined(CONFIG_440)
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2
+ * memory region. Right now the cache should still be disabled in U-Boot
+ * because of the EMAC driver, that need its buffer descriptor to be located
+ * in non cached memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CONFIG_4xx_DCACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#ifdef CONFIG_4xx_DCACHE
+/* enable caching on SDRAM */
+#define MY_TLB_WORD2_I_ENABLE		0
+#else
+/* disable caching on SDRAM */
+#define MY_TLB_WORD2_I_ENABLE		TLB_WORD2_I_ENABLE
+#endif /* CONFIG_4xx_DCACHE */
+
+void dcbz_area(u32 start_address, u32 num_bytes);
+#endif /* CONFIG_440 */
+
+#define MAXRANKS	4
+#define MAXBXCF		4
+
+#define MULDIV64(m1, m2, d)	(u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
+
+#if !defined(CONFIG_NAND_SPL)
+/*-----------------------------------------------------------------------------+
+ * sdram_memsize
+ *-----------------------------------------------------------------------------*/
+phys_size_t sdram_memsize(void)
+{
+	phys_size_t mem_size;
+	unsigned long mcopt2;
+	unsigned long mcstat;
+	unsigned long mb0cf;
+	unsigned long sdsz;
+	unsigned long i;
+
+	mem_size = 0;
+
+	mfsdram(SDRAM_MCOPT2, mcopt2);
+	mfsdram(SDRAM_MCSTAT, mcstat);
+
+	/* DDR controller must be enabled and not in self-refresh. */
+	/* Otherwise memsize is zero. */
+	if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+	    && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
+	    && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
+		== (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
+		for (i = 0; i < MAXBXCF; i++) {
+			mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
+			/* Banks enabled */
+			if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+#if defined(CONFIG_440)
+				sdsz = mfdcr_any(SDRAM_R0BAS + i) & SDRAM_RXBAS_SDSZ_MASK;
+#else
+				sdsz = mb0cf & SDRAM_RXBAS_SDSZ_MASK;
+#endif
+				switch(sdsz) {
+				case SDRAM_RXBAS_SDSZ_8:
+					mem_size+=8;
+					break;
+				case SDRAM_RXBAS_SDSZ_16:
+					mem_size+=16;
+					break;
+				case SDRAM_RXBAS_SDSZ_32:
+					mem_size+=32;
+					break;
+				case SDRAM_RXBAS_SDSZ_64:
+					mem_size+=64;
+					break;
+				case SDRAM_RXBAS_SDSZ_128:
+					mem_size+=128;
+					break;
+				case SDRAM_RXBAS_SDSZ_256:
+					mem_size+=256;
+					break;
+				case SDRAM_RXBAS_SDSZ_512:
+					mem_size+=512;
+					break;
+				case SDRAM_RXBAS_SDSZ_1024:
+					mem_size+=1024;
+					break;
+				case SDRAM_RXBAS_SDSZ_2048:
+					mem_size+=2048;
+					break;
+				case SDRAM_RXBAS_SDSZ_4096:
+					mem_size+=4096;
+					break;
+				default:
+					printf("WARNING: Unsupported bank size (SDSZ=0x%lx)!\n"
+					       , sdsz);
+					mem_size=0;
+					break;
+				}
+			}
+		}
+	}
+
+	return mem_size << 20;
+}
+
+/*-----------------------------------------------------------------------------+
+ * is_ecc_enabled
+ *-----------------------------------------------------------------------------*/
+static unsigned long is_ecc_enabled(void)
+{
+	unsigned long val;
+
+	mfsdram(SDRAM_MCOPT1, val);
+
+	return SDRAM_MCOPT1_MCHK_CHK_DECODE(val);
+}
+
+/*-----------------------------------------------------------------------------+
+ * board_add_ram_info
+ *-----------------------------------------------------------------------------*/
+void board_add_ram_info(int use_default)
+{
+	PPC4xx_SYS_INFO board_cfg;
+	u32 val;
+
+	if (is_ecc_enabled())
+		puts(" (ECC");
+	else
+		puts(" (ECC not");
+
+	get_sys_info(&board_cfg);
+
+#if defined(CONFIG_405EX)
+	val = board_cfg.freqPLB;
+#else
+	mfsdr(SDR0_DDR0, val);
+	val = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(val), 1);
+#endif
+	printf(" enabled, %d MHz", (val * 2) / 1000000);
+
+	mfsdram(SDRAM_MMODE, val);
+	val = (val & SDRAM_MMODE_DCL_MASK) >> 4;
+	printf(", CL%d)", val);
+}
+#endif /* !CONFIG_NAND_SPL */
+
+#if defined(CONFIG_SPD_EEPROM)
+
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
+#ifndef	TRUE
+#define TRUE		1
+#endif
+#ifndef FALSE
+#define FALSE		0
+#endif
+
+#define SDRAM_DDR1	1
+#define SDRAM_DDR2	2
+#define SDRAM_NONE	0
+
+#define MAXDIMMS	2
+#define MAX_SPD_BYTES	256   /* Max number of bytes on the DIMM's SPD EEPROM */
+
+#define ONE_BILLION	1000000000
+
+#define CMD_NOP		(7 << 19)
+#define CMD_PRECHARGE	(2 << 19)
+#define CMD_REFRESH	(1 << 19)
+#define CMD_EMR		(0 << 19)
+#define CMD_READ	(5 << 19)
+#define CMD_WRITE	(4 << 19)
+
+#define SELECT_MR	(0 << 16)
+#define SELECT_EMR	(1 << 16)
+#define SELECT_EMR2	(2 << 16)
+#define SELECT_EMR3	(3 << 16)
+
+/* MR */
+#define DLL_RESET	0x00000100
+
+#define WRITE_RECOV_2	(1 << 9)
+#define WRITE_RECOV_3	(2 << 9)
+#define WRITE_RECOV_4	(3 << 9)
+#define WRITE_RECOV_5	(4 << 9)
+#define WRITE_RECOV_6	(5 << 9)
+
+#define BURST_LEN_4	0x00000002
+
+/* EMR */
+#define ODT_0_OHM	0x00000000
+#define ODT_50_OHM	0x00000044
+#define ODT_75_OHM	0x00000004
+#define ODT_150_OHM	0x00000040
+
+#define ODS_FULL	0x00000000
+#define ODS_REDUCED	0x00000002
+#define OCD_CALIB_DEF	0x00000380
+
+/* defines for ODT (On Die Termination) of the 440SP(e) DDR2 controller */
+#define ODT_EB0R	(0x80000000 >> 8)
+#define ODT_EB0W	(0x80000000 >> 7)
+#define CALC_ODT_R(n)	(ODT_EB0R << (n << 1))
+#define CALC_ODT_W(n)	(ODT_EB0W << (n << 1))
+#define CALC_ODT_RW(n)	(CALC_ODT_R(n) | CALC_ODT_W(n))
+
+/* Defines for the Read Cycle Delay test */
+#define NUMMEMTESTS	8
+#define NUMMEMWORDS	8
+#define NUMLOOPS	64		/* memory test loops */
+
+/*
+ * Newer PPC's like 440SPe, 460EX/GT can be equipped with more than 2GB of SDRAM.
+ * To support such configurations, we "only" map the first 2GB via the TLB's. We
+ * need some free virtual address space for the remaining peripherals like, SoC
+ * devices, FLASH etc.
+ *
+ * Note that ECC is currently not supported on configurations with more than 2GB
+ * SDRAM. This is because we only map the first 2GB on such systems, and therefore
+ * the ECC parity byte of the remaining area can't be written.
+ */
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang (void)
+{
+	hang ();
+}
+void spd_ddr_init_hang (void) __attribute__((weak, alias("__spd_ddr_init_hang")));
+
+/*
+ * To provide an interface for board specific config values in this common
+ * DDR setup code, we implement he "weak" default functions here. They return
+ * the default value back to the caller.
+ *
+ * Please see include/configs/yucca.h for an example fora board specific
+ * implementation.
+ */
+u32 __ddr_wrdtr(u32 default_val)
+{
+	return default_val;
+}
+u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr")));
+
+u32 __ddr_clktr(u32 default_val)
+{
+	return default_val;
+}
+u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr")));
+
+
+/* Private Structure Definitions */
+
+/* enum only to ease code for cas latency setting */
+typedef enum ddr_cas_id {
+	DDR_CAS_2      = 20,
+	DDR_CAS_2_5    = 25,
+	DDR_CAS_3      = 30,
+	DDR_CAS_4      = 40,
+	DDR_CAS_5      = 50
+} ddr_cas_id_t;
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes
+ *-----------------------------------------------------------------------------*/
+static void get_spd_info(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks);
+static void check_mem_type(unsigned long *dimm_populated,
+			   unsigned char *iic0_dimm_addr,
+			   unsigned long num_dimm_banks);
+static void check_frequency(unsigned long *dimm_populated,
+			    unsigned char *iic0_dimm_addr,
+			    unsigned long num_dimm_banks);
+static void check_rank_number(unsigned long *dimm_populated,
+			      unsigned char *iic0_dimm_addr,
+			      unsigned long num_dimm_banks);
+static void check_voltage_type(unsigned long *dimm_populated,
+			       unsigned char *iic0_dimm_addr,
+			       unsigned long num_dimm_banks);
+static void program_memory_queue(unsigned long *dimm_populated,
+				 unsigned char *iic0_dimm_addr,
+				 unsigned long num_dimm_banks);
+static void program_codt(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks);
+static void program_mode(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks,
+			 ddr_cas_id_t *selected_cas,
+			 int *write_recovery);
+static void program_tr(unsigned long *dimm_populated,
+		       unsigned char *iic0_dimm_addr,
+		       unsigned long num_dimm_banks);
+static void program_rtr(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks);
+static void program_bxcf(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks);
+static void program_copt1(unsigned long *dimm_populated,
+			  unsigned char *iic0_dimm_addr,
+			  unsigned long num_dimm_banks);
+static void program_initplr(unsigned long *dimm_populated,
+			    unsigned char *iic0_dimm_addr,
+			    unsigned long num_dimm_banks,
+			    ddr_cas_id_t selected_cas,
+			    int write_recovery);
+#ifdef CONFIG_DDR_ECC
+static void program_ecc(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks,
+			unsigned long tlb_word2_i_value);
+#endif
+#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+static void program_DQS_calibration(unsigned long *dimm_populated,
+				unsigned char *iic0_dimm_addr,
+				unsigned long num_dimm_banks);
+#ifdef HARD_CODED_DQS /* calibration test with hardvalues */
+static void	test(void);
+#else
+static void	DQS_calibration_process(void);
+#endif
+#endif
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+
+static unsigned char spd_read(uchar chip, uint addr)
+{
+	unsigned char data[2];
+
+	if (i2c_probe(chip) == 0)
+		if (i2c_read(chip, addr, 1, data, 1) == 0)
+			return data[0];
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------+
+ * initdram.  Initializes the 440SP Memory Queue and DDR SDRAM controller.
+ * Note: This routine runs from flash with a stack set up in the chip's
+ * sram space.  It is important that the routine does not require .sbss, .bss or
+ * .data sections.  It also cannot call routines that require these sections.
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------
+ * Function:	 initdram
+ * Description:  Configures SDRAM memory banks for DDR operation.
+ *		 Auto Memory Configuration option reads the DDR SDRAM EEPROMs
+ *		 via the IIC bus and then configures the DDR SDRAM memory
+ *		 banks appropriately. If Auto Memory Configuration is
+ *		 not used, it is assumed that no DIMM is plugged
+ *-----------------------------------------------------------------------------*/
+phys_size_t initdram(int board_type)
+{
+	unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+	unsigned char spd0[MAX_SPD_BYTES];
+	unsigned char spd1[MAX_SPD_BYTES];
+	unsigned char *dimm_spd[MAXDIMMS];
+	unsigned long dimm_populated[MAXDIMMS] = {SDRAM_NONE, SDRAM_NONE};
+	unsigned long num_dimm_banks;		/* on board dimm banks */
+	unsigned long val;
+	ddr_cas_id_t selected_cas = DDR_CAS_5;	/* preset to silence compiler */
+	int write_recovery;
+	phys_size_t dram_size = 0;
+
+	num_dimm_banks = sizeof(iic0_dimm_addr);
+
+	/*------------------------------------------------------------------
+	 * Set up an array of SPD matrixes.
+	 *-----------------------------------------------------------------*/
+	dimm_spd[0] = spd0;
+	dimm_spd[1] = spd1;
+
+	/*------------------------------------------------------------------
+	 * Reset the DDR-SDRAM controller.
+	 *-----------------------------------------------------------------*/
+	mtsdr(SDR0_SRST, (0x80000000 >> 10));
+	mtsdr(SDR0_SRST, 0x00000000);
+
+	/*
+	 * Make sure I2C controller is initialized
+	 * before continuing.
+	 */
+
+	/* switch to correct I2C bus */
+	I2C_SET_BUS(CONFIG_SYS_SPD_BUS_NUM);
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	/*------------------------------------------------------------------
+	 * Clear out the serial presence detect buffers.
+	 * Perform IIC reads from the dimm.  Fill in the spds.
+	 * Check to see if the dimm slots are populated
+	 *-----------------------------------------------------------------*/
+	get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Check the memory type for the dimms plugged.
+	 *-----------------------------------------------------------------*/
+	check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Check the frequency supported for the dimms plugged.
+	 *-----------------------------------------------------------------*/
+	check_frequency(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Check the total rank number.
+	 *-----------------------------------------------------------------*/
+	check_rank_number(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Check the voltage type for the dimms plugged.
+	 *-----------------------------------------------------------------*/
+	check_voltage_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Program SDRAM controller options 2 register
+	 * Except Enabling of the memory controller.
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_MCOPT2, val);
+	mtsdram(SDRAM_MCOPT2,
+		(val &
+		 ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_PMEN_MASK |
+		   SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_XSRP_MASK |
+		   SDRAM_MCOPT2_ISIE_MASK))
+		| (SDRAM_MCOPT2_SREN_ENTER | SDRAM_MCOPT2_PMEN_DISABLE |
+		   SDRAM_MCOPT2_IPTR_IDLE | SDRAM_MCOPT2_XSRP_ALLOW |
+		   SDRAM_MCOPT2_ISIE_ENABLE));
+
+	/*------------------------------------------------------------------
+	 * Program SDRAM controller options 1 register
+	 * Note: Does not enable the memory controller.
+	 *-----------------------------------------------------------------*/
+	program_copt1(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Controller On Die Termination Register
+	 *-----------------------------------------------------------------*/
+	program_codt(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Program SDRAM refresh register.
+	 *-----------------------------------------------------------------*/
+	program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Program SDRAM mode register.
+	 *-----------------------------------------------------------------*/
+	program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+		     &selected_cas, &write_recovery);
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Write Data/DM/DQS Clock Timing Reg
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_WRDTR, val);
+	mtsdram(SDRAM_WRDTR, (val & ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) |
+		ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV));
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Clock Timing Register
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_CLKTR, val);
+	mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) |
+		ddr_clktr(SDRAM_CLKTR_CLKP_0_DEG));
+
+	/*------------------------------------------------------------------
+	 * Program the BxCF registers.
+	 *-----------------------------------------------------------------*/
+	program_bxcf(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Program SDRAM timing registers.
+	 *-----------------------------------------------------------------*/
+	program_tr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Set the Extended Mode register
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_MEMODE, val);
+	mtsdram(SDRAM_MEMODE,
+		(val & ~(SDRAM_MEMODE_DIC_MASK  | SDRAM_MEMODE_DLL_MASK |
+			 SDRAM_MEMODE_RTT_MASK | SDRAM_MEMODE_DQS_MASK)) |
+		(SDRAM_MEMODE_DIC_NORMAL | SDRAM_MEMODE_DLL_ENABLE
+		 | SDRAM_MEMODE_RTT_150OHM | SDRAM_MEMODE_DQS_ENABLE));
+
+	/*------------------------------------------------------------------
+	 * Program Initialization preload registers.
+	 *-----------------------------------------------------------------*/
+	program_initplr(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+			selected_cas, write_recovery);
+
+	/*------------------------------------------------------------------
+	 * Delay to ensure 200usec have elapsed since reset.
+	 *-----------------------------------------------------------------*/
+	udelay(400);
+
+	/*------------------------------------------------------------------
+	 * Set the memory queue core base addr.
+	 *-----------------------------------------------------------------*/
+	program_memory_queue(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Program SDRAM controller options 2 register
+	 * Enable the memory controller.
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_MCOPT2, val);
+	mtsdram(SDRAM_MCOPT2,
+		(val & ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_DCEN_MASK |
+			 SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_ISIE_MASK)) |
+			 SDRAM_MCOPT2_IPTR_EXECUTE);
+
+	/*------------------------------------------------------------------
+	 * Wait for IPTR_EXECUTE init sequence to complete.
+	 *-----------------------------------------------------------------*/
+	do {
+		mfsdram(SDRAM_MCSTAT, val);
+	} while ((val & SDRAM_MCSTAT_MIC_MASK) == SDRAM_MCSTAT_MIC_NOTCOMP);
+
+	/* enable the controller only after init sequence completes */
+	mfsdram(SDRAM_MCOPT2, val);
+	mtsdram(SDRAM_MCOPT2, (val | SDRAM_MCOPT2_DCEN_ENABLE));
+
+	/* Make sure delay-line calibration is done before proceeding */
+	do {
+		mfsdram(SDRAM_DLCR, val);
+	} while (!(val & SDRAM_DLCR_DLCS_COMPLETE));
+
+	/* get installed memory size */
+	dram_size = sdram_memsize();
+
+	/*
+	 * Limit size to 2GB
+	 */
+	if (dram_size > CONFIG_MAX_MEM_MAPPED)
+		dram_size = CONFIG_MAX_MEM_MAPPED;
+
+	/* and program tlb entries for this size (dynamic) */
+
+	/*
+	 * Program TLB entries with caches enabled, for best performace
+	 * while auto-calibrating and ECC generation
+	 */
+	program_tlb(0, 0, dram_size, 0);
+
+	/*------------------------------------------------------------------
+	 * DQS calibration.
+	 *-----------------------------------------------------------------*/
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+	DQS_autocalibration();
+#else
+	program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+#endif
+
+#ifdef CONFIG_DDR_ECC
+	/*------------------------------------------------------------------
+	 * If ecc is enabled, initialize the parity bits.
+	 *-----------------------------------------------------------------*/
+	program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, 0);
+#endif
+
+	/*
+	 * Now after initialization (auto-calibration and ECC generation)
+	 * remove the TLB entries with caches enabled and program again with
+	 * desired cache functionality
+	 */
+	remove_tlb(0, dram_size);
+	program_tlb(0, 0, dram_size, MY_TLB_WORD2_I_ENABLE);
+
+	ppc4xx_ibm_ddr2_register_dump();
+
+	/*
+	 * Clear potential errors resulting from auto-calibration.
+	 * If not done, then we could get an interrupt later on when
+	 * exceptions are enabled.
+	 */
+	set_mcsr(get_mcsr());
+
+	return sdram_memsize();
+}
+
+static void get_spd_info(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long dimm_found;
+	unsigned char num_of_bytes;
+	unsigned char total_size;
+
+	dimm_found = FALSE;
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		num_of_bytes = 0;
+		total_size = 0;
+
+		num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+		debug("\nspd_read(0x%x) returned %d\n",
+		      iic0_dimm_addr[dimm_num], num_of_bytes);
+		total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+		debug("spd_read(0x%x) returned %d\n",
+		      iic0_dimm_addr[dimm_num], total_size);
+
+		if ((num_of_bytes != 0) && (total_size != 0)) {
+			dimm_populated[dimm_num] = TRUE;
+			dimm_found = TRUE;
+			debug("DIMM slot %lu: populated\n", dimm_num);
+		} else {
+			dimm_populated[dimm_num] = FALSE;
+			debug("DIMM slot %lu: Not populated\n", dimm_num);
+		}
+	}
+
+	if (dimm_found == FALSE) {
+		printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n");
+		spd_ddr_init_hang ();
+	}
+}
+
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that they
+ * really are DDR specific DIMMs.
+ *-----------------------------------------------------------------*/
+static void check_mem_type(unsigned long *dimm_populated,
+			   unsigned char *iic0_dimm_addr,
+			   unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long dimm_type;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] == TRUE) {
+			dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2);
+			switch (dimm_type) {
+			case 1:
+				printf("ERROR: Standard Fast Page Mode DRAM DIMM detected in "
+				       "slot %d.\n", (unsigned int)dimm_num);
+				printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			case 2:
+				printf("ERROR: EDO DIMM detected in slot %d.\n",
+				       (unsigned int)dimm_num);
+				printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			case 3:
+				printf("ERROR: Pipelined Nibble DIMM detected in slot %d.\n",
+				       (unsigned int)dimm_num);
+				printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			case 4:
+				printf("ERROR: SDRAM DIMM detected in slot %d.\n",
+				       (unsigned int)dimm_num);
+				printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			case 5:
+				printf("ERROR: Multiplexed ROM DIMM detected in slot %d.\n",
+				       (unsigned int)dimm_num);
+				printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			case 6:
+				printf("ERROR: SGRAM DIMM detected in slot %d.\n",
+				       (unsigned int)dimm_num);
+				printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			case 7:
+				debug("DIMM slot %lu: DDR1 SDRAM detected\n", dimm_num);
+				dimm_populated[dimm_num] = SDRAM_DDR1;
+				break;
+			case 8:
+				debug("DIMM slot %lu: DDR2 SDRAM detected\n", dimm_num);
+				dimm_populated[dimm_num] = SDRAM_DDR2;
+				break;
+			default:
+				printf("ERROR: Unknown DIMM detected in slot %d.\n",
+				       (unsigned int)dimm_num);
+				printf("Only DDR1 and DDR2 SDRAM DIMMs are supported.\n");
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			}
+		}
+	}
+	for (dimm_num = 1; dimm_num < num_dimm_banks; dimm_num++) {
+		if ((dimm_populated[dimm_num-1] != SDRAM_NONE)
+		    && (dimm_populated[dimm_num]   != SDRAM_NONE)
+		    && (dimm_populated[dimm_num-1] != dimm_populated[dimm_num])) {
+			printf("ERROR: DIMM's DDR1 and DDR2 type can not be mixed.\n");
+			spd_ddr_init_hang ();
+		}
+	}
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that
+ * frequency previously calculated is supported.
+ *-----------------------------------------------------------------*/
+static void check_frequency(unsigned long *dimm_populated,
+			    unsigned char *iic0_dimm_addr,
+			    unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long tcyc_reg;
+	unsigned long cycle_time;
+	unsigned long calc_cycle_time;
+	unsigned long sdram_freq;
+	unsigned long sdr_ddrpll;
+	PPC4xx_SYS_INFO board_cfg;
+
+	/*------------------------------------------------------------------
+	 * Get the board configuration info.
+	 *-----------------------------------------------------------------*/
+	get_sys_info(&board_cfg);
+
+	mfsdr(SDR0_DDR0, sdr_ddrpll);
+	sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+	/*
+	 * calc_cycle_time is calculated from DDR frequency set by board/chip
+	 * and is expressed in multiple of 10 picoseconds
+	 * to match the way DIMM cycle time is calculated below.
+	 */
+	calc_cycle_time = MULDIV64(ONE_BILLION, 100, sdram_freq);
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+			/*
+			 * Byte 9, Cycle time for CAS Latency=X, is split into two nibbles:
+			 * the higher order nibble (bits 4-7) designates the cycle time
+			 * to a granularity of 1ns;
+			 * the value presented by the lower order nibble (bits 0-3)
+			 * has a granularity of .1ns and is added to the value designated
+			 * by the higher nibble. In addition, four lines of the lower order
+			 * nibble are assigned to support +.25,+.33, +.66 and +.75.
+			 */
+			 /* Convert from hex to decimal */
+			if ((tcyc_reg & 0x0F) == 0x0D)
+				cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+			else if ((tcyc_reg & 0x0F) == 0x0C)
+				cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 66;
+			else if ((tcyc_reg & 0x0F) == 0x0B)
+				cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 33;
+			else if ((tcyc_reg & 0x0F) == 0x0A)
+				cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 25;
+			else
+				cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) +
+					((tcyc_reg & 0x0F)*10);
+			debug("cycle_time=%lu [10 picoseconds]\n", cycle_time);
+
+			if  (cycle_time > (calc_cycle_time + 10)) {
+				/*
+				 * the provided sdram cycle_time is too small
+				 * for the available DIMM cycle_time.
+				 * The additionnal 100ps is here to accept a small incertainty.
+				 */
+				printf("ERROR: DRAM DIMM detected with cycle_time %d ps in "
+				       "slot %d \n while calculated cycle time is %d ps.\n",
+				       (unsigned int)(cycle_time*10),
+				       (unsigned int)dimm_num,
+				       (unsigned int)(calc_cycle_time*10));
+				printf("Replace the DIMM, or change DDR frequency via "
+				       "strapping bits.\n\n");
+				spd_ddr_init_hang ();
+			}
+		}
+	}
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies two
+ * ranks/banks maximum are availables.
+ *-----------------------------------------------------------------*/
+static void check_rank_number(unsigned long *dimm_populated,
+			      unsigned char *iic0_dimm_addr,
+			      unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long dimm_rank;
+	unsigned long total_rank = 0;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			dimm_rank = spd_read(iic0_dimm_addr[dimm_num], 5);
+			if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+				dimm_rank = (dimm_rank & 0x0F) +1;
+			else
+				dimm_rank = dimm_rank & 0x0F;
+
+
+			if (dimm_rank > MAXRANKS) {
+				printf("ERROR: DRAM DIMM detected with %lu ranks in "
+				       "slot %lu is not supported.\n", dimm_rank, dimm_num);
+				printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS);
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+			} else
+				total_rank += dimm_rank;
+		}
+		if (total_rank > MAXRANKS) {
+			printf("ERROR: DRAM DIMM detected with a total of %d ranks "
+			       "for all slots.\n", (unsigned int)total_rank);
+			printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS);
+			printf("Remove one of the DIMM modules.\n\n");
+			spd_ddr_init_hang ();
+		}
+	}
+}
+
+/*------------------------------------------------------------------
+ * only support 2.5V modules.
+ * This routine verifies this.
+ *-----------------------------------------------------------------*/
+static void check_voltage_type(unsigned long *dimm_populated,
+			       unsigned char *iic0_dimm_addr,
+			       unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long voltage_type;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+			switch (voltage_type) {
+			case 0x00:
+				printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+				printf("This DIMM is 5.0 Volt/TTL.\n");
+				printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+				       (unsigned int)dimm_num);
+				spd_ddr_init_hang ();
+				break;
+			case 0x01:
+				printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+				printf("This DIMM is LVTTL.\n");
+				printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+				       (unsigned int)dimm_num);
+				spd_ddr_init_hang ();
+				break;
+			case 0x02:
+				printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+				printf("This DIMM is 1.5 Volt.\n");
+				printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+				       (unsigned int)dimm_num);
+				spd_ddr_init_hang ();
+				break;
+			case 0x03:
+				printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+				printf("This DIMM is 3.3 Volt/TTL.\n");
+				printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+				       (unsigned int)dimm_num);
+				spd_ddr_init_hang ();
+				break;
+			case 0x04:
+				/* 2.5 Voltage only for DDR1 */
+				break;
+			case 0x05:
+				/* 1.8 Voltage only for DDR2 */
+				break;
+			default:
+				printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+				printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+				       (unsigned int)dimm_num);
+				spd_ddr_init_hang ();
+				break;
+			}
+		}
+	}
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_copt1.
+ *-----------------------------------------------------------------------------*/
+static void program_copt1(unsigned long *dimm_populated,
+			  unsigned char *iic0_dimm_addr,
+			  unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long mcopt1;
+	unsigned long ecc_enabled;
+	unsigned long ecc = 0;
+	unsigned long data_width = 0;
+	unsigned long dimm_32bit;
+	unsigned long dimm_64bit;
+	unsigned long registered = 0;
+	unsigned long attribute = 0;
+	unsigned long buf0, buf1; /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */
+	unsigned long bankcount;
+	unsigned long ddrtype;
+	unsigned long val;
+
+#ifdef CONFIG_DDR_ECC
+	ecc_enabled = TRUE;
+#else
+	ecc_enabled = FALSE;
+#endif
+	dimm_32bit = FALSE;
+	dimm_64bit = FALSE;
+	buf0 = FALSE;
+	buf1 = FALSE;
+
+	/*------------------------------------------------------------------
+	 * Set memory controller options reg 1, SDRAM_MCOPT1.
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_MCOPT1, val);
+	mcopt1 = val & ~(SDRAM_MCOPT1_MCHK_MASK | SDRAM_MCOPT1_RDEN_MASK |
+			 SDRAM_MCOPT1_PMU_MASK  | SDRAM_MCOPT1_DMWD_MASK |
+			 SDRAM_MCOPT1_UIOS_MASK | SDRAM_MCOPT1_BCNT_MASK |
+			 SDRAM_MCOPT1_DDR_TYPE_MASK | SDRAM_MCOPT1_RWOO_MASK |
+			 SDRAM_MCOPT1_WOOO_MASK | SDRAM_MCOPT1_DCOO_MASK |
+			 SDRAM_MCOPT1_DREF_MASK);
+
+	mcopt1 |= SDRAM_MCOPT1_QDEP;
+	mcopt1 |= SDRAM_MCOPT1_PMU_OPEN;
+	mcopt1 |= SDRAM_MCOPT1_RWOO_DISABLED;
+	mcopt1 |= SDRAM_MCOPT1_WOOO_DISABLED;
+	mcopt1 |= SDRAM_MCOPT1_DCOO_DISABLED;
+	mcopt1 |= SDRAM_MCOPT1_DREF_NORMAL;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			/* test ecc support */
+			ecc = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 11);
+			if (ecc != 0x02) /* ecc not supported */
+				ecc_enabled = FALSE;
+
+			/* test bank count */
+			bankcount = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 17);
+			if (bankcount == 0x04) /* bank count = 4 */
+				mcopt1 |= SDRAM_MCOPT1_4_BANKS;
+			else /* bank count = 8 */
+				mcopt1 |= SDRAM_MCOPT1_8_BANKS;
+
+			/* test DDR type */
+			ddrtype = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2);
+			/* test for buffered/unbuffered, registered, differential clocks */
+			registered = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 20);
+			attribute = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 21);
+
+			/* TODO: code to be changed for IOP1.6 to support 4 DIMMs */
+			if (dimm_num == 0) {
+				if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */
+					mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE;
+				if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */
+					mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE;
+				if (registered == 1) { /* DDR2 always buffered */
+					/* TODO: what about above  comments ? */
+					mcopt1 |= SDRAM_MCOPT1_RDEN;
+					buf0 = TRUE;
+				} else {
+					/* TODO: the mask 0x02 doesn't match Samsung def for byte 21. */
+					if ((attribute & 0x02) == 0x00) {
+						/* buffered not supported */
+						buf0 = FALSE;
+					} else {
+						mcopt1 |= SDRAM_MCOPT1_RDEN;
+						buf0 = TRUE;
+					}
+				}
+			}
+			else if (dimm_num == 1) {
+				if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */
+					mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE;
+				if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */
+					mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE;
+				if (registered == 1) {
+					/* DDR2 always buffered */
+					mcopt1 |= SDRAM_MCOPT1_RDEN;
+					buf1 = TRUE;
+				} else {
+					if ((attribute & 0x02) == 0x00) {
+						/* buffered not supported */
+						buf1 = FALSE;
+					} else {
+						mcopt1 |= SDRAM_MCOPT1_RDEN;
+						buf1 = TRUE;
+					}
+				}
+			}
+
+			/* Note that for DDR2 the byte 7 is reserved, but OK to keep code as is. */
+			data_width = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 6) +
+				(((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 7)) << 8);
+
+			switch (data_width) {
+			case 72:
+			case 64:
+				dimm_64bit = TRUE;
+				break;
+			case 40:
+			case 32:
+				dimm_32bit = TRUE;
+				break;
+			default:
+				printf("WARNING: Detected a DIMM with a data width of %lu bits.\n",
+				       data_width);
+				printf("Only DIMMs with 32 or 64 bit DDR-SDRAM widths are supported.\n");
+				break;
+			}
+		}
+	}
+
+	/* verify matching properties */
+	if ((dimm_populated[0] != SDRAM_NONE) && (dimm_populated[1] != SDRAM_NONE)) {
+		if (buf0 != buf1) {
+			printf("ERROR: DIMM's buffered/unbuffered, registered, clocking don't match.\n");
+			spd_ddr_init_hang ();
+		}
+	}
+
+	if ((dimm_64bit == TRUE) && (dimm_32bit == TRUE)) {
+		printf("ERROR: Cannot mix 32 bit and 64 bit DDR-SDRAM DIMMs together.\n");
+		spd_ddr_init_hang ();
+	}
+	else if ((dimm_64bit == TRUE) && (dimm_32bit == FALSE)) {
+		mcopt1 |= SDRAM_MCOPT1_DMWD_64;
+	} else if ((dimm_64bit == FALSE) && (dimm_32bit == TRUE)) {
+		mcopt1 |= SDRAM_MCOPT1_DMWD_32;
+	} else {
+		printf("ERROR: Please install only 32 or 64 bit DDR-SDRAM DIMMs.\n\n");
+		spd_ddr_init_hang ();
+	}
+
+	if (ecc_enabled == TRUE)
+		mcopt1 |= SDRAM_MCOPT1_MCHK_GEN;
+	else
+		mcopt1 |= SDRAM_MCOPT1_MCHK_NON;
+
+	mtsdram(SDRAM_MCOPT1, mcopt1);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_codt.
+ *-----------------------------------------------------------------------------*/
+static void program_codt(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long codt;
+	unsigned long modt0 = 0;
+	unsigned long modt1 = 0;
+	unsigned long modt2 = 0;
+	unsigned long modt3 = 0;
+	unsigned char dimm_num;
+	unsigned char dimm_rank;
+	unsigned char total_rank = 0;
+	unsigned char total_dimm = 0;
+	unsigned char dimm_type = 0;
+	unsigned char firstSlot = 0;
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Controller On Die Termination Register
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_CODT, codt);
+	codt &= ~(SDRAM_CODT_DQS_SINGLE_END | SDRAM_CODT_CKSE_SINGLE_END);
+	codt |= SDRAM_CODT_IO_NMODE;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			dimm_rank = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 5);
+			if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) {
+				dimm_rank = (dimm_rank & 0x0F) + 1;
+				dimm_type = SDRAM_DDR2;
+			} else {
+				dimm_rank = dimm_rank & 0x0F;
+				dimm_type = SDRAM_DDR1;
+			}
+
+			total_rank += dimm_rank;
+			total_dimm++;
+			if ((dimm_num == 0) && (total_dimm == 1))
+				firstSlot = TRUE;
+			else
+				firstSlot = FALSE;
+		}
+	}
+	if (dimm_type == SDRAM_DDR2) {
+		codt |= SDRAM_CODT_DQS_1_8_V_DDR2;
+		if ((total_dimm == 1) && (firstSlot == TRUE)) {
+			if (total_rank == 1) {	/* PUUU */
+				codt |= CALC_ODT_R(0);
+				modt0 = CALC_ODT_W(0);
+				modt1 = 0x00000000;
+				modt2 = 0x00000000;
+				modt3 = 0x00000000;
+			}
+			if (total_rank == 2) {	/* PPUU */
+				codt |= CALC_ODT_R(0) | CALC_ODT_R(1);
+				modt0 = CALC_ODT_W(0) | CALC_ODT_W(1);
+				modt1 = 0x00000000;
+				modt2 = 0x00000000;
+				modt3 = 0x00000000;
+			}
+		} else if ((total_dimm == 1) && (firstSlot != TRUE)) {
+			if (total_rank == 1) {	/* UUPU */
+				codt |= CALC_ODT_R(2);
+				modt0 = 0x00000000;
+				modt1 = 0x00000000;
+				modt2 = CALC_ODT_W(2);
+				modt3 = 0x00000000;
+			}
+			if (total_rank == 2) {	/* UUPP */
+				codt |= CALC_ODT_R(2) | CALC_ODT_R(3);
+				modt0 = 0x00000000;
+				modt1 = 0x00000000;
+				modt2 = CALC_ODT_W(2) | CALC_ODT_W(3);
+				modt3 = 0x00000000;
+			}
+		}
+		if (total_dimm == 2) {
+			if (total_rank == 2) {	/* PUPU */
+				codt |= CALC_ODT_R(0) | CALC_ODT_R(2);
+				modt0 = CALC_ODT_RW(2);
+				modt1 = 0x00000000;
+				modt2 = CALC_ODT_RW(0);
+				modt3 = 0x00000000;
+			}
+			if (total_rank == 4) {	/* PPPP */
+				codt |= CALC_ODT_R(0) | CALC_ODT_R(1) |
+					CALC_ODT_R(2) | CALC_ODT_R(3);
+				modt0 = CALC_ODT_RW(2) | CALC_ODT_RW(3);
+				modt1 = 0x00000000;
+				modt2 = CALC_ODT_RW(0) | CALC_ODT_RW(1);
+				modt3 = 0x00000000;
+			}
+		}
+	} else {
+		codt |= SDRAM_CODT_DQS_2_5_V_DDR1;
+		modt0 = 0x00000000;
+		modt1 = 0x00000000;
+		modt2 = 0x00000000;
+		modt3 = 0x00000000;
+
+		if (total_dimm == 1) {
+			if (total_rank == 1)
+				codt |= 0x00800000;
+			if (total_rank == 2)
+				codt |= 0x02800000;
+		}
+		if (total_dimm == 2) {
+			if (total_rank == 2)
+				codt |= 0x08800000;
+			if (total_rank == 4)
+				codt |= 0x2a800000;
+		}
+	}
+
+	debug("nb of dimm %d\n", total_dimm);
+	debug("nb of rank %d\n", total_rank);
+	if (total_dimm == 1)
+		debug("dimm in slot %d\n", firstSlot);
+
+	mtsdram(SDRAM_CODT, codt);
+	mtsdram(SDRAM_MODT0, modt0);
+	mtsdram(SDRAM_MODT1, modt1);
+	mtsdram(SDRAM_MODT2, modt2);
+	mtsdram(SDRAM_MODT3, modt3);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_initplr.
+ *-----------------------------------------------------------------------------*/
+static void program_initplr(unsigned long *dimm_populated,
+			    unsigned char *iic0_dimm_addr,
+			    unsigned long num_dimm_banks,
+			    ddr_cas_id_t selected_cas,
+			    int write_recovery)
+{
+	u32 cas = 0;
+	u32 odt = 0;
+	u32 ods = 0;
+	u32 mr;
+	u32 wr;
+	u32 emr;
+	u32 emr2;
+	u32 emr3;
+	int dimm_num;
+	int total_dimm = 0;
+
+	/******************************************************
+	 ** Assumption: if more than one DIMM, all DIMMs are the same
+	 **		as already checked in check_memory_type
+	 ******************************************************/
+
+	if ((dimm_populated[0] == SDRAM_DDR1) || (dimm_populated[1] == SDRAM_DDR1)) {
+		mtsdram(SDRAM_INITPLR0, 0x81B80000);
+		mtsdram(SDRAM_INITPLR1, 0x81900400);
+		mtsdram(SDRAM_INITPLR2, 0x81810000);
+		mtsdram(SDRAM_INITPLR3, 0xff800162);
+		mtsdram(SDRAM_INITPLR4, 0x81900400);
+		mtsdram(SDRAM_INITPLR5, 0x86080000);
+		mtsdram(SDRAM_INITPLR6, 0x86080000);
+		mtsdram(SDRAM_INITPLR7, 0x81000062);
+	} else if ((dimm_populated[0] == SDRAM_DDR2) || (dimm_populated[1] == SDRAM_DDR2)) {
+		switch (selected_cas) {
+		case DDR_CAS_3:
+			cas = 3 << 4;
+			break;
+		case DDR_CAS_4:
+			cas = 4 << 4;
+			break;
+		case DDR_CAS_5:
+			cas = 5 << 4;
+			break;
+		default:
+			printf("ERROR: ucode error on selected_cas value %d", selected_cas);
+			spd_ddr_init_hang ();
+			break;
+		}
+
+#if 0
+		/*
+		 * ToDo - Still a problem with the write recovery:
+		 * On the Corsair CM2X512-5400C4 module, setting write recovery
+		 * in the INITPLR reg to the value calculated in program_mode()
+		 * results in not correctly working DDR2 memory (crash after
+		 * relocation).
+		 *
+		 * So for now, set the write recovery to 3. This seems to work
+		 * on the Corair module too.
+		 *
+		 * 2007-03-01, sr
+		 */
+		switch (write_recovery) {
+		case 3:
+			wr = WRITE_RECOV_3;
+			break;
+		case 4:
+			wr = WRITE_RECOV_4;
+			break;
+		case 5:
+			wr = WRITE_RECOV_5;
+			break;
+		case 6:
+			wr = WRITE_RECOV_6;
+			break;
+		default:
+			printf("ERROR: write recovery not support (%d)", write_recovery);
+			spd_ddr_init_hang ();
+			break;
+		}
+#else
+		wr = WRITE_RECOV_3; /* test-only, see description above */
+#endif
+
+		for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++)
+			if (dimm_populated[dimm_num] != SDRAM_NONE)
+				total_dimm++;
+		if (total_dimm == 1) {
+			odt = ODT_150_OHM;
+			ods = ODS_FULL;
+		} else if (total_dimm == 2) {
+			odt = ODT_75_OHM;
+			ods = ODS_REDUCED;
+		} else {
+			printf("ERROR: Unsupported number of DIMM's (%d)", total_dimm);
+			spd_ddr_init_hang ();
+		}
+
+		mr = CMD_EMR | SELECT_MR | BURST_LEN_4 | wr | cas;
+		emr = CMD_EMR | SELECT_EMR | odt | ods;
+		emr2 = CMD_EMR | SELECT_EMR2;
+		emr3 = CMD_EMR | SELECT_EMR3;
+		/* NOP - Wait 106 MemClk cycles */
+		mtsdram(SDRAM_INITPLR0, SDRAM_INITPLR_ENABLE | CMD_NOP |
+					SDRAM_INITPLR_IMWT_ENCODE(106));
+		udelay(1000);
+		/* precharge 4 MemClk cycles */
+		mtsdram(SDRAM_INITPLR1, SDRAM_INITPLR_ENABLE | CMD_PRECHARGE |
+					SDRAM_INITPLR_IMWT_ENCODE(4));
+		/* EMR2 - Wait tMRD (2 MemClk cycles) */
+		mtsdram(SDRAM_INITPLR2, SDRAM_INITPLR_ENABLE | emr2 |
+					SDRAM_INITPLR_IMWT_ENCODE(2));
+		/* EMR3 - Wait tMRD (2 MemClk cycles) */
+		mtsdram(SDRAM_INITPLR3, SDRAM_INITPLR_ENABLE | emr3 |
+					SDRAM_INITPLR_IMWT_ENCODE(2));
+		/* EMR DLL ENABLE - Wait tMRD (2 MemClk cycles) */
+		mtsdram(SDRAM_INITPLR4, SDRAM_INITPLR_ENABLE | emr |
+					SDRAM_INITPLR_IMWT_ENCODE(2));
+		/* MR w/ DLL reset - 200 cycle wait for DLL reset */
+		mtsdram(SDRAM_INITPLR5, SDRAM_INITPLR_ENABLE | mr | DLL_RESET |
+					SDRAM_INITPLR_IMWT_ENCODE(200));
+		udelay(1000);
+		/* precharge 4 MemClk cycles */
+		mtsdram(SDRAM_INITPLR6, SDRAM_INITPLR_ENABLE | CMD_PRECHARGE |
+					SDRAM_INITPLR_IMWT_ENCODE(4));
+		/* Refresh 25 MemClk cycles */
+		mtsdram(SDRAM_INITPLR7, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+					SDRAM_INITPLR_IMWT_ENCODE(25));
+		/* Refresh 25 MemClk cycles */
+		mtsdram(SDRAM_INITPLR8, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+					SDRAM_INITPLR_IMWT_ENCODE(25));
+		/* Refresh 25 MemClk cycles */
+		mtsdram(SDRAM_INITPLR9, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+					SDRAM_INITPLR_IMWT_ENCODE(25));
+		/* Refresh 25 MemClk cycles */
+		mtsdram(SDRAM_INITPLR10, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+					 SDRAM_INITPLR_IMWT_ENCODE(25));
+		/* MR w/o DLL reset - Wait tMRD (2 MemClk cycles) */
+		mtsdram(SDRAM_INITPLR11, SDRAM_INITPLR_ENABLE | mr |
+					 SDRAM_INITPLR_IMWT_ENCODE(2));
+		/* EMR OCD Default - Wait tMRD (2 MemClk cycles) */
+		mtsdram(SDRAM_INITPLR12, SDRAM_INITPLR_ENABLE | OCD_CALIB_DEF |
+					 SDRAM_INITPLR_IMWT_ENCODE(2) | emr);
+		/* EMR OCD Exit */
+		mtsdram(SDRAM_INITPLR13, SDRAM_INITPLR_ENABLE | emr |
+					 SDRAM_INITPLR_IMWT_ENCODE(2));
+	} else {
+		printf("ERROR: ucode error as unknown DDR type in program_initplr");
+		spd_ddr_init_hang ();
+	}
+}
+
+/*------------------------------------------------------------------
+ * This routine programs the SDRAM_MMODE register.
+ * the selected_cas is an output parameter, that will be passed
+ * by caller to call the above program_initplr( )
+ *-----------------------------------------------------------------*/
+static void program_mode(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks,
+			 ddr_cas_id_t *selected_cas,
+			 int *write_recovery)
+{
+	unsigned long dimm_num;
+	unsigned long sdram_ddr1;
+	unsigned long t_wr_ns;
+	unsigned long t_wr_clk;
+	unsigned long cas_bit;
+	unsigned long cas_index;
+	unsigned long sdram_freq;
+	unsigned long ddr_check;
+	unsigned long mmode;
+	unsigned long tcyc_reg;
+	unsigned long cycle_2_0_clk;
+	unsigned long cycle_2_5_clk;
+	unsigned long cycle_3_0_clk;
+	unsigned long cycle_4_0_clk;
+	unsigned long cycle_5_0_clk;
+	unsigned long max_2_0_tcyc_ns_x_100;
+	unsigned long max_2_5_tcyc_ns_x_100;
+	unsigned long max_3_0_tcyc_ns_x_100;
+	unsigned long max_4_0_tcyc_ns_x_100;
+	unsigned long max_5_0_tcyc_ns_x_100;
+	unsigned long cycle_time_ns_x_100[3];
+	PPC4xx_SYS_INFO board_cfg;
+	unsigned char cas_2_0_available;
+	unsigned char cas_2_5_available;
+	unsigned char cas_3_0_available;
+	unsigned char cas_4_0_available;
+	unsigned char cas_5_0_available;
+	unsigned long sdr_ddrpll;
+
+	/*------------------------------------------------------------------
+	 * Get the board configuration info.
+	 *-----------------------------------------------------------------*/
+	get_sys_info(&board_cfg);
+
+	mfsdr(SDR0_DDR0, sdr_ddrpll);
+	sdram_freq = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(sdr_ddrpll), 1);
+	debug("sdram_freq=%lu\n", sdram_freq);
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	t_wr_ns = 0;
+	cas_2_0_available = TRUE;
+	cas_2_5_available = TRUE;
+	cas_3_0_available = TRUE;
+	cas_4_0_available = TRUE;
+	cas_5_0_available = TRUE;
+	max_2_0_tcyc_ns_x_100 = 10;
+	max_2_5_tcyc_ns_x_100 = 10;
+	max_3_0_tcyc_ns_x_100 = 10;
+	max_4_0_tcyc_ns_x_100 = 10;
+	max_5_0_tcyc_ns_x_100 = 10;
+	sdram_ddr1 = TRUE;
+
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			if (dimm_populated[dimm_num] == SDRAM_DDR1)
+				sdram_ddr1 = TRUE;
+			else
+				sdram_ddr1 = FALSE;
+
+			/* t_wr_ns = max(t_wr_ns, (unsigned long)dimm_spd[dimm_num][36] >> 2); */ /*  not used in this loop. */
+			cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+			debug("cas_bit[SPD byte 18]=%02lx\n", cas_bit);
+
+			/* For a particular DIMM, grab the three CAS values it supports */
+			for (cas_index = 0; cas_index < 3; cas_index++) {
+				switch (cas_index) {
+				case 0:
+					tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+					break;
+				case 1:
+					tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23);
+					break;
+				default:
+					tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25);
+					break;
+				}
+
+				if ((tcyc_reg & 0x0F) >= 10) {
+					if ((tcyc_reg & 0x0F) == 0x0D) {
+						/* Convert from hex to decimal */
+						cycle_time_ns_x_100[cas_index] =
+							(((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+					} else {
+						printf("ERROR: SPD reported Tcyc is incorrect for DIMM "
+						       "in slot %d\n", (unsigned int)dimm_num);
+						spd_ddr_init_hang ();
+					}
+				} else {
+					/* Convert from hex to decimal */
+					cycle_time_ns_x_100[cas_index] =
+						(((tcyc_reg & 0xF0) >> 4) * 100) +
+						((tcyc_reg & 0x0F)*10);
+				}
+				debug("cas_index=%lu: cycle_time_ns_x_100=%lu\n", cas_index,
+				      cycle_time_ns_x_100[cas_index]);
+			}
+
+			/* The rest of this routine determines if CAS 2.0, 2.5, 3.0, 4.0 and 5.0 are */
+			/* supported for a particular DIMM. */
+			cas_index = 0;
+
+			if (sdram_ddr1) {
+				/*
+				 * DDR devices use the following bitmask for CAS latency:
+				 *  Bit   7    6    5    4    3    2    1    0
+				 *       TBD  4.0  3.5  3.0  2.5  2.0  1.5  1.0
+				 */
+				if (((cas_bit & 0x40) == 0x40) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_4_0_available = FALSE;
+				}
+
+				if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_3_0_available = FALSE;
+				}
+
+				if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_2_5_tcyc_ns_x_100 = max(max_2_5_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_2_5_available = FALSE;
+				}
+
+				if (((cas_bit & 0x04) == 0x04) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_2_0_tcyc_ns_x_100 = max(max_2_0_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_2_0_available = FALSE;
+				}
+			} else {
+				/*
+				 * DDR2 devices use the following bitmask for CAS latency:
+				 *  Bit   7    6    5    4    3    2    1    0
+				 *       TBD  6.0  5.0  4.0  3.0  2.0  TBD  TBD
+				 */
+				if (((cas_bit & 0x20) == 0x20) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_5_0_tcyc_ns_x_100 = max(max_5_0_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_5_0_available = FALSE;
+				}
+
+				if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_4_0_available = FALSE;
+				}
+
+				if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) &&
+				    (cycle_time_ns_x_100[cas_index] != 0)) {
+					max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100,
+								    cycle_time_ns_x_100[cas_index]);
+					cas_index++;
+				} else {
+					if (cas_index != 0)
+						cas_index++;
+					cas_3_0_available = FALSE;
+				}
+			}
+		}
+	}
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM mode, SDRAM_MMODE
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_MMODE, mmode);
+	mmode = mmode & ~(SDRAM_MMODE_WR_MASK | SDRAM_MMODE_DCL_MASK);
+
+	/* add 10 here because of rounding problems */
+	cycle_2_0_clk = MULDIV64(ONE_BILLION, 100, max_2_0_tcyc_ns_x_100) + 10;
+	cycle_2_5_clk = MULDIV64(ONE_BILLION, 100, max_2_5_tcyc_ns_x_100) + 10;
+	cycle_3_0_clk = MULDIV64(ONE_BILLION, 100, max_3_0_tcyc_ns_x_100) + 10;
+	cycle_4_0_clk = MULDIV64(ONE_BILLION, 100, max_4_0_tcyc_ns_x_100) + 10;
+	cycle_5_0_clk = MULDIV64(ONE_BILLION, 100, max_5_0_tcyc_ns_x_100) + 10;
+	debug("cycle_3_0_clk=%lu\n", cycle_3_0_clk);
+	debug("cycle_4_0_clk=%lu\n", cycle_4_0_clk);
+	debug("cycle_5_0_clk=%lu\n", cycle_5_0_clk);
+
+	if (sdram_ddr1 == TRUE) { /* DDR1 */
+		if ((cas_2_0_available == TRUE) && (sdram_freq <= cycle_2_0_clk)) {
+			mmode |= SDRAM_MMODE_DCL_DDR1_2_0_CLK;
+			*selected_cas = DDR_CAS_2;
+		} else if ((cas_2_5_available == TRUE) && (sdram_freq <= cycle_2_5_clk)) {
+			mmode |= SDRAM_MMODE_DCL_DDR1_2_5_CLK;
+			*selected_cas = DDR_CAS_2_5;
+		} else if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) {
+			mmode |= SDRAM_MMODE_DCL_DDR1_3_0_CLK;
+			*selected_cas = DDR_CAS_3;
+		} else {
+			printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
+			printf("Only DIMMs DDR1 with CAS latencies of 2.0, 2.5, and 3.0 are supported.\n");
+			printf("Make sure the PLB speed is within the supported range of the DIMMs.\n\n");
+			spd_ddr_init_hang ();
+		}
+	} else { /* DDR2 */
+		debug("cas_3_0_available=%d\n", cas_3_0_available);
+		debug("cas_4_0_available=%d\n", cas_4_0_available);
+		debug("cas_5_0_available=%d\n", cas_5_0_available);
+		if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) {
+			mmode |= SDRAM_MMODE_DCL_DDR2_3_0_CLK;
+			*selected_cas = DDR_CAS_3;
+		} else if ((cas_4_0_available == TRUE) && (sdram_freq <= cycle_4_0_clk)) {
+			mmode |= SDRAM_MMODE_DCL_DDR2_4_0_CLK;
+			*selected_cas = DDR_CAS_4;
+		} else if ((cas_5_0_available == TRUE) && (sdram_freq <= cycle_5_0_clk)) {
+			mmode |= SDRAM_MMODE_DCL_DDR2_5_0_CLK;
+			*selected_cas = DDR_CAS_5;
+		} else {
+			printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
+			printf("Only DIMMs DDR2 with CAS latencies of 3.0, 4.0, and 5.0 are supported.\n");
+			printf("Make sure the PLB speed is within the supported range of the DIMMs.\n");
+			printf("cas3=%d cas4=%d cas5=%d\n",
+			       cas_3_0_available, cas_4_0_available, cas_5_0_available);
+			printf("sdram_freq=%lu cycle3=%lu cycle4=%lu cycle5=%lu\n\n",
+			       sdram_freq, cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk);
+			spd_ddr_init_hang ();
+		}
+	}
+
+	if (sdram_ddr1 == TRUE)
+		mmode |= SDRAM_MMODE_WR_DDR1;
+	else {
+
+		/* loop through all the DIMM slots on the board */
+		for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+			/* If a dimm is installed in a particular slot ... */
+			if (dimm_populated[dimm_num] != SDRAM_NONE)
+				t_wr_ns = max(t_wr_ns,
+					      spd_read(iic0_dimm_addr[dimm_num], 36) >> 2);
+		}
+
+		/*
+		 * convert from nanoseconds to ddr clocks
+		 * round up if necessary
+		 */
+		t_wr_clk = MULDIV64(sdram_freq, t_wr_ns, ONE_BILLION);
+		ddr_check = MULDIV64(ONE_BILLION, t_wr_clk, t_wr_ns);
+		if (sdram_freq != ddr_check)
+			t_wr_clk++;
+
+		switch (t_wr_clk) {
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+			mmode |= SDRAM_MMODE_WR_DDR2_3_CYC;
+			break;
+		case 4:
+			mmode |= SDRAM_MMODE_WR_DDR2_4_CYC;
+			break;
+		case 5:
+			mmode |= SDRAM_MMODE_WR_DDR2_5_CYC;
+			break;
+		default:
+			mmode |= SDRAM_MMODE_WR_DDR2_6_CYC;
+			break;
+		}
+		*write_recovery = t_wr_clk;
+	}
+
+	debug("CAS latency = %d\n", *selected_cas);
+	debug("Write recovery = %d\n", *write_recovery);
+
+	mtsdram(SDRAM_MMODE, mmode);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_rtr.
+ *-----------------------------------------------------------------------------*/
+static void program_rtr(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks)
+{
+	PPC4xx_SYS_INFO board_cfg;
+	unsigned long max_refresh_rate;
+	unsigned long dimm_num;
+	unsigned long refresh_rate_type;
+	unsigned long refresh_rate;
+	unsigned long rint;
+	unsigned long sdram_freq;
+	unsigned long sdr_ddrpll;
+	unsigned long val;
+
+	/*------------------------------------------------------------------
+	 * Get the board configuration info.
+	 *-----------------------------------------------------------------*/
+	get_sys_info(&board_cfg);
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Refresh Timing Register, SDRAM_RTR
+	 *-----------------------------------------------------------------*/
+	mfsdr(SDR0_DDR0, sdr_ddrpll);
+	sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+	max_refresh_rate = 0;
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+
+			refresh_rate_type = spd_read(iic0_dimm_addr[dimm_num], 12);
+			refresh_rate_type &= 0x7F;
+			switch (refresh_rate_type) {
+			case 0:
+				refresh_rate =  15625;
+				break;
+			case 1:
+				refresh_rate =   3906;
+				break;
+			case 2:
+				refresh_rate =   7812;
+				break;
+			case 3:
+				refresh_rate =  31250;
+				break;
+			case 4:
+				refresh_rate =  62500;
+				break;
+			case 5:
+				refresh_rate = 125000;
+				break;
+			default:
+				refresh_rate = 0;
+				printf("ERROR: DIMM %d unsupported refresh rate/type.\n",
+				       (unsigned int)dimm_num);
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+				break;
+			}
+
+			max_refresh_rate = max(max_refresh_rate, refresh_rate);
+		}
+	}
+
+	rint = MULDIV64(sdram_freq, max_refresh_rate, ONE_BILLION);
+	mfsdram(SDRAM_RTR, val);
+	mtsdram(SDRAM_RTR, (val & ~SDRAM_RTR_RINT_MASK) |
+		(SDRAM_RTR_RINT_ENCODE(rint)));
+}
+
+/*------------------------------------------------------------------
+ * This routine programs the SDRAM_TRx registers.
+ *-----------------------------------------------------------------*/
+static void program_tr(unsigned long *dimm_populated,
+		       unsigned char *iic0_dimm_addr,
+		       unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long sdram_ddr1;
+	unsigned long t_rp_ns;
+	unsigned long t_rcd_ns;
+	unsigned long t_rrd_ns;
+	unsigned long t_ras_ns;
+	unsigned long t_rc_ns;
+	unsigned long t_rfc_ns;
+	unsigned long t_wpc_ns;
+	unsigned long t_wtr_ns;
+	unsigned long t_rpc_ns;
+	unsigned long t_rp_clk;
+	unsigned long t_rcd_clk;
+	unsigned long t_rrd_clk;
+	unsigned long t_ras_clk;
+	unsigned long t_rc_clk;
+	unsigned long t_rfc_clk;
+	unsigned long t_wpc_clk;
+	unsigned long t_wtr_clk;
+	unsigned long t_rpc_clk;
+	unsigned long sdtr1, sdtr2, sdtr3;
+	unsigned long ddr_check;
+	unsigned long sdram_freq;
+	unsigned long sdr_ddrpll;
+
+	PPC4xx_SYS_INFO board_cfg;
+
+	/*------------------------------------------------------------------
+	 * Get the board configuration info.
+	 *-----------------------------------------------------------------*/
+	get_sys_info(&board_cfg);
+
+	mfsdr(SDR0_DDR0, sdr_ddrpll);
+	sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	t_rp_ns = 0;
+	t_rrd_ns = 0;
+	t_rcd_ns = 0;
+	t_ras_ns = 0;
+	t_rc_ns = 0;
+	t_rfc_ns = 0;
+	t_wpc_ns = 0;
+	t_wtr_ns = 0;
+	t_rpc_ns = 0;
+	sdram_ddr1 = TRUE;
+
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			if (dimm_populated[dimm_num] == SDRAM_DDR2)
+				sdram_ddr1 = TRUE;
+			else
+				sdram_ddr1 = FALSE;
+
+			t_rcd_ns = max(t_rcd_ns, spd_read(iic0_dimm_addr[dimm_num], 29) >> 2);
+			t_rrd_ns = max(t_rrd_ns, spd_read(iic0_dimm_addr[dimm_num], 28) >> 2);
+			t_rp_ns  = max(t_rp_ns,  spd_read(iic0_dimm_addr[dimm_num], 27) >> 2);
+			t_ras_ns = max(t_ras_ns, spd_read(iic0_dimm_addr[dimm_num], 30));
+			t_rc_ns  = max(t_rc_ns,  spd_read(iic0_dimm_addr[dimm_num], 41));
+			t_rfc_ns = max(t_rfc_ns, spd_read(iic0_dimm_addr[dimm_num], 42));
+		}
+	}
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Timing Reg 1, SDRAM_TR1
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_SDTR1, sdtr1);
+	sdtr1 &= ~(SDRAM_SDTR1_LDOF_MASK | SDRAM_SDTR1_RTW_MASK |
+		   SDRAM_SDTR1_WTWO_MASK | SDRAM_SDTR1_RTRO_MASK);
+
+	/* default values */
+	sdtr1 |= SDRAM_SDTR1_LDOF_2_CLK;
+	sdtr1 |= SDRAM_SDTR1_RTW_2_CLK;
+
+	/* normal operations */
+	sdtr1 |= SDRAM_SDTR1_WTWO_0_CLK;
+	sdtr1 |= SDRAM_SDTR1_RTRO_1_CLK;
+
+	mtsdram(SDRAM_SDTR1, sdtr1);
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Timing Reg 2, SDRAM_TR2
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_SDTR2, sdtr2);
+	sdtr2 &= ~(SDRAM_SDTR2_RCD_MASK  | SDRAM_SDTR2_WTR_MASK |
+		   SDRAM_SDTR2_XSNR_MASK | SDRAM_SDTR2_WPC_MASK |
+		   SDRAM_SDTR2_RPC_MASK  | SDRAM_SDTR2_RP_MASK  |
+		   SDRAM_SDTR2_RRD_MASK);
+
+	/*
+	 * convert t_rcd from nanoseconds to ddr clocks
+	 * round up if necessary
+	 */
+	t_rcd_clk = MULDIV64(sdram_freq, t_rcd_ns, ONE_BILLION);
+	ddr_check = MULDIV64(ONE_BILLION, t_rcd_clk, t_rcd_ns);
+	if (sdram_freq != ddr_check)
+		t_rcd_clk++;
+
+	switch (t_rcd_clk) {
+	case 0:
+	case 1:
+		sdtr2 |= SDRAM_SDTR2_RCD_1_CLK;
+		break;
+	case 2:
+		sdtr2 |= SDRAM_SDTR2_RCD_2_CLK;
+		break;
+	case 3:
+		sdtr2 |= SDRAM_SDTR2_RCD_3_CLK;
+		break;
+	case 4:
+		sdtr2 |= SDRAM_SDTR2_RCD_4_CLK;
+		break;
+	default:
+		sdtr2 |= SDRAM_SDTR2_RCD_5_CLK;
+		break;
+	}
+
+	if (sdram_ddr1 == TRUE) { /* DDR1 */
+		if (sdram_freq < 200000000) {
+			sdtr2 |= SDRAM_SDTR2_WTR_1_CLK;
+			sdtr2 |= SDRAM_SDTR2_WPC_2_CLK;
+			sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+		} else {
+			sdtr2 |= SDRAM_SDTR2_WTR_2_CLK;
+			sdtr2 |= SDRAM_SDTR2_WPC_3_CLK;
+			sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+		}
+	} else { /* DDR2 */
+		/* loop through all the DIMM slots on the board */
+		for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+			/* If a dimm is installed in a particular slot ... */
+			if (dimm_populated[dimm_num] != SDRAM_NONE) {
+				t_wpc_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 36) >> 2);
+				t_wtr_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 37) >> 2);
+				t_rpc_ns = max(t_rpc_ns, spd_read(iic0_dimm_addr[dimm_num], 38) >> 2);
+			}
+		}
+
+		/*
+		 * convert from nanoseconds to ddr clocks
+		 * round up if necessary
+		 */
+		t_wpc_clk = MULDIV64(sdram_freq, t_wpc_ns, ONE_BILLION);
+		ddr_check = MULDIV64(ONE_BILLION, t_wpc_clk, t_wpc_ns);
+		if (sdram_freq != ddr_check)
+			t_wpc_clk++;
+
+		switch (t_wpc_clk) {
+		case 0:
+		case 1:
+		case 2:
+			sdtr2 |= SDRAM_SDTR2_WPC_2_CLK;
+			break;
+		case 3:
+			sdtr2 |= SDRAM_SDTR2_WPC_3_CLK;
+			break;
+		case 4:
+			sdtr2 |= SDRAM_SDTR2_WPC_4_CLK;
+			break;
+		case 5:
+			sdtr2 |= SDRAM_SDTR2_WPC_5_CLK;
+			break;
+		default:
+			sdtr2 |= SDRAM_SDTR2_WPC_6_CLK;
+			break;
+		}
+
+		/*
+		 * convert from nanoseconds to ddr clocks
+		 * round up if necessary
+		 */
+		t_wtr_clk = MULDIV64(sdram_freq, t_wtr_ns, ONE_BILLION);
+		ddr_check = MULDIV64(ONE_BILLION, t_wtr_clk, t_wtr_ns);
+		if (sdram_freq != ddr_check)
+			t_wtr_clk++;
+
+		switch (t_wtr_clk) {
+		case 0:
+		case 1:
+			sdtr2 |= SDRAM_SDTR2_WTR_1_CLK;
+			break;
+		case 2:
+			sdtr2 |= SDRAM_SDTR2_WTR_2_CLK;
+			break;
+		case 3:
+			sdtr2 |= SDRAM_SDTR2_WTR_3_CLK;
+			break;
+		default:
+			sdtr2 |= SDRAM_SDTR2_WTR_4_CLK;
+			break;
+		}
+
+		/*
+		 * convert from nanoseconds to ddr clocks
+		 * round up if necessary
+		 */
+		t_rpc_clk = MULDIV64(sdram_freq, t_rpc_ns, ONE_BILLION);
+		ddr_check = MULDIV64(ONE_BILLION, t_rpc_clk, t_rpc_ns);
+		if (sdram_freq != ddr_check)
+			t_rpc_clk++;
+
+		switch (t_rpc_clk) {
+		case 0:
+		case 1:
+		case 2:
+			sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+			break;
+		case 3:
+			sdtr2 |= SDRAM_SDTR2_RPC_3_CLK;
+			break;
+		default:
+			sdtr2 |= SDRAM_SDTR2_RPC_4_CLK;
+			break;
+		}
+	}
+
+	/* default value */
+	sdtr2 |= SDRAM_SDTR2_XSNR_16_CLK;
+
+	/*
+	 * convert t_rrd from nanoseconds to ddr clocks
+	 * round up if necessary
+	 */
+	t_rrd_clk = MULDIV64(sdram_freq, t_rrd_ns, ONE_BILLION);
+	ddr_check = MULDIV64(ONE_BILLION, t_rrd_clk, t_rrd_ns);
+	if (sdram_freq != ddr_check)
+		t_rrd_clk++;
+
+	if (t_rrd_clk == 3)
+		sdtr2 |= SDRAM_SDTR2_RRD_3_CLK;
+	else
+		sdtr2 |= SDRAM_SDTR2_RRD_2_CLK;
+
+	/*
+	 * convert t_rp from nanoseconds to ddr clocks
+	 * round up if necessary
+	 */
+	t_rp_clk = MULDIV64(sdram_freq, t_rp_ns, ONE_BILLION);
+	ddr_check = MULDIV64(ONE_BILLION, t_rp_clk, t_rp_ns);
+	if (sdram_freq != ddr_check)
+		t_rp_clk++;
+
+	switch (t_rp_clk) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		sdtr2 |= SDRAM_SDTR2_RP_3_CLK;
+		break;
+	case 4:
+		sdtr2 |= SDRAM_SDTR2_RP_4_CLK;
+		break;
+	case 5:
+		sdtr2 |= SDRAM_SDTR2_RP_5_CLK;
+		break;
+	case 6:
+		sdtr2 |= SDRAM_SDTR2_RP_6_CLK;
+		break;
+	default:
+		sdtr2 |= SDRAM_SDTR2_RP_7_CLK;
+		break;
+	}
+
+	mtsdram(SDRAM_SDTR2, sdtr2);
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM Timing Reg 3, SDRAM_TR3
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_SDTR3, sdtr3);
+	sdtr3 &= ~(SDRAM_SDTR3_RAS_MASK  | SDRAM_SDTR3_RC_MASK |
+		   SDRAM_SDTR3_XCS_MASK | SDRAM_SDTR3_RFC_MASK);
+
+	/*
+	 * convert t_ras from nanoseconds to ddr clocks
+	 * round up if necessary
+	 */
+	t_ras_clk = MULDIV64(sdram_freq, t_ras_ns, ONE_BILLION);
+	ddr_check = MULDIV64(ONE_BILLION, t_ras_clk, t_ras_ns);
+	if (sdram_freq != ddr_check)
+		t_ras_clk++;
+
+	sdtr3 |= SDRAM_SDTR3_RAS_ENCODE(t_ras_clk);
+
+	/*
+	 * convert t_rc from nanoseconds to ddr clocks
+	 * round up if necessary
+	 */
+	t_rc_clk = MULDIV64(sdram_freq, t_rc_ns, ONE_BILLION);
+	ddr_check = MULDIV64(ONE_BILLION, t_rc_clk, t_rc_ns);
+	if (sdram_freq != ddr_check)
+		t_rc_clk++;
+
+	sdtr3 |= SDRAM_SDTR3_RC_ENCODE(t_rc_clk);
+
+	/* default xcs value */
+	sdtr3 |= SDRAM_SDTR3_XCS;
+
+	/*
+	 * convert t_rfc from nanoseconds to ddr clocks
+	 * round up if necessary
+	 */
+	t_rfc_clk = MULDIV64(sdram_freq, t_rfc_ns, ONE_BILLION);
+	ddr_check = MULDIV64(ONE_BILLION, t_rfc_clk, t_rfc_ns);
+	if (sdram_freq != ddr_check)
+		t_rfc_clk++;
+
+	sdtr3 |= SDRAM_SDTR3_RFC_ENCODE(t_rfc_clk);
+
+	mtsdram(SDRAM_SDTR3, sdtr3);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_bxcf.
+ *-----------------------------------------------------------------------------*/
+static void program_bxcf(unsigned long *dimm_populated,
+			 unsigned char *iic0_dimm_addr,
+			 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long num_col_addr;
+	unsigned long num_ranks;
+	unsigned long num_banks;
+	unsigned long mode;
+	unsigned long ind_rank;
+	unsigned long ind;
+	unsigned long ind_bank;
+	unsigned long bank_0_populated;
+
+	/*------------------------------------------------------------------
+	 * Set the BxCF regs.  First, wipe out the bank config registers.
+	 *-----------------------------------------------------------------*/
+	mtsdram(SDRAM_MB0CF, 0x00000000);
+	mtsdram(SDRAM_MB1CF, 0x00000000);
+	mtsdram(SDRAM_MB2CF, 0x00000000);
+	mtsdram(SDRAM_MB3CF, 0x00000000);
+
+	mode = SDRAM_BXCF_M_BE_ENABLE;
+
+	bank_0_populated = 0;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
+			num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5);
+			if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+				num_ranks = (num_ranks & 0x0F) +1;
+			else
+				num_ranks = num_ranks & 0x0F;
+
+			num_banks = spd_read(iic0_dimm_addr[dimm_num], 17);
+
+			for (ind_bank = 0; ind_bank < 2; ind_bank++) {
+				if (num_banks == 4)
+					ind = 0;
+				else
+					ind = 5 << 8;
+				switch (num_col_addr) {
+				case 0x08:
+					mode |= (SDRAM_BXCF_M_AM_0 + ind);
+					break;
+				case 0x09:
+					mode |= (SDRAM_BXCF_M_AM_1 + ind);
+					break;
+				case 0x0A:
+					mode |= (SDRAM_BXCF_M_AM_2 + ind);
+					break;
+				case 0x0B:
+					mode |= (SDRAM_BXCF_M_AM_3 + ind);
+					break;
+				case 0x0C:
+					mode |= (SDRAM_BXCF_M_AM_4 + ind);
+					break;
+				default:
+					printf("DDR-SDRAM: DIMM %d BxCF configuration.\n",
+					       (unsigned int)dimm_num);
+					printf("ERROR: Unsupported value for number of "
+					       "column addresses: %d.\n", (unsigned int)num_col_addr);
+					printf("Replace the DIMM module with a supported DIMM.\n\n");
+					spd_ddr_init_hang ();
+				}
+			}
+
+			if ((dimm_populated[dimm_num] != SDRAM_NONE)&& (dimm_num ==1))
+				bank_0_populated = 1;
+
+			for (ind_rank = 0; ind_rank < num_ranks; ind_rank++) {
+				mtsdram(SDRAM_MB0CF +
+					((dimm_num + bank_0_populated + ind_rank) << 2),
+					mode);
+			}
+		}
+	}
+}
+
+/*------------------------------------------------------------------
+ * program memory queue.
+ *-----------------------------------------------------------------*/
+static void program_memory_queue(unsigned long *dimm_populated,
+				 unsigned char *iic0_dimm_addr,
+				 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	phys_size_t rank_base_addr;
+	unsigned long rank_reg;
+	phys_size_t rank_size_bytes;
+	unsigned long rank_size_id;
+	unsigned long num_ranks;
+	unsigned long baseadd_size;
+	unsigned long i;
+	unsigned long bank_0_populated = 0;
+	phys_size_t total_size = 0;
+
+	/*------------------------------------------------------------------
+	 * Reset the rank_base_address.
+	 *-----------------------------------------------------------------*/
+	rank_reg   = SDRAM_R0BAS;
+
+	rank_base_addr = 0x00000000;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_populated[dimm_num] != SDRAM_NONE) {
+			num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5);
+			if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+				num_ranks = (num_ranks & 0x0F) + 1;
+			else
+				num_ranks = num_ranks & 0x0F;
+
+			rank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
+
+			/*------------------------------------------------------------------
+			 * Set the sizes
+			 *-----------------------------------------------------------------*/
+			baseadd_size = 0;
+			switch (rank_size_id) {
+			case 0x01:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_1024;
+				total_size = 1024;
+				break;
+			case 0x02:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_2048;
+				total_size = 2048;
+				break;
+			case 0x04:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_4096;
+				total_size = 4096;
+				break;
+			case 0x08:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_32;
+				total_size = 32;
+				break;
+			case 0x10:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_64;
+				total_size = 64;
+				break;
+			case 0x20:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_128;
+				total_size = 128;
+				break;
+			case 0x40:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_256;
+				total_size = 256;
+				break;
+			case 0x80:
+				baseadd_size |= SDRAM_RXBAS_SDSZ_512;
+				total_size = 512;
+				break;
+			default:
+				printf("DDR-SDRAM: DIMM %d memory queue configuration.\n",
+				       (unsigned int)dimm_num);
+				printf("ERROR: Unsupported value for the banksize: %d.\n",
+				       (unsigned int)rank_size_id);
+				printf("Replace the DIMM module with a supported DIMM.\n\n");
+				spd_ddr_init_hang ();
+			}
+			rank_size_bytes = total_size << 20;
+
+			if ((dimm_populated[dimm_num] != SDRAM_NONE) && (dimm_num == 1))
+				bank_0_populated = 1;
+
+			for (i = 0; i < num_ranks; i++)	{
+				mtdcr_any(rank_reg+i+dimm_num+bank_0_populated,
+					  (SDRAM_RXBAS_SDBA_ENCODE(rank_base_addr) |
+					   baseadd_size));
+				rank_base_addr += rank_size_bytes;
+			}
+		}
+	}
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+    defined(CONFIG_460SX)
+	/*
+	 * Enable high bandwidth access
+	 * This is currently not used, but with this setup
+	 * it is possible to use it later on in e.g. the Linux
+	 * EMAC driver for performance gain.
+	 */
+	mtdcr(SDRAM_PLBADDULL, 0x00000000); /* MQ0_BAUL */
+	mtdcr(SDRAM_PLBADDUHB, 0x00000008); /* MQ0_BAUH */
+
+	/*
+	 * Set optimal value for Memory Queue HB/LL Configuration registers
+	 */
+	mtdcr(SDRAM_CONF1HB, (mfdcr(SDRAM_CONF1HB) & ~SDRAM_CONF1HB_MASK) |
+	      SDRAM_CONF1HB_AAFR | SDRAM_CONF1HB_RPEN | SDRAM_CONF1HB_RFTE |
+	      SDRAM_CONF1HB_RPLM | SDRAM_CONF1HB_WRCL);
+	mtdcr(SDRAM_CONF1LL, (mfdcr(SDRAM_CONF1LL) & ~SDRAM_CONF1LL_MASK) |
+	      SDRAM_CONF1LL_AAFR | SDRAM_CONF1LL_RPEN | SDRAM_CONF1LL_RFTE |
+	      SDRAM_CONF1LL_RPLM);
+	mtdcr(SDRAM_CONFPATHB, mfdcr(SDRAM_CONFPATHB) | SDRAM_CONFPATHB_TPEN);
+#endif
+}
+
+#ifdef CONFIG_DDR_ECC
+/*-----------------------------------------------------------------------------+
+ * program_ecc.
+ *-----------------------------------------------------------------------------*/
+static void program_ecc(unsigned long *dimm_populated,
+			unsigned char *iic0_dimm_addr,
+			unsigned long num_dimm_banks,
+			unsigned long tlb_word2_i_value)
+{
+	unsigned long dimm_num;
+	unsigned long ecc;
+
+	ecc = 0;
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_populated[dimm_num] != SDRAM_NONE)
+			ecc = max(ecc, spd_read(iic0_dimm_addr[dimm_num], 11));
+	}
+	if (ecc == 0)
+		return;
+
+	do_program_ecc(tlb_word2_i_value);
+}
+#endif
+
+#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+/*-----------------------------------------------------------------------------+
+ * program_DQS_calibration.
+ *-----------------------------------------------------------------------------*/
+static void program_DQS_calibration(unsigned long *dimm_populated,
+				    unsigned char *iic0_dimm_addr,
+				    unsigned long num_dimm_banks)
+{
+	unsigned long val;
+
+#ifdef HARD_CODED_DQS /* calibration test with hardvalues */
+	mtsdram(SDRAM_RQDC, 0x80000037);
+	mtsdram(SDRAM_RDCC, 0x40000000);
+	mtsdram(SDRAM_RFDC, 0x000001DF);
+
+	test();
+#else
+	/*------------------------------------------------------------------
+	 * Program RDCC register
+	 * Read sample cycle auto-update enable
+	 *-----------------------------------------------------------------*/
+
+	mfsdram(SDRAM_RDCC, val);
+	mtsdram(SDRAM_RDCC,
+		(val & ~(SDRAM_RDCC_RDSS_MASK | SDRAM_RDCC_RSAE_MASK))
+		| SDRAM_RDCC_RSAE_ENABLE);
+
+	/*------------------------------------------------------------------
+	 * Program RQDC register
+	 * Internal DQS delay mechanism enable
+	 *-----------------------------------------------------------------*/
+	mtsdram(SDRAM_RQDC, (SDRAM_RQDC_RQDE_ENABLE|SDRAM_RQDC_RQFD_ENCODE(0x38)));
+
+	/*------------------------------------------------------------------
+	 * Program RFDC register
+	 * Set Feedback Fractional Oversample
+	 * Auto-detect read sample cycle enable
+	 * Set RFOS to 1/4 of memclk cycle (0x3f)
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_RFDC, val);
+	mtsdram(SDRAM_RFDC,
+		(val & ~(SDRAM_RFDC_ARSE_MASK | SDRAM_RFDC_RFOS_MASK |
+			 SDRAM_RFDC_RFFD_MASK))
+		| (SDRAM_RFDC_ARSE_ENABLE | SDRAM_RFDC_RFOS_ENCODE(0x3f) |
+		   SDRAM_RFDC_RFFD_ENCODE(0)));
+
+	DQS_calibration_process();
+#endif
+}
+
+static int short_mem_test(void)
+{
+	u32 *membase;
+	u32 bxcr_num;
+	u32 bxcf;
+	int i;
+	int j;
+	phys_size_t base_addr;
+	u32 test[NUMMEMTESTS][NUMMEMWORDS] = {
+		{0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+		{0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+		{0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+		{0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+		{0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+		{0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+		{0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+		{0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+	int l;
+
+	for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+		mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf);
+
+		/* Banks enabled */
+		if ((bxcf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+			/* Bank is enabled */
+
+			/*
+			 * Only run test on accessable memory (below 2GB)
+			 */
+			base_addr = SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num));
+			if (base_addr >= CONFIG_MAX_MEM_MAPPED)
+				continue;
+
+			/*------------------------------------------------------------------
+			 * Run the short memory test.
+			 *-----------------------------------------------------------------*/
+			membase = (u32 *)(u32)base_addr;
+
+			for (i = 0; i < NUMMEMTESTS; i++) {
+				for (j = 0; j < NUMMEMWORDS; j++) {
+					membase[j] = test[i][j];
+					ppcDcbf((u32)&(membase[j]));
+				}
+				sync();
+				for (l=0; l<NUMLOOPS; l++) {
+					for (j = 0; j < NUMMEMWORDS; j++) {
+						if (membase[j] != test[i][j]) {
+							ppcDcbf((u32)&(membase[j]));
+							return 0;
+						}
+						ppcDcbf((u32)&(membase[j]));
+					}
+					sync();
+				}
+			}
+		}	/* if bank enabled */
+	}		/* for bxcf_num */
+
+	return 1;
+}
+
+#ifndef HARD_CODED_DQS
+/*-----------------------------------------------------------------------------+
+ * DQS_calibration_process.
+ *-----------------------------------------------------------------------------*/
+static void DQS_calibration_process(void)
+{
+	unsigned long rfdc_reg;
+	unsigned long rffd;
+	unsigned long val;
+	long rffd_average;
+	long max_start;
+	long min_end;
+	unsigned long begin_rqfd[MAXRANKS];
+	unsigned long begin_rffd[MAXRANKS];
+	unsigned long end_rqfd[MAXRANKS];
+	unsigned long end_rffd[MAXRANKS];
+	char window_found;
+	unsigned long dlycal;
+	unsigned long dly_val;
+	unsigned long max_pass_length;
+	unsigned long current_pass_length;
+	unsigned long current_fail_length;
+	unsigned long current_start;
+	long max_end;
+	unsigned char fail_found;
+	unsigned char pass_found;
+#if !defined(CONFIG_DDR_RQDC_FIXED)
+	u32 rqdc_reg;
+	u32 rqfd;
+	u32 rqfd_start;
+	u32 rqfd_average;
+	int loopi = 0;
+	char str[] = "Auto calibration -";
+	char slash[] = "\\|/-\\|/-";
+
+	/*------------------------------------------------------------------
+	 * Test to determine the best read clock delay tuning bits.
+	 *
+	 * Before the DDR controller can be used, the read clock delay needs to be
+	 * set.  This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+	 * This value cannot be hardcoded into the program because it changes
+	 * depending on the board's setup and environment.
+	 * To do this, all delay values are tested to see if they
+	 * work or not.  By doing this, you get groups of fails with groups of
+	 * passing values.  The idea is to find the start and end of a passing
+	 * window and take the center of it to use as the read clock delay.
+	 *
+	 * A failure has to be seen first so that when we hit a pass, we know
+	 * that it is truely the start of the window.  If we get passing values
+	 * to start off with, we don't know if we are at the start of the window.
+	 *
+	 * The code assumes that a failure will always be found.
+	 * If a failure is not found, there is no easy way to get the middle
+	 * of the passing window.  I guess we can pretty much pick any value
+	 * but some values will be better than others.  Since the lowest speed
+	 * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+	 * from experimentation it is safe to say you will always have a failure.
+	 *-----------------------------------------------------------------*/
+
+	/* first fix RQDC[RQFD] to an average of 80 degre phase shift to find RFDC[RFFD] */
+	rqfd_start = 64; /* test-only: don't know if this is the _best_ start value */
+
+	puts(str);
+
+calibration_loop:
+	mfsdram(SDRAM_RQDC, rqdc_reg);
+	mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+		SDRAM_RQDC_RQFD_ENCODE(rqfd_start));
+#else /* CONFIG_DDR_RQDC_FIXED */
+	/*
+	 * On Katmai the complete auto-calibration somehow doesn't seem to
+	 * produce the best results, meaning optimal values for RQFD/RFFD.
+	 * This was discovered by GDA using a high bandwidth scope,
+	 * analyzing the DDR2 signals. GDA provided a fixed value for RQFD,
+	 * so now on Katmai "only" RFFD is auto-calibrated.
+	 */
+	mtsdram(SDRAM_RQDC, CONFIG_DDR_RQDC_FIXED);
+#endif /* CONFIG_DDR_RQDC_FIXED */
+
+	max_start = 0;
+	min_end = 0;
+	begin_rqfd[0] = 0;
+	begin_rffd[0] = 0;
+	begin_rqfd[1] = 0;
+	begin_rffd[1] = 0;
+	end_rqfd[0] = 0;
+	end_rffd[0] = 0;
+	end_rqfd[1] = 0;
+	end_rffd[1] = 0;
+	window_found = FALSE;
+
+	max_pass_length = 0;
+	max_start = 0;
+	max_end = 0;
+	current_pass_length = 0;
+	current_fail_length = 0;
+	current_start = 0;
+	window_found = FALSE;
+	fail_found = FALSE;
+	pass_found = FALSE;
+
+	/*
+	 * get the delay line calibration register value
+	 */
+	mfsdram(SDRAM_DLCR, dlycal);
+	dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
+
+	for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+		mfsdram(SDRAM_RFDC, rfdc_reg);
+		rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+
+		/*------------------------------------------------------------------
+		 * Set the timing reg for the test.
+		 *-----------------------------------------------------------------*/
+		mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+		/*------------------------------------------------------------------
+		 * See if the rffd value passed.
+		 *-----------------------------------------------------------------*/
+		if (short_mem_test()) {
+			if (fail_found == TRUE) {
+				pass_found = TRUE;
+				if (current_pass_length == 0)
+					current_start = rffd;
+
+				current_fail_length = 0;
+				current_pass_length++;
+
+				if (current_pass_length > max_pass_length) {
+					max_pass_length = current_pass_length;
+					max_start = current_start;
+					max_end = rffd;
+				}
+			}
+		} else {
+			current_pass_length = 0;
+			current_fail_length++;
+
+			if (current_fail_length >= (dly_val >> 2)) {
+				if (fail_found == FALSE) {
+					fail_found = TRUE;
+				} else if (pass_found == TRUE) {
+					window_found = TRUE;
+					break;
+				}
+			}
+		}
+	}		/* for rffd */
+
+	/*------------------------------------------------------------------
+	 * Set the average RFFD value
+	 *-----------------------------------------------------------------*/
+	rffd_average = ((max_start + max_end) >> 1);
+
+	if (rffd_average < 0)
+		rffd_average = 0;
+
+	if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+		rffd_average = SDRAM_RFDC_RFFD_MAX;
+	/* now fix RFDC[RFFD] found and find RQDC[RQFD] */
+	mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+
+#if !defined(CONFIG_DDR_RQDC_FIXED)
+	max_pass_length = 0;
+	max_start = 0;
+	max_end = 0;
+	current_pass_length = 0;
+	current_fail_length = 0;
+	current_start = 0;
+	window_found = FALSE;
+	fail_found = FALSE;
+	pass_found = FALSE;
+
+	for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+		mfsdram(SDRAM_RQDC, rqdc_reg);
+		rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+
+		/*------------------------------------------------------------------
+		 * Set the timing reg for the test.
+		 *-----------------------------------------------------------------*/
+		mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+		/*------------------------------------------------------------------
+		 * See if the rffd value passed.
+		 *-----------------------------------------------------------------*/
+		if (short_mem_test()) {
+			if (fail_found == TRUE) {
+				pass_found = TRUE;
+				if (current_pass_length == 0)
+					current_start = rqfd;
+
+				current_fail_length = 0;
+				current_pass_length++;
+
+				if (current_pass_length > max_pass_length) {
+					max_pass_length = current_pass_length;
+					max_start = current_start;
+					max_end = rqfd;
+				}
+			}
+		} else {
+			current_pass_length = 0;
+			current_fail_length++;
+
+			if (fail_found == FALSE) {
+				fail_found = TRUE;
+			} else if (pass_found == TRUE) {
+				window_found = TRUE;
+				break;
+			}
+		}
+	}
+
+	rqfd_average = ((max_start + max_end) >> 1);
+
+	/*------------------------------------------------------------------
+	 * Make sure we found the valid read passing window.  Halt if not
+	 *-----------------------------------------------------------------*/
+	if (window_found == FALSE) {
+		if (rqfd_start < SDRAM_RQDC_RQFD_MAX) {
+			putc('\b');
+			putc(slash[loopi++ % 8]);
+
+			/* try again from with a different RQFD start value */
+			rqfd_start++;
+			goto calibration_loop;
+		}
+
+		printf("\nERROR: Cannot determine a common read delay for the "
+		       "DIMM(s) installed.\n");
+		debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__);
+		ppc4xx_ibm_ddr2_register_dump();
+		spd_ddr_init_hang ();
+	}
+
+	if (rqfd_average < 0)
+		rqfd_average = 0;
+
+	if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+		rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+	mtsdram(SDRAM_RQDC,
+		(rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+		SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+	blank_string(strlen(str));
+#endif /* CONFIG_DDR_RQDC_FIXED */
+
+	/*
+	 * Now complete RDSS configuration as mentioned on page 7 of the AMCC
+	 * PowerPC440SP/SPe DDR2 application note:
+	 * "DDR1/DDR2 Initialization Sequence and Dynamic Tuning"
+	 */
+	mfsdram(SDRAM_RTSR, val);
+	if ((val & SDRAM_RTSR_TRK1SM_MASK) == SDRAM_RTSR_TRK1SM_ATPLS1) {
+		mfsdram(SDRAM_RDCC, val);
+		if ((val & SDRAM_RDCC_RDSS_MASK) != SDRAM_RDCC_RDSS_T4) {
+			val += 0x40000000;
+			mtsdram(SDRAM_RDCC, val);
+		}
+	}
+
+	mfsdram(SDRAM_DLCR, val);
+	debug("%s[%d] DLCR: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+	mfsdram(SDRAM_RQDC, val);
+	debug("%s[%d] RQDC: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+	mfsdram(SDRAM_RFDC, val);
+	debug("%s[%d] RFDC: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+	mfsdram(SDRAM_RDCC, val);
+	debug("%s[%d] RDCC: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+}
+#else /* calibration test with hardvalues */
+/*-----------------------------------------------------------------------------+
+ * DQS_calibration_process.
+ *-----------------------------------------------------------------------------*/
+static void test(void)
+{
+	unsigned long dimm_num;
+	unsigned long ecc_temp;
+	unsigned long i, j;
+	unsigned long *membase;
+	unsigned long bxcf[MAXRANKS];
+	unsigned long val;
+	char window_found;
+	char begin_found[MAXDIMMS];
+	char end_found[MAXDIMMS];
+	char search_end[MAXDIMMS];
+	unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
+		{0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+		{0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+		{0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+		{0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+		{0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+		{0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+		{0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+		{0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+
+	/*------------------------------------------------------------------
+	 * Test to determine the best read clock delay tuning bits.
+	 *
+	 * Before the DDR controller can be used, the read clock delay needs to be
+	 * set.  This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+	 * This value cannot be hardcoded into the program because it changes
+	 * depending on the board's setup and environment.
+	 * To do this, all delay values are tested to see if they
+	 * work or not.  By doing this, you get groups of fails with groups of
+	 * passing values.  The idea is to find the start and end of a passing
+	 * window and take the center of it to use as the read clock delay.
+	 *
+	 * A failure has to be seen first so that when we hit a pass, we know
+	 * that it is truely the start of the window.  If we get passing values
+	 * to start off with, we don't know if we are at the start of the window.
+	 *
+	 * The code assumes that a failure will always be found.
+	 * If a failure is not found, there is no easy way to get the middle
+	 * of the passing window.  I guess we can pretty much pick any value
+	 * but some values will be better than others.  Since the lowest speed
+	 * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+	 * from experimentation it is safe to say you will always have a failure.
+	 *-----------------------------------------------------------------*/
+	mfsdram(SDRAM_MCOPT1, ecc_temp);
+	ecc_temp &= SDRAM_MCOPT1_MCHK_MASK;
+	mfsdram(SDRAM_MCOPT1, val);
+	mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) |
+		SDRAM_MCOPT1_MCHK_NON);
+
+	window_found = FALSE;
+	begin_found[0] = FALSE;
+	end_found[0] = FALSE;
+	search_end[0] = FALSE;
+	begin_found[1] = FALSE;
+	end_found[1] = FALSE;
+	search_end[1] = FALSE;
+
+	for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+		mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf[bxcr_num]);
+
+		/* Banks enabled */
+		if ((bxcf[dimm_num] & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+
+			/* Bank is enabled */
+			membase =
+				(unsigned long*)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+dimm_num)));
+
+			/*------------------------------------------------------------------
+			 * Run the short memory test.
+			 *-----------------------------------------------------------------*/
+			for (i = 0; i < NUMMEMTESTS; i++) {
+				for (j = 0; j < NUMMEMWORDS; j++) {
+					membase[j] = test[i][j];
+					ppcDcbf((u32)&(membase[j]));
+				}
+				sync();
+				for (j = 0; j < NUMMEMWORDS; j++) {
+					if (membase[j] != test[i][j]) {
+						ppcDcbf((u32)&(membase[j]));
+						break;
+					}
+					ppcDcbf((u32)&(membase[j]));
+				}
+				sync();
+				if (j < NUMMEMWORDS)
+					break;
+			}
+
+			/*------------------------------------------------------------------
+			 * See if the rffd value passed.
+			 *-----------------------------------------------------------------*/
+			if (i < NUMMEMTESTS) {
+				if ((end_found[dimm_num] == FALSE) &&
+				    (search_end[dimm_num] == TRUE)) {
+					end_found[dimm_num] = TRUE;
+				}
+				if ((end_found[0] == TRUE) &&
+				    (end_found[1] == TRUE))
+					break;
+			} else {
+				if (begin_found[dimm_num] == FALSE) {
+					begin_found[dimm_num] = TRUE;
+					search_end[dimm_num] = TRUE;
+				}
+			}
+		} else {
+			begin_found[dimm_num] = TRUE;
+			end_found[dimm_num] = TRUE;
+		}
+	}
+
+	if ((begin_found[0] == TRUE) && (begin_found[1] == TRUE))
+		window_found = TRUE;
+
+	/*------------------------------------------------------------------
+	 * Make sure we found the valid read passing window.  Halt if not
+	 *-----------------------------------------------------------------*/
+	if (window_found == FALSE) {
+		printf("ERROR: Cannot determine a common read delay for the "
+		       "DIMM(s) installed.\n");
+		spd_ddr_init_hang ();
+	}
+
+	/*------------------------------------------------------------------
+	 * Restore the ECC variable to what it originally was
+	 *-----------------------------------------------------------------*/
+	mtsdram(SDRAM_MCOPT1,
+		(ppcMfdcr_sdram(SDRAM_MCOPT1) & ~SDRAM_MCOPT1_MCHK_MASK)
+		| ecc_temp);
+}
+#endif /* !HARD_CODED_DQS */
+#endif /* !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION) */
+
+#else /* CONFIG_SPD_EEPROM */
+
+/*-----------------------------------------------------------------------------
+ * Function:	initdram
+ * Description: Configures the PPC4xx IBM DDR1/DDR2 SDRAM memory controller.
+ * 		The configuration is performed using static, compile-
+ *		time parameters.
+ * 		Configures the PPC405EX(r) and PPC460EX/GT
+ *---------------------------------------------------------------------------*/
+phys_size_t initdram(int board_type)
+{
+	/*
+	 * Only run this SDRAM init code once. For NAND booting
+	 * targets like Kilauea, we call initdram() early from the
+	 * 4k NAND booting image (CONFIG_NAND_SPL) from nand_boot().
+	 * Later on the NAND U-Boot image runs (CONFIG_NAND_U_BOOT)
+	 * which calls initdram() again. This time the controller
+	 * mustn't be reconfigured again since we're already running
+	 * from SDRAM.
+	 */
+#if !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL)
+	unsigned long val;
+
+#if defined(CONFIG_440)
+	mtdcr(SDRAM_R0BAS,	CONFIG_SYS_SDRAM_R0BAS);
+	mtdcr(SDRAM_R1BAS,	CONFIG_SYS_SDRAM_R1BAS);
+	mtdcr(SDRAM_R2BAS,	CONFIG_SYS_SDRAM_R2BAS);
+	mtdcr(SDRAM_R3BAS,	CONFIG_SYS_SDRAM_R3BAS);
+	mtdcr(SDRAM_PLBADDULL,	CONFIG_SYS_SDRAM_PLBADDULL);	/* MQ0_BAUL */
+	mtdcr(SDRAM_PLBADDUHB,	CONFIG_SYS_SDRAM_PLBADDUHB);	/* MQ0_BAUH */
+	mtdcr(SDRAM_CONF1LL,	CONFIG_SYS_SDRAM_CONF1LL);
+	mtdcr(SDRAM_CONF1HB,	CONFIG_SYS_SDRAM_CONF1HB);
+	mtdcr(SDRAM_CONFPATHB,	CONFIG_SYS_SDRAM_CONFPATHB);
+#endif
+
+	/* Set Memory Bank Configuration Registers */
+
+	mtsdram(SDRAM_MB0CF, CONFIG_SYS_SDRAM0_MB0CF);
+	mtsdram(SDRAM_MB1CF, CONFIG_SYS_SDRAM0_MB1CF);
+	mtsdram(SDRAM_MB2CF, CONFIG_SYS_SDRAM0_MB2CF);
+	mtsdram(SDRAM_MB3CF, CONFIG_SYS_SDRAM0_MB3CF);
+
+	/* Set Memory Clock Timing Register */
+
+	mtsdram(SDRAM_CLKTR, CONFIG_SYS_SDRAM0_CLKTR);
+
+	/* Set Refresh Time Register */
+
+	mtsdram(SDRAM_RTR, CONFIG_SYS_SDRAM0_RTR);
+
+	/* Set SDRAM Timing Registers */
+
+	mtsdram(SDRAM_SDTR1, CONFIG_SYS_SDRAM0_SDTR1);
+	mtsdram(SDRAM_SDTR2, CONFIG_SYS_SDRAM0_SDTR2);
+	mtsdram(SDRAM_SDTR3, CONFIG_SYS_SDRAM0_SDTR3);
+
+	/* Set Mode and Extended Mode Registers */
+
+	mtsdram(SDRAM_MMODE, CONFIG_SYS_SDRAM0_MMODE);
+	mtsdram(SDRAM_MEMODE, CONFIG_SYS_SDRAM0_MEMODE);
+
+	/* Set Memory Controller Options 1 Register */
+
+	mtsdram(SDRAM_MCOPT1, CONFIG_SYS_SDRAM0_MCOPT1);
+
+	/* Set Manual Initialization Control Registers */
+
+	mtsdram(SDRAM_INITPLR0, CONFIG_SYS_SDRAM0_INITPLR0);
+	mtsdram(SDRAM_INITPLR1, CONFIG_SYS_SDRAM0_INITPLR1);
+	mtsdram(SDRAM_INITPLR2, CONFIG_SYS_SDRAM0_INITPLR2);
+	mtsdram(SDRAM_INITPLR3, CONFIG_SYS_SDRAM0_INITPLR3);
+	mtsdram(SDRAM_INITPLR4, CONFIG_SYS_SDRAM0_INITPLR4);
+	mtsdram(SDRAM_INITPLR5, CONFIG_SYS_SDRAM0_INITPLR5);
+	mtsdram(SDRAM_INITPLR6, CONFIG_SYS_SDRAM0_INITPLR6);
+	mtsdram(SDRAM_INITPLR7, CONFIG_SYS_SDRAM0_INITPLR7);
+	mtsdram(SDRAM_INITPLR8, CONFIG_SYS_SDRAM0_INITPLR8);
+	mtsdram(SDRAM_INITPLR9, CONFIG_SYS_SDRAM0_INITPLR9);
+	mtsdram(SDRAM_INITPLR10, CONFIG_SYS_SDRAM0_INITPLR10);
+	mtsdram(SDRAM_INITPLR11, CONFIG_SYS_SDRAM0_INITPLR11);
+	mtsdram(SDRAM_INITPLR12, CONFIG_SYS_SDRAM0_INITPLR12);
+	mtsdram(SDRAM_INITPLR13, CONFIG_SYS_SDRAM0_INITPLR13);
+	mtsdram(SDRAM_INITPLR14, CONFIG_SYS_SDRAM0_INITPLR14);
+	mtsdram(SDRAM_INITPLR15, CONFIG_SYS_SDRAM0_INITPLR15);
+
+	/* Set On-Die Termination Registers */
+
+	mtsdram(SDRAM_CODT, CONFIG_SYS_SDRAM0_CODT);
+	mtsdram(SDRAM_MODT0, CONFIG_SYS_SDRAM0_MODT0);
+	mtsdram(SDRAM_MODT1, CONFIG_SYS_SDRAM0_MODT1);
+
+	/* Set Write Timing Register */
+
+	mtsdram(SDRAM_WRDTR, CONFIG_SYS_SDRAM0_WRDTR);
+
+	/*
+	 * Start Initialization by SDRAM0_MCOPT2[SREN] = 0 and
+	 * SDRAM0_MCOPT2[IPTR] = 1
+	 */
+
+	mtsdram(SDRAM_MCOPT2, (SDRAM_MCOPT2_SREN_EXIT |
+			       SDRAM_MCOPT2_IPTR_EXECUTE));
+
+	/*
+	 * Poll SDRAM0_MCSTAT[MIC] for assertion to indicate the
+	 * completion of initialization.
+	 */
+
+	do {
+		mfsdram(SDRAM_MCSTAT, val);
+	} while ((val & SDRAM_MCSTAT_MIC_MASK) != SDRAM_MCSTAT_MIC_COMP);
+
+	/* Set Delay Control Registers */
+
+	mtsdram(SDRAM_DLCR, CONFIG_SYS_SDRAM0_DLCR);
+
+#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+	mtsdram(SDRAM_RDCC, CONFIG_SYS_SDRAM0_RDCC);
+	mtsdram(SDRAM_RQDC, CONFIG_SYS_SDRAM0_RQDC);
+	mtsdram(SDRAM_RFDC, CONFIG_SYS_SDRAM0_RFDC);
+#endif /* !CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
+
+	/*
+	 * Enable Controller by SDRAM0_MCOPT2[DCEN] = 1:
+	 */
+
+	mfsdram(SDRAM_MCOPT2, val);
+	mtsdram(SDRAM_MCOPT2, val | SDRAM_MCOPT2_DCEN_ENABLE);
+
+#if defined(CONFIG_440)
+	/*
+	 * Program TLB entries with caches enabled, for best performace
+	 * while auto-calibrating and ECC generation
+	 */
+	program_tlb(0, 0, (CONFIG_SYS_MBYTES_SDRAM << 20), 0);
+#endif
+
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+	/*------------------------------------------------------------------
+	 | DQS calibration.
+	 +-----------------------------------------------------------------*/
+	DQS_autocalibration();
+#endif /* !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) */
+#endif /* CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
+
+#if defined(CONFIG_DDR_ECC)
+	do_program_ecc(0);
+#endif /* defined(CONFIG_DDR_ECC) */
+
+#if defined(CONFIG_440)
+	/*
+	 * Now after initialization (auto-calibration and ECC generation)
+	 * remove the TLB entries with caches enabled and program again with
+	 * desired cache functionality
+	 */
+	remove_tlb(0, (CONFIG_SYS_MBYTES_SDRAM << 20));
+	program_tlb(0, 0, (CONFIG_SYS_MBYTES_SDRAM << 20), MY_TLB_WORD2_I_ENABLE);
+#endif
+
+	ppc4xx_ibm_ddr2_register_dump();
+
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+	/*
+	 * Clear potential errors resulting from auto-calibration.
+	 * If not done, then we could get an interrupt later on when
+	 * exceptions are enabled.
+	 */
+	set_mcsr(get_mcsr());
+#endif /* CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
+
+#endif /* !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) */
+
+	return (CONFIG_SYS_MBYTES_SDRAM << 20);
+}
+#endif /* CONFIG_SPD_EEPROM */
+
+#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+#if defined(CONFIG_440)
+u32 mfdcr_any(u32 dcr)
+{
+	u32 val;
+
+	switch (dcr) {
+	case SDRAM_R0BAS + 0:
+		val = mfdcr(SDRAM_R0BAS + 0);
+		break;
+	case SDRAM_R0BAS + 1:
+		val = mfdcr(SDRAM_R0BAS + 1);
+		break;
+	case SDRAM_R0BAS + 2:
+		val = mfdcr(SDRAM_R0BAS + 2);
+		break;
+	case SDRAM_R0BAS + 3:
+		val = mfdcr(SDRAM_R0BAS + 3);
+		break;
+	default:
+		printf("DCR %d not defined in case statement!!!\n", dcr);
+		val = 0; /* just to satisfy the compiler */
+	}
+
+	return val;
+}
+
+void mtdcr_any(u32 dcr, u32 val)
+{
+	switch (dcr) {
+	case SDRAM_R0BAS + 0:
+		mtdcr(SDRAM_R0BAS + 0, val);
+		break;
+	case SDRAM_R0BAS + 1:
+		mtdcr(SDRAM_R0BAS + 1, val);
+		break;
+	case SDRAM_R0BAS + 2:
+		mtdcr(SDRAM_R0BAS + 2, val);
+		break;
+	case SDRAM_R0BAS + 3:
+		mtdcr(SDRAM_R0BAS + 3, val);
+		break;
+	default:
+		printf("DCR %d not defined in case statement!!!\n", dcr);
+	}
+}
+#endif /* defined(CONFIG_440) */
+#endif /* !defined(CONFIG_NAND_U_BOOT) &&  !defined(CONFIG_NAND_SPL) */
+
+inline void ppc4xx_ibm_ddr2_register_dump(void)
+{
+#if defined(DEBUG)
+	printf("\nPPC4xx IBM DDR2 Register Dump:\n");
+
+#if (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+     defined(CONFIG_460EX) || defined(CONFIG_460GT))
+	PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R0BAS);
+	PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R1BAS);
+	PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R2BAS);
+	PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R3BAS);
+#endif /* (defined(CONFIG_440SP) || ... */
+#if defined(CONFIG_405EX)
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(BESR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(BEARL);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(BEARH);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(WMIRQ);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(PLBOPT);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(PUABA);
+#endif /* defined(CONFIG_405EX) */
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MB0CF);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MB1CF);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MB2CF);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MB3CF);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MCSTAT);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MCOPT1);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MCOPT2);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT0);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT1);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT2);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT3);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(CODT);
+#if (defined(CONFIG_440SP) || defined(CONFIG_440SPE) ||	\
+     defined(CONFIG_460EX) || defined(CONFIG_460GT))
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(VVPR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(OPARS);
+	/*
+	 * OPART is only used as a trigger register.
+	 *
+	 * No data is contained in this register, and reading or writing
+	 * to is can cause bad things to happen (hangs). Just skip it and
+	 * report "N/A".
+	 */
+	printf("%20s = N/A\n", "SDRAM_OPART");
+#endif /* defined(CONFIG_440SP) || ... */
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(RTR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR0);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR1);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR2);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR3);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR4);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR5);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR6);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR7);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR8);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR9);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR10);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR11);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR12);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR13);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR14);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR15);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(RQDC);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(RFDC);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(RDCC);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(DLCR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(CLKTR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(WRDTR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(SDTR1);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(SDTR2);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(SDTR3);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MMODE);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(MEMODE);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(ECCES);
+#if (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+     defined(CONFIG_460EX) || defined(CONFIG_460GT))
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(CID);
+#endif /* defined(CONFIG_440SP) || ... */
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(RID);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(FCSR);
+	PPC4xx_IBM_DDR2_DUMP_REGISTER(RTSR);
+#endif /* defined(DEBUG) */
+}
+
+#endif /* CONFIG_SDRAM_PPC4xx_IBM_DDR2 */
diff --git a/arch/ppc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c b/arch/ppc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
new file mode 100644
index 0000000..7263071
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
@@ -0,0 +1,1251 @@
+/*
+ * arch/ppc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
+ * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a
+ * DDR2 controller (non Denali Core). Those currently are:
+ *
+ * 405:		405EX
+ * 440/460:	440SP/440SPe/460EX/460GT/460SX
+ *
+ * (C) Copyright 2008 Applied Micro Circuits Corporation
+ * Adam Graham  <agraham@amcc.com>
+ *
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT   AMCC   CORPORATION 2004
+ *
+ * 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
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#undef DEBUG
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "ecc.h"
+
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+
+/*
+ * Only compile the DDR auto-calibration code for NOR boot and
+ * not for NAND boot (NAND SPL and NAND U-Boot - NUB)
+ */
+#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+
+#define MAXBXCF			4
+#define SDRAM_RXBAS_SHIFT_1M	20
+
+#if defined(CONFIG_SYS_DECREMENT_PATTERNS)
+#define NUMMEMTESTS		24
+#else
+#define NUMMEMTESTS		8
+#endif /* CONFIG_SYS_DECREMENT_PATTERNS */
+#define NUMLOOPS		1	/* configure as you deem approporiate */
+#define NUMMEMWORDS		16
+
+#define SDRAM_RDCC_RDSS_VAL(n)	SDRAM_RDCC_RDSS_DECODE(ddr_rdss_opt(n))
+
+/* Private Structure Definitions */
+
+struct autocal_regs {
+	u32 rffd;
+	u32 rqfd;
+};
+
+struct ddrautocal {
+	u32 rffd;
+	u32 rffd_min;
+	u32 rffd_max;
+	u32 rffd_size;
+	u32 rqfd;
+	u32 rqfd_size;
+	u32 rdcc;
+	u32 flags;
+};
+
+struct sdram_timing {
+	u32 wrdtr;
+	u32 clktr;
+};
+
+struct sdram_timing_clks {
+	u32 wrdtr;
+	u32 clktr;
+	u32 rdcc;
+	u32 flags;
+};
+
+struct autocal_clks {
+	struct sdram_timing_clks clocks;
+	struct ddrautocal	 autocal;
+};
+
+/*--------------------------------------------------------------------------+
+ * Prototypes
+ *--------------------------------------------------------------------------*/
+#if defined(CONFIG_PPC4xx_DDR_METHOD_A)
+static u32 DQS_calibration_methodA(struct ddrautocal *);
+static u32 program_DQS_calibration_methodA(struct ddrautocal *);
+#else
+static u32 DQS_calibration_methodB(struct ddrautocal *);
+static u32 program_DQS_calibration_methodB(struct ddrautocal *);
+#endif
+static int short_mem_test(u32 *);
+
+/*
+ * To provide an interface for board specific config values in this common
+ * DDR setup code, we implement he "weak" default functions here. They return
+ * the default value back to the caller.
+ *
+ * Please see include/configs/yucca.h for an example fora board specific
+ * implementation.
+ */
+
+#if !defined(CONFIG_SPD_EEPROM)
+u32 __ddr_wrdtr(u32 default_val)
+{
+	return default_val;
+}
+u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr")));
+
+u32 __ddr_clktr(u32 default_val)
+{
+	return default_val;
+}
+u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr")));
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang(void)
+{
+	hang();
+}
+void
+spd_ddr_init_hang(void) __attribute__((weak, alias("__spd_ddr_init_hang")));
+#endif /* defined(CONFIG_SPD_EEPROM) */
+
+ulong __ddr_scan_option(ulong default_val)
+{
+	return default_val;
+}
+ulong ddr_scan_option(ulong) __attribute__((weak, alias("__ddr_scan_option")));
+
+u32 __ddr_rdss_opt(u32 default_val)
+{
+	return default_val;
+}
+u32 ddr_rdss_opt(ulong) __attribute__((weak, alias("__ddr_rdss_opt")));
+
+
+static u32 *get_membase(int bxcr_num)
+{
+	ulong bxcf;
+	u32 *membase;
+
+#if defined(SDRAM_R0BAS)
+	/* BAS from Memory Queue rank reg. */
+	membase =
+	    (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num)));
+	bxcf = 0;	/* just to satisfy the compiler */
+#else
+	/* BAS from SDRAM_MBxCF mem rank reg. */
+	mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+	membase = (u32 *)((bxcf & 0xfff80000) << 3);
+#endif
+
+	return membase;
+}
+
+static inline void ecc_clear_status_reg(void)
+{
+	mtsdram(SDRAM_ECCES, 0xffffffff);
+#if defined(SDRAM_R0BAS)
+	mtdcr(SDRAM_ERRSTATLL, 0xffffffff);
+#endif
+}
+
+/*
+ * Reset and relock memory DLL after SDRAM_CLKTR change
+ */
+static inline void relock_memory_DLL(void)
+{
+	u32 reg;
+
+	mtsdram(SDRAM_MCOPT2, SDRAM_MCOPT2_IPTR_EXECUTE);
+
+	do {
+		mfsdram(SDRAM_MCSTAT, reg);
+	} while (!(reg & SDRAM_MCSTAT_MIC_COMP));
+
+	mfsdram(SDRAM_MCOPT2, reg);
+	mtsdram(SDRAM_MCOPT2, reg | SDRAM_MCOPT2_DCEN_ENABLE);
+}
+
+static int ecc_check_status_reg(void)
+{
+	u32 ecc_status;
+
+	/*
+	 * Compare suceeded, now check
+	 * if got ecc error. If got an
+	 * ecc error, then don't count
+	 * this as a passing value
+	 */
+	mfsdram(SDRAM_ECCES, ecc_status);
+	if (ecc_status != 0x00000000) {
+		/* clear on error */
+		ecc_clear_status_reg();
+		/* ecc check failure */
+		return 0;
+	}
+	ecc_clear_status_reg();
+	sync();
+
+	return 1;
+}
+
+/* return 1 if passes, 0 if fail */
+static int short_mem_test(u32 *base_address)
+{
+	int i, j, l;
+	u32 ecc_mode = 0;
+
+	ulong test[NUMMEMTESTS][NUMMEMWORDS] = {
+	/* 0 */	{0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+	/* 1 */	{0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+	/* 2 */	{0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+	/* 3 */	{0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+	/* 4 */	{0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+	/* 5 */	{0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+	/* 6 */	{0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+	/* 7 */	{0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55},
+
+#if defined(CONFIG_SYS_DECREMENT_PATTERNS)
+	/* 8 */	{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff},
+	/* 9 */	{0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe,
+		 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe,
+		 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe,
+		 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe},
+	/* 10 */{0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd,
+		 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd,
+		 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd,
+		 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd},
+	/* 11 */{0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc,
+		 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc,
+		 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc,
+		 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc},
+	/* 12 */{0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb,
+		 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb,
+		 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb,
+		 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb},
+	/* 13 */{0xfffafffa, 0xfffafffa, 0xfffffffa, 0xfffafffa,
+		 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa,
+		 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa,
+		 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa},
+	/* 14 */{0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9,
+		 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9,
+		 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9,
+		 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9},
+	/* 15 */{0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8,
+		 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8,
+		 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8,
+		 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8},
+	/* 16 */{0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7,
+		 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7,
+		 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7,
+		 0xfff7ffff, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7},
+	/* 17 */{0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7,
+		 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7,
+		 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7,
+		 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7},
+	/* 18 */{0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5,
+		 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5,
+		 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5,
+		 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5},
+	/* 19 */{0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4,
+		 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4,
+		 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4,
+		 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4},
+	/* 20 */{0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3,
+		 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3,
+		 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3,
+		 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3},
+	/* 21 */{0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2,
+		 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2,
+		 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2,
+		 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2},
+	/* 22 */{0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1,
+		 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1,
+		 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1,
+		 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1},
+	/* 23 */{0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0,
+		 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0,
+		 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0,
+		 0xfff0fff0, 0xfff0fffe, 0xfff0fff0, 0xfff0fff0},
+#endif /* CONFIG_SYS_DECREMENT_PATTERNS */
+								 };
+
+	mfsdram(SDRAM_MCOPT1, ecc_mode);
+	if ((ecc_mode & SDRAM_MCOPT1_MCHK_CHK_REP) ==
+						SDRAM_MCOPT1_MCHK_CHK_REP) {
+		ecc_clear_status_reg();
+		sync();
+		ecc_mode = 1;
+	} else {
+		ecc_mode = 0;
+	}
+
+	/*
+	 * Run the short memory test.
+	 */
+	for (i = 0; i < NUMMEMTESTS; i++) {
+		for (j = 0; j < NUMMEMWORDS; j++) {
+			base_address[j] = test[i][j];
+			ppcDcbf((ulong)&(base_address[j]));
+		}
+		sync();
+		iobarrier_rw();
+		for (l = 0; l < NUMLOOPS; l++) {
+			for (j = 0; j < NUMMEMWORDS; j++) {
+				if (base_address[j] != test[i][j]) {
+					ppcDcbf((u32)&(base_address[j]));
+					return 0;
+				} else {
+					if (ecc_mode) {
+						if (!ecc_check_status_reg())
+							return 0;
+					}
+				}
+				ppcDcbf((u32)&(base_address[j]));
+			} /* for (j = 0; j < NUMMEMWORDS; j++) */
+			sync();
+			iobarrier_rw();
+		} /* for (l=0; l<NUMLOOPS; l++) */
+	}
+
+	return 1;
+}
+
+#if defined(CONFIG_PPC4xx_DDR_METHOD_A)
+/*-----------------------------------------------------------------------------+
+| program_DQS_calibration_methodA.
++-----------------------------------------------------------------------------*/
+static u32 program_DQS_calibration_methodA(struct ddrautocal *ddrcal)
+{
+	u32 pass_result = 0;
+
+#ifdef DEBUG
+	ulong temp;
+
+	mfsdram(SDRAM_RDCC, temp);
+	debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp);
+#endif
+
+	pass_result = DQS_calibration_methodA(ddrcal);
+
+	return pass_result;
+}
+
+/*
+ * DQS_calibration_methodA()
+ *
+ * Autocalibration Method A
+ *
+ *  ARRAY [Entire DQS Range] DQS_Valid_Window ;    initialized to all zeros
+ *  ARRAY [Entire FDBK Range] FDBK_Valid_Window;   initialized to all zeros
+ *  MEMWRITE(addr, expected_data);
+ *  for (i = 0; i < Entire DQS Range; i++) {       RQDC.RQFD
+ *      for (j = 0; j < Entire FDBK Range; j++) {  RFDC.RFFD
+ *         MEMREAD(addr, actual_data);
+ *         if (actual_data == expected_data) {
+ *             DQS_Valid_Window[i] = 1;            RQDC.RQFD
+ *             FDBK_Valid_Window[i][j] = 1;        RFDC.RFFD
+ *         }
+ *      }
+ *  }
+ */
+static u32 DQS_calibration_methodA(struct ddrautocal *cal)
+{
+	ulong rfdc_reg;
+	ulong rffd;
+
+	ulong rqdc_reg;
+	ulong rqfd;
+
+	u32 *membase;
+	ulong bxcf;
+	int rqfd_average;
+	int bxcr_num;
+	int rffd_average;
+	int pass;
+	u32 passed = 0;
+
+	int in_window;
+	struct autocal_regs curr_win_min;
+	struct autocal_regs curr_win_max;
+	struct autocal_regs best_win_min;
+	struct autocal_regs best_win_max;
+	struct autocal_regs loop_win_min;
+	struct autocal_regs loop_win_max;
+
+#ifdef DEBUG
+	ulong temp;
+#endif
+	ulong rdcc;
+
+	char slash[] = "\\|/-\\|/-";
+	int loopi = 0;
+
+	/* start */
+	in_window = 0;
+
+	memset(&curr_win_min, 0, sizeof(curr_win_min));
+	memset(&curr_win_max, 0, sizeof(curr_win_max));
+	memset(&best_win_min, 0, sizeof(best_win_min));
+	memset(&best_win_max, 0, sizeof(best_win_max));
+	memset(&loop_win_min, 0, sizeof(loop_win_min));
+	memset(&loop_win_max, 0, sizeof(loop_win_max));
+
+	rdcc = 0;
+
+	/*
+	 * Program RDCC register
+	 * Read sample cycle auto-update enable
+	 */
+	mtsdram(SDRAM_RDCC,
+		ddr_rdss_opt(SDRAM_RDCC_RDSS_T2) | SDRAM_RDCC_RSAE_ENABLE);
+
+#ifdef DEBUG
+	mfsdram(SDRAM_RDCC, temp);
+	debug("<%s>SDRAM_RDCC=0x%x\n", __func__, temp);
+	mfsdram(SDRAM_RTSR, temp);
+	debug("<%s>SDRAM_RTSR=0x%x\n", __func__, temp);
+	mfsdram(SDRAM_FCSR, temp);
+	debug("<%s>SDRAM_FCSR=0x%x\n", __func__, temp);
+#endif
+
+	/*
+	 * Program RQDC register
+	 * Internal DQS delay mechanism enable
+	 */
+	mtsdram(SDRAM_RQDC,
+		SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x00));
+
+#ifdef DEBUG
+	mfsdram(SDRAM_RQDC, temp);
+	debug("<%s>SDRAM_RQDC=0x%x\n", __func__, temp);
+#endif
+
+	/*
+	 * Program RFDC register
+	 * Set Feedback Fractional Oversample
+	 * Auto-detect read sample cycle enable
+	 */
+	mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE |
+		SDRAM_RFDC_RFOS_ENCODE(0) | SDRAM_RFDC_RFFD_ENCODE(0));
+
+#ifdef DEBUG
+	mfsdram(SDRAM_RFDC, temp);
+	debug("<%s>SDRAM_RFDC=0x%x\n", __func__, temp);
+#endif
+
+	putc(' ');
+	for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+
+		mfsdram(SDRAM_RQDC, rqdc_reg);
+		rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+		mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+		putc('\b');
+		putc(slash[loopi++ % 8]);
+
+		curr_win_min.rffd = 0;
+		curr_win_max.rffd = 0;
+		in_window = 0;
+
+		for (rffd = 0, pass = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+			mfsdram(SDRAM_RFDC, rfdc_reg);
+			rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+			mtsdram(SDRAM_RFDC,
+				    rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+			for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+				mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+
+				/* Banks enabled */
+				if (bxcf & SDRAM_BXCF_M_BE_MASK) {
+					/* Bank is enabled */
+					membase = get_membase(bxcr_num);
+					pass = short_mem_test(membase);
+				} /* if bank enabled */
+			} /* for bxcr_num */
+
+			/* If this value passed update RFFD windows */
+			if (pass && !in_window) { /* at the start of window */
+				in_window = 1;
+				curr_win_min.rffd = curr_win_max.rffd = rffd;
+				curr_win_min.rqfd = curr_win_max.rqfd = rqfd;
+				mfsdram(SDRAM_RDCC, rdcc); /*record this value*/
+			} else if (!pass && in_window) { /* at end of window */
+				in_window = 0;
+			} else if (pass && in_window) { /* within the window */
+				curr_win_max.rffd = rffd;
+				curr_win_max.rqfd = rqfd;
+			}
+			/* else if (!pass && !in_window)
+				skip - no pass, not currently in a window */
+
+			if (in_window) {
+				if ((curr_win_max.rffd - curr_win_min.rffd) >
+				    (best_win_max.rffd - best_win_min.rffd)) {
+					best_win_min.rffd = curr_win_min.rffd;
+					best_win_max.rffd = curr_win_max.rffd;
+
+					best_win_min.rqfd = curr_win_min.rqfd;
+					best_win_max.rqfd = curr_win_max.rqfd;
+					cal->rdcc	  = rdcc;
+				}
+				passed = 1;
+			}
+		} /* RFDC.RFFD */
+
+		/*
+		 * save-off the best window results of the RFDC.RFFD
+		 * for this RQDC.RQFD setting
+		 */
+		/*
+		 * if (just ended RFDC.RFDC loop pass window) >
+		 *	(prior RFDC.RFFD loop pass window)
+		 */
+		if ((best_win_max.rffd - best_win_min.rffd) >
+		    (loop_win_max.rffd - loop_win_min.rffd)) {
+			loop_win_min.rffd = best_win_min.rffd;
+			loop_win_max.rffd = best_win_max.rffd;
+			loop_win_min.rqfd = rqfd;
+			loop_win_max.rqfd = rqfd;
+			debug("RQFD.min 0x%08x, RQFD.max 0x%08x, "
+			      "RFFD.min 0x%08x, RFFD.max 0x%08x\n",
+					loop_win_min.rqfd, loop_win_max.rqfd,
+					loop_win_min.rffd, loop_win_max.rffd);
+		}
+	} /* RQDC.RQFD */
+
+	putc('\b');
+
+	debug("\n");
+
+	if ((loop_win_min.rffd == 0) && (loop_win_max.rffd == 0) &&
+	    (best_win_min.rffd == 0) && (best_win_max.rffd == 0) &&
+	    (best_win_min.rqfd == 0) && (best_win_max.rqfd == 0)) {
+		passed = 0;
+	}
+
+	/*
+	 * Need to program RQDC before RFDC.
+	 */
+	debug("<%s> RQFD Min: 0x%x\n", __func__, loop_win_min.rqfd);
+	debug("<%s> RQFD Max: 0x%x\n", __func__, loop_win_max.rqfd);
+	rqfd_average = loop_win_max.rqfd;
+
+	if (rqfd_average < 0)
+		rqfd_average = 0;
+
+	if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+		rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+	debug("<%s> RFFD average: 0x%08x\n", __func__, rqfd_average);
+	mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+				SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+	debug("<%s> RFFD Min: 0x%08x\n", __func__, loop_win_min.rffd);
+	debug("<%s> RFFD Max: 0x%08x\n", __func__, loop_win_max.rffd);
+	rffd_average = ((loop_win_min.rffd + loop_win_max.rffd) / 2);
+
+	if (rffd_average < 0)
+		rffd_average = 0;
+
+	if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+		rffd_average = SDRAM_RFDC_RFFD_MAX;
+
+	debug("<%s> RFFD average: 0x%08x\n", __func__, rffd_average);
+	mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+
+	/* if something passed, then return the size of the largest window */
+	if (passed != 0) {
+		passed		= loop_win_max.rffd - loop_win_min.rffd;
+		cal->rqfd	= rqfd_average;
+		cal->rffd	= rffd_average;
+		cal->rffd_min	= loop_win_min.rffd;
+		cal->rffd_max	= loop_win_max.rffd;
+	}
+
+	return (u32)passed;
+}
+
+#else	/* !defined(CONFIG_PPC4xx_DDR_METHOD_A) */
+
+/*-----------------------------------------------------------------------------+
+| program_DQS_calibration_methodB.
++-----------------------------------------------------------------------------*/
+static u32 program_DQS_calibration_methodB(struct ddrautocal *ddrcal)
+{
+	u32 pass_result = 0;
+
+#ifdef DEBUG
+	ulong temp;
+#endif
+
+	/*
+	 * Program RDCC register
+	 * Read sample cycle auto-update enable
+	 */
+	mtsdram(SDRAM_RDCC,
+		ddr_rdss_opt(SDRAM_RDCC_RDSS_T2) | SDRAM_RDCC_RSAE_ENABLE);
+
+#ifdef DEBUG
+	mfsdram(SDRAM_RDCC, temp);
+	debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp);
+#endif
+
+	/*
+	 * Program RQDC register
+	 * Internal DQS delay mechanism enable
+	 */
+	mtsdram(SDRAM_RQDC,
+#if defined(CONFIG_DDR_RQDC_START_VAL)
+			SDRAM_RQDC_RQDE_ENABLE |
+			    SDRAM_RQDC_RQFD_ENCODE(CONFIG_DDR_RQDC_START_VAL));
+#else
+			SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x38));
+#endif
+
+#ifdef DEBUG
+	mfsdram(SDRAM_RQDC, temp);
+	debug("<%s>SDRAM_RQDC=0x%08x\n", __func__, temp);
+#endif
+
+	/*
+	 * Program RFDC register
+	 * Set Feedback Fractional Oversample
+	 * Auto-detect read sample cycle enable
+	 */
+	mtsdram(SDRAM_RFDC,	SDRAM_RFDC_ARSE_ENABLE |
+				SDRAM_RFDC_RFOS_ENCODE(0) |
+				SDRAM_RFDC_RFFD_ENCODE(0));
+
+#ifdef DEBUG
+	mfsdram(SDRAM_RFDC, temp);
+	debug("<%s>SDRAM_RFDC=0x%08x\n", __func__, temp);
+#endif
+
+	pass_result = DQS_calibration_methodB(ddrcal);
+
+	return pass_result;
+}
+
+/*
+ * DQS_calibration_methodB()
+ *
+ * Autocalibration Method B
+ *
+ * ARRAY [Entire DQS Range] DQS_Valid_Window ;       initialized to all zeros
+ * ARRAY [Entire Feedback Range] FDBK_Valid_Window;  initialized to all zeros
+ * MEMWRITE(addr, expected_data);
+ * Initialialize the DQS delay to 80 degrees (MCIF0_RRQDC[RQFD]=0x38).
+ *
+ *  for (j = 0; j < Entire Feedback Range; j++) {
+ *      MEMREAD(addr, actual_data);
+ *       if (actual_data == expected_data) {
+ *           FDBK_Valid_Window[j] = 1;
+ *       }
+ * }
+ *
+ * Set MCIF0_RFDC[RFFD] to the middle of the FDBK_Valid_Window.
+ *
+ * for (i = 0; i < Entire DQS Range; i++) {
+ *     MEMREAD(addr, actual_data);
+ *     if (actual_data == expected_data) {
+ *         DQS_Valid_Window[i] = 1;
+ *      }
+ * }
+ *
+ * Set MCIF0_RRQDC[RQFD] to the middle of the DQS_Valid_Window.
+ */
+/*-----------------------------------------------------------------------------+
+| DQS_calibration_methodB.
++-----------------------------------------------------------------------------*/
+static u32 DQS_calibration_methodB(struct ddrautocal *cal)
+{
+	ulong rfdc_reg;
+	ulong rffd;
+
+	ulong rqdc_reg;
+	ulong rqfd;
+
+	ulong rdcc;
+
+	u32 *membase;
+	ulong bxcf;
+	int rqfd_average;
+	int bxcr_num;
+	int rffd_average;
+	int pass;
+	uint passed = 0;
+
+	int in_window;
+	u32 curr_win_min, curr_win_max;
+	u32 best_win_min, best_win_max;
+	u32 size = 0;
+
+	/*------------------------------------------------------------------
+	 | Test to determine the best read clock delay tuning bits.
+	 |
+	 | Before the DDR controller can be used, the read clock delay needs to
+	 | be set.  This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+	 | This value cannot be hardcoded into the program because it changes
+	 | depending on the board's setup and environment.
+	 | To do this, all delay values are tested to see if they
+	 | work or not.  By doing this, you get groups of fails with groups of
+	 | passing values.  The idea is to find the start and end of a passing
+	 | window and take the center of it to use as the read clock delay.
+	 |
+	 | A failure has to be seen first so that when we hit a pass, we know
+	 | that it is truely the start of the window.  If we get passing values
+	 | to start off with, we don't know if we are at the start of the window
+	 |
+	 | The code assumes that a failure will always be found.
+	 | If a failure is not found, there is no easy way to get the middle
+	 | of the passing window.  I guess we can pretty much pick any value
+	 | but some values will be better than others.  Since the lowest speed
+	 | we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+	 | from experimentation it is safe to say you will always have a failure
+	 +-----------------------------------------------------------------*/
+
+	debug("\n\n");
+
+	in_window = 0;
+	rdcc = 0;
+
+	curr_win_min = curr_win_max = 0;
+	best_win_min = best_win_max = 0;
+	for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+		mfsdram(SDRAM_RFDC, rfdc_reg);
+		rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+		mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+		pass = 1;
+		for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+			mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+
+			/* Banks enabled */
+			if (bxcf & SDRAM_BXCF_M_BE_MASK) {
+				/* Bank is enabled */
+				membase = get_membase(bxcr_num);
+				pass &= short_mem_test(membase);
+			} /* if bank enabled */
+		} /* for bxcf_num */
+
+		/* If this value passed */
+		if (pass && !in_window) {	/* start of passing window */
+			in_window = 1;
+			curr_win_min = curr_win_max = rffd;
+			mfsdram(SDRAM_RDCC, rdcc);	/* record this value */
+		} else if (!pass && in_window) {	/* end passing window */
+			in_window = 0;
+		} else if (pass && in_window) {	/* within the passing window */
+			curr_win_max = rffd;
+		}
+
+		if (in_window) {
+			if ((curr_win_max - curr_win_min) >
+			    (best_win_max - best_win_min)) {
+				best_win_min = curr_win_min;
+				best_win_max = curr_win_max;
+				cal->rdcc    = rdcc;
+			}
+			passed = 1;
+		}
+	} /* for rffd */
+
+	if ((best_win_min == 0) && (best_win_max == 0))
+		passed = 0;
+	else
+		size = best_win_max - best_win_min;
+
+	debug("RFFD Min: 0x%x\n", best_win_min);
+	debug("RFFD Max: 0x%x\n", best_win_max);
+	rffd_average = ((best_win_min + best_win_max) / 2);
+
+	cal->rffd_min = best_win_min;
+	cal->rffd_max = best_win_max;
+
+	if (rffd_average < 0)
+		rffd_average = 0;
+
+	if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+		rffd_average = SDRAM_RFDC_RFFD_MAX;
+
+	mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+
+	rffd = rffd_average;
+	in_window = 0;
+
+	curr_win_min = curr_win_max = 0;
+	best_win_min = best_win_max = 0;
+	for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+		mfsdram(SDRAM_RQDC, rqdc_reg);
+		rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+		mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+		pass = 1;
+		for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+
+			mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+
+			/* Banks enabled */
+			if (bxcf & SDRAM_BXCF_M_BE_MASK) {
+				/* Bank is enabled */
+				membase = get_membase(bxcr_num);
+				pass &= short_mem_test(membase);
+			} /* if bank enabled */
+		} /* for bxcf_num */
+
+		/* If this value passed */
+		if (pass && !in_window) {
+			in_window = 1;
+			curr_win_min = curr_win_max = rqfd;
+		} else if (!pass && in_window) {
+			in_window = 0;
+		} else if (pass && in_window) {
+			curr_win_max = rqfd;
+		}
+
+		if (in_window) {
+			if ((curr_win_max - curr_win_min) >
+			    (best_win_max - best_win_min)) {
+				best_win_min = curr_win_min;
+				best_win_max = curr_win_max;
+			}
+			passed = 1;
+		}
+	} /* for rqfd */
+
+	if ((best_win_min == 0) && (best_win_max == 0))
+		passed = 0;
+
+	debug("RQFD Min: 0x%x\n", best_win_min);
+	debug("RQFD Max: 0x%x\n", best_win_max);
+	rqfd_average = ((best_win_min + best_win_max) / 2);
+
+	if (rqfd_average < 0)
+		rqfd_average = 0;
+
+	if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+		rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+	mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+					SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+	mfsdram(SDRAM_RQDC, rqdc_reg);
+	mfsdram(SDRAM_RFDC, rfdc_reg);
+
+	/*
+	 * Need to program RQDC before RFDC. The value is read above.
+	 * That is the reason why auto cal not work.
+	 * See, comments below.
+	 */
+	mtsdram(SDRAM_RQDC, rqdc_reg);
+	mtsdram(SDRAM_RFDC, rfdc_reg);
+
+	debug("RQDC: 0x%08X\n", rqdc_reg);
+	debug("RFDC: 0x%08X\n", rfdc_reg);
+
+	/* if something passed, then return the size of the largest window */
+	if (passed != 0) {
+		passed		= size;
+		cal->rqfd	= rqfd_average;
+		cal->rffd	= rffd_average;
+	}
+
+	return (uint)passed;
+}
+#endif /* defined(CONFIG_PPC4xx_DDR_METHOD_A) */
+
+/*
+ * Default table for DDR auto-calibration of all
+ * possible WRDTR and CLKTR values.
+ * Table format is:
+ *	 {SDRAM_WRDTR.[WDTR], SDRAM_CLKTR.[CKTR]}
+ *
+ * Table is terminated with {-1, -1} value pair.
+ *
+ * Board vendors can specify their own board specific subset of
+ * known working {SDRAM_WRDTR.[WDTR], SDRAM_CLKTR.[CKTR]} value
+ * pairs via a board defined ddr_scan_option() function.
+ */
+struct sdram_timing full_scan_options[] = {
+	{0, 0}, {0, 1}, {0, 2}, {0, 3},
+	{1, 0}, {1, 1}, {1, 2}, {1, 3},
+	{2, 0}, {2, 1}, {2, 2}, {2, 3},
+	{3, 0}, {3, 1}, {3, 2}, {3, 3},
+	{4, 0}, {4, 1}, {4, 2}, {4, 3},
+	{5, 0}, {5, 1}, {5, 2}, {5, 3},
+	{6, 0}, {6, 1}, {6, 2}, {6, 3},
+	{-1, -1}
+};
+
+/*---------------------------------------------------------------------------+
+| DQS_calibration.
++----------------------------------------------------------------------------*/
+u32 DQS_autocalibration(void)
+{
+	u32 wdtr;
+	u32 clkp;
+	u32 result = 0;
+	u32 best_result = 0;
+	u32 best_rdcc;
+	struct ddrautocal ddrcal;
+	struct autocal_clks tcal;
+	ulong rfdc_reg;
+	ulong rqdc_reg;
+	u32 val;
+	int verbose_lvl = 0;
+	char *str;
+	char slash[] = "\\|/-\\|/-";
+	int loopi = 0;
+	struct sdram_timing *scan_list;
+
+#if defined(DEBUG_PPC4xx_DDR_AUTOCALIBRATION)
+	int i;
+	char tmp[64];	/* long enough for environment variables */
+#endif
+
+	memset(&tcal, 0, sizeof(tcal));
+
+	ddr_scan_option((ulong)full_scan_options);
+
+	scan_list =
+	      (struct sdram_timing *)ddr_scan_option((ulong)full_scan_options);
+
+	mfsdram(SDRAM_MCOPT1, val);
+	if ((val & SDRAM_MCOPT1_MCHK_CHK_REP) == SDRAM_MCOPT1_MCHK_CHK_REP)
+		str = "ECC Auto calibration -";
+	else
+		str = "Auto calibration -";
+
+	puts(str);
+
+#if defined(DEBUG_PPC4xx_DDR_AUTOCALIBRATION)
+	i = getenv_r("autocalib", tmp, sizeof(tmp));
+	if (i < 0)
+		strcpy(tmp, CONFIG_AUTOCALIB);
+
+	if (strcmp(tmp, "final") == 0) {
+		/* display the final autocalibration results only */
+		verbose_lvl = 1;
+	} else if (strcmp(tmp, "loop") == 0) {
+		/* display summary autocalibration info per iteration */
+		verbose_lvl = 2;
+	} else if (strcmp(tmp, "display") == 0) {
+		/* display full debug autocalibration window info. */
+		verbose_lvl = 3;
+	}
+#endif /* (DEBUG_PPC4xx_DDR_AUTOCALIBRATION) */
+
+	best_rdcc = (SDRAM_RDCC_RDSS_T4 >> 30);
+
+	while ((scan_list->wrdtr != -1) && (scan_list->clktr != -1)) {
+		wdtr = scan_list->wrdtr;
+		clkp = scan_list->clktr;
+
+		mfsdram(SDRAM_WRDTR, val);
+		val &= ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK);
+		mtsdram(SDRAM_WRDTR, (val |
+			ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | (wdtr << 25))));
+
+		mtsdram(SDRAM_CLKTR, clkp << 30);
+
+		relock_memory_DLL();
+
+		putc('\b');
+		putc(slash[loopi++ % 8]);
+
+#ifdef DEBUG
+		debug("\n");
+		debug("*** --------------\n");
+		mfsdram(SDRAM_WRDTR, val);
+		debug("*** SDRAM_WRDTR set to 0x%08x\n", val);
+		mfsdram(SDRAM_CLKTR, val);
+		debug("*** SDRAM_CLKTR set to 0x%08x\n", val);
+#endif
+
+		debug("\n");
+		if (verbose_lvl > 2) {
+			printf("*** SDRAM_WRDTR (wdtr) set to %d\n", wdtr);
+			printf("*** SDRAM_CLKTR (clkp) set to %d\n", clkp);
+		}
+
+		memset(&ddrcal, 0, sizeof(ddrcal));
+
+		/*
+		 * DQS calibration.
+		 */
+		/*
+		 * program_DQS_calibration_method[A|B]() returns 0 if no
+		 * passing RFDC.[RFFD] window is found or returns the size
+		 * of the best passing window; in the case of a found passing
+		 * window, the ddrcal will contain the values of the best
+		 * window RQDC.[RQFD] and RFDC.[RFFD].
+		 */
+
+		/*
+		 * Call PPC4xx SDRAM DDR autocalibration methodA or methodB.
+		 * Default is methodB.
+		 * Defined the autocalibration method in the board specific
+		 * header file.
+		 * Please see include/configs/kilauea.h for an example for
+		 * a board specific implementation.
+		 */
+#if defined(CONFIG_PPC4xx_DDR_METHOD_A)
+		result = program_DQS_calibration_methodA(&ddrcal);
+#else
+		result = program_DQS_calibration_methodB(&ddrcal);
+#endif
+
+		sync();
+
+		/*
+		 * Clear potential errors resulting from auto-calibration.
+		 * If not done, then we could get an interrupt later on when
+		 * exceptions are enabled.
+		 */
+		set_mcsr(get_mcsr());
+
+		val = ddrcal.rdcc;	/* RDCC from the best passing window */
+
+		udelay(100);
+
+		if (verbose_lvl > 1) {
+			char *tstr;
+			switch ((val >> 30)) {
+			case 0:
+				if (result != 0)
+					tstr = "T1";
+				else
+					tstr = "N/A";
+				break;
+			case 1:
+				tstr = "T2";
+				break;
+			case 2:
+				tstr = "T3";
+				break;
+			case 3:
+				tstr = "T4";
+				break;
+			default:
+				tstr = "unknown";
+				break;
+			}
+			printf("** WRDTR(%d) CLKTR(%d), Wind (%d), best (%d), "
+			       "max-min(0x%04x)(0x%04x), RDCC: %s\n",
+				wdtr, clkp, result, best_result,
+				ddrcal.rffd_min, ddrcal.rffd_max, tstr);
+		}
+
+		/*
+		 * The DQS calibration "result" is either "0"
+		 * if no passing window was found, or is the
+		 * size of the RFFD passing window.
+		 */
+		/*
+		 * want the lowest Read Sample Cycle Select
+		 */
+		val = SDRAM_RDCC_RDSS_DECODE(val);
+		debug("*** (%d) (%d) current_rdcc, best_rdcc\n",
+			val, best_rdcc);
+
+		if ((result != 0) &&
+		    (val >= SDRAM_RDCC_RDSS_VAL(SDRAM_RDCC_RDSS_T2))) {
+			if (((result == best_result) && (val < best_rdcc)) ||
+			    ((result > best_result) && (val <= best_rdcc))) {
+				tcal.autocal.flags = 1;
+				debug("*** (%d)(%d) result passed window "
+					"size: 0x%08x, rqfd = 0x%08x, "
+					"rffd = 0x%08x, rdcc = 0x%08x\n",
+					wdtr, clkp, result, ddrcal.rqfd,
+					ddrcal.rffd, ddrcal.rdcc);
+
+				/*
+				 * Save the SDRAM_WRDTR and SDRAM_CLKTR
+				 * settings for the largest returned
+				 * RFFD passing window size.
+				 */
+				best_rdcc = val;
+				tcal.clocks.wrdtr = wdtr;
+				tcal.clocks.clktr = clkp;
+				tcal.clocks.rdcc = SDRAM_RDCC_RDSS_ENCODE(val);
+				tcal.autocal.rqfd = ddrcal.rqfd;
+				tcal.autocal.rffd = ddrcal.rffd;
+				best_result = result;
+
+					if (verbose_lvl > 2) {
+						printf("** (%d)(%d)  "
+						       "best result: 0x%04x\n",
+							wdtr, clkp,
+							best_result);
+						printf("** (%d)(%d)  "
+						       "best WRDTR: 0x%04x\n",
+							wdtr, clkp,
+							tcal.clocks.wrdtr);
+						printf("** (%d)(%d)  "
+						       "best CLKTR: 0x%04x\n",
+							wdtr, clkp,
+							tcal.clocks.clktr);
+						printf("** (%d)(%d)  "
+						       "best RQDC: 0x%04x\n",
+							wdtr, clkp,
+							tcal.autocal.rqfd);
+						printf("** (%d)(%d)  "
+						       "best RFDC: 0x%04x\n",
+							wdtr, clkp,
+							tcal.autocal.rffd);
+						printf("** (%d)(%d)  "
+						       "best RDCC: 0x%08x\n",
+							wdtr, clkp,
+							(u32)tcal.clocks.rdcc);
+						mfsdram(SDRAM_RTSR, val);
+						printf("** (%d)(%d)  best "
+						       "loop RTSR: 0x%08x\n",
+							wdtr, clkp, val);
+						mfsdram(SDRAM_FCSR, val);
+						printf("** (%d)(%d)  best "
+						       "loop FCSR: 0x%08x\n",
+							wdtr, clkp, val);
+					}
+			}
+		} /* if ((result != 0) && (val >= (ddr_rdss_opt()))) */
+		scan_list++;
+	} /* while ((scan_list->wrdtr != -1) && (scan_list->clktr != -1)) */
+
+	if (tcal.autocal.flags == 1) {
+		if (verbose_lvl > 0) {
+			printf("*** --------------\n");
+			printf("*** best_result window size: %d\n",
+							best_result);
+			printf("*** best_result WRDTR: 0x%04x\n",
+							tcal.clocks.wrdtr);
+			printf("*** best_result CLKTR: 0x%04x\n",
+							tcal.clocks.clktr);
+			printf("*** best_result RQFD: 0x%04x\n",
+							tcal.autocal.rqfd);
+			printf("*** best_result RFFD: 0x%04x\n",
+							tcal.autocal.rffd);
+			printf("*** best_result RDCC: 0x%04x\n",
+							tcal.clocks.rdcc);
+			printf("*** --------------\n");
+			printf("\n");
+		}
+
+		/*
+		 * if got best passing result window, then lock in the
+		 * best CLKTR, WRDTR, RQFD, and RFFD values
+		 */
+		mfsdram(SDRAM_WRDTR, val);
+		mtsdram(SDRAM_WRDTR, (val &
+		    ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) |
+		    ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC |
+					(tcal.clocks.wrdtr << 25)));
+
+		mtsdram(SDRAM_CLKTR, tcal.clocks.clktr << 30);
+
+		relock_memory_DLL();
+
+		mfsdram(SDRAM_RQDC, rqdc_reg);
+		rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+		mtsdram(SDRAM_RQDC, rqdc_reg |
+				SDRAM_RQDC_RQFD_ENCODE(tcal.autocal.rqfd));
+
+		mfsdram(SDRAM_RQDC, rqdc_reg);
+		debug("*** best_result: read value SDRAM_RQDC 0x%08x\n",
+				rqdc_reg);
+
+		mfsdram(SDRAM_RFDC, rfdc_reg);
+		rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+		mtsdram(SDRAM_RFDC, rfdc_reg |
+				SDRAM_RFDC_RFFD_ENCODE(tcal.autocal.rffd));
+
+		mfsdram(SDRAM_RFDC, rfdc_reg);
+		debug("*** best_result: read value SDRAM_RFDC 0x%08x\n",
+				rfdc_reg);
+		mfsdram(SDRAM_RDCC, val);
+		debug("***  SDRAM_RDCC 0x%08x\n", val);
+	} else {
+		/*
+		 * no valid windows were found
+		 */
+		printf("DQS memory calibration window can not be determined, "
+		       "terminating u-boot.\n");
+		ppc4xx_ibm_ddr2_register_dump();
+		spd_ddr_init_hang();
+	}
+
+	blank_string(strlen(str));
+
+	return 0;
+}
+#else /* defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) */
+u32 DQS_autocalibration(void)
+{
+	return 0;
+}
+#endif /* !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) */
+#endif /* defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION) */
diff --git a/arch/ppc/cpu/ppc4xx/4xx_pci.c b/arch/ppc/cpu/ppc4xx/4xx_pci.c
new file mode 100644
index 0000000..eed4534
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/4xx_pci.c
@@ -0,0 +1,873 @@
+/*-----------------------------------------------------------------------------+
+ *       This source code is dual-licensed.  You may use it under the terms of
+ *       the GNU General Public license version 2, or under the license below.
+ *
+ *       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 <asm/4xx_pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#ifdef CONFIG_PCI
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
+
+#if defined(CONFIG_PMC405)
+ushort pmc405_pci_subsys_deviceid(void);
+#endif
+
+/*#define DEBUG*/
+
+/*
+ * Board-specific pci initialization
+ * Platform code can reimplement pci_pre_init() if needed
+ */
+int __pci_pre_init(struct pci_controller *hose)
+{
+#if defined(CONFIG_405EP)
+	/*
+	 * Enable the internal PCI arbiter by default.
+	 *
+	 * On 405EP CPUs the internal arbiter can be controlled
+	 * by the I2C strapping EEPROM. If you want to do so
+	 * or if you want to disable the arbiter pci_pre_init()
+	 * must be reimplemented without enabling the arbiter.
+	 * The arbiter is enabled in this place because of
+	 * compatibility reasons.
+	 */
+	mtdcr(CPC0_PCI, mfdcr(CPC0_PCI) | CPC0_PCI_ARBIT_EN);
+#endif /* CONFIG_405EP */
+
+	return 1;
+}
+int pci_pre_init(struct pci_controller *hose)
+	__attribute__((weak, alias("__pci_pre_init")));
+
+int __is_pci_host(struct pci_controller *hose)
+{
+#if defined(CONFIG_405GP)
+	if (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN)
+		return 1;
+#elif defined (CONFIG_405EP)
+	if (mfdcr(CPC0_PCI) & CPC0_PCI_ARBIT_EN)
+		return 1;
+#endif
+	return 0;
+}
+int is_pci_host(struct pci_controller *hose) __attribute__((weak, alias("__is_pci_host")));
+
+/*-----------------------------------------------------------------------------+
+ * pci_init.  Initializes the 405GP PCI Configuration regs.
+ *-----------------------------------------------------------------------------*/
+void pci_405gp_init(struct pci_controller *hose)
+{
+	int i, reg_num = 0;
+	bd_t *bd = gd->bd;
+
+	unsigned short temp_short;
+	unsigned long ptmpcila[2] = {CONFIG_SYS_PCI_PTM1PCI, CONFIG_SYS_PCI_PTM2PCI};
+#if defined(CONFIG_PCI_4xx_PTM_OVERWRITE)
+	char *ptmla_str, *ptmms_str;
+#endif
+	unsigned long ptmla[2]    = {CONFIG_SYS_PCI_PTM1LA, CONFIG_SYS_PCI_PTM2LA};
+	unsigned long ptmms[2]    = {CONFIG_SYS_PCI_PTM1MS, CONFIG_SYS_PCI_PTM2MS};
+#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
+#ifdef CONFIG_PCI_PNP
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+	char *s;
+#endif
+#endif
+
+#if defined(CONFIG_PCI_4xx_PTM_OVERWRITE)
+	ptmla_str = getenv("ptm1la");
+	ptmms_str = getenv("ptm1ms");
+	if(NULL != ptmla_str && NULL != ptmms_str ) {
+	        ptmla[0] = simple_strtoul (ptmla_str, NULL, 16);
+		ptmms[0] = simple_strtoul (ptmms_str, NULL, 16);
+	}
+
+	ptmla_str = getenv("ptm2la");
+	ptmms_str = getenv("ptm2ms");
+	if(NULL != ptmla_str && NULL != ptmms_str ) {
+	        ptmla[1] = simple_strtoul (ptmla_str, NULL, 16);
+		ptmms[1] = simple_strtoul (ptmms_str, NULL, 16);
+	}
+#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_SYS_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);
+
+	/* 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;
+	}
+
+	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]&~0x1)); /* disable, configure PMMxLA, PMMxPCILA first */
+	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]&~0x1));
+	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]&~0x1));
+	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       */
+	pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_1, ptmpcila[0]);
+
+	/*--------------------------------------------------------------------------+
+	 * 405GP PCI Target configuration.  (PTM2)
+	 *--------------------------------------------------------------------------*/
+	out32r(PTM2LA, ptmla[1]);            /* insert address                     */
+	pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, ptmpcila[1]);
+
+	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, CONFIG_SYS_PCI_SUBSYS_VENDORID);
+#ifdef CONFIG_CPCI405
+	if (is_pci_host(hose))
+		pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
+	else
+		pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID2);
+#else
+	pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
+#endif
+
+	/*
+	 * Insert Class-code
+	 */
+#ifdef CONFIG_SYS_PCI_CLASSCODE
+	pci_write_config_word(PCIDEVID_405GP, PCI_CLASS_SUB_CODE, CONFIG_SYS_PCI_CLASSCODE);
+#endif /* CONFIG_SYS_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_HOST == PCI_HOST_AUTO)
+	if (is_pci_host(hose) ||
+	    (((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
+#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
+
+#if defined(CONFIG_405EP)
+	/*
+	 * on ppc405ep vendor/device id is not set
+	 * The user manual says 0x1014 (IBM) / 0x0156 (405GP!)
+	 * are the correct values.
+	 */
+	pci_write_config_word(PCIDEVID_405GP, PCI_VENDOR_ID, PCI_VENDOR_ID_IBM);
+	pci_write_config_word(PCIDEVID_405GP,
+			      PCI_DEVICE_ID, PCI_DEVICE_ID_IBM_405GP);
+#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 (is_pci_host(hose) ||
+	    (((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
+#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/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_prefetch, 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)) && !(defined (CONFIG_SC3))
+
+/*
+ *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)*/
+#ifdef CONFIG_SYS_PCI_SUBSYS_VENDORID
+	{CONFIG_SYS_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_board(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_405GP */
+
+/*-----------------------------------------------------------------------------+
+ * CONFIG_440
+ *-----------------------------------------------------------------------------*/
+#if defined(CONFIG_440)
+
+static struct pci_controller ppc440_hose = {0};
+
+/*
+ * This routine is called to determine if a pci scan should be
+ * performed. With various hardware environments (especially cPCI and
+ * PPMC) it's insufficient to depend on the state of the arbiter enable
+ * bit in the strap register, or generic host/adapter assumptions.
+ *
+ * Rather than hard-code a bad assumption in the general 440 code, the
+ * 440 pci code requires the board to decide at runtime.
+ *
+ * Return 0 for adapter mode, non-zero for host (monarch) mode.
+ *
+ * Weak default implementation: "Normal" boards implement the PCI
+ * host functionality. This can be overridden for PCI adapter boards.
+ */
+int __is_pci_host(struct pci_controller *hose)
+{
+	return 1;
+}
+int is_pci_host(struct pci_controller *hose)
+	__attribute__((weak, alias("__is_pci_host")));
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+    defined(CONFIG_440GR) || defined(CONFIG_440GRX)
+
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+/*
+ * pci_target_init
+ *
+ * The bootstrap configuration provides default settings for the pci
+ * inbound map (PIM). But the bootstrap config choices are limited and
+ * may not be sufficient for a given board.
+ */
+void __pci_target_init(struct pci_controller *hose)
+{
+	/*
+	 * Set up Direct MMIO registers
+	 */
+
+	/*
+	 * PowerPC440 EP PCI Master configuration.
+	 * Map one 1Gig range of PLB/processor addresses to PCI memory space.
+	 * PLB address 0xA0000000-0xDFFFFFFF ==> PCI address 0xA0000000-0xDFFFFFFF
+	 * Use byte reversed out routines to handle endianess.
+	 * Make this region non-prefetchable.
+	 */
+	/* PMM0 Mask/Attribute - disabled b4 setting */
+	out_le32((void *)PCIL0_PMM0MA, 0x00000000);
+	/* PMM0 Local Address */
+	out_le32((void *)PCIL0_PMM0LA, CONFIG_SYS_PCI_MEMBASE);
+	/* PMM0 PCI Low Address */
+	out_le32((void *)PCIL0_PMM0PCILA, CONFIG_SYS_PCI_MEMBASE);
+	/* PMM0 PCI High Address */
+	out_le32((void *)PCIL0_PMM0PCIHA, 0x00000000);
+	/* 512M + No prefetching, and enable region */
+	out_le32((void *)PCIL0_PMM0MA, 0xE0000001);
+
+	/* PMM1 Mask/Attribute - disabled b4 setting */
+	out_le32((void *)PCIL0_PMM1MA, 0x00000000);
+	/* PMM1 Local Address */
+	out_le32((void *)PCIL0_PMM1LA, CONFIG_SYS_PCI_MEMBASE2);
+	/* PMM1 PCI Low Address */
+	out_le32((void *)PCIL0_PMM1PCILA, CONFIG_SYS_PCI_MEMBASE2);
+	/* PMM1 PCI High Address */
+	out_le32((void *)PCIL0_PMM1PCIHA, 0x00000000);
+	/* 512M + No prefetching, and enable region */
+	out_le32((void *)PCIL0_PMM1MA, 0xE0000001);
+
+	out_le32((void *)PCIL0_PTM1MS, 0x00000001); /* Memory Size/Attribute */
+	out_le32((void *)PCIL0_PTM1LA, 0);	/* Local Addr. Reg */
+	out_le32((void *)PCIL0_PTM2MS, 0);	/* Memory Size/Attribute */
+	out_le32((void *)PCIL0_PTM2LA, 0);	/* Local Addr. Reg */
+
+	/*
+	 * Set up Configuration registers
+	 */
+
+	/* Program the board's subsystem id/vendor id */
+	pci_write_config_word(0, PCI_SUBSYSTEM_VENDOR_ID,
+			      CONFIG_SYS_PCI_SUBSYS_VENDORID);
+	pci_write_config_word(0, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_ID);
+
+	/* Configure command register as bus master */
+	pci_write_config_word(0, PCI_COMMAND, PCI_COMMAND_MASTER);
+
+	/* 240nS PCI clock */
+	pci_write_config_word(0, PCI_LATENCY_TIMER, 1);
+
+	/* No error reporting */
+	pci_write_config_word(0, PCI_ERREN, 0);
+
+	pci_write_config_dword(0, PCI_BRDGOPT2, 0x00000101);
+}
+#endif /* CONFIG_SYS_PCI_TARGET_INIT */
+
+/*
+ * pci_pre_init
+ *
+ * This routine is called just prior to registering the hose and gives
+ * the board the opportunity to check things. Returning a value of zero
+ * indicates that things are bad & PCI initialization should be aborted.
+ *
+ * Different boards may wish to customize the pci controller structure
+ * (add regions, override default access routines, etc) or perform
+ * certain pre-initialization actions.
+ *
+ */
+int __pci_pre_init(struct pci_controller *hose)
+{
+	u32 reg;
+
+	/*
+	 * Set priority for all PLB3 devices to 0.
+	 * Set PLB3 arbiter to fair mode.
+	 */
+	mfsdr(SD0_AMP1, reg);
+	mtsdr(SD0_AMP1, (reg & 0x000000FF) | 0x0000FF00);
+	reg = mfdcr(PLB3_ACR);
+	mtdcr(PLB3_ACR, reg | 0x80000000);
+
+	/*
+	 * Set priority for all PLB4 devices to 0.
+	 */
+	mfsdr(SD0_AMP0, reg);
+	mtsdr(SD0_AMP0, (reg & 0x000000FF) | 0x0000FF00);
+	reg = mfdcr(PLB4_ACR) | 0xa0000000;
+	mtdcr(PLB4_ACR, reg);
+
+	/*
+	 * Set Nebula PLB4 arbiter to fair mode.
+	 */
+	/* Segment0 */
+	reg = (mfdcr(PLB0_ACR) & ~PLB0_ACR_PPM_MASK) | PLB0_ACR_PPM_FAIR;
+	reg = (reg & ~PLB0_ACR_HBU_MASK) | PLB0_ACR_HBU_ENABLED;
+	reg = (reg & ~PLB0_ACR_RDP_MASK) | PLB0_ACR_RDP_4DEEP;
+	reg = (reg & ~PLB0_ACR_WRP_MASK) | PLB0_ACR_WRP_2DEEP;
+	mtdcr(PLB0_ACR, reg);
+
+	/* Segment1 */
+	reg = (mfdcr(PLB1_ACR) & ~PLB1_ACR_PPM_MASK) | PLB1_ACR_PPM_FAIR;
+	reg = (reg & ~PLB1_ACR_HBU_MASK) | PLB1_ACR_HBU_ENABLED;
+	reg = (reg & ~PLB1_ACR_RDP_MASK) | PLB1_ACR_RDP_4DEEP;
+	reg = (reg & ~PLB1_ACR_WRP_MASK) | PLB1_ACR_WRP_2DEEP;
+	mtdcr(PLB1_ACR, reg);
+
+#if defined(CONFIG_SYS_PCI_BOARD_FIXUP_IRQ)
+	hose->fixup_irq = board_pci_fixup_irq;
+#endif
+
+	return 1;
+}
+
+#else /* defined(CONFIG_440EP) ... */
+
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+void __pci_target_init(struct pci_controller * hose)
+{
+	/*
+	 * Disable everything
+	 */
+	out_le32((void *)PCIL0_PIM0SA, 0); /* disable */
+	out_le32((void *)PCIL0_PIM1SA, 0); /* disable */
+	out_le32((void *)PCIL0_PIM2SA, 0); /* disable */
+	out_le32((void *)PCIL0_EROMBA, 0); /* disable expansion rom */
+
+	/*
+	 * Map all of SDRAM to PCI address 0x0000_0000. Note that the 440
+	 * strapping options do not support sizes such as 128/256 MB.
+	 */
+	out_le32((void *)PCIL0_PIM0LAL, CONFIG_SYS_SDRAM_BASE);
+	out_le32((void *)PCIL0_PIM0LAH, 0);
+	out_le32((void *)PCIL0_PIM0SA, ~(gd->ram_size - 1) | 1);
+	out_le32((void *)PCIL0_BAR0, 0);
+
+	/*
+	 * Program the board's subsystem id/vendor id
+	 */
+	out_le16((void *)PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID);
+	out_le16((void *)PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
+
+	out_le16((void *)PCIL0_CMD, in_le16((void *)PCIL0_CMD) |
+		 PCI_COMMAND_MEMORY);
+}
+#endif /* CONFIG_SYS_PCI_TARGET_INIT */
+
+int __pci_pre_init(struct pci_controller *hose)
+{
+	/*
+	 * This board is always configured as the host & requires the
+	 * PCI arbiter to be enabled.
+	 */
+	if (!pci_arbiter_enabled()) {
+		printf("PCI: PCI Arbiter disabled!\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+#endif /* defined(CONFIG_440EP) ... */
+
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+void pci_target_init(struct pci_controller * hose)
+	__attribute__((weak, alias("__pci_target_init")));
+#endif /* CONFIG_SYS_PCI_TARGET_INIT */
+
+int pci_pre_init(struct pci_controller *hose)
+	__attribute__((weak, alias("__pci_pre_init")));
+
+#if defined(CONFIG_SYS_PCI_MASTER_INIT)
+void __pci_master_init(struct pci_controller *hose)
+{
+	u16 reg;
+
+	/*
+	 * Write the PowerPC440 EP PCI Configuration regs.
+	 * Enable PowerPC440 EP to be a master on the PCI bus (PMM).
+	 * Enable PowerPC440 EP to act as a PCI memory target (PTM).
+	 */
+	pci_read_config_word(0, PCI_COMMAND, &reg);
+	pci_write_config_word(0, PCI_COMMAND, reg |
+			      PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+}
+void pci_master_init(struct pci_controller *hose)
+	__attribute__((weak, alias("__pci_master_init")));
+#endif /* CONFIG_SYS_PCI_MASTER_INIT */
+
+int pci_440_init (struct pci_controller *hose)
+{
+	int reg_num = 0;
+
+#ifndef CONFIG_DISABLE_PISE_TEST
+	/*--------------------------------------------------------------------------+
+	 * The PCI initialization sequence enable bit must be set ... if not abort
+	 * pci setup since updating the bit requires chip reset.
+	 *--------------------------------------------------------------------------*/
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+	unsigned long strap;
+
+	mfsdr(SDR0_SDSTP1,strap);
+	if ((strap & SDR0_SDSTP1_PISE_MASK) == 0) {
+		printf("PCI: SDR0_STRP1[PISE] not set.\n");
+		printf("PCI: Configuration aborted.\n");
+		return -1;
+	}
+#elif defined(CONFIG_440GP)
+	unsigned long strap;
+
+	strap = mfdcr(CPC0_STRP1);
+	if ((strap & CPC0_STRP1_PISE_MASK) == 0) {
+		printf("PCI: CPC0_STRP1[PISE] not set.\n");
+		printf("PCI: Configuration aborted.\n");
+		return -1;
+	}
+#endif
+#endif /* CONFIG_DISABLE_PISE_TEST */
+
+	/*--------------------------------------------------------------------------+
+	 * PCI controller init
+	 *--------------------------------------------------------------------------*/
+	hose->first_busno = 0;
+	hose->last_busno = 0;
+
+	/* PCI I/O space */
+	pci_set_region(hose->regions + reg_num++,
+		       0x00000000,
+		       PCIL0_IOBASE,
+		       0x10000,
+		       PCI_REGION_IO);
+
+	/* PCI memory space */
+	pci_set_region(hose->regions + reg_num++,
+		       CONFIG_SYS_PCI_TARGBASE,
+		       CONFIG_SYS_PCI_MEMBASE,
+#ifdef CONFIG_SYS_PCI_MEMSIZE
+		       CONFIG_SYS_PCI_MEMSIZE,
+#else
+		       0x10000000,
+#endif
+		       PCI_REGION_MEM );
+
+#if defined(CONFIG_PCI_SYS_MEM_BUS) && defined(CONFIG_PCI_SYS_MEM_PHYS) && \
+	defined(CONFIG_PCI_SYS_MEM_SIZE)
+	/* System memory space */
+	pci_set_region(hose->regions + reg_num++,
+		       CONFIG_PCI_SYS_MEM_BUS,
+		       CONFIG_PCI_SYS_MEM_PHYS,
+		       CONFIG_PCI_SYS_MEM_SIZE,
+		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY );
+#endif
+
+	hose->region_count = reg_num;
+
+	pci_setup_indirect(hose, PCIL0_CFGADR, PCIL0_CFGDATA);
+
+	/* 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 -1;
+	}
+
+	pci_register_hose( hose );
+
+	/*--------------------------------------------------------------------------+
+	 * PCI target init
+	 *--------------------------------------------------------------------------*/
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+	pci_target_init(hose);                /* Let board setup pci target */
+#else
+	out16r( PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID );
+	out16r( PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_ID );
+	out16r( PCIL0_CLS, 0x00060000 ); /* Bridge, host bridge */
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	out32r( PCIL0_BRDGOPT1, 0x04000060 );               /* PLB Rq pri highest   */
+	out32r( PCIL0_BRDGOPT2, in32(PCIL0_BRDGOPT2) | 0x83 ); /* Enable host config, clear Timeout, ensure int src1  */
+#elif defined(PCIL0_BRDGOPT1)
+	out32r( PCIL0_BRDGOPT1, 0x10000060 );               /* PLB Rq pri highest   */
+	out32r( PCIL0_BRDGOPT2, in32(PCIL0_BRDGOPT2) | 1 ); /* Enable host config   */
+#endif
+
+	/*--------------------------------------------------------------------------+
+	 * PCI master init: default is one 256MB region for PCI memory:
+	 * 0x3_00000000 - 0x3_0FFFFFFF  ==> CONFIG_SYS_PCI_MEMBASE
+	 *--------------------------------------------------------------------------*/
+#if defined(CONFIG_SYS_PCI_MASTER_INIT)
+	pci_master_init(hose);          /* Let board setup pci master */
+#else
+	out32r( PCIL0_POM0SA, 0 ); /* disable */
+	out32r( PCIL0_POM1SA, 0 ); /* disable */
+	out32r( PCIL0_POM2SA, 0 ); /* disable */
+#if defined(CONFIG_440SPE)
+	out32r( PCIL0_POM0LAL, 0x10000000 );
+	out32r( PCIL0_POM0LAH, 0x0000000c );
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	out32r( PCIL0_POM0LAL, 0x20000000 );
+	out32r( PCIL0_POM0LAH, 0x0000000c );
+#else
+	out32r( PCIL0_POM0LAL, 0x00000000 );
+	out32r( PCIL0_POM0LAH, 0x00000003 );
+#endif
+	out32r( PCIL0_POM0PCIAL, CONFIG_SYS_PCI_MEMBASE );
+	out32r( PCIL0_POM0PCIAH, 0x00000000 );
+	out32r( PCIL0_POM0SA, 0xf0000001 ); /* 256MB, enabled */
+	out32r( PCIL0_STS, in32r( PCIL0_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
+#if !defined(CONFIG_440EP) && !defined(CONFIG_440GR) && \
+    !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX)
+		out16r( PCIL0_CMD, in16r( PCIL0_CMD ) | PCI_COMMAND_MASTER);
+#endif
+		hose->last_busno = pci_hose_scan(hose);
+	}
+	return hose->last_busno;
+}
+
+void pci_init_board(void)
+{
+	int busno;
+
+	busno = pci_440_init (&ppc440_hose);
+#if (defined(CONFIG_440SPE) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)) && \
+    !defined(CONFIG_PCI_DISABLE_PCIE)
+	pcie_setup_hoses(busno + 1);
+#endif
+}
+
+#endif /* CONFIG_440 */
+
+#if defined(CONFIG_405EX)
+void pci_init_board(void)
+{
+#ifdef CONFIG_PCI_SCAN_SHOW
+	printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
+	pcie_setup_hoses(0);
+}
+#endif /* CONFIG_405EX */
+
+#endif /* CONFIG_PCI */
diff --git a/arch/ppc/cpu/ppc4xx/4xx_pcie.c b/arch/ppc/cpu/ppc4xx/4xx_pcie.c
new file mode 100644
index 0000000..10b58b7
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/4xx_pcie.c
@@ -0,0 +1,1298 @@
+/*
+ * (C) Copyright 2006 - 2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Roland Dreier <rolandd@cisco.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.
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <pci.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#if (defined(CONFIG_440SPE) || defined(CONFIG_405EX) ||	\
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)) && \
+    defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_PCIE)
+
+#include <asm/4xx_pcie.h>
+
+enum {
+	PTYPE_ENDPOINT		= 0x0,
+	PTYPE_LEGACY_ENDPOINT	= 0x1,
+	PTYPE_ROOT_PORT		= 0x4,
+
+	LNKW_X1			= 0x1,
+	LNKW_X4			= 0x4,
+	LNKW_X8			= 0x8
+};
+
+static struct pci_controller pcie_hose[CONFIG_SYS_PCIE_NR_PORTS];
+
+/*
+ * Per default, all cards are present, so we need to check if the
+ * link comes up.
+ */
+int __board_pcie_card_present(int port)
+{
+	return 1;
+}
+int board_pcie_card_present(int port)
+	__attribute__((weak, alias("__board_pcie_card_present")));
+
+/*
+ * Some boards have runtime detection of the first and last PCIe
+ * slot used, so let's provide weak default functions for the
+ * common version.
+ */
+int __board_pcie_first(void)
+{
+	return 0;
+}
+int board_pcie_first(void)
+	__attribute__((weak, alias("__board_pcie_first")));
+
+int __board_pcie_last(void)
+{
+	return CONFIG_SYS_PCIE_NR_PORTS - 1;
+}
+int board_pcie_last(void)
+	__attribute__((weak, alias("__board_pcie_last")));
+
+void __board_pcie_setup_port(int port, int rootpoint)
+{
+	/* noting in this weak default implementation */
+}
+void board_pcie_setup_port(int port, int rootpoint)
+	__attribute__((weak, alias("__board_pcie_setup_port")));
+
+void pcie_setup_hoses(int busno)
+{
+	struct pci_controller *hose;
+	int i, bus;
+	int ret = 0;
+	char *env;
+	unsigned int delay;
+	int first = board_pcie_first();
+	int last = board_pcie_last();
+
+	/*
+	 * Assume we're called after the PCI(X) hose(s) are initialized,
+	 * which takes bus ID 0... and therefore start numbering PCIe's
+	 * from the next number.
+	 */
+	bus = busno;
+
+	for (i = first; i <= last; i++) {
+		/*
+		 * Some boards (e.g. Katmai) can detects via hardware
+		 * if a PCIe card is plugged, so let's check this.
+		 */
+		if (!board_pcie_card_present(i))
+			continue;
+
+		if (is_end_point(i)) {
+			board_pcie_setup_port(i, 0);
+			ret = ppc4xx_init_pcie_endport(i);
+		} else {
+			board_pcie_setup_port(i, 1);
+			ret = ppc4xx_init_pcie_rootport(i);
+		}
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			printf("PCIE%d: initialization as %s failed\n", i,
+			       is_end_point(i) ? "endpoint" : "root-complex");
+			continue;
+		}
+
+		hose = &pcie_hose[i];
+		hose->first_busno = bus;
+		hose->last_busno = bus;
+		hose->current_busno = bus;
+
+		/* setup mem resource */
+		pci_set_region(hose->regions + 0,
+			       CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE,
+			       CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE,
+			       CONFIG_SYS_PCIE_MEMSIZE,
+			       PCI_REGION_MEM);
+		hose->region_count = 1;
+		pci_register_hose(hose);
+
+		if (is_end_point(i)) {
+			ppc4xx_setup_pcie_endpoint(hose, i);
+			/*
+			 * Reson for no scanning is endpoint can not generate
+			 * upstream configuration accesses.
+			 */
+		} else {
+			ppc4xx_setup_pcie_rootpoint(hose, i);
+			env = getenv ("pciscandelay");
+			if (env != NULL) {
+				delay = simple_strtoul(env, NULL, 10);
+				if (delay > 5)
+					printf("Warning, expect noticable delay before "
+					       "PCIe scan due to 'pciscandelay' value!\n");
+				mdelay(delay * 1000);
+			}
+
+			/*
+			 * Config access can only go down stream
+			 */
+			hose->last_busno = pci_hose_scan(hose);
+			bus = hose->last_busno + 1;
+		}
+	}
+}
+
+static int validate_endpoint(struct pci_controller *hose)
+{
+	if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE0_CFGBASE)
+		return (is_end_point(0));
+	else if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE1_CFGBASE)
+		return (is_end_point(1));
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	else if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE2_CFGBASE)
+		return (is_end_point(2));
+#endif
+
+	return 0;
+}
+
+static u8* pcie_get_base(struct pci_controller *hose, unsigned int devfn)
+{
+	u8 *base = (u8*)hose->cfg_data;
+
+	/* use local configuration space for the first bus */
+	if (PCI_BUS(devfn) == 0) {
+		if (hose->cfg_data == (u8*)CONFIG_SYS_PCIE0_CFGBASE)
+			base = (u8*)CONFIG_SYS_PCIE0_XCFGBASE;
+		if (hose->cfg_data == (u8*)CONFIG_SYS_PCIE1_CFGBASE)
+			base = (u8*)CONFIG_SYS_PCIE1_XCFGBASE;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+		if (hose->cfg_data == (u8*)CONFIG_SYS_PCIE2_CFGBASE)
+			base = (u8*)CONFIG_SYS_PCIE2_XCFGBASE;
+#endif
+	}
+
+	return base;
+}
+
+static void pcie_dmer_disable(void)
+{
+	mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE),
+		mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) | GPL_DMER_MASK_DISA);
+	mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE),
+		mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) | GPL_DMER_MASK_DISA);
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE),
+		mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) | GPL_DMER_MASK_DISA);
+#endif
+}
+
+static void pcie_dmer_enable(void)
+{
+	mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE0_BASE),
+		mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) & ~GPL_DMER_MASK_DISA);
+	mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE1_BASE),
+		mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) & ~GPL_DMER_MASK_DISA);
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE2_BASE),
+		mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) & ~GPL_DMER_MASK_DISA);
+#endif
+}
+
+static int pcie_read_config(struct pci_controller *hose, unsigned int devfn,
+	int offset, int len, u32 *val) {
+
+	u8 *address;
+	*val = 0;
+
+	if (validate_endpoint(hose))
+		return 0;		/* No upstream config access */
+
+	/*
+	 * Bus numbers are relative to hose->first_busno
+	 */
+	devfn -= PCI_BDF(hose->first_busno, 0, 0);
+
+	/*
+	 * NOTICE: configuration space ranges are currenlty mapped only for
+	 * the first 16 buses, so such limit must be imposed. In case more
+	 * buses are required the TLB settings in board/amcc/<board>/init.S
+	 * need to be altered accordingly (one bus takes 1 MB of memory space).
+	 */
+	if (PCI_BUS(devfn) >= 16)
+		return 0;
+
+	/*
+	 * Only single device/single function is supported for the primary and
+	 * secondary buses of the 440SPe host bridge.
+	 */
+	if ((!((PCI_FUNC(devfn) == 0) && (PCI_DEV(devfn) == 0))) &&
+		((PCI_BUS(devfn) == 0) || (PCI_BUS(devfn) == 1)))
+		return 0;
+
+	address = pcie_get_base(hose, devfn);
+	offset += devfn << 4;
+
+	/*
+	 * Reading from configuration space of non-existing device can
+	 * generate transaction errors. For the read duration we suppress
+	 * assertion of machine check exceptions to avoid those.
+	 */
+	pcie_dmer_disable ();
+
+	debug("%s: cfg_data=%08x offset=%08x\n", __func__, hose->cfg_data, offset);
+	switch (len) {
+	case 1:
+		*val = in_8(hose->cfg_data + offset);
+		break;
+	case 2:
+		*val = in_le16((u16 *)(hose->cfg_data + offset));
+		break;
+	default:
+		*val = in_le32((u32*)(hose->cfg_data + offset));
+		break;
+	}
+
+	pcie_dmer_enable ();
+
+	return 0;
+}
+
+static int pcie_write_config(struct pci_controller *hose, unsigned int devfn,
+	int offset, int len, u32 val) {
+
+	u8 *address;
+
+	if (validate_endpoint(hose))
+		return 0;		/* No upstream config access */
+
+	/*
+	 * Bus numbers are relative to hose->first_busno
+	 */
+	devfn -= PCI_BDF(hose->first_busno, 0, 0);
+
+	/*
+	 * Same constraints as in pcie_read_config().
+	 */
+	if (PCI_BUS(devfn) >= 16)
+		return 0;
+
+	if ((!((PCI_FUNC(devfn) == 0) && (PCI_DEV(devfn) == 0))) &&
+		((PCI_BUS(devfn) == 0) || (PCI_BUS(devfn) == 1)))
+		return 0;
+
+	address = pcie_get_base(hose, devfn);
+	offset += devfn << 4;
+
+	/*
+	 * Suppress MCK exceptions, similar to pcie_read_config()
+	 */
+	pcie_dmer_disable ();
+
+	switch (len) {
+	case 1:
+		out_8(hose->cfg_data + offset, val);
+		break;
+	case 2:
+		out_le16((u16 *)(hose->cfg_data + offset), val);
+		break;
+	default:
+		out_le32((u32 *)(hose->cfg_data + offset), val);
+		break;
+	}
+
+	pcie_dmer_enable ();
+
+	return 0;
+}
+
+int pcie_read_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 *val)
+{
+	u32 v;
+	int rv;
+
+	rv = pcie_read_config(hose, dev, offset, 1, &v);
+	*val = (u8)v;
+	return rv;
+}
+
+int pcie_read_config_word(struct pci_controller *hose,pci_dev_t dev,int offset,u16 *val)
+{
+	u32 v;
+	int rv;
+
+	rv = pcie_read_config(hose, dev, offset, 2, &v);
+	*val = (u16)v;
+	return rv;
+}
+
+int pcie_read_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 *val)
+{
+	u32 v;
+	int rv;
+
+	rv = pcie_read_config(hose, dev, offset, 3, &v);
+	*val = (u32)v;
+	return rv;
+}
+
+int pcie_write_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 val)
+{
+	return pcie_write_config(hose,(u32)dev,offset,1,val);
+}
+
+int pcie_write_config_word(struct pci_controller *hose,pci_dev_t dev,int offset,u16 val)
+{
+	return pcie_write_config(hose,(u32)dev,offset,2,(u32 )val);
+}
+
+int pcie_write_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 val)
+{
+	return pcie_write_config(hose,(u32)dev,offset,3,(u32 )val);
+}
+
+#if defined(CONFIG_440SPE)
+static void ppc4xx_setup_utl(u32 port) {
+
+	volatile void *utl_base = NULL;
+
+	/*
+	 * Map UTL registers
+	 */
+	switch (port) {
+	case 0:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x0000000c);
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE0), 0x20000000);
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001);
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0x68782800);
+		break;
+
+	case 1:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x0000000c);
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE1), 0x20001000);
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001);
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0x68782800);
+		break;
+
+	case 2:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE2), 0x0000000c);
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE2), 0x20002000);
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE2), 0x00007001);
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE2), 0x68782800);
+		break;
+	}
+	utl_base = (unsigned int *)(CONFIG_SYS_PCIE_BASE + 0x1000 * port);
+
+	/*
+	 * Set buffer allocations and then assert VRB and TXE.
+	 */
+	out_be32(utl_base + PEUTL_OUTTR,   0x08000000);
+	out_be32(utl_base + PEUTL_INTR,    0x02000000);
+	out_be32(utl_base + PEUTL_OPDBSZ,  0x10000000);
+	out_be32(utl_base + PEUTL_PBBSZ,   0x53000000);
+	out_be32(utl_base + PEUTL_IPHBSZ,  0x08000000);
+	out_be32(utl_base + PEUTL_IPDBSZ,  0x10000000);
+	out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
+	out_be32(utl_base + PEUTL_PCTL,    0x80800066);
+}
+
+static int check_error(void)
+{
+	u32 valPE0, valPE1, valPE2;
+	int err = 0;
+
+	/* SDR0_PEGPLLLCT1 reset */
+	if (!(valPE0 = SDR_READ(PESDR0_PLLLCT1) & 0x01000000))
+		printf("PCIE: SDR0_PEGPLLLCT1 reset error 0x%x\n", valPE0);
+
+	valPE0 = SDR_READ(PESDR0_RCSSET);
+	valPE1 = SDR_READ(PESDR1_RCSSET);
+	valPE2 = SDR_READ(PESDR2_RCSSET);
+
+	/* SDR0_PExRCSSET rstgu */
+	if (!(valPE0 & 0x01000000) ||
+	    !(valPE1 & 0x01000000) ||
+	    !(valPE2 & 0x01000000)) {
+		printf("PCIE:  SDR0_PExRCSSET rstgu error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET rstdl */
+	if (!(valPE0 & 0x00010000) ||
+	    !(valPE1 & 0x00010000) ||
+	    !(valPE2 & 0x00010000)) {
+		printf("PCIE:  SDR0_PExRCSSET rstdl error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET rstpyn */
+	if ((valPE0 & 0x00001000) ||
+	    (valPE1 & 0x00001000) ||
+	    (valPE2 & 0x00001000)) {
+		printf("PCIE:  SDR0_PExRCSSET rstpyn error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET hldplb */
+	if ((valPE0 & 0x10000000) ||
+	    (valPE1 & 0x10000000) ||
+	    (valPE2 & 0x10000000)) {
+		printf("PCIE:  SDR0_PExRCSSET hldplb error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET rdy */
+	if ((valPE0 & 0x00100000) ||
+	    (valPE1 & 0x00100000) ||
+	    (valPE2 & 0x00100000)) {
+		printf("PCIE:  SDR0_PExRCSSET rdy error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET shutdown */
+	if ((valPE0 & 0x00000100) ||
+	    (valPE1 & 0x00000100) ||
+	    (valPE2 & 0x00000100)) {
+		printf("PCIE:  SDR0_PExRCSSET shutdown error\n");
+		err = -1;
+	}
+	return err;
+}
+
+/*
+ * Initialize PCI Express core
+ */
+int ppc4xx_init_pcie(void)
+{
+	int time_out = 20;
+
+	/* Set PLL clock receiver to LVPECL */
+	SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) | 1 << 28);
+
+	if (check_error()) {
+		printf("ERROR: failed to set PCIe reference clock receiver --"
+			"PESDR0_PLLLCT1 = 0x%08x\n", SDR_READ(PESDR0_PLLLCT1));
+
+		return -1;
+	}
+
+	/* Did resistance calibration work? */
+	if (!(SDR_READ(PESDR0_PLLLCT2) & 0x10000)) {
+		printf("ERROR: PCIe resistance calibration failed --"
+			"PESDR0_PLLLCT2 = 0x%08x\n", SDR_READ(PESDR0_PLLLCT2));
+
+		return -1;
+	}
+	/* De-assert reset of PCIe PLL, wait for lock */
+	SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) & ~(1 << 24));
+	udelay(300);	/* 300 uS is maximum time lock should take */
+
+	while (time_out) {
+		if (!(SDR_READ(PESDR0_PLLLCT3) & 0x10000000)) {
+			time_out--;
+			udelay(20);	/* Wait 20 uS more if needed */
+		} else
+			break;
+	}
+	if (!time_out) {
+		printf("ERROR: PCIe PLL VCO output not locked to ref clock --"
+			"PESDR0_PLLLCTS=0x%08x\n", SDR_READ(PESDR0_PLLLCT3));
+
+		return -1;
+	}
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+static void ppc4xx_setup_utl(u32 port)
+{
+	volatile void *utl_base = NULL;
+
+	/*
+	 * Map UTL registers at 0x0801_n000 (4K 0xfff mask) PEGPLn_REGMSK
+	 */
+	switch (port) {
+	case 0:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE0), U64_TO_U32_HIGH(CONFIG_SYS_PCIE0_UTLBASE));
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE0), U64_TO_U32_LOW(CONFIG_SYS_PCIE0_UTLBASE));
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001);	/* BAM 11100000=4KB */
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0);
+		break;
+
+	case 1:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE1), U64_TO_U32_HIGH(CONFIG_SYS_PCIE0_UTLBASE));
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE1), U64_TO_U32_LOW(CONFIG_SYS_PCIE0_UTLBASE)
+			+ 0x1000);
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001);	/* BAM 11100000=4KB */
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0);
+		break;
+	}
+	utl_base = (unsigned int *)(CONFIG_SYS_PCIE_BASE + 0x1000 * port);
+
+	/*
+	 * Set buffer allocations and then assert VRB and TXE.
+	 */
+	out_be32(utl_base + PEUTL_PBCTL, 0x0800000c);	/* PLBME, CRRE */
+	out_be32(utl_base + PEUTL_OUTTR, 0x08000000);
+	out_be32(utl_base + PEUTL_INTR, 0x02000000);
+	out_be32(utl_base + PEUTL_OPDBSZ, 0x04000000);	/* OPD = 512 Bytes */
+	out_be32(utl_base + PEUTL_PBBSZ, 0x00000000);	/* Max 512 Bytes */
+	out_be32(utl_base + PEUTL_IPHBSZ, 0x02000000);
+	out_be32(utl_base + PEUTL_IPDBSZ, 0x04000000);	/* IPD = 512 Bytes */
+	out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
+	out_be32(utl_base + PEUTL_PCTL, 0x80800066);	/* VRB,TXE,timeout=default */
+}
+
+/*
+ * TODO: double check PCI express SDR based on the latest user manual
+ *		 Some registers specified here no longer exist.. has to be
+ *		 updated based on the final EAS spec.
+ */
+static int check_error(void)
+{
+	u32 valPE0, valPE1;
+	int err = 0;
+
+	valPE0 = SDR_READ(SDRN_PESDR_RCSSET(0));
+	valPE1 = SDR_READ(SDRN_PESDR_RCSSET(1));
+
+	/* SDR0_PExRCSSET rstgu */
+	if (!(valPE0 & PESDRx_RCSSET_RSTGU) || !(valPE1 & PESDRx_RCSSET_RSTGU)) {
+		printf("PCIE:  SDR0_PExRCSSET rstgu error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET rstdl */
+	if (!(valPE0 & PESDRx_RCSSET_RSTDL) || !(valPE1 & PESDRx_RCSSET_RSTDL)) {
+		printf("PCIE:  SDR0_PExRCSSET rstdl error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET rstpyn */
+	if ((valPE0 & PESDRx_RCSSET_RSTPYN) || (valPE1 & PESDRx_RCSSET_RSTPYN)) {
+		printf("PCIE:  SDR0_PExRCSSET rstpyn error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET hldplb */
+	if ((valPE0 & PESDRx_RCSSET_HLDPLB) || (valPE1 & PESDRx_RCSSET_HLDPLB)) {
+		printf("PCIE:  SDR0_PExRCSSET hldplb error\n");
+		err = -1;
+	}
+
+	/* SDR0_PExRCSSET rdy */
+	if ((valPE0 & PESDRx_RCSSET_RDY) || (valPE1 & PESDRx_RCSSET_RDY)) {
+		printf("PCIE:  SDR0_PExRCSSET rdy error\n");
+		err = -1;
+	}
+
+	return err;
+}
+
+/*
+ * Initialize PCI Express core as described in User Manual
+ * TODO: double check PE SDR PLL Register with the updated user manual.
+ */
+int ppc4xx_init_pcie(void)
+{
+	if (check_error())
+		return -1;
+
+	return 0;
+}
+#endif /* CONFIG_460EX */
+
+#if defined(CONFIG_405EX)
+static void ppc4xx_setup_utl(u32 port)
+{
+	u32 utl_base;
+
+	/*
+	 * Map UTL registers at 0xef4f_n000 (4K 0xfff mask) PEGPLn_REGMSK
+	 */
+	switch (port) {
+	case 0:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x00000000);
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE0), CONFIG_SYS_PCIE0_UTLBASE);
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001); /* 4k region, valid */
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0);
+		break;
+
+	case 1:
+		mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x00000000);
+		mtdcr(DCRN_PEGPL_REGBAL(PCIE1), CONFIG_SYS_PCIE1_UTLBASE);
+		mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001); /* 4k region, valid */
+		mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0);
+
+		break;
+	}
+	utl_base = (port==0) ? CONFIG_SYS_PCIE0_UTLBASE : CONFIG_SYS_PCIE1_UTLBASE;
+
+	/*
+	 * Set buffer allocations and then assert VRB and TXE.
+	 */
+	out_be32((u32 *)(utl_base + PEUTL_OUTTR),   0x02000000);
+	out_be32((u32 *)(utl_base + PEUTL_INTR),    0x02000000);
+	out_be32((u32 *)(utl_base + PEUTL_OPDBSZ),  0x04000000);
+	out_be32((u32 *)(utl_base + PEUTL_PBBSZ),   0x21000000);
+	out_be32((u32 *)(utl_base + PEUTL_IPHBSZ),  0x02000000);
+	out_be32((u32 *)(utl_base + PEUTL_IPDBSZ),  0x04000000);
+	out_be32((u32 *)(utl_base + PEUTL_RCIRQEN), 0x00f00000);
+	out_be32((u32 *)(utl_base + PEUTL_PCTL),    0x80800066);
+
+	out_be32((u32 *)(utl_base + PEUTL_PBCTL),   0x0800000c);
+	out_be32((u32 *)(utl_base + PEUTL_RCSTA),
+		 in_be32((u32 *)(utl_base + PEUTL_RCSTA)) | 0x000040000);
+}
+
+int ppc4xx_init_pcie(void)
+{
+	/*
+	 * Nothing to do on 405EX
+	 */
+	return 0;
+}
+#endif /* CONFIG_405EX */
+
+/*
+ * Board-specific pcie initialization
+ * Platform code can reimplement ppc4xx_init_pcie_port_hw() if needed
+ */
+
+/*
+ * Initialize various parts of the PCI Express core for our port:
+ *
+ * - Set as a root port and enable max width
+ *   (PXIE0 -> X8, PCIE1 and PCIE2 -> X4).
+ * - Set up UTL configuration.
+ * - Increase SERDES drive strength to levels suggested by AMCC.
+ * - De-assert RSTPYN, RSTDL and RSTGU.
+ *
+ * NOTICE for 440SPE revB chip: PESDRn_UTLSET2 is not set - we leave it
+ * with default setting 0x11310000. The register has new fields,
+ * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core
+ * hang.
+ */
+#if defined(CONFIG_440SPE)
+int __ppc4xx_init_pcie_port_hw(int port, int rootport)
+{
+	u32 val = 1 << 24;
+	u32 utlset1;
+
+	if (rootport) {
+		val = PTYPE_ROOT_PORT << 20;
+		utlset1 = 0x21222222;
+	} else {
+		val = PTYPE_LEGACY_ENDPOINT << 20;
+		utlset1 = 0x20222222;
+	}
+
+	if (port == 0)
+		val |= LNKW_X8 << 12;
+	else
+		val |= LNKW_X4 << 12;
+
+	SDR_WRITE(SDRN_PESDR_DLPSET(port), val);
+	SDR_WRITE(SDRN_PESDR_UTLSET1(port), utlset1);
+	if (!ppc440spe_revB())
+		SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x11000000);
+	SDR_WRITE(SDRN_PESDR_HSSL0SET1(port), 0x35000000);
+	SDR_WRITE(SDRN_PESDR_HSSL1SET1(port), 0x35000000);
+	SDR_WRITE(SDRN_PESDR_HSSL2SET1(port), 0x35000000);
+	SDR_WRITE(SDRN_PESDR_HSSL3SET1(port), 0x35000000);
+	if (port == 0) {
+		SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000);
+		SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000);
+		SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000);
+		SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000);
+	}
+	SDR_WRITE(SDRN_PESDR_RCSSET(port), (SDR_READ(SDRN_PESDR_RCSSET(port)) &
+					    ~(1 << 24 | 1 << 16)) | 1 << 12);
+
+	return 0;
+}
+#endif /* CONFIG_440SPE */
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+int __ppc4xx_init_pcie_port_hw(int port, int rootport)
+{
+	u32 val;
+	u32 utlset1;
+
+	if (rootport)
+		val = PTYPE_ROOT_PORT << 20;
+	else
+		val = PTYPE_LEGACY_ENDPOINT << 20;
+
+	if (port == 0) {
+		val |= LNKW_X1 << 12;
+		utlset1 = 0x20000000;
+	} else {
+		val |= LNKW_X4 << 12;
+		utlset1 = 0x20101101;
+	}
+
+	SDR_WRITE(SDRN_PESDR_DLPSET(port), val);
+	SDR_WRITE(SDRN_PESDR_UTLSET1(port), utlset1);
+	SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01210000);
+
+	switch (port) {
+	case 0:
+		SDR_WRITE(PESDR0_L0CDRCTL, 0x00003230);
+		SDR_WRITE(PESDR0_L0DRV, 0x00000130);
+		SDR_WRITE(PESDR0_L0CLK, 0x00000006);
+
+		SDR_WRITE(PESDR0_PHY_CTL_RST,0x10000000);
+		break;
+
+	case 1:
+		SDR_WRITE(PESDR1_L0CDRCTL, 0x00003230);
+		SDR_WRITE(PESDR1_L1CDRCTL, 0x00003230);
+		SDR_WRITE(PESDR1_L2CDRCTL, 0x00003230);
+		SDR_WRITE(PESDR1_L3CDRCTL, 0x00003230);
+		SDR_WRITE(PESDR1_L0DRV, 0x00000130);
+		SDR_WRITE(PESDR1_L1DRV, 0x00000130);
+		SDR_WRITE(PESDR1_L2DRV, 0x00000130);
+		SDR_WRITE(PESDR1_L3DRV, 0x00000130);
+		SDR_WRITE(PESDR1_L0CLK, 0x00000006);
+		SDR_WRITE(PESDR1_L1CLK, 0x00000006);
+		SDR_WRITE(PESDR1_L2CLK, 0x00000006);
+		SDR_WRITE(PESDR1_L3CLK, 0x00000006);
+
+		SDR_WRITE(PESDR1_PHY_CTL_RST,0x10000000);
+		break;
+	}
+
+	SDR_WRITE(SDRN_PESDR_RCSSET(port), SDR_READ(SDRN_PESDR_RCSSET(port)) |
+		  (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
+
+	/* Poll for PHY reset */
+	switch (port) {
+	case 0:
+		while (!(SDR_READ(PESDR0_RSTSTA) & 0x1))
+			udelay(10);
+		break;
+	case 1:
+		while (!(SDR_READ(PESDR1_RSTSTA) & 0x1))
+			udelay(10);
+		break;
+	}
+
+	SDR_WRITE(SDRN_PESDR_RCSSET(port),
+		  (SDR_READ(SDRN_PESDR_RCSSET(port)) &
+		   ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
+		  PESDRx_RCSSET_RSTPYN);
+
+	return 0;
+}
+#endif /* CONFIG_440SPE */
+
+#if defined(CONFIG_405EX)
+int __ppc4xx_init_pcie_port_hw(int port, int rootport)
+{
+	u32 val;
+
+	if (rootport)
+		val = 0x00401000;
+	else
+		val = 0x00101000;
+
+	SDR_WRITE(SDRN_PESDR_DLPSET(port), val);
+	SDR_WRITE(SDRN_PESDR_UTLSET1(port), 0x00000000);
+	SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01010000);
+	SDR_WRITE(SDRN_PESDR_PHYSET1(port), 0x720F0000);
+	SDR_WRITE(SDRN_PESDR_PHYSET2(port), 0x70600003);
+
+	/* Assert the PE0_PHY reset */
+	SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01010000);
+	udelay(1000);
+
+	/* deassert the PE0_hotreset */
+	if (is_end_point(port))
+		SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01111000);
+	else
+		SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01101000);
+
+	/* poll for phy !reset */
+	while (!(SDR_READ(SDRN_PESDR_PHYSTA(port)) & 0x00001000))
+		;
+
+	/* deassert the PE0_gpl_utl_reset */
+	SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x00101000);
+
+	if (port == 0)
+		mtdcr(DCRN_PEGPL_CFG(PCIE0), 0x10000000);  /* guarded on */
+	else
+		mtdcr(DCRN_PEGPL_CFG(PCIE1), 0x10000000);  /* guarded on */
+
+	return 0;
+}
+#endif /* CONFIG_405EX */
+
+int ppc4xx_init_pcie_port_hw(int port, int rootport)
+__attribute__((weak, alias("__ppc4xx_init_pcie_port_hw")));
+
+/*
+ * We map PCI Express configuration access into the 512MB regions
+ *
+ * NOTICE: revB is very strict about PLB real addressess and ranges to
+ * be mapped for config space; it seems to only work with d_nnnn_nnnn
+ * range (hangs the core upon config transaction attempts when set
+ * otherwise) while revA uses c_nnnn_nnnn.
+ *
+ * For 440SPe revA:
+ *     PCIE0: 0xc_4000_0000
+ *     PCIE1: 0xc_8000_0000
+ *     PCIE2: 0xc_c000_0000
+ *
+ * For 440SPe revB:
+ *     PCIE0: 0xd_0000_0000
+ *     PCIE1: 0xd_2000_0000
+ *     PCIE2: 0xd_4000_0000
+ *
+ * For 405EX:
+ *     PCIE0: 0xa000_0000
+ *     PCIE1: 0xc000_0000
+ *
+ * For 460EX/GT:
+ *     PCIE0: 0xd_0000_0000
+ *     PCIE1: 0xd_2000_0000
+ */
+static inline u64 ppc4xx_get_cfgaddr(int port)
+{
+#if defined(CONFIG_405EX)
+	if (port == 0)
+		return (u64)CONFIG_SYS_PCIE0_CFGBASE;
+	else
+		return (u64)CONFIG_SYS_PCIE1_CFGBASE;
+#endif
+#if defined(CONFIG_440SPE)
+	if (ppc440spe_revB()) {
+		switch (port) {
+		default:	/* to satisfy compiler */
+		case 0:
+			return 0x0000000d00000000ULL;
+		case 1:
+			return 0x0000000d20000000ULL;
+		case 2:
+			return 0x0000000d40000000ULL;
+		}
+	} else {
+		switch (port) {
+		default:	/* to satisfy compiler */
+		case 0:
+			return 0x0000000c40000000ULL;
+		case 1:
+			return 0x0000000c80000000ULL;
+		case 2:
+			return 0x0000000cc0000000ULL;
+		}
+	}
+#endif
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	if (port == 0)
+		return 0x0000000d00000000ULL;
+	else
+		return 0x0000000d20000000ULL;
+#endif
+}
+
+/*
+ *  4xx boards as endpoint and root point setup
+ *                    and
+ *    testing inbound and out bound windows
+ *
+ *  4xx boards can be plugged into another 4xx boards or you can get PCI-E
+ *  cable which can be used to setup loop back from one port to another port.
+ *  Please rememeber that unless there is a endpoint plugged in to root port it
+ *  will not initialize. It is the same in case of endpoint , unless there is
+ *  root port attached it will not initialize.
+ *
+ *  In this release of software all the PCI-E ports are configured as either
+ *  endpoint or rootpoint.In future we will have support for selective ports
+ *  setup as endpoint and root point in single board.
+ *
+ *  Once your board came up as root point , you can verify by reading
+ *  /proc/bus/pci/devices. Where you can see the configuration registers
+ *  of endpoint device attached to the port.
+ *
+ *  Enpoint cofiguration can be verified by connecting 4xx board to any
+ *  host or another 4xx board. Then try to scan the device. In case of
+ *  linux use "lspci" or appripriate os command.
+ *
+ *  How do I verify the inbound and out bound windows ? (4xx to 4xx)
+ *  in this configuration inbound and outbound windows are setup to access
+ *  sram memroy area. SRAM is at 0x4 0000 0000 , on PLB bus. This address
+ *  is mapped at 0x90000000. From u-boot prompt write data 0xb000 0000,
+ *  This is waere your POM(PLB out bound memory window) mapped. then
+ *  read the data from other 4xx board's u-boot prompt at address
+ *  0x9000 0000(SRAM). Data should match.
+ *  In case of inbound , write data to u-boot command prompt at 0xb000 0000
+ *  which is mapped to 0x4 0000 0000. Now on rootpoint yucca u-boot prompt check
+ *  data at 0x9000 0000(SRAM).Data should match.
+ */
+int ppc4xx_init_pcie_port(int port, int rootport)
+{
+	static int core_init;
+	volatile u32 val = 0;
+	int attempts;
+	u64 addr;
+	u32 low, high;
+
+	if (!core_init) {
+		if (ppc4xx_init_pcie())
+			return -1;
+		++core_init;
+	}
+
+	/*
+	 * Initialize various parts of the PCI Express core for our port
+	 */
+	ppc4xx_init_pcie_port_hw(port, rootport);
+
+	/*
+	 * Notice: the following delay has critical impact on device
+	 * initialization - if too short (<50ms) the link doesn't get up.
+	 */
+	mdelay(100);
+
+	val = SDR_READ(SDRN_PESDR_RCSSTS(port));
+	if (val & (1 << 20)) {
+		printf("PCIE%d: PGRST failed %08x\n", port, val);
+		return -1;
+	}
+
+	/*
+	 * Verify link is up
+	 */
+	val = SDR_READ(SDRN_PESDR_LOOP(port));
+	if (!(val & 0x00001000)) {
+		printf("PCIE%d: link is not up.\n", port);
+		return -ENODEV;
+	}
+
+	/*
+	 * Setup UTL registers - but only on revA!
+	 * We use default settings for revB chip.
+	 */
+	if (!ppc440spe_revB())
+		ppc4xx_setup_utl(port);
+
+	/*
+	 * We map PCI Express configuration access into the 512MB regions
+	 */
+	addr = ppc4xx_get_cfgaddr(port);
+	low = U64_TO_U32_LOW(addr);
+	high = U64_TO_U32_HIGH(addr);
+
+	switch (port) {
+	case 0:
+		mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), high);
+		mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), low);
+		mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */
+		break;
+	case 1:
+		mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), high);
+		mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), low);
+		mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */
+		break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	case 2:
+		mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), high);
+		mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), low);
+		mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */
+		break;
+#endif
+	}
+
+	/*
+	 * Check for VC0 active and assert RDY.
+	 */
+	attempts = 10;
+	while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 16))) {
+		if (!(attempts--)) {
+			printf("PCIE%d: VC0 not active\n", port);
+			return -1;
+		}
+		mdelay(1000);
+	}
+	SDR_WRITE(SDRN_PESDR_RCSSET(port),
+		  SDR_READ(SDRN_PESDR_RCSSET(port)) | 1 << 20);
+	mdelay(100);
+
+	return 0;
+}
+
+int ppc4xx_init_pcie_rootport(int port)
+{
+	return ppc4xx_init_pcie_port(port, 1);
+}
+
+int ppc4xx_init_pcie_endport(int port)
+{
+	return ppc4xx_init_pcie_port(port, 0);
+}
+
+void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port)
+{
+	volatile void *mbase = NULL;
+	volatile void *rmbase = NULL;
+
+	pci_set_ops(hose,
+		    pcie_read_config_byte,
+		    pcie_read_config_word,
+		    pcie_read_config_dword,
+		    pcie_write_config_byte,
+		    pcie_write_config_word,
+		    pcie_write_config_dword);
+
+	switch (port) {
+	case 0:
+		mbase = (u32 *)CONFIG_SYS_PCIE0_XCFGBASE;
+		rmbase = (u32 *)CONFIG_SYS_PCIE0_CFGBASE;
+		hose->cfg_data = (u8 *)CONFIG_SYS_PCIE0_CFGBASE;
+		break;
+	case 1:
+		mbase = (u32 *)CONFIG_SYS_PCIE1_XCFGBASE;
+		rmbase = (u32 *)CONFIG_SYS_PCIE1_CFGBASE;
+		hose->cfg_data = (u8 *)CONFIG_SYS_PCIE1_CFGBASE;
+		break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	case 2:
+		mbase = (u32 *)CONFIG_SYS_PCIE2_XCFGBASE;
+		rmbase = (u32 *)CONFIG_SYS_PCIE2_CFGBASE;
+		hose->cfg_data = (u8 *)CONFIG_SYS_PCIE2_CFGBASE;
+		break;
+#endif
+	}
+
+	/*
+	 * Set bus numbers on our root port
+	 */
+	out_8((u8 *)mbase + PCI_PRIMARY_BUS, 0);
+	out_8((u8 *)mbase + PCI_SECONDARY_BUS, 1);
+	out_8((u8 *)mbase + PCI_SUBORDINATE_BUS, 1);
+
+	/*
+	 * Set up outbound translation to hose->mem_space from PLB
+	 * addresses at an offset of 0xd_0000_0000.  We set the low
+	 * bits of the mask to 11 to turn off splitting into 8
+	 * subregions and to enable the outbound translation.
+	 */
+	out_le32(mbase + PECFG_POM0LAH, 0x00000000);
+	out_le32(mbase + PECFG_POM0LAL, CONFIG_SYS_PCIE_MEMBASE +
+		 port * CONFIG_SYS_PCIE_MEMSIZE);
+	debug("PECFG_POM0LA=%08x.%08x\n", in_le32(mbase + PECFG_POM0LAH),
+	      in_le32(mbase + PECFG_POM0LAL));
+
+	switch (port) {
+	case 0:
+		mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), CONFIG_SYS_PCIE_ADDR_HIGH);
+		mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CONFIG_SYS_PCIE_MEMBASE +
+		      port * CONFIG_SYS_PCIE_MEMSIZE);
+		mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff);
+		mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0),
+		      ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+		debug("0:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n",
+		      mfdcr(DCRN_PEGPL_OMR1BAH(PCIE0)),
+		      mfdcr(DCRN_PEGPL_OMR1BAL(PCIE0)),
+		      mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE0)),
+		      mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE0)));
+		break;
+	case 1:
+		mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), CONFIG_SYS_PCIE_ADDR_HIGH);
+		mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CONFIG_SYS_PCIE_MEMBASE +
+		      port * CONFIG_SYS_PCIE_MEMSIZE);
+		mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff);
+		mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1),
+		      ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+		debug("1:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n",
+		      mfdcr(DCRN_PEGPL_OMR1BAH(PCIE1)),
+		      mfdcr(DCRN_PEGPL_OMR1BAL(PCIE1)),
+		      mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE1)),
+		      mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE1)));
+		break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	case 2:
+		mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), CONFIG_SYS_PCIE_ADDR_HIGH);
+		mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CONFIG_SYS_PCIE_MEMBASE +
+		      port * CONFIG_SYS_PCIE_MEMSIZE);
+		mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff);
+		mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2),
+		      ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+		debug("2:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n",
+		      mfdcr(DCRN_PEGPL_OMR1BAH(PCIE2)),
+		      mfdcr(DCRN_PEGPL_OMR1BAL(PCIE2)),
+		      mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE2)),
+		      mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE2)));
+		break;
+#endif
+	}
+
+	/* Set up 4GB inbound memory window at 0 */
+	out_le32(mbase + PCI_BASE_ADDRESS_0, 0);
+	out_le32(mbase + PCI_BASE_ADDRESS_1, 0);
+	out_le32(mbase + PECFG_BAR0HMPA, 0x7ffffff);
+	out_le32(mbase + PECFG_BAR0LMPA, 0);
+
+	out_le32(mbase + PECFG_PIM01SAH, 0xffff0000);
+	out_le32(mbase + PECFG_PIM01SAL, 0x00000000);
+	out_le32(mbase + PECFG_PIM0LAL, 0);
+	out_le32(mbase + PECFG_PIM0LAH, 0);
+	out_le32(mbase + PECFG_PIM1LAL, 0x00000000);
+	out_le32(mbase + PECFG_PIM1LAH, 0x00000004);
+	out_le32(mbase + PECFG_PIMEN, 0x1);
+
+	/* Enable I/O, Mem, and Busmaster cycles */
+	out_le16((u16 *)(mbase + PCI_COMMAND),
+		 in_le16((u16 *)(mbase + PCI_COMMAND)) |
+		 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+	/* Set Device and Vendor Id */
+	out_le16(mbase + 0x200, 0xaaa0 + port);
+	out_le16(mbase + 0x202, 0xbed0 + port);
+
+	/* Set Class Code to PCI-PCI bridge and Revision Id to 1 */
+	out_le32(mbase + 0x208, 0x06040001);
+
+	printf("PCIE%d: successfully set as root-complex\n", port);
+}
+
+int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port)
+{
+	volatile void *mbase = NULL;
+	int attempts = 0;
+
+	pci_set_ops(hose,
+		    pcie_read_config_byte,
+		    pcie_read_config_word,
+		    pcie_read_config_dword,
+		    pcie_write_config_byte,
+		    pcie_write_config_word,
+		    pcie_write_config_dword);
+
+	switch (port) {
+	case 0:
+		mbase = (u32 *)CONFIG_SYS_PCIE0_XCFGBASE;
+		hose->cfg_data = (u8 *)CONFIG_SYS_PCIE0_CFGBASE;
+		break;
+	case 1:
+		mbase = (u32 *)CONFIG_SYS_PCIE1_XCFGBASE;
+		hose->cfg_data = (u8 *)CONFIG_SYS_PCIE1_CFGBASE;
+		break;
+#if defined(CONFIG_SYS_PCIE2_CFGBASE)
+	case 2:
+		mbase = (u32 *)CONFIG_SYS_PCIE2_XCFGBASE;
+		hose->cfg_data = (u8 *)CONFIG_SYS_PCIE2_CFGBASE;
+		break;
+#endif
+	}
+
+	/*
+	 * Set up outbound translation to hose->mem_space from PLB
+	 * addresses at an offset of 0xd_0000_0000.  We set the low
+	 * bits of the mask to 11 to turn off splitting into 8
+	 * subregions and to enable the outbound translation.
+	 */
+	out_le32(mbase + PECFG_POM0LAH, 0x00001ff8);
+	out_le32(mbase + PECFG_POM0LAL, 0x00001000);
+
+	switch (port) {
+	case 0:
+		mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), CONFIG_SYS_PCIE_ADDR_HIGH);
+		mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CONFIG_SYS_PCIE_MEMBASE +
+		      port * CONFIG_SYS_PCIE_MEMSIZE);
+		mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff);
+		mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0),
+		      ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+		break;
+	case 1:
+		mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), CONFIG_SYS_PCIE_ADDR_HIGH);
+		mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CONFIG_SYS_PCIE_MEMBASE +
+		      port * CONFIG_SYS_PCIE_MEMSIZE);
+		mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff);
+		mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1),
+		      ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+		break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+	case 2:
+		mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), CONFIG_SYS_PCIE_ADDR_HIGH);
+		mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CONFIG_SYS_PCIE_MEMBASE +
+		      port * CONFIG_SYS_PCIE_MEMSIZE);
+		mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff);
+		mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2),
+		      ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+		break;
+#endif
+	}
+
+	/* Set up 64MB inbound memory window at 0 */
+	out_le32(mbase + PCI_BASE_ADDRESS_0, 0);
+	out_le32(mbase + PCI_BASE_ADDRESS_1, 0);
+
+	out_le32(mbase + PECFG_PIM01SAH, 0xffffffff);
+	out_le32(mbase + PECFG_PIM01SAL, 0xfc000000);
+
+	/* Setup BAR0 */
+	out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffff);
+	out_le32(mbase + PECFG_BAR0LMPA, 0xfc000000 | PCI_BASE_ADDRESS_MEM_TYPE_64);
+
+	/* Disable BAR1 & BAR2 */
+	out_le32(mbase + PECFG_BAR1MPA, 0);
+	out_le32(mbase + PECFG_BAR2HMPA, 0);
+	out_le32(mbase + PECFG_BAR2LMPA, 0);
+
+	out_le32(mbase + PECFG_PIM0LAL, U64_TO_U32_LOW(CONFIG_SYS_PCIE_INBOUND_BASE));
+	out_le32(mbase + PECFG_PIM0LAH, U64_TO_U32_HIGH(CONFIG_SYS_PCIE_INBOUND_BASE));
+	out_le32(mbase + PECFG_PIMEN, 0x1);
+
+	/* Enable I/O, Mem, and Busmaster cycles */
+	out_le16((u16 *)(mbase + PCI_COMMAND),
+		 in_le16((u16 *)(mbase + PCI_COMMAND)) |
+		 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+	out_le16(mbase + 0x200, 0xcaad);		/* Setting vendor ID */
+	out_le16(mbase + 0x202, 0xfeed);		/* Setting device ID */
+
+	/* Set Class Code to Processor/PPC */
+	out_le32(mbase + 0x208, 0x0b200001);
+
+	attempts = 10;
+	while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 8))) {
+		if (!(attempts--)) {
+			printf("PCIE%d: BME not active\n", port);
+			return -1;
+		}
+		mdelay(1000);
+	}
+
+	printf("PCIE%d: successfully set as endpoint\n", port);
+
+	return 0;
+}
+#endif /* CONFIG_440SPE && CONFIG_PCI */
diff --git a/arch/ppc/cpu/ppc4xx/4xx_uart.c b/arch/ppc/cpu/ppc4xx/4xx_uart.c
new file mode 100644
index 0000000..8de6542
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/4xx_uart.c
@@ -0,0 +1,878 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This source code is dual-licensed.  You may use it under the terms of the
+ * GNU General Public License version 2, or under the license below.
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <watchdog.h>
+#include <ppc4xx.h>
+
+#ifdef CONFIG_SERIAL_MULTI
+#include <serial.h>
+#endif
+
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+#include <malloc.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+    defined(CONFIG_405EX) || defined(CONFIG_440)
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define UART0_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000300)
+#define UART1_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000400)
+#else
+#define UART0_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000200)
+#define UART1_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000300)
+#endif
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+#define UART2_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000600)
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define UART2_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000500)
+#define UART3_BASE	(CONFIG_SYS_PERIPHERAL_BASE + 0x00000600)
+#endif
+
+#if defined(CONFIG_440GP)
+#define CR0_MASK        0x3fff0000
+#define CR0_EXTCLK_ENA  0x00600000
+#define CR0_UDIV_POS    16
+#define UDIV_SUBTRACT	1
+#define UART0_SDR	CPC0_CR0
+#define MFREG(a, d)	d = mfdcr(a)
+#define MTREG(a, d)	mtdcr(a, d)
+#else /* #if defined(CONFIG_440GP) */
+/* all other 440 PPC's access clock divider via sdr register */
+#define CR0_MASK        0xdfffffff
+#define CR0_EXTCLK_ENA  0x00800000
+#define CR0_UDIV_POS    0
+#define UDIV_SUBTRACT	0
+#define UART0_SDR	SDR0_UART0
+#define UART1_SDR	SDR0_UART1
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+    defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define UART2_SDR	SDR0_UART2
+#endif
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+    defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define UART3_SDR	SDR0_UART3
+#endif
+#define MFREG(a, d)	mfsdr(a, d)
+#define MTREG(a, d)	mtsdr(a, d)
+#endif /* #if defined(CONFIG_440GP) */
+#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
+#define UART0_BASE      0xef600300
+#define UART1_BASE      0xef600400
+#define UCR0_MASK       0x0000007f
+#define UCR1_MASK       0x00007f00
+#define UCR0_UDIV_POS   0
+#define UCR1_UDIV_POS   8
+#define UDIV_MAX        127
+#elif defined(CONFIG_405EX)
+#define UART0_BASE	0xef600200
+#define UART1_BASE	0xef600300
+#define CR0_MASK	0x000000ff
+#define CR0_EXTCLK_ENA	0x00800000
+#define CR0_UDIV_POS	0
+#define UDIV_SUBTRACT	0
+#define UART0_SDR	SDR0_UART0
+#define UART1_SDR	SDR0_UART1
+#else /* CONFIG_405GP || CONFIG_405CR */
+#define UART0_BASE      0xef600300
+#define UART1_BASE      0xef600400
+#define CR0_MASK        0x00001fff
+#define CR0_EXTCLK_ENA  0x000000c0
+#define CR0_UDIV_POS    1
+#define UDIV_MAX        32
+#endif
+
+/* using serial port 0 or 1 as U-Boot console ? */
+#if defined(CONFIG_UART1_CONSOLE)
+#define ACTING_UART0_BASE	UART1_BASE
+#define ACTING_UART1_BASE	UART0_BASE
+#else
+#define ACTING_UART0_BASE	UART0_BASE
+#define ACTING_UART1_BASE	UART1_BASE
+#endif
+
+#if defined(CONFIG_405EP) && defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
+#error "External serial clock not supported on AMCC PPC405EP!"
+#endif
+
+#define UART_RBR    0x00
+#define UART_THR    0x00
+#define UART_IER    0x01
+#define UART_IIR    0x02
+#define UART_FCR    0x02
+#define UART_LCR    0x03
+#define UART_MCR    0x04
+#define UART_LSR    0x05
+#define UART_MSR    0x06
+#define UART_SCR    0x07
+#define UART_DLL    0x00
+#define UART_DLM    0x01
+
+/*-----------------------------------------------------------------------------+
+  | Line Status Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncLSRDataReady1            0x01
+#define asyncLSROverrunError1         0x02
+#define asyncLSRParityError1          0x04
+#define asyncLSRFramingError1         0x08
+#define asyncLSRBreakInterrupt1       0x10
+#define asyncLSRTxHoldEmpty1          0x20
+#define asyncLSRTxShiftEmpty1         0x40
+#define asyncLSRRxFifoError1          0x80
+
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+/*-----------------------------------------------------------------------------+
+  | Fifo
+  +-----------------------------------------------------------------------------*/
+typedef struct {
+	char *rx_buffer;
+	ulong rx_put;
+	ulong rx_get;
+} serial_buffer_t;
+
+volatile static serial_buffer_t buf_info;
+#endif
+
+static void serial_init_common(u32 base, u32 udiv, u16 bdiv)
+{
+	PPC4xx_SYS_INFO sys_info;
+	u8 val;
+
+	get_sys_info(&sys_info);
+
+	/* Correct UART frequency in bd-info struct now that
+	 * the UART divisor is available
+	 */
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+	gd->uart_clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
+#else
+	gd->uart_clk = sys_info.freqUART / udiv;
+#endif
+
+	out_8((u8 *)base + UART_LCR, 0x80);	/* set DLAB bit */
+	out_8((u8 *)base + UART_DLL, bdiv);	/* set baudrate divisor */
+	out_8((u8 *)base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
+	out_8((u8 *)base + UART_LCR, 0x03);	/* clear DLAB; set 8 bits, no parity */
+	out_8((u8 *)base + UART_FCR, 0x00);	/* disable FIFO */
+	out_8((u8 *)base + UART_MCR, 0x00);	/* no modem control DTR RTS */
+	val = in_8((u8 *)base + UART_LSR);	/* clear line status */
+	val = in_8((u8 *)base + UART_RBR);	/* read receive buffer */
+	out_8((u8 *)base + UART_SCR, 0x00);	/* set scratchpad */
+	out_8((u8 *)base + UART_IER, 0x00);	/* set interrupt enable reg */
+}
+
+#if (defined(CONFIG_440) || defined(CONFIG_405EX)) &&	\
+    !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
+static void serial_divs (int baudrate, unsigned long *pudiv,
+			 unsigned short *pbdiv)
+{
+	sys_info_t sysinfo;
+	unsigned long div;		/* total divisor udiv * bdiv */
+	unsigned long umin;		/* minimum udiv	*/
+	unsigned short diff;		/* smallest diff */
+	unsigned long udiv;		/* best udiv */
+	unsigned short idiff;		/* current diff */
+	unsigned short ibdiv;		/* current bdiv */
+	unsigned long i;
+	unsigned long est;		/* current estimate */
+
+	get_sys_info(&sysinfo);
+
+	udiv = 32;			/* Assume lowest possible serial clk */
+	div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
+	umin = sysinfo.pllOpbDiv << 1;	/* 2 x OPB divisor */
+	diff = 32;			/* highest possible */
+
+	/* i is the test udiv value -- start with the largest
+	 * possible (32) to minimize serial clock and constrain
+	 * search to umin.
+	 */
+	for (i = 32; i > umin; i--) {
+		ibdiv = div / i;
+		est = i * ibdiv;
+		idiff = (est > div) ? (est-div) : (div-est);
+		if (idiff == 0) {
+			udiv = i;
+			break;      /* can't do better */
+		} else if (idiff < diff) {
+			udiv = i;       /* best so far */
+			diff = idiff;   /* update lowest diff*/
+		}
+	}
+
+	*pudiv = udiv;
+	*pbdiv = div / udiv;
+}
+
+#elif defined(CONFIG_405EZ)
+
+static void serial_divs (int baudrate, unsigned long *pudiv,
+			 unsigned short *pbdiv)
+{
+	sys_info_t sysinfo;
+	unsigned long div;		/* total divisor udiv * bdiv */
+	unsigned long umin;		/* minimum udiv	*/
+	unsigned short diff;		/* smallest diff */
+	unsigned long udiv;		/* best udiv */
+	unsigned short idiff;		/* current diff */
+	unsigned short ibdiv;		/* current bdiv */
+	unsigned long i;
+	unsigned long est;		/* current estimate */
+	unsigned long plloutb;
+	unsigned long cpr_pllc;
+	u32 reg;
+
+	/* check the pll feedback source */
+	mfcpr(CPR0_PLLC, cpr_pllc);
+
+	get_sys_info(&sysinfo);
+
+	plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
+					   sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) *
+		    sysinfo.pllFbkDiv) / sysinfo.pllFwdDivB);
+	udiv = 256;			/* Assume lowest possible serial clk */
+	div = plloutb / (16 * baudrate); /* total divisor */
+	umin = (plloutb / get_OPB_freq()) << 1;	/* 2 x OPB divisor */
+	diff = 256;			/* highest possible */
+
+	/* i is the test udiv value -- start with the largest
+	 * possible (256) to minimize serial clock and constrain
+	 * search to umin.
+	 */
+	for (i = 256; i > umin; i--) {
+		ibdiv = div / i;
+		est = i * ibdiv;
+		idiff = (est > div) ? (est-div) : (div-est);
+		if (idiff == 0) {
+			udiv = i;
+			break;      /* can't do better */
+		} else if (idiff < diff) {
+			udiv = i;       /* best so far */
+			diff = idiff;   /* update lowest diff*/
+		}
+	}
+
+	*pudiv = udiv;
+	mfcpr(CPC0_PERD0, reg);
+	reg &= ~0x0000ffff;
+	reg |= ((udiv - 0) << 8) | (udiv - 0);
+	mtcpr(CPC0_PERD0, reg);
+	*pbdiv = div / udiv;
+}
+#endif /* defined(CONFIG_440) && !defined(CONFIG_SYS_EXT_SERIAL_CLK) */
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+#if defined(CONFIG_440)
+int serial_init_dev(unsigned long base)
+{
+	unsigned long reg;
+	unsigned long udiv;
+	unsigned short bdiv;
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+	unsigned long tmp;
+#endif
+
+	MFREG(UART0_SDR, reg);
+	reg &= ~CR0_MASK;
+
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+	reg |= CR0_EXTCLK_ENA;
+	udiv = 1;
+	tmp  = gd->baudrate * 16;
+	bdiv = (CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
+#else
+	/* For 440, the cpu clock is on divider chain A, UART on divider
+	 * chain B ... so cpu clock is irrelevant. Get the "optimized"
+	 * values that are subject to the 1/2 opb clock constraint
+	 */
+	serial_divs (gd->baudrate, &udiv, &bdiv);
+#endif
+
+	reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;	/* set the UART divisor */
+
+	/*
+	 * Configure input clock to baudrate generator for all
+	 * available serial ports here
+	 */
+	MTREG(UART0_SDR, reg);
+#if defined(UART1_SDR)
+	MTREG(UART1_SDR, reg);
+#endif
+#if defined(UART2_SDR)
+	MTREG(UART2_SDR, reg);
+#endif
+#if defined(UART3_SDR)
+	MTREG(UART3_SDR, reg);
+#endif
+
+	serial_init_common(base, udiv, bdiv);
+
+	return (0);
+}
+
+#else /* !defined(CONFIG_440) */
+
+int serial_init_dev (unsigned long base)
+{
+	unsigned long reg;
+	unsigned long tmp;
+	unsigned long clk;
+	unsigned long udiv;
+	unsigned short bdiv;
+
+#ifdef CONFIG_405EX
+	clk = tmp = 0;
+	mfsdr(UART0_SDR, reg);
+	reg &= ~CR0_MASK;
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+	reg |= CR0_EXTCLK_ENA;
+	udiv = 1;
+	tmp  = gd->baudrate * 16;
+	bdiv = (CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
+#else
+	serial_divs(gd->baudrate, &udiv, &bdiv);
+#endif
+	reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
+
+	/*
+	 * Configure input clock to baudrate generator for all
+	 * available serial ports here
+	 */
+	mtsdr(UART0_SDR, reg);
+
+#if defined(UART1_SDR)
+	mtsdr(UART1_SDR, reg);
+#endif
+
+#elif defined(CONFIG_405EZ)
+	serial_divs(gd->baudrate, &udiv, &bdiv);
+	clk = tmp = reg = 0;
+#else
+#ifdef CONFIG_405EP
+	reg = mfdcr(CPC0_UCR) & ~(UCR0_MASK | UCR1_MASK);
+	clk = gd->cpu_clk;
+	tmp = CONFIG_SYS_BASE_BAUD * 16;
+	udiv = (clk + tmp / 2) / tmp;
+	if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
+		udiv = UDIV_MAX;
+	reg |= (udiv) << UCR0_UDIV_POS;	        /* set the UART divisor */
+	reg |= (udiv) << UCR1_UDIV_POS;	        /* set the UART divisor */
+	mtdcr (CPC0_UCR, reg);
+#else /* CONFIG_405EP */
+	reg = mfdcr(CPC0_CR0) & ~CR0_MASK;
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+	clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
+	udiv = 1;
+	reg |= CR0_EXTCLK_ENA;
+#else
+	clk = gd->cpu_clk;
+#ifdef CONFIG_SYS_405_UART_ERRATA_59
+	udiv = 31;			/* Errata 59: stuck at 31 */
+#else
+	tmp = CONFIG_SYS_BASE_BAUD * 16;
+	udiv = (clk + tmp / 2) / tmp;
+	if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
+		udiv = UDIV_MAX;
+#endif
+#endif
+	reg |= (udiv - 1) << CR0_UDIV_POS;	/* set the UART divisor */
+	mtdcr (CPC0_CR0, reg);
+#endif /* CONFIG_405EP */
+	tmp = gd->baudrate * udiv * 16;
+	bdiv = (clk + tmp / 2) / tmp;
+#endif /* CONFIG_405EX */
+
+	serial_init_common(base, udiv, bdiv);
+
+	return (0);
+}
+
+#endif /* if defined(CONFIG_440) */
+
+void serial_setbrg_dev(unsigned long base)
+{
+	serial_init_dev(base);
+}
+
+void serial_putc_dev(unsigned long base, const char c)
+{
+	int i;
+
+	if (c == '\n')
+		serial_putc_dev(base, '\r');
+
+	/* check THRE bit, wait for transmiter available */
+	for (i = 1; i < 3500; i++) {
+		if ((in_8((u8 *)base + UART_LSR) & 0x20) == 0x20)
+			break;
+		udelay (100);
+	}
+
+	out_8((u8 *)base + UART_THR, c);	/* put character out */
+}
+
+void serial_puts_dev (unsigned long base, const char *s)
+{
+	while (*s)
+		serial_putc_dev (base, *s++);
+}
+
+int serial_getc_dev (unsigned long base)
+{
+	unsigned char status = 0;
+
+	while (1) {
+#if defined(CONFIG_HW_WATCHDOG)
+		WATCHDOG_RESET ();	/* Reset HW Watchdog, if needed */
+#endif	/* CONFIG_HW_WATCHDOG */
+
+		status = in_8((u8 *)base + UART_LSR);
+		if ((status & asyncLSRDataReady1) != 0x0)
+			break;
+
+		if ((status & ( asyncLSRFramingError1 |
+				asyncLSROverrunError1 |
+				asyncLSRParityError1  |
+				asyncLSRBreakInterrupt1 )) != 0) {
+			out_8((u8 *)base + UART_LSR,
+			      asyncLSRFramingError1 |
+			      asyncLSROverrunError1 |
+			      asyncLSRParityError1  |
+			      asyncLSRBreakInterrupt1);
+		}
+	}
+
+	return (0x000000ff & (int) in_8((u8 *)base));
+}
+
+int serial_tstc_dev (unsigned long base)
+{
+	unsigned char status;
+
+	status = in_8((u8 *)base + UART_LSR);
+	if ((status & asyncLSRDataReady1) != 0x0)
+		return (1);
+
+	if ((status & ( asyncLSRFramingError1 |
+			asyncLSROverrunError1 |
+			asyncLSRParityError1  |
+			asyncLSRBreakInterrupt1 )) != 0) {
+		out_8((u8 *)base + UART_LSR,
+		      asyncLSRFramingError1 |
+		      asyncLSROverrunError1 |
+		      asyncLSRParityError1  |
+		      asyncLSRBreakInterrupt1);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+
+void serial_isr (void *arg)
+{
+	int space;
+	int c;
+	const int rx_get = buf_info.rx_get;
+	int rx_put = buf_info.rx_put;
+
+	if (rx_get <= rx_put)
+		space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
+	else
+		space = rx_get - rx_put;
+
+	while (serial_tstc_dev (ACTING_UART0_BASE)) {
+		c = serial_getc_dev (ACTING_UART0_BASE);
+		if (space) {
+			buf_info.rx_buffer[rx_put++] = c;
+			space--;
+		}
+		if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
+			rx_put = 0;
+		if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
+			/* Stop flow by setting RTS inactive */
+			out_8((u8 *)ACTING_UART0_BASE + UART_MCR,
+			      in_8((u8 *)ACTING_UART0_BASE + UART_MCR) &
+			      (0xFF ^ 0x02));
+		}
+	}
+	buf_info.rx_put = rx_put;
+}
+
+void serial_buffered_init (void)
+{
+	serial_puts ("Switching to interrupt driven serial input mode.\n");
+	buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
+	buf_info.rx_put = 0;
+	buf_info.rx_get = 0;
+
+	if (in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10)
+		serial_puts ("Check CTS signal present on serial port: OK.\n");
+	else
+		serial_puts ("WARNING: CTS signal not present on serial port.\n");
+
+	irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
+			      serial_isr /*interrupt_handler_t *handler */ ,
+			      (void *) &buf_info /*void *arg */ );
+
+	/* Enable "RX Data Available" Interrupt on UART */
+	out_8(ACTING_UART0_BASE + UART_IER, 0x01);
+	/* Set DTR active */
+	out_8(ACTING_UART0_BASE + UART_MCR,
+	      in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x01);
+	/* Start flow by setting RTS active */
+	out_8(ACTING_UART0_BASE + UART_MCR,
+	      in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x02);
+	/* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
+	out_8(ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
+}
+
+void serial_buffered_putc (const char c)
+{
+	/* Wait for CTS */
+#if defined(CONFIG_HW_WATCHDOG)
+	while (!(in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10))
+		WATCHDOG_RESET ();
+#else
+	while (!(in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10));
+#endif
+	serial_putc (c);
+}
+
+void serial_buffered_puts (const char *s)
+{
+	serial_puts (s);
+}
+
+int serial_buffered_getc (void)
+{
+	int space;
+	int c;
+	int rx_get = buf_info.rx_get;
+	int rx_put;
+
+#if defined(CONFIG_HW_WATCHDOG)
+	while (rx_get == buf_info.rx_put)
+		WATCHDOG_RESET ();
+#else
+	while (rx_get == buf_info.rx_put);
+#endif
+	c = buf_info.rx_buffer[rx_get++];
+	if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
+		rx_get = 0;
+	buf_info.rx_get = rx_get;
+
+	rx_put = buf_info.rx_put;
+	if (rx_get <= rx_put)
+		space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
+	else
+		space = rx_get - rx_put;
+
+	if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
+		/* Start flow by setting RTS active */
+		out_8(ACTING_UART0_BASE + UART_MCR,
+		      in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x02);
+	}
+
+	return c;
+}
+
+int serial_buffered_tstc (void)
+{
+	return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
+}
+
+#endif	/* CONFIG_SERIAL_SOFTWARE_FIFO */
+
+#if defined(CONFIG_CMD_KGDB)
+/*
+  AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
+  number 0 or number 1
+  - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
+  configuration has been already done
+  - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
+  configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
+*/
+#if (CONFIG_KGDB_SER_INDEX & 2)
+void kgdb_serial_init (void)
+{
+	u8 val;
+	u16 br_reg;
+
+	get_clocks ();
+	br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
+		  5) / 10;
+	/*
+	 * Init onboard 16550 UART
+	 */
+	out_8((u8 *)ACTING_UART1_BASE + UART_LCR, 0x80);	/* set DLAB bit */
+	out_8((u8 *)ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */
+	out_8((u8 *)ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8)); /* set divisor for 9600 baud */
+	out_8((u8 *)ACTING_UART1_BASE + UART_LCR, 0x03);	/* line control 8 bits no parity */
+	out_8((u8 *)ACTING_UART1_BASE + UART_FCR, 0x00);	/* disable FIFO */
+	out_8((u8 *)ACTING_UART1_BASE + UART_MCR, 0x00);	/* no modem control DTR RTS */
+	val = in_8((u8 *)ACTING_UART1_BASE + UART_LSR);		/* clear line status */
+	val = in_8((u8 *)ACTING_UART1_BASE + UART_RBR);		/* read receive buffer */
+	out_8((u8 *)ACTING_UART1_BASE + UART_SCR, 0x00);	/* set scratchpad */
+	out_8((u8 *)ACTING_UART1_BASE + UART_IER, 0x00);	/* set interrupt enable reg */
+}
+
+void putDebugChar (const char c)
+{
+	if (c == '\n')
+		serial_putc ('\r');
+
+	out_8((u8 *)ACTING_UART1_BASE + UART_THR, c);	/* put character out */
+
+	/* check THRE bit, wait for transfer done */
+	while ((in_8((u8 *)ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
+}
+
+void putDebugStr (const char *s)
+{
+	while (*s)
+		serial_putc (*s++);
+}
+
+int getDebugChar (void)
+{
+	unsigned char status = 0;
+
+	while (1) {
+		status = in_8((u8 *)ACTING_UART1_BASE + UART_LSR);
+		if ((status & asyncLSRDataReady1) != 0x0)
+			break;
+
+		if ((status & (asyncLSRFramingError1 |
+			       asyncLSROverrunError1 |
+			       asyncLSRParityError1  |
+			       asyncLSRBreakInterrupt1 )) != 0) {
+			out_8((u8 *)ACTING_UART1_BASE + UART_LSR,
+			      asyncLSRFramingError1 |
+			      asyncLSROverrunError1 |
+			      asyncLSRParityError1  |
+			      asyncLSRBreakInterrupt1);
+		}
+	}
+
+	return (0x000000ff & (int) in_8((u8 *)ACTING_UART1_BASE));
+}
+
+void kgdb_interruptible (int yes)
+{
+	return;
+}
+
+#else	/* ! (CONFIG_KGDB_SER_INDEX & 2) */
+
+void kgdb_serial_init (void)
+{
+	serial_printf ("[on serial] ");
+}
+
+void putDebugChar (int c)
+{
+	serial_putc (c);
+}
+
+void putDebugStr (const char *str)
+{
+	serial_puts (str);
+}
+
+int getDebugChar (void)
+{
+	return serial_getc ();
+}
+
+void kgdb_interruptible (int yes)
+{
+	return;
+}
+#endif	/* (CONFIG_KGDB_SER_INDEX & 2) */
+#endif
+
+
+#if defined(CONFIG_SERIAL_MULTI)
+int serial0_init(void)
+{
+	return (serial_init_dev(UART0_BASE));
+}
+
+int serial1_init(void)
+{
+	return (serial_init_dev(UART1_BASE));
+}
+
+void serial0_setbrg (void)
+{
+	serial_setbrg_dev(UART0_BASE);
+}
+
+void serial1_setbrg (void)
+{
+	serial_setbrg_dev(UART1_BASE);
+}
+
+void serial0_putc(const char c)
+{
+	serial_putc_dev(UART0_BASE,c);
+}
+
+void serial1_putc(const char c)
+{
+	serial_putc_dev(UART1_BASE, c);
+}
+
+void serial0_puts(const char *s)
+{
+	serial_puts_dev(UART0_BASE, s);
+}
+
+void serial1_puts(const char *s)
+{
+	serial_puts_dev(UART1_BASE, s);
+}
+
+int serial0_getc(void)
+{
+	return(serial_getc_dev(UART0_BASE));
+}
+
+int serial1_getc(void)
+{
+	return(serial_getc_dev(UART1_BASE));
+}
+
+int serial0_tstc(void)
+{
+	return (serial_tstc_dev(UART0_BASE));
+}
+
+int serial1_tstc(void)
+{
+	return (serial_tstc_dev(UART1_BASE));
+}
+
+struct serial_device serial0_device =
+{
+	"serial0",
+	"UART0",
+	serial0_init,
+	serial0_setbrg,
+	serial0_getc,
+	serial0_tstc,
+	serial0_putc,
+	serial0_puts,
+};
+
+struct serial_device serial1_device =
+{
+	"serial1",
+	"UART1",
+	serial1_init,
+	serial1_setbrg,
+	serial1_getc,
+	serial1_tstc,
+	serial1_putc,
+	serial1_puts,
+};
+#else
+/*
+ * Wrapper functions
+ */
+int serial_init(void)
+{
+	return serial_init_dev(ACTING_UART0_BASE);
+}
+
+void serial_setbrg(void)
+{
+	serial_setbrg_dev(ACTING_UART0_BASE);
+}
+
+void serial_putc(const char c)
+{
+	serial_putc_dev(ACTING_UART0_BASE, c);
+}
+
+void serial_puts(const char *s)
+{
+	serial_puts_dev(ACTING_UART0_BASE, s);
+}
+
+int serial_getc(void)
+{
+	return serial_getc_dev(ACTING_UART0_BASE);
+}
+
+int serial_tstc(void)
+{
+	return serial_tstc_dev(ACTING_UART0_BASE);
+}
+#endif /* CONFIG_SERIAL_MULTI */
+
+#endif	/* CONFIG_405GP || CONFIG_405CR */
diff --git a/arch/ppc/cpu/ppc4xx/Makefile b/arch/ppc/cpu/ppc4xx/Makefile
new file mode 100644
index 0000000..88d53fb
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/Makefile
@@ -0,0 +1,92 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+START	:= resetvec.o
+START	+= start.o
+
+SOBJS	:= cache.o
+SOBJS	+= dcr.o
+SOBJS	+= kgdb.o
+
+COBJS	:= 40x_spd_sdram.o
+
+COBJS	+= 44x_spd_ddr.o
+COBJS	+= 44x_spd_ddr2.o
+ifdef CONFIG_PPC4xx_DDR_AUTOCALIBRATION
+COBJS	+= 4xx_ibm_ddr2_autocalib.o
+endif
+COBJS	+= 4xx_pci.o
+COBJS	+= 4xx_pcie.o
+COBJS	+= bedbug_405.o
+ifdef CONFIG_CMD_CHIP_CONFIG
+COBJS	+= cmd_chip_config.o
+endif
+COBJS	+= commproc.o
+COBJS	+= cpu.o
+COBJS	+= cpu_init.o
+COBJS	+= denali_data_eye.o
+COBJS	+= denali_spd_ddr2.o
+COBJS	+= ecc.o
+COBJS	+= fdt.o
+COBJS	+= interrupts.o
+COBJS	+= iop480_uart.o
+ifdef CONFIG_CMD_REGINFO
+COBJS	+= reginfo.o
+endif
+COBJS	+= sdram.o
+COBJS	+= speed.o
+COBJS	+= tlb.o
+COBJS	+= traps.o
+COBJS	+= usb.o
+COBJS	+= usb_ohci.o
+COBJS	+= usbdev.o
+ifndef CONFIG_XILINX_440
+COBJS	+= 4xx_uart.o
+COBJS	+= gpio.o
+COBJS	+= miiphy.o
+COBJS	+= uic.o
+else
+COBJS	+= xilinx_irq.o
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/ppc/cpu/ppc4xx/bedbug_405.c b/arch/ppc/cpu/ppc4xx/bedbug_405.c
new file mode 100644
index 0000000..ef11cb6
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/bedbug_405.c
@@ -0,0 +1,308 @@
+/*
+ * Bedbug Functions specific to the PPC405 chip
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/type.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+
+#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_4xx)
+
+#define MAX_BREAK_POINTS 4
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug405_init __P ((void));
+void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char *[]));
+void bedbug405_break_isr __P ((struct pt_regs *));
+int bedbug405_find_empty __P ((void));
+int bedbug405_set __P ((int, unsigned long));
+int bedbug405_clear __P ((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the AMCC PPC405.	Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug405_init (void)
+{
+	int i;
+
+	/* -------------------------------------------------- */
+
+	bug_ctx.hw_debug_enabled = 0;
+	bug_ctx.stopped = 0;
+	bug_ctx.current_bp = 0;
+	bug_ctx.regs = NULL;
+
+	bug_ctx.do_break = bedbug405_do_break;
+	bug_ctx.break_isr = bedbug405_break_isr;
+	bug_ctx.find_empty = bedbug405_find_empty;
+	bug_ctx.set = bedbug405_set;
+	bug_ctx.clear = bedbug405_clear;
+
+	for (i = 1; i <= MAX_BREAK_POINTS; ++i)
+		(*bug_ctx.clear) (i);
+
+	puts ("BEDBUG:ready\n");
+	return;
+}	/* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show one of the hardware breakpoints for the 405.	The "off"
+ * string will disable a specific breakpoint.  The "show" string will
+ * display the current breakpoints.  Otherwise an address will set a
+ * breakpoint at that address.	Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	long addr = 0;		/* Address to break at  */
+	int which_bp;		/* Breakpoint number    */
+
+	/* -------------------------------------------------- */
+
+	if (argc < 2) {
+		cmd_usage(cmdtp);
+		return;
+	}
+
+	/* Turn off a breakpoint */
+
+	if (strcmp (argv[1], "off") == 0) {
+		if (bug_ctx.hw_debug_enabled == 0) {
+			printf ("No breakpoints enabled\n");
+			return;
+		}
+
+		which_bp = simple_strtoul (argv[2], NULL, 10);
+
+		if (bug_ctx.clear)
+			(*bug_ctx.clear) (which_bp);
+
+		printf ("Breakpoint %d removed\n", which_bp);
+		return;
+	}
+
+	/* Show a list of breakpoints */
+
+	if (strcmp (argv[1], "show") == 0) {
+		for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
+
+			switch (which_bp) {
+			case 1:
+				addr = GET_IAC1 ();
+				break;
+			case 2:
+				addr = GET_IAC2 ();
+				break;
+			case 3:
+				addr = GET_IAC3 ();
+				break;
+			case 4:
+				addr = GET_IAC4 ();
+				break;
+			}
+
+			printf ("Breakpoint [%d]: ", which_bp);
+			if (addr == 0)
+				printf ("NOT SET\n");
+			else
+				disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
+						F_RADHEX);
+		}
+		return;
+	}
+
+	/* Set a breakpoint at the address */
+
+	if (!isdigit (argv[1][0])) {
+		cmd_usage(cmdtp);
+		return;
+	}
+
+	addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
+
+	if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
+		printf ("Breakpoint [%d]: ", which_bp);
+		disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
+	}
+
+	return;
+}	/* bedbug405_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint.	 First determine which breakpoint was hit by
+ * looking at the DeBug Status Register (DBSR), clear the breakpoint
+ * and enter a mini main loop.	Stay in the loop until the stopped flag
+ * in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug405_break_isr (struct pt_regs *regs)
+{
+	unsigned long dbsr_val;		/* Value of the DBSR    */
+	unsigned long addr = 0;		/* Address stopped at   */
+
+	/* -------------------------------------------------- */
+
+	dbsr_val = GET_DBSR ();
+
+	if (dbsr_val & DBSR_IA1) {
+		bug_ctx.current_bp = 1;
+		addr = GET_IAC1 ();
+		SET_DBSR (DBSR_IA1);	/* Write a 1 to clear */
+	} else if (dbsr_val & DBSR_IA2) {
+		bug_ctx.current_bp = 2;
+		addr = GET_IAC2 ();
+		SET_DBSR (DBSR_IA2);	/* Write a 1 to clear */
+	} else if (dbsr_val & DBSR_IA3) {
+		bug_ctx.current_bp = 3;
+		addr = GET_IAC3 ();
+		SET_DBSR (DBSR_IA3);	/* Write a 1 to clear */
+	} else if (dbsr_val & DBSR_IA4) {
+		bug_ctx.current_bp = 4;
+		addr = GET_IAC4 ();
+		SET_DBSR (DBSR_IA4);	/* Write a 1 to clear */
+	}
+
+	bedbug_main_loop (addr, regs);
+	return;
+}	/* bedbug405_break_isr */
+
+
+
+/* ======================================================================
+ * Look through all of the hardware breakpoints available to see if one
+ * is unused.
+ * ====================================================================== */
+
+int bedbug405_find_empty (void)
+{
+	/* -------------------------------------------------- */
+
+	if (GET_IAC1 () == 0)
+		return 1;
+
+	if (GET_IAC2 () == 0)
+		return 2;
+
+	if (GET_IAC3 () == 0)
+		return 3;
+
+	if (GET_IAC4 () == 0)
+		return 4;
+
+	return 0;
+}	/* bedbug405_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint.  If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint.  If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0.  Set the break
+ * address in the appropriate IACx register and enable proper address
+ * beakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug405_set (int which_bp, unsigned long addr)
+{
+	/* -------------------------------------------------- */
+
+	/* Only look if which_bp == 0, else use which_bp */
+	if ((bug_ctx.find_empty) && (!which_bp) &&
+		(which_bp = (*bug_ctx.find_empty) ()) == 0) {
+		printf ("All breakpoints in use\n");
+		return 0;
+	}
+
+	if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
+		printf ("Invalid break point # %d\n", which_bp);
+		return 0;
+	}
+
+	if (!bug_ctx.hw_debug_enabled) {
+		SET_MSR (GET_MSR () | 0x200);	/* set MSR[ DE ] */
+		SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
+		bug_ctx.hw_debug_enabled = 1;
+	}
+
+	switch (which_bp) {
+	case 1:
+		SET_IAC1 (addr);
+		SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
+		break;
+
+	case 2:
+		SET_IAC2 (addr);
+		SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
+		break;
+
+	case 3:
+		SET_IAC3 (addr);
+		SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
+		break;
+
+	case 4:
+		SET_IAC4 (addr);
+		SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
+		break;
+	}
+
+	return which_bp;
+}	/* bedbug405_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the appropriate IACx register
+ * to zero and claring the instruction address breakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug405_clear (int which_bp)
+{
+	/* -------------------------------------------------- */
+
+	if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
+		printf ("Invalid break point # (%d)\n", which_bp);
+		return -1;
+	}
+
+	switch (which_bp) {
+	case 1:
+		SET_IAC1 (0);
+		SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
+		break;
+
+	case 2:
+		SET_IAC2 (0);
+		SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
+		break;
+
+	case 3:
+		SET_IAC3 (0);
+		SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
+		break;
+
+	case 4:
+		SET_IAC4 (0);
+		SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
+		break;
+	}
+
+	return 0;
+}	/* bedbug405_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/cache.S b/arch/ppc/cpu/ppc4xx/cache.S
new file mode 100644
index 0000000..269716f
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/cache.S
@@ -0,0 +1,235 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+#include <config.h>
+#include <ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/*
+ * Flush instruction cache.
+ */
+_GLOBAL(invalidate_icache)
+	iccci	r0,r0
+	isync
+	blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+	li	r5,L1_CACHE_BYTES-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,L1_CACHE_SHIFT
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,L1_CACHE_BYTES
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,L1_CACHE_BYTES
+	bdnz	2b
+	sync				/* additional sync needed on g4 */
+	isync
+	blr
+
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+	li	r5,L1_CACHE_BYTES-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,L1_CACHE_SHIFT
+	beqlr
+	mtctr	r4
+
+1:	dcbst	0,r3
+	addi	r3,r3,L1_CACHE_BYTES
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	blr
+
+/*
+ * Write any modified data cache blocks out to memory and invalidate them.
+ * Does not invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+	li	r5,L1_CACHE_BYTES-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,L1_CACHE_SHIFT
+	beqlr
+	mtctr	r4
+
+1:	dcbf	0,r3
+	addi	r3,r3,L1_CACHE_BYTES
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	blr
+
+/*
+ * Like above, but invalidate the D-cache.  This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+	li	r5,L1_CACHE_BYTES-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,L1_CACHE_SHIFT
+	beqlr
+	mtctr	r4
+
+1:	dcbi	0,r3
+	addi	r3,r3,L1_CACHE_BYTES
+	bdnz	1b
+	sync				/* wait for dcbi's to get to ram */
+	blr
+
+/*
+ * 40x cores have 8K or 16K dcache and 32 byte line size.
+ * 44x has a 32K dcache and 32 byte line size.
+ * 8xx has 1, 2, 4, 8K variants.
+ * For now, cover the worst case of the 44x.
+ * Must be called with external interrupts disabled.
+ */
+#define CACHE_NWAYS     64
+#define CACHE_NLINES    32
+
+_GLOBAL(flush_dcache)
+	li	r4,(2 * CACHE_NWAYS * CACHE_NLINES)
+	mtctr	r4
+	lis	r5,0
+1:	lwz	r3,0(r5)		/* Load one word from every line */
+	addi	r5,r5,L1_CACHE_BYTES
+	bdnz	1b
+	sync
+	blr
+
+_GLOBAL(invalidate_dcache)
+	addi	r6,0,0x0000		/* clear GPR 6 */
+	/* Do loop for # of dcache congruence classes. */
+	lis	r7,(CONFIG_SYS_DCACHE_SIZE / L1_CACHE_BYTES / 2)@ha	/* TBS for large sized cache */
+	ori	r7,r7,(CONFIG_SYS_DCACHE_SIZE / L1_CACHE_BYTES / 2)@l
+					/* NOTE: dccci invalidates both */
+	mtctr	r7			/* ways in the D cache */
+..dcloop:
+	dccci	0,r6			/* invalidate line */
+	addi	r6,r6,L1_CACHE_BYTES	/* bump to next line */
+	bdnz	..dcloop
+	sync
+	blr
+
+/*
+ * Cache functions.
+ *
+ * NOTE: currently the 440s run with dcache _disabled_ once relocated to DRAM,
+ * although for some cache-ralated calls stubs have to be provided to satisfy
+ * symbols resolution.
+ * Icache-related functions are used in POST framework.
+ *
+ */
+#ifdef CONFIG_440
+
+       .globl  dcache_disable
+       .globl  dcache_enable
+       .globl  icache_disable
+       .globl  icache_enable
+dcache_disable:
+dcache_enable:
+icache_disable:
+icache_enable:
+	blr
+
+	.globl	dcache_status
+	.globl	icache_status
+dcache_status:
+icache_status:
+	mr	r3,  0
+	blr
+
+#else /* CONFIG_440 */
+
+	.globl	icache_enable
+icache_enable:
+	mflr	r8
+	bl	invalidate_icache
+	mtlr	r8
+	isync
+	addis	r3,r0, 0xc000	      /* set bit 0 */
+	mticcr	r3
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	addis	r3,r0, 0x0000	      /* clear bit 0 */
+	mticcr	r3
+	isync
+	blr
+
+	.globl	icache_status
+icache_status:
+	mficcr	r3
+	srwi	r3, r3, 31	/* >>31 => select bit 0 */
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	mflr	r8
+	bl	invalidate_dcache
+	mtlr	r8
+	isync
+	addis	r3,r0, 0x8000	      /* set bit 0 */
+	mtdccr	r3
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mflr	r8
+	bl	flush_dcache
+	mtlr	r8
+	addis	r3,r0, 0x0000	      /* clear bit 0 */
+	mtdccr	r3
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfdccr	r3
+	srwi	r3, r3, 31	/* >>31 => select bit 0 */
+	blr
+
+#endif /* CONFIG_440 */
diff --git a/arch/ppc/cpu/ppc4xx/cmd_chip_config.c b/arch/ppc/cpu/ppc4xx/cmd_chip_config.c
new file mode 100644
index 0000000..ba57211
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/cmd_chip_config.c
@@ -0,0 +1,148 @@
+/*
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2009
+ * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.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 <command.h>
+#include <i2c.h>
+#include <asm/ppc4xx_config.h>
+#include <asm/io.h>
+
+static void print_configs(int cur_config_nr)
+{
+	int i;
+
+	for (i = 0; i < ppc4xx_config_count; i++) {
+		printf("%-16s - %s", ppc4xx_config_val[i].label,
+		       ppc4xx_config_val[i].description);
+		if (i == cur_config_nr)
+			printf(" ***");
+		printf("\n");
+	}
+
+}
+
+static int do_chip_config(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int i;
+	int ret;
+	int cur_config_nr = -1;
+	u8 cur_config[CONFIG_4xx_CONFIG_BLOCKSIZE];
+
+	/*
+	 * First switch to correct I2C bus. This is I2C bus 0
+	 * for all currently available 4xx derivats.
+	 */
+	I2C_SET_BUS(0);
+
+#ifdef CONFIG_CMD_EEPROM
+	ret = eeprom_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+			  CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+			  cur_config, CONFIG_4xx_CONFIG_BLOCKSIZE);
+#else
+	ret = i2c_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+		       CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+		       1, cur_config, CONFIG_4xx_CONFIG_BLOCKSIZE);
+#endif
+	if (ret) {
+		printf("Error reading EEPROM at addr 0x%x\n",
+		       CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+		return -1;
+	}
+
+	/*
+	 * Search the current configuration
+	 */
+	for (i = 0; i < ppc4xx_config_count; i++) {
+		if (memcmp(cur_config, ppc4xx_config_val[i].val,
+			   CONFIG_4xx_CONFIG_BLOCKSIZE) == 0)
+			cur_config_nr = i;
+	}
+
+	if (cur_config_nr == -1) {
+		printf("Warning: The I2C bootstrap values don't match any"
+		       " of the available options!\n");
+		printf("I2C bootstrap EEPROM values are (I2C address 0x%02x):\n",
+			CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+		for (i = 0; i < CONFIG_4xx_CONFIG_BLOCKSIZE; i++) {
+			printf("%02x ", cur_config[i]);
+		}
+		printf("\n");
+	}
+
+	if (argc < 2) {
+		printf("Available configurations (I2C address 0x%02x):\n",
+		       CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+		print_configs(cur_config_nr);
+		return 0;
+	}
+
+	for (i = 0; i < ppc4xx_config_count; i++) {
+		/*
+		 * Search for configuration name/label
+		 */
+		if (strcmp(argv[1], ppc4xx_config_val[i].label) == 0) {
+			printf("Using configuration:\n%-16s - %s\n",
+			       ppc4xx_config_val[i].label,
+			       ppc4xx_config_val[i].description);
+
+#ifdef CONFIG_CMD_EEPROM
+			ret = eeprom_write(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+					   CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+					   ppc4xx_config_val[i].val,
+					   CONFIG_4xx_CONFIG_BLOCKSIZE);
+#else
+			ret = i2c_write(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+					CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+					1, ppc4xx_config_val[i].val,
+					CONFIG_4xx_CONFIG_BLOCKSIZE);
+#endif
+			udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+			if (ret) {
+				printf("Error updating EEPROM at addr 0x%x\n",
+				       CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+				return -1;
+			}
+
+			printf("done (dump via 'i2c md %x 0.1 %x')\n",
+			       CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+			       CONFIG_4xx_CONFIG_BLOCKSIZE);
+			printf("Reset the board for the changes to"
+			       " take effect\n");
+			return 0;
+		}
+	}
+
+	printf("Configuration %s not found!\n", argv[1]);
+	print_configs(cur_config_nr);
+	return -1;
+}
+
+U_BOOT_CMD(
+	chip_config,	2,	0,	do_chip_config,
+	"program the I2C bootstrap EEPROM",
+	"[config-label]"
+);
diff --git a/arch/ppc/cpu/ppc4xx/commproc.c b/arch/ppc/cpu/ppc4xx/commproc.c
new file mode 100644
index 0000000..a1696d3
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/commproc.c
@@ -0,0 +1,77 @@
+/*
+ * (C) Copyright 2000-2004
+ * 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
+ *
+ *
+ * Atapted for ppc4XX by Denis Peter
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
+
+#if defined(CONFIG_SYS_POST_WORD_ADDR)
+# define _POST_ADDR	((CONFIG_SYS_OCM_DATA_ADDR) + (CONFIG_SYS_POST_WORD_ADDR))
+#elif defined(CONFIG_SYS_POST_ALT_WORD_ADDR)
+# define _POST_ADDR	(CONFIG_SYS_POST_ALT_WORD_ADDR)
+#endif
+
+void post_word_store (ulong a)
+{
+	volatile void *save_addr = (volatile void *)(_POST_ADDR);
+
+	out_be32(save_addr, a);
+}
+
+ulong post_word_load (void)
+{
+	volatile void *save_addr = (volatile void *)(_POST_ADDR);
+
+	return in_be32(save_addr);
+}
+
+#endif	/* CONFIG_POST || CONFIG_LOGBUFFER*/
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+void bootcount_store (ulong a)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_OCM_DATA_ADDR + CONFIG_SYS_BOOTCOUNT_ADDR);
+
+	save_addr[0] = a;
+	save_addr[1] = BOOTCOUNT_MAGIC;
+}
+
+ulong bootcount_load (void)
+{
+	volatile ulong *save_addr =
+		(volatile ulong *)(CONFIG_SYS_OCM_DATA_ADDR + CONFIG_SYS_BOOTCOUNT_ADDR);
+
+	if (save_addr[1] != BOOTCOUNT_MAGIC)
+		return 0;
+	else
+		return save_addr[0];
+}
+
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/arch/ppc/cpu/ppc4xx/config.mk b/arch/ppc/cpu/ppc4xx/config.mk
new file mode 100644
index 0000000..ea4d707
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/config.mk
@@ -0,0 +1,37 @@
+#
+# (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
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+PLATFORM_CPPFLAGS += -DCONFIG_4xx -ffixed-r2 -mstring -msoft-float
+
+cfg=$(shell grep configs $(OBJTREE)/include/config.h | sed 's/.*<\(configs.*\)>/\1/')
+is440:=$(shell grep CONFIG_440 $(TOPDIR)/include/$(cfg))
+
+ifneq (,$(findstring CONFIG_440,$(is440)))
+PLATFORM_CPPFLAGS += -Wa,-m440 -mcpu=440
+else
+PLATFORM_CPPFLAGS += -Wa,-m405 -mcpu=405
+endif
+
+# Use default linker script.  Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/ppc/cpu/ppc4xx/u-boot.lds
diff --git a/arch/ppc/cpu/ppc4xx/cpu.c b/arch/ppc/cpu/ppc4xx/cpu.c
new file mode 100644
index 0000000..e1a023b
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/cpu.c
@@ -0,0 +1,754 @@
+/*
+ * (C) Copyright 2000-2007
+ * 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
+ */
+
+/*
+ * 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>
+#include <netdev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_reset(void);
+
+/*
+ * To provide an interface to detect CPU number for boards that support
+ * more then one CPU, we implement the "weak" default functions here.
+ *
+ * Returns CPU number
+ */
+int __get_cpu_num(void)
+{
+	return NA_OR_UNKNOWN_CPU;
+}
+int get_cpu_num(void) __attribute__((weak, alias("__get_cpu_num")));
+
+#if defined(CONFIG_PCI)
+#if defined(CONFIG_405GP) || \
+    defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+
+#define PCI_ASYNC
+
+static int pci_async_enabled(void)
+{
+#if defined(CONFIG_405GP)
+	return (mfdcr(CPC0_PSR) & PSR_PCI_ASYNC_EN);
+#endif
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	unsigned long val;
+
+	mfsdr(SDR0_SDSTP1, val);
+	return (val & SDR0_SDSTP1_PAME_MASK);
+#endif
+}
+#endif
+#endif /* CONFIG_PCI */
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_IOP480) && \
+    !defined(CONFIG_405) && !defined(CONFIG_405EX)
+int pci_arbiter_enabled(void)
+{
+#if defined(CONFIG_405GP)
+	return (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN);
+#endif
+
+#if defined(CONFIG_405EP)
+	return (mfdcr(CPC0_PCI) & CPC0_PCI_ARBIT_EN);
+#endif
+
+#if defined(CONFIG_440GP)
+	return (mfdcr(CPC0_STRP1) & CPC0_STRP1_PAE_MASK);
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+	unsigned long val;
+
+	mfsdr(SDR0_XCR, val);
+	return (val & 0x80000000);
+#endif
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	unsigned long val;
+
+	mfsdr(SDR0_PCI0, val);
+	return (val & 0x80000000);
+#endif
+}
+#endif
+
+#if defined(CONFIG_405EP)
+#define I2C_BOOTROM
+
+static int i2c_bootrom_enabled(void)
+{
+#if defined(CONFIG_405EP)
+	return (mfdcr(CPC0_BOOT) & CPC0_BOOT_SEP);
+#else
+	unsigned long val;
+
+	mfsdr(SDR0_SDCS0, val);
+	return (val & SDR0_SDCS_SDD);
+#endif
+}
+#endif
+
+#if defined(CONFIG_440GX)
+#define SDR0_PINSTP_SHIFT	29
+static char *bootstrap_str[] = {
+	"EBC (16 bits)",
+	"EBC (8 bits)",
+	"EBC (32 bits)",
+	"EBC (8 bits)",
+	"PCI",
+	"I2C (Addr 0x54)",
+	"Reserved",
+	"I2C (Addr 0x50)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'B', 'D', 'E', 'x', 'F' };
+#endif
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+#define SDR0_PINSTP_SHIFT	30
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"PCI",
+	"I2C (Addr 0x54)",
+	"I2C (Addr 0x50)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D'};
+#endif
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+#define SDR0_PINSTP_SHIFT	29
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"PCI",
+	"NAND (8 bits)",
+	"EBC (16 bits)",
+	"EBC (16 bits)",
+	"I2C (Addr 0x54)",
+	"PCI",
+	"I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
+#endif
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define SDR0_PINSTP_SHIFT	29
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"EBC (16 bits)",
+	"EBC (16 bits)",
+	"NAND (8 bits)",
+	"PCI",
+	"I2C (Addr 0x54)",
+	"PCI",
+	"I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define SDR0_PINSTP_SHIFT	29
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"EBC (16 bits)",
+	"PCI",
+	"PCI",
+	"EBC (16 bits)",
+	"NAND (8 bits)",
+	"I2C (Addr 0x54)",	/* A8 */
+	"I2C (Addr 0x52)",	/* A4 */
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
+#endif
+
+#if defined(CONFIG_460SX)
+#define SDR0_PINSTP_SHIFT	29
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"EBC (16 bits)",
+	"EBC (32 bits)",
+	"NAND (8 bits)",
+	"I2C (Addr 0x54)",      /* A8 */
+	"I2C (Addr 0x52)",      /* A4 */
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G' };
+#endif
+
+#if defined(CONFIG_405EZ)
+#define SDR0_PINSTP_SHIFT	28
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"SPI (fast)",
+	"NAND (512 page, 4 addr cycle)",
+	"I2C (Addr 0x50)",
+	"EBC (32 bits)",
+	"I2C (Addr 0x50)",
+	"NAND (2K page, 5 addr cycle)",
+	"I2C (Addr 0x50)",
+	"EBC (16 bits)",
+	"Reserved",
+	"NAND (2K page, 4 addr cycle)",
+	"I2C (Addr 0x50)",
+	"NAND (512 page, 3 addr cycle)",
+	"I2C (Addr 0x50)",
+	"SPI (slow)",
+	"I2C (Addr 0x50)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', \
+				 'I', 'x', 'K', 'L', 'M', 'N', 'O', 'P' };
+#endif
+
+#if defined(CONFIG_405EX)
+#define SDR0_PINSTP_SHIFT	29
+static char *bootstrap_str[] = {
+	"EBC (8 bits)",
+	"EBC (16 bits)",
+	"EBC (16 bits)",
+	"NAND (8 bits)",
+	"NAND (8 bits)",
+	"I2C (Addr 0x54)",
+	"EBC (8 bits)",
+	"I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
+#endif
+
+#if defined(SDR0_PINSTP_SHIFT)
+static int bootstrap_option(void)
+{
+	unsigned long val;
+
+	mfsdr(SDR0_PINSTP, val);
+	return ((val & 0xf0000000) >> SDR0_PINSTP_SHIFT);
+}
+#endif /* SDR0_PINSTP_SHIFT */
+
+
+#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 (CPC0_CR0, mfdcr (CPC0_CR0) | 0x80000000);	/* Set SWE */
+	mtdcr (CPC0_SYS0, sys0);
+	mtdcr (CPC0_SYS1, sys1);
+	mtdcr (CPC0_CR0, mfdcr (CPC0_CR0) & ~0x80000000);	/* Clr SWE */
+	mtspr (SPRN_DBCR0, 0x20000000);	/* Reset the chip */
+
+	return 1;
+}
+#endif
+
+
+int checkcpu (void)
+{
+#if !defined(CONFIG_405)	/* not used on Xilinx 405 FPGA implementations */
+	uint pvr = get_pvr();
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	u32 reg;
+#endif
+
+#if !defined(CONFIG_IOP480)
+	char addstr[64] = "";
+	sys_info_t sys_info;
+	int cpu_num;
+
+	cpu_num = get_cpu_num();
+	if (cpu_num >= 0)
+		printf("CPU%d:  ", cpu_num);
+	else
+		puts("CPU:   ");
+
+	get_sys_info(&sys_info);
+
+#if defined(CONFIG_XILINX_440)
+	puts("IBM PowerPC 4");
+#else
+	puts("AMCC PowerPC 4");
+#endif
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+    defined(CONFIG_405EX)
+	puts("05");
+#endif
+#if defined(CONFIG_440)
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	puts("60");
+#else
+	puts("40");
+#endif
+#endif
+
+	switch (pvr) {
+	case PVR_405GP_RB:
+		puts("GP Rev. B");
+		break;
+
+	case PVR_405GP_RC:
+		puts("GP Rev. C");
+		break;
+
+	case PVR_405GP_RD:
+		puts("GP Rev. D");
+		break;
+
+#ifdef CONFIG_405GP
+	case PVR_405GP_RE: /* 405GP rev E and 405CR rev C have same PVR */
+		puts("GP Rev. E");
+		break;
+#endif
+
+	case PVR_405CR_RA:
+		puts("CR Rev. A");
+		break;
+
+	case PVR_405CR_RB:
+		puts("CR Rev. B");
+		break;
+
+#ifdef CONFIG_405CR
+	case PVR_405CR_RC: /* 405GP rev E and 405CR rev C have same PVR */
+		puts("CR Rev. C");
+		break;
+#endif
+
+	case PVR_405GPR_RB:
+		puts("GPr Rev. B");
+		break;
+
+	case PVR_405EP_RB:
+		puts("EP Rev. B");
+		break;
+
+	case PVR_405EZ_RA:
+		puts("EZ Rev. A");
+		break;
+
+	case PVR_405EX1_RA:
+		puts("EX Rev. A");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_405EXR2_RA:
+		puts("EXr Rev. A");
+		strcpy(addstr, "No Security support");
+		break;
+
+	case PVR_405EX1_RC:
+		puts("EX Rev. C");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_405EX2_RC:
+		puts("EX Rev. C");
+		strcpy(addstr, "No Security support");
+		break;
+
+	case PVR_405EXR1_RC:
+		puts("EXr Rev. C");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_405EXR2_RC:
+		puts("EXr Rev. C");
+		strcpy(addstr, "No Security support");
+		break;
+
+	case PVR_405EX1_RD:
+		puts("EX Rev. D");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_405EX2_RD:
+		puts("EX Rev. D");
+		strcpy(addstr, "No Security support");
+		break;
+
+	case PVR_405EXR1_RD:
+		puts("EXr Rev. D");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_405EXR2_RD:
+		puts("EXr Rev. D");
+		strcpy(addstr, "No Security support");
+		break;
+
+#if defined(CONFIG_440)
+	case PVR_440GP_RB:
+		puts("GP Rev. 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:
+		puts("GP Rev. C");
+		break;
+
+	case PVR_440GX_RA:
+		puts("GX Rev. A");
+		break;
+
+	case PVR_440GX_RB:
+		puts("GX Rev. B");
+		break;
+
+	case PVR_440GX_RC:
+		puts("GX Rev. C");
+		break;
+
+	case PVR_440GX_RF:
+		puts("GX Rev. F");
+		break;
+
+	case PVR_440EP_RA:
+		puts("EP Rev. A");
+		break;
+
+#ifdef CONFIG_440EP
+	case PVR_440EP_RB: /* 440EP rev B and 440GR rev A have same PVR */
+		puts("EP Rev. B");
+		break;
+
+	case PVR_440EP_RC: /* 440EP rev C and 440GR rev B have same PVR */
+		puts("EP Rev. C");
+		break;
+#endif /*  CONFIG_440EP */
+
+#ifdef CONFIG_440GR
+	case PVR_440GR_RA: /* 440EP rev B and 440GR rev A have same PVR */
+		puts("GR Rev. A");
+		break;
+
+	case PVR_440GR_RB: /* 440EP rev C and 440GR rev B have same PVR */
+		puts("GR Rev. B");
+		break;
+#endif /* CONFIG_440GR */
+#endif /* CONFIG_440 */
+
+#ifdef CONFIG_440EPX
+	case PVR_440EPX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+		puts("EPx Rev. A");
+		strcpy(addstr, "Security/Kasumi support");
+		break;
+
+	case PVR_440EPX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+		puts("EPx Rev. A");
+		strcpy(addstr, "No Security/Kasumi support");
+		break;
+#endif /* CONFIG_440EPX */
+
+#ifdef CONFIG_440GRX
+	case PVR_440GRX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+		puts("GRx Rev. A");
+		strcpy(addstr, "Security/Kasumi support");
+		break;
+
+	case PVR_440GRX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+		puts("GRx Rev. A");
+		strcpy(addstr, "No Security/Kasumi support");
+		break;
+#endif /* CONFIG_440GRX */
+
+	case PVR_440SP_6_RAB:
+		puts("SP Rev. A/B");
+		strcpy(addstr, "RAID 6 support");
+		break;
+
+	case PVR_440SP_RAB:
+		puts("SP Rev. A/B");
+		strcpy(addstr, "No RAID 6 support");
+		break;
+
+	case PVR_440SP_6_RC:
+		puts("SP Rev. C");
+		strcpy(addstr, "RAID 6 support");
+		break;
+
+	case PVR_440SP_RC:
+		puts("SP Rev. C");
+		strcpy(addstr, "No RAID 6 support");
+		break;
+
+	case PVR_440SPe_6_RA:
+		puts("SPe Rev. A");
+		strcpy(addstr, "RAID 6 support");
+		break;
+
+	case PVR_440SPe_RA:
+		puts("SPe Rev. A");
+		strcpy(addstr, "No RAID 6 support");
+		break;
+
+	case PVR_440SPe_6_RB:
+		puts("SPe Rev. B");
+		strcpy(addstr, "RAID 6 support");
+		break;
+
+	case PVR_440SPe_RB:
+		puts("SPe Rev. B");
+		strcpy(addstr, "No RAID 6 support");
+		break;
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	case PVR_460EX_RA:
+		puts("EX Rev. A");
+		strcpy(addstr, "No Security/Kasumi support");
+		break;
+
+	case PVR_460EX_SE_RA:
+		puts("EX Rev. A");
+		strcpy(addstr, "Security/Kasumi support");
+		break;
+
+	case PVR_460EX_RB:
+		puts("EX Rev. B");
+		mfsdr(SDR0_ECID3, reg);
+		if (reg & 0x00100000)
+			strcpy(addstr, "No Security/Kasumi support");
+		else
+			strcpy(addstr, "Security/Kasumi support");
+		break;
+
+	case PVR_460GT_RA:
+		puts("GT Rev. A");
+		strcpy(addstr, "No Security/Kasumi support");
+		break;
+
+	case PVR_460GT_SE_RA:
+		puts("GT Rev. A");
+		strcpy(addstr, "Security/Kasumi support");
+		break;
+
+	case PVR_460GT_RB:
+		puts("GT Rev. B");
+		mfsdr(SDR0_ECID3, reg);
+		if (reg & 0x00100000)
+			strcpy(addstr, "No Security/Kasumi support");
+		else
+			strcpy(addstr, "Security/Kasumi support");
+		break;
+#endif
+
+	case PVR_460SX_RA:
+		puts("SX Rev. A");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_460SX_RA_V1:
+		puts("SX Rev. A");
+		strcpy(addstr, "No Security support");
+		break;
+
+	case PVR_460GX_RA:
+		puts("GX Rev. A");
+		strcpy(addstr, "Security support");
+		break;
+
+	case PVR_460GX_RA_V1:
+		puts("GX Rev. A");
+		strcpy(addstr, "No Security support");
+		break;
+
+	case PVR_VIRTEX5:
+		puts("x5 VIRTEX5");
+		break;
+
+	default:
+		printf (" UNKNOWN (PVR=%08x)", pvr);
+		break;
+	}
+
+	printf (" at %s MHz (PLB=%lu OPB=%lu EBC=%lu",
+		strmhz(buf, clock),
+		sys_info.freqPLB / 1000000,
+		get_OPB_freq() / 1000000,
+		sys_info.freqEBC / 1000000);
+#if defined(CONFIG_PCI) && \
+	(defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+	 defined(CONFIG_440GR) || defined(CONFIG_440GRX))
+	printf(" PCI=%lu MHz", sys_info.freqPCI / 1000000);
+#endif
+	printf(")\n");
+
+	if (addstr[0] != 0)
+		printf("       %s\n", addstr);
+
+#if defined(I2C_BOOTROM)
+	printf ("       I2C boot EEPROM %sabled\n", i2c_bootrom_enabled() ? "en" : "dis");
+#endif	/* I2C_BOOTROM */
+#if defined(SDR0_PINSTP_SHIFT)
+	printf ("       Bootstrap Option %c - ", bootstrap_char[bootstrap_option()]);
+	printf ("Boot ROM Location %s", bootstrap_str[bootstrap_option()]);
+#ifdef CONFIG_NAND_U_BOOT
+	puts(", booting from NAND");
+#endif /* CONFIG_NAND_U_BOOT */
+	putc('\n');
+#endif	/* SDR0_PINSTP_SHIFT */
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_405EX)
+	printf ("       Internal PCI arbiter %sabled", pci_arbiter_enabled() ? "en" : "dis");
+#endif
+
+#if defined(CONFIG_PCI) && defined(PCI_ASYNC)
+	if (pci_async_enabled()) {
+		printf (", PCI async ext clock used");
+	} else {
+		printf (", PCI sync clock at %lu MHz",
+		       sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
+	}
+#endif
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_405EX)
+	putc('\n');
+#endif
+
+#if defined(CONFIG_405EP) || defined(CONFIG_405EZ) || defined(CONFIG_405EX)
+	printf ("       16 kB I-Cache 16 kB D-Cache");
+#elif defined(CONFIG_440)
+	printf ("       32 kB I-Cache 32 kB D-Cache");
+#else
+	printf ("       16 kB I-Cache %d kB D-Cache",
+		((pvr | 0x00000001) == PVR_405GPR_RB) ? 16 : 8);
+#endif
+#endif /* !defined(CONFIG_IOP480) */
+
+#if defined(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
+
+#endif /* !defined(CONFIG_405) */
+
+	putc ('\n');
+
+	return 0;
+}
+
+int ppc440spe_revB() {
+	unsigned int pvr;
+
+	pvr = get_pvr();
+	if ((pvr == PVR_440SPe_6_RB) || (pvr == PVR_440SPe_RB))
+		return 1;
+	else
+		return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_BOARD_RESET)
+	board_reset();
+#else
+#if defined(CONFIG_SYS_4xx_RESET_TYPE)
+	mtspr(SPRN_DBCR0, CONFIG_SYS_4xx_RESET_TYPE << 28);
+#else
+	/*
+	 * Initiate system reset in debug control register DBCR
+	 */
+	mtspr(SPRN_DBCR0, 0x30000000);
+#endif /* defined(CONFIG_SYS_4xx_RESET_TYPE) */
+#endif /* defined(CONFIG_BOARD_RESET) */
+
+	return 1;
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+#if !defined(CONFIG_IOP480)
+	sys_info_t  sys_info;
+
+	get_sys_info(&sys_info);
+	return (sys_info.freqProcessor);
+#else
+	return (66000000);
+#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(SPRN_TSR, 0x40000000);
+}
+#endif	/* CONFIG_WATCHDOG */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_PPC4xx_EMAC)
+	ppc_4xx_eth_initialize(bis);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/ppc4xx/cpu_init.c b/arch/ppc/cpu/ppc4xx/cpu_init.c
new file mode 100644
index 0000000..8a6e545
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/cpu_init.c
@@ -0,0 +1,456 @@
+/*
+ * (C) Copyright 2000-2007
+ * 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 <watchdog.h>
+#include <ppc4xx_enet.h>
+#include <asm/processor.h>
+#include <asm/gpio.h>
+#include <ppc4xx.h>
+
+#if defined(CONFIG_405GP)  || defined(CONFIG_405EP)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#ifndef CONFIG_SYS_PLL_RECONFIG
+#define CONFIG_SYS_PLL_RECONFIG	0
+#endif
+
+void reconfigure_pll(u32 new_cpu_freq)
+{
+#if defined(CONFIG_440EPX)
+	int	reset_needed = 0;
+	u32	reg, temp;
+	u32	prbdv0, target_prbdv0,				/* CLK_PRIMBD */
+		fwdva, target_fwdva, fwdvb, target_fwdvb,	/* CLK_PLLD */
+		fbdv, target_fbdv, lfbdv, target_lfbdv,
+		perdv0,	target_perdv0,				/* CLK_PERD */
+		spcid0,	target_spcid0;				/* CLK_SPCID */
+
+	/* Reconfigure clocks if necessary.
+	 * See PPC440EPx User's Manual, sections 8.2 and 14 */
+	if (new_cpu_freq == 667) {
+		target_prbdv0 = 2;
+		target_fwdva = 2;
+		target_fwdvb = 4;
+		target_fbdv = 20;
+		target_lfbdv = 1;
+		target_perdv0 = 4;
+		target_spcid0 = 4;
+
+		mfcpr(CPR0_PRIMBD0, reg);
+		temp = (reg & PRBDV_MASK) >> 24;
+		prbdv0 = temp ? temp : 8;
+		if (prbdv0 != target_prbdv0) {
+			reg &= ~PRBDV_MASK;
+			reg |= ((target_prbdv0 == 8 ? 0 : target_prbdv0) << 24);
+			mtcpr(CPR0_PRIMBD0, reg);
+			reset_needed = 1;
+		}
+
+		mfcpr(CPR0_PLLD, reg);
+
+		temp = (reg & PLLD_FWDVA_MASK) >> 16;
+		fwdva = temp ? temp : 16;
+
+		temp = (reg & PLLD_FWDVB_MASK) >> 8;
+		fwdvb = temp ? temp : 8;
+
+		temp = (reg & PLLD_FBDV_MASK) >> 24;
+		fbdv = temp ? temp : 32;
+
+		temp = (reg & PLLD_LFBDV_MASK);
+		lfbdv = temp ? temp : 64;
+
+		if (fwdva != target_fwdva || fbdv != target_fbdv || lfbdv != target_lfbdv) {
+			reg &= ~(PLLD_FWDVA_MASK | PLLD_FWDVB_MASK |
+				 PLLD_FBDV_MASK | PLLD_LFBDV_MASK);
+			reg |= ((target_fwdva == 16 ? 0 : target_fwdva) << 16) |
+				((target_fwdvb == 8 ? 0 : target_fwdvb) << 8) |
+				((target_fbdv == 32 ? 0 : target_fbdv) << 24) |
+				(target_lfbdv == 64 ? 0 : target_lfbdv);
+			mtcpr(CPR0_PLLD, reg);
+			reset_needed = 1;
+		}
+
+		mfcpr(CPR0_PERD, reg);
+		perdv0 = (reg & CPR0_PERD_PERDV0_MASK) >> 24;
+		if (perdv0 != target_perdv0) {
+			reg &= ~CPR0_PERD_PERDV0_MASK;
+			reg |= (target_perdv0 << 24);
+			mtcpr(CPR0_PERD, reg);
+			reset_needed = 1;
+		}
+
+		mfcpr(CPR0_SPCID, reg);
+		temp = (reg & CPR0_SPCID_SPCIDV0_MASK) >> 24;
+		spcid0 = temp ? temp : 4;
+		if (spcid0 != target_spcid0) {
+			reg &= ~CPR0_SPCID_SPCIDV0_MASK;
+			reg |= ((target_spcid0 == 4 ? 0 : target_spcid0) << 24);
+			mtcpr(CPR0_SPCID, reg);
+			reset_needed = 1;
+		}
+	}
+
+	/* Get current value of FWDVA.*/
+	mfcpr(CPR0_PLLD, reg);
+	temp = (reg & PLLD_FWDVA_MASK) >> 16;
+
+	/*
+	 * Check to see if FWDVA has been set to value of 1. if it has we must
+	 * modify it.
+	 */
+	if (temp == 1) {
+		mfcpr(CPR0_PLLD, reg);
+		/* Get current value of fbdv.  */
+		temp = (reg & PLLD_FBDV_MASK) >> 24;
+		fbdv = temp ? temp : 32;
+		/* Get current value of lfbdv. */
+		temp = (reg & PLLD_LFBDV_MASK);
+		lfbdv = temp ? temp : 64;
+		/*
+		 * Load register that contains current boot strapping option.
+		 */
+		mfcpr(CPR0_ICFG, reg);
+		/* Shift strapping option into low 3 bits.*/
+		reg = (reg >> 28);
+
+		if ((reg == BOOT_STRAP_OPTION_A) || (reg == BOOT_STRAP_OPTION_B) ||
+		    (reg == BOOT_STRAP_OPTION_D) || (reg == BOOT_STRAP_OPTION_E)) {
+			/*
+			 * Get current value of FWDVA. Assign current FWDVA to
+			 * new FWDVB.
+			 */
+			mfcpr(CPR0_PLLD, reg);
+			target_fwdvb = (reg & PLLD_FWDVA_MASK) >> 16;
+			fwdvb = target_fwdvb ? target_fwdvb : 8;
+			/*
+			 * Get current value of FWDVB. Assign current FWDVB to
+			 * new FWDVA.
+			 */
+			target_fwdva = (reg & PLLD_FWDVB_MASK) >> 8;
+			fwdva = target_fwdva ? target_fwdva : 16;
+			/*
+			 * Update CPR0_PLLD with switched FWDVA and FWDVB.
+			 */
+			reg &= ~(PLLD_FWDVA_MASK | PLLD_FWDVB_MASK |
+				PLLD_FBDV_MASK | PLLD_LFBDV_MASK);
+			reg |= ((fwdva == 16 ? 0 : fwdva) << 16) |
+				((fwdvb == 8 ? 0 : fwdvb) << 8) |
+				((fbdv == 32 ? 0 : fbdv) << 24) |
+				(lfbdv == 64 ? 0 : lfbdv);
+			mtcpr(CPR0_PLLD, reg);
+			/* Acknowledge that a reset is required. */
+			reset_needed = 1;
+		}
+	}
+
+	if (reset_needed) {
+		/*
+		 * Set reload inhibit so configuration will persist across
+		 * processor resets
+		 */
+		mfcpr(CPR0_ICFG, reg);
+		reg &= ~CPR0_ICFG_RLI_MASK;
+		reg |= 1 << 31;
+		mtcpr(CPR0_ICFG, reg);
+
+		/* Reset processor if configuration changed */
+		__asm__ __volatile__ ("sync; isync");
+		mtspr(SPRN_DBCR0, 0x20000000);
+	}
+#endif
+}
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Reconfigure PLL if necessary,
+ * set up the memory map,
+ * initialize a bunch of registers
+ */
+void
+cpu_init_f (void)
+{
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_440GX) || defined(CONFIG_460EX)
+	u32 val;
+#endif
+
+	reconfigure_pll(CONFIG_SYS_PLL_RECONFIG);
+
+#if (defined(CONFIG_405EP) || defined (CONFIG_405EX)) && !defined(CONFIG_SYS_4xx_GPIO_TABLE)
+	/*
+	 * GPIO0 setup (select GPIO or alternate function)
+	 */
+#if defined(CONFIG_SYS_GPIO0_OR)
+	out32(GPIO0_OR, CONFIG_SYS_GPIO0_OR);		/* set initial state of output pins	*/
+#endif
+#if defined(CONFIG_SYS_GPIO0_ODR)
+	out32(GPIO0_ODR, CONFIG_SYS_GPIO0_ODR);	/* open-drain select			*/
+#endif
+	out32(GPIO0_OSRH, CONFIG_SYS_GPIO0_OSRH);	/* output select			*/
+	out32(GPIO0_OSRL, CONFIG_SYS_GPIO0_OSRL);
+	out32(GPIO0_ISR1H, CONFIG_SYS_GPIO0_ISR1H);	/* input select				*/
+	out32(GPIO0_ISR1L, CONFIG_SYS_GPIO0_ISR1L);
+	out32(GPIO0_TSRH, CONFIG_SYS_GPIO0_TSRH);	/* three-state select			*/
+	out32(GPIO0_TSRL, CONFIG_SYS_GPIO0_TSRL);
+#if defined(CONFIG_SYS_GPIO0_ISR2H)
+	out32(GPIO0_ISR2H, CONFIG_SYS_GPIO0_ISR2H);
+	out32(GPIO0_ISR2L, CONFIG_SYS_GPIO0_ISR2L);
+#endif
+#if defined (CONFIG_SYS_GPIO0_TCR)
+	out32(GPIO0_TCR, CONFIG_SYS_GPIO0_TCR);	/* enable output driver for outputs	*/
+#endif
+#endif /* CONFIG_405EP ... && !CONFIG_SYS_4xx_GPIO_TABLE */
+
+#if defined (CONFIG_405EP)
+	/*
+	 * Set EMAC noise filter bits
+	 */
+	mtdcr(CPC0_EPCTL, CPC0_EPRCSR_E0NFE | CPC0_EPRCSR_E1NFE);
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
+	gpio_set_chip_configuration();
+#endif /* CONFIG_SYS_4xx_GPIO_TABLE */
+
+	/*
+	 * External Bus Controller (EBC) Setup
+	 */
+#if (defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))
+#if (defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+     defined(CONFIG_405EX) || defined(CONFIG_405))
+	/*
+	 * Move the next instructions into icache, since these modify the flash
+	 * we are running from!
+	 */
+	asm volatile("	bl	0f"		::: "lr");
+	asm volatile("0:	mflr	3"		::: "r3");
+	asm volatile("	addi	4, 0, 14"	::: "r4");
+	asm volatile("	mtctr	4"		::: "ctr");
+	asm volatile("1:	icbt	0, 3");
+	asm volatile("	addi	3, 3, 32"	::: "r3");
+	asm volatile("	bdnz	1b"		::: "ctr", "cr0");
+	asm volatile("	addis	3, 0, 0x0"	::: "r3");
+	asm volatile("	ori	3, 3, 0xA000"	::: "r3");
+	asm volatile("	mtctr	3"		::: "ctr");
+	asm volatile("2:	bdnz	2b"		::: "ctr", "cr0");
+#endif
+
+	mtebc(PB0AP, CONFIG_SYS_EBC_PB0AP);
+	mtebc(PB0CR, CONFIG_SYS_EBC_PB0CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB1AP) && defined(CONFIG_SYS_EBC_PB1CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 1))
+	mtebc(PB1AP, CONFIG_SYS_EBC_PB1AP);
+	mtebc(PB1CR, CONFIG_SYS_EBC_PB1CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB2AP) && defined(CONFIG_SYS_EBC_PB2CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 2))
+	mtebc(PB2AP, CONFIG_SYS_EBC_PB2AP);
+	mtebc(PB2CR, CONFIG_SYS_EBC_PB2CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB3AP) && defined(CONFIG_SYS_EBC_PB3CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 3))
+	mtebc(PB3AP, CONFIG_SYS_EBC_PB3AP);
+	mtebc(PB3CR, CONFIG_SYS_EBC_PB3CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB4AP) && defined(CONFIG_SYS_EBC_PB4CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 4))
+	mtebc(PB4AP, CONFIG_SYS_EBC_PB4AP);
+	mtebc(PB4CR, CONFIG_SYS_EBC_PB4CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB5AP) && defined(CONFIG_SYS_EBC_PB5CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 5))
+	mtebc(PB5AP, CONFIG_SYS_EBC_PB5AP);
+	mtebc(PB5CR, CONFIG_SYS_EBC_PB5CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB6AP) && defined(CONFIG_SYS_EBC_PB6CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 6))
+	mtebc(PB6AP, CONFIG_SYS_EBC_PB6AP);
+	mtebc(PB6CR, CONFIG_SYS_EBC_PB6CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB7AP) && defined(CONFIG_SYS_EBC_PB7CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 7))
+	mtebc(PB7AP, CONFIG_SYS_EBC_PB7AP);
+	mtebc(PB7CR, CONFIG_SYS_EBC_PB7CR);
+#endif
+
+#if defined (CONFIG_SYS_EBC_CFG)
+	mtebc(EBC0_CFG, CONFIG_SYS_EBC_CFG);
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+	val = mfspr(tcr);
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+	val |= 0xb8000000;      /* generate system reset after 1.34 seconds */
+#elif defined(CONFIG_440EPX)
+	val |= 0xb0000000;      /* generate system reset after 1.34 seconds */
+#else
+	val |= 0xf0000000;      /* generate system reset after 2.684 seconds */
+#endif
+#if defined(CONFIG_SYS_4xx_RESET_TYPE)
+	val &= ~0x30000000;			/* clear WRC bits */
+	val |= CONFIG_SYS_4xx_RESET_TYPE << 28;	/* set board specific WRC type */
+#endif
+	mtspr(tcr, val);
+
+	val = mfspr(tsr);
+	val |= 0x80000000;      /* enable watchdog timer */
+	mtspr(tsr, val);
+
+	reset_4xx_watchdog();
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_440GX)
+	/* Take the GX out of compatibility mode
+	 * Travis Sawyer, 9 Mar 2004
+	 * NOTE: 440gx user manual inconsistency here
+	 *       Compatibility mode and Ethernet Clock select are not
+	 *       correct in the manual
+	 */
+	mfsdr(SDR0_MFR, val);
+	val &= ~0x10000000;
+	mtsdr(SDR0_MFR,val);
+#endif /* CONFIG_440GX */
+
+#if defined(CONFIG_460EX)
+	/*
+	 * Set SDR0_AHB_CFG[A2P_INCR4] (bit 24) and
+	 * clear SDR0_AHB_CFG[A2P_PROT2] (bit 25) for a new 460EX errata
+	 * regarding concurrent use of AHB USB OTG, USB 2.0 host and SATA
+	 */
+	mfsdr(SDR0_AHB_CFG, val);
+	val |= 0x80;
+	val &= ~0x40;
+	mtsdr(SDR0_AHB_CFG, val);
+	mfsdr(SDR0_USB2HOST_CFG, val);
+	val &= ~0xf00;
+	val |= 0x400;
+	mtsdr(SDR0_USB2HOST_CFG, val);
+#endif /* CONFIG_460EX */
+
+#if defined(CONFIG_405EX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT)  || \
+    defined(CONFIG_460SX)
+	/*
+	 * Set PLB4 arbiter (Segment 0 and 1) to 4 deep pipeline read
+	 */
+	mtdcr(PLB0_ACR, (mfdcr(PLB0_ACR) & ~PLB0_ACR_RDP_MASK) |
+	      PLB0_ACR_RDP_4DEEP);
+	mtdcr(PLB1_ACR, (mfdcr(PLB1_ACR) & ~PLB1_ACR_RDP_MASK) |
+	      PLB1_ACR_RDP_4DEEP);
+#endif /* CONFIG_440SP/SPE || CONFIG_460EX/GT || CONFIG_405EX */
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CONFIG_405GP)
+	uint pvr = get_pvr();
+
+	/*
+	 * Set edge conditioning circuitry on PPC405GPr
+	 * for compatibility to existing PPC405GP designs.
+	 */
+	if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
+		mtdcr(CPC0_ECR, 0x60606000);
+	}
+#endif  /* defined(CONFIG_405GP) */
+
+	return 0;
+}
+
+#if defined(CONFIG_PCI) && \
+	(defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+	 defined(CONFIG_440GR) || defined(CONFIG_440GRX))
+/*
+ * 440EP(x)/GR(x) PCI async/sync clocking restriction:
+ *
+ * In asynchronous PCI mode, the synchronous PCI clock must meet
+ * certain requirements. The following equation describes the
+ * relationship that must be maintained between the asynchronous PCI
+ * clock and synchronous PCI clock. Select an appropriate PCI:PLB
+ * ratio to maintain the relationship:
+ *
+ * AsyncPCIClk - 1MHz <= SyncPCIclock <= (2 * AsyncPCIClk) - 1MHz
+ */
+static int ppc4xx_pci_sync_clock_ok(u32 sync, u32 async)
+{
+	if (((async - 1000000) > sync) || (sync > ((2 * async) - 1000000)))
+		return 0;
+	else
+		return 1;
+}
+
+int ppc4xx_pci_sync_clock_config(u32 async)
+{
+	sys_info_t sys_info;
+	u32 sync;
+	int div;
+	u32 reg;
+	u32 spcid_val[] = {
+		CPR0_SPCID_SPCIDV0_DIV1, CPR0_SPCID_SPCIDV0_DIV2,
+		CPR0_SPCID_SPCIDV0_DIV3, CPR0_SPCID_SPCIDV0_DIV4 };
+
+	get_sys_info(&sys_info);
+	sync = sys_info.freqPCI;
+
+	/*
+	 * First check if the equation above is met
+	 */
+	if (!ppc4xx_pci_sync_clock_ok(sync, async)) {
+		/*
+		 * Reconfigure PCI sync clock to meet the equation.
+		 * Start with highest possible PCI sync frequency
+		 * (divider 1).
+		 */
+		for (div = 1; div <= 4; div++) {
+			sync = sys_info.freqPLB / div;
+			if (ppc4xx_pci_sync_clock_ok(sync, async))
+			    break;
+		}
+
+		if (div <= 4) {
+			mtcpr(CPR0_SPCID, spcid_val[div]);
+
+			mfcpr(CPR0_ICFG, reg);
+			reg |= CPR0_ICFG_RLI_MASK;
+			mtcpr(CPR0_ICFG, reg);
+
+			/* do chip reset */
+			mtspr(SPRN_DBCR0, 0x20000000);
+		} else {
+			/* Impossible to configure the PCI sync clock */
+			return -1;
+		}
+	}
+
+	return 0;
+}
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/dcr.S b/arch/ppc/cpu/ppc4xx/dcr.S
new file mode 100644
index 0000000..93465a3
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/dcr.S
@@ -0,0 +1,198 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <config.h>
+
+#if defined(CONFIG_4xx) && defined(CONFIG_CMD_SETGETDCR)
+
+#include <ppc4xx.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>
+
+#define _ASMLANGUAGE
+
+/*****************************************************************************
+ *
+ *  XXX - DANGER
+ *        These routines make use of self modifying code.  DO NOT CALL THEM
+ *	  UNTIL THEY ARE RELOCATED TO RAM.  Additionally, I do not
+ *	  recommend them for use in anything other than an interactive
+ *        debugging environment.  This is mainly due to performance reasons.
+ *
+ ****************************************************************************/
+
+/*
+ * static void _create_MFDCR(unsigned short dcrn)
+ *
+ * Builds a 'mfdcr' instruction for get_dcr
+ * function.
+ */
+		.section ".text"
+		.align 2
+		.type	 _create_MFDCR,@function
+_create_MFDCR:
+		/*
+		 * Build up a 'mfdcr' instruction formatted as follows:
+		 *
+		 *  OPCD |   RT   |    DCRF      |     XO       | CR |
+		 * ---------------|--------------|--------------|----|
+		 * 0   5 | 6   10 | 11        20 | 21        30 | 31 |
+		 *       |        |    DCRN      |              |    |
+		 *   31  |  %r3   | (5..9|0..4)  |      323     |  0 |
+		 *
+		 * Where:
+		 *	OPCD = opcode - 31
+		 *	RT   = destination register - %r3 return register
+		 *	DCRF = DCRN # with upper and lower halves swapped
+		 *	XO   = extended opcode - 323
+		 *	CR   = CR[CR0] NOT undefined - 0
+		 */
+		rlwinm	r0, r3, 27, 27, 31	/* OPCD = 31 */
+		rlwinm	r3, r3, 5, 22, 26
+		or	r3, r3, r0
+		slwi	r3, r3, 10
+		oris	r3, r3, 0x3e30		/* RT = %r3 */
+		ori	r3, r3, 323		/* XO = 323 */
+		slwi	r3, r3, 1		/* CR = 0 */
+
+		mflr	r4
+		stw	r3, 0(r4)		/* Store instr in get_dcr() */
+		dcbst	r0, r4			/* Make sure val is written out */
+		sync				/* Wait for write to complete */
+		icbi	r0, r4			/* Make sure old instr is dumped */
+		isync				/* Wait for icbi to complete */
+
+		blr
+.Lfe1:		.size	 _create_MFDCR,.Lfe1-_create_MFDCR
+/* end _create_MFDCR() */
+
+/*
+ * static void _create_MTDCR(unsigned short dcrn, unsigned long value)
+ *
+ * Builds a 'mtdcr' instruction for set_dcr
+ * function.
+ */
+		.section ".text"
+		.align 2
+		.type	 _create_MTDCR,@function
+_create_MTDCR:
+		/*
+		 * Build up a 'mtdcr' instruction formatted as follows:
+		 *
+		 *  OPCD |   RS   |    DCRF      |     XO       | CR |
+		 * ---------------|--------------|--------------|----|
+		 * 0   5 | 6   10 | 11        20 | 21        30 | 31 |
+		 *       |        |    DCRN      |              |    |
+		 *   31  |  %r3   | (5..9|0..4)  |      451     |  0 |
+		 *
+		 * Where:
+		 *	OPCD = opcode - 31
+		 *	RS   = source register - %r4
+		 *	DCRF = dest. DCRN # with upper and lower halves swapped
+		 *	XO   = extended opcode - 451
+		 *	CR   = CR[CR0] NOT undefined - 0
+		 */
+		rlwinm	r0, r3, 27, 27, 31	/* OPCD = 31 */
+		rlwinm	r3, r3, 5, 22, 26
+		or	r3, r3, r0
+		slwi	r3, r3, 10
+		oris	r3, r3, 0x3e40		/* RS = %r4 */
+		ori	r3, r3, 451		/* XO = 451 */
+		slwi	r3, r3, 1		/* CR = 0 */
+
+		mflr	r5
+		stw	r3, 0(r5)		/* Store instr in set_dcr() */
+		dcbst	r0, r5			/* Make sure val is written out */
+		sync				/* Wait for write to complete */
+		icbi	r0, r5			/* Make sure old instr is dumped */
+		isync				/* Wait for icbi to complete */
+
+		blr
+.Lfe2:		.size	 _create_MTDCR,.Lfe2-_create_MTDCR
+/* end _create_MTDCR() */
+
+
+/*
+ * unsigned long get_dcr(unsigned short dcrn)
+ *
+ * Return a given DCR's value.
+ */
+		/* */
+		/* XXX - This is self modifying code, hence */
+		/* it is in the data section. */
+		/* */
+		.section ".data"
+		.align	2
+		.globl	get_dcr
+		.type	get_dcr,@function
+get_dcr:
+		mflr	r0			/* Get link register */
+		stwu	r1, -32(r1)		/* Save back chain and move SP */
+		stw	r0, +36(r1)		/* Save link register */
+
+		bl	_create_MFDCR		/* Build following instruction */
+		/* XXX - we build this instuction up on the fly. */
+		.long	0			/* Get DCR's value */
+
+		lwz	r0, +36(r1)		/* Get saved link register */
+		mtlr	r0			/* Restore link register */
+		addi	r1, r1, +32		/* Remove frame from stack */
+		blr				/* Return to calling function */
+.Lfe3:		.size	get_dcr,.Lfe3-get_dcr
+/* end get_dcr() */
+
+
+/*
+ * unsigned void set_dcr(unsigned short dcrn, unsigned long value)
+ *
+ * Return a given DCR's value.
+ */
+		/*
+		 * XXX - This is self modifying code, hence
+		 * it is in the data section.
+		 */
+		.section ".data"
+		.align	2
+		.globl	set_dcr
+		.type	set_dcr,@function
+set_dcr:
+		mflr	r0			/* Get link register */
+		stwu	r1, -32(r1)		/* Save back chain and move SP */
+		stw	r0, +36(r1)		/* Save link register */
+
+		bl	_create_MTDCR		/* Build following instruction */
+		/* XXX - we build this instuction up on the fly. */
+		.long	0			/* Set DCR's value */
+
+		lwz	r0, +36(r1)		/* Get saved link register */
+		mtlr	r0			/* Restore link register */
+		addi	r1, r1, +32		/* Remove frame from stack */
+		blr				/* Return to calling function */
+.Lfe4:		.size	set_dcr,.Lfe4-set_dcr
+/* end set_dcr() */
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/denali_data_eye.c b/arch/ppc/cpu/ppc4xx/denali_data_eye.c
new file mode 100644
index 0000000..15a9b4f
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/denali_data_eye.c
@@ -0,0 +1,389 @@
+/*
+ * arch/ppc/cpu/ppc4xx/denali_data_eye.c
+ * Extracted from board/amcc/sequoia/sdram.c by Larry Johnson <lrj@acm.org>.
+ *
+ * (C) Copyright 2006
+ * Sylvie Gohl,             AMCC/IBM, gohl.sylvie@fr.ibm.com
+ * Jacqueline Pira-Ferriol, AMCC/IBM, jpira-ferriol@fr.ibm.com
+ * Thierry Roman,           AMCC/IBM, thierry_roman@fr.ibm.com
+ * Alain Saurel,            AMCC/IBM, alain.saurel@fr.ibm.com
+ * Robert Snyder,           AMCC/IBM, rob.snyder@fr.ibm.com
+ *
+ * (C) Copyright 2006-2007
+ * Stefan Roese, DENX Software Engineering, sr@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
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <ppc4xx.h>
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+/*-----------------------------------------------------------------------------+
+ * denali_wait_for_dlllock.
+ +----------------------------------------------------------------------------*/
+int denali_wait_for_dlllock(void)
+{
+	u32 val;
+	int wait;
+
+	/* -----------------------------------------------------------+
+	 * Wait for the DCC master delay line to finish calibration
+	 * ----------------------------------------------------------*/
+	for (wait = 0; wait != 0xffff; ++wait) {
+		mfsdram(DDR0_17, val);
+		if (DDR0_17_DLLLOCKREG_DECODE(val)) {
+			/* dlllockreg bit on */
+			return 0;
+		}
+	}
+	debug("0x%04x: DDR0_17 Value (dlllockreg bit): 0x%08x\n", wait, val);
+	debug("Waiting for dlllockreg bit to raise\n");
+	return -1;
+}
+
+#if defined(CONFIG_DDR_DATA_EYE)
+#define DDR_DCR_BASE 0x10
+#define ddrcfga  (DDR_DCR_BASE+0x0)	/* DDR configuration address reg */
+#define ddrcfgd  (DDR_DCR_BASE+0x1)	/* DDR configuration data reg    */
+
+/*-----------------------------------------------------------------------------+
+ * wait_for_dram_init_complete.
+ +----------------------------------------------------------------------------*/
+static int wait_for_dram_init_complete(void)
+{
+	unsigned long val;
+	int wait = 0;
+
+	/* --------------------------------------------------------------+
+	 * Wait for 'DRAM initialization complete' bit in status register
+	 * -------------------------------------------------------------*/
+	mtdcr(ddrcfga, DDR0_00);
+
+	while (wait != 0xffff) {
+		val = mfdcr(ddrcfgd);
+		if ((val & DDR0_00_INT_STATUS_BIT6) == DDR0_00_INT_STATUS_BIT6)
+			/* 'DRAM initialization complete' bit */
+			return 0;
+		else
+			wait++;
+	}
+	debug("DRAM initialization complete bit in status register did not "
+	      "rise\n");
+	return -1;
+}
+
+#define NUM_TRIES 64
+#define NUM_READS 10
+
+/*-----------------------------------------------------------------------------+
+ * denali_core_search_data_eye.
+ +----------------------------------------------------------------------------*/
+void denali_core_search_data_eye(void)
+{
+	int k, j;
+	u32 val;
+	u32 wr_dqs_shift, dqs_out_shift, dll_dqs_delay_X;
+	u32 max_passing_cases = 0, wr_dqs_shift_with_max_passing_cases = 0;
+	u32 passing_cases = 0, dll_dqs_delay_X_sw_val = 0;
+	u32 dll_dqs_delay_X_start_window = 0, dll_dqs_delay_X_end_window = 0;
+	volatile u32 *ram_pointer;
+	u32 test[NUM_TRIES] = {
+		0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55
+	};
+
+	ram_pointer = (volatile u32 *)(CONFIG_SYS_SDRAM_BASE);
+
+	for (wr_dqs_shift = 64; wr_dqs_shift < 96; wr_dqs_shift++) {
+		/* for (wr_dqs_shift=1; wr_dqs_shift<96; wr_dqs_shift++) { */
+
+		/* -----------------------------------------------------------+
+		 * De-assert 'start' parameter.
+		 * ----------------------------------------------------------*/
+		mtdcr(ddrcfga, DDR0_02);
+		val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
+		    DDR0_02_START_OFF;
+		mtdcr(ddrcfgd, val);
+
+		/* -----------------------------------------------------------+
+		 * Set 'wr_dqs_shift'
+		 * ----------------------------------------------------------*/
+		mtdcr(ddrcfga, DDR0_09);
+		val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK) |
+		    DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift);
+		mtdcr(ddrcfgd, val);
+
+		/* -----------------------------------------------------------+
+		 * Set 'dqs_out_shift' = wr_dqs_shift + 32
+		 * ----------------------------------------------------------*/
+		dqs_out_shift = wr_dqs_shift + 32;
+		mtdcr(ddrcfga, DDR0_22);
+		val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK) |
+		    DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift);
+		mtdcr(ddrcfgd, val);
+
+		passing_cases = 0;
+
+		for (dll_dqs_delay_X = 1; dll_dqs_delay_X < 64;
+		     dll_dqs_delay_X++) {
+			/* for (dll_dqs_delay_X=1; dll_dqs_delay_X<128;
+			   dll_dqs_delay_X++) { */
+			/* -----------------------------------------------------------+
+			 * Set 'dll_dqs_delay_X'.
+			 * ----------------------------------------------------------*/
+			/* dll_dqs_delay_0 */
+			mtdcr(ddrcfga, DDR0_17);
+			val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK)
+			    | DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X);
+			mtdcr(ddrcfgd, val);
+			/* dll_dqs_delay_1 to dll_dqs_delay_4 */
+			mtdcr(ddrcfga, DDR0_18);
+			val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK)
+			    | DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X)
+			    | DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X)
+			    | DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X)
+			    | DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X);
+			mtdcr(ddrcfgd, val);
+			/* dll_dqs_delay_5 to dll_dqs_delay_8 */
+			mtdcr(ddrcfga, DDR0_19);
+			val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK)
+			    | DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X)
+			    | DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X)
+			    | DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X)
+			    | DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X);
+			mtdcr(ddrcfgd, val);
+			/* clear any ECC errors */
+			mtdcr(ddrcfga, DDR0_00);
+			mtdcr(ddrcfgd,
+			      mfdcr(ddrcfgd) | DDR0_00_INT_ACK_ENCODE(0x3C));
+
+			sync();
+			eieio();
+
+			/* -----------------------------------------------------------+
+			 * Assert 'start' parameter.
+			 * ----------------------------------------------------------*/
+			mtdcr(ddrcfga, DDR0_02);
+			val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
+			    DDR0_02_START_ON;
+			mtdcr(ddrcfgd, val);
+
+			sync();
+			eieio();
+
+			/* -----------------------------------------------------------+
+			 * Wait for the DCC master delay line to finish calibration
+			 * ----------------------------------------------------------*/
+			if (denali_wait_for_dlllock() != 0) {
+				printf("dll lock did not occur !!!\n");
+				printf("denali_core_search_data_eye!!!\n");
+				printf("wr_dqs_shift = %d - dll_dqs_delay_X = "
+				       "%d\n", wr_dqs_shift, dll_dqs_delay_X);
+				hang();
+			}
+			sync();
+			eieio();
+
+			if (wait_for_dram_init_complete() != 0) {
+				printf("dram init complete did not occur!!!\n");
+				printf("denali_core_search_data_eye!!!\n");
+				printf("wr_dqs_shift = %d - dll_dqs_delay_X = "
+				       "%d\n", wr_dqs_shift, dll_dqs_delay_X);
+				hang();
+			}
+			udelay(100); /* wait 100us to ensure init is really completed !!! */
+
+			/* write values */
+			for (j = 0; j < NUM_TRIES; j++) {
+				ram_pointer[j] = test[j];
+
+				/* clear any cache at ram location */
+			      __asm__("dcbf 0,%0": :"r"(&ram_pointer[j]));
+			}
+
+			/* read values back */
+			for (j = 0; j < NUM_TRIES; j++) {
+				for (k = 0; k < NUM_READS; k++) {
+					/* clear any cache at ram location */
+				      __asm__("dcbf 0,%0": :"r"(&ram_pointer
+					    [j]));
+
+					if (ram_pointer[j] != test[j])
+						break;
+				}
+
+				/* read error */
+				if (k != NUM_READS)
+					break;
+			}
+
+			/* See if the dll_dqs_delay_X value passed. */
+			mtdcr(ddrcfga, DDR0_00);
+			if (j < NUM_TRIES
+			    || (DDR0_00_INT_STATUS_DECODE(mfdcr(ddrcfgd)) &
+				0x3F)) {
+				/* Failed */
+				passing_cases = 0;
+				/* break; */
+			} else {
+				/* Passed */
+				if (passing_cases == 0)
+					dll_dqs_delay_X_sw_val =
+					    dll_dqs_delay_X;
+				passing_cases++;
+				if (passing_cases >= max_passing_cases) {
+					max_passing_cases = passing_cases;
+					wr_dqs_shift_with_max_passing_cases =
+					    wr_dqs_shift;
+					dll_dqs_delay_X_start_window =
+					    dll_dqs_delay_X_sw_val;
+					dll_dqs_delay_X_end_window =
+					    dll_dqs_delay_X;
+				}
+			}
+
+			/* -----------------------------------------------------------+
+			 * De-assert 'start' parameter.
+			 * ----------------------------------------------------------*/
+			mtdcr(ddrcfga, DDR0_02);
+			val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
+			    DDR0_02_START_OFF;
+			mtdcr(ddrcfgd, val);
+		} /* for (dll_dqs_delay_X=0; dll_dqs_delay_X<128; dll_dqs_delay_X++) */
+	} /* for (wr_dqs_shift=0; wr_dqs_shift<96; wr_dqs_shift++) */
+
+	/* -----------------------------------------------------------+
+	 * Largest passing window is now detected.
+	 * ----------------------------------------------------------*/
+
+	/* Compute dll_dqs_delay_X value */
+	dll_dqs_delay_X = (dll_dqs_delay_X_end_window +
+			   dll_dqs_delay_X_start_window) / 2;
+	wr_dqs_shift = wr_dqs_shift_with_max_passing_cases;
+
+	debug("DQS calibration - Window detected:\n");
+	debug("max_passing_cases = %d\n", max_passing_cases);
+	debug("wr_dqs_shift      = %d\n", wr_dqs_shift);
+	debug("dll_dqs_delay_X   = %d\n", dll_dqs_delay_X);
+	debug("dll_dqs_delay_X window = %d - %d\n",
+	      dll_dqs_delay_X_start_window, dll_dqs_delay_X_end_window);
+
+	/* -----------------------------------------------------------+
+	 * De-assert 'start' parameter.
+	 * ----------------------------------------------------------*/
+	mtdcr(ddrcfga, DDR0_02);
+	val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_OFF;
+	mtdcr(ddrcfgd, val);
+
+	/* -----------------------------------------------------------+
+	 * Set 'wr_dqs_shift'
+	 * ----------------------------------------------------------*/
+	mtdcr(ddrcfga, DDR0_09);
+	val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK)
+	    | DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift);
+	mtdcr(ddrcfgd, val);
+	debug("DDR0_09=0x%08lx\n", val);
+
+	/* -----------------------------------------------------------+
+	 * Set 'dqs_out_shift' = wr_dqs_shift + 32
+	 * ----------------------------------------------------------*/
+	dqs_out_shift = wr_dqs_shift + 32;
+	mtdcr(ddrcfga, DDR0_22);
+	val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK)
+	    | DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift);
+	mtdcr(ddrcfgd, val);
+	debug("DDR0_22=0x%08lx\n", val);
+
+	/* -----------------------------------------------------------+
+	 * Set 'dll_dqs_delay_X'.
+	 * ----------------------------------------------------------*/
+	/* dll_dqs_delay_0 */
+	mtdcr(ddrcfga, DDR0_17);
+	val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK)
+	    | DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X);
+	mtdcr(ddrcfgd, val);
+	debug("DDR0_17=0x%08lx\n", val);
+
+	/* dll_dqs_delay_1 to dll_dqs_delay_4 */
+	mtdcr(ddrcfga, DDR0_18);
+	val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK)
+	    | DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X)
+	    | DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X)
+	    | DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X)
+	    | DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X);
+	mtdcr(ddrcfgd, val);
+	debug("DDR0_18=0x%08lx\n", val);
+
+	/* dll_dqs_delay_5 to dll_dqs_delay_8 */
+	mtdcr(ddrcfga, DDR0_19);
+	val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK)
+	    | DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X)
+	    | DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X)
+	    | DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X)
+	    | DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X);
+	mtdcr(ddrcfgd, val);
+	debug("DDR0_19=0x%08lx\n", val);
+
+	/* -----------------------------------------------------------+
+	 * Assert 'start' parameter.
+	 * ----------------------------------------------------------*/
+	mtdcr(ddrcfga, DDR0_02);
+	val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_ON;
+	mtdcr(ddrcfgd, val);
+
+	sync();
+	eieio();
+
+	/* -----------------------------------------------------------+
+	 * Wait for the DCC master delay line to finish calibration
+	 * ----------------------------------------------------------*/
+	if (denali_wait_for_dlllock() != 0) {
+		printf("dll lock did not occur !!!\n");
+		hang();
+	}
+	sync();
+	eieio();
+
+	if (wait_for_dram_init_complete() != 0) {
+		printf("dram init complete did not occur !!!\n");
+		hang();
+	}
+	udelay(100); /* wait 100us to ensure init is really completed !!! */
+}
+#endif /* defined(CONFIG_DDR_DATA_EYE) */
+#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */
diff --git a/arch/ppc/cpu/ppc4xx/denali_spd_ddr2.c b/arch/ppc/cpu/ppc4xx/denali_spd_ddr2.c
new file mode 100644
index 0000000..72f76cd
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/denali_spd_ddr2.c
@@ -0,0 +1,1256 @@
+/*
+ * arch/ppc/cpu/ppc4xx/denali_spd_ddr2.c
+ * This SPD SDRAM detection code supports AMCC PPC44x CPUs with a Denali-core
+ * DDR2 controller, specifically the 440EPx/GRx.
+ *
+ * (C) Copyright 2007-2008
+ * Larry Johnson, lrj@acm.org.
+ *
+ * Based primarily on arch/ppc/cpu/ppc4xx/4xx_spd_ddr2.c, which is...
+ *
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT   AMCC   CORPORATION 2004
+ *
+ * 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
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <command.h>
+#include <ppc4xx.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_SPD_EEPROM) &&				\
+	(defined(CONFIG_440EPX) || defined(CONFIG_440GRX))
+
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
+#ifndef	TRUE
+#define TRUE		1
+#endif
+#ifndef FALSE
+#define FALSE		0
+#endif
+
+#define MAXDIMMS	2
+#define MAXRANKS	2
+
+#define ONE_BILLION	1000000000
+
+#define MULDIV64(m1, m2, d)	(u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
+
+#define DLL_DQS_DELAY	0x19
+#define DLL_DQS_BYPASS	0x0B
+#define DQS_OUT_SHIFT	0x7F
+
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory
+ * region. Right now the cache should still be disabled in U-Boot because of the
+ * EMAC driver, that need it's buffer descriptor to be located in non cached
+ * memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CONFIG_4xx_DCACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#if defined(CONFIG_4xx_DCACHE)
+#define MY_TLB_WORD2_I_ENABLE	0			/* enable caching on SDRAM */
+#else
+#define MY_TLB_WORD2_I_ENABLE	TLB_WORD2_I_ENABLE	/* disable caching on SDRAM */
+#endif
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes
+ *-----------------------------------------------------------------------------*/
+extern int denali_wait_for_dlllock(void);
+extern void denali_core_search_data_eye(void);
+extern void dcbz_area(u32 start_address, u32 num_bytes);
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang(void)
+{
+	hang();
+}
+void spd_ddr_init_hang(void)
+    __attribute__ ((weak, alias("__spd_ddr_init_hang")));
+
+#if defined(DEBUG)
+static void print_mcsr(void)
+{
+	printf("MCSR = 0x%08X\n", mfspr(SPRN_MCSR));
+}
+
+static void denali_sdram_register_dump(void)
+{
+	unsigned int sdram_data;
+
+	printf("\n  Register Dump:\n");
+	mfsdram(DDR0_00, sdram_data);
+	printf("        DDR0_00 = 0x%08X", sdram_data);
+	mfsdram(DDR0_01, sdram_data);
+	printf("        DDR0_01 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_02, sdram_data);
+	printf("        DDR0_02 = 0x%08X", sdram_data);
+	mfsdram(DDR0_03, sdram_data);
+	printf("        DDR0_03 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_04, sdram_data);
+	printf("        DDR0_04 = 0x%08X", sdram_data);
+	mfsdram(DDR0_05, sdram_data);
+	printf("        DDR0_05 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_06, sdram_data);
+	printf("        DDR0_06 = 0x%08X", sdram_data);
+	mfsdram(DDR0_07, sdram_data);
+	printf("        DDR0_07 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_08, sdram_data);
+	printf("        DDR0_08 = 0x%08X", sdram_data);
+	mfsdram(DDR0_09, sdram_data);
+	printf("        DDR0_09 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_10, sdram_data);
+	printf("        DDR0_10 = 0x%08X", sdram_data);
+	mfsdram(DDR0_11, sdram_data);
+	printf("        DDR0_11 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_12, sdram_data);
+	printf("        DDR0_12 = 0x%08X", sdram_data);
+	mfsdram(DDR0_14, sdram_data);
+	printf("        DDR0_14 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_17, sdram_data);
+	printf("        DDR0_17 = 0x%08X", sdram_data);
+	mfsdram(DDR0_18, sdram_data);
+	printf("        DDR0_18 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_19, sdram_data);
+	printf("        DDR0_19 = 0x%08X", sdram_data);
+	mfsdram(DDR0_20, sdram_data);
+	printf("        DDR0_20 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_21, sdram_data);
+	printf("        DDR0_21 = 0x%08X", sdram_data);
+	mfsdram(DDR0_22, sdram_data);
+	printf("        DDR0_22 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_23, sdram_data);
+	printf("        DDR0_23 = 0x%08X", sdram_data);
+	mfsdram(DDR0_24, sdram_data);
+	printf("        DDR0_24 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_25, sdram_data);
+	printf("        DDR0_25 = 0x%08X", sdram_data);
+	mfsdram(DDR0_26, sdram_data);
+	printf("        DDR0_26 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_27, sdram_data);
+	printf("        DDR0_27 = 0x%08X", sdram_data);
+	mfsdram(DDR0_28, sdram_data);
+	printf("        DDR0_28 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_31, sdram_data);
+	printf("        DDR0_31 = 0x%08X", sdram_data);
+	mfsdram(DDR0_32, sdram_data);
+	printf("        DDR0_32 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_33, sdram_data);
+	printf("        DDR0_33 = 0x%08X", sdram_data);
+	mfsdram(DDR0_34, sdram_data);
+	printf("        DDR0_34 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_35, sdram_data);
+	printf("        DDR0_35 = 0x%08X", sdram_data);
+	mfsdram(DDR0_36, sdram_data);
+	printf("        DDR0_36 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_37, sdram_data);
+	printf("        DDR0_37 = 0x%08X", sdram_data);
+	mfsdram(DDR0_38, sdram_data);
+	printf("        DDR0_38 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_39, sdram_data);
+	printf("        DDR0_39 = 0x%08X", sdram_data);
+	mfsdram(DDR0_40, sdram_data);
+	printf("        DDR0_40 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_41, sdram_data);
+	printf("        DDR0_41 = 0x%08X", sdram_data);
+	mfsdram(DDR0_42, sdram_data);
+	printf("        DDR0_42 = 0x%08X\n", sdram_data);
+	mfsdram(DDR0_43, sdram_data);
+	printf("        DDR0_43 = 0x%08X", sdram_data);
+	mfsdram(DDR0_44, sdram_data);
+	printf("        DDR0_44 = 0x%08X\n", sdram_data);
+}
+#else
+static inline void denali_sdram_register_dump(void)
+{
+}
+
+inline static void print_mcsr(void)
+{
+}
+#endif /* defined(DEBUG) */
+
+static int is_ecc_enabled(void)
+{
+	u32 val;
+
+	mfsdram(DDR0_22, val);
+	return 0x3 == DDR0_22_CTRL_RAW_DECODE(val);
+}
+
+static unsigned char spd_read(u8 chip, unsigned int addr)
+{
+	u8 data[2];
+
+	if (0 != i2c_probe(chip) || 0 != i2c_read(chip, addr, 1, data, 1)) {
+		debug("spd_read(0x%02X, 0x%02X) failed\n", chip, addr);
+		return 0;
+	}
+	debug("spd_read(0x%02X, 0x%02X) returned 0x%02X\n",
+	      chip, addr, data[0]);
+	return data[0];
+}
+
+static unsigned long get_tcyc(unsigned char reg)
+{
+	/*
+	 * Byte 9, et al: Cycle time for CAS Latency=X, is split into two
+	 * nibbles: the higher order nibble (bits 4-7) designates the cycle time
+	 * to a granularity of 1ns; the value presented by the lower order
+	 * nibble (bits 0-3) has a granularity of .1ns and is added to the value
+	 * designated by the higher nibble. In addition, four lines of the lower
+	 * order nibble are assigned to support +.25, +.33, +.66, and +.75.
+	 */
+
+	unsigned char subfield_b = reg & 0x0F;
+
+	switch (subfield_b & 0x0F) {
+	case 0x0:
+	case 0x1:
+	case 0x2:
+	case 0x3:
+	case 0x4:
+	case 0x5:
+	case 0x6:
+	case 0x7:
+	case 0x8:
+	case 0x9:
+		return 1000 * (reg >> 4) + 100 * subfield_b;
+	case 0xA:
+		return 1000 * (reg >> 4) + 250;
+	case 0xB:
+		return 1000 * (reg >> 4) + 333;
+	case 0xC:
+		return 1000 * (reg >> 4) + 667;
+	case 0xD:
+		return 1000 * (reg >> 4) + 750;
+	}
+	return 0;
+}
+
+/*------------------------------------------------------------------
+ * Find the installed DIMMs, make sure that the are DDR2, and fill
+ * in the dimm_ranks array.  Then dimm_ranks[dimm_num] > 0 iff the
+ * DIMM and dimm_num is present.
+ * Note: Because there are only two chip-select lines, it is assumed
+ * that a board with a single socket can support two ranks on that
+ * socket, while a board with two sockets can support only one rank
+ * on each socket.
+ *-----------------------------------------------------------------*/
+static void get_spd_info(unsigned long dimm_ranks[],
+			 unsigned long *ranks,
+			 unsigned char const iic0_dimm_addr[],
+			 unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long dimm_found = FALSE;
+	unsigned long const max_ranks_per_dimm = (1 == num_dimm_banks) ? 2 : 1;
+	unsigned char num_of_bytes;
+	unsigned char total_size;
+
+	*ranks = 0;
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		num_of_bytes = 0;
+		total_size = 0;
+
+		num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+		total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+		if ((num_of_bytes != 0) && (total_size != 0)) {
+			unsigned char const dimm_type =
+			    spd_read(iic0_dimm_addr[dimm_num], 2);
+
+			unsigned long ranks_on_dimm =
+			    (spd_read(iic0_dimm_addr[dimm_num], 5) & 0x07) + 1;
+
+			if (8 != dimm_type) {
+				switch (dimm_type) {
+				case 1:
+					printf("ERROR: Standard Fast Page Mode "
+					       "DRAM DIMM");
+					break;
+				case 2:
+					printf("ERROR: EDO DIMM");
+					break;
+				case 3:
+					printf("ERROR: Pipelined Nibble DIMM");
+					break;
+				case 4:
+					printf("ERROR: SDRAM DIMM");
+					break;
+				case 5:
+					printf("ERROR: Multiplexed ROM DIMM");
+					break;
+				case 6:
+					printf("ERROR: SGRAM DIMM");
+					break;
+				case 7:
+					printf("ERROR: DDR1 DIMM");
+					break;
+				default:
+					printf("ERROR: Unknown DIMM (type %d)",
+					       (unsigned int)dimm_type);
+					break;
+				}
+				printf(" detected in slot %lu.\n", dimm_num);
+				printf("Only DDR2 SDRAM DIMMs are supported."
+				       "\n");
+				printf("Replace the module with a DDR2 DIMM."
+				       "\n\n");
+				spd_ddr_init_hang();
+			}
+			dimm_found = TRUE;
+			debug("DIMM slot %lu: populated with %lu-rank DDR2 DIMM"
+			      "\n", dimm_num, ranks_on_dimm);
+			if (ranks_on_dimm > max_ranks_per_dimm) {
+				printf("WARNING: DRAM DIMM in slot %lu has %lu "
+				       "ranks.\n", dimm_num, ranks_on_dimm);
+				if (1 == max_ranks_per_dimm) {
+					printf("Only one rank will be used.\n");
+				} else {
+					printf
+					    ("Only two ranks will be used.\n");
+				}
+				ranks_on_dimm = max_ranks_per_dimm;
+			}
+			dimm_ranks[dimm_num] = ranks_on_dimm;
+			*ranks += ranks_on_dimm;
+		} else {
+			dimm_ranks[dimm_num] = 0;
+			debug("DIMM slot %lu: Not populated\n", dimm_num);
+		}
+	}
+	if (dimm_found == FALSE) {
+		printf("ERROR: No memory installed.\n");
+		printf("Install at least one DDR2 DIMM.\n\n");
+		spd_ddr_init_hang();
+	}
+	debug("Total number of ranks = %d\n", *ranks);
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that
+ * frequency previously calculated is supported.
+ *-----------------------------------------------------------------*/
+static void check_frequency(unsigned long *dimm_ranks,
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq)
+{
+	unsigned long dimm_num;
+	unsigned long cycle_time;
+	unsigned long calc_cycle_time;
+
+	/*
+	 * calc_cycle_time is calculated from DDR frequency set by board/chip
+	 * and is expressed in picoseconds to match the way DIMM cycle time is
+	 * calculated below.
+	 */
+	calc_cycle_time = MULDIV64(ONE_BILLION, 1000, sdram_freq);
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_ranks[dimm_num]) {
+			cycle_time =
+			    get_tcyc(spd_read(iic0_dimm_addr[dimm_num], 9));
+			debug("cycle_time=%d ps\n", cycle_time);
+
+			if (cycle_time > (calc_cycle_time + 10)) {
+				/*
+				 * the provided sdram cycle_time is too small
+				 * for the available DIMM cycle_time. The
+				 * additionnal 10ps is here to accept a small
+				 * incertainty.
+				 */
+				printf
+				    ("ERROR: DRAM DIMM detected with cycle_time %d ps in "
+				     "slot %d \n while calculated cycle time is %d ps.\n",
+				     (unsigned int)cycle_time,
+				     (unsigned int)dimm_num,
+				     (unsigned int)calc_cycle_time);
+				printf
+				    ("Replace the DIMM, or change DDR frequency via "
+				     "strapping bits.\n\n");
+				spd_ddr_init_hang();
+			}
+		}
+	}
+}
+
+/*------------------------------------------------------------------
+ * This routine gets size information for the installed memory
+ * DIMMs.
+ *-----------------------------------------------------------------*/
+static void get_dimm_size(unsigned long dimm_ranks[],
+			  unsigned char const iic0_dimm_addr[],
+			  unsigned long num_dimm_banks,
+			  unsigned long *const rows,
+			  unsigned long *const banks,
+			  unsigned long *const cols, unsigned long *const width)
+{
+	unsigned long dimm_num;
+
+	*rows = 0;
+	*banks = 0;
+	*cols = 0;
+	*width = 0;
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_ranks[dimm_num]) {
+			unsigned long t;
+
+			/* Rows */
+			t = spd_read(iic0_dimm_addr[dimm_num], 3);
+			if (0 == *rows) {
+				*rows = t;
+			} else if (t != *rows) {
+				printf("ERROR: DRAM DIMM modules do not all "
+				       "have the same number of rows.\n\n");
+				spd_ddr_init_hang();
+			}
+			/* Banks */
+			t = spd_read(iic0_dimm_addr[dimm_num], 17);
+			if (0 == *banks) {
+				*banks = t;
+			} else if (t != *banks) {
+				printf("ERROR: DRAM DIMM modules do not all "
+				       "have the same number of banks.\n\n");
+				spd_ddr_init_hang();
+			}
+			/* Columns */
+			t = spd_read(iic0_dimm_addr[dimm_num], 4);
+			if (0 == *cols) {
+				*cols = t;
+			} else if (t != *cols) {
+				printf("ERROR: DRAM DIMM modules do not all "
+				       "have the same number of columns.\n\n");
+				spd_ddr_init_hang();
+			}
+			/* Data width */
+			t = spd_read(iic0_dimm_addr[dimm_num], 6);
+			if (0 == *width) {
+				*width = t;
+			} else if (t != *width) {
+				printf("ERROR: DRAM DIMM modules do not all "
+				       "have the same data width.\n\n");
+				spd_ddr_init_hang();
+			}
+		}
+	}
+	debug("Number of rows = %d\n", *rows);
+	debug("Number of columns = %d\n", *cols);
+	debug("Number of banks = %d\n", *banks);
+	debug("Data width = %d\n", *width);
+	if (*rows > 14) {
+		printf("ERROR: DRAM DIMM modules have %lu address rows.\n",
+		       *rows);
+		printf("Only modules with 14 or fewer rows are supported.\n\n");
+		spd_ddr_init_hang();
+	}
+	if (4 != *banks && 8 != *banks) {
+		printf("ERROR: DRAM DIMM modules have %lu banks.\n", *banks);
+		printf("Only modules with 4 or 8 banks are supported.\n\n");
+		spd_ddr_init_hang();
+	}
+	if (*cols > 12) {
+		printf("ERROR: DRAM DIMM modules have %lu address columns.\n",
+		       *cols);
+		printf("Only modules with 12 or fewer columns are "
+		       "supported.\n\n");
+		spd_ddr_init_hang();
+	}
+	if (32 != *width && 40 != *width && 64 != *width && 72 != *width) {
+		printf("ERROR: DRAM DIMM modules have a width of %lu bit.\n",
+		       *width);
+		printf("Only modules with widths of 32, 40, 64, and 72 bits "
+		       "are supported.\n\n");
+		spd_ddr_init_hang();
+	}
+}
+
+/*------------------------------------------------------------------
+ * Only 1.8V modules are supported.  This routine verifies this.
+ *-----------------------------------------------------------------*/
+static void check_voltage_type(unsigned long dimm_ranks[],
+			       unsigned char const iic0_dimm_addr[],
+			       unsigned long num_dimm_banks)
+{
+	unsigned long dimm_num;
+	unsigned long voltage_type;
+
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		if (dimm_ranks[dimm_num]) {
+			voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+			if (0x05 != voltage_type) {	/* 1.8V for DDR2 */
+				printf("ERROR: Slot %lu provides 1.8V for DDR2 "
+				       "DIMMs.\n", dimm_num);
+				switch (voltage_type) {
+				case 0x00:
+					printf("This DIMM is 5.0 Volt/TTL.\n");
+					break;
+				case 0x01:
+					printf("This DIMM is LVTTL.\n");
+					break;
+				case 0x02:
+					printf("This DIMM is 1.5 Volt.\n");
+					break;
+				case 0x03:
+					printf("This DIMM is 3.3 Volt/TTL.\n");
+					break;
+				case 0x04:
+					printf("This DIMM is 2.5 Volt.\n");
+					break;
+				default:
+					printf("This DIMM is an unknown "
+					       "voltage.\n");
+					break;
+				}
+				printf("Replace it with a 1.8V DDR2 DIMM.\n\n");
+				spd_ddr_init_hang();
+			}
+		}
+	}
+}
+
+static void program_ddr0_03(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq,
+			    unsigned long rows, unsigned long *cas_latency)
+{
+	unsigned long dimm_num;
+	unsigned long cas_index;
+	unsigned long cycle_2_0_clk;
+	unsigned long cycle_3_0_clk;
+	unsigned long cycle_4_0_clk;
+	unsigned long cycle_5_0_clk;
+	unsigned long max_2_0_tcyc_ps = 100;
+	unsigned long max_3_0_tcyc_ps = 100;
+	unsigned long max_4_0_tcyc_ps = 100;
+	unsigned long max_5_0_tcyc_ps = 100;
+	unsigned char cas_available = 0x3C;	/* value for DDR2 */
+	u32 ddr0_03 = DDR0_03_BSTLEN_ENCODE(0x2) | DDR0_03_INITAREF_ENCODE(0x2);
+	unsigned int const tcyc_addr[3] = { 9, 23, 25 };
+
+	/*------------------------------------------------------------------
+	 * Get the board configuration info.
+	 *-----------------------------------------------------------------*/
+	debug("sdram_freq = %d\n", sdram_freq);
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			unsigned char const cas_bit =
+			    spd_read(iic0_dimm_addr[dimm_num], 18);
+			unsigned char cas_mask;
+
+			cas_available &= cas_bit;
+			for (cas_mask = 0x80; cas_mask; cas_mask >>= 1) {
+				if (cas_bit & cas_mask)
+					break;
+			}
+			debug("cas_bit (SPD byte 18) = %02X, cas_mask = %02X\n",
+			      cas_bit, cas_mask);
+
+			for (cas_index = 0; cas_index < 3;
+			     cas_mask >>= 1, cas_index++) {
+				unsigned long cycle_time_ps;
+
+				if (!(cas_available & cas_mask)) {
+					continue;
+				}
+				cycle_time_ps =
+				    get_tcyc(spd_read(iic0_dimm_addr[dimm_num],
+						      tcyc_addr[cas_index]));
+
+				debug("cas_index = %d: cycle_time_ps = %d\n",
+				      cas_index, cycle_time_ps);
+				/*
+				 * DDR2 devices use the following bitmask for CAS latency:
+				 *  Bit   7    6    5    4    3    2    1    0
+				 *       TBD  6.0  5.0  4.0  3.0  2.0  TBD  TBD
+				 */
+				switch (cas_mask) {
+				case 0x20:
+					max_5_0_tcyc_ps =
+					    max(max_5_0_tcyc_ps, cycle_time_ps);
+					break;
+				case 0x10:
+					max_4_0_tcyc_ps =
+					    max(max_4_0_tcyc_ps, cycle_time_ps);
+					break;
+				case 0x08:
+					max_3_0_tcyc_ps =
+					    max(max_3_0_tcyc_ps, cycle_time_ps);
+					break;
+				case 0x04:
+					max_2_0_tcyc_ps =
+					    max(max_2_0_tcyc_ps, cycle_time_ps);
+					break;
+				}
+			}
+		}
+	}
+	debug("cas_available (bit map) = 0x%02X\n", cas_available);
+
+	/*------------------------------------------------------------------
+	 * Set the SDRAM mode, SDRAM_MMODE
+	 *-----------------------------------------------------------------*/
+
+	/* add 10 here because of rounding problems */
+	cycle_2_0_clk = MULDIV64(ONE_BILLION, 1000, max_2_0_tcyc_ps) + 10;
+	cycle_3_0_clk = MULDIV64(ONE_BILLION, 1000, max_3_0_tcyc_ps) + 10;
+	cycle_4_0_clk = MULDIV64(ONE_BILLION, 1000, max_4_0_tcyc_ps) + 10;
+	cycle_5_0_clk = MULDIV64(ONE_BILLION, 1000, max_5_0_tcyc_ps) + 10;
+	debug("cycle_2_0_clk = %d\n", cycle_2_0_clk);
+	debug("cycle_3_0_clk = %d\n", cycle_3_0_clk);
+	debug("cycle_4_0_clk = %d\n", cycle_4_0_clk);
+	debug("cycle_5_0_clk = %d\n", cycle_5_0_clk);
+
+	if ((cas_available & 0x04) && (sdram_freq <= cycle_2_0_clk)) {
+		*cas_latency = 2;
+		ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x2) |
+		    DDR0_03_CASLAT_LIN_ENCODE(0x4);
+	} else if ((cas_available & 0x08) && (sdram_freq <= cycle_3_0_clk)) {
+		*cas_latency = 3;
+		ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x3) |
+		    DDR0_03_CASLAT_LIN_ENCODE(0x6);
+	} else if ((cas_available & 0x10) && (sdram_freq <= cycle_4_0_clk)) {
+		*cas_latency = 4;
+		ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x4) |
+		    DDR0_03_CASLAT_LIN_ENCODE(0x8);
+	} else if ((cas_available & 0x20) && (sdram_freq <= cycle_5_0_clk)) {
+		*cas_latency = 5;
+		ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x5) |
+		    DDR0_03_CASLAT_LIN_ENCODE(0xA);
+	} else {
+		printf("ERROR: Cannot find a supported CAS latency with the "
+		       "installed DIMMs.\n");
+		printf("Only DDR2 DIMMs with CAS latencies of 2.0, 3.0, 4.0, "
+		       "and 5.0 are supported.\n");
+		printf("Make sure the PLB speed is within the supported range "
+		       "of the DIMMs.\n");
+		printf("sdram_freq=%ld cycle2=%ld cycle3=%ld cycle4=%ld "
+		       "cycle5=%ld\n\n", sdram_freq, cycle_2_0_clk,
+		       cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk);
+		spd_ddr_init_hang();
+	}
+	debug("CAS latency = %d\n", *cas_latency);
+	mtsdram(DDR0_03, ddr0_03);
+}
+
+static void program_ddr0_04(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq)
+{
+	unsigned long dimm_num;
+	unsigned long t_rc_ps = 0;
+	unsigned long t_rrd_ps = 0;
+	unsigned long t_rtp_ps = 0;
+	unsigned long t_rc_clk;
+	unsigned long t_rrd_clk;
+	unsigned long t_rtp_clk;
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			unsigned long ps;
+
+			/* tRC */
+			ps = 1000 * spd_read(iic0_dimm_addr[dimm_num], 41);
+			switch (spd_read(iic0_dimm_addr[dimm_num], 40) >> 4) {
+			case 0x1:
+				ps += 250;
+				break;
+			case 0x2:
+				ps += 333;
+				break;
+			case 0x3:
+				ps += 500;
+				break;
+			case 0x4:
+				ps += 667;
+				break;
+			case 0x5:
+				ps += 750;
+				break;
+			}
+			t_rc_ps = max(t_rc_ps, ps);
+			/* tRRD */
+			ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 28);
+			t_rrd_ps = max(t_rrd_ps, ps);
+			/* tRTP */
+			ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 38);
+			t_rtp_ps = max(t_rtp_ps, ps);
+		}
+	}
+	debug("t_rc_ps  = %d\n", t_rc_ps);
+	t_rc_clk = (MULDIV64(sdram_freq, t_rc_ps, ONE_BILLION) + 999) / 1000;
+	debug("t_rrd_ps = %d\n", t_rrd_ps);
+	t_rrd_clk = (MULDIV64(sdram_freq, t_rrd_ps, ONE_BILLION) + 999) / 1000;
+	debug("t_rtp_ps = %d\n", t_rtp_ps);
+	t_rtp_clk = (MULDIV64(sdram_freq, t_rtp_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_04, DDR0_04_TRC_ENCODE(t_rc_clk) |
+		DDR0_04_TRRD_ENCODE(t_rrd_clk) |
+		DDR0_04_TRTP_ENCODE(t_rtp_clk));
+}
+
+static void program_ddr0_05(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq)
+{
+	unsigned long dimm_num;
+	unsigned long t_rp_ps = 0;
+	unsigned long t_ras_ps = 0;
+	unsigned long t_rp_clk;
+	unsigned long t_ras_clk;
+	u32 ddr0_05 = DDR0_05_TMRD_ENCODE(0x2) | DDR0_05_TEMRS_ENCODE(0x2);
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			unsigned long ps;
+
+			/* tRP */
+			ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 27);
+			t_rp_ps = max(t_rp_ps, ps);
+			/* tRAS */
+			ps = 1000 * spd_read(iic0_dimm_addr[dimm_num], 30);
+			t_ras_ps = max(t_ras_ps, ps);
+		}
+	}
+	debug("t_rp_ps  = %d\n", t_rp_ps);
+	t_rp_clk = (MULDIV64(sdram_freq, t_rp_ps, ONE_BILLION) + 999) / 1000;
+	debug("t_ras_ps = %d\n", t_ras_ps);
+	t_ras_clk = (MULDIV64(sdram_freq, t_ras_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_05, ddr0_05 | DDR0_05_TRP_ENCODE(t_rp_clk) |
+		DDR0_05_TRAS_MIN_ENCODE(t_ras_clk));
+}
+
+static void program_ddr0_06(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq)
+{
+	unsigned long dimm_num;
+	unsigned char spd_40;
+	unsigned long t_wtr_ps = 0;
+	unsigned long t_rfc_ps = 0;
+	unsigned long t_wtr_clk;
+	unsigned long t_rfc_clk;
+	u32 ddr0_06 =
+	    DDR0_06_WRITEINTERP_ENCODE(0x1) | DDR0_06_TDLL_ENCODE(200);
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			unsigned long ps;
+
+			/* tWTR */
+			ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 37);
+			t_wtr_ps = max(t_wtr_ps, ps);
+			/* tRFC */
+			ps = 1000 * spd_read(iic0_dimm_addr[dimm_num], 42);
+			spd_40 = spd_read(iic0_dimm_addr[dimm_num], 40);
+			ps += 256000 * (spd_40 & 0x01);
+			switch ((spd_40 & 0x0E) >> 1) {
+			case 0x1:
+				ps += 250;
+				break;
+			case 0x2:
+				ps += 333;
+				break;
+			case 0x3:
+				ps += 500;
+				break;
+			case 0x4:
+				ps += 667;
+				break;
+			case 0x5:
+				ps += 750;
+				break;
+			}
+			t_rfc_ps = max(t_rfc_ps, ps);
+		}
+	}
+	debug("t_wtr_ps = %d\n", t_wtr_ps);
+	t_wtr_clk = (MULDIV64(sdram_freq, t_wtr_ps, ONE_BILLION) + 999) / 1000;
+	debug("t_rfc_ps = %d\n", t_rfc_ps);
+	t_rfc_clk = (MULDIV64(sdram_freq, t_rfc_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_06, ddr0_06 | DDR0_06_TWTR_ENCODE(t_wtr_clk) |
+		DDR0_06_TRFC_ENCODE(t_rfc_clk));
+}
+
+static void program_ddr0_10(unsigned long dimm_ranks[], unsigned long ranks)
+{
+	unsigned long csmap;
+
+	if (2 == ranks) {
+		/* Both chip selects in use */
+		csmap = 0x03;
+	} else {
+		/* One chip select in use */
+		csmap = (1 == dimm_ranks[0]) ? 0x1 : 0x2;
+	}
+	mtsdram(DDR0_10, DDR0_10_WRITE_MODEREG_ENCODE(0x0) |
+		DDR0_10_CS_MAP_ENCODE(csmap) |
+		DDR0_10_OCD_ADJUST_PUP_CS_0_ENCODE(0));
+}
+
+static void program_ddr0_11(unsigned long sdram_freq)
+{
+	unsigned long const t_xsnr_ps = 200000;	/* 200 ns */
+	unsigned long t_xsnr_clk;
+
+	debug("t_xsnr_ps = %d\n", t_xsnr_ps);
+	t_xsnr_clk =
+	    (MULDIV64(sdram_freq, t_xsnr_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_11, DDR0_11_SREFRESH_ENCODE(0) |
+		DDR0_11_TXSNR_ENCODE(t_xsnr_clk) | DDR0_11_TXSR_ENCODE(200));
+}
+
+static void program_ddr0_22(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks, unsigned long width)
+{
+#if defined(CONFIG_DDR_ECC)
+	unsigned long dimm_num;
+	unsigned long ecc_available = width >= 64;
+	u32 ddr0_22 = DDR0_22_DQS_OUT_SHIFT_BYPASS_ENCODE(0x26) |
+	    DDR0_22_DQS_OUT_SHIFT_ENCODE(DQS_OUT_SHIFT) |
+	    DDR0_22_DLL_DQS_BYPASS_8_ENCODE(DLL_DQS_BYPASS);
+
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			/* Check for ECC */
+			if (0 == (spd_read(iic0_dimm_addr[dimm_num], 11) &
+				  0x02)) {
+				ecc_available = FALSE;
+			}
+		}
+	}
+	if (ecc_available) {
+		debug("ECC found on all DIMMs present\n");
+		mtsdram(DDR0_22, ddr0_22 | DDR0_22_CTRL_RAW_ENCODE(0x3));
+	} else {
+		debug("ECC not found on some or all DIMMs present\n");
+		mtsdram(DDR0_22, ddr0_22 | DDR0_22_CTRL_RAW_ENCODE(0x0));
+	}
+#else
+	mtsdram(DDR0_22, DDR0_22_CTRL_RAW_ENCODE(0x0) |
+		DDR0_22_DQS_OUT_SHIFT_BYPASS_ENCODE(0x26) |
+		DDR0_22_DQS_OUT_SHIFT_ENCODE(DQS_OUT_SHIFT) |
+		DDR0_22_DLL_DQS_BYPASS_8_ENCODE(DLL_DQS_BYPASS));
+#endif /* defined(CONFIG_DDR_ECC) */
+}
+
+static void program_ddr0_24(unsigned long ranks)
+{
+	u32 ddr0_24 = DDR0_24_RTT_PAD_TERMINATION_ENCODE(0x1) |	/* 75 ohm */
+	    DDR0_24_ODT_RD_MAP_CS1_ENCODE(0x0);
+
+	if (2 == ranks) {
+		/* Both chip selects in use */
+		ddr0_24 |= DDR0_24_ODT_WR_MAP_CS1_ENCODE(0x1) |
+		    DDR0_24_ODT_WR_MAP_CS0_ENCODE(0x2);
+	} else {
+		/* One chip select in use */
+		/* One of the two fields added to ddr0_24 is a "don't care" */
+		ddr0_24 |= DDR0_24_ODT_WR_MAP_CS1_ENCODE(0x2) |
+		    DDR0_24_ODT_WR_MAP_CS0_ENCODE(0x1);
+	}
+	mtsdram(DDR0_24, ddr0_24);
+}
+
+static void program_ddr0_26(unsigned long sdram_freq)
+{
+	unsigned long const t_ref_ps = 7800000;	/* 7.8 us. refresh */
+	/* TODO: check definition of tRAS_MAX */
+	unsigned long const t_ras_max_ps = 9 * t_ref_ps;
+	unsigned long t_ras_max_clk;
+	unsigned long t_ref_clk;
+
+	/* Round down t_ras_max_clk and t_ref_clk */
+	debug("t_ras_max_ps = %d\n", t_ras_max_ps);
+	t_ras_max_clk = MULDIV64(sdram_freq, t_ras_max_ps, ONE_BILLION) / 1000;
+	debug("t_ref_ps     = %d\n", t_ref_ps);
+	t_ref_clk = MULDIV64(sdram_freq, t_ref_ps, ONE_BILLION) / 1000;
+	mtsdram(DDR0_26, DDR0_26_TRAS_MAX_ENCODE(t_ras_max_clk) |
+		DDR0_26_TREF_ENCODE(t_ref_clk));
+}
+
+static void program_ddr0_27(unsigned long sdram_freq)
+{
+	unsigned long const t_init_ps = 200000000;	/* 200 us. init */
+	unsigned long t_init_clk;
+
+	debug("t_init_ps = %d\n", t_init_ps);
+	t_init_clk =
+	    (MULDIV64(sdram_freq, t_init_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_27, DDR0_27_EMRS_DATA_ENCODE(0x0000) |
+		DDR0_27_TINIT_ENCODE(t_init_clk));
+}
+
+static void program_ddr0_43(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq,
+			    unsigned long cols, unsigned long banks)
+{
+	unsigned long dimm_num;
+	unsigned long t_wr_ps = 0;
+	unsigned long t_wr_clk;
+	u32 ddr0_43 = DDR0_43_APREBIT_ENCODE(10) |
+	    DDR0_43_COLUMN_SIZE_ENCODE(12 - cols) |
+	    DDR0_43_EIGHT_BANK_MODE_ENCODE(8 == banks ? 1 : 0);
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			unsigned long ps;
+
+			ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 36);
+			t_wr_ps = max(t_wr_ps, ps);
+		}
+	}
+	debug("t_wr_ps = %d\n", t_wr_ps);
+	t_wr_clk = (MULDIV64(sdram_freq, t_wr_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_43, ddr0_43 | DDR0_43_TWR_ENCODE(t_wr_clk));
+}
+
+static void program_ddr0_44(unsigned long dimm_ranks[],
+			    unsigned char const iic0_dimm_addr[],
+			    unsigned long num_dimm_banks,
+			    unsigned long sdram_freq)
+{
+	unsigned long dimm_num;
+	unsigned long t_rcd_ps = 0;
+	unsigned long t_rcd_clk;
+
+	/*------------------------------------------------------------------
+	 * Handle the timing.  We need to find the worst case timing of all
+	 * the dimm modules installed.
+	 *-----------------------------------------------------------------*/
+	/* loop through all the DIMM slots on the board */
+	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+		/* If a dimm is installed in a particular slot ... */
+		if (dimm_ranks[dimm_num]) {
+			unsigned long ps;
+
+			ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 29);
+			t_rcd_ps = max(t_rcd_ps, ps);
+		}
+	}
+	debug("t_rcd_ps = %d\n", t_rcd_ps);
+	t_rcd_clk = (MULDIV64(sdram_freq, t_rcd_ps, ONE_BILLION) + 999) / 1000;
+	mtsdram(DDR0_44, DDR0_44_TRCD_ENCODE(t_rcd_clk));
+}
+
+/*-----------------------------------------------------------------------------+
+ * initdram.  Initializes the 440EPx/GPx DDR SDRAM controller.
+ * Note: This routine runs from flash with a stack set up in the chip's
+ * sram space.  It is important that the routine does not require .sbss, .bss or
+ * .data sections.  It also cannot call routines that require these sections.
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------
+ * Function:	 initdram
+ * Description:  Configures SDRAM memory banks for DDR operation.
+ *		 Auto Memory Configuration option reads the DDR SDRAM EEPROMs
+ *		 via the IIC bus and then configures the DDR SDRAM memory
+ *		 banks appropriately. If Auto Memory Configuration is
+ *		 not used, it is assumed that no DIMM is plugged
+ *-----------------------------------------------------------------------------*/
+phys_size_t initdram(int board_type)
+{
+	unsigned char const iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+	unsigned long dimm_ranks[MAXDIMMS];
+	unsigned long ranks;
+	unsigned long rows;
+	unsigned long banks;
+	unsigned long cols;
+	unsigned long width;
+	unsigned long const sdram_freq = get_bus_freq(0);
+	unsigned long const num_dimm_banks = sizeof(iic0_dimm_addr);	/* on board dimm banks */
+	unsigned long cas_latency = 0;	/* to quiet initialization warning */
+	unsigned long dram_size;
+
+	debug("\nEntering initdram()\n");
+
+	/*------------------------------------------------------------------
+	 * Stop the DDR-SDRAM controller.
+	 *-----------------------------------------------------------------*/
+	mtsdram(DDR0_02, DDR0_02_START_ENCODE(0));
+
+	/*
+	 * Make sure I2C controller is initialized
+	 * before continuing.
+	 */
+	/* switch to correct I2C bus */
+	I2C_SET_BUS(CONFIG_SYS_SPD_BUS_NUM);
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	/*------------------------------------------------------------------
+	 * Clear out the serial presence detect buffers.
+	 * Perform IIC reads from the dimm.  Fill in the spds.
+	 * Check to see if the dimm slots are populated
+	 *-----------------------------------------------------------------*/
+	get_spd_info(dimm_ranks, &ranks, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Check the frequency supported for the dimms plugged.
+	 *-----------------------------------------------------------------*/
+	check_frequency(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+	/*------------------------------------------------------------------
+	 * Check and get size information.
+	 *-----------------------------------------------------------------*/
+	get_dimm_size(dimm_ranks, iic0_dimm_addr, num_dimm_banks, &rows, &banks,
+		      &cols, &width);
+
+	/*------------------------------------------------------------------
+	 * Check the voltage type for the dimms plugged.
+	 *-----------------------------------------------------------------*/
+	check_voltage_type(dimm_ranks, iic0_dimm_addr, num_dimm_banks);
+
+	/*------------------------------------------------------------------
+	 * Program registers for SDRAM controller.
+	 *-----------------------------------------------------------------*/
+	mtsdram(DDR0_00, DDR0_00_DLL_INCREMENT_ENCODE(0x19) |
+		DDR0_00_DLL_START_POINT_DECODE(0x0A));
+
+	mtsdram(DDR0_01, DDR0_01_PLB0_DB_CS_LOWER_ENCODE(0x01) |
+		DDR0_01_PLB0_DB_CS_UPPER_ENCODE(0x00) |
+		DDR0_01_INT_MASK_ENCODE(0xFF));
+
+	program_ddr0_03(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq,
+			rows, &cas_latency);
+
+	program_ddr0_04(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+	program_ddr0_05(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+	program_ddr0_06(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+	/*
+	 * TODO: tFAW not found in SPD.  Value of 13 taken from Sequoia
+	 * board SDRAM, but may be overly conservative.
+	 */
+	mtsdram(DDR0_07, DDR0_07_NO_CMD_INIT_ENCODE(0) |
+		DDR0_07_TFAW_ENCODE(13) |
+		DDR0_07_AUTO_REFRESH_MODE_ENCODE(1) |
+		DDR0_07_AREFRESH_ENCODE(0));
+
+	mtsdram(DDR0_08, DDR0_08_WRLAT_ENCODE(cas_latency - 1) |
+		DDR0_08_TCPD_ENCODE(200) | DDR0_08_DQS_N_EN_ENCODE(0) |
+		DDR0_08_DDRII_ENCODE(1));
+
+	mtsdram(DDR0_09, DDR0_09_OCD_ADJUST_PDN_CS_0_ENCODE(0x00) |
+		DDR0_09_RTT_0_ENCODE(0x1) |
+		DDR0_09_WR_DQS_SHIFT_BYPASS_ENCODE(0x1D) |
+		DDR0_09_WR_DQS_SHIFT_ENCODE(DQS_OUT_SHIFT - 0x20));
+
+	program_ddr0_10(dimm_ranks, ranks);
+
+	program_ddr0_11(sdram_freq);
+
+	mtsdram(DDR0_12, DDR0_12_TCKE_ENCODE(3));
+
+	mtsdram(DDR0_14, DDR0_14_DLL_BYPASS_MODE_ENCODE(0) |
+		DDR0_14_REDUC_ENCODE(width <= 40 ? 1 : 0) |
+		DDR0_14_REG_DIMM_ENABLE_ENCODE(0));
+
+	mtsdram(DDR0_17, DDR0_17_DLL_DQS_DELAY_0_ENCODE(DLL_DQS_DELAY));
+
+	mtsdram(DDR0_18, DDR0_18_DLL_DQS_DELAY_4_ENCODE(DLL_DQS_DELAY) |
+		DDR0_18_DLL_DQS_DELAY_3_ENCODE(DLL_DQS_DELAY) |
+		DDR0_18_DLL_DQS_DELAY_2_ENCODE(DLL_DQS_DELAY) |
+		DDR0_18_DLL_DQS_DELAY_1_ENCODE(DLL_DQS_DELAY));
+
+	mtsdram(DDR0_19, DDR0_19_DLL_DQS_DELAY_8_ENCODE(DLL_DQS_DELAY) |
+		DDR0_19_DLL_DQS_DELAY_7_ENCODE(DLL_DQS_DELAY) |
+		DDR0_19_DLL_DQS_DELAY_6_ENCODE(DLL_DQS_DELAY) |
+		DDR0_19_DLL_DQS_DELAY_5_ENCODE(DLL_DQS_DELAY));
+
+	mtsdram(DDR0_20, DDR0_20_DLL_DQS_BYPASS_3_ENCODE(DLL_DQS_BYPASS) |
+		DDR0_20_DLL_DQS_BYPASS_2_ENCODE(DLL_DQS_BYPASS) |
+		DDR0_20_DLL_DQS_BYPASS_1_ENCODE(DLL_DQS_BYPASS) |
+		DDR0_20_DLL_DQS_BYPASS_0_ENCODE(DLL_DQS_BYPASS));
+
+	mtsdram(DDR0_21, DDR0_21_DLL_DQS_BYPASS_7_ENCODE(DLL_DQS_BYPASS) |
+		DDR0_21_DLL_DQS_BYPASS_6_ENCODE(DLL_DQS_BYPASS) |
+		DDR0_21_DLL_DQS_BYPASS_5_ENCODE(DLL_DQS_BYPASS) |
+		DDR0_21_DLL_DQS_BYPASS_4_ENCODE(DLL_DQS_BYPASS));
+
+	program_ddr0_22(dimm_ranks, iic0_dimm_addr, num_dimm_banks, width);
+
+	mtsdram(DDR0_23, DDR0_23_ODT_RD_MAP_CS0_ENCODE(0x0) |
+		DDR0_23_FWC_ENCODE(0));
+
+	program_ddr0_24(ranks);
+
+	program_ddr0_26(sdram_freq);
+
+	program_ddr0_27(sdram_freq);
+
+	mtsdram(DDR0_28, DDR0_28_EMRS3_DATA_ENCODE(0x0000) |
+		DDR0_28_EMRS2_DATA_ENCODE(0x0000));
+
+	mtsdram(DDR0_31, DDR0_31_XOR_CHECK_BITS_ENCODE(0x0000));
+
+	mtsdram(DDR0_42, DDR0_42_ADDR_PINS_ENCODE(14 - rows) |
+		DDR0_42_CASLAT_LIN_GATE_ENCODE(2 * cas_latency));
+
+	program_ddr0_43(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq,
+			cols, banks);
+
+	program_ddr0_44(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+	denali_sdram_register_dump();
+
+	dram_size = (width >= 64) ? 8 : 4;
+	dram_size *= 1 << cols;
+	dram_size *= banks;
+	dram_size *= 1 << rows;
+	dram_size *= ranks;
+	debug("dram_size = %lu\n", dram_size);
+
+	/* Start the SDRAM controler */
+	mtsdram(DDR0_02, DDR0_02_START_ENCODE(1));
+	denali_wait_for_dlllock();
+
+#if defined(CONFIG_DDR_DATA_EYE)
+	/*
+	 * Map the first 1 MiB of memory in the TLB, and perform the data eye
+	 * search.
+	 */
+	program_tlb(0, CONFIG_SYS_SDRAM_BASE, TLB_1MB_SIZE, TLB_WORD2_I_ENABLE);
+	denali_core_search_data_eye();
+	denali_sdram_register_dump();
+	remove_tlb(CONFIG_SYS_SDRAM_BASE, TLB_1MB_SIZE);
+#endif
+
+#if defined(CONFIG_ZERO_SDRAM) || defined(CONFIG_DDR_ECC)
+	program_tlb(0, CONFIG_SYS_SDRAM_BASE, dram_size, 0);
+	sync();
+	/* Zero the memory */
+	debug("Zeroing SDRAM...");
+#if defined(CONFIG_SYS_MEM_TOP_HIDE)
+	dcbz_area(CONFIG_SYS_SDRAM_BASE, dram_size - CONFIG_SYS_MEM_TOP_HIDE);
+#else
+#error Please define CONFIG_SYS_MEM_TOP_HIDE (see README) in your board config file
+#endif
+	/* Write modified dcache lines back to memory */
+	clean_dcache_range(CONFIG_SYS_SDRAM_BASE, CONFIG_SYS_SDRAM_BASE + dram_size - CONFIG_SYS_MEM_TOP_HIDE);
+	debug("Completed\n");
+	sync();
+	remove_tlb(CONFIG_SYS_SDRAM_BASE, dram_size);
+
+#if defined(CONFIG_DDR_ECC)
+	/*
+	 * If ECC is enabled, clear and enable interrupts
+	 */
+	if (is_ecc_enabled()) {
+		u32 val;
+
+		sync();
+		/* Clear error status */
+		mfsdram(DDR0_00, val);
+		mtsdram(DDR0_00, val | DDR0_00_INT_ACK_ALL);
+		/* Set 'int_mask' parameter to functionnal value */
+		mfsdram(DDR0_01, val);
+		mtsdram(DDR0_01, (val & ~DDR0_01_INT_MASK_MASK) |
+			DDR0_01_INT_MASK_ALL_OFF);
+#if defined(CONFIG_DDR_DATA_EYE)
+		/*
+		 * Running denali_core_search_data_eye() when ECC is enabled
+		 * causes non-ECC machine checks.  This clears them.
+		 */
+		print_mcsr();
+		mtspr(SPRN_MCSR, mfspr(SPRN_MCSR));
+		print_mcsr();
+#endif
+		sync();
+	}
+#endif /* defined(CONFIG_DDR_ECC) */
+#endif /* defined(CONFIG_ZERO_SDRAM) || defined(CONFIG_DDR_ECC) */
+
+	program_tlb(0, CONFIG_SYS_SDRAM_BASE, dram_size, MY_TLB_WORD2_I_ENABLE);
+	return dram_size;
+}
+
+void board_add_ram_info(int use_default)
+{
+	u32 val;
+
+	printf(" (ECC");
+	if (!is_ecc_enabled()) {
+		printf(" not");
+	}
+	printf(" enabled, %ld MHz", (2 * get_bus_freq(0)) / 1000000);
+
+	mfsdram(DDR0_03, val);
+	printf(", CL%d)", DDR0_03_CASLAT_LIN_DECODE(val) >> 1);
+}
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/arch/ppc/cpu/ppc4xx/ecc.c b/arch/ppc/cpu/ppc4xx/ecc.c
new file mode 100644
index 0000000..f105605
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/ecc.c
@@ -0,0 +1,185 @@
+/*
+ *    Copyright (c) 2008 Nuovation System Designs, LLC
+ *      Grant Erickson <gerickson@nuovations.com>
+ *
+ *    (C) Copyright 2005-2009
+ *    Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ *    (C) Copyright 2002
+ *    Jun Gu, Artesyn Technology, jung@artesyncp.com
+ *
+ *    (C) Copyright 2001
+ *    Bill Hunter, Wave 7 Optics, williamhunter@attbi.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 abe 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
+ *
+ *    Description:
+ *	This file implements generic DRAM ECC initialization for
+ *	PowerPC processors using a SDRAM DDR/DDR2 controller,
+ *	including the 405EX(r), 440GP/GX/EP/GR, 440SP(E), and
+ *	460EX/GT.
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#include "ecc.h"
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
+    defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
+
+#if defined(CONFIG_405EX)
+/*
+ * Currently only 405EX uses 16bit data bus width as an alternative
+ * option to 32bit data width (SDRAM0_MCOPT1_WDTH)
+ */
+#define SDRAM_DATA_ALT_WIDTH	2
+#else
+#define SDRAM_DATA_ALT_WIDTH	8
+#endif
+
+static void wait_ddr_idle(void)
+{
+	u32 val;
+
+	do {
+		mfsdram(SDRAM_MCSTAT, val);
+	} while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
+}
+
+static void program_ecc_addr(unsigned long start_address,
+			     unsigned long num_bytes,
+			     unsigned long tlb_word2_i_value)
+{
+	unsigned long current_address;
+	unsigned long end_address;
+	unsigned long address_increment;
+	unsigned long mcopt1;
+	char str[] = "ECC generation -";
+	char slash[] = "\\|/-\\|/-";
+	int loop = 0;
+	int loopi = 0;
+
+	current_address = start_address;
+	mfsdram(SDRAM_MCOPT1, mcopt1);
+	if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+		mtsdram(SDRAM_MCOPT1,
+			(mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN);
+		sync();
+		eieio();
+		wait_ddr_idle();
+
+		puts(str);
+
+#ifdef CONFIG_440
+		if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
+#endif
+			/* ECC bit set method for non-cached memory */
+			if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
+				address_increment = 4;
+			else
+				address_increment = SDRAM_DATA_ALT_WIDTH;
+			end_address = current_address + num_bytes;
+
+			while (current_address < end_address) {
+				*((unsigned long *)current_address) = 0;
+				current_address += address_increment;
+
+				if ((loop++ % (2 << 20)) == 0) {
+					putc('\b');
+					putc(slash[loopi++ % 8]);
+				}
+			}
+#ifdef CONFIG_440
+		} else {
+			/* ECC bit set method for cached memory */
+			dcbz_area(start_address, num_bytes);
+			/* Write modified dcache lines back to memory */
+			clean_dcache_range(start_address, start_address + num_bytes);
+		}
+#endif /* CONFIG_440 */
+
+		blank_string(strlen(str));
+
+		sync();
+		eieio();
+		wait_ddr_idle();
+
+		/* clear ECC error repoting registers */
+		mtsdram(SDRAM_ECCES, 0xffffffff);
+		mtdcr(0x4c, 0xffffffff);
+
+		mtsdram(SDRAM_MCOPT1,
+			(mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
+		sync();
+		eieio();
+		wait_ddr_idle();
+	}
+}
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
+void ecc_init(unsigned long * const start, unsigned long size)
+{
+	/*
+	 * Init ECC with cache disabled (on PPC's with IBM DDR
+	 * controller (non DDR2), not tested with cache enabled yet
+	 */
+	program_ecc_addr((u32)start, size, TLB_WORD2_I_ENABLE);
+}
+#endif
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+void do_program_ecc(unsigned long tlb_word2_i_value)
+{
+	unsigned long mcopt1;
+	unsigned long mcopt2;
+	unsigned long mcstat;
+	phys_size_t memsize = sdram_memsize();
+
+	if (memsize > CONFIG_MAX_MEM_MAPPED) {
+		printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
+		return;
+	}
+
+	mfsdram(SDRAM_MCOPT1, mcopt1);
+	mfsdram(SDRAM_MCOPT2, mcopt2);
+
+	if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+		/* DDR controller must be enabled and not in self-refresh. */
+		mfsdram(SDRAM_MCSTAT, mcstat);
+		if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+		    && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
+		    && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
+			== (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
+
+			program_ecc_addr(0, memsize, tlb_word2_i_value);
+		}
+	}
+}
+#endif
+
+#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
+#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
diff --git a/arch/ppc/cpu/ppc4xx/ecc.h b/arch/ppc/cpu/ppc4xx/ecc.h
new file mode 100644
index 0000000..b258891
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/ecc.h
@@ -0,0 +1,75 @@
+/*
+ *    Copyright (c) 2008 Nuovation System Designs, LLC
+ *	Grant Erickson <gerickson@nuovations.com>
+ *
+ *    Copyright (c) 2007-2009 DENX Software Engineering, GmbH
+ *	Stefan Roese <sr@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 abe 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
+ *
+ *    Description:
+ *	This file implements ECC initialization for PowerPC processors
+ *	using the IBM SDRAM DDR1 & DDR2 controller.
+ *
+ */
+
+#ifndef _ECC_H_
+#define _ECC_H_
+
+/*
+ * Since the IBM DDR controller used on 440GP/GX/EP/GR is not register
+ * compatible to the IBM DDR/2 controller used on 405EX/440SP/SPe/460EX/GT
+ * we need to make some processor dependant defines used later on by the
+ * driver.
+ */
+
+/* For 440GP/GX/EP/GR */
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
+#define SDRAM_MCOPT1		SDRAM_CFG0
+#define SDRAM_MCOPT1_MCHK_MASK	SDRAM_CFG0_MCHK_MASK
+#define SDRAM_MCOPT1_MCHK_NON	SDRAM_CFG0_MCHK_NON
+#define SDRAM_MCOPT1_MCHK_GEN	SDRAM_CFG0_MCHK_GEN
+#define SDRAM_MCOPT1_MCHK_CHK	SDRAM_CFG0_MCHK_CHK
+#define SDRAM_MCOPT1_MCHK_CHK_REP SDRAM_CFG0_MCHK_CHK
+#define SDRAM_MCOPT1_DMWD_MASK	SDRAM_CFG0_DMWD_MASK
+#define SDRAM_MCOPT1_DMWD_32	SDRAM_CFG0_DMWD_32
+
+#define SDRAM_MCSTAT		SDRAM0_MCSTS
+#define SDRAM_MCSTAT_IDLE_MASK	SDRAM_MCSTS_CIS
+#define SDRAM_MCSTAT_IDLE_NOT	SDRAM_MCSTS_IDLE_NOT
+
+#define SDRAM_ECCES		SDRAM0_ECCESR
+#endif
+
+void ecc_init(unsigned long * const start, unsigned long size);
+void do_program_ecc(unsigned long tlb_word2_i_value);
+
+static void inline blank_string(int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		putc('\b');
+	for (i = 0; i < size; i++)
+		putc(' ');
+	for (i = 0; i < size; i++)
+		putc('\b');
+}
+
+#endif /* _ECC_H_ */
diff --git a/arch/ppc/cpu/ppc4xx/fdt.c b/arch/ppc/cpu/ppc4xx/fdt.c
new file mode 100644
index 0000000..15a184b
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/fdt.c
@@ -0,0 +1,177 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@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 <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <ppc4xx.h>
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt_support.h>
+#include <asm/4xx_pcie.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void __ft_board_setup(void *blob, bd_t *bd)
+{
+	int rc;
+	int i;
+	u32 bxcr;
+	u32 ranges[EBC_NUM_BANKS * 4];
+	u32 *p = ranges;
+	char ebc_path[] = "/plb/opb/ebc";
+
+	ft_cpu_setup(blob, bd);
+
+	/*
+	 * Read 4xx EBC bus bridge registers to get mappings of the
+	 * peripheral banks into the OPB/PLB address space
+	 */
+	for (i = 0; i < EBC_NUM_BANKS; i++) {
+		mtdcr(EBC0_CFGADDR, EBC_BXCR(i));
+		bxcr = mfdcr(EBC0_CFGDATA);
+
+		if ((bxcr & EBC_BXCR_BU_MASK) != EBC_BXCR_BU_NONE) {
+			*p++ = i;
+			*p++ = 0;
+			*p++ = bxcr & EBC_BXCR_BAS_MASK;
+			*p++ = EBC_BXCR_BANK_SIZE(bxcr);
+
+#ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
+			/* Try to update reg property in nor flash node too */
+			fdt_fixup_nor_flash_size(blob, i,
+						 EBC_BXCR_BANK_SIZE(bxcr));
+#endif
+		}
+	}
+
+	/* Some 405 PPC's have EBC as direct PLB child in the dts */
+	if (fdt_path_offset(blob, ebc_path) < 0)
+		strcpy(ebc_path, "/plb/ebc");
+	rc = fdt_find_and_setprop(blob, ebc_path, "ranges", ranges,
+				  (p - ranges) * sizeof(u32), 1);
+	if (rc) {
+		printf("Unable to update property EBC mappings, err=%s\n",
+		       fdt_strerror(rc));
+	}
+}
+void ft_board_setup(void *blob, bd_t *bd) __attribute__((weak, alias("__ft_board_setup")));
+
+/*
+ * Fixup all PCIe nodes by setting the device_type property
+ * to "pci-endpoint" instead is "pci" for endpoint ports.
+ * This property will get checked later by the Linux driver
+ * to properly configure the PCIe port in Linux (again).
+ */
+void fdt_pcie_setup(void *blob)
+{
+	const char *compat = "ibm,plb-pciex";
+	const char *prop = "device_type";
+	const char *prop_val = "pci-endpoint";
+	const u32 *port;
+	int no;
+	int rc;
+
+	/* Search first PCIe node */
+	no = fdt_node_offset_by_compatible(blob, -1, compat);
+	while (no != -FDT_ERR_NOTFOUND) {
+		port = fdt_getprop(blob, no, "port", NULL);
+		if (port == NULL) {
+			printf("WARNING: could not find port property\n");
+		} else {
+			if (is_end_point(*port)) {
+				rc = fdt_setprop(blob, no, prop, prop_val,
+						 strlen(prop_val) + 1);
+				if (rc < 0)
+					printf("WARNING: could not set %s for %s: %s.\n",
+					       prop, compat, fdt_strerror(rc));
+			}
+		}
+
+		/* Jump to next PCIe node */
+		no = fdt_node_offset_by_compatible(blob, no, compat);
+	}
+}
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	sys_info_t sys_info;
+	int off, ndepth = 0;
+
+	get_sys_info(&sys_info);
+
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, "timebase-frequency",
+			     bd->bi_intfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, "clock-frequency",
+			     bd->bi_intfreq, 1);
+	do_fixup_by_path_u32(blob, "/plb", "clock-frequency", sys_info.freqPLB, 1);
+	do_fixup_by_path_u32(blob, "/plb/opb", "clock-frequency", sys_info.freqOPB, 1);
+
+	if (fdt_path_offset(blob, "/plb/opb/ebc") >= 0)
+		do_fixup_by_path_u32(blob, "/plb/opb/ebc", "clock-frequency",
+			sys_info.freqEBC, 1);
+	else
+		do_fixup_by_path_u32(blob, "/plb/ebc", "clock-frequency",
+			sys_info.freqEBC, 1);
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+	/*
+	 * Fixup all UART clocks for CPU internal UARTs
+	 * (only these UARTs are definitely clocked by gd->uart_clk)
+	 *
+	 * These UARTs are direct childs of /plb/opb. This code
+	 * does not touch any UARTs that are connected to the ebc.
+	 */
+	off = fdt_path_offset(blob, "/plb/opb");
+	while ((off = fdt_next_node(blob, off, &ndepth)) >= 0) {
+		/*
+		 * process all sub nodes and stop when we are back
+		 * at the starting depth
+		 */
+		if (ndepth <= 0)
+			break;
+
+		/* only update direct childs */
+		if ((ndepth == 1) &&
+		    (fdt_node_check_compatible(blob, off, "ns16550") == 0))
+			fdt_setprop(blob, off,
+				    "clock-frequency",
+				    (void*)&(gd->uart_clk), 4);
+	}
+
+	/*
+	 * Fixup all ethernet nodes
+	 * Note: aliases in the dts are required for this
+	 */
+	fdt_fixup_ethernet(blob);
+
+	/*
+	 * Fixup all available PCIe nodes by setting the device_type property
+	 */
+	fdt_pcie_setup(blob);
+}
+#endif /* CONFIG_OF_LIBFDT && CONFIG_OF_BOARD_SETUP */
diff --git a/arch/ppc/cpu/ppc4xx/gpio.c b/arch/ppc/cpu/ppc4xx/gpio.c
new file mode 100644
index 0000000..c0d351a
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/gpio.c
@@ -0,0 +1,255 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@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 <asm/processor.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
+gpio_param_s const gpio_tab[GPIO_GROUP_MAX][GPIO_MAX] = CONFIG_SYS_4xx_GPIO_TABLE;
+#endif
+
+#if defined(GPIO0_OSRL)
+/* Only some 4xx variants support alternate funtions on the GPIO's */
+void gpio_config(int pin, int in_out, int gpio_alt, int out_val)
+{
+	u32 mask;
+	u32 mask2;
+	u32 val;
+	u32 offs = 0;
+	u32 offs2 = 0;
+	int pin2 = pin << 1;
+
+	if (pin >= GPIO_MAX) {
+		offs = 0x100;
+		pin -= GPIO_MAX;
+	}
+
+	if (pin >= GPIO_MAX/2) {
+		offs2 = 0x4;
+		pin2 = (pin - GPIO_MAX/2) << 1;
+	}
+
+	mask = 0x80000000 >> pin;
+	mask2 = 0xc0000000 >> pin2;
+
+	/* first set TCR to 0 */
+	out_be32((void *)GPIO0_TCR + offs, in_be32((void *)GPIO0_TCR + offs) & ~mask);
+
+	if (in_out == GPIO_OUT) {
+		val = in_be32((void *)GPIO0_OSRL + offs + offs2) & ~mask2;
+		switch (gpio_alt) {
+		case GPIO_ALT1:
+			val |= GPIO_ALT1_SEL >> pin2;
+			break;
+		case GPIO_ALT2:
+			val |= GPIO_ALT2_SEL >> pin2;
+			break;
+		case GPIO_ALT3:
+			val |= GPIO_ALT3_SEL >> pin2;
+			break;
+		}
+		out_be32((void *)GPIO0_OSRL + offs + offs2, val);
+
+		/* setup requested output value */
+		if (out_val == GPIO_OUT_0)
+			out_be32((void *)GPIO0_OR + offs,
+				 in_be32((void *)GPIO0_OR + offs) & ~mask);
+		else if (out_val == GPIO_OUT_1)
+			out_be32((void *)GPIO0_OR + offs,
+				 in_be32((void *)GPIO0_OR + offs) | mask);
+
+		/* now configure TCR to drive output if selected */
+		out_be32((void *)GPIO0_TCR + offs,
+			 in_be32((void *)GPIO0_TCR + offs) | mask);
+	} else {
+		val = in_be32((void *)GPIO0_ISR1L + offs + offs2) & ~mask2;
+		val |= GPIO_IN_SEL >> pin2;
+		out_be32((void *)GPIO0_ISR1L + offs + offs2, val);
+	}
+}
+#endif /* GPIO_OSRL */
+
+void gpio_write_bit(int pin, int val)
+{
+	u32 offs = 0;
+
+	if (pin >= GPIO_MAX) {
+		offs = 0x100;
+		pin -= GPIO_MAX;
+	}
+
+	if (val)
+		out_be32((void *)GPIO0_OR + offs,
+			 in_be32((void *)GPIO0_OR + offs) | GPIO_VAL(pin));
+	else
+		out_be32((void *)GPIO0_OR + offs,
+			 in_be32((void *)GPIO0_OR + offs) & ~GPIO_VAL(pin));
+}
+
+int gpio_read_out_bit(int pin)
+{
+	u32 offs = 0;
+
+	if (pin >= GPIO_MAX) {
+		offs = 0x100;
+		pin -= GPIO_MAX;
+	}
+
+	return (in_be32((void *)GPIO0_OR + offs) & GPIO_VAL(pin) ? 1 : 0);
+}
+
+int gpio_read_in_bit(int pin)
+{
+	u32 offs = 0;
+
+	if (pin >= GPIO_MAX) {
+		offs = 0x100;
+		pin -= GPIO_MAX;
+	}
+
+	return (in_be32((void *)GPIO0_IR + offs) & GPIO_VAL(pin) ? 1 : 0);
+}
+
+#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
+void gpio_set_chip_configuration(void)
+{
+	unsigned char i=0, j=0, offs=0, gpio_core;
+	unsigned long reg, core_add;
+
+	for (gpio_core=0; gpio_core<GPIO_GROUP_MAX; gpio_core++) {
+		j = 0;
+		offs = 0;
+		/* GPIO config of the GPIOs 0 to 31 */
+		for (i=0; i<GPIO_MAX; i++, j++) {
+			if (i == GPIO_MAX/2) {
+				offs = 4;
+				j = i-16;
+			}
+
+			core_add = gpio_tab[gpio_core][i].add;
+
+			if ((gpio_tab[gpio_core][i].in_out == GPIO_IN) ||
+			    (gpio_tab[gpio_core][i].in_out == GPIO_BI)) {
+
+				switch (gpio_tab[gpio_core][i].alt_nb) {
+				case GPIO_SEL:
+					break;
+
+				case GPIO_ALT1:
+					reg = in_be32((void *)GPIO_IS1(core_add+offs))
+						& ~(GPIO_MASK >> (j*2));
+					reg = reg | (GPIO_IN_SEL >> (j*2));
+					out_be32((void *)GPIO_IS1(core_add+offs), reg);
+					break;
+
+				case GPIO_ALT2:
+					reg = in_be32((void *)GPIO_IS2(core_add+offs))
+						& ~(GPIO_MASK >> (j*2));
+					reg = reg | (GPIO_IN_SEL >> (j*2));
+					out_be32((void *)GPIO_IS2(core_add+offs), reg);
+					break;
+
+				case GPIO_ALT3:
+					reg = in_be32((void *)GPIO_IS3(core_add+offs))
+						& ~(GPIO_MASK >> (j*2));
+					reg = reg | (GPIO_IN_SEL >> (j*2));
+					out_be32((void *)GPIO_IS3(core_add+offs), reg);
+					break;
+				}
+			}
+
+			if ((gpio_tab[gpio_core][i].in_out == GPIO_OUT) ||
+			    (gpio_tab[gpio_core][i].in_out == GPIO_BI)) {
+
+				u32 gpio_alt_sel = 0;
+
+				switch (gpio_tab[gpio_core][i].alt_nb) {
+				case GPIO_SEL:
+					/*
+					 * Setup output value
+					 * 1 -> high level
+					 * 0 -> low level
+					 * else -> don't touch
+					 */
+					reg = in_be32((void *)GPIO_OR(core_add));
+					if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1)
+						reg |= (0x80000000 >> (i));
+					else if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_0)
+						reg &= ~(0x80000000 >> (i));
+					out_be32((void *)GPIO_OR(core_add), reg);
+
+					reg = in_be32((void *)GPIO_TCR(core_add)) |
+						(0x80000000 >> (i));
+					out_be32((void *)GPIO_TCR(core_add), reg);
+
+					reg = in_be32((void *)GPIO_OS(core_add+offs))
+						& ~(GPIO_MASK >> (j*2));
+					out_be32((void *)GPIO_OS(core_add+offs), reg);
+					reg = in_be32((void *)GPIO_TS(core_add+offs))
+						& ~(GPIO_MASK >> (j*2));
+					out_be32((void *)GPIO_TS(core_add+offs), reg);
+					break;
+
+				case GPIO_ALT1:
+					gpio_alt_sel = GPIO_ALT1_SEL;
+					break;
+
+				case GPIO_ALT2:
+					gpio_alt_sel = GPIO_ALT2_SEL;
+					break;
+
+				case GPIO_ALT3:
+					gpio_alt_sel = GPIO_ALT3_SEL;
+					break;
+				}
+
+				if (0 != gpio_alt_sel) {
+					reg = in_be32((void *)GPIO_OS(core_add+offs))
+						& ~(GPIO_MASK >> (j*2));
+					reg = reg | (gpio_alt_sel >> (j*2));
+					out_be32((void *)GPIO_OS(core_add+offs), reg);
+
+					if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1) {
+						reg = in_be32((void *)GPIO_TCR(core_add))
+							| (0x80000000 >> (i));
+						out_be32((void *)GPIO_TCR(core_add), reg);
+						reg = in_be32((void *)GPIO_TS(core_add+offs))
+							& ~(GPIO_MASK >> (j*2));
+						out_be32((void *)GPIO_TS(core_add+offs), reg);
+					} else {
+						reg = in_be32((void *)GPIO_TCR(core_add))
+							& ~(0x80000000 >> (i));
+						out_be32((void *)GPIO_TCR(core_add), reg);
+						reg = in_be32((void *)GPIO_TS(core_add+offs))
+							& ~(GPIO_MASK >> (j*2));
+						reg = reg | (gpio_alt_sel >> (j*2));
+						out_be32((void *)GPIO_TS(core_add+offs), reg);
+					}
+				}
+			}
+		}
+	}
+}
+#endif /* CONFIG_SYS_4xx_GPIO_TABLE */
diff --git a/arch/ppc/cpu/ppc4xx/interrupts.c b/arch/ppc/cpu/ppc4xx/interrupts.c
new file mode 100644
index 0000000..6db8421
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/interrupts.c
@@ -0,0 +1,216 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 (440GX port)
+ * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
+ *
+ * (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
+ * Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@uam.es
+ * Work supported by Qtechnology (htpp://qtec.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/interrupt.h>
+#include <ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct	irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	int count;
+};
+static struct irq_action irq_vecs[IRQ_MAX];
+
+#if defined(CONFIG_440)
+
+/* SPRN changed in 440 */
+static __inline__ void set_evpr(unsigned long val)
+{
+	asm volatile("mtspr 0x03f,%0" : : "r" (val));
+}
+
+#else /* !defined(CONFIG_440) */
+
+static __inline__ void set_pit(unsigned long val)
+{
+	asm volatile("mtpit %0" : : "r" (val));
+}
+
+
+static __inline__ void set_tcr(unsigned long val)
+{
+	asm volatile("mttcr %0" : : "r" (val));
+}
+
+
+static __inline__ void set_evpr(unsigned long val)
+{
+	asm volatile("mtevpr %0" : : "r" (val));
+}
+#endif /* defined(CONFIG_440 */
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	int vec;
+	unsigned long val;
+
+	/* decrementer is automatically reloaded */
+	*decrementer_count = 0;
+
+	/*
+	 * Mark all irqs as free
+	 */
+	for (vec = 0; vec < IRQ_MAX; vec++) {
+		irq_vecs[vec].handler = NULL;
+		irq_vecs[vec].arg = NULL;
+		irq_vecs[vec].count = 0;
+	}
+
+#ifdef CONFIG_4xx
+	/*
+	 * Init PIT
+	 */
+#if defined(CONFIG_440)
+	val = mfspr( SPRN_TCR );
+	val &= (~0x04400000);		/* clear DIS & ARE */
+	mtspr( SPRN_TCR, val );
+	mtspr( SPRN_DEC, 0 );		/* Prevent exception after TSR clear*/
+	mtspr( SPRN_DECAR, 0 );		/* clear reload */
+	mtspr( SPRN_TSR, 0x08000000 );	/* clear DEC status */
+	val = gd->bd->bi_intfreq/1000;	/* 1 msec */
+	mtspr( SPRN_DECAR, val );		/* Set auto-reload value */
+	mtspr( SPRN_DEC, val );		/* Set inital val */
+#else
+	set_pit(gd->bd->bi_intfreq / 1000);
+#endif
+#endif  /* CONFIG_4xx */
+
+#ifdef CONFIG_ADCIOP
+	/*
+	 * Init PIT
+	 */
+	set_pit(66000);
+#endif
+
+	/*
+	 * Enable PIT
+	 */
+	val = mfspr(SPRN_TCR);
+	val |= 0x04400000;
+	mtspr(SPRN_TCR, val);
+
+	/*
+	 * Set EVPR to 0
+	 */
+	set_evpr(0x00000000);
+
+	/*
+	 * Call uic or xilinx_irq pic_enable
+	 */
+	pic_enable();
+
+	return (0);
+}
+
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+void interrupt_run_handler(int vec)
+{
+	irq_vecs[vec].count++;
+
+	if (irq_vecs[vec].handler != NULL) {
+		/* call isr */
+		(*irq_vecs[vec].handler) (irq_vecs[vec].arg);
+	} else {
+		pic_irq_disable(vec);
+		printf("Masking bogus interrupt vector %d\n", vec);
+	}
+
+	pic_irq_ack(vec);
+	return;
+}
+
+void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
+{
+	/*
+	 * Print warning when replacing with a different irq vector
+	 */
+	if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
+		printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
+		       vec, (uint) handler, (uint) irq_vecs[vec].handler);
+	}
+	irq_vecs[vec].handler = handler;
+	irq_vecs[vec].arg = arg;
+
+	pic_irq_enable(vec);
+	return;
+}
+
+void irq_free_handler(int vec)
+{
+	debug("Free interrupt for vector %d ==> %p\n",
+	      vec, irq_vecs[vec].handler);
+
+	pic_irq_disable(vec);
+
+	irq_vecs[vec].handler = NULL;
+	irq_vecs[vec].arg = NULL;
+	return;
+}
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int vec;
+
+	printf ("Interrupt-Information:\n");
+	printf ("Nr  Routine   Arg       Count\n");
+
+	for (vec = 0; vec < IRQ_MAX; vec++) {
+		if (irq_vecs[vec].handler != NULL) {
+			printf ("%02d  %08lx  %08lx  %d\n",
+				vec,
+				(ulong)irq_vecs[vec].handler,
+				(ulong)irq_vecs[vec].arg,
+				irq_vecs[vec].count);
+		}
+	}
+
+	return 0;
+}
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/iop480_uart.c b/arch/ppc/cpu/ppc4xx/iop480_uart.c
new file mode 100644
index 0000000..0e3423f
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/iop480_uart.c
@@ -0,0 +1,237 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <watchdog.h>
+
+#ifdef CONFIG_SERIAL_MULTI
+#include <serial.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_IOP480
+
+#define SPU_BASE         0x40000000
+
+#define spu_LineStat_rc  0x00	/* Line Status Register (Read/Clear) */
+#define spu_LineStat_w   0x04	/* Line Status Register (Set) */
+#define spu_Handshk_rc   0x08	/* Handshake Status Register (Read/Clear) */
+#define spu_Handshk_w    0x0c	/* Handshake Status Register (Set) */
+#define spu_BRateDivh    0x10	/* Baud rate divisor high */
+#define spu_BRateDivl    0x14	/* Baud rate divisor low */
+#define spu_CtlReg       0x18	/* Control Register */
+#define spu_RxCmd        0x1c	/* Rx Command Register */
+#define spu_TxCmd        0x20	/* Tx Command Register */
+#define spu_RxBuff       0x24	/* Rx data buffer */
+#define spu_TxBuff       0x24	/* Tx data buffer */
+
+/*-----------------------------------------------------------------------------+
+  | Line Status Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncLSRport1           0x40000000
+#define asyncLSRport1set        0x40000004
+#define asyncLSRDataReady             0x80
+#define asyncLSRFramingError          0x40
+#define asyncLSROverrunError          0x20
+#define asyncLSRParityError           0x10
+#define asyncLSRBreakInterrupt        0x08
+#define asyncLSRTxHoldEmpty           0x04
+#define asyncLSRTxShiftEmpty          0x02
+
+/*-----------------------------------------------------------------------------+
+  | Handshake Status Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncHSRport1           0x40000008
+#define asyncHSRport1set        0x4000000c
+#define asyncHSRDsr                   0x80
+#define asyncLSRCts                   0x40
+
+/*-----------------------------------------------------------------------------+
+  | Control Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncCRport1            0x40000018
+#define asyncCRNormal                 0x00
+#define asyncCRLoopback               0x40
+#define asyncCRAutoEcho               0x80
+#define asyncCRDtr                    0x20
+#define asyncCRRts                    0x10
+#define asyncCRWordLength7            0x00
+#define asyncCRWordLength8            0x08
+#define asyncCRParityDisable          0x00
+#define asyncCRParityEnable           0x04
+#define asyncCREvenParity             0x00
+#define asyncCROddParity              0x02
+#define asyncCRStopBitsOne            0x00
+#define asyncCRStopBitsTwo            0x01
+#define asyncCRDisableDtrRts          0x00
+
+/*-----------------------------------------------------------------------------+
+  | Receiver Command Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncRCRport1           0x4000001c
+#define asyncRCRDisable               0x00
+#define asyncRCREnable                0x80
+#define asyncRCRIntDisable            0x00
+#define asyncRCRIntEnabled            0x20
+#define asyncRCRDMACh2                0x40
+#define asyncRCRDMACh3                0x60
+#define asyncRCRErrorInt              0x10
+#define asyncRCRPauseEnable           0x08
+
+/*-----------------------------------------------------------------------------+
+  | Transmitter Command Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncTCRport1           0x40000020
+#define asyncTCRDisable               0x00
+#define asyncTCREnable                0x80
+#define asyncTCRIntDisable            0x00
+#define asyncTCRIntEnabled            0x20
+#define asyncTCRDMACh2                0x40
+#define asyncTCRDMACh3                0x60
+#define asyncTCRTxEmpty               0x10
+#define asyncTCRErrorInt              0x08
+#define asyncTCRStopPause             0x04
+#define asyncTCRBreakGen              0x02
+
+/*-----------------------------------------------------------------------------+
+  | Miscellanies defines.
+  +-----------------------------------------------------------------------------*/
+#define asyncTxBufferport1      0x40000024
+#define asyncRxBufferport1      0x40000024
+#define asyncDLABLsbport1       0x40000014
+#define asyncDLABMsbport1       0x40000010
+#define asyncXOFFchar                 0x13
+#define asyncXONchar                  0x11
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+int serial_init (void)
+{
+	volatile char val;
+	unsigned short br_reg;
+
+	br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1);
+
+	/*
+	 * Init onboard UART
+	 */
+	out_8((u8 *)SPU_BASE + spu_LineStat_rc, 0x78); /* Clear all bits in Line Status Reg */
+	out_8((u8 *)SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */
+	out_8((u8 *)SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */
+	out_8((u8 *)SPU_BASE + spu_CtlReg, 0x08);	/* Set 8 bits, no parity and 1 stop bit */
+	out_8((u8 *)SPU_BASE + spu_RxCmd, 0xb0);	/* Enable Rx */
+	out_8((u8 *)SPU_BASE + spu_TxCmd, 0x9c);	/* Enable Tx */
+	out_8((u8 *)SPU_BASE + spu_Handshk_rc, 0xff);	/* Clear Handshake */
+	val = in_8((u8 *)SPU_BASE + spu_RxBuff);	/* Dummy read, to clear receiver */
+
+	return (0);
+}
+
+void serial_setbrg (void)
+{
+	unsigned short br_reg;
+
+	br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1);
+
+	out_8((u8 *)SPU_BASE + spu_BRateDivl,
+	      (br_reg & 0x00ff)); /* Set baud rate divisor... */
+	out_8((u8 *)SPU_BASE + spu_BRateDivh,
+	      ((br_reg & 0xff00) >> 8)); /* ... */
+}
+
+void serial_putc (const char c)
+{
+	if (c == '\n')
+		serial_putc ('\r');
+
+	/* load status from handshake register */
+	if (in_8((u8 *)SPU_BASE + spu_Handshk_rc) != 00)
+		out_8((u8 *)SPU_BASE + spu_Handshk_rc, 0xff);	/* Clear Handshake */
+
+	out_8((u8 *)SPU_BASE + spu_TxBuff, c);	/* Put char */
+
+	while ((in_8((u8 *)SPU_BASE + spu_LineStat_rc) & 04) != 04) {
+		if (in_8((u8 *)SPU_BASE + spu_Handshk_rc) != 00)
+			out_8((u8 *)SPU_BASE + spu_Handshk_rc, 0xff);	/* Clear Handshake */
+	}
+}
+
+void serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int serial_getc ()
+{
+	unsigned char status = 0;
+
+	while (1) {
+		status = in_8((u8 *)asyncLSRport1);
+		if ((status & asyncLSRDataReady) != 0x0) {
+			break;
+		}
+		if ((status & ( asyncLSRFramingError |
+				asyncLSROverrunError |
+				asyncLSRParityError  |
+				asyncLSRBreakInterrupt )) != 0) {
+			(void) out_8((u8 *)asyncLSRport1,
+				     asyncLSRFramingError |
+				     asyncLSROverrunError |
+				     asyncLSRParityError  |
+				     asyncLSRBreakInterrupt );
+		}
+	}
+	return (0x000000ff & (int) in_8((u8 *)asyncRxBufferport1));
+}
+
+int serial_tstc ()
+{
+	unsigned char status;
+
+	status = in_8((u8 *)asyncLSRport1);
+	if ((status & asyncLSRDataReady) != 0x0) {
+		return (1);
+	}
+	if ((status & ( asyncLSRFramingError |
+			asyncLSROverrunError |
+			asyncLSRParityError  |
+			asyncLSRBreakInterrupt )) != 0) {
+		(void) out_8((u8 *)asyncLSRport1,
+			     asyncLSRFramingError |
+			     asyncLSROverrunError |
+			     asyncLSRParityError  |
+			     asyncLSRBreakInterrupt);
+	}
+	return 0;
+}
+
+#endif	/* CONFIG_IOP480 */
diff --git a/arch/ppc/cpu/ppc4xx/kgdb.S b/arch/ppc/cpu/ppc4xx/kgdb.S
new file mode 100644
index 0000000..4227a4c
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/kgdb.S
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (C) 2000	Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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 <command.h>
+#include <ppc4xx.h>
+#include <version.h>
+
+#define CONFIG_405GP 1		/* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+ /*
+ * cache flushing routines for kgdb
+ */
+
+	.globl	kgdb_flush_cache_all
+kgdb_flush_cache_all:
+	/* icache */
+	iccci   r0,r0		/* iccci invalidates the entire I cache */
+	/* dcache */
+	addi    r6,0,0x0000     /* clear GPR 6 */
+	addi    r7,r0, 128	/* do loop for # of dcache lines */
+				/* NOTE: dccci invalidates both */
+	mtctr   r7              /* ways in the D cache */
+..dcloop:
+	dccci   0,r6            /* invalidate line */
+	addi    r6,r6, 32	/* bump to next line */
+	bdnz    ..dcloop
+	blr
+
+	.globl	kgdb_flush_cache_range
+kgdb_flush_cache_range:
+	li	r5,L1_CACHE_BYTES-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,L1_CACHE_SHIFT
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,L1_CACHE_BYTES
+	bdnz	1b
+	sync			/* wait for dcbst's to get to ram */
+	mtctr	r4
+2:	icbi	0,r6
+	addi	r6,r6,L1_CACHE_BYTES
+	bdnz	2b
+	SYNC
+	blr
+
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/miiphy.c b/arch/ppc/cpu/ppc4xx/miiphy.c
new file mode 100644
index 0000000..22ed5c2
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/miiphy.c
@@ -0,0 +1,366 @@
+/*-----------------------------------------------------------------------------+
+  |   This source code is dual-licensed.  You may use it under the terms of the
+  |   GNU General Public License version 2, or under the license below.
+  |
+  |	  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:	 miiphy.c
+  |
+  |  Function:	 This module has utilities for accessing the MII PHY through
+  |	       the EMAC3 macro.
+  |
+  |  Author:	 Mark Wisner
+  |
+  +-----------------------------------------------------------------------------*/
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <ppc4xx_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+
+#if !defined(CONFIG_PHY_CLK_FREQ)
+#define CONFIG_PHY_CLK_FREQ	0
+#endif
+
+/***********************************************************/
+/* Dump out to the screen PHY regs			   */
+/***********************************************************/
+
+void miiphy_dump (char *devname, unsigned char addr)
+{
+	unsigned long i;
+	unsigned short data;
+
+	for (i = 0; i < 0x1A; i++) {
+		if (miiphy_read (devname, addr, i, &data)) {
+			printf ("read error for reg %lx\n", i);
+			return;
+		}
+		printf ("Phy reg %lx ==> %4x\n", i, data);
+
+		/* jump to the next set of regs */
+		if (i == 0x07)
+			i = 0x0f;
+
+	}			/* end for loop */
+}				/* end dump */
+
+/***********************************************************/
+/* (Re)start autonegotiation				   */
+/***********************************************************/
+int phy_setup_aneg (char *devname, unsigned char addr)
+{
+	u16 bmcr;
+
+#if defined(CONFIG_PHY_DYNAMIC_ANEG)
+	/*
+	 * Set up advertisement based on capablilities reported by the PHY.
+	 * This should work for both copper and fiber.
+	 */
+	u16 bmsr;
+#if defined(CONFIG_PHY_GIGE)
+	u16 exsr = 0x0000;
+#endif
+
+	miiphy_read (devname, addr, PHY_BMSR, &bmsr);
+
+#if defined(CONFIG_PHY_GIGE)
+	if (bmsr & PHY_BMSR_EXT_STAT)
+		miiphy_read (devname, addr, PHY_EXSR, &exsr);
+
+	if (exsr & (PHY_EXSR_1000XF | PHY_EXSR_1000XH)) {
+		/* 1000BASE-X */
+		u16 anar = 0x0000;
+
+		if (exsr & PHY_EXSR_1000XF)
+			anar |= PHY_X_ANLPAR_FD;
+
+		if (exsr & PHY_EXSR_1000XH)
+			anar |= PHY_X_ANLPAR_HD;
+
+		miiphy_write (devname, addr, PHY_ANAR, anar);
+	} else
+#endif
+	{
+		u16 anar, btcr;
+
+		miiphy_read (devname, addr, PHY_ANAR, &anar);
+		anar &= ~(0x5000 | PHY_ANLPAR_T4 | PHY_ANLPAR_TXFD |
+			  PHY_ANLPAR_TX | PHY_ANLPAR_10FD | PHY_ANLPAR_10);
+
+		miiphy_read (devname, addr, PHY_1000BTCR, &btcr);
+		btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
+
+		if (bmsr & PHY_BMSR_100T4)
+			anar |= PHY_ANLPAR_T4;
+
+		if (bmsr & PHY_BMSR_100TXF)
+			anar |= PHY_ANLPAR_TXFD;
+
+		if (bmsr & PHY_BMSR_100TXH)
+			anar |= PHY_ANLPAR_TX;
+
+		if (bmsr & PHY_BMSR_10TF)
+			anar |= PHY_ANLPAR_10FD;
+
+		if (bmsr & PHY_BMSR_10TH)
+			anar |= PHY_ANLPAR_10;
+
+		miiphy_write (devname, addr, PHY_ANAR, anar);
+
+#if defined(CONFIG_PHY_GIGE)
+		if (exsr & PHY_EXSR_1000TF)
+			btcr |= PHY_1000BTCR_1000FD;
+
+		if (exsr & PHY_EXSR_1000TH)
+			btcr |= PHY_1000BTCR_1000HD;
+
+		miiphy_write (devname, addr, PHY_1000BTCR, btcr);
+#endif
+	}
+
+#else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+	/*
+	 * Set up standard advertisement
+	 */
+	u16 adv;
+
+	miiphy_read (devname, addr, PHY_ANAR, &adv);
+	adv |= (PHY_ANLPAR_ACK  | PHY_ANLPAR_TXFD | PHY_ANLPAR_TX |
+		PHY_ANLPAR_10FD | PHY_ANLPAR_10);
+	miiphy_write (devname, addr, PHY_ANAR, adv);
+
+	miiphy_read (devname, addr, PHY_1000BTCR, &adv);
+	adv |= (0x0300);
+	miiphy_write (devname, addr, PHY_1000BTCR, adv);
+
+#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+
+	/* Start/Restart aneg */
+	miiphy_read (devname, addr, PHY_BMCR, &bmcr);
+	bmcr |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+	miiphy_write (devname, addr, PHY_BMCR, bmcr);
+
+	return 0;
+}
+
+/***********************************************************/
+/* read a phy reg and return the value with a rc	   */
+/***********************************************************/
+/* AMCC_TODO:
+ * Find out of the choice for the emac for MDIO is from the bridges,
+ * i.e. ZMII or RGMII as approporiate.  If the bridges are not used
+ * to determine the emac for MDIO, then is the SDR0_ETH_CFG[MDIO_SEL]
+ * used?  If so, then this routine below does not apply to the 460EX/GT.
+ *
+ * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
+ * return EMAC0 offset here
+ * vg: For 460EX/460GT if internal GPCS PHY address is specified
+ * return appropriate EMAC offset
+ */
+unsigned int miiphy_getemac_offset(u8 addr)
+{
+#if (defined(CONFIG_440) && \
+    !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
+    !defined(CONFIG_460EX) && !defined(CONFIG_460GT)) && \
+    defined(CONFIG_NET_MULTI)
+	unsigned long zmii;
+	unsigned long eoffset;
+
+	/* Need to find out which mdi port we're using */
+	zmii = in_be32((void *)ZMII0_FER);
+
+	if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0)))
+		/* using port 0 */
+		eoffset = 0;
+
+	else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1)))
+		/* using port 1 */
+		eoffset = 0x100;
+
+	else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2)))
+		/* using port 2 */
+		eoffset = 0x400;
+
+	else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3)))
+		/* using port 3 */
+		eoffset = 0x600;
+
+	else {
+		/* None of the mdi ports are enabled! */
+		/* enable port 0 */
+		zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
+		out_be32((void *)ZMII0_FER, zmii);
+		eoffset = 0;
+		/* need to soft reset port 0 */
+		zmii = in_be32((void *)EMAC0_MR0);
+		zmii |= EMAC_MR0_SRST;
+		out_be32((void *)EMAC0_MR0, zmii);
+	}
+
+	return (eoffset);
+#else
+
+#if defined(CONFIG_NET_MULTI) && defined(CONFIG_405EX)
+	unsigned long rgmii;
+	int devnum = 1;
+
+	rgmii = in_be32((void *)RGMII_FER);
+	if (rgmii & (1 << (19 - devnum)))
+		return 0x100;
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	u32 eoffset = 0;
+
+	switch (addr) {
+#if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
+	case CONFIG_GPCS_PHY1_ADDR:
+		if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x100)))
+			eoffset = 0x100;
+		break;
+#endif
+#if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
+	case CONFIG_GPCS_PHY2_ADDR:
+		if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x300)))
+			eoffset = 0x300;
+		break;
+#endif
+#if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
+	case CONFIG_GPCS_PHY3_ADDR:
+		if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x400)))
+			eoffset = 0x400;
+		break;
+#endif
+	default:
+		eoffset = 0;
+		break;
+	}
+	return eoffset;
+#endif
+
+	return 0;
+#endif
+}
+
+static int emac_miiphy_wait(u32 emac_reg)
+{
+	u32 sta_reg;
+	int i;
+
+	/* wait for completion */
+	i = 0;
+	do {
+		sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
+		if (i++ > 5) {
+			debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__,
+			      __LINE__, sta_reg);
+			return -1;
+		}
+		udelay(10);
+	} while ((sta_reg & EMAC_STACR_OC) == EMAC_STACR_OC_MASK);
+
+	return 0;
+}
+
+static int emac_miiphy_command(u8 addr, u8 reg, int cmd, u16 value)
+{
+	u32 emac_reg;
+	u32 sta_reg;
+
+	emac_reg = miiphy_getemac_offset(addr);
+
+	/* wait for completion */
+	if (emac_miiphy_wait(emac_reg) != 0)
+		return -1;
+
+	sta_reg = reg;		/* reg address */
+
+	/* set clock (50MHz) and read flags */
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+    defined(CONFIG_405EX)
+#if defined(CONFIG_IBM_EMAC4_V4)	/* EMAC4 V4 changed bit setting */
+	sta_reg = (sta_reg & ~EMAC_STACR_OP_MASK) | cmd;
+#else
+	sta_reg |= cmd;
+#endif
+#else
+	sta_reg = (sta_reg | cmd) & ~EMAC_STACR_CLK_100MHZ;
+#endif
+
+	/* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
+	sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
+	sta_reg = sta_reg | ((u32)addr << 5);	/* Phy address */
+	sta_reg = sta_reg | EMAC_STACR_OC_MASK;	/* new IBM emac v4 */
+	if (cmd == EMAC_STACR_WRITE)
+		memcpy(&sta_reg, &value, 2);	/* put in data */
+
+	out_be32((void *)EMAC0_STACR + emac_reg, sta_reg);
+	debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
+
+	/* wait for completion */
+	if (emac_miiphy_wait(emac_reg) != 0)
+		return -1;
+
+	debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
+	if ((sta_reg & EMAC_STACR_PHYE) != 0)
+		return -1;
+
+	return 0;
+}
+
+int emac4xx_miiphy_read (char *devname, unsigned char addr, unsigned char reg,
+			 unsigned short *value)
+{
+	unsigned long sta_reg;
+	unsigned long emac_reg;
+
+	emac_reg = miiphy_getemac_offset(addr);
+
+	if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
+		return -1;
+
+	sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
+	*value = sta_reg >> 16;
+
+	return 0;
+}
+
+/***********************************************************/
+/* write a phy reg and return the value with a rc	    */
+/***********************************************************/
+
+int emac4xx_miiphy_write (char *devname, unsigned char addr, unsigned char reg,
+			  unsigned short value)
+{
+	return emac_miiphy_command(addr, reg, EMAC_STACR_WRITE, value);
+}
diff --git a/arch/ppc/cpu/ppc4xx/reginfo.c b/arch/ppc/cpu/ppc4xx/reginfo.c
new file mode 100644
index 0000000..a975667
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/reginfo.c
@@ -0,0 +1,370 @@
+/*
+ *(C) Copyright 2005-2009 Netstal Maschinen AG
+ *    Bruno Hars (Bruno.Hars@netstal.com)
+ *    Niklaus Giger (Niklaus.Giger@netstal.com)
+ *
+ *    This source code is free software; you can redistribute it
+ *    and/or modify it in source code form 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
+ */
+
+/*
+ * reginfo.c - register dump of HW-configuratin register for PPC4xx based board
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/ppc4xx-uic.h>
+#include <ppc4xx_enet.h>
+
+enum REGISTER_TYPE {
+	IDCR1,	/* Indirectly Accessed DCR via SDRAM0_CFGADDR/SDRAM0_CFGDATA */
+	IDCR2,	/* Indirectly Accessed DCR via EBC0_CFGADDR/EBC0_CFGDATA */
+	IDCR3,	/* Indirectly Accessed DCR via EBM0_CFGADDR/EBM0_CFGDATA */
+	IDCR4,	/* Indirectly Accessed DCR via PPM0_CFGADDR/PPM0_CFGDATA */
+	IDCR5,	/* Indirectly Accessed DCR via CPR0_CFGADDR/CPR0_CFGDATA */
+	IDCR6,	/* Indirectly Accessed DCR via SDR0_CFGADDR/SDR0_CFGDATA */
+	MM	/* Directly Accessed MMIO Register */
+};
+
+struct cpu_register {
+	char *name;
+	enum REGISTER_TYPE type;
+	u32 address;
+};
+
+/*
+ * PPC440EPx registers ordered for output
+ * name           type    addr            size
+ * -------------------------------------------
+ */
+
+const struct cpu_register ppc4xx_reg[] = {
+	{"PB0CR",		IDCR2,	PB0CR},
+	{"PB0AP",		IDCR2,	PB0AP},
+	{"PB1CR",		IDCR2,	PB1CR},
+	{"PB1AP",		IDCR2,	PB1AP},
+	{"PB2CR",		IDCR2,	PB2CR},
+	{"PB2AP",		IDCR2,	PB2AP},
+	{"PB3CR",		IDCR2,	PB3CR},
+	{"PB3AP",		IDCR2,	PB3AP},
+
+	{"PB4CR",		IDCR2,	PB4CR},
+	{"PB4AP",		IDCR2,	PB4AP},
+#if !defined(CONFIG_405EP)
+	{"PB5CR",		IDCR2,	PB5CR},
+	{"PB5AP",		IDCR2,	PB5AP},
+	{"PB6CR",		IDCR2,	PB6CR},
+	{"PB6AP",		IDCR2,	PB6AP},
+	{"PB7CR",		IDCR2,	PB7CR},
+	{"PB7AP",		IDCR2,	PB7AP},
+#endif
+
+	{"PBEAR",		IDCR2,	PBEAR},
+#if defined(CONFIG_405EP) || defined (CONFIG_405GP)
+	{"PBESR0",		IDCR2,	PBESR0},
+	{"PBESR1",		IDCR2,	PBESR1},
+#endif
+	{"EBC0_CFG",		IDCR2,	EBC0_CFG},
+
+#ifdef CONFIG_405GP
+	{"SDRAM0_BESR0",	IDCR1,	SDRAM0_BESR0},
+	{"SDRAM0_BESRS0",	IDCR1,	SDRAM0_BESRS0},
+	{"SDRAM0_BESR1",	IDCR1,	SDRAM0_BESR1},
+	{"SDRAM0_BESRS1",	IDCR1,	SDRAM0_BESRS1},
+	{"SDRAM0_BEAR",		IDCR1,	SDRAM0_BEAR},
+	{"SDRAM0_CFG",		IDCR1,	SDRAM0_CFG},
+	{"SDRAM0_RTR",		IDCR1,	SDRAM0_RTR},
+	{"SDRAM0_PMIT",		IDCR1,	SDRAM0_PMIT},
+
+	{"SDRAM0_B0CR",		IDCR1,	SDRAM0_B0CR},
+	{"SDRAM0_B1CR",		IDCR1,	SDRAM0_B1CR},
+	{"SDRAM0_B2CR",		IDCR1,	SDRAM0_B2CR},
+	{"SDRAM0_B3CR",		IDCR1,	SDRAM0_B1CR},
+	{"SDRAM0_TR",		IDCR1,	SDRAM0_TR},
+	{"SDRAM0_ECCCFG",	IDCR1,	SDRAM0_B1CR},
+	{"SDRAM0_ECCESR",	IDCR1,	SDRAM0_ECCESR},
+
+
+#endif
+
+#ifdef CONFIG_440EPX
+	{"SDR0_SDSTP0",		IDCR6,	SDR0_SDSTP0},
+	{"SDR0_SDSTP1",		IDCR6,	SDR0_SDSTP1},
+	{"SDR0_SDSTP2",		IDCR6,	SDR0_SDSTP2},
+	{"SDR0_SDSTP3",		IDCR6,	SDR0_SDSTP3},
+	{"SDR0_CUST0",		IDCR6,	SDR0_CUST0},
+	{"SDR0_CUST1",		IDCR6,	SDR0_CUST1},
+	{"SDR0_EBC0",		IDCR6,	SDR0_EBC0},
+	{"SDR0_AMP0",		IDCR6,	SD0_AMP0},
+	{"SDR0_AMP1",		IDCR6,	SD0_AMP1},
+	{"SDR0_CP440",		IDCR6,	SDR0_CP440},
+	{"SDR0_CRYP0",		IDCR6,	SDR0_CRYP0},
+	{"SDR0_DDRCFG",		IDCR6,	SDR0_DDRCFG},
+	{"SDR0_EMAC0RXST",	IDCR6,	SDR0_EMAC0RXST},
+	{"SDR0_EMAC0TXST",	IDCR6,	SDR0_EMAC0TXST},
+	{"SDR0_MFR",		IDCR6,	SDR0_MFR},
+	{"SDR0_PCI0",		IDCR6,	SDR0_PCI0},
+	{"SDR0_PFC0",		IDCR6,	SDR0_PFC0},
+	{"SDR0_PFC1",		IDCR6,	SDR0_PFC1},
+	{"SDR0_PFC2",		IDCR6,	SDR0_PFC2},
+	{"SDR0_PFC4",		IDCR6,	SDR0_PFC4},
+	{"SDR0_UART0",		IDCR6,	SDR0_UART0},
+	{"SDR0_UART1",		IDCR6,	SDR0_UART1},
+	{"SDR0_UART2",		IDCR6,	SDR0_UART2},
+	{"SDR0_UART3",		IDCR6,	SDR0_UART3},
+	{"DDR0_02",		IDCR1,	DDR0_02},
+	{"DDR0_00",		IDCR1,	DDR0_00},
+	{"DDR0_01",		IDCR1,	DDR0_01},
+	{"DDR0_03",		IDCR1,	DDR0_03},
+	{"DDR0_04",		IDCR1,	DDR0_04},
+	{"DDR0_05",		IDCR1,	DDR0_05},
+	{"DDR0_06",		IDCR1,	DDR0_06},
+	{"DDR0_07",		IDCR1,	DDR0_07},
+	{"DDR0_08",		IDCR1,	DDR0_08},
+	{"DDR0_09",		IDCR1,	DDR0_09},
+	{"DDR0_10",		IDCR1,	DDR0_10},
+	{"DDR0_11",		IDCR1,	DDR0_11},
+	{"DDR0_12",		IDCR1,	DDR0_12},
+	{"DDR0_14",		IDCR1,	DDR0_14},
+	{"DDR0_17",		IDCR1,	DDR0_17},
+	{"DDR0_18",		IDCR1,	DDR0_18},
+	{"DDR0_19",		IDCR1,	DDR0_19},
+	{"DDR0_20",		IDCR1,	DDR0_20},
+	{"DDR0_21",		IDCR1,	DDR0_21},
+	{"DDR0_22",		IDCR1,	DDR0_22},
+	{"DDR0_23",		IDCR1,	DDR0_23},
+	{"DDR0_24",		IDCR1,	DDR0_24},
+	{"DDR0_25",		IDCR1,	DDR0_25},
+	{"DDR0_26",		IDCR1,	DDR0_26},
+	{"DDR0_27",		IDCR1,	DDR0_27},
+	{"DDR0_28",		IDCR1,	DDR0_28},
+	{"DDR0_31",		IDCR1,	DDR0_31},
+	{"DDR0_32",		IDCR1,	DDR0_32},
+	{"DDR0_33",		IDCR1,	DDR0_33},
+	{"DDR0_34",		IDCR1,	DDR0_34},
+	{"DDR0_35",		IDCR1,	DDR0_35},
+	{"DDR0_36",		IDCR1,	DDR0_36},
+	{"DDR0_37",		IDCR1,	DDR0_37},
+	{"DDR0_38",		IDCR1,	DDR0_38},
+	{"DDR0_39",		IDCR1,	DDR0_39},
+	{"DDR0_40",		IDCR1,	DDR0_40},
+	{"DDR0_41",		IDCR1,	DDR0_41},
+	{"DDR0_42",		IDCR1,	DDR0_42},
+	{"DDR0_43",		IDCR1,	DDR0_43},
+	{"DDR0_44",		IDCR1,	DDR0_44},
+	{"CPR0_ICFG",		IDCR5,	CPR0_ICFG},
+	{"CPR0_MALD",		IDCR5,	CPR0_MALD},
+	{"CPR0_OPBD00",		IDCR5,	CPR0_OPBD0},
+	{"CPR0_PERD0",		IDCR5,	CPR0_PERD},
+	{"CPR0_PLLC0",		IDCR5,	CPR0_PLLC},
+	{"CPR0_PLLD0",		IDCR5,	CPR0_PLLD},
+	{"CPR0_PRIMAD0",	IDCR5,	CPR0_PRIMAD0},
+	{"CPR0_PRIMBD0",	IDCR5,	CPR0_PRIMBD0},
+	{"CPR0_SPCID",		IDCR5,	CPR0_SPCID},
+	{"SPI0_MODE",		MM,	SPI0_MODE},
+	{"IIC0_CLKDIV",		MM,	PCIL0_PMM1MA},
+	{"PCIL0_PMM0MA",	MM,	PCIL0_PMM0MA},
+	{"PCIL0_PMM1MA",	MM,	PCIL0_PMM1MA},
+	{"PCIL0_PTM1LA",	MM,	PCIL0_PMM1MA},
+	{"PCIL0_PTM1MS",	MM,	PCIL0_PTM1MS},
+	{"PCIL0_PTM2LA",	MM,	PCIL0_PMM1MA},
+	{"PCIL0_PTM2MS",	MM,	PCIL0_PTM2MS},
+	{"ZMII0_FER",		MM,	ZMII0_FER},
+	{"ZMII0_SSR",		MM,	ZMII0_SSR},
+	{"EMAC0_IPGVR",		MM,	EMAC0_IPGVR},
+	{"EMAC0_MR1",		MM,	EMAC0_MR1},
+	{"EMAC0_PTR",		MM,	EMAC0_PTR},
+	{"EMAC0_RWMR",		MM,	EMAC0_RWMR},
+	{"EMAC0_STACR",		MM,	EMAC0_STACR},
+	{"EMAC0_TMR0",		MM,	EMAC0_TMR0},
+	{"EMAC0_TMR1",		MM,	EMAC0_TMR1},
+	{"EMAC0_TRTR",		MM,	EMAC0_TRTR},
+	{"EMAC1_MR1",		MM,	EMAC1_MR1},
+	{"GPIO0_OR",		MM,	GPIO0_OR},
+	{"GPIO1_OR",		MM,	GPIO1_OR},
+	{"GPIO0_TCR",		MM,	GPIO0_TCR},
+	{"GPIO1_TCR",		MM,	GPIO1_TCR},
+	{"GPIO0_ODR",		MM,	GPIO0_ODR},
+	{"GPIO1_ODR",		MM,	GPIO1_ODR},
+	{"GPIO0_OSRL",		MM,	GPIO0_OSRL},
+	{"GPIO0_OSRH",		MM,	GPIO0_OSRH},
+	{"GPIO1_OSRL",		MM,	GPIO1_OSRL},
+	{"GPIO1_OSRH",		MM,	GPIO1_OSRH},
+	{"GPIO0_TSRL",		MM,	GPIO0_TSRL},
+	{"GPIO0_TSRH",		MM,	GPIO0_TSRH},
+	{"GPIO1_TSRL",		MM,	GPIO1_TSRL},
+	{"GPIO1_TSRH",		MM,	GPIO1_TSRH},
+	{"GPIO0_IR",		MM,	GPIO0_IR},
+	{"GPIO1_IR",		MM,	GPIO1_IR},
+	{"GPIO0_ISR1L",		MM,	GPIO0_ISR1L},
+	{"GPIO0_ISR1H",		MM,	GPIO0_ISR1H},
+	{"GPIO1_ISR1L",		MM,	GPIO1_ISR1L},
+	{"GPIO1_ISR1H",		MM,	GPIO1_ISR1H},
+	{"GPIO0_ISR2L",		MM,	GPIO0_ISR2L},
+	{"GPIO0_ISR2H",		MM,	GPIO0_ISR2H},
+	{"GPIO1_ISR2L",		MM,	GPIO1_ISR2L},
+	{"GPIO1_ISR2H",		MM,	GPIO1_ISR2H},
+	{"GPIO0_ISR3L",		MM,	GPIO0_ISR3L},
+	{"GPIO0_ISR3H",		MM,	GPIO0_ISR3H},
+	{"GPIO1_ISR3L",		MM,	GPIO1_ISR3L},
+	{"GPIO1_ISR3H",		MM,	GPIO1_ISR3H},
+	{"SDR0_USB2PHY0CR",	IDCR6,	SDR0_USB2PHY0CR},
+	{"SDR0_USB2H0CR",	IDCR6,	SDR0_USB2H0CR},
+	{"SDR0_USB2D0CR",	IDCR6,	SDR0_USB2D0CR},
+#endif
+};
+
+/*
+ * CPU Register dump of PPC4xx HW configuration registers
+ * Output: first all DCR-registers, then in order of struct ppc4xx_reg
+ */
+#define PRINT_DCR(dcr) 	printf("0x%08x %-16s: 0x%08x\n", dcr,#dcr, mfdcr(dcr));
+
+void ppc4xx_reginfo(void)
+{
+	unsigned int i;
+	unsigned int n;
+	u32 value;
+	enum REGISTER_TYPE type;
+#if defined (CONFIG_405EP)
+	printf("Dump PPC405EP HW configuration registers\n\n");
+#elif CONFIG_405GP
+	printf ("Dump 405GP HW configuration registers\n\n");
+#elif CONFIG_440EPX
+	printf("Dump PPC440EPx HW configuration registers\n\n");
+#endif
+	printf("MSR: 0x%08x\n", mfmsr());
+
+	printf ("\nUniversal Interrupt Controller Regs\n");
+	PRINT_DCR(UIC0SR);
+	PRINT_DCR(UIC0ER);
+	PRINT_DCR(UIC0CR);
+	PRINT_DCR(UIC0PR);
+	PRINT_DCR(UIC0TR);
+	PRINT_DCR(UIC0MSR);
+	PRINT_DCR(UIC0VR);
+	PRINT_DCR(UIC0VCR);
+
+#if (UIC_MAX > 1)
+	PRINT_DCR(UIC2SR);
+	PRINT_DCR(UIC2ER);
+	PRINT_DCR(UIC2CR);
+	PRINT_DCR(UIC2PR);
+	PRINT_DCR(UIC2TR);
+	PRINT_DCR(UIC2MSR);
+	PRINT_DCR(UIC2VR);
+	PRINT_DCR(UIC2VCR);
+#endif
+
+#if (UIC_MAX > 2)
+	PRINT_DCR(UIC2SR);
+	PRINT_DCR(UIC2ER);
+	PRINT_DCR(UIC2CR);
+	PRINT_DCR(UIC2PR);
+	PRINT_DCR(UIC2TR);
+	PRINT_DCR(UIC2MSR);
+	PRINT_DCR(UIC2VR);
+	PRINT_DCR(UIC2VCR);
+#endif
+
+#if (UIC_MAX > 3)
+	PRINT_DCR(UIC3SR);
+	PRINT_DCR(UIC3ER);
+	PRINT_DCR(UIC3CR);
+	PRINT_DCR(UIC3PR);
+	PRINT_DCR(UIC3TR);
+	PRINT_DCR(UIC3MSR);
+	PRINT_DCR(UIC3VR);
+	PRINT_DCR(UIC3VCR);
+#endif
+
+#if defined (CONFIG_405EP) || defined (CONFIG_405GP)
+	printf ("\n\nDMA Channels\n");
+	PRINT_DCR(DMASR);
+	PRINT_DCR(DMASGC);
+	PRINT_DCR(DMAADR);
+
+	PRINT_DCR(DMACR0);
+	PRINT_DCR(DMACT0);
+	PRINT_DCR(DMADA0);
+	PRINT_DCR(DMASA0);
+	PRINT_DCR(DMASB0);
+
+	PRINT_DCR(DMACR1);
+	PRINT_DCR(DMACT1);
+	PRINT_DCR(DMADA1);
+	PRINT_DCR(DMASA1);
+	PRINT_DCR(DMASB1);
+
+	PRINT_DCR(DMACR2);
+	PRINT_DCR(DMACT2);
+	PRINT_DCR(DMADA2);
+	PRINT_DCR(DMASA2);
+	PRINT_DCR(DMASB2);
+
+	PRINT_DCR(DMACR3);
+	PRINT_DCR(DMACT3);
+	PRINT_DCR(DMADA3);
+	PRINT_DCR(DMASA3);
+	PRINT_DCR(DMASB3);
+#endif
+
+	printf ("\n\nVarious HW-Configuration registers\n");
+#if defined (CONFIG_440EPX)
+	PRINT_DCR(MAL0_CFG);
+	PRINT_DCR(CPM0_ER);
+	PRINT_DCR(CPM1_ER);
+	PRINT_DCR(PLB4A0_ACR);
+	PRINT_DCR(PLB4A1_ACR);
+	PRINT_DCR(PLB3A0_ACR);
+	PRINT_DCR(OPB2PLB40_BCTRL);
+	PRINT_DCR(P4P3BO0_CFG);
+#endif
+	n = sizeof(ppc4xx_reg) / sizeof(ppc4xx_reg[0]);
+	for (i = 0; i < n; i++) {
+		value = 0;
+		type = ppc4xx_reg[i].type;
+		switch (type) {
+		case IDCR1:	/* Indirect via SDRAM0_CFGADDR/DDR0_CFGDATA */
+			mtdcr(SDRAM0_CFGADDR, ppc4xx_reg[i].address);
+			value = mfdcr(SDRAM0_CFGDATA);
+			break;
+		case IDCR2:	/* Indirect via EBC0_CFGADDR/EBC0_CFGDATA */
+			mtdcr(EBC0_CFGADDR, ppc4xx_reg[i].address);
+			value = mfdcr(EBC0_CFGDATA);
+			break;
+		case IDCR5:	/* Indirect via CPR0_CFGADDR/CPR0_CFGDATA */
+			mtdcr(CPR0_CFGADDR, ppc4xx_reg[i].address);
+			value = mfdcr(CPR0_CFGDATA);
+			break;
+		case IDCR6:	/* Indirect via SDR0_CFGADDR/SDR0_CFGDATA */
+			mtdcr(SDR0_CFGADDR, ppc4xx_reg[i].address);
+			value = mfdcr(SDR0_CFGDATA);
+			break;
+		case MM:	/* Directly Accessed MMIO Register */
+			value = in_be32((const volatile unsigned __iomem *)
+				ppc4xx_reg[i].address);
+			break;
+		default:
+			printf("\nERROR: struct entry %d: unknown register"
+				"type\n", i);
+			break;
+		}
+		printf("0x%08x %-16s: 0x%08x\n",ppc4xx_reg[i].address,
+			ppc4xx_reg[i].name, value);
+	}
+}
diff --git a/arch/ppc/cpu/ppc4xx/resetvec.S b/arch/ppc/cpu/ppc4xx/resetvec.S
new file mode 100644
index 0000000..b3308bd
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/resetvec.S
@@ -0,0 +1,12 @@
+/* Copyright MontaVista Software Incorporated, 2000 */
+#include <config.h>
+	.section .resetvec,"ax"
+#if defined(CONFIG_440)
+	b _start_440
+#else
+#if defined(CONFIG_BOOT_PCI) && defined(CONFIG_MIP405)
+	b _start_pci
+#else
+	b _start
+#endif
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/sdram.c b/arch/ppc/cpu/ppc4xx/sdram.c
new file mode 100644
index 0000000..30c6e0e
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/sdram.c
@@ -0,0 +1,468 @@
+/*
+ * (C) Copyright 2005-2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2006
+ * DAVE Srl <www.dave-tech.it>
+ *
+ * (C) Copyright 2002-2004
+ * 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 "sdram.h"
+#include "ecc.h"
+
+#ifdef CONFIG_SDRAM_BANK0
+
+#ifndef CONFIG_440
+
+#ifndef CONFIG_SYS_SDRAM_TABLE
+sdram_conf_t mb0cf[] = {
+	{(128 << 20), 13, 0x000A4001},	    /* (0-128MB) Address Mode 3, 13x10(4) */
+	{(64 << 20),  13, 0x00084001},	    /* (0-64MB) Address Mode 3, 13x9(4)	  */
+	{(32 << 20),  12, 0x00062001},	    /* (0-32MB) Address Mode 2, 12x9(4)	  */
+	{(16 << 20),  12, 0x00046001},	    /* (0-16MB) Address Mode 4, 12x8(4)	  */
+	{(4 << 20),   11, 0x00008001},	    /* (0-4MB) Address Mode 5, 11x8(2)	  */
+};
+#else
+sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
+#endif
+
+#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
+
+#ifdef CONFIG_SYS_SDRAM_CASL
+static ulong ns2clks(ulong ns)
+{
+	ulong bus_period_x_10 = ONE_BILLION / (get_bus_freq(0) / 10);
+
+	return ((ns * 10) + bus_period_x_10) / bus_period_x_10;
+}
+#endif /* CONFIG_SYS_SDRAM_CASL */
+
+static ulong compute_sdtr1(ulong speed)
+{
+#ifdef CONFIG_SYS_SDRAM_CASL
+	ulong tmp;
+	ulong sdtr1 = 0;
+
+	/* CASL */
+	if (CONFIG_SYS_SDRAM_CASL < 2)
+		sdtr1 |= (1 << SDRAM0_TR_CASL);
+	else
+		if (CONFIG_SYS_SDRAM_CASL > 4)
+			sdtr1 |= (3 << SDRAM0_TR_CASL);
+		else
+			sdtr1 |= ((CONFIG_SYS_SDRAM_CASL-1) << SDRAM0_TR_CASL);
+
+	/* PTA */
+	tmp = ns2clks(CONFIG_SYS_SDRAM_PTA);
+	if ((tmp >= 2) && (tmp <= 4))
+		sdtr1 |= ((tmp-1) << SDRAM0_TR_PTA);
+	else
+		sdtr1 |= ((4-1) << SDRAM0_TR_PTA);
+
+	/* CTP */
+	tmp = ns2clks(CONFIG_SYS_SDRAM_CTP);
+	if ((tmp >= 2) && (tmp <= 4))
+		sdtr1 |= ((tmp-1) << SDRAM0_TR_CTP);
+	else
+		sdtr1 |= ((4-1) << SDRAM0_TR_CTP);
+
+	/* LDF */
+	tmp = ns2clks(CONFIG_SYS_SDRAM_LDF);
+	if ((tmp >= 2) && (tmp <= 4))
+		sdtr1 |= ((tmp-1) << SDRAM0_TR_LDF);
+	else
+		sdtr1 |= ((2-1) << SDRAM0_TR_LDF);
+
+	/* RFTA */
+	tmp = ns2clks(CONFIG_SYS_SDRAM_RFTA);
+	if ((tmp >= 4) && (tmp <= 10))
+		sdtr1 |= ((tmp-4) << SDRAM0_TR_RFTA);
+	else
+		sdtr1 |= ((10-4) << SDRAM0_TR_RFTA);
+
+	/* RCD */
+	tmp = ns2clks(CONFIG_SYS_SDRAM_RCD);
+	if ((tmp >= 2) && (tmp <= 4))
+		sdtr1 |= ((tmp-1) << SDRAM0_TR_RCD);
+	else
+		sdtr1 |= ((4-1) << SDRAM0_TR_RCD);
+
+	return sdtr1;
+#else /* CONFIG_SYS_SDRAM_CASL */
+	/*
+	 * If no values are configured in the board config file
+	 * use the default values, which seem to be ok for most
+	 * boards.
+	 *
+	 * REMARK:
+	 * For new board ports we strongly recommend to define the
+	 * correct values for the used SDRAM chips in your board
+	 * config file (see PPChameleonEVB.h)
+	 */
+	if (speed > 100000000) {
+		/*
+		 * 133 MHz SDRAM
+		 */
+		return 0x01074015;
+	} else {
+		/*
+		 * default: 100 MHz SDRAM
+		 */
+		return 0x0086400d;
+	}
+#endif /* CONFIG_SYS_SDRAM_CASL */
+}
+
+/* refresh is expressed in ms */
+static ulong compute_rtr(ulong speed, ulong rows, ulong refresh)
+{
+#ifdef CONFIG_SYS_SDRAM_CASL
+	ulong tmp;
+
+	tmp = ((refresh*1000*1000) / (1 << rows)) * (speed / 1000);
+	tmp /= 1000000;
+
+	return ((tmp & 0x00003FF8) << 16);
+#else /* CONFIG_SYS_SDRAM_CASL */
+	if (speed > 100000000) {
+		/*
+		 * 133 MHz SDRAM
+		 */
+		return 0x07f00000;
+	} else {
+		/*
+		 * default: 100 MHz SDRAM
+		 */
+		return 0x05f00000;
+	}
+#endif /* CONFIG_SYS_SDRAM_CASL */
+}
+
+/*
+ * Autodetect onboard SDRAM on 405 platforms
+ */
+phys_size_t initdram(int board_type)
+{
+	ulong speed;
+	ulong sdtr1;
+	int i;
+
+	/*
+	 * Determine SDRAM speed
+	 */
+	speed = get_bus_freq(0); /* parameter not used on ppc4xx */
+
+	/*
+	 * sdtr1 (register SDRAM0_TR) must take into account timings listed
+	 * in SDRAM chip datasheet. rtr (register SDRAM0_RTR) must take into
+	 * account actual SDRAM size. So we can set up sdtr1 according to what
+	 * is specified in board configuration file while rtr dependds on SDRAM
+	 * size we are assuming before detection.
+	 */
+	sdtr1 = compute_sdtr1(speed);
+
+	for (i=0; i<N_MB0CF; i++) {
+		/*
+		 * Disable memory controller.
+		 */
+		mtsdram(SDRAM0_CFG, 0x00000000);
+
+		/*
+		 * Set MB0CF for bank 0.
+		 */
+		mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
+		mtsdram(SDRAM0_TR, sdtr1);
+		mtsdram(SDRAM0_RTR, compute_rtr(speed, mb0cf[i].rows, 64));
+
+		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.
+		 */
+		mtsdram(SDRAM0_CFG, 0x80800000);
+
+		udelay(10000);
+
+		if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
+			phys_size_t size = mb0cf[i].size;
+
+			/*
+			 * OK, size detected.  Enable second bank if
+			 * defined (assumes same type as bank 0)
+			 */
+#ifdef CONFIG_SDRAM_BANK1
+			mtsdram(SDRAM0_CFG, 0x00000000);
+			mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
+			mtsdram(SDRAM0_CFG, 0x80800000);
+			udelay(10000);
+
+			/*
+			 * Check if 2nd bank is really available.
+			 * If the size not equal to the size of the first
+			 * bank, then disable the 2nd bank completely.
+			 */
+			if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) !=
+			    mb0cf[i].size) {
+				mtsdram(SDRAM0_B1CR, 0);
+				mtsdram(SDRAM0_CFG, 0);
+			} else {
+				/*
+				 * We have two identical banks, so the size
+				 * is twice the bank size
+				 */
+				size = 2 * size;
+			}
+#endif
+
+			/*
+			 * OK, size detected -> all done
+			 */
+			return size;
+		}
+	}
+
+	return 0;
+}
+
+#else /* CONFIG_440 */
+
+/*
+ * Define some default values. Those can be overwritten in the
+ * board config file.
+ */
+
+#ifndef CONFIG_SYS_SDRAM_TABLE
+sdram_conf_t mb0cf[] = {
+	{(256 << 20), 13, 0x000C4001},	/* 256MB mode 3, 13x10(4)	*/
+	{(128 << 20), 13, 0x000A4001},	/* 128MB mode 3, 13x10(4)	*/
+	{(64 << 20),  12, 0x00082001}	/* 64MB mode 2, 12x9(4)		*/
+};
+#else
+sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_TR0
+#define	CONFIG_SYS_SDRAM0_TR0		0x41094012
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_WDDCTR
+#define CONFIG_SYS_SDRAM0_WDDCTR	0x00000000  /* wrcp=0 dcd=0	*/
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_RTR
+#define CONFIG_SYS_SDRAM0_RTR 		0x04100000 /* 7.8us @ 133MHz PLB */
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_CFG0
+#define CONFIG_SYS_SDRAM0_CFG0		0x82000000 /* DCEN=1, PMUD=0, 64-bit */
+#endif
+
+#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
+
+#define NUM_TRIES 64
+#define NUM_READS 10
+
+static void sdram_tr1_set(int ram_address, int* tr1_value)
+{
+	int i;
+	int j, k;
+	volatile unsigned int* ram_pointer = (unsigned int *)ram_address;
+	int first_good = -1, last_bad = 0x1ff;
+
+	unsigned long test[NUM_TRIES] = {
+		0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+		0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+		0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+		0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+		0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+		0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+		0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+		0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+		0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55 };
+
+	/* go through all possible SDRAM0_TR1[RDCT] values */
+	for (i=0; i<=0x1ff; i++) {
+		/* set the current value for TR1 */
+		mtsdram(SDRAM0_TR1, (0x80800800 | i));
+
+		/* write values */
+		for (j=0; j<NUM_TRIES; j++) {
+			ram_pointer[j] = test[j];
+
+			/* clear any cache at ram location */
+			__asm__("dcbf 0,%0": :"r" (&ram_pointer[j]));
+		}
+
+		/* read values back */
+		for (j=0; j<NUM_TRIES; j++) {
+			for (k=0; k<NUM_READS; k++) {
+				/* clear any cache at ram location */
+				__asm__("dcbf 0,%0": :"r" (&ram_pointer[j]));
+
+				if (ram_pointer[j] != test[j])
+					break;
+			}
+
+			/* read error */
+			if (k != NUM_READS)
+				break;
+		}
+
+		/* we have a SDRAM0_TR1[RDCT] that is part of the window */
+		if (j == NUM_TRIES) {
+			if (first_good == -1)
+				first_good = i;		/* found beginning of window */
+		} else { /* bad read */
+			/* if we have not had a good read then don't care */
+			if (first_good != -1) {
+				/* first failure after a good read */
+				last_bad = i-1;
+				break;
+			}
+		}
+	}
+
+	/* return the current value for TR1 */
+	*tr1_value = (first_good + last_bad) / 2;
+}
+
+/*
+ * Autodetect onboard DDR SDRAM on 440 platforms
+ *
+ * NOTE: Some of the hardcoded values are hardware dependant,
+ *	 so this should be extended for other future boards
+ *	 using this routine!
+ */
+phys_size_t initdram(int board_type)
+{
+	int i;
+	int tr1_bank1;
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \
+    defined(CONFIG_440GR) || defined(CONFIG_440SP)
+	/*
+	 * Soft-reset SDRAM controller.
+	 */
+	mtsdr(SDR0_SRST, SDR0_SRST_DMC);
+	mtsdr(SDR0_SRST, 0x00000000);
+#endif
+
+	for (i=0; i<N_MB0CF; i++) {
+		/*
+		 * Disable memory controller.
+		 */
+		mtsdram(SDRAM0_CFG0, 0x00000000);
+
+		/*
+		 * Setup some default
+		 */
+		mtsdram(SDRAM0_UABBA, 0x00000000); /* ubba=0 (default)		*/
+		mtsdram(SDRAM0_SLIO, 0x00000000);	/* rdre=0 wrre=0 rarw=0		*/
+		mtsdram(SDRAM0_DEVOPT, 0x00000000); /* dll=0 ds=0 (normal)		*/
+		mtsdram(SDRAM0_WDDCTR, CONFIG_SYS_SDRAM0_WDDCTR);
+		mtsdram(SDRAM0_CLKTR, 0x40000000); /* clkp=1 (90 deg wr) dcdt=0	*/
+
+		/*
+		 * Following for CAS Latency = 2.5 @ 133 MHz PLB
+		 */
+		mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
+		mtsdram(SDRAM0_TR0, CONFIG_SYS_SDRAM0_TR0);
+		mtsdram(SDRAM0_TR1, 0x80800800);	/* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/
+		mtsdram(SDRAM0_RTR, CONFIG_SYS_SDRAM0_RTR);
+		mtsdram(SDRAM0_CFG1, 0x00000000);	/* Self-refresh exit, disable PM*/
+		udelay(400);			/* Delay 200 usecs (min)	*/
+
+		/*
+		 * Enable the controller, then wait for DCEN to complete
+		 */
+		mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
+		udelay(10000);
+
+		if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
+			phys_size_t size = mb0cf[i].size;
+			/*
+			 * Optimize TR1 to current hardware environment
+			 */
+			sdram_tr1_set(0x00000000, &tr1_bank1);
+			mtsdram(SDRAM0_TR1, (tr1_bank1 | 0x80800800));
+
+
+			/*
+			 * OK, size detected.  Enable second bank if
+			 * defined (assumes same type as bank 0)
+			 */
+#ifdef CONFIG_SDRAM_BANK1
+			mtsdram(SDRAM0_CFG0, 0);
+			mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
+			mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
+			udelay(10000);
+
+			/*
+			 * Check if 2nd bank is really available.
+			 * If the size not equal to the size of the first
+			 * bank, then disable the 2nd bank completely.
+			 */
+			if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size)
+			    != mb0cf[i].size) {
+				mtsdram(SDRAM0_CFG0, 0);
+				mtsdram(SDRAM0_B1CR, 0);
+				mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
+				udelay(10000);
+			} else {
+				/*
+				 * We have two identical banks, so the size
+				 * is twice the bank size
+				 */
+				size = 2 * size;
+			}
+#endif
+
+#ifdef CONFIG_SDRAM_ECC
+			ecc_init(0, size);
+#endif
+
+			/*
+			 * OK, size detected -> all done
+			 */
+			return size;
+		}
+	}
+
+	return 0;				/* nothing found !		*/
+}
+
+#endif /* CONFIG_440 */
+
+#endif /* CONFIG_SDRAM_BANK0 */
diff --git a/arch/ppc/cpu/ppc4xx/sdram.h b/arch/ppc/cpu/ppc4xx/sdram.h
new file mode 100644
index 0000000..bea3376
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/sdram.h
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2006
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2006
+ * DAVE Srl <www.dave-tech.it>
+ *
+ * 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
+ */
+
+#ifndef _SDRAM_H_
+#define _SDRAM_H_
+
+#include <config.h>
+
+#define ONE_BILLION	1000000000
+
+struct sdram_conf_s {
+	unsigned long size;
+	int rows;
+	unsigned long reg;
+};
+
+typedef struct sdram_conf_s sdram_conf_t;
+
+/* Bitfields offsets */
+#define SDRAM0_TR_CASL		(31 - 8)
+#define SDRAM0_TR_PTA		(31 - 13)
+#define SDRAM0_TR_CTP		(31 - 15)
+#define SDRAM0_TR_LDF		(31 - 17)
+#define SDRAM0_TR_RFTA		(31 - 29)
+#define SDRAM0_TR_RCD		(31 - 31)
+
+#ifdef CONFIG_SYS_SDRAM_CL
+/* SDRAM timings [ns] according to AMCC/IBM names (see SDRAM_faq.doc) */
+#define CONFIG_SYS_SDRAM_CASL		CONFIG_SYS_SDRAM_CL
+#define CONFIG_SYS_SDRAM_PTA		CONFIG_SYS_SDRAM_tRP
+#define CONFIG_SYS_SDRAM_CTP		(CONFIG_SYS_SDRAM_tRC - CONFIG_SYS_SDRAM_tRCD - CONFIG_SYS_SDRAM_tRP)
+#define CONFIG_SYS_SDRAM_LDF		0
+#ifdef CONFIG_SYS_SDRAM_tRFC
+#define CONFIG_SYS_SDRAM_RFTA		CONFIG_SYS_SDRAM_tRFC
+#else
+#define CONFIG_SYS_SDRAM_RFTA		CONFIG_SYS_SDRAM_tRC
+#endif
+#define CONFIG_SYS_SDRAM_RCD		CONFIG_SYS_SDRAM_tRCD
+#endif /* #ifdef CONFIG_SYS_SDRAM_CL */
+
+/*
+ * Some defines for the 440 DDR controller
+ */
+#define SDRAM_CFG0_DC_EN	0x80000000	/* SDRAM Controller Enable	*/
+#define SDRAM_CFG0_MEMCHK	0x30000000	/* Memory data error checking mask*/
+#define SDRAM_CFG0_MEMCHK_NON	0x00000000	/* No ECC generation		*/
+#define SDRAM_CFG0_MEMCHK_GEN	0x20000000	/* ECC generation		*/
+#define SDRAM_CFG0_MEMCHK_CHK	0x30000000	/* ECC generation and checking	*/
+#define SDRAM_CFG0_DRAMWDTH	0x02000000	/* DRAM width mask		*/
+#define SDRAM_CFG0_DRAMWDTH_32	0x00000000	/* 32 bits			*/
+#define SDRAM_CFG0_DRAMWDTH_64	0x02000000	/* 64 bits			*/
+
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/speed.c b/arch/ppc/cpu/ppc4xx/speed.c
new file mode 100644
index 0000000..906face
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/speed.c
@@ -0,0 +1,1177 @@
+/*
+ * (C) Copyright 2000-2008
+ * 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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ONE_BILLION        1000000000
+#ifdef DEBUG
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
+
+void get_sys_info (PPC4xx_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 (CPC0_PLLMR);
+
+	/*
+	 * Read Pin Strapping register
+	 */
+	psr = mfdcr (CPC0_PSR);
+
+	/*
+	 * 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_RB & 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->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+			(unsigned long long)sysClkPeriodPs;
+		sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
+		sysInfo->freqPLB = sysInfo->freqVCOHz / (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->freqVCOHz = ( 1000000000000LL *
+					       (unsigned long long)sysInfo->pllFwdDiv *
+					       (unsigned long long)sysInfo->pllFbkDiv *
+					       (unsigned long long)sysInfo->pllPlbDiv
+				) / (unsigned long long)sysClkPeriodPs;
+			sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
+							   sysInfo->pllFbkDiv)) * 10000;
+			sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
+		}
+	}
+
+	sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+	sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
+	sysInfo->freqUART = sysInfo->freqProcessor;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+	ulong val;
+	PPC4xx_SYS_INFO sys_info;
+
+	get_sys_info (&sys_info);
+	val = sys_info.freqPLB / sys_info.pllPciDiv;
+	return val;
+}
+
+
+#elif defined(CONFIG_440)
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+    defined(CONFIG_460SX)
+static u8 pll_fwdv_multi_bits[] = {
+	/* values for:  1 - 16 */
+	0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
+	0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
+};
+
+u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
+{
+	u32 index;
+
+	for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
+		if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
+			return index + 1;
+
+	return 0;
+}
+
+static u8 pll_fbdv_multi_bits[] = {
+	/* values for:  1 - 100 */
+	0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
+	0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
+	0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
+	0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
+	0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
+	0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
+	0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
+	0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
+	0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
+	0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
+	/* values for:  101 - 200 */
+	0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
+	0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
+	0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
+	0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
+	0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
+	0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
+	0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
+	0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
+	0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
+	0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
+	/* values for:  201 - 255 */
+	0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
+	0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
+	0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
+	0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
+	0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
+	0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
+};
+
+u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
+{
+	u32 index;
+
+	for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
+		if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
+			return index + 1;
+
+	return 0;
+}
+
+/*
+ * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
+ *            with latest EAS
+ */
+void get_sys_info (sys_info_t * sysInfo)
+{
+	unsigned long strp0;
+	unsigned long strp1;
+	unsigned long temp;
+	unsigned long m;
+	unsigned long plbedv0;
+
+	/* Extract configured divisors */
+	mfsdr(SDR0_SDSTP0, strp0);
+	mfsdr(SDR0_SDSTP1, strp1);
+
+	temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
+	sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
+
+	temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
+	sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
+
+	temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
+	sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
+
+	temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
+	sysInfo->pllOpbDiv = temp ? temp : 4;
+
+	/* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
+	temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
+	sysInfo->pllExtBusDiv = temp ? temp : 4;
+
+	temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
+	plbedv0 = temp ? temp: 8;
+
+	/* Calculate 'M' based on feedback source */
+	temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
+	if (temp == 0) {
+		/* PLL internal feedback */
+		m = sysInfo->pllFbkDiv;
+	} else {
+		/* PLL PerClk feedback */
+		m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
+			sysInfo->pllExtBusDiv;
+	}
+
+	/* 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->pllFwdDivA / plbedv0;
+	sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+	sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
+	sysInfo->freqDDR = sysInfo->freqPLB;
+	sysInfo->freqUART = sysInfo->freqPLB;
+
+	return;
+}
+
+#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+void get_sys_info (sys_info_t *sysInfo)
+{
+	unsigned long temp;
+	unsigned long reg;
+	unsigned long lfdiv;
+	unsigned long m;
+	unsigned long prbdv0;
+	/*
+	  WARNING: ASSUMES the following:
+	  ENG=1
+	  PRADV0=1
+	  PRBDV0=1
+	*/
+
+	/* Decode CPR0_PLLD0 for divisors */
+	mfcpr(CPR0_PLLD, reg);
+	temp = (reg & PLLD_FWDVA_MASK) >> 16;
+	sysInfo->pllFwdDivA = temp ? temp : 16;
+	temp = (reg & PLLD_FWDVB_MASK) >> 8;
+	sysInfo->pllFwdDivB = temp ? temp: 8 ;
+	temp = (reg & PLLD_FBDV_MASK) >> 24;
+	sysInfo->pllFbkDiv = temp ? temp : 32;
+	lfdiv = reg & PLLD_LFBDV_MASK;
+
+	mfcpr(CPR0_OPBD0, reg);
+	temp = (reg & OPBDDV_MASK) >> 24;
+	sysInfo->pllOpbDiv = temp ? temp : 4;
+
+	mfcpr(CPR0_PERD, reg);
+	temp = (reg & PERDV_MASK) >> 24;
+	sysInfo->pllExtBusDiv = temp ? temp : 8;
+
+	mfcpr(CPR0_PRIMBD0, reg);
+	temp = (reg & PRBDV_MASK) >> 24;
+	prbdv0 = temp ? temp : 8;
+
+	mfcpr(CPR0_SPCID, reg);
+	temp = (reg & SPCID_MASK) >> 24;
+	sysInfo->pllPciDiv = temp ? temp : 4;
+
+	/* Calculate 'M' based on feedback source */
+	mfsdr(SDR0_SDSTP0, reg);
+	temp = (reg & PLLSYS0_SEL_MASK) >> 27;
+	if (temp == 0) { /* PLL output */
+		/* Figure which pll to use */
+		mfcpr(CPR0_PLLC, reg);
+		temp = (reg & PLLC_SRC_MASK) >> 29;
+		if (!temp) /* PLLOUTA */
+			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
+		else       /* PLLOUTB */
+			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
+	}
+	else if (temp == 1) /* CPU output */
+		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+	else /* PerClk */
+		m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+
+	/* 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/prbdv0;
+	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+	sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
+	sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
+	sysInfo->freqUART = sysInfo->freqPLB;
+
+	/* Figure which timer source to use */
+	if (mfspr(SPRN_CCR1) & 0x0080) {
+		/* External Clock, assume same as SYS_CLK */
+		temp = sysInfo->freqProcessor / 2;  /* Max extern clock speed */
+		if (CONFIG_SYS_CLK_FREQ > temp)
+			sysInfo->freqTmrClk = temp;
+		else
+			sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
+	}
+	else  /* Internal clock */
+		sysInfo->freqTmrClk = sysInfo->freqProcessor;
+}
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+	sys_info_t sys_info;
+	get_sys_info (&sys_info);
+	return sys_info.freqPCI;
+}
+
+#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
+	&& !defined(CONFIG_XILINX_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->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+	sysInfo->freqUART = sysInfo->freqPLB;
+}
+#else
+
+#if !defined(CONFIG_XILINX_440)
+void get_sys_info (sys_info_t * sysInfo)
+{
+	unsigned long strp0;
+	unsigned long strp1;
+	unsigned long temp;
+	unsigned long temp1;
+	unsigned long lfdiv;
+	unsigned long m;
+	unsigned long prbdv0;
+
+#if defined(CONFIG_YUCCA)
+	unsigned long sys_freq;
+	unsigned long sys_per=0;
+	unsigned long msr;
+	unsigned long pci_clock_per;
+	unsigned long sdr_ddrpll;
+
+	/*-------------------------------------------------------------------------+
+	 | Get the system clock period.
+	 +-------------------------------------------------------------------------*/
+	sys_per = determine_sysper();
+
+	msr = (mfmsr () & ~(MSR_EE));	/* disable interrupts */
+
+	/*-------------------------------------------------------------------------+
+	 | Calculate the system clock speed from the period.
+	 +-------------------------------------------------------------------------*/
+	sys_freq = (ONE_BILLION / sys_per) * 1000;
+#endif
+
+	/* Extract configured divisors */
+	mfsdr( SDR0_SDSTP0,strp0 );
+	mfsdr( SDR0_SDSTP1,strp1 );
+
+	temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
+	sysInfo->pllFwdDivA = temp ? temp : 16 ;
+	temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
+	sysInfo->pllFwdDivB = temp ? temp: 8 ;
+	temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
+	sysInfo->pllFbkDiv = temp ? temp : 32;
+	temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
+	sysInfo->pllOpbDiv = temp ? temp : 4;
+	temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
+	sysInfo->pllExtBusDiv = temp ? temp : 4;
+	prbdv0 = (strp0 >> 2) & 0x7;
+
+	/* Calculate 'M' based on feedback source */
+	temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
+	temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
+	lfdiv = temp1 ? temp1 : 64;
+	if (temp == 0) { /* PLL output */
+		/* Figure which pll to use */
+		temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
+		if (!temp)
+			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
+		else
+			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
+	}
+	else if (temp == 1) /* CPU output */
+		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+	else /* PerClk */
+		m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+
+	/* Now calculate the individual clocks */
+#if defined(CONFIG_YUCCA)
+	sysInfo->freqVCOMhz = (m * sys_freq) ;
+#else
+	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
+#endif
+	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
+	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+	sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+
+#if defined(CONFIG_YUCCA)
+	/* Determine PCI Clock Period */
+	pci_clock_per = determine_pci_clock_per();
+	sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
+	mfsdr(SDR0_DDR0, sdr_ddrpll);
+	sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+#endif
+
+	sysInfo->freqUART = sysInfo->freqPLB;
+}
+
+#endif
+#endif /* CONFIG_XILINX_440 */
+
+#if defined(CONFIG_YUCCA)
+unsigned long determine_sysper(void)
+{
+	unsigned int fpga_clocking_reg;
+	unsigned int master_clock_selection;
+	unsigned long master_clock_per = 0;
+	unsigned long fb_div_selection;
+	unsigned int vco_div_reg_value;
+	unsigned long vco_div_selection;
+	unsigned long sys_per = 0;
+	int extClkVal;
+
+	/*-------------------------------------------------------------------------+
+	 | Read FPGA reg 0 and reg 1 to get FPGA reg information
+	 +-------------------------------------------------------------------------*/
+	fpga_clocking_reg = in16(FPGA_REG16);
+
+
+	/* Determine Master Clock Source Selection */
+	master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
+
+	switch(master_clock_selection) {
+		case FPGA_REG16_MASTER_CLK_66_66:
+			master_clock_per = PERIOD_66_66MHZ;
+			break;
+		case FPGA_REG16_MASTER_CLK_50:
+			master_clock_per = PERIOD_50_00MHZ;
+			break;
+		case FPGA_REG16_MASTER_CLK_33_33:
+			master_clock_per = PERIOD_33_33MHZ;
+			break;
+		case FPGA_REG16_MASTER_CLK_25:
+			master_clock_per = PERIOD_25_00MHZ;
+			break;
+		case FPGA_REG16_MASTER_CLK_EXT:
+			if ((extClkVal==EXTCLK_33_33)
+					&& (extClkVal==EXTCLK_50)
+					&& (extClkVal==EXTCLK_66_66)
+					&& (extClkVal==EXTCLK_83)) {
+				/* calculate master clock period from external clock value */
+				master_clock_per=(ONE_BILLION/extClkVal) * 1000;
+			} else {
+				/* Unsupported */
+				DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
+				hang();
+			}
+			break;
+		default:
+			/* Unsupported */
+			DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
+			hang();
+			break;
+	}
+
+	/* Determine FB divisors values */
+	if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
+		if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
+			fb_div_selection = FPGA_FB_DIV_6;
+		else
+			fb_div_selection = FPGA_FB_DIV_12;
+	} else {
+		if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
+			fb_div_selection = FPGA_FB_DIV_10;
+		else
+			fb_div_selection = FPGA_FB_DIV_20;
+	}
+
+	/* Determine VCO divisors values */
+	vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
+
+	switch(vco_div_reg_value) {
+		case FPGA_REG16_VCO_DIV_4:
+			vco_div_selection = FPGA_VCO_DIV_4;
+			break;
+		case FPGA_REG16_VCO_DIV_6:
+			vco_div_selection = FPGA_VCO_DIV_6;
+			break;
+		case FPGA_REG16_VCO_DIV_8:
+			vco_div_selection = FPGA_VCO_DIV_8;
+			break;
+		case FPGA_REG16_VCO_DIV_10:
+		default:
+			vco_div_selection = FPGA_VCO_DIV_10;
+			break;
+	}
+
+	if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
+		switch(master_clock_per) {
+			case PERIOD_25_00MHZ:
+				if (fb_div_selection == FPGA_FB_DIV_12) {
+					if (vco_div_selection == FPGA_VCO_DIV_4)
+						sys_per = PERIOD_75_00MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_50_00MHZ;
+				}
+				break;
+			case PERIOD_33_33MHZ:
+				if (fb_div_selection == FPGA_FB_DIV_6) {
+					if (vco_div_selection == FPGA_VCO_DIV_4)
+						sys_per = PERIOD_50_00MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_33_33MHZ;
+				}
+				if (fb_div_selection == FPGA_FB_DIV_10) {
+					if (vco_div_selection == FPGA_VCO_DIV_4)
+						sys_per = PERIOD_83_33MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_10)
+						sys_per = PERIOD_33_33MHZ;
+				}
+				if (fb_div_selection == FPGA_FB_DIV_12) {
+					if (vco_div_selection == FPGA_VCO_DIV_4)
+						sys_per = PERIOD_100_00MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_66_66MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_8)
+						sys_per = PERIOD_50_00MHZ;
+				}
+				break;
+			case PERIOD_50_00MHZ:
+				if (fb_div_selection == FPGA_FB_DIV_6) {
+					if (vco_div_selection == FPGA_VCO_DIV_4)
+						sys_per = PERIOD_75_00MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_50_00MHZ;
+				}
+				if (fb_div_selection == FPGA_FB_DIV_10) {
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_83_33MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_10)
+						sys_per = PERIOD_50_00MHZ;
+				}
+				if (fb_div_selection == FPGA_FB_DIV_12) {
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_100_00MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_8)
+						sys_per = PERIOD_75_00MHZ;
+				}
+				break;
+			case PERIOD_66_66MHZ:
+				if (fb_div_selection == FPGA_FB_DIV_6) {
+					if (vco_div_selection == FPGA_VCO_DIV_4)
+						sys_per = PERIOD_100_00MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_6)
+						sys_per = PERIOD_66_66MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_8)
+						sys_per = PERIOD_50_00MHZ;
+				}
+				if (fb_div_selection == FPGA_FB_DIV_10) {
+					if (vco_div_selection == FPGA_VCO_DIV_8)
+						sys_per = PERIOD_83_33MHZ;
+					if (vco_div_selection == FPGA_VCO_DIV_10)
+						sys_per = PERIOD_66_66MHZ;
+				}
+				if (fb_div_selection == FPGA_FB_DIV_12) {
+					if (vco_div_selection == FPGA_VCO_DIV_8)
+						sys_per = PERIOD_100_00MHZ;
+				}
+				break;
+			default:
+				break;
+		}
+
+		if (sys_per == 0) {
+			/* Other combinations are not supported */
+			DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
+			hang();
+		}
+	} else {
+		/* calcul system clock without cheking */
+		/* if engineering option clock no check is selected */
+		/* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
+		sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
+	}
+
+	return(sys_per);
+}
+
+/*-------------------------------------------------------------------------+
+| determine_pci_clock_per.
++-------------------------------------------------------------------------*/
+unsigned long determine_pci_clock_per(void)
+{
+	unsigned long pci_clock_selection,  pci_period;
+
+	/*-------------------------------------------------------------------------+
+	 | Read FPGA reg 6 to get PCI 0 FPGA reg information
+	 +-------------------------------------------------------------------------*/
+	pci_clock_selection = in16(FPGA_REG16);	/* was reg6 averifier */
+
+
+	pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
+
+	switch (pci_clock_selection) {
+		case FPGA_REG16_PCI0_CLK_133_33:
+			pci_period = PERIOD_133_33MHZ;
+			break;
+		case FPGA_REG16_PCI0_CLK_100:
+			pci_period = PERIOD_100_00MHZ;
+			break;
+		case FPGA_REG16_PCI0_CLK_66_66:
+			pci_period = PERIOD_66_66MHZ;
+			break;
+		default:
+			pci_period = PERIOD_33_33MHZ;;
+			break;
+	}
+
+	return(pci_period);
+}
+#endif
+
+#elif defined(CONFIG_XILINX_405)
+extern void get_sys_info (sys_info_t * sysInfo);
+extern ulong get_PCI_freq (void);
+
+#elif defined(CONFIG_AP1000)
+void get_sys_info (sys_info_t * sysInfo)
+{
+	sysInfo->freqProcessor = 240 * 1000 * 1000;
+	sysInfo->freqPLB = 80 * 1000 * 1000;
+	sysInfo->freqPCI = 33 * 1000 * 1000;
+}
+
+#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;
+}
+
+#elif defined(CONFIG_405EP)
+void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
+{
+	unsigned long pllmr0;
+	unsigned long pllmr1;
+	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+	unsigned long m;
+	unsigned long pllmr0_ccdv;
+
+	/*
+	 * Read PLL Mode registers
+	 */
+	pllmr0 = mfdcr (CPC0_PLLMR0);
+	pllmr1 = mfdcr (CPC0_PLLMR1);
+
+	/*
+	 * Determine forward divider A
+	 */
+	sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
+
+	/*
+	 * Determine forward divider B (should be equal to A)
+	 */
+	sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
+
+	/*
+	 * Determine FBK_DIV.
+	 */
+	sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
+	if (sysInfo->pllFbkDiv == 0)
+		sysInfo->pllFbkDiv = 16;
+
+	/*
+	 * Determine PLB_DIV.
+	 */
+	sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
+
+	/*
+	 * Determine PCI_DIV.
+	 */
+	sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
+
+	/*
+	 * Determine EXTBUS_DIV.
+	 */
+	sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
+
+	/*
+	 * Determine OPB_DIV.
+	 */
+	sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
+
+	/*
+	 * Determine the M factor
+	 */
+	m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
+
+	/*
+	 * Determine VCO clock frequency
+	 */
+	sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+		(unsigned long long)sysClkPeriodPs;
+
+	/*
+	 * Determine CPU clock frequency
+	 */
+	pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
+	if (pllmr1 & PLLMR1_SSCS_MASK) {
+		/*
+		 * This is true if FWDVA == FWDVB:
+		 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
+		 *	/ pllmr0_ccdv;
+		 */
+		sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
+			/ sysInfo->pllFwdDiv / pllmr0_ccdv;
+	} else {
+		sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
+	}
+
+	/*
+	 * Determine PLB clock frequency
+	 */
+	sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
+
+	sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
+
+	sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+
+	sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+	ulong val;
+	PPC4xx_SYS_INFO sys_info;
+
+	get_sys_info (&sys_info);
+	val = sys_info.freqPLB / sys_info.pllPciDiv;
+	return val;
+}
+
+#elif defined(CONFIG_405EZ)
+void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
+{
+	unsigned long cpr_plld;
+	unsigned long cpr_pllc;
+	unsigned long cpr_primad;
+	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
+	unsigned long primad_cpudv;
+	unsigned long m;
+	unsigned long plloutb;
+
+	/*
+	 * Read PLL Mode registers
+	 */
+	mfcpr(CPR0_PLLD, cpr_plld);
+	mfcpr(CPR0_PLLC, cpr_pllc);
+
+	/*
+	 * Determine forward divider A
+	 */
+	sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
+
+	/*
+	 * Determine forward divider B
+	 */
+	sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
+	if (sysInfo->pllFwdDivB == 0)
+		sysInfo->pllFwdDivB = 8;
+
+	/*
+	 * Determine FBK_DIV.
+	 */
+	sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
+	if (sysInfo->pllFbkDiv == 0)
+		sysInfo->pllFbkDiv = 256;
+
+	/*
+	 * Read CPR_PRIMAD register
+	 */
+	mfcpr(CPC0_PRIMAD, cpr_primad);
+
+	/*
+	 * Determine PLB_DIV.
+	 */
+	sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
+	if (sysInfo->pllPlbDiv == 0)
+		sysInfo->pllPlbDiv = 16;
+
+	/*
+	 * Determine EXTBUS_DIV.
+	 */
+	sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
+	if (sysInfo->pllExtBusDiv == 0)
+		sysInfo->pllExtBusDiv = 16;
+
+	/*
+	 * Determine OPB_DIV.
+	 */
+	sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
+	if (sysInfo->pllOpbDiv == 0)
+		sysInfo->pllOpbDiv = 16;
+
+	/*
+	 * Determine the M factor
+	 */
+	if (cpr_pllc & PLLC_SRC_MASK)
+		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
+	else
+		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
+
+	/*
+	 * Determine VCO clock frequency
+	 */
+	sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+		(unsigned long long)sysClkPeriodPs;
+
+	/*
+	 * Determine CPU clock frequency
+	 */
+	primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
+	if (primad_cpudv == 0)
+		primad_cpudv = 16;
+
+	sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
+		sysInfo->pllFwdDiv / primad_cpudv;
+
+	/*
+	 * Determine PLB clock frequency
+	 */
+	sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
+		sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
+
+	sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
+		sysInfo->pllOpbDiv;
+
+	sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
+		sysInfo->pllExtBusDiv;
+
+	plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
+		sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
+		sysInfo->pllFwdDivB);
+	sysInfo->freqUART = plloutb;
+}
+
+#elif defined(CONFIG_405EX)
+
+/*
+ * TODO: We need to get the CPR registers and calculate these values correctly!!!!
+ *   We need the specs!!!!
+ */
+static unsigned char get_fbdv(unsigned char index)
+{
+	unsigned char ret = 0;
+	/* This is table should be 256 bytes.
+	 * Only take first 52 values.
+	 */
+	unsigned char fbdv_tb[] = {
+		0x00, 0xff, 0x7f, 0xfd,
+		0x7a, 0xf5, 0x6a, 0xd5,
+		0x2a, 0xd4, 0x29, 0xd3,
+		0x26, 0xcc, 0x19, 0xb3,
+		0x67, 0xce, 0x1d, 0xbb,
+		0x77, 0xee, 0x5d, 0xba,
+		0x74, 0xe9, 0x52, 0xa5,
+		0x4b, 0x96, 0x2c, 0xd8,
+		0x31, 0xe3, 0x46, 0x8d,
+		0x1b, 0xb7, 0x6f, 0xde,
+		0x3d, 0xfb, 0x76, 0xed,
+		0x5a, 0xb5, 0x6b, 0xd6,
+		0x2d, 0xdb, 0x36, 0xec,
+
+	};
+
+	if ((index & 0x7f) == 0)
+		return 1;
+	while (ret < sizeof (fbdv_tb)) {
+		if (fbdv_tb[ret] == index)
+			break;
+		ret++;
+	}
+	ret++;
+
+	return ret;
+}
+
+#define PLL_FBK_PLL_LOCAL	0
+#define PLL_FBK_CPU		1
+#define PLL_FBK_PERCLK		5
+
+void get_sys_info (sys_info_t * sysInfo)
+{
+	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+	unsigned long m = 1;
+	unsigned int  tmp;
+	unsigned char fwdva[16] = {
+		1, 2, 14, 9, 4, 11, 16, 13,
+		12, 5, 6, 15, 10, 7, 8, 3,
+	};
+	unsigned char sel, cpudv0, plb2xDiv;
+
+	mfcpr(CPR0_PLLD, tmp);
+
+	/*
+	 * Determine forward divider A
+	 */
+	sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)];	/* FWDVA */
+
+	/*
+	 * Determine FBK_DIV.
+	 */
+	sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
+
+	/*
+	 * Determine PLBDV0
+	 */
+	sysInfo->pllPlbDiv = 2;
+
+	/*
+	 * Determine PERDV0
+	 */
+	mfcpr(CPR0_PERD, tmp);
+	tmp = (tmp >> 24) & 0x03;
+	sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
+
+	/*
+	 * Determine OPBDV0
+	 */
+	mfcpr(CPR0_OPBD0, tmp);
+	tmp = (tmp >> 24) & 0x03;
+	sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
+
+	/* Determine PLB2XDV0 */
+	mfcpr(CPR0_PLBD, tmp);
+	tmp = (tmp >> 16) & 0x07;
+	plb2xDiv = (tmp == 0) ? 8 : tmp;
+
+	/* Determine CPUDV0 */
+	mfcpr(CPR0_CPUD, tmp);
+	tmp = (tmp >> 24) & 0x07;
+	cpudv0 = (tmp == 0) ? 8 : tmp;
+
+	/* Determine SEL(5:7) in CPR0_PLLC */
+	mfcpr(CPR0_PLLC, tmp);
+	sel = (tmp >> 24) & 0x07;
+
+	/*
+	 * Determine the M factor
+	 * PLL local: M = FBDV
+	 * CPU clock: M = FBDV * FWDVA * CPUDV0
+	 * PerClk	: M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
+	 *
+	 */
+	switch (sel) {
+	case PLL_FBK_CPU:
+		m = sysInfo->pllFwdDiv * cpudv0;
+		break;
+	case PLL_FBK_PERCLK:
+		m = sysInfo->pllFwdDiv * plb2xDiv * 2
+			* sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
+		break;
+	case PLL_FBK_PLL_LOCAL:
+		break;
+	default:
+		printf("%s unknown m\n", __FUNCTION__);
+		return;
+
+	}
+	m *= sysInfo->pllFbkDiv;
+
+	/*
+	 * Determine VCO clock frequency
+	 */
+	sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+		(unsigned long long)sysClkPeriodPs;
+
+	/*
+	 * Determine CPU clock frequency
+	 */
+	sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
+
+	/*
+	 * Determine PLB clock frequency, ddr1x should be the same
+	 */
+	sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
+	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+	sysInfo->freqDDR = sysInfo->freqPLB;
+	sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
+	sysInfo->freqUART = sysInfo->freqPLB;
+}
+
+#endif
+
+int get_clocks (void)
+{
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+    defined(CONFIG_405EX) || defined(CONFIG_405) || \
+    defined(CONFIG_440)
+	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
+	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_405EP) || defined(CONFIG_405EZ) || \
+    defined(CONFIG_405EX) || 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;
+}
+
+#if !defined(CONFIG_IOP480)
+ulong get_OPB_freq (void)
+{
+	PPC4xx_SYS_INFO sys_info;
+
+	get_sys_info (&sys_info);
+
+	return sys_info.freqOPB;
+}
+#endif
diff --git a/arch/ppc/cpu/ppc4xx/start.S b/arch/ppc/cpu/ppc4xx/start.S
new file mode 100644
index 0000000..927c88c
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/start.S
@@ -0,0 +1,2170 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ *  Copyright (C) 2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *  Copyright (c) 2008 Nuovation System Designs, LLC
+ *    Grant Erickson <gerickson@nuovations.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
+ */
+/*------------------------------------------------------------------------------+
+ *   This source code is dual-licensed.  You may use it under the terms of the
+ *   GNU General Public License version 2, or under the license below.
+ *
+ *	 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
+ *-------------------------------------------------------------------------------
+ */
+
+/*  U-Boot - Startup Code for AMCC 4xx PowerPC based Embedded Boards
+ *
+ *
+ *  The processor starts at 0xfffffffc and the code is executed
+ *  from flash/rom.
+ *  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 <ppc4xx.h>
+#include <timestamp.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>
+#include <asm/ppc4xx-isram.h>
+
+#ifndef	 CONFIG_IDENT_STRING
+#define	 CONFIG_IDENT_STRING ""
+#endif
+
+#ifdef CONFIG_SYS_INIT_DCACHE_CS
+# if (CONFIG_SYS_INIT_DCACHE_CS == 0)
+#  define PBxAP PB1AP
+#  define PBxCR PB0CR
+#  if (defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB0AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB0CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 1)
+#  define PBxAP PB1AP
+#  define PBxCR PB1CR
+#  if (defined(CONFIG_SYS_EBC_PB1AP) && defined(CONFIG_SYS_EBC_PB1CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB1AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB1CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 2)
+#  define PBxAP PB2AP
+#  define PBxCR PB2CR
+#  if (defined(CONFIG_SYS_EBC_PB2AP) && defined(CONFIG_SYS_EBC_PB2CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB2AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB2CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 3)
+#  define PBxAP PB3AP
+#  define PBxCR PB3CR
+#  if (defined(CONFIG_SYS_EBC_PB3AP) && defined(CONFIG_SYS_EBC_PB3CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB3AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB3CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 4)
+#  define PBxAP PB4AP
+#  define PBxCR PB4CR
+#  if (defined(CONFIG_SYS_EBC_PB4AP) && defined(CONFIG_SYS_EBC_PB4CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB4AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB4CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 5)
+#  define PBxAP PB5AP
+#  define PBxCR PB5CR
+#  if (defined(CONFIG_SYS_EBC_PB5AP) && defined(CONFIG_SYS_EBC_PB5CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB5AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB5CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 6)
+#  define PBxAP PB6AP
+#  define PBxCR PB6CR
+#  if (defined(CONFIG_SYS_EBC_PB6AP) && defined(CONFIG_SYS_EBC_PB6CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB6AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB6CR
+#  endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 7)
+#  define PBxAP PB7AP
+#  define PBxCR PB7CR
+#  if (defined(CONFIG_SYS_EBC_PB7AP) && defined(CONFIG_SYS_EBC_PB7CR))
+#   define PBxAP_VAL CONFIG_SYS_EBC_PB7AP
+#   define PBxCR_VAL CONFIG_SYS_EBC_PB7CR
+#  endif
+# endif
+# ifndef PBxAP_VAL
+#  define PBxAP_VAL	0
+# endif
+# ifndef PBxCR_VAL
+#  define PBxCR_VAL	0
+# endif
+/*
+ * Memory Bank x (nothingness) initialization CONFIG_SYS_INIT_RAM_ADDR + 64 MiB
+ * used as temporary stack pointer for the primordial stack
+ */
+# ifndef CONFIG_SYS_INIT_DCACHE_PBxAR
+#  define CONFIG_SYS_INIT_DCACHE_PBxAR	(EBC_BXAP_BME_DISABLED			| \
+				 EBC_BXAP_TWT_ENCODE(7)			| \
+				 EBC_BXAP_BCE_DISABLE			| \
+				 EBC_BXAP_BCT_2TRANS			| \
+				 EBC_BXAP_CSN_ENCODE(0)			| \
+				 EBC_BXAP_OEN_ENCODE(0)			| \
+				 EBC_BXAP_WBN_ENCODE(0)			| \
+				 EBC_BXAP_WBF_ENCODE(0)			| \
+				 EBC_BXAP_TH_ENCODE(2)			| \
+				 EBC_BXAP_RE_DISABLED			| \
+				 EBC_BXAP_SOR_NONDELAYED		| \
+				 EBC_BXAP_BEM_WRITEONLY			| \
+				 EBC_BXAP_PEN_DISABLED)
+# endif /* CONFIG_SYS_INIT_DCACHE_PBxAR */
+# ifndef CONFIG_SYS_INIT_DCACHE_PBxCR
+#  define CONFIG_SYS_INIT_DCACHE_PBxCR	(EBC_BXCR_BAS_ENCODE(CONFIG_SYS_INIT_RAM_ADDR)	| \
+				 EBC_BXCR_BS_64MB			| \
+				 EBC_BXCR_BU_RW				| \
+				 EBC_BXCR_BW_16BIT)
+# endif /* CONFIG_SYS_INIT_DCACHE_PBxCR */
+# ifndef CONFIG_SYS_INIT_RAM_PATTERN
+#  define CONFIG_SYS_INIT_RAM_PATTERN	0xDEADDEAD
+# endif
+#endif /* CONFIG_SYS_INIT_DCACHE_CS */
+
+#if (defined(CONFIG_SYS_INIT_RAM_DCACHE) && (CONFIG_SYS_INIT_RAM_END > (4 << 10)))
+#error Only 4k of init-ram is supported - please adjust CONFIG_SYS_INIT_RAM_END!
+#endif
+
+/*
+ * Unless otherwise overriden, enable two 128MB cachable instruction regions
+ * at CONFIG_SYS_SDRAM_BASE and another 128MB cacheable instruction region covering
+ * NOR flash at CONFIG_SYS_FLASH_BASE. Disable all cacheable data regions.
+ */
+#if !defined(CONFIG_SYS_FLASH_BASE)
+/* If not already defined, set it to the "last" 128MByte region */
+# define CONFIG_SYS_FLASH_BASE		0xf8000000
+#endif
+#if !defined(CONFIG_SYS_ICACHE_SACR_VALUE)
+# define CONFIG_SYS_ICACHE_SACR_VALUE		\
+		(PPC_128MB_SACR_VALUE(CONFIG_SYS_SDRAM_BASE + (  0 << 20)) | \
+		 PPC_128MB_SACR_VALUE(CONFIG_SYS_SDRAM_BASE + (128 << 20)) | \
+		 PPC_128MB_SACR_VALUE(CONFIG_SYS_FLASH_BASE))
+#endif /* !defined(CONFIG_SYS_ICACHE_SACR_VALUE) */
+
+#if !defined(CONFIG_SYS_DCACHE_SACR_VALUE)
+# define CONFIG_SYS_DCACHE_SACR_VALUE		\
+		(0x00000000)
+#endif /* !defined(CONFIG_SYS_DCACHE_SACR_VALUE) */
+
+#define function_prolog(func_name)	.text; \
+					.align 2; \
+					.globl func_name; \
+					func_name:
+#define function_epilog(func_name)	.type func_name,@function; \
+					.size func_name,.-func_name
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME  )	/* Machine Check */
+
+
+	.extern ext_bus_cntlr_init
+#ifdef CONFIG_NAND_U_BOOT
+	.extern reconfig_tlb0
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+#if !defined(CONFIG_NAND_SPL)
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+#endif /* CONFIG_NAND_SPL */
+
+#if defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+	/*
+	 * NAND U-Boot image is started from offset 0
+	 */
+	.text
+#if defined(CONFIG_440)
+	bl	reconfig_tlb0
+#endif
+	GET_GOT
+	bl	cpu_init_f	/* run low-level CPU init code	   (from Flash) */
+	bl	board_init_f
+#endif
+
+#if defined(CONFIG_SYS_RAMBOOT)
+	/*
+	 * 4xx RAM-booting U-Boot image is started from offset 0
+	 */
+	.text
+	bl	_start_440
+#endif
+
+/*
+ * 440 Startup -- on reset only the top 4k of the effective
+ * address space is mapped in by an entry in the instruction
+ * and data shadow TLB. The .bootpg section is located in the
+ * top 4k & does only what's necessary to map in the the rest
+ * of the boot rom. Once the boot rom is mapped in we can
+ * proceed with normal startup.
+ *
+ * NOTE: CS0 only covers the top 2MB of the effective address
+ * space after reset.
+ */
+
+#if defined(CONFIG_440)
+#if !defined(CONFIG_NAND_SPL)
+    .section .bootpg,"ax"
+#endif
+    .globl _start_440
+
+/**************************************************************************/
+_start_440:
+	/*--------------------------------------------------------------------+
+	| 440EPX BUP Change - Hardware team request
+	+--------------------------------------------------------------------*/
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+	sync
+	nop
+	nop
+#endif
+	/*----------------------------------------------------------------+
+	| Core bug fix.  Clear the esr
+	+-----------------------------------------------------------------*/
+	li	r0,0
+	mtspr	SPRN_ESR,r0
+	/*----------------------------------------------------------------*/
+	/* Clear and set up some registers. */
+	/*----------------------------------------------------------------*/
+	iccci	r0,r0		/* NOTE: operands not used for 440 */
+	dccci	r0,r0		/* NOTE: operands not used for 440 */
+	sync
+	li	r0,0
+	mtspr	SPRN_SRR0,r0
+	mtspr	SPRN_SRR1,r0
+	mtspr	SPRN_CSRR0,r0
+	mtspr	SPRN_CSRR1,r0
+	/* NOTE: 440GX adds machine check status regs */
+#if defined(CONFIG_440) && !defined(CONFIG_440GP)
+	mtspr	SPRN_MCSRR0,r0
+	mtspr	SPRN_MCSRR1,r0
+	mfspr	r1,SPRN_MCSR
+	mtspr	SPRN_MCSR,r1
+#endif
+
+	/*----------------------------------------------------------------*/
+	/* CCR0 init */
+	/*----------------------------------------------------------------*/
+	/* Disable store gathering & broadcast, guarantee inst/data
+	* cache block touch, force load/store alignment
+	* (see errata 1.12: 440_33)
+	*/
+	lis	r1,0x0030	/* store gathering & broadcast disable */
+	ori	r1,r1,0x6000	/* cache touch */
+	mtspr	SPRN_CCR0,r1
+
+	/*----------------------------------------------------------------*/
+	/* Initialize debug */
+	/*----------------------------------------------------------------*/
+	mfspr	r1,SPRN_DBCR0
+	andis.	r1, r1, 0x8000	/* test DBCR0[EDM] bit			*/
+	bne	skip_debug_init	/* if set, don't clear debug register	*/
+	mtspr	SPRN_DBCR0,r0
+	mtspr	SPRN_DBCR1,r0
+	mtspr	SPRN_DBCR2,r0
+	mtspr	SPRN_IAC1,r0
+	mtspr	SPRN_IAC2,r0
+	mtspr	SPRN_IAC3,r0
+	mtspr	SPRN_DAC1,r0
+	mtspr	SPRN_DAC2,r0
+	mtspr	SPRN_DVC1,r0
+	mtspr	SPRN_DVC2,r0
+
+	mfspr	r1,SPRN_DBSR
+	mtspr	SPRN_DBSR,r1	/* Clear all valid bits */
+skip_debug_init:
+
+#if defined (CONFIG_440SPE)
+	/*----------------------------------------------------------------+
+	| Initialize Core Configuration Reg1.
+	| a. ICDPEI: Record even parity. Normal operation.
+	| b. ICTPEI: Record even parity. Normal operation.
+	| c. DCTPEI: Record even parity. Normal operation.
+	| d. DCDPEI: Record even parity. Normal operation.
+	| e. DCUPEI: Record even parity. Normal operation.
+	| f. DCMPEI: Record even parity. Normal operation.
+	| g. FCOM:   Normal operation
+	| h. MMUPEI: Record even parity. Normal operation.
+	| i. FFF:    Flush only as much data as necessary.
+	| j. TCS:    Timebase increments from CPU clock.
+	+-----------------------------------------------------------------*/
+	li	r0,0
+	mtspr	SPRN_CCR1, r0
+
+	/*----------------------------------------------------------------+
+	| Reset the timebase.
+	| The previous write to CCR1 sets the timebase source.
+	+-----------------------------------------------------------------*/
+	mtspr	SPRN_TBWL, r0
+	mtspr	SPRN_TBWU, r0
+#endif
+
+	/*----------------------------------------------------------------*/
+	/* Setup interrupt vectors */
+	/*----------------------------------------------------------------*/
+	mtspr	SPRN_IVPR,r0		/* Vectors start at 0x0000_0000 */
+	li	r1,0x0100
+	mtspr	SPRN_IVOR0,r1	/* Critical input */
+	li	r1,0x0200
+	mtspr	SPRN_IVOR1,r1	/* Machine check */
+	li	r1,0x0300
+	mtspr	SPRN_IVOR2,r1	/* Data storage */
+	li	r1,0x0400
+	mtspr	SPRN_IVOR3,r1	/* Instruction storage */
+	li	r1,0x0500
+	mtspr	SPRN_IVOR4,r1	/* External interrupt */
+	li	r1,0x0600
+	mtspr	SPRN_IVOR5,r1	/* Alignment */
+	li	r1,0x0700
+	mtspr	SPRN_IVOR6,r1	/* Program check */
+	li	r1,0x0800
+	mtspr	SPRN_IVOR7,r1	/* Floating point unavailable */
+	li	r1,0x0c00
+	mtspr	SPRN_IVOR8,r1	/* System call */
+	li	r1,0x0a00
+	mtspr	SPRN_IVOR9,r1	/* Auxiliary Processor unavailable */
+	li	r1,0x0900
+	mtspr	SPRN_IVOR10,r1	/* Decrementer */
+	li	r1,0x1300
+	mtspr	SPRN_IVOR13,r1	/* Data TLB error */
+	li	r1,0x1400
+	mtspr	SPRN_IVOR14,r1	/* Instr TLB error */
+	li	r1,0x2000
+	mtspr	SPRN_IVOR15,r1	/* Debug */
+
+	/*----------------------------------------------------------------*/
+	/* Configure cache regions  */
+	/*----------------------------------------------------------------*/
+	mtspr	SPRN_INV0,r0
+	mtspr	SPRN_INV1,r0
+	mtspr	SPRN_INV2,r0
+	mtspr	SPRN_INV3,r0
+	mtspr	SPRN_DNV0,r0
+	mtspr	SPRN_DNV1,r0
+	mtspr	SPRN_DNV2,r0
+	mtspr	SPRN_DNV3,r0
+	mtspr	SPRN_ITV0,r0
+	mtspr	SPRN_ITV1,r0
+	mtspr	SPRN_ITV2,r0
+	mtspr	SPRN_ITV3,r0
+	mtspr	SPRN_DTV0,r0
+	mtspr	SPRN_DTV1,r0
+	mtspr	SPRN_DTV2,r0
+	mtspr	SPRN_DTV3,r0
+
+	/*----------------------------------------------------------------*/
+	/* Cache victim limits */
+	/*----------------------------------------------------------------*/
+	/* floors 0, ceiling max to use the entire cache -- nothing locked
+	*/
+	lis	r1,0x0001
+	ori	r1,r1,0xf800
+	mtspr	SPRN_IVLIM,r1
+	mtspr	SPRN_DVLIM,r1
+
+	/*----------------------------------------------------------------+
+	|Initialize MMUCR[STID] = 0.
+	+-----------------------------------------------------------------*/
+	mfspr	r0,SPRN_MMUCR
+	addis	r1,0,0xFFFF
+	ori	r1,r1,0xFF00
+	and	r0,r0,r1
+	mtspr	SPRN_MMUCR,r0
+
+	/*----------------------------------------------------------------*/
+	/* Clear all TLB entries -- TID = 0, TS = 0 */
+	/*----------------------------------------------------------------*/
+	addis	r0,0,0x0000
+#ifdef CONFIG_SYS_RAMBOOT
+	li	r4,0		/* Start with TLB #0 */
+#else
+	li	r4,1		/* Start with TLB #1 */
+#endif
+	li	r1,64		/* 64 TLB entries */
+	sub	r1,r1,r4	/* calculate last TLB # */
+	mtctr	r1
+rsttlb:
+#ifdef CONFIG_SYS_RAMBOOT
+	tlbre	r3,r4,0		/* Read contents from TLB word #0 to get EPN */
+	rlwinm.	r3,r3,0,0xfffffc00	/* Mask EPN */
+	beq	tlbnxt		/* Skip EPN=0 TLB, this is the SDRAM TLB */
+#endif
+	tlbwe	r0,r4,0		/* Invalidate all entries (V=0)*/
+	tlbwe	r0,r4,1
+	tlbwe	r0,r4,2
+tlbnxt:	addi	r4,r4,1		/* Next TLB */
+	bdnz	rsttlb
+
+	/*----------------------------------------------------------------*/
+	/* TLB entry setup -- step thru tlbtab */
+	/*----------------------------------------------------------------*/
+#if defined(CONFIG_440SPE)
+	/*----------------------------------------------------------------*/
+	/* We have different TLB tables for revA and rev B of 440SPe */
+	/*----------------------------------------------------------------*/
+	mfspr	r1, PVR
+	lis	r0,0x5342
+	ori	r0,r0,0x1891
+	cmpw	r7,r1,r0
+	bne	r7,..revA
+	bl	tlbtabB
+	b	..goon
+..revA:
+	bl	tlbtabA
+..goon:
+#else
+	bl	tlbtab		/* Get tlbtab pointer */
+#endif
+	mr	r5,r0
+	li	r1,0x003f	/* 64 TLB entries max */
+	mtctr	r1
+	li	r4,0		/* TLB # */
+
+	addi	r5,r5,-4
+1:
+#ifdef CONFIG_SYS_RAMBOOT
+	tlbre	r3,r4,0		/* Read contents from TLB word #0 */
+	rlwinm.	r3,r3,0,0x00000200	/* Mask V (valid) bit */
+	bne	tlbnx2		/* Skip V=1 TLB, this is the SDRAM TLB */
+#endif
+	lwzu	r0,4(r5)
+	cmpwi	r0,0
+	beq	2f		/* 0 marks end */
+	lwzu	r1,4(r5)
+	lwzu	r2,4(r5)
+	tlbwe	r0,r4,0		/* TLB Word 0 */
+	tlbwe	r1,r4,1		/* TLB Word 1 */
+	tlbwe	r2,r4,2		/* TLB Word 2 */
+tlbnx2:	addi	r4,r4,1		/* Next TLB */
+	bdnz	1b
+
+	/*----------------------------------------------------------------*/
+	/* Continue from 'normal' start */
+	/*----------------------------------------------------------------*/
+2:
+	bl	3f
+	b	_start
+
+3:	li	r0,0
+	mtspr	SPRN_SRR1,r0		/* Keep things disabled for now */
+	mflr	r1
+	mtspr	SPRN_SRR0,r1
+	rfi
+#endif /* CONFIG_440 */
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+#ifndef CONFIG_NAND_SPL
+	.text
+	.long	0x27051956		/* U-Boot Magic Number			*/
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Critical input. */
+	CRIT_EXCEPTION(0x100, CritcalInput, UnknownException)
+
+#ifdef CONFIG_440
+/* Machine check */
+	MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+#else
+	CRIT_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+#endif /* CONFIG_440 */
+
+/* Data Storage exception. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+#ifdef CONFIG_440
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+	STD_EXCEPTION(0x900, Decrementer, DecrementerPITException)
+	STD_EXCEPTION(0xa00, APU, UnknownException)
+#endif
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+
+#ifdef CONFIG_440
+	STD_EXCEPTION(0x1300, DataTLBError, UnknownException)
+	STD_EXCEPTION(0x1400, InstructionTLBError, UnknownException)
+#else
+	STD_EXCEPTION(0x1000, PIT, DecrementerPITException)
+	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+#endif
+	CRIT_EXCEPTION(0x2000, DebugBreakpoint, DebugException )
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+	. = _START_OFFSET
+#endif
+	.globl	_start
+_start:
+
+/*****************************************************************************/
+#if defined(CONFIG_440)
+
+	/*----------------------------------------------------------------*/
+	/* Clear and set up some registers. */
+	/*----------------------------------------------------------------*/
+	li	r0,0x0000
+	lis	r1,0xffff
+	mtspr	SPRN_DEC,r0			/* prevent dec exceptions */
+	mtspr	SPRN_TBWL,r0			/* prevent fit & wdt exceptions */
+	mtspr	SPRN_TBWU,r0
+	mtspr	SPRN_TSR,r1			/* clear all timer exception status */
+	mtspr	SPRN_TCR,r0			/* disable all */
+	mtspr	SPRN_ESR,r0			/* clear exception syndrome register */
+	mtxer	r0			/* clear integer exception register */
+
+	/*----------------------------------------------------------------*/
+	/* Debug setup -- some (not very good) ice's need an event*/
+	/* to establish control :-( Define CONFIG_SYS_INIT_DBCR to the dbsr */
+	/* value you need in this case 0x8cff 0000 should do the trick */
+	/*----------------------------------------------------------------*/
+#if defined(CONFIG_SYS_INIT_DBCR)
+	lis	r1,0xffff
+	ori	r1,r1,0xffff
+	mtspr	SPRN_DBSR,r1			/* Clear all status bits */
+	lis	r0,CONFIG_SYS_INIT_DBCR@h
+	ori	r0,r0,CONFIG_SYS_INIT_DBCR@l
+	mtspr	SPRN_DBCR0,r0
+	isync
+#endif
+
+	/*----------------------------------------------------------------*/
+	/* Setup the internal SRAM */
+	/*----------------------------------------------------------------*/
+	li	r0,0
+
+#ifdef CONFIG_SYS_INIT_RAM_DCACHE
+	/* Clear Dcache to use as RAM */
+	addis	r3,r0,CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
+	addis	r4,r0,CONFIG_SYS_INIT_RAM_END@h
+	ori	r4,r4,CONFIG_SYS_INIT_RAM_END@l
+	rlwinm. r5,r4,0,27,31
+	rlwinm	r5,r4,27,5,31
+	beq	..d_ran
+	addi	r5,r5,0x0001
+..d_ran:
+	mtctr	r5
+..d_ag:
+	dcbz	r0,r3
+	addi	r3,r3,32
+	bdnz	..d_ag
+
+	/*
+	 * Lock the init-ram/stack in d-cache, so that other regions
+	 * may use d-cache as well
+	 * Note, that this current implementation locks exactly 4k
+	 * of d-cache, so please make sure that you don't define a
+	 * bigger init-ram area. Take a look at the lwmon5 440EPx
+	 * implementation as a reference.
+	 */
+	msync
+	isync
+	/* 8. set TFLOOR/NFLOOR to 8 (-> 8*16*32 bytes locked -> 4k) */
+	lis	r1,0x0201
+	ori	r1,r1,0xf808
+	mtspr	SPRN_DVLIM,r1
+	lis	r1,0x0808
+	ori	r1,r1,0x0808
+	mtspr	SPRN_DNV0,r1
+	mtspr	SPRN_DNV1,r1
+	mtspr	SPRN_DNV2,r1
+	mtspr	SPRN_DNV3,r1
+	mtspr	SPRN_DTV0,r1
+	mtspr	SPRN_DTV1,r1
+	mtspr	SPRN_DTV2,r1
+	mtspr	SPRN_DTV3,r1
+	msync
+	isync
+#endif /* CONFIG_SYS_INIT_RAM_DCACHE */
+
+	/* 440EP & 440GR are only 440er PPC's without internal SRAM */
+#if !defined(CONFIG_440EP) && !defined(CONFIG_440GR)
+	/* not all PPC's have internal SRAM usable as L2-cache */
+#if defined(CONFIG_440GX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_460SX)
+	mtdcr	L2_CACHE_CFG,r0		/* Ensure L2 Cache is off */
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	lis	r1, 0x0000
+	ori	r1,r1,0x0008		/* Set L2_CACHE_CFG[RDBW]=1 */
+	mtdcr	L2_CACHE_CFG,r1
+#endif
+
+	lis	r2,0x7fff
+	ori	r2,r2,0xffff
+	mfdcr	r1,ISRAM0_DPC
+	and	r1,r1,r2		/* Disable parity check */
+	mtdcr	ISRAM0_DPC,r1
+	mfdcr	r1,ISRAM0_PMEG
+	and	r1,r1,r2		/* Disable pwr mgmt */
+	mtdcr	ISRAM0_PMEG,r1
+
+	lis	r1,0x8000		/* BAS = 8000_0000 */
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+	ori	r1,r1,0x0980		/* first 64k */
+	mtdcr	ISRAM0_SB0CR,r1
+	lis	r1,0x8001
+	ori	r1,r1,0x0980		/* second 64k */
+	mtdcr	ISRAM0_SB1CR,r1
+	lis	r1, 0x8002
+	ori	r1,r1, 0x0980		/* third 64k */
+	mtdcr	ISRAM0_SB2CR,r1
+	lis	r1, 0x8003
+	ori	r1,r1, 0x0980		/* fourth 64k */
+	mtdcr	ISRAM0_SB3CR,r1
+#elif defined(CONFIG_440SPE) || defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	lis	r1,0x0000		/* BAS = X_0000_0000 */
+	ori	r1,r1,0x0984		/* first 64k */
+	mtdcr	ISRAM0_SB0CR,r1
+	lis	r1,0x0001
+	ori	r1,r1,0x0984		/* second 64k */
+	mtdcr	ISRAM0_SB1CR,r1
+	lis	r1, 0x0002
+	ori	r1,r1, 0x0984		/* third 64k */
+	mtdcr	ISRAM0_SB2CR,r1
+	lis	r1, 0x0003
+	ori	r1,r1, 0x0984		/* fourth 64k */
+	mtdcr	ISRAM0_SB3CR,r1
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	lis	r2,0x7fff
+	ori	r2,r2,0xffff
+	mfdcr	r1,ISRAM1_DPC
+	and	r1,r1,r2		/* Disable parity check */
+	mtdcr	ISRAM1_DPC,r1
+	mfdcr	r1,ISRAM1_PMEG
+	and	r1,r1,r2		/* Disable pwr mgmt */
+	mtdcr	ISRAM1_PMEG,r1
+
+	lis	r1,0x0004		/* BAS = 4_0004_0000 */
+	ori	r1,r1,0x0984		/* 64k */
+	mtdcr	ISRAM1_SB0CR,r1
+#endif
+#elif defined(CONFIG_460SX)
+	lis     r1,0x0000               /* BAS = 0000_0000 */
+	ori     r1,r1,0x0B84            /* first 128k */
+	mtdcr   ISRAM0_SB0CR,r1
+	lis     r1,0x0001
+	ori     r1,r1,0x0B84            /* second 128k */
+	mtdcr   ISRAM0_SB1CR,r1
+	lis     r1, 0x0002
+	ori     r1,r1, 0x0B84           /* third 128k */
+	mtdcr   ISRAM0_SB2CR,r1
+	lis     r1, 0x0003
+	ori     r1,r1, 0x0B84           /* fourth 128k */
+	mtdcr   ISRAM0_SB3CR,r1
+#elif defined(CONFIG_440GP)
+	ori	r1,r1,0x0380		/* 8k rw */
+	mtdcr	ISRAM0_SB0CR,r1
+	mtdcr	ISRAM0_SB1CR,r0		/* Disable bank 1 */
+#endif
+#endif /* #if !defined(CONFIG_440EP) && !defined(CONFIG_440GR) */
+
+	/*----------------------------------------------------------------*/
+	/* Setup the stack in internal SRAM */
+	/*----------------------------------------------------------------*/
+	lis	r1,CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r1,r1,CONFIG_SYS_INIT_SP_OFFSET@l
+	li	r0,0
+	stwu	r0,-4(r1)
+	stwu	r0,-4(r1)		/* Terminate call chain */
+
+	stwu	r1,-8(r1)		/* Save back chain and move SP */
+	lis	r0,RESET_VECTOR@h	/* Address of reset vector */
+	ori	r0,r0, RESET_VECTOR@l
+	stwu	r1,-8(r1)		/* Save back chain and move SP */
+	stw	r0,+12(r1)		/* Save return addr (underflow vect) */
+
+#ifdef CONFIG_NAND_SPL
+	bl	nand_boot_common	/* will not return */
+#else
+	GET_GOT
+
+	bl	cpu_init_f	/* run low-level CPU init code	   (from Flash) */
+	bl	board_init_f
+#endif
+
+#endif /* CONFIG_440 */
+
+/*****************************************************************************/
+#ifdef CONFIG_IOP480
+	/*----------------------------------------------------------------------- */
+	/* Set up some machine state registers. */
+	/*----------------------------------------------------------------------- */
+	addi	r0,r0,0x0000		/* initialize r0 to zero */
+	mtspr	SPRN_ESR,r0		/* clear Exception Syndrome Reg */
+	mttcr	r0			/* timer control register */
+	mtexier r0			/* disable all interrupts */
+	addis	r4,r0,0xFFFF		/* set r4 to 0xFFFFFFFF (status in the */
+	ori	r4,r4,0xFFFF		/* dbsr is cleared by setting bits to 1) */
+	mtdbsr	r4			/* clear/reset the dbsr */
+	mtexisr r4			/* clear all pending interrupts */
+	addis	r4,r0,0x8000
+	mtexier r4			/* enable critical exceptions */
+	addis	r4,r0,0x0000		/* assume 403GCX - enable core clk */
+	ori	r4,r4,0x4020		/* dbling (no harm done on GA and GC */
+	mtiocr	r4			/* since bit not used) & DRC to latch */
+					/* data bus on rising edge of CAS */
+	/*----------------------------------------------------------------------- */
+	/* Clear XER. */
+	/*----------------------------------------------------------------------- */
+	mtxer	r0
+	/*----------------------------------------------------------------------- */
+	/* Invalidate i-cache and d-cache TAG arrays. */
+	/*----------------------------------------------------------------------- */
+	addi	r3,0,1024		/* 1/4 of I-cache size, half of D-cache */
+	addi	r4,0,1024		/* 1/4 of I-cache */
+..cloop:
+	iccci	0,r3
+	iccci	r4,r3
+	dccci	0,r3
+	addic.	r3,r3,-16		/* move back one cache line */
+	bne	..cloop			/* loop back to do rest until r3 = 0 */
+
+	/* */
+	/* initialize IOP480 so it can read 1 MB code area for SRAM spaces */
+	/* this requires enabling MA[17..0], by default only MA[12..0] are enabled. */
+	/* */
+
+	/* first copy IOP480 register base address into r3 */
+	addis	r3,0,0x5000		/* IOP480 register base address hi */
+/*	ori	r3,r3,0x0000		/  IOP480 register base address lo */
+
+#ifdef CONFIG_ADCIOP
+	/* use r4 as the working variable */
+	/* turn on CS3 (LOCCTL.7) */
+	lwz	r4,0x84(r3)		/* LOCTL is at offset 0x84 */
+	andi.	r4,r4,0xff7f		/* make bit 7 = 0 -- CS3 mode */
+	stw	r4,0x84(r3)		/* LOCTL is at offset 0x84 */
+#endif
+
+#ifdef CONFIG_DASA_SIM
+	/* use r4 as the working variable */
+	/* turn on MA17 (LOCCTL.7) */
+	lwz	r4,0x84(r3)		/* LOCTL is at offset 0x84 */
+	ori	r4,r4,0x80		/* make bit 7 = 1 -- MA17 mode */
+	stw	r4,0x84(r3)		/* LOCTL is at offset 0x84 */
+#endif
+
+	/* turn on MA16..13 (LCS0BRD.12 = 0) */
+	lwz	r4,0x100(r3)		/* LCS0BRD is at offset 0x100 */
+	andi.	r4,r4,0xefff		/* make bit 12 = 0 */
+	stw	r4,0x100(r3)		/* LCS0BRD is at offset 0x100 */
+
+	/* make sure above stores all comlete before going on */
+	sync
+
+	/* last thing, set local init status done bit (DEVINIT.31) */
+	lwz	r4,0x80(r3)		/* DEVINIT is at offset 0x80 */
+	oris	r4,r4,0x8000		/* make bit 31 = 1 */
+	stw	r4,0x80(r3)		/* DEVINIT is at offset 0x80 */
+
+	/* clear all pending interrupts and disable all interrupts */
+	li	r4,-1			/* set p1 to 0xffffffff */
+	stw	r4,0x1b0(r3)		/* clear all pending interrupts */
+	stw	r4,0x1b8(r3)		/* clear all pending interrupts */
+	li	r4,0			/* set r4 to 0 */
+	stw	r4,0x1b4(r3)		/* disable all interrupts */
+	stw	r4,0x1bc(r3)		/* disable all interrupts */
+
+	/* make sure above stores all comlete before going on */
+	sync
+
+	/* Set-up icache cacheability. */
+	lis	r1, CONFIG_SYS_ICACHE_SACR_VALUE@h
+	ori	r1, r1, CONFIG_SYS_ICACHE_SACR_VALUE@l
+	mticcr	r1
+	isync
+
+	/* Set-up dcache cacheability. */
+	lis	r1, CONFIG_SYS_DCACHE_SACR_VALUE@h
+	ori	r1, r1, CONFIG_SYS_DCACHE_SACR_VALUE@l
+	mtdccr	r1
+
+	addis	r1,r0,CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r1,r1,CONFIG_SYS_INIT_SP_OFFSET /* set up the stack to SDRAM */
+	li	r0, 0			/* Make room for stack frame header and */
+	stwu	r0, -4(r1)		/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)		/* stack backtraces terminate cleanly	*/
+
+	GET_GOT			/* initialize GOT access			*/
+
+	bl	board_init_f	/* run first part of init code (from Flash)	*/
+
+#endif	/* CONFIG_IOP480 */
+
+/*****************************************************************************/
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+    defined(CONFIG_405EX) || defined(CONFIG_405)
+	/*----------------------------------------------------------------------- */
+	/* Clear and set up some registers. */
+	/*----------------------------------------------------------------------- */
+	addi	r4,r0,0x0000
+#if !defined(CONFIG_405EX)
+	mtspr	SPRN_SGR,r4
+#else
+	/*
+	 * On 405EX, completely clearing the SGR leads to PPC hangup
+	 * upon PCIe configuration access. The PCIe memory regions
+	 * need to be guarded!
+	 */
+	lis	r3,0x0000
+	ori	r3,r3,0x7FFC
+	mtspr	SPRN_SGR,r3
+#endif
+	mtspr	SPRN_DCWR,r4
+	mtesr	r4			/* clear Exception Syndrome Reg */
+	mttcr	r4			/* clear Timer Control Reg */
+	mtxer	r4			/* clear Fixed-Point Exception Reg */
+	mtevpr	r4			/* clear Exception Vector Prefix Reg */
+	addi	r4,r0,(0xFFFF-0x10000)		/* set r4 to 0xFFFFFFFF (status in the */
+					/* dbsr is cleared by setting bits to 1) */
+	mtdbsr	r4			/* clear/reset the dbsr */
+
+	/* Invalidate the i- and d-caches. */
+	bl	invalidate_icache
+	bl	invalidate_dcache
+
+	/* Set-up icache cacheability. */
+	lis	r4, CONFIG_SYS_ICACHE_SACR_VALUE@h
+	ori	r4, r4, CONFIG_SYS_ICACHE_SACR_VALUE@l
+	mticcr	r4
+	isync
+
+	/* Set-up dcache cacheability. */
+	lis	r4, CONFIG_SYS_DCACHE_SACR_VALUE@h
+	ori	r4, r4, CONFIG_SYS_DCACHE_SACR_VALUE@l
+	mtdccr	r4
+
+#if !(defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))\
+				&& !defined (CONFIG_XILINX_405)
+	/*----------------------------------------------------------------------- */
+	/* Tune the speed and size for flash CS0  */
+	/*----------------------------------------------------------------------- */
+	bl	ext_bus_cntlr_init
+#endif
+
+#if !(defined(CONFIG_SYS_INIT_DCACHE_CS) || defined(CONFIG_SYS_TEMP_STACK_OCM))
+	/*
+	 * For boards that don't have OCM and can't use the data cache
+	 * for their primordial stack, setup stack here directly after the
+	 * SDRAM is initialized in ext_bus_cntlr_init.
+	 */
+	lis	r1, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r1,r1,CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in SDRAM */
+
+	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	*/
+	/*
+	 * Set up a dummy frame to store reset vector as return address.
+	 * this causes stack underflow to reset board.
+	 */
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	lis	r0, RESET_VECTOR@h	/* Address of reset vector */
+	ori	r0, r0, RESET_VECTOR@l
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	stw	r0, +12(r1)		/* Save return addr (underflow vect) */
+#endif /* !(CONFIG_SYS_INIT_DCACHE_CS	|| !CONFIG_SYS_TEM_STACK_OCM) */
+
+#if defined(CONFIG_405EP)
+	/*----------------------------------------------------------------------- */
+	/* DMA Status, clear to come up clean */
+	/*----------------------------------------------------------------------- */
+	addis	r3,r0, 0xFFFF		/* Clear all existing DMA status */
+	ori	r3,r3, 0xFFFF
+	mtdcr	DMASR, r3
+
+	bl	ppc405ep_init		/* do ppc405ep specific init */
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_SYS_OCM_DATA_ADDR) && defined(CONFIG_SYS_OCM_DATA_SIZE)
+#if defined(CONFIG_405EZ)
+	/********************************************************************
+	 * Setup OCM - On Chip Memory - PPC405EZ uses OCM Controller V2
+	 *******************************************************************/
+	/*
+	 * We can map the OCM on the PLB3, so map it at
+	 * CONFIG_SYS_OCM_DATA_ADDR + 0x8000
+	 */
+	lis	r3,CONFIG_SYS_OCM_DATA_ADDR@h	/* OCM location */
+	ori	r3,r3,CONFIG_SYS_OCM_DATA_ADDR@l
+	ori	r3,r3,0x0270		/* 16K for Bank 1, R/W/Enable */
+	mtdcr	OCM0_PLBCR1,r3		/* Set PLB Access */
+	ori	r3,r3,0x4000		/* Add 0x4000 for bank 2 */
+	mtdcr	OCM0_PLBCR2,r3		/* Set PLB Access */
+	isync
+
+	lis	r3,CONFIG_SYS_OCM_DATA_ADDR@h	/* OCM location */
+	ori	r3,r3,CONFIG_SYS_OCM_DATA_ADDR@l
+	ori	r3,r3,0x0270		/* 16K for Bank 1, R/W/Enable */
+	mtdcr	OCM0_DSRC1, r3		/* Set Data Side */
+	mtdcr	OCM0_ISRC1, r3		/* Set Instruction Side */
+	ori	r3,r3,0x4000		/* Add 0x4000 for bank 2 */
+	mtdcr	OCM0_DSRC2, r3		/* Set Data Side */
+	mtdcr	OCM0_ISRC2, r3		/* Set Instruction Side */
+	addis	r3,0,0x0800		/* OCM Data Parity Disable - 1 Wait State */
+	mtdcr	OCM0_DISDPC,r3
+
+	isync
+#else /* CONFIG_405EZ */
+	/********************************************************************
+	 * Setup OCM - On Chip Memory
+	 *******************************************************************/
+	/* Setup OCM */
+	lis	r0, 0x7FFF
+	ori	r0, r0, 0xFFFF
+	mfdcr	r3, OCM0_ISCNTL		/* get instr-side IRAM config */
+	mfdcr	r4, OCM0_DSCNTL		/* get data-side IRAM config */
+	and	r3, r3, r0		/* disable data-side IRAM */
+	and	r4, r4, r0		/* disable data-side IRAM */
+	mtdcr	OCM0_ISCNTL, r3		/* set instr-side IRAM config */
+	mtdcr	OCM0_DSCNTL, r4		/* set data-side IRAM config */
+	isync
+
+	lis	r3,CONFIG_SYS_OCM_DATA_ADDR@h	/* OCM location */
+	ori	r3,r3,CONFIG_SYS_OCM_DATA_ADDR@l
+	mtdcr	OCM0_DSARC, r3
+	addis	r4, 0, 0xC000		/* OCM data area enabled */
+	mtdcr	OCM0_DSCNTL, r4
+	isync
+#endif /* CONFIG_405EZ */
+#endif
+
+	/*----------------------------------------------------------------------- */
+	/* Setup temporary stack in DCACHE or OCM if needed for SDRAM SPD. */
+	/*----------------------------------------------------------------------- */
+#ifdef CONFIG_SYS_INIT_DCACHE_CS
+	li	r4, PBxAP
+	mtdcr	EBC0_CFGADDR, r4
+	lis	r4, CONFIG_SYS_INIT_DCACHE_PBxAR@h
+	ori	r4, r4, CONFIG_SYS_INIT_DCACHE_PBxAR@l
+	mtdcr	EBC0_CFGDATA, r4
+
+	addi	r4, 0, PBxCR
+	mtdcr	EBC0_CFGADDR, r4
+	lis	r4, CONFIG_SYS_INIT_DCACHE_PBxCR@h
+	ori	r4, r4, CONFIG_SYS_INIT_DCACHE_PBxCR@l
+	mtdcr	EBC0_CFGDATA, r4
+
+	/*
+	 * Enable the data cache for the 128MB storage access control region
+	 * at CONFIG_SYS_INIT_RAM_ADDR.
+	 */
+	mfdccr	r4
+	oris	r4, r4, PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@h
+	ori	r4, r4, PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@l
+	mtdccr	r4
+
+	/*
+	 * Preallocate data cache lines to be used to avoid a subsequent
+	 * cache miss and an ensuing machine check exception when exceptions
+	 * are enabled.
+	 */
+	li	r0, 0
+
+	lis	r3, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+
+	lis	r4, CONFIG_SYS_INIT_RAM_END@h
+	ori	r4, r4, CONFIG_SYS_INIT_RAM_END@l
+
+	/*
+	 * Convert the size, in bytes, to the number of cache lines/blocks
+	 * to preallocate.
+	 */
+	clrlwi. r5, r4, (32 - L1_CACHE_SHIFT)
+	srwi	r5, r4, L1_CACHE_SHIFT
+	beq	..load_counter
+	addi	r5, r5, 0x0001
+..load_counter:
+	mtctr	r5
+
+	/* Preallocate the computed number of cache blocks. */
+..alloc_dcache_block:
+	dcba	r0, r3
+	addi	r3, r3, L1_CACHE_BYTES
+	bdnz	..alloc_dcache_block
+	sync
+
+	/*
+	 * Load the initial stack pointer and data area and convert the size,
+	 * in bytes, to the number of words to initialize to a known value.
+	 */
+	lis	r1, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r1, r1, CONFIG_SYS_INIT_SP_OFFSET@l
+
+	lis	r4, (CONFIG_SYS_INIT_RAM_END >> 2)@h
+	ori	r4, r4, (CONFIG_SYS_INIT_RAM_END >> 2)@l
+	mtctr	r4
+
+	lis	r2, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r2, r2, CONFIG_SYS_INIT_RAM_END@l
+
+	lis	r4, CONFIG_SYS_INIT_RAM_PATTERN@h
+	ori	r4, r4, CONFIG_SYS_INIT_RAM_PATTERN@l
+
+..stackloop:
+	stwu	r4, -4(r2)
+	bdnz	..stackloop
+
+	/*
+	 * Make room for stack frame header and clear final stack frame so
+	 * that stack backtraces terminate cleanly.
+	 */
+	stwu	r0, -4(r1)
+	stwu	r0, -4(r1)
+
+	/*
+	 * Set up a dummy frame to store reset vector as return address.
+	 * this causes stack underflow to reset board.
+	 */
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	addis	r0, 0, RESET_VECTOR@h	/* Address of reset vector */
+	ori	r0, r0, RESET_VECTOR@l
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	stw	r0, +12(r1)		/* Save return addr (underflow vect) */
+
+#elif defined(CONFIG_SYS_TEMP_STACK_OCM) && \
+	(defined(CONFIG_SYS_OCM_DATA_ADDR) && defined(CONFIG_SYS_OCM_DATA_SIZE))
+	/*
+	 * Stack in OCM.
+	 */
+
+	/* Set up Stack at top of OCM */
+	lis	r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)@h
+	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)@l
+
+	/* Set up a zeroized stack frame so that backtrace works right */
+	li	r0, 0
+	stwu	r0, -4(r1)
+	stwu	r0, -4(r1)
+
+	/*
+	 * Set up a dummy frame to store reset vector as return address.
+	 * this causes stack underflow to reset board.
+	 */
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	lis	r0, RESET_VECTOR@h	/* Address of reset vector */
+	ori	r0, r0, RESET_VECTOR@l
+	stwu	r1, -8(r1)		/* Save back chain and move SP */
+	stw	r0, +12(r1)		/* Save return addr (underflow vect) */
+#endif /* CONFIG_SYS_INIT_DCACHE_CS */
+
+#ifdef CONFIG_NAND_SPL
+	bl	nand_boot_common	/* will not return */
+#else
+	GET_GOT			/* initialize GOT access			*/
+
+	bl	cpu_init_f	/* run low-level CPU init code	   (from Flash) */
+
+	/* NEVER RETURNS! */
+	bl	board_init_f	/* run first part of init code (from Flash)	*/
+#endif /* CONFIG_NAND_SPL */
+
+#endif	/* CONFIG_405GP || CONFIG_405CR || CONFIG_405 || CONFIG_405EP */
+	/*----------------------------------------------------------------------- */
+
+
+#ifndef CONFIG_NAND_SPL
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+crit_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	SPRN_CSRR0,r2
+	mtspr	SPRN_CSRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfci
+
+#ifdef CONFIG_440
+mck_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	SPRN_MCSRR0,r2
+	mtspr	SPRN_MCSRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfmci
+#endif /* CONFIG_440 */
+
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out16 */
+/* Description:	 Output 16 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out16
+out16:
+	sth	r4,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out16r */
+/* Description:	 Byte reverse and output 16 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out16r
+out16r:
+	sthbrx	r4,r0,r3
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out32r */
+/* Description:	 Byte reverse and output 32 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out32r
+out32r:
+	stwbrx	r4,r0,r3
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in16 */
+/* Description:	 Input 16 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	in16
+in16:
+	lhz	r3,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in16r */
+/* Description:	 Input 16 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+	.globl	in16r
+in16r:
+	lhbrx	r3,r0,r3
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in32r */
+/* Description:	 Input 32 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+	.globl	in32r
+in32r:
+	lwbrx	r3,r0,r3
+	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 = Relocated stack pointer
+ * r4 = Relocated global data pointer
+ * r5 = Relocated text pointer
+ */
+	.globl	relocate_code
+relocate_code:
+#if defined(CONFIG_4xx_DCACHE) || defined(CONFIG_SYS_INIT_DCACHE_CS)
+	/*
+	 * We need to flush the initial global data (gd_t) before the dcache
+	 * will be invalidated.
+	 */
+
+	/* Save registers */
+	mr	r9, r3
+	mr	r10, r4
+	mr	r11, r5
+
+	/* Flush initial global data range */
+	mr	r3, r4
+	addi	r4, r4, CONFIG_SYS_GBL_DATA_SIZE@l
+	bl	flush_dcache_range
+
+#if defined(CONFIG_SYS_INIT_DCACHE_CS)
+	/*
+	 * Undo the earlier data cache set-up for the primordial stack and
+	 * data area. First, invalidate the data cache and then disable data
+	 * cacheability for that area. Finally, restore the EBC values, if
+	 * any.
+	 */
+
+	/* Invalidate the primordial stack and data area in cache */
+	lis	r3, CONFIG_SYS_INIT_RAM_ADDR@h
+	ori	r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+
+	lis	r4, CONFIG_SYS_INIT_RAM_END@h
+	ori	r4, r4, CONFIG_SYS_INIT_RAM_END@l
+	add	r4, r4, r3
+
+	bl	invalidate_dcache_range
+
+	/* Disable cacheability for the region */
+	mfdccr	r3
+	lis     r4, ~PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@h
+	ori     r4, r4, ~PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@l
+	and     r3, r3, r4
+	mtdccr  r3
+
+	/* Restore the EBC parameters */
+	li	r3, PBxAP
+	mtdcr	EBC0_CFGADDR, r3
+	lis	r3, PBxAP_VAL@h
+	ori	r3, r3, PBxAP_VAL@l
+	mtdcr	EBC0_CFGDATA, r3
+
+	li	r3, PBxCR
+	mtdcr	EBC0_CFGADDR, r3
+	lis	r3, PBxCR_VAL@h
+	ori	r3, r3, PBxCR_VAL@l
+	mtdcr	EBC0_CFGDATA, r3
+#endif /* defined(CONFIG_SYS_INIT_DCACHE_CS) */
+
+	/* Restore registers */
+	mr	r3, r9
+	mr	r4, r10
+	mr	r5, r11
+#endif /* defined(CONFIG_4xx_DCACHE) || defined(CONFIG_SYS_INIT_DCACHE_CS) */
+
+#ifdef CONFIG_SYS_INIT_RAM_DCACHE
+	/*
+	 * Unlock the previously locked d-cache
+	 */
+	msync
+	isync
+	/* set TFLOOR/NFLOOR to 0 again */
+	lis	r6,0x0001
+	ori	r6,r6,0xf800
+	mtspr	SPRN_DVLIM,r6
+	lis	r6,0x0000
+	ori	r6,r6,0x0000
+	mtspr	SPRN_DNV0,r6
+	mtspr	SPRN_DNV1,r6
+	mtspr	SPRN_DNV2,r6
+	mtspr	SPRN_DNV3,r6
+	mtspr	SPRN_DTV0,r6
+	mtspr	SPRN_DTV1,r6
+	mtspr	SPRN_DTV2,r6
+	mtspr	SPRN_DTV3,r6
+	msync
+	isync
+#endif /* CONFIG_SYS_INIT_RAM_DCACHE */
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+    defined(CONFIG_460SX)
+	/*
+	 * On some 440er platforms the cache is enabled in the first TLB (Boot-CS)
+	 * to speed up the boot process. Now this cache needs to be disabled.
+	 */
+	iccci	0,0			/* Invalidate inst cache */
+	dccci	0,0			/* Invalidate data cache, now no longer our stack */
+	sync
+	isync
+
+	/* Clear all potential pending exceptions */
+	mfspr	r1,SPRN_MCSR
+	mtspr	SPRN_MCSR,r1
+#ifdef CONFIG_SYS_TLB_FOR_BOOT_FLASH
+	addi	r1,r0,CONFIG_SYS_TLB_FOR_BOOT_FLASH	/* Use defined TLB */
+#else
+	addi	r1,r0,0x0000		/* Default TLB entry is #0 */
+#endif /* CONFIG_SYS_TLB_FOR_BOOT_FLASH */
+	tlbre	r0,r1,0x0002		/* Read contents */
+	ori	r0,r0,0x0c00		/* Or in the inhibit, write through bit */
+	tlbwe	r0,r1,0x0002		/* Save it out */
+	sync
+	isync
+#endif /* defined(CONFIG_440EP) || ... || defined(CONFIG_460GT) */
+	mr	r1,  r3		/* Set new stack pointer		*/
+	mr	r9,  r4		/* Save copy of Init Data pointer	*/
+	mr	r10, r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, L1_CACHE_BYTES		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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 + _START_OFFSET
+	mtlr	r0
+	blr				/* NEVER RETURNS! */
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(_end)
+
+	cmplw	0, r3, r4
+	beq	7f
+
+	li	r0, 0
+
+	andi.	r5, r4, 3
+	beq	6f
+	sub	r4, r4, r5
+	mtctr	r5
+	mr	r5, r4
+5:	stb	r0, 0(r5)
+	addi	r5, r5, 1
+	bdnz	5b
+6:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	6b
+
+7:
+	mr	r3, r9		/* Init Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start_of_vectors)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + _START_OFFSET
+	li	r8, Alignment - _start + _START_OFFSET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector */
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + _START_OFFSET
+	bl	trap_reloc
+
+#ifdef CONFIG_440
+	li	r7, .L_FPUnavailable - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_Decrementer - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_APU - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_InstructionTLBError - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_DataTLBError - _start + _START_OFFSET
+	bl	trap_reloc
+#else /* CONFIG_440 */
+	li	r7, .L_PIT - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_InstructionTLBMiss - _start + _START_OFFSET
+	bl	trap_reloc
+
+	li	r7, .L_DataTLBMiss - _start + _START_OFFSET
+	bl	trap_reloc
+#endif /* CONFIG_440 */
+
+	li	r7, .L_DebugBreakpoint - _start + _START_OFFSET
+	bl	trap_reloc
+
+#if !defined(CONFIG_440)
+	addi	r7,r0,0x1000		/* set ME bit (Machine Exceptions) */
+	oris	r7,r7,0x0002		/* set CE bit (Critical Exceptions) */
+	mtmsr	r7			/* change MSR */
+#else
+	bl	__440_msr_set
+	b	__440_msr_continue
+
+__440_msr_set:
+	addi	r7,r0,0x1000		/* set ME bit (Machine Exceptions) */
+	oris	r7,r7,0x0002		/* set CE bit (Critical Exceptions) */
+	mtspr	SPRN_SRR1,r7
+	mflr	r7
+	mtspr	SPRN_SRR0,r7
+	rfi
+__440_msr_continue:
+#endif
+
+	mtlr	r4			/* restore link register	*/
+	blr
+
+#if defined(CONFIG_440)
+/*----------------------------------------------------------------------------+
+| dcbz_area.
++----------------------------------------------------------------------------*/
+	function_prolog(dcbz_area)
+	rlwinm. r5,r4,0,27,31
+	rlwinm	r5,r4,27,5,31
+	beq	..d_ra2
+	addi	r5,r5,0x0001
+..d_ra2:mtctr	r5
+..d_ag2:dcbz	r0,r3
+	addi	r3,r3,32
+	bdnz	..d_ag2
+	sync
+	blr
+	function_epilog(dcbz_area)
+#endif /* CONFIG_440 */
+#endif /* CONFIG_NAND_SPL */
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in8 */
+/* Description:	 Input 8 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	in8
+in8:
+	lbz	r3,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out8 */
+/* Description:	 Output 8 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out8
+out8:
+	stb	r4,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 out32 */
+/* Description:	 Output 32 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	out32
+out32:
+	stw	r4,0x0000(r3)
+	blr
+
+/*------------------------------------------------------------------------------- */
+/* Function:	 in32 */
+/* Description:	 Input 32 bits */
+/*------------------------------------------------------------------------------- */
+	.globl	in32
+in32:
+	lwz	3,0x0000(3)
+	blr
+
+/**************************************************************************/
+/* PPC405EP specific stuff						  */
+/**************************************************************************/
+#ifdef CONFIG_405EP
+ppc405ep_init:
+
+#ifdef CONFIG_BUBINGA
+	/*
+	 * Initialize EBC chip selects 1 & 4 and GPIO pins (for alternate
+	 * function) to support FPGA and NVRAM accesses below.
+	 */
+
+	lis	r3,GPIO0_OSRH@h		/* config GPIO output select */
+	ori	r3,r3,GPIO0_OSRH@l
+	lis	r4,CONFIG_SYS_GPIO0_OSRH@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_OSRH@l
+	stw	r4,0(r3)
+	lis	r3,GPIO0_OSRL@h
+	ori	r3,r3,GPIO0_OSRL@l
+	lis	r4,CONFIG_SYS_GPIO0_OSRL@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_OSRL@l
+	stw	r4,0(r3)
+
+	lis	r3,GPIO0_ISR1H@h	/* config GPIO input select */
+	ori	r3,r3,GPIO0_ISR1H@l
+	lis	r4,CONFIG_SYS_GPIO0_ISR1H@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_ISR1H@l
+	stw	r4,0(r3)
+	lis	r3,GPIO0_ISR1L@h
+	ori	r3,r3,GPIO0_ISR1L@l
+	lis	r4,CONFIG_SYS_GPIO0_ISR1L@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_ISR1L@l
+	stw	r4,0(r3)
+
+	lis	r3,GPIO0_TSRH@h		/* config GPIO three-state select */
+	ori	r3,r3,GPIO0_TSRH@l
+	lis	r4,CONFIG_SYS_GPIO0_TSRH@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_TSRH@l
+	stw	r4,0(r3)
+	lis	r3,GPIO0_TSRL@h
+	ori	r3,r3,GPIO0_TSRL@l
+	lis	r4,CONFIG_SYS_GPIO0_TSRL@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_TSRL@l
+	stw	r4,0(r3)
+
+	lis	r3,GPIO0_TCR@h		/* config GPIO driver output enables */
+	ori	r3,r3,GPIO0_TCR@l
+	lis	r4,CONFIG_SYS_GPIO0_TCR@h
+	ori	r4,r4,CONFIG_SYS_GPIO0_TCR@l
+	stw	r4,0(r3)
+
+	li	r3,PB1AP		/* program EBC bank 1 for RTC access */
+	mtdcr	EBC0_CFGADDR,r3
+	lis	r3,CONFIG_SYS_EBC_PB1AP@h
+	ori	r3,r3,CONFIG_SYS_EBC_PB1AP@l
+	mtdcr	EBC0_CFGDATA,r3
+	li	r3,PB1CR
+	mtdcr	EBC0_CFGADDR,r3
+	lis	r3,CONFIG_SYS_EBC_PB1CR@h
+	ori	r3,r3,CONFIG_SYS_EBC_PB1CR@l
+	mtdcr	EBC0_CFGDATA,r3
+
+	li	r3,PB1AP		/* program EBC bank 1 for RTC access */
+	mtdcr	EBC0_CFGADDR,r3
+	lis	r3,CONFIG_SYS_EBC_PB1AP@h
+	ori	r3,r3,CONFIG_SYS_EBC_PB1AP@l
+	mtdcr	EBC0_CFGDATA,r3
+	li	r3,PB1CR
+	mtdcr	EBC0_CFGADDR,r3
+	lis	r3,CONFIG_SYS_EBC_PB1CR@h
+	ori	r3,r3,CONFIG_SYS_EBC_PB1CR@l
+	mtdcr	EBC0_CFGDATA,r3
+
+	li	r3,PB4AP		/* program EBC bank 4 for FPGA access */
+	mtdcr	EBC0_CFGADDR,r3
+	lis	r3,CONFIG_SYS_EBC_PB4AP@h
+	ori	r3,r3,CONFIG_SYS_EBC_PB4AP@l
+	mtdcr	EBC0_CFGDATA,r3
+	li	r3,PB4CR
+	mtdcr	EBC0_CFGADDR,r3
+	lis	r3,CONFIG_SYS_EBC_PB4CR@h
+	ori	r3,r3,CONFIG_SYS_EBC_PB4CR@l
+	mtdcr	EBC0_CFGDATA,r3
+#endif
+
+	/*
+	!-----------------------------------------------------------------------
+	! Check to see if chip is in bypass mode.
+	! If so, write stored CPC0_PLLMR0 and CPC0_PLLMR1 values and perform a
+	! CPU reset   Otherwise, skip this step and keep going.
+	! Note:	 Running BIOS in bypass mode is not supported since PLB speed
+	!	 will not be fast enough for the SDRAM (min 66MHz)
+	!-----------------------------------------------------------------------
+	*/
+	mfdcr	r5, CPC0_PLLMR1
+	rlwinm	r4,r5,1,0x1		/* get system clock source (SSCS) */
+	cmpi	cr0,0,r4,0x1
+
+	beq    pll_done			/* if SSCS =b'1' then PLL has */
+					/* already been set */
+					/* and CPU has been reset */
+					/* so skip to next section */
+
+#ifdef CONFIG_BUBINGA
+	/*
+	!-----------------------------------------------------------------------
+	! Read NVRAM to get value to write in PLLMR.
+	! If value has not been correctly saved, write default value
+	! Default config values (assuming on-board 33MHz SYS_CLK) are above.
+	! See CPU_DEFAULT_200 and CPU_DEFAULT_266 above.
+	!
+	! WARNING:  This code assumes the first three words in the nvram_t
+	!	    structure in openbios.h.  Changing the beginning of
+	!	    the structure will break this code.
+	!
+	!-----------------------------------------------------------------------
+	*/
+	addis	r3,0,NVRAM_BASE@h
+	addi	r3,r3,NVRAM_BASE@l
+
+	lwz	r4, 0(r3)
+	addis	r5,0,NVRVFY1@h
+	addi	r5,r5,NVRVFY1@l
+	cmp	cr0,0,r4,r5		/* Compare 1st NVRAM Magic number*/
+	bne	..no_pllset
+	addi	r3,r3,4
+	lwz	r4, 0(r3)
+	addis	r5,0,NVRVFY2@h
+	addi	r5,r5,NVRVFY2@l
+	cmp	cr0,0,r4,r5		/* Compare 2 NVRAM Magic number */
+	bne	..no_pllset
+	addi	r3,r3,8			/* Skip over conf_size */
+	lwz	r4, 4(r3)		/* Load PLLMR1 value from NVRAM */
+	lwz	r3, 0(r3)		/* Load PLLMR0 value from NVRAM */
+	rlwinm	r5,r4,1,0x1		/* get system clock source (SSCS) */
+	cmpi	 cr0,0,r5,1		/* See if PLL is locked */
+	beq	pll_write
+..no_pllset:
+#endif /* CONFIG_BUBINGA */
+
+#ifdef CONFIG_TAIHU
+	mfdcr	r4, CPC0_BOOT
+	andi.	r5, r4, CPC0_BOOT_SEP@l
+	bne	strap_1			/* serial eeprom present */
+	addis	r5,0,CPLD_REG0_ADDR@h
+	ori	r5,r5,CPLD_REG0_ADDR@l
+	andi.	r5, r5, 0x10
+	bne	_pci_66mhz
+#endif /* CONFIG_TAIHU */
+
+#if defined(CONFIG_ZEUS)
+	mfdcr	r4, CPC0_BOOT
+	andi.	r5, r4, CPC0_BOOT_SEP@l
+	bne	strap_1			/* serial eeprom present */
+	lis	r3,0x0000
+	addi	r3,r3,0x3030
+	lis	r4,0x8042
+	addi	r4,r4,0x223e
+	b	1f
+strap_1:
+	mfdcr	r3, CPC0_PLLMR0
+	mfdcr	r4, CPC0_PLLMR1
+	b	1f
+#endif
+
+	addis	r3,0,PLLMR0_DEFAULT@h	/* PLLMR0 default value */
+	ori	r3,r3,PLLMR0_DEFAULT@l	/* */
+	addis	r4,0,PLLMR1_DEFAULT@h	/* PLLMR1 default value */
+	ori	r4,r4,PLLMR1_DEFAULT@l	/* */
+
+#ifdef CONFIG_TAIHU
+	b	1f
+_pci_66mhz:
+	addis	r3,0,PLLMR0_DEFAULT_PCI66@h
+	ori	r3,r3,PLLMR0_DEFAULT_PCI66@l
+	addis	r4,0,PLLMR1_DEFAULT_PCI66@h
+	ori	r4,r4,PLLMR1_DEFAULT_PCI66@l
+	b	1f
+strap_1:
+	mfdcr	r3, CPC0_PLLMR0
+	mfdcr	r4, CPC0_PLLMR1
+#endif /* CONFIG_TAIHU */
+
+1:
+	b	pll_write		/* Write the CPC0_PLLMR with new value */
+
+pll_done:
+	/*
+	!-----------------------------------------------------------------------
+	! Clear Soft Reset Register
+	! This is needed to enable PCI if not booting from serial EPROM
+	!-----------------------------------------------------------------------
+		*/
+	addi	r3, 0, 0x0
+	mtdcr	CPC0_SRR, r3
+
+	addis	 r3,0,0x0010
+	mtctr	r3
+pci_wait:
+	bdnz	pci_wait
+
+	blr				/* return to main code */
+
+/*
+!-----------------------------------------------------------------------------
+! Function:	pll_write
+! Description:	Updates the value of the CPC0_PLLMR according to CMOS27E documentation
+!		That is:
+!			  1.  Pll is first disabled (de-activated by putting in bypass mode)
+!			  2.  PLL is reset
+!			  3.  Clock dividers are set while PLL is held in reset and bypassed
+!			  4.  PLL Reset is cleared
+!			  5.  Wait 100us for PLL to lock
+!			  6.  A core reset is performed
+! Input: r3 = Value to write to CPC0_PLLMR0
+! Input: r4 = Value to write to CPC0_PLLMR1
+! Output r3 = none
+!-----------------------------------------------------------------------------
+*/
+	.globl	pll_write
+pll_write:
+	mfdcr  r5, CPC0_UCR
+	andis. r5,r5,0xFFFF
+	ori    r5,r5,0x0101		/* Stop the UART clocks */
+	mtdcr  CPC0_UCR,r5		/* Before changing PLL */
+
+	mfdcr  r5, CPC0_PLLMR1
+	rlwinm r5,r5,0,0x7FFFFFFF	/* Disable PLL */
+	mtdcr	CPC0_PLLMR1,r5
+	oris   r5,r5,0x4000		/* Set PLL Reset */
+	mtdcr	CPC0_PLLMR1,r5
+
+	mtdcr	CPC0_PLLMR0,r3		/* Set clock dividers */
+	rlwinm r5,r4,0,0x3FFFFFFF	/* Reset & Bypass new PLL dividers */
+	oris   r5,r5,0x4000		/* Set PLL Reset */
+	mtdcr	CPC0_PLLMR1,r5		/* Set clock dividers */
+	rlwinm r5,r5,0,0xBFFFFFFF	/* Clear PLL Reset */
+	mtdcr	CPC0_PLLMR1,r5
+
+		/*
+	! Wait min of 100us for PLL to lock.
+	! See CMOS 27E databook for more info.
+	! At 200MHz, that means waiting 20,000 instructions
+		 */
+	addi	r3,0,20000		/* 2000 = 0x4e20 */
+	mtctr	r3
+pll_wait:
+	bdnz	pll_wait
+
+	oris   r5,r5,0x8000		/* Enable PLL */
+	mtdcr	CPC0_PLLMR1,r5		/* Engage */
+
+	/*
+	 * Reset CPU to guarantee timings are OK
+	 * Not sure if this is needed...
+	 */
+	addis r3,0,0x1000
+	mtspr SPRN_DBCR0,r3		/* This will cause a CPU core reset, and */
+					/* execution will continue from the poweron */
+					/* vector of 0xfffffffc */
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_440)
+/*----------------------------------------------------------------------------+
+| mttlb3.
++----------------------------------------------------------------------------*/
+	function_prolog(mttlb3)
+	TLBWE(4,3,2)
+	blr
+	function_epilog(mttlb3)
+
+/*----------------------------------------------------------------------------+
+| mftlb3.
++----------------------------------------------------------------------------*/
+	function_prolog(mftlb3)
+	TLBRE(3,3,2)
+	blr
+	function_epilog(mftlb3)
+
+/*----------------------------------------------------------------------------+
+| mttlb2.
++----------------------------------------------------------------------------*/
+	function_prolog(mttlb2)
+	TLBWE(4,3,1)
+	blr
+	function_epilog(mttlb2)
+
+/*----------------------------------------------------------------------------+
+| mftlb2.
++----------------------------------------------------------------------------*/
+	function_prolog(mftlb2)
+	TLBRE(3,3,1)
+	blr
+	function_epilog(mftlb2)
+
+/*----------------------------------------------------------------------------+
+| mttlb1.
++----------------------------------------------------------------------------*/
+	function_prolog(mttlb1)
+	TLBWE(4,3,0)
+	blr
+	function_epilog(mttlb1)
+
+/*----------------------------------------------------------------------------+
+| mftlb1.
++----------------------------------------------------------------------------*/
+	function_prolog(mftlb1)
+	TLBRE(3,3,0)
+	blr
+	function_epilog(mftlb1)
+#endif /* CONFIG_440 */
+
+#if defined(CONFIG_NAND_SPL)
+/*
+ * void nand_boot_relocate(dst, src, bytes)
+ *
+ * r3 = Destination address to copy code to (in SDRAM)
+ * r4 = Source address to copy code from
+ * r5 = size to copy in bytes
+ */
+nand_boot_relocate:
+	mr	r6,r3
+	mr	r7,r4
+	mflr	r8
+
+	/*
+	 * Copy SPL from icache into SDRAM
+	 */
+	subi	r3,r3,4
+	subi	r4,r4,4
+	srwi	r5,r5,2
+	mtctr	r5
+..spl_loop:
+	lwzu	r0,4(r4)
+	stwu	r0,4(r3)
+	bdnz	..spl_loop
+
+	/*
+	 * Calculate "corrected" link register, so that we "continue"
+	 * in execution in destination range
+	 */
+	sub	r3,r7,r6	/* r3 = src - dst */
+	sub	r8,r8,r3	/* r8 = link-reg - (src - dst) */
+	mtlr	r8
+	blr
+
+nand_boot_common:
+	/*
+	 * First initialize SDRAM. It has to be available *before* calling
+	 * nand_boot().
+	 */
+	lis	r3,CONFIG_SYS_SDRAM_BASE@h
+	ori	r3,r3,CONFIG_SYS_SDRAM_BASE@l
+	bl	initdram
+
+	/*
+	 * Now copy the 4k SPL code into SDRAM and continue execution
+	 * from there.
+	 */
+	lis	r3,CONFIG_SYS_NAND_BOOT_SPL_DST@h
+	ori	r3,r3,CONFIG_SYS_NAND_BOOT_SPL_DST@l
+	lis	r4,CONFIG_SYS_NAND_BOOT_SPL_SRC@h
+	ori	r4,r4,CONFIG_SYS_NAND_BOOT_SPL_SRC@l
+	lis	r5,CONFIG_SYS_NAND_BOOT_SPL_SIZE@h
+	ori	r5,r5,CONFIG_SYS_NAND_BOOT_SPL_SIZE@l
+	bl	nand_boot_relocate
+
+	/*
+	 * We're running from SDRAM now!!!
+	 *
+	 * It is necessary for 4xx systems to relocate from running at
+	 * the original location (0xfffffxxx) to somewhere else (SDRAM
+	 * preferably). This is because CS0 needs to be reconfigured for
+	 * NAND access. And we can't reconfigure this CS when currently
+	 * "running" from it.
+	 */
+
+	/*
+	 * Finally call nand_boot() to load main NAND U-Boot image from
+	 * NAND and jump to it.
+	 */
+	bl	nand_boot		/* will not return */
+#endif /* CONFIG_NAND_SPL */
diff --git a/arch/ppc/cpu/ppc4xx/tlb.c b/arch/ppc/cpu/ppc4xx/tlb.c
new file mode 100644
index 0000000..24a9a9c
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/tlb.c
@@ -0,0 +1,352 @@
+/*
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@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>
+
+#if defined(CONFIG_440)
+
+#include <ppc440.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+
+typedef struct region {
+	u64 base;
+	u32 size;
+	u32 tlb_word2_i_value;
+} region_t;
+
+void remove_tlb(u32 vaddr, u32 size)
+{
+	int i;
+	u32 tlb_word0_value;
+	u32 tlb_vaddr;
+	u32 tlb_size = 0;
+
+	for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+		tlb_word0_value = mftlb1(i);
+		tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value);
+		if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) &&
+		    (tlb_vaddr >= vaddr)) {
+			/*
+			 * TLB is enabled and start address is lower or equal
+			 * than the area we are looking for. Now we only have
+			 * to check the size/end address for a match.
+			 */
+			switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) {
+			case TLB_WORD0_SIZE_1KB:
+				tlb_size = 1 << 10;
+				break;
+			case TLB_WORD0_SIZE_4KB:
+				tlb_size = 4 << 10;
+				break;
+			case TLB_WORD0_SIZE_16KB:
+				tlb_size = 16 << 10;
+				break;
+			case TLB_WORD0_SIZE_64KB:
+				tlb_size = 64 << 10;
+				break;
+			case TLB_WORD0_SIZE_256KB:
+				tlb_size = 256 << 10;
+				break;
+			case TLB_WORD0_SIZE_1MB:
+				tlb_size = 1 << 20;
+				break;
+			case TLB_WORD0_SIZE_16MB:
+				tlb_size = 16 << 20;
+				break;
+			case TLB_WORD0_SIZE_256MB:
+				tlb_size = 256 << 20;
+				break;
+			}
+
+			/*
+			 * Now check the end-address if it's in the range
+			 */
+			if ((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1))
+				/*
+				 * Found a TLB in the range.
+				 * Disable it by writing 0 to tlb0 word.
+				 */
+				mttlb1(i, 0);
+		}
+	}
+
+	/* Execute an ISYNC instruction so that the new TLB entry takes effect */
+	asm("isync");
+}
+
+/*
+ * Change the I attribute (cache inhibited) of a TLB or multiple TLB's.
+ * This function is used to either turn cache on or off in a specific
+ * memory area.
+ */
+void change_tlb(u32 vaddr, u32 size, u32 tlb_word2_i_value)
+{
+	int i;
+	u32 tlb_word0_value;
+	u32 tlb_word2_value;
+	u32 tlb_vaddr;
+	u32 tlb_size = 0;
+
+	for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+		tlb_word0_value = mftlb1(i);
+		tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value);
+		if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) &&
+		    (tlb_vaddr >= vaddr)) {
+			/*
+			 * TLB is enabled and start address is lower or equal
+			 * than the area we are looking for. Now we only have
+			 * to check the size/end address for a match.
+			 */
+			switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) {
+			case TLB_WORD0_SIZE_1KB:
+				tlb_size = 1 << 10;
+				break;
+			case TLB_WORD0_SIZE_4KB:
+				tlb_size = 4 << 10;
+				break;
+			case TLB_WORD0_SIZE_16KB:
+				tlb_size = 16 << 10;
+				break;
+			case TLB_WORD0_SIZE_64KB:
+				tlb_size = 64 << 10;
+				break;
+			case TLB_WORD0_SIZE_256KB:
+				tlb_size = 256 << 10;
+				break;
+			case TLB_WORD0_SIZE_1MB:
+				tlb_size = 1 << 20;
+				break;
+			case TLB_WORD0_SIZE_16MB:
+				tlb_size = 16 << 20;
+				break;
+			case TLB_WORD0_SIZE_256MB:
+				tlb_size = 256 << 20;
+				break;
+			}
+
+			/*
+			 * Now check the end-address if it's in the range
+			 */
+			if (((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1)) ||
+			    ((tlb_vaddr < (vaddr + size - 1)) &&
+			     ((tlb_vaddr + tlb_size - 1) > (vaddr + size - 1)))) {
+				/*
+				 * Found a TLB in the range.
+				 * Change cache attribute in tlb2 word.
+				 */
+				tlb_word2_value =
+					TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
+					TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
+					TLB_WORD2_W_DISABLE | tlb_word2_i_value |
+					TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
+					TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
+					TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
+					TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
+					TLB_WORD2_SR_ENABLE;
+
+				/*
+				 * Now either flush or invalidate the dcache
+				 */
+				if (tlb_word2_i_value)
+					flush_dcache();
+				else
+					invalidate_dcache();
+
+				mttlb3(i, tlb_word2_value);
+				asm("iccci 0,0");
+			}
+		}
+	}
+
+	/* Execute an ISYNC instruction so that the new TLB entry takes effect */
+	asm("isync");
+}
+
+static int add_tlb_entry(u64 phys_addr,
+			 u32 virt_addr,
+			 u32 tlb_word0_size_value,
+			 u32 tlb_word2_i_value)
+{
+	int i;
+	unsigned long tlb_word0_value;
+	unsigned long tlb_word1_value;
+	unsigned long tlb_word2_value;
+
+	/* First, find the index of a TLB entry not being used */
+	for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+		tlb_word0_value = mftlb1(i);
+		if ((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_DISABLE)
+			break;
+	}
+	if (i >= PPC4XX_TLB_SIZE)
+		return -1;
+
+	/* Second, create the TLB entry */
+	tlb_word0_value = TLB_WORD0_EPN_ENCODE(virt_addr) | TLB_WORD0_V_ENABLE |
+		TLB_WORD0_TS_0 | tlb_word0_size_value;
+	tlb_word1_value = TLB_WORD1_RPN_ENCODE((u32)phys_addr) |
+		TLB_WORD1_ERPN_ENCODE(phys_addr >> 32);
+	tlb_word2_value = TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
+		TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
+		TLB_WORD2_W_DISABLE | tlb_word2_i_value |
+		TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
+		TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
+		TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
+		TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
+		TLB_WORD2_SR_ENABLE;
+
+	/* Wait for all memory accesses to complete */
+	sync();
+
+	/* Third, add the TLB entries */
+	mttlb1(i, tlb_word0_value);
+	mttlb2(i, tlb_word1_value);
+	mttlb3(i, tlb_word2_value);
+
+	/* Execute an ISYNC instruction so that the new TLB entry takes effect */
+	asm("isync");
+
+	return 0;
+}
+
+static void program_tlb_addr(u64 phys_addr,
+			     u32 virt_addr,
+			     u32 mem_size,
+			     u32 tlb_word2_i_value)
+{
+	int rc;
+	int tlb_i;
+
+	tlb_i = tlb_word2_i_value;
+	while (mem_size != 0) {
+		rc = 0;
+		/* Add the TLB entries in to map the region. */
+		if (((phys_addr & TLB_256MB_ALIGN_MASK) == phys_addr) &&
+		    (mem_size >= TLB_256MB_SIZE)) {
+			/* Add a 256MB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_256MB, tlb_i)) == 0) {
+				mem_size -= TLB_256MB_SIZE;
+				phys_addr += TLB_256MB_SIZE;
+				virt_addr += TLB_256MB_SIZE;
+			}
+		} else if (((phys_addr & TLB_16MB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_16MB_SIZE)) {
+			/* Add a 16MB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_16MB, tlb_i)) == 0) {
+				mem_size -= TLB_16MB_SIZE;
+				phys_addr += TLB_16MB_SIZE;
+				virt_addr += TLB_16MB_SIZE;
+			}
+		} else if (((phys_addr & TLB_1MB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_1MB_SIZE)) {
+			/* Add a 1MB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_1MB, tlb_i)) == 0) {
+				mem_size -= TLB_1MB_SIZE;
+				phys_addr += TLB_1MB_SIZE;
+				virt_addr += TLB_1MB_SIZE;
+			}
+		} else if (((phys_addr & TLB_256KB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_256KB_SIZE)) {
+			/* Add a 256KB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_256KB, tlb_i)) == 0) {
+				mem_size -= TLB_256KB_SIZE;
+				phys_addr += TLB_256KB_SIZE;
+				virt_addr += TLB_256KB_SIZE;
+			}
+		} else if (((phys_addr & TLB_64KB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_64KB_SIZE)) {
+			/* Add a 64KB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_64KB, tlb_i)) == 0) {
+				mem_size -= TLB_64KB_SIZE;
+				phys_addr += TLB_64KB_SIZE;
+				virt_addr += TLB_64KB_SIZE;
+			}
+		} else if (((phys_addr & TLB_16KB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_16KB_SIZE)) {
+			/* Add a 16KB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_16KB, tlb_i)) == 0) {
+				mem_size -= TLB_16KB_SIZE;
+				phys_addr += TLB_16KB_SIZE;
+				virt_addr += TLB_16KB_SIZE;
+			}
+		} else if (((phys_addr & TLB_4KB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_4KB_SIZE)) {
+			/* Add a 4KB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_4KB, tlb_i)) == 0) {
+				mem_size -= TLB_4KB_SIZE;
+				phys_addr += TLB_4KB_SIZE;
+				virt_addr += TLB_4KB_SIZE;
+			}
+		} else if (((phys_addr & TLB_1KB_ALIGN_MASK) == phys_addr) &&
+			   (mem_size >= TLB_1KB_SIZE)) {
+			/* Add a 1KB TLB entry */
+			if ((rc = add_tlb_entry(phys_addr, virt_addr,
+						TLB_WORD0_SIZE_1KB, tlb_i)) == 0) {
+				mem_size -= TLB_1KB_SIZE;
+				phys_addr += TLB_1KB_SIZE;
+				virt_addr += TLB_1KB_SIZE;
+			}
+		} else {
+			printf("ERROR: no TLB size exists for the base address 0x%llx.\n",
+				phys_addr);
+		}
+
+		if (rc != 0)
+			printf("ERROR: no TLB entries available for the base addr 0x%llx.\n",
+				phys_addr);
+	}
+
+	return;
+}
+
+/*
+ * Program one (or multiple) TLB entries for one memory region
+ *
+ * Common usage for boards with SDRAM DIMM modules to dynamically
+ * configure the TLB's for the SDRAM
+ */
+void program_tlb(u64 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value)
+{
+	region_t region_array;
+
+	region_array.base = phys_addr;
+	region_array.size = size;
+	region_array.tlb_word2_i_value = tlb_word2_i_value;	/* en-/disable cache */
+
+	/* Call the routine to add in the tlb entries for the memory regions */
+	program_tlb_addr(region_array.base, virt_addr, region_array.size,
+			 region_array.tlb_word2_i_value);
+
+	return;
+}
+
+#endif /* CONFIG_440 */
diff --git a/arch/ppc/cpu/ppc4xx/traps.c b/arch/ppc/cpu/ppc4xx/traps.c
new file mode 100644
index 0000000..42e4221
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/traps.c
@@ -0,0 +1,409 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+ */
+#define END_OF_MEM	(gd->bd->bi_memstart + gd->bd->bi_memsize)
+
+static __inline__ void set_tsr(unsigned long val)
+{
+#if defined(CONFIG_440)
+	asm volatile("mtspr 0x150, %0" : : "r" (val));
+#else
+	asm volatile("mttsr %0" : : "r" (val));
+#endif
+}
+
+static __inline__ unsigned long get_esr(void)
+{
+	unsigned long val;
+
+#if defined(CONFIG_440)
+	asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+#else
+	asm volatile("mfesr %0" : "=r" (val) :);
+#endif
+	return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf("Call backtrace: ");
+	while (sp) {
+		if ((uint)sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf("\n");
+		printf("%08lX ", i);
+		if (cnt > 32) break;
+		sp = (unsigned long *)*sp;
+	}
+	printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DEAR: %08lX\n",
+	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+
+	printf("\n");
+	for (i = 0;  i < 32;  i++) {
+		if ((i % 8) == 0) {
+			printf("GPR%02d: ", i);
+		}
+
+		printf("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			printf("\n");
+		}
+	}
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception");
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup, val;
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+	u32 value2;
+	int corr_ecc = 0;
+	int uncorr_ecc = 0;
+#endif
+
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		val = mfspr(MCSR);
+		/* Clear MCSR */
+		mtspr(SPRN_MCSR, val);
+		return;
+	}
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Machine Check Exception.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ", regs);
+
+	val = get_esr();
+
+#if !defined(CONFIG_440) && !defined(CONFIG_405EX)
+	if (val& ESR_IMCP) {
+		printf("Instruction");
+		mtspr(ESR, val & ~ESR_IMCP);
+	} else {
+		printf("Data");
+	}
+	printf(" machine check.\n");
+
+#elif defined(CONFIG_440) || defined(CONFIG_405EX)
+	if (val& ESR_IMCP){
+		printf("Instruction Synchronous Machine Check exception\n");
+		mtspr(SPRN_ESR, val & ~ESR_IMCP);
+	} else {
+		val = mfspr(MCSR);
+		if (val & MCSR_IB)
+			printf("Instruction Read PLB Error\n");
+#if defined(CONFIG_440)
+		if (val & MCSR_DRB)
+			printf("Data Read PLB Error\n");
+		if (val & MCSR_DWB)
+			printf("Data Write PLB Error\n");
+#else
+		if (val & MCSR_DB)
+			printf("Data PLB Error\n");
+#endif
+		if (val & MCSR_TLBP)
+			printf("TLB Parity Error\n");
+		if (val & MCSR_ICP){
+			/*flush_instruction_cache(); */
+			printf("I-Cache Parity Error\n");
+		}
+		if (val & MCSR_DCSP)
+			printf("D-Cache Search Parity Error\n");
+		if (val & MCSR_DCFP)
+			printf("D-Cache Flush Parity Error\n");
+		if (val & MCSR_IMPE)
+			printf("Machine Check exception is imprecise\n");
+
+		/* Clear MCSR */
+		mtspr(SPRN_MCSR, val);
+	}
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+	mfsdram(DDR0_00, val) ;
+	printf("DDR0: DDR0_00 %lx\n", val);
+	val = (val >> 16) & 0xff;
+	if (val & 0x80)
+		printf("DDR0: At least one interrupt active\n");
+	if (val & 0x40)
+		printf("DDR0: DRAM initialization complete.\n");
+	if (val & 0x20) {
+		printf("DDR0: Multiple uncorrectable ECC events.\n");
+		uncorr_ecc = 1;
+	}
+	if (val & 0x10) {
+		printf("DDR0: Single uncorrectable ECC event.\n");
+		uncorr_ecc = 1;
+	}
+	if (val & 0x08) {
+		printf("DDR0: Multiple correctable ECC events.\n");
+		corr_ecc = 1;
+	}
+	if (val & 0x04) {
+		printf("DDR0: Single correctable ECC event.\n");
+		corr_ecc = 1;
+	}
+	if (val & 0x02)
+		printf("Multiple accesses outside the defined"
+		       " physical memory space detected\n");
+	if (val & 0x01)
+		printf("DDR0: Single access outside the defined"
+		       " physical memory space detected.\n");
+
+	mfsdram(DDR0_01, val);
+	val = (val >> 8) & 0x7;
+	switch (val ) {
+	case 0:
+		printf("DDR0: Write Out-of-Range command\n");
+		break;
+	case 1:
+		printf("DDR0: Read Out-of-Range command\n");
+		break;
+	case 2:
+		printf("DDR0: Masked write Out-of-Range command\n");
+		break;
+	case 4:
+		printf("DDR0: Wrap write Out-of-Range command\n");
+		break;
+	case 5:
+		printf("DDR0: Wrap read Out-of-Range command\n");
+		break;
+	default:
+		mfsdram(DDR0_01, value2);
+		printf("DDR0: No DDR0 error know 0x%lx %x\n", val, value2);
+	}
+	mfsdram(DDR0_23, val);
+	if (((val >> 16) & 0xff) && corr_ecc)
+		printf("DDR0: Syndrome for correctable ECC event 0x%lx\n",
+		       (val >> 16) & 0xff);
+	mfsdram(DDR0_23, val);
+	if (((val >> 8) & 0xff) && uncorr_ecc)
+		printf("DDR0: Syndrome for uncorrectable ECC event 0x%lx\n",
+		       (val >> 8) & 0xff);
+	mfsdram(DDR0_33, val);
+	if (val)
+		printf("DDR0: Address of command that caused an "
+		       "Out-of-Range interrupt %lx\n", val);
+	mfsdram(DDR0_34, val);
+	if (val && uncorr_ecc)
+		printf("DDR0: Address of uncorrectable ECC event %lx\n", val);
+	mfsdram(DDR0_35, val);
+	if (val && uncorr_ecc)
+		printf("DDR0: Address of uncorrectable ECC event %lx\n", val);
+	mfsdram(DDR0_36, val);
+	if (val && uncorr_ecc)
+		printf("DDR0: Data of uncorrectable ECC event 0x%08lx\n", val);
+	mfsdram(DDR0_37, val);
+	if (val && uncorr_ecc)
+		printf("DDR0: Data of uncorrectable ECC event 0x%08lx\n", val);
+	mfsdram(DDR0_38, val);
+	if (val && corr_ecc)
+		printf("DDR0: Address of correctable ECC event %lx\n", val);
+	mfsdram(DDR0_39, val);
+	if (val && corr_ecc)
+		printf("DDR0: Address of correctable ECC event %lx\n", val);
+	mfsdram(DDR0_40, val);
+	if (val && corr_ecc)
+		printf("DDR0: Data of correctable ECC event 0x%08lx\n", val);
+	mfsdram(DDR0_41, val);
+	if (val && corr_ecc)
+		printf("DDR0: Data of correctable ECC event 0x%08lx\n", val);
+#endif /* CONFIG_440EPX */
+#endif /* CONFIG_440 */
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	long esr_val;
+
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	show_regs(regs);
+
+	esr_val = get_esr();
+	if( esr_val & ESR_PIL )
+		printf( "** Illegal Instruction **\n" );
+	else if( esr_val & ESR_PPR )
+		printf( "** Privileged Instruction **\n" );
+	else if( esr_val & ESR_PTR )
+		printf( "** Trap Instruction **\n" );
+
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void
+DecrementerPITException(struct pt_regs *regs)
+{
+	/*
+	 * Reset PIT interrupt
+	 */
+	set_tsr(0x08000000);
+
+	/*
+	 * Call timer_interrupt routine in interrupts.c
+	 */
+	timer_interrupt(NULL);
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+		return;
+#endif
+
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+	printf("Debugger trap at @ %lx\n", regs->nip );
+	show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+	do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/ppc/cpu/ppc4xx/u-boot.lds b/arch/ppc/cpu/ppc4xx/u-boot.lds
new file mode 100644
index 0000000..3704d8a
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/u-boot.lds
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "config.h"	/* CONFIG_BOARDDIR */
+
+#ifndef RESET_VECTOR_ADDRESS
+#define RESET_VECTOR_ADDRESS	0xfffffffc
+#endif
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+PHDRS
+{
+  text PT_LOAD;
+  bss PT_LOAD;
+}
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text)	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data)	}
+  .rel.rodata    : { *(.rel.rodata)	}
+  .rela.rodata   : { *(.rela.rodata)	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.got1)
+   } :text
+    _etext = .;
+    PROVIDE (etext = .);
+    .rodata    :
+   {
+    *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+  } :text
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x00FF) & 0xFFFFFF00;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  . = .;
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+  . = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(256);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(256);
+  __init_end = .;
+
+#ifdef CONFIG_440
+  .bootpg RESET_VECTOR_ADDRESS - 0xffc :
+  {
+    arch/ppc/cpu/ppc4xx/start.o	(.bootpg)
+
+    /*
+     * PPC440 board need a board specific object with the
+     * TLB definitions. This needs to get included right after
+     * start.o, since the first shadow TLB only covers 4k
+     * of address space.
+     */
+    CONFIG_BOARDDIR/init.o	(.bootpg)
+  } :text = 0xffff
+#endif
+
+  .resetvec RESET_VECTOR_ADDRESS :
+  {
+    *(.resetvec)
+  } :text = 0xffff
+
+  . = RESET_VECTOR_ADDRESS + 0x4;
+
+  /*
+   * Make sure that the bss segment isn't linked at 0x0, otherwise its
+   * address won't be updated during relocation fixups.  Note that
+   * this is a temporary fix.  Code to dynamically the fixup the bss
+   * location will be added in the future.  When the bss relocation
+   * fixup code is present this workaround should be removed.
+   */
+#if (RESET_VECTOR_ADDRESS == 0xfffffffc)
+  . |= 0x10;
+#endif
+
+  __bss_start = .;
+  .bss (NOLOAD)       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  } :bss
+
+  . = ALIGN(4);
+  _end = . ;
+  PROVIDE (end = .);
+}
diff --git a/arch/ppc/cpu/ppc4xx/uic.c b/arch/ppc/cpu/ppc4xx/uic.c
new file mode 100644
index 0000000..8b1b259
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/uic.c
@@ -0,0 +1,180 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 (440GX port)
+ * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
+ *
+ * (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
+ * Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@uam.es
+ * Work supported by Qtechnology (htpp://qtec.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/interrupt.h>
+#include <ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+
+#if (UIC_MAX > 3)
+#define UICB0_ALL	(UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
+			 UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI) | \
+			 UIC_MASK(VECNUM_UIC3CI) | UIC_MASK(VECNUM_UIC3NCI))
+#elif (UIC_MAX > 2)
+#define UICB0_ALL	(UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
+			 UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI))
+#elif (UIC_MAX > 1)
+#define UICB0_ALL	(UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI))
+#else
+#define UICB0_ALL	0
+#endif
+
+u32 get_dcr(u16);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void pic_enable(void)
+{
+#if (UIC_MAX > 1)
+	/* Install the UIC1 handlers */
+	irq_install_handler(VECNUM_UIC1NCI, (void *)(void *)external_interrupt, 0);
+	irq_install_handler(VECNUM_UIC1CI, (void *)(void *)external_interrupt, 0);
+#endif
+#if (UIC_MAX > 2)
+	irq_install_handler(VECNUM_UIC2NCI, (void *)(void *)external_interrupt, 0);
+	irq_install_handler(VECNUM_UIC2CI, (void *)(void *)external_interrupt, 0);
+#endif
+#if (UIC_MAX > 3)
+	irq_install_handler(VECNUM_UIC3NCI, (void *)(void *)external_interrupt, 0);
+	irq_install_handler(VECNUM_UIC3CI, (void *)(void *)external_interrupt, 0);
+#endif
+}
+
+/* Handler for UIC interrupt */
+static void uic_interrupt(u32 uic_base, int vec_base)
+{
+	u32 uic_msr;
+	u32 msr_shift;
+	int vec;
+
+	/*
+	 * Read masked interrupt status register to determine interrupt source
+	 */
+	uic_msr = get_dcr(uic_base + UIC_MSR);
+	msr_shift = uic_msr;
+	vec = vec_base;
+
+	while (msr_shift != 0) {
+		if (msr_shift & 0x80000000)
+			interrupt_run_handler(vec);
+		/*
+		 * Shift msr to next position and increment vector
+		 */
+		msr_shift <<= 1;
+		vec++;
+	}
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+	u32 uic_msr;
+
+	/*
+	 * Read masked interrupt status register to determine interrupt source
+	 */
+	uic_msr = mfdcr(UIC0MSR);
+
+#if (UIC_MAX > 1)
+	if ((UIC_MASK(VECNUM_UIC1CI) & uic_msr) ||
+	    (UIC_MASK(VECNUM_UIC1NCI) & uic_msr))
+		uic_interrupt(UIC1_DCR_BASE, 32);
+#endif
+
+#if (UIC_MAX > 2)
+	if ((UIC_MASK(VECNUM_UIC2CI) & uic_msr) ||
+	    (UIC_MASK(VECNUM_UIC2NCI) & uic_msr))
+		uic_interrupt(UIC2_DCR_BASE, 64);
+#endif
+
+#if (UIC_MAX > 3)
+	if ((UIC_MASK(VECNUM_UIC3CI) & uic_msr) ||
+	    (UIC_MASK(VECNUM_UIC3NCI) & uic_msr))
+		uic_interrupt(UIC3_DCR_BASE, 96);
+#endif
+
+	mtdcr(UIC0SR, (uic_msr & UICB0_ALL));
+
+	if (uic_msr & ~(UICB0_ALL))
+		uic_interrupt(UIC0_DCR_BASE, 0);
+
+	return;
+}
+
+void pic_irq_ack(unsigned int vec)
+{
+	if ((vec >= 0) && (vec < 32))
+		mtdcr(UIC0SR, UIC_MASK(vec));
+	else if ((vec >= 32) && (vec < 64))
+		mtdcr(UIC1SR, UIC_MASK(vec));
+	else if ((vec >= 64) && (vec < 96))
+		mtdcr(UIC2SR, UIC_MASK(vec));
+	else if (vec >= 96)
+		mtdcr(UIC3SR, UIC_MASK(vec));
+}
+
+/*
+ * Install and free a interrupt handler.
+ */
+void pic_irq_enable(unsigned int vec)
+{
+
+	if ((vec >= 0) && (vec < 32))
+		mtdcr(UIC0ER, mfdcr(UIC0ER) | UIC_MASK(vec));
+	else if ((vec >= 32) && (vec < 64))
+		mtdcr(UIC1ER, mfdcr(UIC1ER) | UIC_MASK(vec));
+	else if ((vec >= 64) && (vec < 96))
+		mtdcr(UIC2ER, mfdcr(UIC2ER) | UIC_MASK(vec));
+	else if (vec >= 96)
+		mtdcr(UIC3ER, mfdcr(UIC3ER) | UIC_MASK(vec));
+
+	debug("Install interrupt vector %d\n", vec);
+}
+
+void pic_irq_disable(unsigned int vec)
+{
+	if ((vec >= 0) && (vec < 32))
+		mtdcr(UIC0ER, mfdcr(UIC0ER) & ~UIC_MASK(vec));
+	else if ((vec >= 32) && (vec < 64))
+		mtdcr(UIC1ER, mfdcr(UIC1ER) & ~UIC_MASK(vec));
+	else if ((vec >= 64) && (vec < 96))
+		mtdcr(UIC2ER, mfdcr(UIC2ER) & ~UIC_MASK(vec));
+	else if (vec >= 96)
+		mtdcr(UIC3ER, mfdcr(UIC3ER) & ~UIC_MASK(vec));
+}
diff --git a/arch/ppc/cpu/ppc4xx/usb.c b/arch/ppc/cpu/ppc4xx/usb.c
new file mode 100644
index 0000000..592efe7
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/usb.c
@@ -0,0 +1,66 @@
+/*
+ * (C) Copyright 2007
+ * Markus Klotzbuecher, DENX Software Engineering <mk@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>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+
+#ifdef CONFIG_4xx_DCACHE
+#include <asm/mmu.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#include "usbdev.h"
+
+int usb_cpu_init(void)
+{
+#ifdef CONFIG_4xx_DCACHE
+	/* disable cache */
+	change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, TLB_WORD2_I_ENABLE);
+#endif
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX)
+	usb_dev_init();
+#endif
+	return 0;
+}
+
+int usb_cpu_stop(void)
+{
+#ifdef CONFIG_4xx_DCACHE
+	/* enable cache */
+	change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, 0);
+#endif
+	return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+#ifdef CONFIG_4xx_DCACHE
+	/* enable cache */
+	change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, 0);
+#endif
+	return 0;
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
diff --git a/arch/ppc/cpu/ppc4xx/usb_ohci.c b/arch/ppc/cpu/ppc4xx/usb_ohci.c
new file mode 100644
index 0000000..a9edacd
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/usb_ohci.c
@@ -0,0 +1,1648 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the PPC440EP.
+ *
+ * (C) Copyright 2003-2004
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * 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
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - this driver is intended for use with USB Mass Storage Devices
+ *     (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#include "usbdev.h"
+
+#define OHCI_USE_NPS		/* force NoPowerSwitching mode */
+#undef OHCI_VERBOSE_DEBUG	/* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define readl(a) (*((volatile u32 *)(a)))
+#define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#define m16_swap(x) swap_16(x)
+#define m32_swap(x) swap_32(x)
+
+#if defined(CONFIG_405EZ) || defined(CONFIG_440EP) || defined(CONFIG_440EPX)
+#define ohci_cpu_to_le16(x) (x)
+#define ohci_cpu_to_le32(x) (x)
+#else
+#define ohci_cpu_to_le16(x) swap_16(x)
+#define ohci_cpu_to_le32(x) swap_32(x)
+#endif
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* urb_priv */
+urb_priv_t urb_priv;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+	u32 temp = readl (&hc->regs->roothub.register); \
+	if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = readl (&hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+	int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+	int		i;
+	int		last;
+	struct td	* td;
+
+	last = urb->length - 1;
+	if (last >= 0) {
+		for (i = 0; i <= last; i++) {
+			td = urb->td[i];
+			if (td) {
+				td->usb_dev = NULL;
+				urb->td[i] = NULL;
+			}
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
+	int transfer_len, struct devrequest * setup, char * str, int small)
+{
+	urb_priv_t * purb = &urb_priv;
+
+	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+			str,
+			sohci_get_current_frame_number (dev),
+			usb_pipedevice (pipe),
+			usb_pipeendpoint (pipe),
+			usb_pipeout (pipe)? 'O': 'I',
+			usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+				(usb_pipecontrol (pipe)? "CTRL": "BULK"),
+			purb->actual_length,
+			transfer_len, dev->status);
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printf (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++)
+				printf (" %02x", ((__u8 *) setup) [i]);
+			printf ("\n");
+		}
+		if (transfer_len > 0 && buffer) {
+			printf (__FILE__ ": data(%d/%d):",
+				purb->actual_length,
+				transfer_len);
+			len = usb_pipeout (pipe)?
+					transfer_len: purb->actual_length;
+			for (i = 0; i < 16 && i < len; i++)
+				printf (" %02x", ((__u8 *) buffer) [i]);
+			printf ("%s\n", i < len? "...": "");
+		}
+	}
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+	int i, j;
+	 __u32 * ed_p;
+	for (i= 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+		while (*ed_p != 0 && j--) {
+			ed_t *ed = (ed_t *)ohci_cpu_to_le32(ed_p);
+			printf (" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printf ("\n");
+	}
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	ed_t *edp = (ed_t *)value;
+
+	if (value) {
+		dbg ("%s %08x", label, value);
+		dbg ("%08x", edp->hwINFO);
+		dbg ("%08x", edp->hwTailP);
+		dbg ("%08x", edp->hwHeadP);
+		dbg ("%08x", edp->hwNextED);
+	}
+}
+
+static char * hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+	__u32			temp, ndp, i;
+
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = roothub_b (controller);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status (controller);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+	dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+	/* dumps some of the state we know about */
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	ohci_dump_roothub (controller, 1);
+}
+
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup, int interval)
+{
+	ohci_t *ohci;
+	ed_t * ed;
+	urb_priv_t *purb_priv;
+	int i, size = 0;
+
+	ohci = &gohci;
+
+	/* when controller's hung, permit only roothub cleanup attempts
+	 * such as powering down ports */
+	if (ohci->disabled) {
+		err("sohci_submit_job: EPIPE");
+		return -1;
+	}
+
+	/* if we have an unfinished URB from previous transaction let's
+	 * fail and scream as quickly as possible so as not to corrupt
+	 * further communication */
+	if (!urb_finished) {
+		err("sohci_submit_job: URB NOT FINISHED");
+		return -1;
+	}
+	/* we're about to begin a new transaction here so mark the URB unfinished */
+	urb_finished = 0;
+
+	/* every endpoint has a ed, locate and fill it */
+	if (!(ed = ep_add_ed (dev, pipe))) {
+		err("sohci_submit_job: ENOMEM");
+		return -1;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_BULK: /* one TD for every 4096 Byte */
+			size = (transfer_len - 1) / 4096 + 1;
+			break;
+		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+			size = (transfer_len == 0)? 2:
+						(transfer_len - 1) / 4096 + 3;
+			break;
+	}
+
+	if (size >= (N_URB_TD - 1)) {
+		err("need %d TDs, only have %d", size, N_URB_TD);
+		return -1;
+	}
+	purb_priv = &urb_priv;
+	purb_priv->pipe = pipe;
+
+	/* fill the private part of the URB */
+	purb_priv->length = size;
+	purb_priv->ed = ed;
+	purb_priv->actual_length = 0;
+
+	/* allocate the TDs */
+	/* note that td[0] was allocated in ep_add_ed */
+	for (i = 0; i < size; i++) {
+		purb_priv->td[i] = td_alloc (dev);
+		if (!purb_priv->td[i]) {
+			purb_priv->length = i;
+			urb_free_priv (purb_priv);
+			err("sohci_submit_job: ENOMEM");
+			return -1;
+		}
+	}
+
+	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_free_priv (purb_priv);
+		err("sohci_submit_job: EINVAL");
+		return -1;
+	}
+
+	/* link the ed into a chain if is not already */
+	if (ed->state != ED_OPER)
+		ep_link (ohci, ed);
+
+	/* fill the TDs and link it to the ed */
+	td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	ohci_t *ohci = &gohci;
+
+	return ohci_cpu_to_le16 (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+
+	ed->state = ED_OPER;
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+		if (ohci->ed_controltail == NULL) {
+			writel (ed, &ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_controltail = edi;
+		break;
+
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+		if (ohci->ed_bulktail == NULL) {
+			writel (ed, &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_bulktail = edi;
+		break;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+
+	ed->hwINFO |= ohci_cpu_to_le32 (OHCI_ED_SKIP);
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless	so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
+{
+	td_t *td;
+	ed_t *ed_ret;
+	volatile ed_t *ed;
+
+	ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+		err("ep_add_ed: pending delete");
+		/* pending delete request */
+		return NULL;
+	}
+
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = ohci_cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+		/* dummy td; end of td list for ed */
+		td = td_alloc (usb_dev);
+		ed->hwTailP = ohci_cpu_to_le32 ((unsigned long)td);
+		ed->hwHeadP = ed->hwTailP;
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+		ohci_dev.ed_cnt++;
+	}
+
+	ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+			| usb_pipeslow (pipe) << 13
+			| usb_maxpacket (usb_dev, pipe) << 16);
+
+	return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+	void *data, int len,
+	struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+	volatile td_t  *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+	int i;
+#endif
+
+	if (index > urb_priv->length) {
+		err("index > length");
+		return;
+	}
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = (td_t *)(ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf);
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+	if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
+		for (i = 0; i < len; i++)
+		printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+		printf("\n");
+	}
+#endif
+	if (!len)
+		data = 0;
+
+	td->hwINFO = ohci_cpu_to_le32 (info);
+	td->hwCBP = ohci_cpu_to_le32 ((unsigned long)data);
+	if (data)
+		td->hwBE = ohci_cpu_to_le32 ((unsigned long)(data + len - 1));
+	else
+		td->hwBE = 0;
+	td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
+
+	/* append to queue */
+	td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+	int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+	ohci_t *ohci = &gohci;
+	int data_len = transfer_len;
+	void *data;
+	int cnt = 0;
+	__u32 info = 0;
+	unsigned int toggle = 0;
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+	if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+		toggle = TD_T_TOGGLE;
+	} else {
+		toggle = TD_T_DATA0;
+		usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+	}
+	urb->td_cnt = 0;
+	if (data_len)
+		data = buffer;
+	else
+		data = 0;
+
+	switch (usb_pipetype (pipe)) {
+	case PIPE_BULK:
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+		while(data_len > 4096) {
+			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+			data += 4096; data_len -= 4096; cnt++;
+		}
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+		td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+		cnt++;
+
+		if (!ohci->sleeping)
+			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+		break;
+
+	case PIPE_CONTROL:
+		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+		if (data_len > 0) {
+			info = usb_pipeout (pipe)?
+				TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+			/* NOTE:  mishandles transfers >8K, some >4K */
+			td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+		}
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+		td_fill (ohci, info, data, 0, dev, cnt++, urb);
+		if (!ohci->sleeping)
+			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+		break;
+	}
+	if (urb->length != cnt)
+		dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+	__u32 tdINFO, tdBE, tdCBP;
+	urb_priv_t *lurb_priv = &urb_priv;
+
+	tdINFO = ohci_cpu_to_le32 (td->hwINFO);
+	tdBE   = ohci_cpu_to_le32 (td->hwBE);
+	tdCBP  = ohci_cpu_to_le32 (td->hwCBP);
+
+
+	if (!(usb_pipecontrol(lurb_priv->pipe) &&
+	    ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+		if (tdBE != 0) {
+			if (td->hwCBP == 0)
+				lurb_priv->actual_length += tdBE - td->data + 1;
+			else
+				lurb_priv->actual_length += tdCBP - td->data;
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+	__u32 td_list_hc;
+	td_t *td_rev = NULL;
+	td_t *td_list = NULL;
+	urb_priv_t *lurb_priv = NULL;
+
+	td_list_hc = ohci_cpu_to_le32 (ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
+
+	while (td_list_hc) {
+		td_list = (td_t *)td_list_hc;
+
+		if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
+			lurb_priv = &urb_priv;
+			dbg(" USB-error/status: %x : %p",
+					TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
+			if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
+				if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+					td_list->ed->hwHeadP =
+						(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
+									(td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
+					lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+				} else
+					td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
+			}
+#ifdef CONFIG_MPC5200
+			td_list->hwNextTD = 0;
+#endif
+		}
+
+		td_list->next_dl_td = td_rev;
+		td_rev = td_list;
+		td_list_hc = ohci_cpu_to_le32 (td_list->hwNextTD) & 0xfffffff0;
+	}
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+	td_t *td_list_next = NULL;
+	ed_t *ed;
+	int cc = 0;
+	int stat = 0;
+	/* urb_t *urb; */
+	urb_priv_t *lurb_priv;
+	__u32 tdINFO, edHeadP, edTailP;
+
+	while (td_list) {
+		td_list_next = td_list->next_dl_td;
+
+		lurb_priv = &urb_priv;
+		tdINFO = ohci_cpu_to_le32 (td_list->hwINFO);
+
+		ed = td_list->ed;
+
+		dl_transfer_length(td_list);
+
+		/* error code of transfer */
+		cc = TD_CC_GET (tdINFO);
+		if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+			if ((ed->state & (ED_OPER | ED_UNLINK))
+					&& (lurb_priv->state != URB_DEL)) {
+				dbg("ConditionCode %#x", cc);
+				stat = cc_to_error[cc];
+				urb_finished = 1;
+			}
+		}
+
+		if (ed->state != ED_NEW) {
+			edHeadP = ohci_cpu_to_le32 (ed->hwHeadP) & 0xfffffff0;
+			edTailP = ohci_cpu_to_le32 (ed->hwTailP);
+
+			/* unlink eds if they are not busy */
+			if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+				ep_unlink (ohci, ed);
+		}
+
+		td_list = td_list_next;
+	}
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+	0x12,	    /*	__u8  bLength; */
+	0x01,	    /*	__u8  bDescriptorType; Device */
+	0x10,	    /*	__u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*	__u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  bDeviceSubClass; */
+	0x00,	    /*	__u8  bDeviceProtocol; */
+	0x08,	    /*	__u8  bMaxPacketSize0; 8 Bytes */
+	0x00,	    /*	__u16 idVendor; */
+	0x00,
+	0x00,	    /*	__u16 idProduct; */
+	0x00,
+	0x00,	    /*	__u16 bcdDevice; */
+	0x00,
+	0x00,	    /*	__u8  iManufacturer; */
+	0x01,	    /*	__u8  iProduct; */
+	0x00,	    /*	__u8  iSerialNumber; */
+	0x01	    /*	__u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,	    /*	__u8  bLength; */
+	0x02,	    /*	__u8  bDescriptorType; Configuration */
+	0x19,	    /*	__u16 wTotalLength; */
+	0x00,
+	0x01,	    /*	__u8  bNumInterfaces; */
+	0x01,	    /*	__u8  bConfigurationValue; */
+	0x00,	    /*	__u8  iConfiguration; */
+	0x40,	    /*	__u8  bmAttributes;
+		 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,	    /*	__u8  MaxPower; */
+
+	/* interface */
+	0x09,	    /*	__u8  if_bLength; */
+	0x04,	    /*	__u8  if_bDescriptorType; Interface */
+	0x00,	    /*	__u8  if_bInterfaceNumber; */
+	0x00,	    /*	__u8  if_bAlternateSetting; */
+	0x01,	    /*	__u8  if_bNumEndpoints; */
+	0x09,	    /*	__u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  if_bInterfaceSubClass; */
+	0x00,	    /*	__u8  if_bInterfaceProtocol; */
+	0x00,	    /*	__u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,	    /*	__u8  ep_bLength; */
+	0x05,	    /*	__u8  ep_bDescriptorType; Endpoint */
+	0x81,	    /*	__u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,	    /*	__u8  ep_bmAttributes; Interrupt */
+	0x02,	    /*	__u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff	    /*	__u8  ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+	0x04,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	0x09,			/*  __u8  lang ID */
+	0x04,			/*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+	28,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	'O',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'C',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'I',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'R',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	't',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'u',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'b',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x)			len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x)		{info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x)	{info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x)		writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x)	writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT		roothub_status(&gohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+	__u32 temp, ndp, i;
+	int res;
+
+	res = -1;
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		/* check for a device disconnect */
+		if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+			(RH_PS_PESC | RH_PS_CSC)) &&
+			((temp & RH_PS_CCS) == 0)) {
+			res = i;
+			break;
+		}
+	}
+	return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+		void *buffer, int transfer_len, struct devrequest *cmd)
+{
+	void * data = buffer;
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *)datab;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+#ifdef DEBUG
+urb_priv.actual_length = 0;
+pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#endif
+	if (usb_pipeint(pipe)) {
+		info("Root-Hub submit IRQ: NOT implemented");
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+	wValue	      = m16_swap (cmd->value);
+	wIndex	      = m16_swap (cmd->index);
+	wLength	      = m16_swap (cmd->length);
+
+	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device,
+	   RH_INTERFACE: interface,
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here,
+	   RH_OTHER | RH_CLASS	almost ever means HUB_PORT here
+	*/
+
+	case RH_GET_STATUS:
+			*(__u16 *) data_buf = m16_swap (1); OK (2);
+	case RH_GET_STATUS | RH_INTERFACE:
+			*(__u16 *) data_buf = m16_swap (0); OK (2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+			*(__u16 *) data_buf = m16_swap (0); OK (2);
+	case RH_GET_STATUS | RH_CLASS:
+			*(__u32 *) data_buf = m32_swap (
+				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+			OK (4);
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+			*(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+			case (RH_ENDPOINT_STALL): OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+			case RH_C_HUB_LOCAL_POWER:
+				OK(0);
+			case (RH_C_HUB_OVER_CURRENT):
+					WR_RH_STAT(RH_HS_OCIC); OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+			case (RH_PORT_ENABLE):
+					WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+			case (RH_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+			case (RH_PORT_POWER):
+					WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+			case (RH_C_PORT_CONNECTION):
+					WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+			case (RH_C_PORT_ENABLE):
+					WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+			case (RH_C_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+			case (RH_C_PORT_OVER_CURRENT):
+					WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+			case (RH_C_PORT_RESET):
+					WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+			case (RH_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+			case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+					if (RD_RH_PORTSTAT & RH_PS_CCS)
+					    WR_RH_PORTSTAT (RH_PS_PRS);
+					OK (0);
+			case (RH_PORT_POWER):
+					WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
+			case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+					if (RD_RH_PORTSTAT & RH_PS_CCS)
+					    WR_RH_PORTSTAT (RH_PS_PES );
+					OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+			case (0x01): /* device descriptor */
+				len = min_t(unsigned int,
+					  leni,
+					  min_t(unsigned int,
+					      sizeof (root_hub_dev_des),
+					      wLength));
+				data_buf = root_hub_dev_des; OK(len);
+			case (0x02): /* configuration descriptor */
+				len = min_t(unsigned int,
+					  leni,
+					  min_t(unsigned int,
+					      sizeof (root_hub_config_des),
+					      wLength));
+				data_buf = root_hub_config_des; OK(len);
+			case (0x03): /* string descriptors */
+				if(wValue==0x0300) {
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_str_index0),
+						      wLength));
+					data_buf = root_hub_str_index0;
+					OK(len);
+				}
+				if(wValue==0x0301) {
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_str_index1),
+						      wLength));
+					data_buf = root_hub_str_index1;
+					OK(len);
+			}
+			default:
+				stat = USB_ST_STALLED;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+	    {
+		    __u32 temp = roothub_a (&gohci);
+
+		    data_buf [0] = 9;		/* min length; */
+		    data_buf [1] = 0x29;
+		    data_buf [2] = temp & RH_A_NDP;
+		    data_buf [3] = 0;
+		    if (temp & RH_A_PSM)	/* per-port power switching? */
+			data_buf [3] |= 0x1;
+		    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+			data_buf [3] |= 0x10;
+		    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+			data_buf [3] |= 0x8;
+
+		    /* corresponds to data_buf[4-7] */
+		    datab [1] = 0;
+		    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+		    temp = roothub_b (&gohci);
+		    data_buf [7] = temp & RH_B_DR;
+		    if (data_buf [2] < 7) {
+			data_buf [8] = 0xff;
+		    } else {
+			data_buf [0] += 2;
+			data_buf [8] = (temp & RH_B_DR) >> 8;
+			data_buf [10] = data_buf [9] = 0xff;
+		    }
+
+		    len = min_t(unsigned int, leni,
+			      min_t(unsigned int, data_buf [0], wLength));
+		    OK (len);
+		}
+
+	case RH_GET_CONFIGURATION:	*(__u8 *) data_buf = 0x01; OK (1);
+
+	case RH_SET_CONFIGURATION:	WR_RH_STAT (0x10000); OK (0);
+
+	default:
+		dbg ("unsupported root hub command");
+		stat = USB_ST_STALLED;
+	}
+
+#ifdef	DEBUG
+	ohci_dump_roothub (&gohci, 1);
+#endif
+
+	len = min_t(int, len, leni);
+	if (data != data_buf)
+	    memcpy (data, data_buf, len);
+	dev->act_len = len;
+	dev->status = stat;
+
+#ifdef DEBUG
+	if (transfer_len)
+		urb_priv.actual_length = transfer_len;
+	pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#endif
+
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup, int interval)
+{
+	int stat = 0;
+	int maxsize = usb_maxpacket(dev, pipe);
+	int timeout;
+
+	/* device pulled? Shortcut the action. */
+	if (devgone == dev) {
+		dev->status = USB_ST_CRC_ERR;
+		return 0;
+	}
+
+#ifdef DEBUG
+	urb_priv.actual_length = 0;
+	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+	if (!maxsize) {
+		err("submit_common_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+
+	if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
+		err("sohci_submit_job failed");
+		return -1;
+	}
+
+	/* allow more time for a BULK device to react - some are slow */
+#define BULK_TO	 5000	/* timeout in milliseconds */
+	if (usb_pipebulk(pipe))
+		timeout = BULK_TO;
+	else
+		timeout = 100;
+
+	/* wait for it to complete */
+	for (;;) {
+		/* check whether the controller is done */
+		stat = hc_interrupt();
+		if (stat < 0) {
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+
+		/* NOTE: since we are not interrupt driven in U-Boot and always
+		 * handle only one URB at a time, we cannot assume the
+		 * transaction finished on the first successful return from
+		 * hc_interrupt().. unless the flag for current URB is set,
+		 * meaning that all TD's to/from device got actually
+		 * transferred and processed. If the current URB is not
+		 * finished we need to re-iterate this loop so as
+		 * hc_interrupt() gets called again as there needs to be some
+		 * more TD's to process still */
+		if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
+			/* 0xff is returned for an SF-interrupt */
+			break;
+		}
+
+		if (--timeout) {
+			wait_ms(1);
+			if (!urb_finished)
+				dbg("\%");
+
+		} else {
+			err("CTL:TIMEOUT ");
+			dbg("submit_common_msg: TO status %x\n", stat);
+			stat = USB_ST_CRC_ERR;
+			urb_finished = 1;
+			break;
+		}
+	}
+#if 0
+	/* we got an Root Hub Status Change interrupt */
+	if (got_rhsc) {
+#ifdef DEBUG
+		ohci_dump_roothub (&gohci, 1);
+#endif
+		got_rhsc = 0;
+		/* abuse timeout */
+		timeout = rh_check_port_status(&gohci);
+		if (timeout >= 0) {
+#if 0 /* this does nothing useful, but leave it here in case that changes */
+			/* the called routine adds 1 to the passed value */
+			usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
+#endif
+			/*
+			 * XXX
+			 * This is potentially dangerous because it assumes
+			 * that only one device is ever plugged in!
+			 */
+			devgone = dev;
+		}
+	}
+#endif
+
+	dev->status = stat;
+	dev->act_len = transfer_len;
+
+#ifdef DEBUG
+	pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#endif
+
+	/* free TDs in urb_priv */
+	urb_free_priv (&urb_priv);
+	return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len)
+{
+	info("submit_bulk_msg");
+	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup)
+{
+	int maxsize = usb_maxpacket(dev, pipe);
+
+	info("submit_control_msg");
+#ifdef DEBUG
+	urb_priv.actual_length = 0;
+	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+	if (!maxsize) {
+		err("submit_control_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+	if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+		gohci.rh.dev = dev;
+		/* root hub - redirect */
+		return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+			setup);
+	}
+
+	return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, int interval)
+{
+	info("submit_int_msg");
+	return -1;
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+		info("USB HC TakeOver from SMM");
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+			wait_ms (10);
+			if (--smm_timeout == 0) {
+				err("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}
+
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+		ohci->slot_name,
+		readl (&ohci->regs->control));
+
+	/* Reset USB (needed by some controllers) */
+	ohci->hc_control = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
+
+	/* HC Reset requires max 10 us delay */
+	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err("USB HC reset timed out!");
+			return -1;
+		}
+		udelay (1);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+	__u32 mask;
+	unsigned int fminterval;
+
+	ohci->disabled = 1;
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+
+	writel (0, &ohci->regs->ed_controlhead);
+	writel (0, &ohci->regs->ed_bulkhead);
+
+	writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+	fminterval = 0x2edf;
+	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+	writel (fminterval, &ohci->regs->fminterval);
+	writel (0x628, &ohci->regs->lsthresh);
+
+	/* start controller operations */
+	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ohci->disabled = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
+
+	/* disable all interrupts */
+	mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+			OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+			OHCI_INTR_OC | OHCI_INTR_MIE);
+	writel (mask, &ohci->regs->intrdisable);
+	/* clear all interrupts */
+	mask &= ~OHCI_INTR_MIE;
+	writel (mask, &ohci->regs->intrstatus);
+	/* Choose the interrupts we care about now  - but w/o MIE */
+	mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	writel (mask, &ohci->regs->intrenable);
+
+#ifdef	OHCI_USE_NPS
+	/* required for AMD-756 and some Mac platforms */
+	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+		&ohci->regs->roothub.a);
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif	/* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+	/* POTPGT delay is bits 24-31, in 2 ms units. */
+	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+	/* connect the virtual root hub */
+	ohci->rh.devnum = 0;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int
+hc_interrupt (void)
+{
+	ohci_t *ohci = &gohci;
+	struct ohci_regs *regs = ohci->regs;
+	int ints;
+	int stat = -1;
+
+	if ((ohci->hcca->done_head != 0) &&
+	     !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+		ints =  OHCI_INTR_WDH;
+
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->slot_name);
+		return -1;
+
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+		dbg("hc_interrupt: returning..\n");
+		return 0xff;
+	}
+
+	/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+	if (ints & OHCI_INTR_RHSC) {
+		got_rhsc = 1;
+		stat = 0xff;
+	}
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+			ohci->slot_name);
+		/* e.g. due to PCI Master/Target Abort */
+
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#endif
+		/* FIXME: be optimistic, hope that bug won't repeat often. */
+		/* Make some non-interrupt context restart the controller. */
+		/* Count and limit the retries though; either hardware or */
+		/* software errors can go forever... */
+		hc_reset (ohci);
+		return -1;
+	}
+
+	if (ints & OHCI_INTR_WDH) {
+		writel (OHCI_INTR_WDH, &regs->intrdisable);
+		stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+		writel (OHCI_INTR_WDH, &regs->intrenable);
+	}
+
+	if (ints & OHCI_INTR_SO) {
+		dbg("USB Schedule overrun\n");
+		writel (OHCI_INTR_SO, &regs->intrenable);
+		stat = -1;
+	}
+
+	/* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
+	if (ints & OHCI_INTR_SF) {
+		unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
+		wait_ms(1);
+		writel (OHCI_INTR_SF, &regs->intrdisable);
+		if (ohci->ed_rm_list[frame] != NULL)
+			writel (OHCI_INTR_SF, &regs->intrenable);
+		stat = 0xff;
+	}
+
+	writel (ints, &regs->intrstatus);
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+	dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+	if (!ohci->disabled)
+		hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+	memset (&gohci, 0, sizeof (ohci_t));
+	memset (&urb_priv, 0, sizeof (urb_priv_t));
+
+	/* align the storage */
+	if ((__u32)&ghcca[0] & 0xff) {
+		err("HCCA not aligned!!");
+		return -1;
+	}
+	phcca = &ghcca[0];
+	info("aligned ghcca %p", phcca);
+	memset(&ohci_dev, 0, sizeof(struct ohci_device));
+	if ((__u32)&ohci_dev.ed[0] & 0x7) {
+		err("EDs not aligned!!");
+		return -1;
+	}
+	memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+	if ((__u32)gtd & 0x7) {
+		err("TDs not aligned!!");
+		return -1;
+	}
+	ptd = gtd;
+	gohci.hcca = phcca;
+	memset (phcca, 0, sizeof (struct ohci_hcca));
+
+	gohci.disabled = 1;
+	gohci.sleeping = 0;
+	gohci.irq = -1;
+#if defined(CONFIG_440EP)
+	gohci.regs = (struct ohci_regs *)(CONFIG_SYS_PERIPHERAL_BASE | 0x1000);
+#elif defined(CONFIG_440EPX) || defined(CONFIG_SYS_USB_HOST)
+	gohci.regs = (struct ohci_regs *)(CONFIG_SYS_USB_HOST);
+#endif
+
+	gohci.flags = 0;
+	gohci.slot_name = "ppc440";
+
+	if (hc_reset (&gohci) < 0) {
+		hc_release_ohci (&gohci);
+		return -1;
+	}
+
+	if (hc_start (&gohci) < 0) {
+		err ("can't start usb-%s", gohci.slot_name);
+		hc_release_ohci (&gohci);
+		return -1;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (&gohci, 1);
+#endif
+	ohci_inited = 1;
+	urb_finished = 1;
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX)
+	/* init the device driver */
+	usb_dev_init();
+#endif
+
+	return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+	/* this gets called really early - before the controller has */
+	/* even been initialized! */
+	if (!ohci_inited)
+		return 0;
+	/* TODO release any interrupts, etc. */
+	/* call hc_release_ohci() here ? */
+	hc_reset (&gohci);
+	return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
diff --git a/arch/ppc/cpu/ppc4xx/usb_ohci.h b/arch/ppc/cpu/ppc4xx/usb_ohci.h
new file mode 100644
index 0000000..2c3dc4f
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/usb_ohci.h
@@ -0,0 +1,410 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+	/* No  Error  */ 0,
+	/* CRC Error  */ USB_ST_CRC_ERR,
+	/* Bit Stuff  */ USB_ST_BIT_ERR,
+	/* Data Togg  */ USB_ST_CRC_ERR,
+	/* Stall      */ USB_ST_STALLED,
+	/* DevNotResp */ -1,
+	/* PIDCheck   */ USB_ST_BIT_ERR,
+	/* UnExpPID   */ USB_ST_BIT_ERR,
+	/* DataOver   */ USB_ST_BUF_ERR,
+	/* DataUnder  */ USB_ST_BUF_ERR,
+	/* reservd    */ -1,
+	/* reservd    */ -1,
+	/* BufferOver */ USB_ST_BUF_ERR,
+	/* BuffUnder  */ USB_ST_BUF_ERR,
+	/* Not Access */ -1,
+	/* Not Access */ -1
+};
+
+/* ED States */
+
+#define ED_NEW		0x00
+#define ED_UNLINK	0x01
+#define ED_OPER		0x02
+#define ED_DEL		0x04
+#define ED_URB_DEL	0x08
+
+/* usb_ohci_ed */
+struct ed {
+	__u32 hwINFO;
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed *ed_prev;
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load;
+	__u8 int_interval;
+	__u8 state;
+	__u8 type;
+	__u16 last_iso;
+	struct ed *ed_rm_list;
+
+	struct usb_device *usb_dev;
+	__u32 unused[3];
+} __attribute__((aligned(16)));
+typedef struct ed ed_t;
+
+/* TD info field */
+#define TD_CC	    0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC	    0x0C000000
+#define TD_T	    0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R	    0x00040000
+#define TD_DI	    0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP	    0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO	    0x00010000
+#define TD_DEL	    0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR	   0x00
+#define TD_CC_CRC	   0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL	   0x04
+#define TD_DEVNOTRESP	   0x05
+#define TD_PIDCHECKFAIL	   0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN	   0x08
+#define TD_DATAUNDERRUN	   0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED	   0x0F
+
+#define MAXPSW 1
+
+struct td {
+	__u32 hwINFO;
+	__u32 hwCBP;		/* Current Buffer Pointer */
+	__u32 hwNextTD;		/* Next TD Pointer */
+	__u32 hwBE;		/* Memory Buffer End Pointer */
+
+	__u16 hwPSW[MAXPSW];
+	__u8 unused;
+	__u8 index;
+	struct ed *ed;
+	struct td *next_dl_td;
+	struct usb_device *usb_dev;
+	int transfer_len;
+	__u32 data;
+
+	__u32 unused2[2];
+} __attribute__((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32		/* part of the OHCI standard */
+struct ohci_hcca {
+	__u32 int_table[NUM_INTS];	/* Interrupt ED table */
+#if defined(CONFIG_MPC5200)
+	__u16 pad1;		/* set to 0 on each frame_no change */
+	__u16 frame_no;		/* current frame number */
+#else
+	__u16 frame_no;		/* current frame number */
+	__u16 pad1;		/* set to 0 on each frame_no change */
+#endif
+	__u32 done_head;	/* info returned for an interrupt */
+	u8 reserved_for_hc[116];
+} __attribute__((aligned(256)));
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.	You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32 revision;
+	__u32 control;
+	__u32 cmdstatus;
+	__u32 intrstatus;
+	__u32 intrenable;
+	__u32 intrdisable;
+	/* memory pointers */
+	__u32 hcca;
+	__u32 ed_periodcurrent;
+	__u32 ed_controlhead;
+	__u32 ed_controlcurrent;
+	__u32 ed_bulkhead;
+	__u32 ed_bulkcurrent;
+	__u32 donehead;
+	/* frame counters */
+	__u32 fminterval;
+	__u32 fmremaining;
+	__u32 fmnumber;
+	__u32 periodicstart;
+	__u32 lsthresh;
+	/* Root hub ports */
+	struct ohci_roothub_regs {
+		__u32 a;
+		__u32 b;
+		__u32 status;
+		__u32 portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute__((aligned(32)));
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF	(1 << 1)	/* control list filled */
+#define OHCI_BLF	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR	(1 << 3)	/* ownership change request */
+#define OHCI_SOC	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *dev;		/* was urb */
+	void *int_addr;
+	int send;
+	int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE		   0x01
+#define RH_ENDPOINT		   0x02
+#define RH_OTHER		   0x03
+
+#define RH_CLASS		   0x20
+#define RH_VENDOR		   0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	   0x00
+#define RH_PORT_ENABLE		   0x01
+#define RH_PORT_SUSPEND		   0x02
+#define RH_PORT_OVER_CURRENT	   0x03
+#define RH_PORT_RESET		   0x04
+#define RH_PORT_POWER		   0x08
+#define RH_PORT_LOW_SPEED	   0x09
+
+#define RH_C_PORT_CONNECTION	   0x10
+#define RH_C_PORT_ENABLE	   0x11
+#define RH_C_PORT_SUSPEND	   0x12
+#define RH_C_PORT_OVER_CURRENT	   0x13
+#define RH_C_PORT_RESET		   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	   0x00
+#define RH_C_HUB_OVER_CURRENT	   0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	   0x00
+#define RH_ENDPOINT_STALL	   0x01
+
+#define RH_ACK			   0x01
+#define RH_REQ_ERR		   -1
+#define RH_NACK			   0x00
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS	     0x00000001	/* current connect status */
+#define RH_PS_PES	     0x00000002	/* port enable status */
+#define RH_PS_PSS	     0x00000004	/* port suspend status */
+#define RH_PS_POCI	     0x00000008	/* port over current indicator */
+#define RH_PS_PRS	     0x00000010	/* port reset status */
+#define RH_PS_PPS	     0x00000100	/* port power status */
+#define RH_PS_LSDA	     0x00000200	/* low speed device attached */
+#define RH_PS_CSC	     0x00010000	/* connect status change */
+#define RH_PS_PESC	     0x00020000	/* port enable status change */
+#define RH_PS_PSSC	     0x00040000	/* port suspend status change */
+#define RH_PS_OCIC	     0x00080000	/* over current indicator change */
+#define RH_PS_PRSC	     0x00100000	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001	/* local power status */
+#define RH_HS_OCI	     0x00000002	/* over current indicator */
+#define RH_HS_DRWE	     0x00008000	/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000	/* local power status change */
+#define RH_HS_OCIC	     0x00020000	/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000	/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff	/* device removable flags */
+#define RH_B_PPCM	0xffff0000	/* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)	/* number of downstream ports */
+#define RH_A_PSM	(1 << 8)	/* power switching mode */
+#define RH_A_NPS	(1 << 9)	/* no power switching */
+#define RH_A_DT		(1 << 10)	/* device type (mbz) */
+#define RH_A_OCPM	(1 << 11)	/* over current protection mode */
+#define RH_A_NOCP	(1 << 12)	/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)	/* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct {
+	ed_t *ed;
+	__u16 length;		/* number of tds associated with this request */
+	__u16 td_cnt;		/* number of tds already serviced */
+	int state;
+	unsigned long pipe;
+	int actual_length;
+	td_t *td[N_URB_TD];	/* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+typedef struct ohci {
+	struct ohci_hcca *hcca;	/* hcca */
+	/*dma_addr_t hcca_dma; */
+
+	int irq;
+	int disabled;		/* e.g. got a UE, we're hung */
+	int sleeping;
+	unsigned long flags;	/* for HC bugs */
+
+	struct ohci_regs *regs;	/* OHCI controller's memory */
+
+	ed_t *ed_rm_list[2];	/* lists of all endpoints to be removed */
+	ed_t *ed_bulktail;	/* last endpoint of bulk list */
+	ed_t *ed_controltail;	/* last endpoint of control list */
+	int intrstatus;
+	__u32 hc_control;	/* copy of the hc control reg */
+	struct usb_device *dev[32];
+	struct virt_root_hub rh;
+
+	const char *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8		/* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+	ed_t ed[NUM_EDS];
+	int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD + 1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *td_alloc(struct usb_device *usb_dev)
+{
+	int i;
+	struct td *td;
+
+	td = NULL;
+	for (i = 0; i < NUM_TD; i++) {
+		if (ptd[i].usb_dev == NULL) {
+			td = &ptd[i];
+			td->usb_dev = usb_dev;
+			break;
+		}
+	}
+
+	return td;
+}
+
+static inline void ed_free(struct ed *ed)
+{
+	ed->usb_dev = NULL;
+}
diff --git a/arch/ppc/cpu/ppc4xx/usbdev.c b/arch/ppc/cpu/ppc4xx/usbdev.c
new file mode 100644
index 0000000..fe398af
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/usbdev.c
@@ -0,0 +1,230 @@
+/*USB 1.1,2.0 device*/
+
+#include <common.h>
+#include <asm/processor.h>
+
+#if (defined(CONFIG_440EP) || defined(CONFIG_440EPX)) && defined(CONFIG_CMD_USB)
+
+#include <usb.h>
+#include <asm/ppc4xx-uic.h>
+#include "usbdev.h"
+
+#define USB_DT_DEVICE        0x01
+#define USB_DT_CONFIG        0x02
+#define USB_DT_STRING        0x03
+#define USB_DT_INTERFACE     0x04
+#define USB_DT_ENDPOINT      0x05
+
+int set_value = -1;
+
+void process_endpoints(unsigned short usb2d0_intrin)
+{
+	/*will hold the packet received */
+	struct usb_device_descriptor usb_device_packet;
+	struct usb_configuration_descriptor usb_config_packet;
+	struct usb_string_descriptor usb_string_packet;
+	struct devrequest setup_packet;
+	unsigned int *setup_packet_pt;
+	unsigned char *packet_pt = NULL;
+	int temp, temp1;
+
+	int i;
+
+	/*printf("{USB device} - endpoint 0x%X \n", usb2d0_intrin); */
+
+	/*set usb address, seems to not work unless it is done in the next
+	   interrupt, so that is why it is done this way */
+	if (set_value != -1)
+		*(unsigned char *)USB2D0_FADDR_8 = (unsigned char)set_value;
+
+	/*endpoint 1 */
+	if (usb2d0_intrin & 0x01) {
+		setup_packet_pt = (unsigned int *)&setup_packet;
+
+		/*copy packet */
+		setup_packet_pt[0] = *(unsigned int *)USB2D0_FIFO_0;
+		setup_packet_pt[1] = *(unsigned int *)USB2D0_FIFO_0;
+		temp = *(unsigned int *)USB2D0_FIFO_0;
+		temp1 = *(unsigned int *)USB2D0_FIFO_0;
+
+		/*do some swapping */
+		setup_packet.value = swap_16(setup_packet.value);
+		setup_packet.index = swap_16(setup_packet.index);
+		setup_packet.length = swap_16(setup_packet.length);
+
+		/*clear rx packet */
+		*(unsigned short *)USB2D0_INCSR0_8 = 0x48;
+
+		/*printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", setup_packet.requesttype,
+		   setup_packet.request, setup_packet.value,
+		   setup_packet.index, setup_packet.length, temp, temp1 ); */
+
+		switch (setup_packet.request) {
+		case USB_REQ_GET_DESCRIPTOR:
+
+			switch (setup_packet.value >> 8) {
+			case USB_DT_DEVICE:
+				/*create packet */
+				usb_device_packet.bLength = 18;
+				usb_device_packet.bDescriptorType =
+				    USB_DT_DEVICE;
+#ifdef USB_2_0_DEVICE
+				usb_device_packet.bcdUSB = swap_16(0x200);
+#else
+				usb_device_packet.bcdUSB = swap_16(0x110);
+#endif
+				usb_device_packet.bDeviceClass = 0xff;
+				usb_device_packet.bDeviceSubClass = 0;
+				usb_device_packet.bDeviceProtocol = 0;
+				usb_device_packet.bMaxPacketSize0 = 32;
+				usb_device_packet.idVendor = swap_16(1);
+				usb_device_packet.idProduct = swap_16(2);
+				usb_device_packet.bcdDevice = swap_16(0x300);
+				usb_device_packet.iManufacturer = 1;
+				usb_device_packet.iProduct = 1;
+				usb_device_packet.iSerialNumber = 1;
+				usb_device_packet.bNumConfigurations = 1;
+
+				/*put packet in fifo */
+				packet_pt = (unsigned char *)&usb_device_packet;
+				break;
+
+			case USB_DT_CONFIG:
+				/*create packet */
+				usb_config_packet.bLength = 9;
+				usb_config_packet.bDescriptorType =
+				    USB_DT_CONFIG;
+				usb_config_packet.wTotalLength = swap_16(25);
+				usb_config_packet.bNumInterfaces = 1;
+				usb_config_packet.bConfigurationValue = 1;
+				usb_config_packet.iConfiguration = 0;
+				usb_config_packet.bmAttributes = 0x40;
+				usb_config_packet.bMaxPower = 0;
+
+				/*put packet in fifo */
+				packet_pt = (unsigned char *)&usb_config_packet;
+				break;
+
+			case USB_DT_STRING:
+				/*create packet */
+				usb_string_packet.bLength = 2;
+				usb_string_packet.bDescriptorType =
+				    USB_DT_STRING;
+				usb_string_packet.wData[0] = 0x0094;
+
+				/*put packet in fifo */
+				packet_pt = (unsigned char *)&usb_string_packet;
+				break;
+			}
+
+			/*put packet in fifo */
+			for (i = 0; i < (setup_packet.length); i++) {
+				*(unsigned char *)USB2D0_FIFO_0 = packet_pt[i];
+			}
+
+			/*give tx command */
+			*(unsigned short *)USB2D0_INCSR0_8 = 0x0a;
+
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+
+			/*copy usb address */
+			set_value = setup_packet.value;
+
+			break;
+		}
+
+	}
+}
+
+void process_other(unsigned char usb2d0_intrusb)
+{
+
+	/*check for sof */
+	if (usb2d0_intrusb & 0x08) {
+		/*printf("{USB device} - sof detected\n"); */
+	}
+
+	/*check for reset */
+	if (usb2d0_intrusb & 0x04) {
+		/*printf("{USB device} - reset detected\n"); */
+
+		/*copy usb address of zero, need to do this when usb reset */
+		set_value = 0;
+	}
+
+	if (usb2d0_intrusb & 0x02) {
+		/*printf("{USB device} - resume detected\n"); */
+	}
+
+	if (usb2d0_intrusb & 0x01) {
+		/*printf("{USB device} - suspend detected\n"); */
+	}
+}
+
+int usbInt(void)
+{
+	/*Must read these 2 registers and use values to clear interrupts.  If you
+	   do not read them then the interrupt will not be cleared.  If you do not
+	   use the variable the optimizer will not do a read. */
+	volatile unsigned short usb2d0_intrin =
+	    *(unsigned short *)USB2D0_INTRIN_16;
+	volatile unsigned char usb2d0_intrusb =
+	    *(unsigned char *)USB2D0_INTRUSB_8;
+
+	/*check if there was an endpoint interrupt */
+	if (usb2d0_intrin != 0) {
+		process_endpoints(usb2d0_intrin);
+	}
+
+	/*check for other interrupts */
+	if (usb2d0_intrusb != 0) {
+		process_other(usb2d0_intrusb);
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_440EPX)
+void usb_dev_init()
+{
+	printf("USB 2.0 Device init\n");
+
+	/*usb dev init */
+	*(unsigned char *)USB2D0_POWER_8 = 0xa1;	/* 2.0 */
+
+	/*enable interrupts */
+	*(unsigned char *)USB2D0_INTRUSBE_8 = 0x0f;
+
+	irq_install_handler(VECNUM_USBDEV, (interrupt_handler_t *) usbInt,
+			    NULL);
+}
+#else
+void usb_dev_init()
+{
+#ifdef USB_2_0_DEVICE
+	printf("USB 2.0 Device init\n");
+	/*select 2.0 device */
+	mtsdr(SDR0_USB0, 0x0);	/* 2.0 */
+
+	/*usb dev init */
+	*(unsigned char *)USB2D0_POWER_8 = 0xa1;	/* 2.0 */
+#else
+	printf("USB 1.1 Device init\n");
+	/*select 1.1 device */
+	mtsdr(SDR0_USB0, 0x2);	/* 1.1 */
+
+	/*usb dev init */
+	*(unsigned char *)USB2D0_POWER_8 = 0xc0;	/* 1.1 */
+#endif
+
+	/*enable interrupts */
+	*(unsigned char *)USB2D0_INTRUSBE_8 = 0x0f;
+
+	irq_install_handler(VECNUM_USBDEV, (interrupt_handler_t *) usbInt,
+			    NULL);
+}
+#endif
+
+#endif /* CONFIG_440EP || CONFIG_440EPX */
diff --git a/arch/ppc/cpu/ppc4xx/usbdev.h b/arch/ppc/cpu/ppc4xx/usbdev.h
new file mode 100644
index 0000000..ef6a2da
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/usbdev.h
@@ -0,0 +1,31 @@
+#include <config.h>
+
+/*Common Registers*/
+#define USB2D0_INTRIN_16   (CONFIG_SYS_USB_DEVICE | 0x100)
+#define USB2D0_POWER_8     (CONFIG_SYS_USB_DEVICE | 0x102)
+#define USB2D0_FADDR_8     (CONFIG_SYS_USB_DEVICE | 0x103)
+#define USB2D0_INTRINE_16  (CONFIG_SYS_USB_DEVICE | 0x104)
+#define USB2D0_INTROUT_16  (CONFIG_SYS_USB_DEVICE | 0x106)
+#define USB2D0_INTRUSBE_8  (CONFIG_SYS_USB_DEVICE | 0x108)
+#define USB2D0_INTRUSB_8   (CONFIG_SYS_USB_DEVICE | 0x109)
+#define USB2D0_INTROUTE_16 (CONFIG_SYS_USB_DEVICE | 0x10a)
+#define USB2D0_TSTMODE_8   (CONFIG_SYS_USB_DEVICE | 0x10c)
+#define USB2D0_INDEX_8     (CONFIG_SYS_USB_DEVICE | 0x10d)
+#define USB2D0_FRAME_16    (CONFIG_SYS_USB_DEVICE | 0x10e)
+
+/*Indexed Registers*/
+#define USB2D0_INCSR0_8    (CONFIG_SYS_USB_DEVICE | 0x110)
+#define USB2D0_INCSR_16    (CONFIG_SYS_USB_DEVICE | 0x110)
+#define USB2D0_INMAXP_16   (CONFIG_SYS_USB_DEVICE | 0x112)
+#define USB2D0_OUTCSR_16   (CONFIG_SYS_USB_DEVICE | 0x114)
+#define USB2D0_OUTMAXP_16  (CONFIG_SYS_USB_DEVICE | 0x116)
+#define USB2D0_OUTCOUNT0_8 (CONFIG_SYS_USB_DEVICE | 0x11a)
+#define USB2D0_OUTCOUNT_16 (CONFIG_SYS_USB_DEVICE | 0x11a)
+
+/*FIFOs*/
+#define USB2D0_FIFO_0 (CONFIG_SYS_USB_DEVICE | 0x120)
+#define USB2D0_FIFO_1 (CONFIG_SYS_USB_DEVICE | 0x124)
+#define USB2D0_FIFO_2 (CONFIG_SYS_USB_DEVICE | 0x128)
+#define USB2D0_FIFO_3 (CONFIG_SYS_USB_DEVICE | 0x12c)
+
+void usb_dev_init(void);
diff --git a/arch/ppc/cpu/ppc4xx/xilinx_irq.c b/arch/ppc/cpu/ppc4xx/xilinx_irq.c
new file mode 100644
index 0000000..7108777
--- /dev/null
+++ b/arch/ppc/cpu/ppc4xx/xilinx_irq.c
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright 2008
+ * Ricado Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@uam.es
+ * This work has been supported by: QTechnology  http://qtec.com/
+ * Based on interrupts.c Wolfgang Denk-DENX Software Engineering-wd@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, see <http://www.gnu.org/licenses/>.
+*/
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/interrupt.h>
+#include <ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <asm/io.h>
+#include <asm/xilinx_irq.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void pic_enable(void)
+{
+	debug("Xilinx PIC at 0x%8x\n", intc);
+
+	/*
+	 * Disable all external interrupts until they are
+	 * explicitly requested.
+	 */
+	out_be32((u32 *) IER, 0);
+
+	/* Acknowledge any pending interrupts just in case. */
+	out_be32((u32 *) IAR, 0xffffffff);
+
+	/* Turn on the Master Enable. */
+	out_be32((u32 *) MER, 0x3UL);
+
+	return;
+}
+
+int xilinx_pic_irq_get(void)
+{
+	u32 irq;
+	irq = in_be32((u32 *) IVR);
+
+	/* If no interrupt is pending then all bits of the IVR are set to 1. As
+	 * the IVR is as many bits wide as numbers of inputs are available.
+	 * Therefore, if all bits of the IVR are set to one, its content will
+	 * be bigger than XPAR_INTC_MAX_NUM_INTR_INPUTS.
+	 */
+	if (irq >= XPAR_INTC_MAX_NUM_INTR_INPUTS)
+		irq = -1;	/* report no pending interrupt. */
+
+	debug("get_irq: %d\n", irq);
+	return (irq);
+}
+
+void pic_irq_enable(unsigned int irq)
+{
+	u32 mask = IRQ_MASK(irq);
+	debug("enable: %d\n", irq);
+	out_be32((u32 *) SIE, mask);
+}
+
+void pic_irq_disable(unsigned int irq)
+{
+	u32 mask = IRQ_MASK(irq);
+	debug("disable: %d\n", irq);
+	out_be32((u32 *) CIE, mask);
+}
+
+void pic_irq_ack(unsigned int irq)
+{
+	u32 mask = IRQ_MASK(irq);
+	debug("ack: %d\n", irq);
+	out_be32((u32 *) IAR, mask);
+}
+
+void external_interrupt(struct pt_regs *regs)
+{
+	int irq;
+
+	irq = xilinx_pic_irq_get();
+	if (irq < 0)
+		return;
+
+	interrupt_run_handler(irq);
+
+	return;
+}