Move arch/ppc to arch/powerpc

As discussed on the list, move "arch/ppc" to "arch/powerpc" to
better match the Linux directory structure.

Please note that this patch also changes the "ppc" target in
MAKEALL to "powerpc" to match this new infrastructure. But "ppc"
is kept as an alias for now, to not break compatibility with
scripts using this name.

Signed-off-by: Stefan Roese <sr@denx.de>
Acked-by: Wolfgang Denk <wd@denx.de>
Acked-by: Detlev Zundel <dzu@denx.de>
Acked-by: Kim Phillips <kim.phillips@freescale.com>
Cc: Peter Tyser <ptyser@xes-inc.com>
Cc: Anatolij Gustschin <agust@denx.de>
diff --git a/arch/powerpc/cpu/mpc5xxx/Makefile b/arch/powerpc/cpu/mpc5xxx/Makefile
new file mode 100644
index 0000000..0ee0611
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/config.mk b/arch/powerpc/cpu/mpc5xxx/config.mk
new file mode 100644
index 0000000..7ef8a47
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/u-boot.lds
diff --git a/arch/powerpc/cpu/mpc5xxx/cpu.c b/arch/powerpc/cpu/mpc5xxx/cpu.c
new file mode 100644
index 0000000..b20234d
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/cpu_init.c b/arch/powerpc/cpu/mpc5xxx/cpu_init.c
new file mode 100644
index 0000000..9daf375
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S b/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S
new file mode 100644
index 0000000..00c2312
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/i2c.c b/arch/powerpc/cpu/mpc5xxx/i2c.c
new file mode 100644
index 0000000..4f7f716
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/ide.c b/arch/powerpc/cpu/mpc5xxx/ide.c
new file mode 100644
index 0000000..d337abb
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/interrupts.c b/arch/powerpc/cpu/mpc5xxx/interrupts.c
new file mode 100644
index 0000000..16eee3a
--- /dev/null
+++ b/arch/powerpc/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/powerpc/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/powerpc/cpu/mpc5xxx/io.S b/arch/powerpc/cpu/mpc5xxx/io.S
new file mode 100644
index 0000000..2178a26
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/loadtask.c b/arch/powerpc/cpu/mpc5xxx/loadtask.c
new file mode 100644
index 0000000..47e7b59
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/pci_mpc5200.c b/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c
new file mode 100644
index 0000000..8268f8a
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/serial.c b/arch/powerpc/cpu/mpc5xxx/serial.c
new file mode 100644
index 0000000..59a877a
--- /dev/null
+++ b/arch/powerpc/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/powerpc/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/powerpc/cpu/mpc5xxx/speed.c b/arch/powerpc/cpu/mpc5xxx/speed.c
new file mode 100644
index 0000000..8027d3e
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/start.S b/arch/powerpc/cpu/mpc5xxx/start.S
new file mode 100644
index 0000000..8b9f09b
--- /dev/null
+++ b/arch/powerpc/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/powerpc/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/powerpc/cpu/mpc5xxx/traps.c b/arch/powerpc/cpu/mpc5xxx/traps.c
new file mode 100644
index 0000000..5972f34
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/traps.c
@@ -0,0 +1,245 @@
+/*
+ * linux/arch/powerpc/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/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds b/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds
new file mode 100644
index 0000000..ecffc1b
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/start.o          (.text)
+    arch/powerpc/cpu/mpc5xxx/traps.o          (.text)
+    lib/crc32.o         (.text)
+    arch/powerpc/lib/cache.o             (.text)
+    arch/powerpc/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/powerpc/cpu/mpc5xxx/u-boot.lds b/arch/powerpc/cpu/mpc5xxx/u-boot.lds
new file mode 100644
index 0000000..ea4060d
--- /dev/null
+++ b/arch/powerpc/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/powerpc/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/powerpc/cpu/mpc5xxx/usb.c b/arch/powerpc/cpu/mpc5xxx/usb.c
new file mode 100644
index 0000000..bec7da3
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/usb_ohci.c b/arch/powerpc/cpu/mpc5xxx/usb_ohci.c
new file mode 100644
index 0000000..7976e4d
--- /dev/null
+++ b/arch/powerpc/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/powerpc/cpu/mpc5xxx/usb_ohci.h b/arch/powerpc/cpu/mpc5xxx/usb_ohci.h
new file mode 100644
index 0000000..629b529
--- /dev/null
+++ b/arch/powerpc/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;
+}