Patch by TsiChung Liew, 23 Sep 2004:
- add support for MPC8220 CPU
- Add support for Alaska and Yukon boards
diff --git a/cpu/mpc8220/Makefile b/cpu/mpc8220/Makefile
new file mode 100644
index 0000000..e64964b
--- /dev/null
+++ b/cpu/mpc8220/Makefile
@@ -0,0 +1,45 @@
+#
+# (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 $(TOPDIR)/config.mk
+
+LIB	= lib$(CPU).a
+
+START	= start.o
+ASOBJS	= io.o fec_dma_tasks.o
+OBJS	= i2c.o traps.o cpu.o cpu_init.o fec.o dramSetup.o interrupts.o \
+	  loadtask.o uart.o speed.o
+
+all:	.depend $(START) $(ASOBJS) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(ASOBJS) $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(ASOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/mpc8220/config.mk b/cpu/mpc8220/config.mk
new file mode 100644
index 0000000..6fec5df
--- /dev/null
+++ b/cpu/mpc8220/config.mk
@@ -0,0 +1,27 @@
+#
+# (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 -ffixed-r14 -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC8220 -ffixed-r2 -ffixed-r29 \
+		     -mstring -mcpu=603e -mmultiple
diff --git a/cpu/mpc8220/cpu.c b/cpu/mpc8220/cpu.c
new file mode 100644
index 0000000..0cfe808
--- /dev/null
+++ b/cpu/mpc8220/cpu.c
@@ -0,0 +1,93 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC8220 CPUs
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8220.h>
+#include <asm/processor.h>
+
+int checkcpu (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	ulong clock = gd->cpu_clk;
+	char buf[32];
+
+	puts ("CPU:   ");
+
+	printf (CPU_ID_STR);
+
+	printf (" (JTAG ID %08lx)", *(vu_long *) (CFG_MBAR + 0x50));
+
+	printf (" at %s MHz\n", strmhz (buf, clock));
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	volatile gptmr8220_t *gptmr = (volatile gptmr8220_t *) MMAP_GPTMR;
+	ulong msr;
+
+	/* Interrupts and MMU off */
+	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
+
+	msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
+
+	/* Charge the watchdog timer */
+	gptmr->Prescl = 10;
+	gptmr->Count = 1;
+
+	gptmr->Mode = GPT_TMS_SGPIO;
+
+	gptmr->Control = GPT_CTRL_WDEN | GPT_CTRL_CE;
+
+	return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	ulong tbclk;
+
+	tbclk = (gd->bus_clk + 3L) / 4L;
+
+	return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc8220/cpu_init.c b/cpu/mpc8220/cpu_init.c
new file mode 100644
index 0000000..09b23ee
--- /dev/null
+++ b/cpu/mpc8220/cpu_init.c
@@ -0,0 +1,130 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers.
+ */
+void cpu_init_f (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile flexbus8220_t *flexbus = (volatile flexbus8220_t *) MMAP_FB;
+	volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG;
+	volatile xlbarb8220_t *xlbarb = (volatile xlbarb8220_t *) MMAP_XLBARB;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET);
+
+	/* Clear initial global data */
+	memset ((void *) gd, 0, sizeof (gd_t));
+
+	/* Clear all port configuration */
+	portcfg->pcfg0 = 0;
+	portcfg->pcfg1 = 0;
+	portcfg->pcfg2 = 0;
+	portcfg->pcfg3 = 0;
+
+	/*
+	 * Flexbus Controller: configure chip selects and enable them
+	 */
+#if defined (CFG_CS0_BASE)
+	flexbus->csar0 = CFG_CS0_BASE;
+	flexbus->cscr0 = CFG_CS0_CTRL;
+	flexbus->csmr0 = ((CFG_CS0_MASK - 1) & 0xffff0000) | 1;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CFG_CS1_BASE)
+	flexbus->csar1 = CFG_CS1_BASE;
+	flexbus->cscr1 = CFG_CS1_CTRL;
+	flexbus->csmr1 = ((CFG_CS1_MASK - 1) & 0xffff0000) | 1;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CFG_CS2_BASE)
+	flexbus->csar2 = CFG_CS2_BASE;
+	flexbus->cscr2 = CFG_CS2_CTRL;
+	flexbus->csmr2 = ((CFG_CS2_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CFG_CS2_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CFG_CS3_BASE)
+	flexbus->csar3 = CFG_CS3_BASE;
+	flexbus->cscr3 = CFG_CS3_CTRL;
+	flexbus->csmr3 = ((CFG_CS3_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CFG_CS3_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CFG_CS4_BASE)
+	flexbus->csar4 = CFG_CS4_BASE;
+	flexbus->cscr4 = CFG_CS4_CTRL;
+	flexbus->csmr4 = ((CFG_CS4_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CFG_CS4_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+#if defined (CFG_CS5_BASE)
+	flexbus->csar5 = CFG_CS5_BASE;
+	flexbus->cscr5 = CFG_CS5_CTRL;
+	flexbus->csmr5 = ((CFG_CS5_MASK - 1) & 0xffff0000) | 1;
+	portcfg->pcfg3 |= CFG_CS5_PORT3_CONFIG;
+	__asm__ volatile ("sync");
+#endif
+
+	/* This section of the code cannot place in cpu_init_r(),
+	   it will cause the system to hang */
+	/* enable timebase */
+	xlbarb->config = 0x00002000;
+
+	xlbarb->addrTenTimeOut = 0x1000;
+	xlbarb->dataTenTimeOut = 0x1000;
+	xlbarb->busActTimeOut = 0x2000;
+
+	/* Master Priority Enable */
+	xlbarb->mastPriEn = 0x1f;
+	xlbarb->mastPriority = 0;
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+	/* this may belongs to disable interrupt section */
+	/* mask all interrupts */
+	*(vu_long *) 0xf0000700 = 0xfffffc00;
+	*(vu_long *) 0xf0000714 |= 0x0001ffff;
+	*(vu_long *) 0xf0000710 &= ~0x00000f00;
+
+	/* route critical ints to normal ints */
+	*(vu_long *) 0xf0000710 |= 0x00000001;
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_MPC8220_FEC)
+	/* load FEC microcode */
+	loadtask (0, 2);
+#endif
+	return (0);
+}
diff --git a/cpu/mpc8220/dma.h b/cpu/mpc8220/dma.h
new file mode 100644
index 0000000..d06ee63
--- /dev/null
+++ b/cpu/mpc8220/dma.h
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * MPC8220 dma header file
+ */
+
+#ifndef __MPC8220_DMA_H
+#define __MPC8220_DMA_H
+
+#include <common.h>
+#include <mpc8220.h>
+
+/* Task number assignment */
+#define FEC_RECV_TASK_NO            0
+#define FEC_XMIT_TASK_NO            1
+
+/*---------------------------------------------------------------------
+ * Stuff for Ethernet Tx/Rx tasks
+ *---------------------------------------------------------------------
+ */
+
+/* Layout of Ethernet controller Parameter SRAM area:
+ * ----------------------------------------------------------------
+ * 0x00: TBD_BASE, base address of TX BD ring
+ * 0x04: TBD_NEXT, address of next TX BD to be processed
+ * 0x08: RBD_BASE, base address of RX BD ring
+ * 0x0C: RBD_NEXT, address of next RX BD to be processed
+ * ---------------------------------------------------------------
+ * ALL PARAMETERS ARE ALL LONGWORDS (FOUR BYTES EACH).
+ */
+
+/* base address of SRAM area to store parameters used by Ethernet tasks */
+#define FEC_PARAM_BASE  (MMAP_SRAM + 0x5b00)
+
+/* base address of SRAM area for buffer descriptors */
+#define FEC_BD_BASE     (MMAP_SRAM + 0x5b20)
+
+/*---------------------------------------------------------------------
+ * common shortcuts  used  by driver C code
+ *---------------------------------------------------------------------
+ */
+
+/* Disable SmartDMA task */
+#define DMA_TASK_DISABLE(tasknum)						\
+{										\
+	volatile ushort *tcr = (ushort *)(MMAP_DMA + 0x0000001c + 2 * tasknum); \
+	*tcr = (*tcr) & (~0x8000);						\
+}
+
+/* Enable SmartDMA task */
+#define DMA_TASK_ENABLE(tasknum)						\
+{										\
+	volatile ushort *tcr = (ushort *) (MMAP_DMA + 0x0000001c + 2 * tasknum);\
+	*tcr = (*tcr)  | 0x8000;						\
+}
+
+/* Clear interrupt pending bits */
+#define DMA_CLEAR_IEVENT(tasknum)						\
+{										\
+	struct mpc8220_dma *dma = (struct mpc8220_dma *)MMAP_DMA;		\
+	dma->IntPend = (1 << tasknum);						\
+}
+
+#endif  /* __MPC8220_DMA_H */
diff --git a/cpu/mpc8220/dramSetup.c b/cpu/mpc8220/dramSetup.c
new file mode 100644
index 0000000..033b719
--- /dev/null
+++ b/cpu/mpc8220/dramSetup.c
@@ -0,0 +1,755 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+DESCRIPTION
+Read Dram spd and base on its information to calculate the memory size,
+characteristics to initialize the dram on MPC8220
+*/
+
+#include <common.h>
+#include <mpc8220.h>
+#include "i2cCore.h"
+#include "dramSetup.h"
+
+#define SPD_SIZE    0x40
+#define DRAM_SPD    0xA2	/* on Board SPD eeprom */
+#define TOTAL_BANK  2
+
+int spd_status (volatile i2c8220_t * pi2c, u8 sta_bit, u8 truefalse)
+{
+	int i;
+
+	for (i = 0; i < I2C_POLL_COUNT; i++) {
+		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0))
+			return (OK);
+	}
+
+	return (ERROR);
+}
+
+int spd_clear (volatile i2c8220_t * pi2c)
+{
+	pi2c->adr = 0;
+	pi2c->fdr = 0;
+	pi2c->cr = 0;
+	pi2c->sr = 0;
+
+	return (OK);
+}
+
+int spd_stop (volatile i2c8220_t * pi2c)
+{
+	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal         */
+	if (spd_status (pi2c, I2C_STA_BB, 0) != OK)
+		return ERROR;
+
+	return (OK);
+}
+
+int spd_readbyte (volatile i2c8220_t * pi2c, u8 * readb, int *index)
+{
+	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit          */
+	*readb = pi2c->dr;	/* Read a byte                  */
+
+	/*
+	   Set I2C_CTRL_TXAK will cause Transfer pending and
+	   set I2C_CTRL_STA will cause Interrupt pending
+	 */
+	if (*index != 2) {
+		if (spd_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?       */
+			return ERROR;
+	}
+
+	if (*index != 1) {
+		if (spd_status (pi2c, I2C_STA_IF, 1) != OK)
+			return ERROR;
+	}
+
+	return (OK);
+}
+
+int readSpdData (u8 * spdData)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile i2c8220_t *pi2cReg;
+	volatile pcfg8220_t *pcfg;
+	u8 slvAdr = DRAM_SPD;
+	u8 Tmp;
+	int Length = SPD_SIZE;
+	int i = 0;
+
+	/* Enable Port Configuration for SDA and SDL signals */
+	pcfg = (volatile pcfg8220_t *) (MMAP_PCFG);
+	__asm__ ("sync");
+	pcfg->pcfg3 &= ~CFG_I2C_PORT3_CONFIG;
+	__asm__ ("sync");
+
+	/* Points the structure to I2c mbar memory offset */
+	pi2cReg = (volatile i2c8220_t *) (MMAP_I2C);
+
+
+	/* Clear FDR, ADR, SR and CR reg */
+	pi2cReg->adr = 0;
+	pi2cReg->fdr = 0;
+	pi2cReg->cr = 0;
+	pi2cReg->sr = 0;
+
+	/* Set for fix XLB Bus Frequency */
+	switch (gd->bus_clk) {
+	case 60000000:
+		pi2cReg->fdr = 0x15;
+		break;
+	case 70000000:
+		pi2cReg->fdr = 0x16;
+		break;
+	case 80000000:
+		pi2cReg->fdr = 0x3a;
+		break;
+	case 90000000:
+		pi2cReg->fdr = 0x17;
+		break;
+	case 100000000:
+		pi2cReg->fdr = 0x3b;
+		break;
+	case 110000000:
+		pi2cReg->fdr = 0x18;
+		break;
+	case 120000000:
+		pi2cReg->fdr = 0x19;
+		break;
+	case 130000000:
+		pi2cReg->fdr = 0x1a;
+		break;
+	}
+
+	pi2cReg->adr = 0x90;	/* I2C device address */
+
+	pi2cReg->cr = I2C_CTL_EN;	/* Set Enable         */
+
+	/*
+	   The I2C bus should be in Idle state. If the bus is busy,
+	   clear the STA bit in control register
+	 */
+	if (spd_status (pi2cReg, I2C_STA_BB, 0) != OK) {
+		if ((pi2cReg->cr & I2C_CTL_STA) == I2C_CTL_STA)
+			pi2cReg->cr &= ~I2C_CTL_STA;
+
+		/* Check again if it is still busy, return error if found */
+		if (spd_status (pi2cReg, I2C_STA_BB, 1) == OK)
+			return ERROR;
+	}
+
+	pi2cReg->cr |= I2C_CTL_TX;	/* Enable the I2c for TX, Ack   */
+	pi2cReg->cr |= I2C_CTL_STA;	/* Generate start signal        */
+
+	if (spd_status (pi2cReg, I2C_STA_BB, 1) != OK)
+		return ERROR;
+
+
+	/* Write slave address */
+	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */
+	pi2cReg->dr = slvAdr;	/* Write a byte                 */
+
+	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+
+	/* Issue the offset to start */
+	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */
+	pi2cReg->dr = 0;	/* Write a byte                 */
+
+	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+
+	/* Set repeat start */
+	pi2cReg->cr |= I2C_CTL_RSTA;	/* Repeat Start                 */
+
+	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */
+	pi2cReg->dr = slvAdr | 1;	/* Write a byte                 */
+
+	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01))
+		return ERROR;
+
+	pi2cReg->cr &= ~I2C_CTL_TX;	/* Set receive mode             */
+
+	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01))
+		return ERROR;
+
+	/* Dummy Read */
+	if (spd_readbyte (pi2cReg, &Tmp, &i) != OK) {
+		spd_stop (pi2cReg);
+		return ERROR;
+	}
+
+	i = 0;
+	while (Length) {
+		if (Length == 2)
+			pi2cReg->cr |= I2C_CTL_TXAK;
+
+		if (Length == 1)
+			pi2cReg->cr &= ~I2C_CTL_STA;
+
+		if (spd_readbyte (pi2cReg, spdData, &Length) != OK) {
+			return spd_stop (pi2cReg);
+		}
+		i++;
+		Length--;
+		spdData++;
+	}
+
+	/* Stop the service */
+	spd_stop (pi2cReg);
+
+	return OK;
+}
+
+int getBankInfo (int bank, draminfo_t * pBank)
+{
+	int status;
+	int checksum;
+	int count;
+	u8 spdData[SPD_SIZE];
+
+
+	if (bank > 2 || pBank == 0) {
+		/* illegal values */
+		return (-42);
+	}
+
+	status = readSpdData (&spdData[0]);
+	if (status < 0)
+		return (-1);
+
+	/* check the checksum */
+	for (count = 0, checksum = 0; count < LOC_CHECKSUM; count++)
+		checksum += spdData[count];
+
+	checksum = checksum - ((checksum / 256) * 256);
+
+	if (checksum != spdData[LOC_CHECKSUM])
+		return (-2);
+
+	/* Get the memory type */
+	if (!
+	    ((spdData[LOC_TYPE] == TYPE_DDR)
+	     || (spdData[LOC_TYPE] == TYPE_SDR)))
+		/* not one of the types we support */
+		return (-3);
+
+	pBank->type = spdData[LOC_TYPE];
+
+	/* Set logical banks */
+	pBank->banks = spdData[LOC_LOGICAL_BANKS];
+
+	/* Check that we have enough physical banks to cover the bank we are
+	 * figuring out.  Odd-numbered banks correspond to the second bank
+	 * on the device.
+	 */
+	if (bank & 1) {
+		/* Second bank of a "device" */
+		if (spdData[LOC_PHYS_BANKS] < 2)
+			/* this bank doesn't exist on the "device" */
+			return (-4);
+
+		if (spdData[LOC_ROWS] & 0xf0)
+			/* Two asymmetric banks */
+			pBank->rows = spdData[LOC_ROWS] >> 4;
+		else
+			pBank->rows = spdData[LOC_ROWS];
+
+		if (spdData[LOC_COLS] & 0xf0)
+			/* Two asymmetric banks */
+			pBank->cols = spdData[LOC_COLS] >> 4;
+		else
+			pBank->cols = spdData[LOC_COLS];
+	} else {
+		/* First bank of a "device" */
+		pBank->rows = spdData[LOC_ROWS];
+		pBank->cols = spdData[LOC_COLS];
+	}
+
+	pBank->width = spdData[LOC_WIDTH_HIGH] << 8 | spdData[LOC_WIDTH_LOW];
+	pBank->bursts = spdData[LOC_BURSTS];
+	pBank->CAS = spdData[LOC_CAS];
+	pBank->CS = spdData[LOC_CS];
+	pBank->WE = spdData[LOC_WE];
+	pBank->Trp = spdData[LOC_Trp];
+	pBank->Trcd = spdData[LOC_Trcd];
+	pBank->buffered = spdData[LOC_Buffered] & 1;
+	pBank->refresh = spdData[LOC_REFRESH];
+
+	return (0);
+}
+
+
+/* checkMuxSetting -- given a row/column device geometry, return a mask
+ *                    of the valid DRAM controller addr_mux settings for
+ *                    that geometry.
+ *
+ *  Arguments:        u8 rows:     number of row addresses in this device
+ *                    u8 columns:  number of column addresses in this device
+ *
+ *  Returns:          a mask of the allowed addr_mux settings for this
+ *                    geometry.  Each bit in the mask represents a
+ *                    possible addr_mux settings (for example, the
+ *                    (1<<2) bit in the mask represents the 0b10 setting)/
+ *
+ */
+u8 checkMuxSetting (u8 rows, u8 columns)
+{
+	muxdesc_t *pIdx, *pMux;
+	u8 mask;
+	int lrows, lcolumns;
+	u32 mux[4] = { 0x00080c04, 0x01080d03, 0x02080e02, 0xffffffff };
+
+	/* Setup MuxDescriptor in SRAM space */
+	/* MUXDESC AddressRuns [] = {
+	   { 0, 8, 12, 4 },         / setting, columns, rows, extra columns /
+	   { 1, 8, 13, 3 },         / setting, columns, rows, extra columns /
+	   { 2, 8, 14, 2 },         / setting, columns, rows, extra columns /
+	   { 0xff }                 / list terminator /
+	   }; */
+
+	pIdx = (muxdesc_t *) & mux[0];
+
+	/* Check rows x columns against each possible address mux setting */
+	for (pMux = pIdx, mask = 0;; pMux++) {
+		lrows = rows;
+		lcolumns = columns;
+
+		if (pMux->MuxValue == 0xff)
+			break;	/* end of list */
+
+		/* For a given mux setting, since we want all the memory in a
+		 * device to be contiguous, we want the device "use up" the
+		 * address lines such that there are no extra column or row
+		 * address lines on the device.
+		 */
+
+		lcolumns -= pMux->Columns;
+		if (lcolumns < 0)
+			/* Not enough columns to get to the rows */
+			continue;
+
+		lrows -= pMux->Rows;
+		if (lrows > 0)
+			/* we have extra rows left -- can't do that! */
+			continue;
+
+		/* At this point, we either have to have used up all the
+		 * rows or we have to have no columns left.
+		 */
+
+		if (lcolumns != 0 && lrows != 0)
+			/* rows AND columns are left.  Bad! */
+			continue;
+
+		lcolumns -= pMux->MoreColumns;
+
+		if (lcolumns <= 0)
+			mask |= (1 << pMux->MuxValue);
+	}
+
+	return (mask);
+}
+
+
+u32 dramSetup (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	draminfo_t DramInfo[TOTAL_BANK];
+	draminfo_t *pDramInfo;
+	u32 size, temp, cfg_value, mode_value, refresh;
+	u8 *ptr;
+	u8 bursts, Trp, Trcd, type, buffered;
+	u8 muxmask, rows, columns;
+	int count, banknum;
+	u32 *prefresh, *pIdx;
+	u32 refrate[8] = { 15625, 3900, 7800, 31300,
+		62500, 125000, 0xffffffff, 0xffffffff
+	};
+	volatile sysconf8220_t *sysconf;
+	volatile memctl8220_t *memctl;
+
+	sysconf = (volatile sysconf8220_t *) MMAP_MBAR;
+	memctl = (volatile memctl8220_t *) MMAP_MEMCTL;
+
+	/* Set everything in the descriptions to zero */
+	ptr = (u8 *) & DramInfo[0];
+	for (count = 0; count < sizeof (DramInfo); count++)
+		*ptr++ = 0;
+
+	for (banknum = 0; banknum < TOTAL_BANK; banknum++)
+		sysconf->cscfg[banknum];
+
+	/* Descriptions of row/column address muxing for various
+	 * addr_mux settings.
+	 */
+
+	pIdx = prefresh = (u32 *) & refrate[0];
+
+	/* Get all the info for all three logical banks */
+	bursts = 0xff;
+	Trp = 0;
+	Trcd = 0;
+	type = 0;
+	buffered = 0xff;
+	refresh = 0xffffffff;
+	muxmask = 0xff;
+
+	/* Two bank, CS0 and CS1 */
+	for (banknum = 0, pDramInfo = &DramInfo[0];
+	     banknum < TOTAL_BANK; banknum++, pDramInfo++) {
+		pDramInfo->ordinal = banknum;	/* initial sorting */
+		if (getBankInfo (banknum, pDramInfo) < 0)
+			continue;
+
+		/* get cumulative parameters of all three banks */
+		if (type && pDramInfo->type != type)
+			return 0;
+
+		type = pDramInfo->type;
+		rows = pDramInfo->rows;
+		columns = pDramInfo->cols;
+
+		/* This chip only supports 13 DRAM memory lines, but some devices
+		 * have 14 rows.  To deal with this, ignore the 14th address line
+		 * by limiting the number of rows (and columns) to 13.  This will
+		 * mean that for 14-row devices we will only be able to use
+		 * half of the memory, but it's better than nothing.
+		 */
+		if (rows > 13)
+			rows = 13;
+		if (columns > 13)
+			columns = 13;
+
+		pDramInfo->size =
+			((1 << (rows + columns)) * pDramInfo->width);
+		pDramInfo->size *= pDramInfo->banks;
+		pDramInfo->size >>= 3;
+
+		/* figure out which addr_mux configurations will support this device */
+		muxmask &= checkMuxSetting (rows, columns);
+		if (muxmask == 0)
+			return 0;
+
+		buffered = pDramInfo->buffered;
+		bursts &= pDramInfo->bursts;	/* union of all bursts */
+		if (pDramInfo->Trp > Trp)	/* worst case (longest) Trp */
+			Trp = pDramInfo->Trp;
+
+		if (pDramInfo->Trcd > Trcd)	/* worst case (longest) Trcd */
+			Trcd = pDramInfo->Trcd;
+
+		prefresh = pIdx;
+		/* worst case (shortest) Refresh period */
+		if (refresh > prefresh[pDramInfo->refresh & 7])
+			refresh = prefresh[pDramInfo->refresh & 7];
+
+	}			/* for loop */
+
+
+	/* We only allow a burst length of 8! */
+	if (!(bursts & 8))
+		bursts = 8;
+
+	/* Sort the devices.  In order to get each chip select region
+	 * aligned properly, put the biggest device at the lowest address.
+	 * A simple bubble sort will do the trick.
+	 */
+	for (banknum = 0, pDramInfo = &DramInfo[0];
+	     banknum < TOTAL_BANK; banknum++, pDramInfo++) {
+		int i;
+
+		for (i = 0; i < TOTAL_BANK; i++) {
+			if (pDramInfo->size < DramInfo[i].size &&
+			    pDramInfo->ordinal < DramInfo[i].ordinal) {
+				/* If the current bank is smaller, but if the ordinal is also
+				 * smaller, swap the ordinals
+				 */
+				u8 temp8;
+
+				temp8 = DramInfo[i].ordinal;
+				DramInfo[i].ordinal = pDramInfo->ordinal;
+				pDramInfo->ordinal = temp8;
+			}
+		}
+	}
+
+
+	/* Now figure out the base address for each bank.  While
+	 * we're at it, figure out how much memory there is.
+	 *
+	 */
+	size = 0;
+	for (banknum = 0; banknum < TOTAL_BANK; banknum++) {
+		int i;
+
+		for (i = 0; i < TOTAL_BANK; i++) {
+			if (DramInfo[i].ordinal == banknum
+			    && DramInfo[i].size != 0) {
+				DramInfo[i].base = size;
+				size += DramInfo[i].size;
+			}
+		}
+	}
+
+	/* Set up the Drive Strength register */
+	temp = ((DRIVE_STRENGTH_LOW << SDRAMDS_SBE_SHIFT)
+		| (DRIVE_STRENGTH_HIGH << SDRAMDS_SBC_SHIFT)
+		| (DRIVE_STRENGTH_LOW << SDRAMDS_SBA_SHIFT)
+		| (DRIVE_STRENGTH_OFF << SDRAMDS_SBS_SHIFT)
+		| (DRIVE_STRENGTH_LOW << SDRAMDS_SBD_SHIFT));
+	sysconf->sdramds = temp;
+
+	/* ********************** Cfg 1 ************************* */
+
+	/* Set the single read to read/write/precharge delay */
+	cfg_value = CFG1_SRD2RWP ((type == TYPE_DDR) ? 7 : 0xb);
+
+	/* Set the single write to read/write/precharge delay.
+	 * This may or may not be correct.  The controller spec
+	 * says "tWR", but "tWR" does not appear in the SPD.  It
+	 * always seems to be 15nsec for the class of device we're
+	 * using, which turns out to be 2 clock cycles at 133MHz,
+	 * so that's what we're going to use.
+	 *
+	 * HOWEVER, because of a bug in the controller, for DDR
+	 * we need to set this to be the same as the value
+	 * calculated for bwt2rwp.
+	 */
+	cfg_value |= CFG1_SWT2RWP ((type == TYPE_DDR) ? 7 : 2);
+
+	/* Set the Read CAS latency.  We're going to use a CL of
+	 * 2 for DDR and SDR.
+	 */
+	cfg_value |= CFG1_RLATENCY ((type == TYPE_DDR) ? 7 : 2);
+
+
+	/* Set the Active to Read/Write delay.  This depends
+	 * on Trcd which is reported as nanoseconds times 4.
+	 * We want to calculate Trcd (in nanoseconds) times XLB clock (in Hz)
+	 * which gives us a dimensionless quantity.  Play games with
+	 * the divisions so we don't run out of dynamic ranges.
+	 */
+	/* account for megaherz and the times 4 */
+	temp = (Trcd * (gd->bus_clk / 1000000)) / 4;
+
+	/* account for nanoseconds and round up, with a minimum value of 2 */
+	temp = ((temp + 999) / 1000) - 1;
+	if (temp < 2)
+		temp = 2;
+
+	cfg_value |= CFG1_ACT2WR (temp);
+
+	/* Set the precharge to active delay.  This depends
+	 * on Trp which is reported as nanoseconds times 4.
+	 * We want to calculate Trp (in nanoseconds) times XLB clock (in Hz)
+	 * which gives us a dimensionless quantity.  Play games with
+	 * the divisions so we don't run out of dynamic ranges.
+	 */
+	/* account for megaherz and the times 4 */
+	temp = (Trp * (gd->bus_clk / 1000000)) / 4;
+
+	/* account for nanoseconds and round up, then subtract 1, with a
+	 * minumum value of 1 and a maximum value of 7.
+	 */
+	temp = (((temp + 999) / 1000) - 1) & 7;
+	if (temp < 1)
+		temp = 1;
+
+	cfg_value |= CFG1_PRE2ACT (temp);
+
+	/* Set refresh to active delay.  This depends
+	 * on Trfc which is not reported in the SPD.
+	 * We'll use a nominal value of 75nsec which is
+	 * what the controller spec uses.
+	 */
+	temp = (75 * (gd->bus_clk / 1000000));
+	/* account for nanoseconds and round up, then subtract 1 */
+	cfg_value |= CFG1_REF2ACT (((temp + 999) / 1000) - 1);
+
+	/* Set the write latency, using the values given in the controller spec */
+	cfg_value |= CFG1_WLATENCY ((type == TYPE_DDR) ? 3 : 0);
+	memctl->cfg1 = cfg_value;	/* cfg 1 */
+	asm volatile ("sync");
+
+
+	/* ********************** Cfg 2 ************************* */
+
+	/* Set the burst read to read/precharge delay */
+	cfg_value = CFG2_BRD2RP ((type == TYPE_DDR) ? 5 : 8);
+
+	/* Set the burst write to read/precharge delay.  Semi-magic numbers
+	 * based on the controller spec recommendations, assuming tWR is
+	 * two clock cycles.
+	 */
+	cfg_value |= CFG2_BWT2RWP ((type == TYPE_DDR) ? 7 : 10);
+
+	/* Set the Burst read to write delay.  Semi-magic numbers
+	 * based on the DRAM controller documentation.
+	 */
+	cfg_value |= CFG2_BRD2WT ((type == TYPE_DDR) ? 7 : 0xb);
+
+	/* Set the burst length -- must be 8!! Well, 7, actually, becuase
+	 * it's burst lenght minus 1.
+	 */
+	cfg_value |= CFG2_BURSTLEN (7);
+	memctl->cfg2 = cfg_value;	/* cfg 2 */
+	asm volatile ("sync");
+
+
+	/* ********************** mode ************************* */
+
+	/* Set enable bit, CKE high/low bits, and the DDR/SDR mode bit,
+	 * disable automatic refresh.
+	 */
+	cfg_value = CTL_MODE_ENABLE | CTL_CKE_HIGH |
+		((type == TYPE_DDR) ? CTL_DDR_MODE : 0);
+
+	/* Set the address mux based on whichever setting(s) is/are common
+	 * to all the devices we have.  If there is more than one, choose
+	 * one arbitrarily.
+	 */
+	if (muxmask & 0x4)
+		cfg_value |= CTL_ADDRMUX (2);
+	else if (muxmask & 0x2)
+		cfg_value |= CTL_ADDRMUX (1);
+	else
+		cfg_value |= CTL_ADDRMUX (0);
+
+	/* Set the refresh interval. */
+	temp = ((refresh * (gd->bus_clk / 1000000)) / (1000 * 64)) - 1;
+	cfg_value |= CTL_REFRESH_INTERVAL (temp);
+
+	/* Set buffered/non-buffered memory */
+	if (buffered)
+		cfg_value |= CTL_BUFFERED;
+
+	memctl->ctrl = cfg_value;	/* ctrl */
+	asm volatile ("sync");
+
+	if (type == TYPE_DDR) {
+		/* issue precharge all */
+		temp = cfg_value | CTL_PRECHARGE_CMD;
+		memctl->ctrl = temp;	/* ctrl */
+		asm volatile ("sync");
+	}
+
+
+	/* Set up mode value for CAS latency == 2 */
+	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) |
+		      MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2) | MODE_CMD);
+
+	asm volatile ("sync");
+
+	/* Write Extended Mode  - enable DLL */
+	if (type == TYPE_DDR) {
+		temp = MODE_EXTENDED | MODE_X_DLL_ENABLE |
+			MODE_X_DS_NORMAL | MODE_CMD;
+		memctl->mode = (temp >> 16);	/* mode */
+		asm volatile ("sync");
+
+		/* Write Mode - reset DLL, set CAS latency == 2 */
+		temp = mode_value | MODE_OPMODE (MODE_OPMODE_RESETDLL);
+		memctl->mode = (temp >> 16);	/* mode */
+		asm volatile ("sync");
+	}
+
+	/* Program the chip selects. */
+	for (banknum = 0; banknum < TOTAL_BANK; banknum++) {
+		if (DramInfo[banknum].size != 0) {
+			u32 mask;
+			int i;
+
+			for (i = 0, mask = 1; i < 32; mask <<= 1, i++) {
+				if (DramInfo[banknum].size & mask)
+					break;
+			}
+			temp = (DramInfo[banknum].base & 0xfff00000) | (i -
+									1);
+
+			sysconf->cscfg[banknum] = temp;
+			asm volatile ("sync");
+		}
+	}
+
+	/* Wait for DLL lock */
+	udelay (200);
+
+	temp = cfg_value | CTL_PRECHARGE_CMD;	/* issue precharge all */
+	memctl->ctrl = temp;	/* ctrl */
+	asm volatile ("sync");
+
+	temp = cfg_value | CTL_REFRESH_CMD;	/* issue precharge all */
+	memctl->ctrl = temp;	/* ctrl */
+	asm volatile ("sync");
+
+	memctl->ctrl = temp;	/* ctrl */
+	asm volatile ("sync");
+
+	/* Write Mode - DLL normal */
+	temp = mode_value | MODE_OPMODE (MODE_OPMODE_NORMAL);
+	memctl->mode = (temp >> 16);	/* mode */
+	asm volatile ("sync");
+
+	/* Enable refresh, enable DQS's (if DDR), and lock the control register */
+	cfg_value &= ~CTL_MODE_ENABLE;	/* lock register */
+	cfg_value |= CTL_REFRESH_ENABLE;	/* enable refresh */
+
+	if (type == TYPE_DDR)
+		cfg_value |= CTL_DQSOEN (0xf);	/* enable DQS's for DDR */
+
+	memctl->ctrl = cfg_value;	/* ctrl */
+	asm volatile ("sync");
+
+	return size;
+}
diff --git a/cpu/mpc8220/dramSetup.h b/cpu/mpc8220/dramSetup.h
new file mode 100644
index 0000000..3b64e08
--- /dev/null
+++ b/cpu/mpc8220/dramSetup.h
@@ -0,0 +1,108 @@
+/*
+ * dramSetup.h
+ *
+ * Prototypes, etc. for the Motorola MPC8220
+ * embedded cpu chips
+ *
+ * 2004 (c) Freescale, Inc.
+ * Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __INCdramsetuph
+#define __INCdramsetuph
+#ifndef __ASSEMBLY__
+/* Where various things are in the SPD */
+#define LOC_TYPE                    2
+#define LOC_CHECKSUM                63
+#define LOC_PHYS_BANKS              5
+#define LOC_LOGICAL_BANKS           17
+#define LOC_ROWS                    3
+#define LOC_COLS                    4
+#define LOC_WIDTH_HIGH              7
+#define LOC_WIDTH_LOW               6
+#define LOC_REFRESH                 12
+#define LOC_BURSTS                  16
+#define LOC_CAS                     18
+#define LOC_CS                      19
+#define LOC_WE                      20
+#define LOC_Tcyc                    9
+#define LOC_Tac                     10
+#define LOC_Trp                     27
+#define LOC_Trrd                    28
+#define LOC_Trcd                    29
+#define LOC_Tras                    30
+#define LOC_Buffered                21
+/* Types of memory the SPD can tell us about.
+ * We can actually only use SDRAM and DDR.
+ */
+#define TYPE_DRAM                   1	/* plain old dram */
+#define TYPE_EDO                    2	/* EDO dram */
+#define TYPE_Nibble                 3	/* serial nibble memory */
+#define TYPE_SDR                    4	/* SDRAM */
+#define TYPE_ROM                    5	/*  */
+#define TYPE_SGRRAM                 6	/* graphics memory */
+#define TYPE_DDR                    7	/* DDR sdram */
+#define SDRAMDS_MASK        0x3	/* each field is 2 bits wide */
+#define SDRAMDS_SBE_SHIFT     8	/* Clock enable drive strength */
+#define SDRAMDS_SBC_SHIFT     6	/* Clocks drive strength */
+#define SDRAMDS_SBA_SHIFT     4	/* Address drive strength */
+#define SDRAMDS_SBS_SHIFT     2	/* SDR DQS drive strength */
+#define SDRAMDS_SBD_SHIFT     0	/* Data and DQS drive strength */
+#define  DRIVE_STRENGTH_HIGH 0
+#define  DRIVE_STRENGTH_MED  1
+#define  DRIVE_STRENGTH_LOW  2
+#define  DRIVE_STRENGTH_OFF  3
+
+#define OK      0
+#define ERROR   -1
+/* Structure to hold information about address muxing. */
+	typedef struct tagMuxDescriptor {
+	u8 MuxValue;
+	u8 Columns;
+	u8 Rows;
+	u8 MoreColumns;
+} muxdesc_t;
+
+/* Structure to define one physical bank of
+ * memory.  Note that dram size in bytes is
+ * (2^^(rows+columns)) * width * banks / 8
+*/
+typedef struct tagDramInfo {
+	u32 size;		/* size in bytes */
+	u32 base;		/* base address */
+	u8 ordinal;		/* where in the memory map will we put this */
+	u8 type;
+	u8 rows;
+	u8 cols;
+	u16 width;		/* width of each chip in bits */
+	u8 banks;		/* number of chips, aka logical banks */
+	u8 bursts;		/* bit-encoded allowable burst length */
+	u8 CAS;			/* bit-encoded CAS latency values */
+	u8 CS;			/* bit-encoded CS latency values */
+	u8 WE;			/* bit-encoded WE latency values */
+	u8 Trp;			/* bit-encoded row precharge time */
+	u8 Trcd;		/* bit-encoded RAS to CAS delay */
+	u8 buffered;		/* buffered or not */
+	u8 refresh;		/* encoded refresh rate */
+} draminfo_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __INCdramsetuph */
diff --git a/cpu/mpc8220/fec.c b/cpu/mpc8220/fec.c
new file mode 100644
index 0000000..1bc51cd
--- /dev/null
+++ b/cpu/mpc8220/fec.c
@@ -0,0 +1,993 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.c,
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include "dma.h"
+#include "fec.h"
+
+#define DEBUG	0
+/*tbd - rtm */
+/*#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+    defined(CONFIG_MPC8220_FEC)*/
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+
+#if (DEBUG & 0x60)
+static void tfifo_print (mpc8220_fec_priv * fec);
+static void rfifo_print (mpc8220_fec_priv * fec);
+#endif /* DEBUG */
+
+#if (DEBUG & 0x40)
+static u32 local_crc32 (char *string, unsigned int crc_value, int len);
+#endif
+
+typedef struct {
+	u8 data[1500];		/* actual data */
+	int length;		/* actual length */
+	int used;		/* buffer in use or not */
+	u8 head[16];		/* MAC header(6 + 6 + 2) + 2(aligned) */
+} NBUF;
+
+/********************************************************************/
+#if (DEBUG & 0x2)
+static void mpc8220_fec_phydump (void)
+{
+	u16 phyStatus, i;
+	u8 phyAddr = CONFIG_PHY_ADDR;
+	u8 reg_mask[] = {
+#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
+		/* regs to print: 0...7, 16...19, 21, 23, 24 */
+		1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+#else
+		/* regs to print: 0...8, 16...20 */
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+		1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+	};
+
+	for (i = 0; i < 32; i++) {
+		if (reg_mask[i]) {
+			miiphy_read (phyAddr, i, &phyStatus);
+			printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
+		}
+	}
+}
+#endif
+
+/********************************************************************/
+static int mpc8220_fec_rbd_init (mpc8220_fec_priv * fec)
+{
+	int ix;
+	char *data;
+	static int once = 0;
+
+	for (ix = 0; ix < FEC_RBD_NUM; ix++) {
+		if (!once) {
+			data = (char *) malloc (FEC_MAX_PKT_SIZE);
+			if (data == NULL) {
+				printf ("RBD INIT FAILED\n");
+				return -1;
+			}
+			fec->rbdBase[ix].dataPointer = (u32) data;
+		}
+		fec->rbdBase[ix].status = FEC_RBD_EMPTY;
+		fec->rbdBase[ix].dataLength = 0;
+	}
+	once++;
+
+	/*
+	 * have the last RBD to close the ring
+	 */
+	fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP;
+	fec->rbdIndex = 0;
+
+	return 0;
+}
+
+/********************************************************************/
+static void mpc8220_fec_tbd_init (mpc8220_fec_priv * fec)
+{
+	int ix;
+
+	for (ix = 0; ix < FEC_TBD_NUM; ix++) {
+		fec->tbdBase[ix].status = 0;
+	}
+
+	/*
+	 * Have the last TBD to close the ring
+	 */
+	fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP;
+
+	/*
+	 * Initialize some indices
+	 */
+	fec->tbdIndex = 0;
+	fec->usedTbdIndex = 0;
+	fec->cleanTbdNum = FEC_TBD_NUM;
+}
+
+/********************************************************************/
+static void mpc8220_fec_rbd_clean (mpc8220_fec_priv * fec, FEC_RBD * pRbd)
+{
+	/*
+	 * Reset buffer descriptor as empty
+	 */
+	if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
+		pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
+	else
+		pRbd->status = FEC_RBD_EMPTY;
+
+	pRbd->dataLength = 0;
+
+	/*
+	 * Now, we have an empty RxBD, restart the SmartDMA receive task
+	 */
+	DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
+
+	/*
+	 * Increment BD count
+	 */
+	fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
+}
+
+/********************************************************************/
+static void mpc8220_fec_tbd_scrub (mpc8220_fec_priv * fec)
+{
+	FEC_TBD *pUsedTbd;
+
+#if (DEBUG & 0x1)
+	printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
+		fec->cleanTbdNum, fec->usedTbdIndex);
+#endif
+
+	/*
+	 * process all the consumed TBDs
+	 */
+	while (fec->cleanTbdNum < FEC_TBD_NUM) {
+		pUsedTbd = &fec->tbdBase[fec->usedTbdIndex];
+		if (pUsedTbd->status & FEC_TBD_READY) {
+#if (DEBUG & 0x20)
+			printf ("Cannot clean TBD %d, in use\n",
+				fec->cleanTbdNum);
+#endif
+			return;
+		}
+
+		/*
+		 * clean this buffer descriptor
+		 */
+		if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
+			pUsedTbd->status = FEC_TBD_WRAP;
+		else
+			pUsedTbd->status = 0;
+
+		/*
+		 * update some indeces for a correct handling of the TBD ring
+		 */
+		fec->cleanTbdNum++;
+		fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
+	}
+}
+
+/********************************************************************/
+static void mpc8220_fec_set_hwaddr (mpc8220_fec_priv * fec, char *mac)
+{
+	u8 currByte;		/* byte for which to compute the CRC */
+	int byte;		/* loop - counter */
+	int bit;		/* loop - counter */
+	u32 crc = 0xffffffff;	/* initial value */
+
+	/*
+	 * The algorithm used is the following:
+	 * we loop on each of the six bytes of the provided address,
+	 * and we compute the CRC by left-shifting the previous
+	 * value by one position, so that each bit in the current
+	 * byte of the address may contribute the calculation. If
+	 * the latter and the MSB in the CRC are different, then
+	 * the CRC value so computed is also ex-ored with the
+	 * "polynomium generator". The current byte of the address
+	 * is also shifted right by one bit at each iteration.
+	 * This is because the CRC generatore in hardware is implemented
+	 * as a shift-register with as many ex-ores as the radixes
+	 * in the polynomium. This suggests that we represent the
+	 * polynomiumm itself as a 32-bit constant.
+	 */
+	for (byte = 0; byte < 6; byte++) {
+		currByte = mac[byte];
+		for (bit = 0; bit < 8; bit++) {
+			if ((currByte & 0x01) ^ (crc & 0x01)) {
+				crc >>= 1;
+				crc = crc ^ 0xedb88320;
+			} else {
+				crc >>= 1;
+			}
+			currByte >>= 1;
+		}
+	}
+
+	crc = crc >> 26;
+
+	/*
+	 * Set individual hash table register
+	 */
+	if (crc >= 32) {
+		fec->eth->iaddr1 = (1 << (crc - 32));
+		fec->eth->iaddr2 = 0;
+	} else {
+		fec->eth->iaddr1 = 0;
+		fec->eth->iaddr2 = (1 << crc);
+	}
+
+	/*
+	 * Set physical address
+	 */
+	fec->eth->paddr1 =
+		(mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
+	fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
+}
+
+/********************************************************************/
+static int mpc8220_fec_init (struct eth_device *dev, bd_t * bis)
+{
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	struct mpc8220_dma *dma = (struct mpc8220_dma *) MMAP_DMA;
+	const u8 phyAddr = CONFIG_PHY_ADDR;	/* Only one PHY */
+
+#if (DEBUG & 0x1)
+	printf ("mpc8220_fec_init... Begin\n");
+#endif
+
+	/*
+	 * Initialize RxBD/TxBD rings
+	 */
+	mpc8220_fec_rbd_init (fec);
+	mpc8220_fec_tbd_init (fec);
+
+	/*
+	 * Set up Pin Muxing for FEC 1
+	 */
+	*(vu_long *) MMAP_PCFG = 0;
+	*(vu_long *) (MMAP_PCFG + 4) = 0;
+	/*
+	 * Clear FEC-Lite interrupt event register(IEVENT)
+	 */
+	fec->eth->ievent = 0xffffffff;
+
+	/*
+	 * Set interrupt mask register
+	 */
+	fec->eth->imask = 0x00000000;
+
+	/*
+	 * Set FEC-Lite receive control register(R_CNTRL):
+	 */
+	if (fec->xcv_type == SEVENWIRE) {
+		/*
+		 * Frame length=1518; 7-wire mode
+		 */
+		fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */
+	} else {
+		/*
+		 * Frame length=1518; MII mode;
+		 */
+		fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
+	}
+
+	fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
+	if (fec->xcv_type != SEVENWIRE) {
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		/* tbd - rtm */
+		/*fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); */
+		/* No MII for 7-wire mode */
+		fec->eth->mii_speed = 0x00000030;
+	}
+
+	/*
+	 * Set Opcode/Pause Duration Register
+	 */
+	fec->eth->op_pause = 0x00010020;	/*FIXME0xffff0020; */
+
+	/*
+	 * Set Rx FIFO alarm and granularity value
+	 */
+	fec->eth->rfifo_cntrl = 0x0c000000;
+	fec->eth->rfifo_alarm = 0x0000030c;
+#if (DEBUG & 0x22)
+	if (fec->eth->rfifo_status & 0x00700000) {
+		printf ("mpc8220_fec_init() RFIFO error\n");
+	}
+#endif
+
+	/*
+	 * Set Tx FIFO granularity value
+	 */
+	/*fec->eth->tfifo_cntrl = 0x0c000000; */ /*tbd - rtm */
+	fec->eth->tfifo_cntrl = 0x0e000000;
+#if (DEBUG & 0x2)
+	printf ("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
+	printf ("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
+#endif
+
+	/*
+	 * Set transmit fifo watermark register(X_WMRK), default = 64
+	 */
+	fec->eth->tfifo_alarm = 0x00000080;
+	fec->eth->x_wmrk = 0x2;
+
+	/*
+	 * Set individual address filter for unicast address
+	 * and set physical address registers.
+	 */
+	mpc8220_fec_set_hwaddr (fec, dev->enetaddr);
+
+	/*
+	 * Set multicast address filter
+	 */
+	fec->eth->gaddr1 = 0x00000000;
+	fec->eth->gaddr2 = 0x00000000;
+
+	/*
+	 * Turn ON cheater FSM: ????
+	 */
+	fec->eth->xmit_fsm = 0x03000000;
+
+#if 1
+/*#if defined(CONFIG_MPC5200)*/
+	/*
+	 * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't
+	 * work w/ the current receive task.
+	 */
+	dma->PtdCntrl |= 0x00000001;
+#endif
+
+	/*
+	 * Set priority of different initiators
+	 */
+	dma->IPR0 = 7;		/* always */
+	dma->IPR3 = 6;		/* Eth RX */
+	dma->IPR4 = 5;		/* Eth Tx */
+
+	/*
+	 * Clear SmartDMA task interrupt pending bits
+	 */
+	DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+
+	/*
+	 * Initialize SmartDMA parameters stored in SRAM
+	 */
+	*(int *) FEC_TBD_BASE = (int) fec->tbdBase;
+	*(int *) FEC_RBD_BASE = (int) fec->rbdBase;
+	*(int *) FEC_TBD_NEXT = (int) fec->tbdBase;
+	*(int *) FEC_RBD_NEXT = (int) fec->rbdBase;
+
+	if (fec->xcv_type != SEVENWIRE) {
+		/*
+		 * Initialize PHY(LXT971A):
+		 *
+		 *   Generally, on power up, the LXT971A reads its configuration
+		 *   pins to check for forced operation, If not cofigured for
+		 *   forced operation, it uses auto-negotiation/parallel detection
+		 *   to automatically determine line operating conditions.
+		 *   If the PHY device on the other side of the link supports
+		 *   auto-negotiation, the LXT971A auto-negotiates with it
+		 *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
+		 *   support auto-negotiation, the LXT971A automatically detects
+		 *   the presence of either link pulses(10Mbps PHY) or Idle
+		 *   symbols(100Mbps) and sets its operating conditions accordingly.
+		 *
+		 *   When auto-negotiation is controlled by software, the following
+		 *   steps are recommended.
+		 *
+		 * Note:
+		 *   The physical address is dependent on hardware configuration.
+		 *
+		 */
+		int timeout = 1;
+		u16 phyStatus;
+
+		/*
+		 * Reset PHY, then delay 300ns
+		 */
+		miiphy_write (phyAddr, 0x0, 0x8000);
+		udelay (1000);
+
+		if (fec->xcv_type == MII10) {
+			/*
+			 * Force 10Base-T, FDX operation
+			 */
+#if (DEBUG & 0x2)
+			printf ("Forcing 10 Mbps ethernet link... ");
+#endif
+			miiphy_read (phyAddr, 0x1, &phyStatus);
+			/*
+			   miiphy_write(fec, phyAddr, 0x0, 0x0100);
+			 */
+			miiphy_write (phyAddr, 0x0, 0x0180);
+
+			timeout = 20;
+			do {	/* wait for link status to go down */
+				udelay (10000);
+				if ((timeout--) == 0) {
+#if (DEBUG & 0x2)
+					printf ("hmmm, should not have waited...");
+#endif
+					break;
+				}
+				miiphy_read (phyAddr, 0x1, &phyStatus);
+#if (DEBUG & 0x2)
+				printf ("=");
+#endif
+			} while ((phyStatus & 0x0004)); /* !link up */
+
+			timeout = 1000;
+			do {	/* wait for link status to come back up */
+				udelay (10000);
+				if ((timeout--) == 0) {
+					printf ("failed. Link is down.\n");
+					break;
+				}
+				miiphy_read (phyAddr, 0x1, &phyStatus);
+#if (DEBUG & 0x2)
+				printf ("+");
+#endif
+			} while (!(phyStatus & 0x0004));	/* !link up */
+
+#if (DEBUG & 0x2)
+			printf ("done.\n");
+#endif
+		} else {	/* MII100 */
+			/*
+			 * Set the auto-negotiation advertisement register bits
+			 */
+			miiphy_write (phyAddr, 0x4, 0x01e1);
+
+			/*
+			 * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
+			 */
+			miiphy_write (phyAddr, 0x0, 0x1200);
+
+			/*
+			 * Wait for AN completion
+			 */
+			timeout = 5000;
+			do {
+				udelay (1000);
+
+				if ((timeout--) == 0) {
+#if (DEBUG & 0x2)
+					printf ("PHY auto neg 0 failed...\n");
+#endif
+					return -1;
+				}
+
+				if (miiphy_read (phyAddr, 0x1, &phyStatus) !=
+				    0) {
+#if (DEBUG & 0x2)
+					printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
+#endif
+					return -1;
+				}
+			} while (!(phyStatus & 0x0004));
+
+#if (DEBUG & 0x2)
+			printf ("PHY auto neg complete! \n");
+#endif
+		}
+
+	}
+
+	/*
+	 * Enable FEC-Lite controller
+	 */
+	fec->eth->ecntrl |= 0x00000006;
+
+#if (DEBUG & 0x2)
+	if (fec->xcv_type != SEVENWIRE)
+		mpc8220_fec_phydump ();
+#endif
+
+	/*
+	 * Enable SmartDMA receive task
+	 */
+	DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
+
+#if (DEBUG & 0x1)
+	printf ("mpc8220_fec_init... Done \n");
+#endif
+
+	return 1;
+}
+
+/********************************************************************/
+static void mpc8220_fec_halt (struct eth_device *dev)
+{
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	int counter = 0xffff;
+
+#if (DEBUG & 0x2)
+	if (fec->xcv_type != SEVENWIRE)
+		mpc8220_fec_phydump ();
+#endif
+
+	/*
+	 * mask FEC chip interrupts
+	 */
+	fec->eth->imask = 0;
+
+	/*
+	 * issue graceful stop command to the FEC transmitter if necessary
+	 */
+	fec->eth->x_cntrl |= 0x00000001;
+
+	/*
+	 * wait for graceful stop to register
+	 */
+	while ((counter--) && (!(fec->eth->ievent & 0x10000000)));
+
+	/*
+	 * Disable SmartDMA tasks
+	 */
+	DMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
+	DMA_TASK_DISABLE (FEC_RECV_TASK_NO);
+
+	/*
+	 * Disable the Ethernet Controller
+	 */
+	fec->eth->ecntrl &= 0xfffffffd;
+
+	/*
+	 * Clear FIFO status registers
+	 */
+	fec->eth->rfifo_status &= 0x00700000;
+	fec->eth->tfifo_status &= 0x00700000;
+
+	fec->eth->reset_cntrl = 0x01000000;
+
+	/*
+	 * Issue a reset command to the FEC chip
+	 */
+	fec->eth->ecntrl |= 0x1;
+
+	/*
+	 * wait at least 16 clock cycles
+	 */
+	udelay (10);
+
+#if (DEBUG & 0x3)
+	printf ("Ethernet task stopped\n");
+#endif
+}
+
+#if (DEBUG & 0x60)
+/********************************************************************/
+
+static void tfifo_print (mpc8220_fec_priv * fec)
+{
+	u16 phyAddr = CONFIG_PHY_ADDR;
+	u16 phyStatus;
+
+	if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
+	    || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
+
+		miiphy_read (phyAddr, 0x1, &phyStatus);
+		printf ("\nphyStatus: 0x%04x\n", phyStatus);
+		printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl);
+		printf ("ievent:   0x%08x\n", fec->eth->ievent);
+		printf ("x_status: 0x%08x\n", fec->eth->x_status);
+		printf ("tfifo: status	0x%08x\n", fec->eth->tfifo_status);
+
+		printf ("	control 0x%08x\n", fec->eth->tfifo_cntrl);
+		printf ("	lrfp	0x%08x\n", fec->eth->tfifo_lrf_ptr);
+		printf ("	lwfp	0x%08x\n", fec->eth->tfifo_lwf_ptr);
+		printf ("	alarm	0x%08x\n", fec->eth->tfifo_alarm);
+		printf ("	readptr 0x%08x\n", fec->eth->tfifo_rdptr);
+		printf ("	writptr 0x%08x\n", fec->eth->tfifo_wrptr);
+	}
+}
+
+static void rfifo_print (mpc8220_fec_priv * fec)
+{
+	u16 phyAddr = CONFIG_PHY_ADDR;
+	u16 phyStatus;
+
+	if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
+	    || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
+
+		miiphy_read (phyAddr, 0x1, &phyStatus);
+		printf ("\nphyStatus: 0x%04x\n", phyStatus);
+		printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl);
+		printf ("ievent:   0x%08x\n", fec->eth->ievent);
+		printf ("x_status: 0x%08x\n", fec->eth->x_status);
+		printf ("rfifo: status	0x%08x\n", fec->eth->rfifo_status);
+
+		printf ("	control 0x%08x\n", fec->eth->rfifo_cntrl);
+		printf ("	lrfp	0x%08x\n", fec->eth->rfifo_lrf_ptr);
+		printf ("	lwfp	0x%08x\n", fec->eth->rfifo_lwf_ptr);
+		printf ("	alarm	0x%08x\n", fec->eth->rfifo_alarm);
+		printf ("	readptr 0x%08x\n", fec->eth->rfifo_rdptr);
+		printf ("	writptr 0x%08x\n", fec->eth->rfifo_wrptr);
+	}
+}
+#endif /* DEBUG */
+
+/********************************************************************/
+
+static int mpc8220_fec_send (struct eth_device *dev, volatile void *eth_data,
+			     int data_length)
+{
+	/*
+	 * This routine transmits one frame.  This routine only accepts
+	 * 6-byte Ethernet addresses.
+	 */
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	FEC_TBD *pTbd;
+
+#if (DEBUG & 0x20)
+	printf ("tbd status: 0x%04x\n", fec->tbdBase[0].status);
+	tfifo_print (fec);
+#endif
+
+	/*
+	 * Clear Tx BD ring at first
+	 */
+	mpc8220_fec_tbd_scrub (fec);
+
+	/*
+	 * Check for valid length of data.
+	 */
+	if ((data_length > 1500) || (data_length <= 0)) {
+		return -1;
+	}
+
+	/*
+	 * Check the number of vacant TxBDs.
+	 */
+	if (fec->cleanTbdNum < 1) {
+#if (DEBUG & 0x20)
+		printf ("No available TxBDs ...\n");
+#endif
+		return -1;
+	}
+
+	/*
+	 * Get the first TxBD to send the mac header
+	 */
+	pTbd = &fec->tbdBase[fec->tbdIndex];
+	pTbd->dataLength = data_length;
+	pTbd->dataPointer = (u32) eth_data;
+	pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+	fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
+
+#if (DEBUG & 0x100)
+	printf ("DMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
+#endif
+
+	/*
+	 * Kick the MII i/f
+	 */
+	if (fec->xcv_type != SEVENWIRE) {
+		u16 phyStatus;
+
+		miiphy_read (0, 0x1, &phyStatus);
+	}
+
+	/*
+	 * Enable SmartDMA transmit task
+	 */
+
+#if (DEBUG & 0x20)
+	tfifo_print (fec);
+#endif
+
+	DMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
+
+#if (DEBUG & 0x20)
+	tfifo_print (fec);
+#endif
+
+#if (DEBUG & 0x8)
+	printf ("+");
+#endif
+
+	fec->cleanTbdNum -= 1;
+
+#if (DEBUG & 0x129) && (DEBUG & 0x80000000)
+	printf ("smartDMA ethernet Tx task enabled\n");
+#endif
+	/*
+	 * wait until frame is sent .
+	 */
+	while (pTbd->status & FEC_TBD_READY) {
+		udelay (10);
+#if (DEBUG & 0x8)
+		printf ("TDB status = %04x\n", pTbd->status);
+#endif
+	}
+
+	return 0;
+}
+
+
+/********************************************************************/
+static int mpc8220_fec_recv (struct eth_device *dev)
+{
+	/*
+	 * This command pulls one frame from the card
+	 */
+	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+	FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
+	unsigned long ievent;
+	int frame_length, len = 0;
+	NBUF *frame;
+
+#if (DEBUG & 0x1)
+	printf ("mpc8220_fec_recv %d Start...\n", fec->rbdIndex);
+#endif
+#if (DEBUG & 0x8)
+	printf ("-");
+#endif
+
+	/*
+	 * Check if any critical events have happened
+	 */
+	ievent = fec->eth->ievent;
+	fec->eth->ievent = ievent;
+	if (ievent & 0x20060000) {
+		/* BABT, Rx/Tx FIFO errors */
+		mpc8220_fec_halt (dev);
+		mpc8220_fec_init (dev, NULL);
+		return 0;
+	}
+	if (ievent & 0x80000000) {
+		/* Heartbeat error */
+		fec->eth->x_cntrl |= 0x00000001;
+	}
+	if (ievent & 0x10000000) {
+		/* Graceful stop complete */
+		if (fec->eth->x_cntrl & 0x00000001) {
+			mpc8220_fec_halt (dev);
+			fec->eth->x_cntrl &= ~0x00000001;
+			mpc8220_fec_init (dev, NULL);
+		}
+	}
+
+	if (!(pRbd->status & FEC_RBD_EMPTY)) {
+		if ((pRbd->status & FEC_RBD_LAST)
+		    && !(pRbd->status & FEC_RBD_ERR)
+		    && ((pRbd->dataLength - 4) > 14)) {
+
+			/*
+			 * Get buffer address and size
+			 */
+			frame = (NBUF *) pRbd->dataPointer;
+			frame_length = pRbd->dataLength - 4;
+
+#if (0)
+			{
+				int i;
+
+				printf ("recv data hdr:");
+				for (i = 0; i < 14; i++)
+					printf ("%x ", *(frame->head + i));
+				printf ("\n");
+			}
+#endif
+			/*
+			 *  Fill the buffer and pass it to upper layers
+			 */
+/*			memcpy(buff, frame->head, 14);
+			memcpy(buff + 14, frame->data, frame_length);*/
+			NetReceive ((volatile uchar *) pRbd->dataPointer,
+				    frame_length);
+			len = frame_length;
+		}
+		/*
+		 * Reset buffer descriptor as empty
+		 */
+		mpc8220_fec_rbd_clean (fec, pRbd);
+	}
+	DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+	return len;
+}
+
+
+/********************************************************************/
+int mpc8220_fec_initialize (bd_t * bis)
+{
+	mpc8220_fec_priv *fec;
+
+#ifdef CONFIG_ETH1ADDR
+	mpc8220_fec_priv *fec2;
+#endif
+	struct eth_device *dev;
+	char *tmp, *end;
+	char env_enetaddr[6];
+
+#ifdef CONFIG_ETH1ADDR
+	char env_enet1addr[6];
+#endif
+	int i;
+
+	fec = (mpc8220_fec_priv *) malloc (sizeof (*fec));
+	dev = (struct eth_device *) malloc (sizeof (*dev));
+	memset (dev, 0, sizeof *dev);
+
+	fec->eth = (ethernet_regs *) MMAP_FEC1;
+#ifdef CONFIG_ETH1ADDR
+	fec2 = (mpc8220_fec_priv *) malloc (sizeof (*fec));
+	fec2->eth = (ethernet_regs *) MMAP_FEC2;
+#endif
+	fec->tbdBase = (FEC_TBD *) FEC_BD_BASE;
+	fec->rbdBase =
+		(FEC_RBD *) (FEC_BD_BASE + FEC_TBD_NUM * sizeof (FEC_TBD));
+	fec->xcv_type = MII100;
+
+	dev->priv = (void *) fec;
+	dev->iobase = MMAP_FEC1;
+	dev->init = mpc8220_fec_init;
+	dev->halt = mpc8220_fec_halt;
+	dev->send = mpc8220_fec_send;
+	dev->recv = mpc8220_fec_recv;
+
+	sprintf (dev->name, "FEC ETHERNET");
+	eth_register (dev);
+
+	/*
+	 * Try to set the mac address now. The fec mac address is
+	 * a garbage after reset. When not using fec for booting
+	 * the Linux fec driver will try to work with this garbage.
+	 */
+	tmp = getenv ("ethaddr");
+	if (tmp) {
+		for (i = 0; i < 6; i++) {
+			env_enetaddr[i] =
+				tmp ? simple_strtoul (tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+		mpc8220_fec_set_hwaddr (fec, env_enetaddr);
+	}
+#ifdef CONFIG_ETH1ADDR
+	tmp = getenv ("eth1addr");
+	if (tmp) {
+		for (i = 0; i < 6; i++) {
+			env_enet1addr[i] =
+				tmp ? simple_strtoul (tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+		mpc8220_fec_set_hwaddr (fec2, env_enet1addr);
+	}
+#endif
+
+	return 1;
+}
+
+/* MII-interface related functions */
+/********************************************************************/
+int miiphy_read (u8 phyAddr, u8 regAddr, u16 * retVal)
+{
+	ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1;
+	u32 reg;		/* convenient holder for the PHY register */
+	u32 phy;		/* convenient holder for the PHY */
+	int timeout = 0xffff;
+
+	/*
+	 * reading from any PHY's register is done by properly
+	 * programming the FEC's MII data register.
+	 */
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	eth->mii_data =
+		(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy
+		 | reg);
+
+	/*
+	 * wait for the related interrupt
+	 */
+	while ((timeout--) && (!(eth->ievent & 0x00800000)));
+
+	if (timeout == 0) {
+#if (DEBUG & 0x2)
+		printf ("Read MDIO failed...\n");
+#endif
+		return -1;
+	}
+
+	/*
+	 * clear mii interrupt bit
+	 */
+	eth->ievent = 0x00800000;
+
+	/*
+	 * it's now safe to read the PHY's register
+	 */
+	*retVal = (u16) eth->mii_data;
+
+	return 0;
+}
+
+/********************************************************************/
+int miiphy_write (u8 phyAddr, u8 regAddr, u16 data)
+{
+	ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1;
+	u32 reg;		/* convenient holder for the PHY register */
+	u32 phy;		/* convenient holder for the PHY */
+	int timeout = 0xffff;
+
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+			 FEC_MII_DATA_TA | phy | reg | data);
+
+	/*
+	 * wait for the MII interrupt
+	 */
+	while ((timeout--) && (!(eth->ievent & 0x00800000)));
+
+	if (timeout == 0) {
+#if (DEBUG & 0x2)
+		printf ("Write MDIO failed...\n");
+#endif
+		return -1;
+	}
+
+	/*
+	 * clear MII interrupt bit
+	 */
+	eth->ievent = 0x00800000;
+
+	return 0;
+}
+
+#if (DEBUG & 0x40)
+static u32 local_crc32 (char *string, unsigned int crc_value, int len)
+{
+	int i;
+	char c;
+	unsigned int crc, count;
+
+	/*
+	 * crc32 algorithm
+	 */
+	/*
+	 * crc = 0xffffffff; * The initialized value should be 0xffffffff
+	 */
+	crc = crc_value;
+
+	for (i = len; --i >= 0;) {
+		c = *string++;
+		for (count = 0; count < 8; count++) {
+			if ((c & 0x01) ^ (crc & 0x01)) {
+				crc >>= 1;
+				crc = crc ^ 0xedb88320;
+			} else {
+				crc >>= 1;
+			}
+			c >>= 1;
+		}
+	}
+
+	/*
+	 * In big endian system, do byte swaping for crc value
+	 */
+	return crc;
+}
+#endif /* DEBUG */
+
+#endif /* CONFIG_MPC8220_FEC */
diff --git a/cpu/mpc8220/fec.h b/cpu/mpc8220/fec.h
new file mode 100644
index 0000000..a8927fc
--- /dev/null
+++ b/cpu/mpc8220/fec.h
@@ -0,0 +1,283 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * odin ethernet header file
+ */
+
+#ifndef __MPC8220_FEC_H
+#define __MPC8220_FEC_H
+
+#include <common.h>
+#include <mpc8220.h>
+#include "dma.h"
+
+typedef struct ethernet_register_set {
+
+/* [10:2]addr = 00 */
+
+/*  Control and status Registers (offset 000-1FF) */
+
+	volatile u32 fec_id;		/* MBAR_ETH + 0x000 */
+	volatile u32 ievent;		/* MBAR_ETH + 0x004 */
+	volatile u32 imask;		/* MBAR_ETH + 0x008 */
+
+	volatile u32 RES0[1];		/* MBAR_ETH + 0x00C */
+	volatile u32 r_des_active;	/* MBAR_ETH + 0x010 */
+	volatile u32 x_des_active;	/* MBAR_ETH + 0x014 */
+	volatile u32 r_des_active_cl;	/* MBAR_ETH + 0x018 */
+	volatile u32 x_des_active_cl;	/* MBAR_ETH + 0x01C */
+	volatile u32 ivent_set;		/* MBAR_ETH + 0x020 */
+	volatile u32 ecntrl;		/* MBAR_ETH + 0x024 */
+
+	volatile u32 RES1[6];		/* MBAR_ETH + 0x028-03C */
+	volatile u32 mii_data;		/* MBAR_ETH + 0x040 */
+	volatile u32 mii_speed;		/* MBAR_ETH + 0x044 */
+	volatile u32 mii_status;	/* MBAR_ETH + 0x048 */
+
+	volatile u32 RES2[5];		/* MBAR_ETH + 0x04C-05C */
+	volatile u32 mib_data;		/* MBAR_ETH + 0x060 */
+	volatile u32 mib_control;	/* MBAR_ETH + 0x064 */
+
+	volatile u32 RES3[6];		/* MBAR_ETH + 0x068-7C */
+	volatile u32 r_activate;	/* MBAR_ETH + 0x080 */
+	volatile u32 r_cntrl;		/* MBAR_ETH + 0x084 */
+	volatile u32 r_hash;		/* MBAR_ETH + 0x088 */
+	volatile u32 r_data;		/* MBAR_ETH + 0x08C */
+	volatile u32 ar_done;		/* MBAR_ETH + 0x090 */
+	volatile u32 r_test;		/* MBAR_ETH + 0x094 */
+	volatile u32 r_mib;		/* MBAR_ETH + 0x098 */
+	volatile u32 r_da_low;		/* MBAR_ETH + 0x09C */
+	volatile u32 r_da_high;		/* MBAR_ETH + 0x0A0 */
+
+	volatile u32 RES4[7];		/* MBAR_ETH + 0x0A4-0BC */
+	volatile u32 x_activate;	/* MBAR_ETH + 0x0C0 */
+	volatile u32 x_cntrl;		/* MBAR_ETH + 0x0C4 */
+	volatile u32 backoff;		/* MBAR_ETH + 0x0C8 */
+	volatile u32 x_data;		/* MBAR_ETH + 0x0CC */
+	volatile u32 x_status;		/* MBAR_ETH + 0x0D0 */
+	volatile u32 x_mib;		/* MBAR_ETH + 0x0D4 */
+	volatile u32 x_test;		/* MBAR_ETH + 0x0D8 */
+	volatile u32 fdxfc_da1;		/* MBAR_ETH + 0x0DC */
+	volatile u32 fdxfc_da2;		/* MBAR_ETH + 0x0E0 */
+	volatile u32 paddr1;		/* MBAR_ETH + 0x0E4 */
+	volatile u32 paddr2;		/* MBAR_ETH + 0x0E8 */
+	volatile u32 op_pause;		/* MBAR_ETH + 0x0EC */
+
+	volatile u32 RES5[4];		/* MBAR_ETH + 0x0F0-0FC */
+	volatile u32 instr_reg;		/* MBAR_ETH + 0x100 */
+	volatile u32 context_reg;	/* MBAR_ETH + 0x104 */
+	volatile u32 test_cntrl;	/* MBAR_ETH + 0x108 */
+	volatile u32 acc_reg;		/* MBAR_ETH + 0x10C */
+	volatile u32 ones;		/* MBAR_ETH + 0x110 */
+	volatile u32 zeros;		/* MBAR_ETH + 0x114 */
+	volatile u32 iaddr1;		/* MBAR_ETH + 0x118 */
+	volatile u32 iaddr2;		/* MBAR_ETH + 0x11C */
+	volatile u32 gaddr1;		/* MBAR_ETH + 0x120 */
+	volatile u32 gaddr2;		/* MBAR_ETH + 0x124 */
+	volatile u32 random;		/* MBAR_ETH + 0x128 */
+	volatile u32 rand1;		/* MBAR_ETH + 0x12C */
+	volatile u32 tmp;		/* MBAR_ETH + 0x130 */
+
+	volatile u32 RES6[3];		/* MBAR_ETH + 0x134-13C */
+	volatile u32 fifo_id;		/* MBAR_ETH + 0x140 */
+	volatile u32 x_wmrk;		/* MBAR_ETH + 0x144 */
+	volatile u32 fcntrl;		/* MBAR_ETH + 0x148 */
+	volatile u32 r_bound;		/* MBAR_ETH + 0x14C */
+	volatile u32 r_fstart;		/* MBAR_ETH + 0x150 */
+	volatile u32 r_count;		/* MBAR_ETH + 0x154 */
+	volatile u32 r_lag;		/* MBAR_ETH + 0x158 */
+	volatile u32 r_read;		/* MBAR_ETH + 0x15C */
+	volatile u32 r_write;		/* MBAR_ETH + 0x160 */
+	volatile u32 x_count;		/* MBAR_ETH + 0x164 */
+	volatile u32 x_lag;		/* MBAR_ETH + 0x168 */
+	volatile u32 x_retry;		/* MBAR_ETH + 0x16C */
+	volatile u32 x_write;		/* MBAR_ETH + 0x170 */
+	volatile u32 x_read;		/* MBAR_ETH + 0x174 */
+
+	volatile u32 RES7[2];		/* MBAR_ETH + 0x178-17C */
+	volatile u32 fm_cntrl;		/* MBAR_ETH + 0x180 */
+	volatile u32 rfifo_data;	/* MBAR_ETH + 0x184 */
+	volatile u32 rfifo_status;	/* MBAR_ETH + 0x188 */
+	volatile u32 rfifo_cntrl;	/* MBAR_ETH + 0x18C */
+	volatile u32 rfifo_lrf_ptr;	/* MBAR_ETH + 0x190 */
+	volatile u32 rfifo_lwf_ptr;	/* MBAR_ETH + 0x194 */
+	volatile u32 rfifo_alarm;	/* MBAR_ETH + 0x198 */
+	volatile u32 rfifo_rdptr;	/* MBAR_ETH + 0x19C */
+	volatile u32 rfifo_wrptr;	/* MBAR_ETH + 0x1A0 */
+	volatile u32 tfifo_data;	/* MBAR_ETH + 0x1A4 */
+	volatile u32 tfifo_status;	/* MBAR_ETH + 0x1A8 */
+	volatile u32 tfifo_cntrl;	/* MBAR_ETH + 0x1AC */
+	volatile u32 tfifo_lrf_ptr;	/* MBAR_ETH + 0x1B0 */
+	volatile u32 tfifo_lwf_ptr;	/* MBAR_ETH + 0x1B4 */
+	volatile u32 tfifo_alarm;	/* MBAR_ETH + 0x1B8 */
+	volatile u32 tfifo_rdptr;	/* MBAR_ETH + 0x1BC */
+	volatile u32 tfifo_wrptr;	/* MBAR_ETH + 0x1C0 */
+
+	volatile u32 reset_cntrl;	/* MBAR_ETH + 0x1C4 */
+	volatile u32 xmit_fsm;		/* MBAR_ETH + 0x1C8 */
+
+	volatile u32 RES8[3];		/* MBAR_ETH + 0x1CC-1D4 */
+	volatile u32 rdes_data0;	/* MBAR_ETH + 0x1D8 */
+	volatile u32 rdes_data1;	/* MBAR_ETH + 0x1DC */
+	volatile u32 r_length;		/* MBAR_ETH + 0x1E0 */
+	volatile u32 x_length;		/* MBAR_ETH + 0x1E4 */
+	volatile u32 x_addr;		/* MBAR_ETH + 0x1E8 */
+	volatile u32 cdes_data;		/* MBAR_ETH + 0x1EC */
+	volatile u32 status;		/* MBAR_ETH + 0x1F0 */
+	volatile u32 dma_control;	/* MBAR_ETH + 0x1F4 */
+	volatile u32 des_cmnd;		/* MBAR_ETH + 0x1F8 */
+	volatile u32 data;		/* MBAR_ETH + 0x1FC */
+
+	/*  MIB COUNTERS (Offset 200-2FF) */
+
+	volatile u32 rmon_t_drop;	/* MBAR_ETH + 0x200 */
+	volatile u32 rmon_t_packets;	/* MBAR_ETH + 0x204 */
+	volatile u32 rmon_t_bc_pkt;	/* MBAR_ETH + 0x208 */
+	volatile u32 rmon_t_mc_pkt;	/* MBAR_ETH + 0x20C */
+	volatile u32 rmon_t_crc_align;	/* MBAR_ETH + 0x210 */
+	volatile u32 rmon_t_undersize;	/* MBAR_ETH + 0x214 */
+	volatile u32 rmon_t_oversize;	/* MBAR_ETH + 0x218 */
+	volatile u32 rmon_t_frag;	/* MBAR_ETH + 0x21C */
+	volatile u32 rmon_t_jab;	/* MBAR_ETH + 0x220 */
+	volatile u32 rmon_t_col;	/* MBAR_ETH + 0x224 */
+	volatile u32 rmon_t_p64;	/* MBAR_ETH + 0x228 */
+	volatile u32 rmon_t_p65to127;	/* MBAR_ETH + 0x22C */
+	volatile u32 rmon_t_p128to255;	/* MBAR_ETH + 0x230 */
+	volatile u32 rmon_t_p256to511;	/* MBAR_ETH + 0x234 */
+	volatile u32 rmon_t_p512to1023;	/* MBAR_ETH + 0x238 */
+	volatile u32 rmon_t_p1024to2047;/* MBAR_ETH + 0x23C */
+	volatile u32 rmon_t_p_gte2048;	/* MBAR_ETH + 0x240 */
+	volatile u32 rmon_t_octets;	/* MBAR_ETH + 0x244 */
+	volatile u32 ieee_t_drop;	/* MBAR_ETH + 0x248 */
+	volatile u32 ieee_t_frame_ok;	/* MBAR_ETH + 0x24C */
+	volatile u32 ieee_t_1col;	/* MBAR_ETH + 0x250 */
+	volatile u32 ieee_t_mcol;	/* MBAR_ETH + 0x254 */
+	volatile u32 ieee_t_def;	/* MBAR_ETH + 0x258 */
+	volatile u32 ieee_t_lcol;	/* MBAR_ETH + 0x25C */
+	volatile u32 ieee_t_excol;	/* MBAR_ETH + 0x260 */
+	volatile u32 ieee_t_macerr;	/* MBAR_ETH + 0x264 */
+	volatile u32 ieee_t_cserr;	/* MBAR_ETH + 0x268 */
+	volatile u32 ieee_t_sqe;	/* MBAR_ETH + 0x26C */
+	volatile u32 t_fdxfc;		/* MBAR_ETH + 0x270 */
+	volatile u32 ieee_t_octets_ok;	/* MBAR_ETH + 0x274 */
+
+	volatile u32 RES9[2];		/* MBAR_ETH + 0x278-27C */
+	volatile u32 rmon_r_drop;	/* MBAR_ETH + 0x280 */
+	volatile u32 rmon_r_packets;	/* MBAR_ETH + 0x284 */
+	volatile u32 rmon_r_bc_pkt;	/* MBAR_ETH + 0x288 */
+	volatile u32 rmon_r_mc_pkt;	/* MBAR_ETH + 0x28C */
+	volatile u32 rmon_r_crc_align;	/* MBAR_ETH + 0x290 */
+	volatile u32 rmon_r_undersize;	/* MBAR_ETH + 0x294 */
+	volatile u32 rmon_r_oversize;	/* MBAR_ETH + 0x298 */
+	volatile u32 rmon_r_frag;	/* MBAR_ETH + 0x29C */
+	volatile u32 rmon_r_jab;	/* MBAR_ETH + 0x2A0 */
+
+	volatile u32 rmon_r_resvd_0;	/* MBAR_ETH + 0x2A4 */
+
+	volatile u32 rmon_r_p64;	/* MBAR_ETH + 0x2A8 */
+	volatile u32 rmon_r_p65to127;	/* MBAR_ETH + 0x2AC */
+	volatile u32 rmon_r_p128to255;	/* MBAR_ETH + 0x2B0 */
+	volatile u32 rmon_r_p256to511;	/* MBAR_ETH + 0x2B4 */
+	volatile u32 rmon_r_p512to1023;	/* MBAR_ETH + 0x2B8 */
+	volatile u32 rmon_r_p1024to2047;/* MBAR_ETH + 0x2BC */
+	volatile u32 rmon_r_p_gte2048;	/* MBAR_ETH + 0x2C0 */
+	volatile u32 rmon_r_octets;	/* MBAR_ETH + 0x2C4 */
+	volatile u32 ieee_r_drop;	/* MBAR_ETH + 0x2C8 */
+	volatile u32 ieee_r_frame_ok;	/* MBAR_ETH + 0x2CC */
+	volatile u32 ieee_r_crc;	/* MBAR_ETH + 0x2D0 */
+	volatile u32 ieee_r_align;	/* MBAR_ETH + 0x2D4 */
+	volatile u32 r_macerr;		/* MBAR_ETH + 0x2D8 */
+	volatile u32 r_fdxfc;		/* MBAR_ETH + 0x2DC */
+	volatile u32 ieee_r_octets_ok;	/* MBAR_ETH + 0x2E0 */
+
+	volatile u32 RES10[6];		/* MBAR_ETH + 0x2E4-2FC */
+
+	volatile u32 RES11[64];		/* MBAR_ETH + 0x300-3FF */
+} ethernet_regs;
+
+/* Receive & Transmit Buffer Descriptor definitions */
+typedef struct BufferDescriptor {
+	u16 status;
+	u16 dataLength;
+	u32 dataPointer;
+} FEC_RBD;
+
+typedef struct {
+	u16 status;
+	u16 dataLength;
+	u32 dataPointer;
+} FEC_TBD;
+
+/* private structure */
+typedef enum {
+	SEVENWIRE,		/* 7-wire       */
+	MII10,			/* MII 10Mbps   */
+	MII100			/* MII 100Mbps  */
+} xceiver_type;
+
+typedef struct {
+	ethernet_regs *eth;
+	xceiver_type xcv_type;	/* transceiver type */
+	FEC_RBD *rbdBase;	/* RBD ring */
+	FEC_TBD *tbdBase;	/* TBD ring */
+	u16 rbdIndex;		/* next receive BD to read */
+	u16 tbdIndex;		/* next transmit BD to send */
+	u16 usedTbdIndex;	/* next transmit BD to clean */
+	u16 cleanTbdNum;	/* the number of available transmit BDs */
+} mpc8220_fec_priv;
+
+/* Ethernet parameter area */
+#define FEC_TBD_BASE	    (FEC_PARAM_BASE + 0x00)
+#define FEC_TBD_NEXT	    (FEC_PARAM_BASE + 0x04)
+#define FEC_RBD_BASE	    (FEC_PARAM_BASE + 0x08)
+#define FEC_RBD_NEXT	    (FEC_PARAM_BASE + 0x0c)
+
+/* BD Numer definitions */
+#define FEC_TBD_NUM	   48	/* The user can adjust this value */
+#define FEC_RBD_NUM	   32	/* The user can adjust this value */
+
+/* packet size limit */
+#define FEC_MAX_PKT_SIZE   1536
+
+/* RBD bits definitions */
+#define FEC_RBD_EMPTY	0x8000	/* Buffer is empty */
+#define FEC_RBD_WRAP	0x2000	/* Last BD in ring */
+#define FEC_RBD_INT	0x1000	/* Interrupt */
+#define FEC_RBD_LAST	0x0800	/* Buffer is last in frame(useless) */
+#define FEC_RBD_MISS	0x0100	/* Miss bit for prom mode */
+#define FEC_RBD_BC	0x0080	/* The received frame is broadcast frame */
+#define FEC_RBD_MC	0x0040	/* The received frame is multicast frame */
+#define FEC_RBD_LG	0x0020	/* Frame length violation */
+#define FEC_RBD_NO	0x0010	/* Nonoctet align frame */
+#define FEC_RBD_SH	0x0008	/* Short frame */
+#define FEC_RBD_CR	0x0004	/* CRC error */
+#define FEC_RBD_OV	0x0002	/* Receive FIFO overrun */
+#define FEC_RBD_TR	0x0001	/* Frame is truncated */
+#define FEC_RBD_ERR	(FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+			 FEC_RBD_OV | FEC_RBD_TR)
+
+/* TBD bits definitions */
+#define FEC_TBD_READY	0x8000	/* Buffer is ready */
+#define FEC_TBD_WRAP	0x2000	/* Last BD in ring */
+#define FEC_TBD_INT	0x1000	/* Interrupt */
+#define FEC_TBD_LAST	0x0800	/* Buffer is last in frame */
+#define FEC_TBD_TC	0x0400	/* Transmit the CRC */
+#define FEC_TBD_ABC	0x0200	/* Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST		0x40000000	/* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform a read operation */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register field mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x0000ffff	/* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT	18	/* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT	23	/* MII PHY address bits */
+
+#endif /* __MPC8220_FEC_H */
diff --git a/cpu/mpc8220/fec_dma_tasks.S b/cpu/mpc8220/fec_dma_tasks.S
new file mode 100644
index 0000000..3f8a03b
--- /dev/null
+++ b/cpu/mpc8220/fec_dma_tasks.S
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2004, Freescale Semiconductor, Inc.
+ *
+ * This file contains microcode for the FEC controller of the MPC8220.
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_MPC8220)
+
+/* sas/sccg, gas target */
+.section        smartdmaInitData,"aw",@progbits	/* Initialized data for task variables */
+.section        smartdmaTaskTable,"aw",@progbits	/* Task tables */
+.align  9
+.globl taskTable
+taskTable:
+.globl scEthernetRecv_Entry
+scEthernetRecv_Entry:		/* Task 0 */
+.long   scEthernetRecv_TDT - taskTable	/* Task 0 Descriptor Table */
+.long   scEthernetRecv_TDT - taskTable + 0x00000094
+.long   scEthernetRecv_VarTab - taskTable	/* Task 0 Variable Table */
+.long   scEthernetRecv_FDT - taskTable + 0x03	/* Task 0 Function Descriptor Table & Flags */
+.long   0x00000000
+.long   0x00000000
+.long   scEthernetRecv_CSave - taskTable	/* Task 0 context save space */
+.long   0xf0000000
+.globl scEthernetXmit_Entry
+scEthernetXmit_Entry:		/* Task 1 */
+.long   scEthernetXmit_TDT - taskTable	/* Task 1 Descriptor Table */
+.long   scEthernetXmit_TDT - taskTable + 0x000000e0
+.long   scEthernetXmit_VarTab - taskTable	/* Task 1 Variable Table */
+.long   scEthernetXmit_FDT - taskTable + 0x03	/* Task 1 Function Descriptor Table & Flags */
+.long   0x00000000
+.long   0x00000000
+.long   scEthernetXmit_CSave - taskTable	/* Task 1 context save space */
+.long   0xf0000000
+
+
+.globl scEthernetRecv_TDT
+scEthernetRecv_TDT:	/* Task 0 Descriptor Table */
+.long   0xc4c50000	/* 0000(153):  LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */
+.long   0x84c5e000	/* 0004(153):  LCD: idx1 = var9 + var11; ; idx1 += inc0 */
+.long   0x10001f08	/* 0008(156):    DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x10000380	/* 000C(157):    DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f88	/* 0010(158):    DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0x81980000	/* 0014(162):  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long   0x10000780	/* 0018(164):    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 001C(165):    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x010cf04c	/* 0020(165):    DRD2B1: var4 = EU3(); EU3(var1,var12)  */
+.long   0x82180349	/* 0024(169):  LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */
+.long   0x81c68004	/* 0028(172):    LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */
+.long   0x70000000	/* 002C(174):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x018cf04e	/* 0030(174):      DRD2B1: var6 = EU3(); EU3(var1,var14)  */
+.long   0x70000000	/* 0034(175):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x020cf04f	/* 0038(175):      DRD2B1: var8 = EU3(); EU3(var1,var15)  */
+.long   0x00000b88	/* 003C(176):      DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0x80025184	/* 0040(205):    LCDEXT: idx1 = 0xf0009184; ; */
+.long   0x86810412	/* 0044(205):    LCD: idx2 = var13, idx3 = var2; idx2 < var16; idx2 += inc2, idx3 += inc2 */
+.long   0x0200cf88	/* 0048(209):      DRD1A: *idx3 = *idx1; FN=0 init=16 WS=0 RS=0 */
+.long   0x80025184	/* 004C(217):    LCDEXT: idx1 = 0xf0009184; ; */
+.long   0x8681845b	/* 0050(217):    LCD: idx2 = var13, idx3 = var3; idx2 < var17; idx2 += inc3, idx3 += inc3 */
+.long   0x0000cf88	/* 0054(221):      DRD1A: *idx3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long   0xc31883a4	/* 0058(225):    LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc4 */
+.long   0x80190000	/* 005C(225):    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long   0x04008468	/* 0060(227):      DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */
+.long   0xc4038360	/* 0064(232):    LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc4, idx2 += inc0 */
+.long   0x81c50000	/* 0068(233):    LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */
+.long   0x1000cb18	/* 006C(235):      DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f18	/* 0070(236):      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long   0xc418836d	/* 0074(238):    LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc5 */
+.long   0x83990000	/* 0078(238):    LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */
+.long   0x10000c00	/* 007C(240):      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x0000c800	/* 0080(241):      DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */
+.long   0x81988000	/* 0084(245):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x10000788	/* 0088(247):      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 008C(248):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x080cf04c	/* 0090(248):      DRD2B1: idx0 = EU3(); EU3(var1,var12)  */
+.long   0x000001f8	/* 0094(:0):    NOP */
+
+
+.globl scEthernetXmit_TDT
+scEthernetXmit_TDT:	/* Task 1 Descriptor Table */
+.long   0x80095b00	/* 0000(280):  LCDEXT: idx0 = 0xf0025b00; ; */
+.long   0x85c60004	/* 0004(280):  LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */
+.long   0x10002308	/* 0008(283):    DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x10000f88	/* 000C(284):    DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000380	/* 0010(285):    DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */
+.long   0x81980000	/* 0014(288):  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long   0x10000780	/* 0018(290):    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 001C(291):    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x024cf04d	/* 0020(291):    DRD2B1: var9 = EU3(); EU3(var1,var13)  */
+.long   0x84980309	/* 0024(294):  LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */
+.long   0xc0004003	/* 0028(297):    LCDEXT: idx1 = 0x00000003; ; */
+.long   0x81c60004	/* 002C(297):    LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */
+.long   0x70000000	/* 0030(299):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x010cf04e	/* 0034(299):      DRD2B1: var4 = EU3(); EU3(var1,var14)  */
+.long   0x70000000	/* 0038(300):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x014cf04f	/* 003C(300):      DRD2B1: var5 = EU3(); EU3(var1,var15)  */
+.long   0x70000000	/* 0040(301):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x028cf050	/* 0044(301):      DRD2B1: var10 = EU3(); EU3(var1,var16)  */
+.long   0x70000000	/* 0048(302):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long   0x018cf051	/* 004C(302):      DRD2B1: var6 = EU3(); EU3(var1,var17)  */
+.long   0x10000b90	/* 0050(303):      DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 0054(304):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x01ccf0a1	/* 0058(304):      DRD2B1: var7 = EU3(); EU3(var2,idx1)  */
+.long   0xc2988312	/* 005C(308):    LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */
+.long   0x83490000	/* 0060(308):    LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */
+.long   0x00001b10	/* 0064(310):      DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */
+.long   0x800251a4	/* 0068(315):    LCDEXT: idx1 = 0xf00091a4; ; */
+.long   0xc30104dc	/* 006C(315):    LCDEXT: idx2 = var6, idx3 = var2; idx2 >= var19; idx2 += inc3, idx3 += inc4 */
+.long   0x839a032d	/* 0070(316):    LCD: idx4 = var7; idx4 == var12; idx4 += inc5 */
+.long   0x0220c798	/* 0074(321):      DRD1A: *idx1 = *idx3; FN=0 init=17 WS=0 RS=0 */
+.long   0x800251a4	/* 0078(329):    LCDEXT: idx1 = 0xf00091a4; ; */
+.long   0x99198337	/* 007C(329):    LCD: idx2 = idx2, idx3 = idx3; idx2 > var12; idx2 += inc6, idx3 += inc7 */
+.long   0x022ac798	/* 0080(333):      DRD1A: *idx1 = *idx3; FN=0 init=17 WS=1 RS=1 */
+.long   0x800251a4	/* 0084(350):    LCDEXT: idx1 = 0xf00091a4; ; */
+.long   0xc1430000	/* 0088(350):    LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */
+.long   0x82998312	/* 008C(351):    LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */
+.long   0x0a2ac790	/* 0090(354):      DRD1A: *idx1 = *idx2; FN=0 TFD init=17 WS=1 RS=1 */
+.long   0x81988000	/* 0094(359):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x60000002	/* 0098(361):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
+.long   0x0c4cfc4d	/* 009C(361):      DRD2B1: *idx1 = EU3(); EU3(*idx1,var13)  */
+.long   0xc21883ad	/* 00A0(365):    LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */
+.long   0x80190000	/* 00A4(365):    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long   0x04008460	/* 00A8(367):      DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */
+.long   0xc4052305	/* 00AC(371):    LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */
+.long   0x81ca0000	/* 00B0(372):    LCD: idx3 = var3 + var20; idx3 once var0; idx3 += inc0 */
+.long   0x1000c718	/* 00B4(374):      DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00000f18	/* 00B8(375):      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long   0xc4188000	/* 00BC(378):    LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */
+.long   0x85190312	/* 00C0(378):    LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */
+.long   0x10000c00	/* 00C4(380):      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x1000c400	/* 00C8(381):      DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x00008860	/* 00CC(382):      DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */
+.long   0x81988000	/* 00D0(386):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long   0x10000788	/* 00D4(388):      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long   0x60000000	/* 00D8(389):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long   0x080cf04d	/* 00DC(389):      DRD2B1: idx0 = EU3(); EU3(var1,var13)  */
+.long   0x000001f8	/* 00E0(:0):    NOP */
+
+.align 8
+
+.globl scEthernetRecv_VarTab
+scEthernetRecv_VarTab:	/* Task 0 Variable Table */
+.long   0x00000000	/* var[0] */
+.long   0x00000000	/* var[1] */
+.long   0x00000000	/* var[2] */
+.long   0x00000000	/* var[3] */
+.long   0x00000000	/* var[4] */
+.long   0x00000000	/* var[5] */
+.long   0x00000000	/* var[6] */
+.long   0x00000000	/* var[7] */
+.long   0x00000000	/* var[8] */
+.long   0xf0025b00	/* var[9] */
+.long   0x00000008	/* var[10] */
+.long   0x0000000c	/* var[11] */
+.long   0x80000000	/* var[12] */
+.long   0x00000000	/* var[13] */
+.long   0x10000000	/* var[14] */
+.long   0x20000000	/* var[15] */
+.long   0x00000800	/* var[16] */
+.long   0x00000001	/* var[17] */
+.long   0x00000000	/* var[18] */
+.long   0x00000000	/* var[19] */
+.long   0x00000000	/* var[20] */
+.long   0x00000000	/* var[21] */
+.long   0x00000000	/* var[22] */
+.long   0x00000000	/* var[23] */
+.long   0x00000000	/* inc[0] */
+.long   0x60000000	/* inc[1] */
+.long   0x20000004	/* inc[2] */
+.long   0x20000001	/* inc[3] */
+.long   0x80000000	/* inc[4] */
+.long   0x40000000	/* inc[5] */
+.long   0x00000000	/* inc[6] */
+.long   0x00000000	/* inc[7] */
+
+.align  8
+
+.globl scEthernetXmit_VarTab
+scEthernetXmit_VarTab:	/* Task 1 Variable Table */
+.long   0x00000000	/* var[0] */
+.long   0x00000000	/* var[1] */
+.long   0x00000000	/* var[2] */
+.long   0x00000000	/* var[3] */
+.long   0x00000000	/* var[4] */
+.long   0x00000000	/* var[5] */
+.long   0x00000000	/* var[6] */
+.long   0x00000000	/* var[7] */
+.long   0x00000000	/* var[8] */
+.long   0x00000000	/* var[9] */
+.long   0x00000000	/* var[10] */
+.long   0xf0025b00	/* var[11] */
+.long   0x00000000	/* var[12] */
+.long   0x80000000	/* var[13] */
+.long   0x10000000	/* var[14] */
+.long   0x08000000	/* var[15] */
+.long   0x20000000	/* var[16] */
+.long   0x0000ffff	/* var[17] */
+.long   0xffffffff	/* var[18] */
+.long   0x00000004	/* var[19] */
+.long   0x00000008	/* var[20] */
+.long   0x00000000	/* var[21] */
+.long   0x00000000	/* var[22] */
+.long   0x00000000	/* var[23] */
+.long   0x00000000	/* inc[0] */
+.long   0x60000000	/* inc[1] */
+.long   0x40000000	/* inc[2] */
+.long   0xc000fffc	/* inc[3] */
+.long   0xe0000004	/* inc[4] */
+.long   0x80000000	/* inc[5] */
+.long   0x4000ffff	/* inc[6] */
+.long   0xe0000001	/* inc[7] */
+
+.align 8
+
+.globl scEthernetRecv_FDT
+scEthernetRecv_FDT:	/* Task 0 Function Descriptor Table */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x21800000	/* and(), EU# 3 */
+.long   0x21e00000	/* or(), EU# 3 */
+.long   0x21400000	/* andn(), EU# 3 */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+
+.align 8
+
+.globl scEthernetXmit_FDT
+scEthernetXmit_FDT:	/* Task 1 Function Descriptor Table */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x21800000	/* and(), EU# 3 */
+.long   0x21e00000	/* or(), EU# 3 */
+.long   0x21400000	/* andn(), EU# 3 */
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+.long   0x00000000
+
+
+.globl scEthernetRecv_CSave
+scEthernetRecv_CSave:	/* Task 0 context save space */
+.space  128, 0x0
+
+
+.globl scEthernetXmit_CSave
+scEthernetXmit_CSave:	/* Task 1 context save space */
+.space  128, 0x0
+
+#endif
diff --git a/cpu/mpc8220/i2c.c b/cpu/mpc8220/i2c.c
new file mode 100644
index 0000000..e9d0771
--- /dev/null
+++ b/cpu/mpc8220/i2c.c
@@ -0,0 +1,403 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_HARD_I2C
+
+#include <mpc8220.h>
+#include <i2c.h>
+
+typedef struct mpc8220_i2c {
+	volatile u32 adr;	/* I2Cn + 0x00 */
+	volatile u32 fdr;	/* I2Cn + 0x04 */
+	volatile u32 cr;	/* I2Cn + 0x08 */
+	volatile u32 sr;	/* I2Cn + 0x0C */
+	volatile u32 dr;	/* I2Cn + 0x10 */
+} i2c_t;
+
+/* I2Cn control register bits */
+#define I2C_EN      0x80
+#define I2C_IEN     0x40
+#define I2C_STA     0x20
+#define I2C_TX      0x10
+#define I2C_TXAK    0x08
+#define I2C_RSTA    0x04
+#define I2C_INIT_MASK   (I2C_EN | I2C_STA | I2C_TX | I2C_RSTA)
+
+/* I2Cn status register bits */
+#define I2C_CF      0x80
+#define I2C_AAS     0x40
+#define I2C_BB      0x20
+#define I2C_AL      0x10
+#define I2C_SRW     0x04
+#define I2C_IF      0x02
+#define I2C_RXAK    0x01
+
+#define I2C_TIMEOUT 100
+#define I2C_RETRIES 1
+
+struct mpc8220_i2c_tap {
+	int scl2tap;
+	int tap2tap;
+};
+
+static int mpc_reg_in (volatile u32 * reg);
+static void mpc_reg_out (volatile u32 * reg, int val, int mask);
+static int wait_for_bb (void);
+static int wait_for_pin (int *status);
+static int do_address (uchar chip, char rdwr_flag);
+static int send_bytes (uchar chip, char *buf, int len);
+static int receive_bytes (uchar chip, char *buf, int len);
+static int mpc_get_fdr (int);
+
+static int mpc_reg_in (volatile u32 * reg)
+{
+	return *reg >> 24;
+	__asm__ __volatile__ ("eieio");
+}
+
+static void mpc_reg_out (volatile u32 * reg, int val, int mask)
+{
+	int tmp;
+
+	if (!mask) {
+		*reg = val << 24;
+	} else {
+		tmp = mpc_reg_in (reg);
+		*reg = ((tmp & ~mask) | (val & mask)) << 24;
+	}
+	__asm__ __volatile__ ("eieio");
+
+	return;
+}
+
+static int wait_for_bb (void)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int timeout = I2C_TIMEOUT;
+	int status;
+
+	status = mpc_reg_in (&regs->sr);
+
+	while (timeout-- && (status & I2C_BB)) {
+#if 1
+		volatile int temp;
+
+		mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+		temp = mpc_reg_in (&regs->dr);
+		mpc_reg_out (&regs->cr, 0, I2C_STA);
+		mpc_reg_out (&regs->cr, 0, 0);
+		mpc_reg_out (&regs->cr, I2C_EN, 0);
+#endif
+		udelay (1000);
+		status = mpc_reg_in (&regs->sr);
+	}
+
+	return (status & I2C_BB);
+}
+
+static int wait_for_pin (int *status)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int timeout = I2C_TIMEOUT;
+
+	*status = mpc_reg_in (&regs->sr);
+
+	while (timeout-- && !(*status & I2C_IF)) {
+		udelay (1000);
+		*status = mpc_reg_in (&regs->sr);
+	}
+
+	if (!(*status & I2C_IF)) {
+		return -1;
+	}
+
+	mpc_reg_out (&regs->sr, 0, I2C_IF);
+	return 0;
+}
+
+static int do_address (uchar chip, char rdwr_flag)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int status;
+
+	chip <<= 1;
+
+	if (rdwr_flag)
+		chip |= 1;
+
+	mpc_reg_out (&regs->cr, I2C_TX, I2C_TX);
+	mpc_reg_out (&regs->dr, chip, 0);
+
+	if (wait_for_pin (&status))
+		return -2;
+	if (status & I2C_RXAK)
+		return -3;
+	return 0;
+}
+
+static int send_bytes (uchar chip, char *buf, int len)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int wrcount;
+	int status;
+
+	for (wrcount = 0; wrcount < len; ++wrcount) {
+
+		mpc_reg_out (&regs->dr, buf[wrcount], 0);
+
+		if (wait_for_pin (&status))
+			break;
+
+		if (status & I2C_RXAK)
+			break;
+
+	}
+
+	return !(wrcount == len);
+	return 0;
+}
+
+static int receive_bytes (uchar chip, char *buf, int len)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int dummy = 1;
+	int rdcount = 0;
+	int status;
+	int i;
+
+	mpc_reg_out (&regs->cr, 0, I2C_TX);
+
+	for (i = 0; i < len; ++i) {
+		buf[rdcount] = mpc_reg_in (&regs->dr);
+
+		if (dummy)
+			dummy = 0;
+		else
+			rdcount++;
+
+		if (wait_for_pin (&status))
+			return -4;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_TXAK, I2C_TXAK);
+	buf[rdcount++] = mpc_reg_in (&regs->dr);
+
+	if (wait_for_pin (&status))
+		return -5;
+
+	mpc_reg_out (&regs->cr, 0, I2C_TXAK);
+	return 0;
+}
+
+/**************** I2C API ****************/
+
+void i2c_init (int speed, int saddr)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+
+	mpc_reg_out (&regs->cr, 0, 0);
+	mpc_reg_out (&regs->adr, saddr << 1, 0);
+
+	/* Set clock
+	 */
+	mpc_reg_out (&regs->fdr, mpc_get_fdr (speed), 0);
+
+	/* Enable module
+	 */
+	mpc_reg_out (&regs->cr, I2C_EN, I2C_INIT_MASK);
+	mpc_reg_out (&regs->sr, 0, I2C_IF);
+	return;
+}
+
+static int mpc_get_fdr (int speed)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	static int fdr = -1;
+
+	if (fdr == -1) {
+		ulong best_speed = 0;
+		ulong divider;
+		ulong ipb, scl;
+		ulong bestmatch = 0xffffffffUL;
+		int best_i = 0, best_j = 0, i, j;
+		int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8 };
+		struct mpc8220_i2c_tap scltap[] = {
+			{4, 1},
+			{4, 2},
+			{6, 4},
+			{6, 8},
+			{14, 16},
+			{30, 32},
+			{62, 64},
+			{126, 128}
+		};
+
+		ipb = gd->bus_clk;
+		for (i = 7; i >= 0; i--) {
+			for (j = 7; j >= 0; j--) {
+				scl = 2 * (scltap[j].scl2tap +
+					   (SCL_Tap[i] -
+					    1) * scltap[j].tap2tap + 2);
+				if (ipb <= speed * scl) {
+					if ((speed * scl - ipb) < bestmatch) {
+						bestmatch = speed * scl - ipb;
+						best_i = i;
+						best_j = j;
+						best_speed = ipb / scl;
+					}
+				}
+			}
+		}
+		divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+		if (gd->flags & GD_FLG_RELOC) {
+			fdr = divider;
+		} else {
+			printf ("%ld kHz, ", best_speed / 1000);
+			return divider;
+		}
+	}
+
+	return fdr;
+}
+
+int i2c_probe (uchar chip)
+{
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int i;
+
+	for (i = 0; i < I2C_RETRIES; i++) {
+		mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+
+		if (!do_address (chip, 0)) {
+			mpc_reg_out (&regs->cr, 0, I2C_STA);
+			break;
+		}
+
+		mpc_reg_out (&regs->cr, 0, I2C_STA);
+		udelay (50);
+	}
+
+	return (i == I2C_RETRIES);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buf, int len)
+{
+	uchar xaddr[4];
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int ret = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >> 8) & 0xFF;
+	xaddr[3] = addr & 0xFF;
+
+	if (wait_for_bb ()) {
+		printf ("i2c_read: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+	if (do_address (chip, 0)) {
+		printf ("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, &xaddr[4 - alen], alen)) {
+		printf ("i2c_read: send_bytes failed\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_RSTA, I2C_RSTA);
+	if (do_address (chip, 1)) {
+		printf ("i2c_read: failed to address chip\n");
+		goto Done;
+	}
+
+	if (receive_bytes (chip, buf, len)) {
+		printf ("i2c_read: receive_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+      Done:
+	mpc_reg_out (&regs->cr, 0, I2C_STA);
+	return ret;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buf, int len)
+{
+	uchar xaddr[4];
+	i2c_t *regs = (i2c_t *) MMAP_I2C;
+	int ret = -1;
+
+	xaddr[0] = (addr >> 24) & 0xFF;
+	xaddr[1] = (addr >> 16) & 0xFF;
+	xaddr[2] = (addr >> 8) & 0xFF;
+	xaddr[3] = addr & 0xFF;
+
+	if (wait_for_bb ()) {
+		printf ("i2c_write: bus is busy\n");
+		goto Done;
+	}
+
+	mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+	if (do_address (chip, 0)) {
+		printf ("i2c_write: failed to address chip\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, &xaddr[4 - alen], alen)) {
+		printf ("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	if (send_bytes (chip, buf, len)) {
+		printf ("i2c_write: send_bytes failed\n");
+		goto Done;
+	}
+
+	ret = 0;
+      Done:
+	mpc_reg_out (&regs->cr, 0, I2C_STA);
+	return ret;
+}
+
+uchar i2c_reg_read (uchar chip, uchar reg)
+{
+	char buf;
+
+	i2c_read (chip, reg, 1, &buf, 1);
+
+	return buf;
+}
+
+void i2c_reg_write (uchar chip, uchar reg, uchar val)
+{
+	i2c_write (chip, reg, 1, &val, 1);
+
+	return;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/cpu/mpc8220/i2cCore.c b/cpu/mpc8220/i2cCore.c
new file mode 100644
index 0000000..accf43c
--- /dev/null
+++ b/cpu/mpc8220/i2cCore.c
@@ -0,0 +1,627 @@
+/* I2cCore.c - MPC8220 PPC I2C Library */
+
+/* Copyright 2004      Freescale Semiconductor, Inc. */
+
+/*
+modification history
+--------------------
+01c,29jun04,tcl	 1.3	removed CR. Added two bytes offset support.
+01b,19jan04,tcl	 1.2	removed i2cMsDelay and sysDecGet. renamed i2cMsDelay
+			back to sysMsDelay
+01a,19jan04,tcl	 1.1	created and seperated from i2c.c
+*/
+
+/*
+DESCRIPTION
+This file contain I2C low level handling library functions
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vxWorks.h>
+#include <sysLib.h>
+#include <iosLib.h>
+#include <logLib.h>
+#include <tickLib.h>
+
+/* BSP Includes */
+#include "config.h"
+#include "mpc8220.h"
+#include "i2cCore.h"
+
+#ifdef DEBUG_I2CCORE
+int I2CCDbg = 0;
+#endif
+
+#define ABS(x)	((x < 0)? -x : x)
+
+char *I2CERR[16] = {
+	"Transfer in Progress\n",	/* 0 */
+	"Transfer complete\n",
+	"Not Addressed\n",		/* 2 */
+	"Addressed as a slave\n",
+	"Bus is Idle\n",		/* 4 */
+	"Bus is busy\n",
+	"Arbitration Lost\n",		/* 6 */
+	"Arbitration on Track\n",
+	"Slave receive, master writing to slave\n",	/* 8 */
+	"Slave transmit, master reading from slave\n",
+	"Interrupt is pending\n",	/* 10 */
+	"Interrupt complete\n",
+	"Acknowledge received\n",	/* 12 */
+	"No acknowledge received\n",
+	"Unknown status\n",		/* 14 */
+	"\n"
+};
+
+/******************************************************************************
+ *
+ * chk_status - Check I2C status bit
+ *
+ * RETURNS: OK, or ERROR if the bit encounter
+ *
+ */
+
+STATUS chk_status (PSI2C pi2c, UINT8 sta_bit, UINT8 truefalse)
+{
+	int i, status = 0;
+
+	for (i = 0; i < I2C_POLL_COUNT; i++) {
+		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0))
+			return (OK);
+	}
+
+	I2CCDBG (L2, ("--- sr %x stabit %x truefalse %d\n",
+		      pi2c->sr, sta_bit, truefalse, 0, 0, 0));
+
+	if (i == I2C_POLL_COUNT) {
+		switch (sta_bit) {
+		case I2C_STA_CF:
+			status = 0;
+			break;
+		case I2C_STA_AAS:
+			status = 2;
+			break;
+		case I2C_STA_BB:
+			status = 4;
+			break;
+		case I2C_STA_AL:
+			status = 6;
+			break;
+		case I2C_STA_SRW:
+			status = 8;
+			break;
+		case I2C_STA_IF:
+			status = 10;
+			break;
+		case I2C_STA_RXAK:
+			status = 12;
+			break;
+		default:
+			status = 14;
+			break;
+		}
+
+		if (!truefalse)
+			status++;
+
+		I2CCDBG (NO, ("--- status %d\n", status, 0, 0, 0, 0, 0));
+		I2CCDBG (NO, (I2CERR[status], 0, 0, 0, 0, 0, 0));
+	}
+
+	return (ERROR);
+}
+
+/******************************************************************************
+ *
+ * I2C Enable - Enable the I2C Controller
+ *
+ */
+STATUS i2c_enable (SI2C * pi2c, PI2CSET pi2cSet)
+{
+	int fdr = pi2cSet->bit_rate;
+	UINT8 adr = pi2cSet->i2c_adr;
+
+	I2CCDBG (L2, ("i2c_enable fdr %d adr %x\n", fdr, adr, 0, 0, 0, 0));
+
+	i2c_clear (pi2c);	/* Clear FDR, ADR, SR and CR reg */
+
+	SetI2cFDR (pi2c, fdr);	/* Frequency			*/
+	pi2c->adr = adr;
+
+	pi2c->cr = I2C_CTL_EN;	/* Set Enable			*/
+
+	/*
+	   The I2C bus should be in Idle state. If the bus is busy,
+	   clear the STA bit in control register
+	 */
+	if (chk_status (pi2c, I2C_STA_BB, 0) != OK) {
+		if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA)
+			pi2c->cr &= ~I2C_CTL_STA;
+
+		/* Check again if it is still busy, return error if found */
+		if (chk_status (pi2c, I2C_STA_BB, 1) == OK)
+			return ERROR;
+	}
+
+	return (OK);
+}
+
+/******************************************************************************
+ *
+ * I2C Disable - Disable the I2C Controller
+ *
+ */
+STATUS i2c_disable (PSI2C pi2c)
+{
+	i2c_clear (pi2c);
+
+	pi2c->cr &= I2C_CTL_EN; /* Disable I2c			*/
+
+	if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA)
+		pi2c->cr &= ~I2C_CTL_STA;
+
+	if (chk_status (pi2c, I2C_STA_BB, 0) != OK)
+		return ERROR;
+
+	return (OK);
+}
+
+/******************************************************************************
+ *
+ * I2C Clear - Clear the I2C Controller
+ *
+ */
+STATUS i2c_clear (PSI2C pi2c)
+{
+	pi2c->adr = 0;
+	pi2c->fdr = 0;
+	pi2c->cr = 0;
+	pi2c->sr = 0;
+
+	return (OK);
+}
+
+
+STATUS i2c_start (PSI2C pi2c, PI2CSET pi2cSet)
+{
+#ifdef TWOBYTES
+	UINT16 ByteOffset = pi2cSet->str_adr;
+#else
+	UINT8 ByteOffset = pi2cSet->str_adr;
+#endif
+#if 1
+	UINT8 tmp = 0;
+#endif
+	UINT8 Addr = pi2cSet->slv_adr;
+
+	pi2c->cr |= I2C_CTL_STA;	/* Generate start signal	*/
+
+	if (chk_status (pi2c, I2C_STA_BB, 1) != OK)
+		return ERROR;
+
+	/* Write slave address */
+	if (i2c_writebyte (pi2c, &Addr) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#ifdef TWOBYTES
+#   if 0
+	/* Issue the offset to start */
+	if (i2c_write2byte (pi2c, &ByteOffset) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#endif
+	tmp = (ByteOffset >> 8) & 0xff;
+	if (i2c_writebyte (pi2c, &tmp) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+	tmp = ByteOffset & 0xff;
+	if (i2c_writebyte (pi2c, &tmp) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#else
+	if (i2c_writebyte (pi2c, &ByteOffset) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c			*/
+		return ERROR;
+	}
+#endif
+
+	return (OK);
+}
+
+STATUS i2c_stop (PSI2C pi2c)
+{
+	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal		*/
+	if (chk_status (pi2c, I2C_STA_BB, 0) != OK)
+		return ERROR;
+
+	return (OK);
+}
+
+/******************************************************************************
+ *
+ * Read Len bytes to the location pointed to by *Data from the device
+ * with address Addr.
+ */
+int i2c_readblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data)
+{
+	int i = 0;
+	UINT8 Tmp;
+
+/*    UINT8 ByteOffset = pi2cSet->str_adr; not used? */
+	UINT8 Addr = pi2cSet->slv_adr;
+	int Length = pi2cSet->xfer_size;
+
+	I2CCDBG (L1, ("i2c_readblock addr %x data 0x%08x len %d offset %d\n",
+		      Addr, (int) Data, Length, ByteOffset, 0, 0));
+
+	if (pi2c->sr & I2C_STA_AL) {	/* Check if Arbitration lost	*/
+		I2CCDBG (FN, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0));
+		pi2c->sr &= ~I2C_STA_AL;	/* Clear Arbitration status bit */
+		return ERROR;
+	}
+
+	pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack	*/
+
+	if (i2c_start (pi2c, pi2cSet) == ERROR)
+		return ERROR;
+
+	pi2c->cr |= I2C_CTL_RSTA;	/* Repeat Start */
+
+	Tmp = Addr | 1;
+
+	if (i2c_writebyte (pi2c, &Tmp) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c	*/
+		return ERROR;
+	}
+
+	if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01))
+		return ERROR;
+
+	pi2c->cr &= ~I2C_CTL_TX;	/* Set receive mode	*/
+
+	if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01))
+		return ERROR;
+
+	/* Dummy Read */
+	if (i2c_readbyte (pi2c, &Tmp, &i) != OK) {
+		i2c_stop (pi2c);	/* Disable I2c	*/
+		return ERROR;
+	}
+
+	i = 0;
+	while (Length) {
+		if (Length == 2)
+			pi2c->cr |= I2C_CTL_TXAK;
+
+		if (Length == 1)
+			pi2c->cr &= ~I2C_CTL_STA;
+
+		if (i2c_readbyte (pi2c, Data, &Length) != OK) {
+			return i2c_stop (pi2c);
+		}
+		i++;
+		Length--;
+		Data++;
+	}
+
+	if (i2c_stop (pi2c) == ERROR)
+		return ERROR;
+
+	return i;
+}
+
+STATUS i2c_writeblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data)
+{
+	int Length = pi2cSet->xfer_size;
+
+#ifdef TWOBYTES
+	UINT16 ByteOffset = pi2cSet->str_adr;
+#else
+	UINT8 ByteOffset = pi2cSet->str_adr;
+#endif
+	int j, k;
+
+	I2CCDBG (L2, ("i2c_writeblock\n", 0, 0, 0, 0, 0, 0));
+
+	if (pi2c->sr & I2C_STA_AL) {
+		/* Check if arbitration lost */
+		I2CCDBG (L2, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0));
+		pi2c->sr &= ~I2C_STA_AL;	/* Clear the condition	*/
+		return ERROR;
+	}
+
+	pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack	*/
+
+	/* Do the not even offset first */
+	if ((ByteOffset % 8) != 0) {
+		int remain;
+
+		if (Length > 8) {
+			remain = 8 - (ByteOffset % 8);
+			Length -= remain;
+
+			pi2cSet->str_adr = ByteOffset;
+
+			if (i2c_start (pi2c, pi2cSet) == ERROR)
+				return ERROR;
+
+			for (j = ByteOffset; j < remain; j++) {
+				if (i2c_writebyte (pi2c, Data++) != OK)
+					return ERROR;
+			}
+
+			if (i2c_stop (pi2c) == ERROR)
+				return ERROR;
+
+			sysMsDelay (32);
+
+			/* Update the new ByteOffset */
+			ByteOffset += remain;
+		}
+	}
+
+	for (j = ByteOffset, k = 0; j < (Length + ByteOffset); j++) {
+		if ((j % 8) == 0) {
+			pi2cSet->str_adr = j;
+			if (i2c_start (pi2c, pi2cSet) == ERROR)
+				return ERROR;
+		}
+
+		k++;
+
+		if (i2c_writebyte (pi2c, Data++) != OK)
+			return ERROR;
+
+		if ((j == (Length - 1)) || ((k % 8) == 0)) {
+			if (i2c_stop (pi2c) == ERROR)
+				return ERROR;
+
+			sysMsDelay (50);
+		}
+
+	}
+
+	return k;
+}
+
+STATUS i2c_readbyte (SI2C * pi2c, UINT8 * readb, int *index)
+{
+	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit	*/
+	*readb = pi2c->dr;		/* Read a byte		*/
+
+	/*
+	   Set I2C_CTRL_TXAK will cause Transfer pending and
+	   set I2C_CTRL_STA will cause Interrupt pending
+	 */
+	if (*index != 2) {
+		if (chk_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?	*/
+			return ERROR;
+	}
+
+	if (*index != 1) {
+		if (chk_status (pi2c, I2C_STA_IF, 1) != OK)
+			return ERROR;
+	}
+
+	return (OK);
+}
+
+
+STATUS i2c_writebyte (SI2C * pi2c, UINT8 * writeb)
+{
+	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt	*/
+	pi2c->dr = *writeb;		/* Write a byte		*/
+
+	if (chk_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?	*/
+		return ERROR;
+
+	if (chk_status (pi2c, I2C_STA_IF, 1) != OK)
+		return ERROR;
+
+	return OK;
+}
+
+STATUS i2c_write2byte (SI2C * pi2c, UINT16 * writeb)
+{
+	UINT8 data;
+
+	data = (UINT8) ((*writeb >> 8) & 0xff);
+	if (i2c_writebyte (pi2c, &data) != OK)
+		return ERROR;
+	data = (UINT8) (*writeb & 0xff);
+	if (i2c_writebyte (pi2c, &data) != OK)
+		return ERROR;
+	return OK;
+}
+
+/* FDR table base on 33Mhz - more detail please refer to Odini2c_dividers.xls
+FDR FDR scl sda scl2tap2
+510 432 tap tap tap tap scl_per	    sda_hold	I2C Freq    0	1   2	3   4	5
+000 000 9   3	4   1	28 Clocks   9 Clocks	1190 KHz    0	0   0	0   0	0
+000 001 9   3	4   2	44 Clocks   11 Clocks	758 KHz	    0	0   1	0   0	0
+000 010 9   3	6   4	80 Clocks   17 Clocks	417 KHz	    0	0   0	1   0	0
+000 011 9   3	6   8	144 Clocks  25 Clocks	231 KHz	    0	0   1	1   0	0
+000 100 9   3	14  16	288 Clocks  49 Clocks	116 KHz	    0	0   0	0   1	0
+000 101 9   3	30  32	576 Clocks  97 Clocks	58 KHz	    0	0   1	0   1	0
+000 110 9   3	62  64	1152 Clocks 193 Clocks	29 KHz	    0	0   0	1   1	0
+000 111 9   3	126 128 2304 Clocks 385 Clocks	14 KHz	    0	0   1	1   1	0
+001 000 10  3	4   1	30 Clocks   9 Clocks	1111 KHz1   0	0   0	0   0
+001 001 10  3	4   2	48 Clocks   11 Clocks	694 KHz	    1	0   1	0   0	0
+001 010 10  3	6   4	88 Clocks   17 Clocks	379 KHz	    1	0   0	1   0	0
+001 011 10  3	6   8	160 Clocks  25 Clocks	208 KHz	    1	0   1	1   0	0
+001 100 10  3	14  16	320 Clocks  49 Clocks	104 KHz	    1	0   0	0   1	0
+001 101 10  3	30  32	640 Clocks  97 Clocks	52 KHz	    1	0   1	0   1	0
+001 110 10  3	62  64	1280 Clocks 193 Clocks	26 KHz	    1	0   0	1   1	0
+001 111 10  3	126 128 2560 Clocks 385 Clocks	13 KHz	    1	0   1	1   1	0
+010 000 12  4	4   1	34 Clocks   10 Clocks	980 KHz	    0	1   0	0   0	0
+010 001 12  4	4   2	56 Clocks   13 Clocks	595 KHz	    0	1   1	0   0	0
+010 010 12  4	6   4	104 Clocks  21 Clocks	321 KHz	    0	1   0	1   0	0
+010 011 12  4	6   8	192 Clocks  33 Clocks	174 KHz	    0	1   1	1   0	0
+010 100 12  4	14  16	384 Clocks  65 Clocks	87 KHz	    0	1   0	0   1	0
+010 101 12  4	30  32	768 Clocks  129 Clocks	43 KHz	    0	1   1	0   1	0
+010 110 12  4	62  64	1536 Clocks 257 Clocks	22 KHz	    0	1   0	1   1	0
+010 111 12  4	126 128 3072 Clocks 513 Clocks	11 KHz	    0	1   1	1   1	0
+011 000 15  4	4   1	40 Clocks   10 Clocks	833 KHz	    1	1   0	0   0	0
+011 001 15  4	4   2	68 Clocks   13 Clocks	490 KHz	    1	1   1	0   0	0
+011 010 15  4	6   4	128 Clocks  21 Clocks	260 KHz	    1	1   0	1   0	0
+011 011 15  4	6   8	240 Clocks  33 Clocks	139 KHz	    1	1   1	1   0	0
+011 100 15  4	14  16	480 Clocks  65 Clocks	69 KHz	    1	1   0	0   1	0
+011 101 15  4	30  32	960 Clocks  129 Clocks	35 KHz	    1	1   1	0   1	0
+011 110 15  4	62  64	1920 Clocks 257 Clocks	17 KHz	    1	1   0	1   1	0
+011 111 15  4	126 128 3840 Clocks 513 Clocks	9 KHz	    1	1   1	1   1	0
+100 000 5   1	4   1	20 Clocks   7 Clocks	1667 KHz    0	0   0	0   0	1
+100 001 5   1	4   2	28 Clocks   7 Clocks	1190 KHz    0	0   1	0   0	1
+100 010 5   1	6   4	48 Clocks   9 Clocks	694 KHz	    0	0   0	1   0	1
+100 011 5   1	6   8	80 Clocks   9 Clocks	417 KHz	    0	0   1	1   0	1
+100 100 5   1	14  16	160 Clocks  17 Clocks	208 KHz	    0	0   0	0   1	1
+100 101 5   1	30  32	320 Clocks  33 Clocks	104 KHz	    0	0   1	0   1	1
+100 110 5   1	62  64	640 Clocks  65 Clocks	52 KHz	    0	0   0	1   1	1
+100 111 5   1	126 128 1280 Clocks 129 Clocks	26 KHz	    0	0   1	1   1	1
+101 000 6   1	4   1	22 Clocks   7 Clocks	1515 KHz    1	0   0	0   0	1
+101 001 6   1	4   2	32 Clocks   7 Clocks	1042 KHz    1	0   1	0   0	1
+101 010 6   1	6   4	56 Clocks   9 Clocks	595 KHz	    1	0   0	1   0	1
+101 011 6   1	6   8	96 Clocks   9 Clocks	347 KHz	    1	0   1	1   0	1
+101 100 6   1	14  16	192 Clocks  17 Clocks	174 KHz	    1	0   0	0   1	1
+101 101 6   1	30  32	384 Clocks  33 Clocks	87 KHz	    1	0   1	0   1	1
+101 110 6   1	62  64	768 Clocks  65 Clocks	43 KHz	    1	0   0	1   1	1
+101 111 6   1	126 128 1536 Clocks 129 Clocks	22 KHz	    1	0   1	1   1	1
+110 000 7   2	4   1	24 Clocks   8 Clocks	1389 KHz    0	1   0	0   0	1
+110 001 7   2	4   2	36 Clocks   9 Clocks	926 KHz	    0	1   1	0   0	1
+110 010 7   2	6   4	64 Clocks   13 Clocks	521 KHz	    0	1   0	1   0	1
+110 011 7   2	6   8	112 Clocks  17 Clocks	298 KHz	    0	1   1	1   0	1
+110 100 7   2	14  16	224 Clocks  33 Clocks	149 KHz	    0	1   0	0   1	1
+110 101 7   2	30  32	448 Clocks  65 Clocks	74 KHz	    0	1   1	0   1	1
+110 110 7   2	62  64	896 Clocks  129 Clocks	37 KHz	    0	1   0	1   1	1
+110 111 7   2	126 128 1792 Clocks 257 Clocks	19 KHz	    0	1   1	1   1	1
+111 000 8   2	4   1	26 Clocks   8 Clocks	1282 KHz    1	1   0	0   0	1
+111 001 8   2	4   2	40 Clocks   9 Clocks	833 KHz	    1	1   1	0   0	1
+111 010 8   2	6   4	72 Clocks   13 Clocks	463 KHz	    1	1   0	1   0	1
+111 011 8   2	6   8	128 Clocks  17 Clocks	260 KHz	    1	1   1	1   0	1
+111 100 8   2	14  16	256 Clocks  33 Clocks	130 KHz	    1	1   0	0   1	1
+111 101 8   2	30  32	512 Clocks  65 Clocks	65 KHz	    1	1   1	0   1	1
+111 110 8   2	62  64	1024 Clocks 129 Clocks	33 KHz	    1	1   0	1   1	1
+111 111 8   2	126 128 2048 Clocks 257 Clocks	16 KHz	    1	1   1	1   1	1
+*/
+STATUS SetI2cFDR (PSI2C pi2cRegs, int bitrate)
+{
+/* Constants */
+	const UINT8 div_hold[8][3] = { {9, 3}, {10, 3},
+	{12, 4}, {15, 4},
+	{5, 1}, {6, 1},
+	{7, 2}, {8, 2}
+	};
+
+	const UINT8 scl_tap[8][2] = { {4, 1}, {4, 2},
+	{6, 4}, {6, 8},
+	{14, 16}, {30, 32},
+	{62, 64}, {126, 128}
+	};
+
+	UINT8 mfdr_bits;
+
+	int i = 0;
+	int j = 0;
+
+	int Diff, min;
+	int WhichFreq, iRec, jRec;
+	int SCL_Period;
+	int SCL_Hold;
+	int I2C_Freq;
+
+	I2CCDBG (L2, ("Entering getBitRate: bitrate %d pi2cRegs 0x%08x\n",
+		      bitrate, (int) pi2cRegs, 0, 0, 0, 0));
+
+	if (bitrate < 0) {
+		I2CCDBG (NO, ("Invalid bitrate\n", 0, 0, 0, 0, 0, 0));
+		return ERROR;
+	}
+
+	/* Initialize */
+	mfdr_bits = 0;
+	min = 0x7fffffff;
+	WhichFreq = iRec = jRec = 0;
+
+	for (i = 0; i < 8; i++) {
+		for (j = 0; j < 8; j++) {
+			/* SCL Period = 2 * (scl2tap + [(SCL_Tap - 1) * tap2tap] + 2)
+			 * SCL Hold   = scl2tap + ((SDA_Tap - 1) * tap2tap) + 3
+			 * Bit Rate (I2C Freq) = System Freq / SCL Period
+			 */
+			SCL_Period =
+				2 * (scl_tap[i][0] +
+				     ((div_hold[j][0] - 1) * scl_tap[i][1]) +
+				     2);
+
+			/* Now get the I2C Freq */
+			I2C_Freq = DEV_CLOCK_FREQ / SCL_Period;
+
+			/* Take equal or slower */
+			if (I2C_Freq > bitrate)
+				continue;
+
+			/* Take the differences */
+			Diff = I2C_Freq - bitrate;
+
+			Diff = ABS (Diff);
+
+			/* Find the closer value */
+			if (Diff < min) {
+				min = Diff;
+				WhichFreq = I2C_Freq;
+				iRec = i;
+				jRec = j;
+			}
+
+			I2CCDBG (L2,
+				 ("--- (%d,%d) I2C_Freq %d minDiff %d min %d\n",
+				  i, j, I2C_Freq, Diff, min, 0));
+		}
+	}
+
+	SCL_Period =
+		2 * (scl_tap[iRec][0] +
+		     ((div_hold[jRec][0] - 1) * scl_tap[iRec][1]) + 2);
+
+	I2CCDBG (L2, ("\nmin %d WhichFreq %d iRec %d jRec %d\n",
+		      min, WhichFreq, iRec, jRec, 0, 0));
+	I2CCDBG (L2, ("--- scl2tap %d SCL_Tap %d tap2tap %d\n",
+		      scl_tap[iRec][0], div_hold[jRec][0], scl_tap[iRec][1],
+		      0, 0, 0));
+
+	/* This may no require */
+	SCL_Hold =
+		scl_tap[iRec][0] +
+		((div_hold[jRec][1] - 1) * scl_tap[iRec][1]) + 3;
+	I2CCDBG (L2,
+		 ("--- SCL_Period %d SCL_Hold %d\n", SCL_Period, SCL_Hold, 0,
+		  0, 0, 0));
+
+	I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0));
+
+	/* FDR 4,3,2 */
+	if ((iRec & 1) == 1)
+		mfdr_bits |= 0x04;	/* FDR 2 */
+	if ((iRec & 2) == 2)
+		mfdr_bits |= 0x08;	/* FDR 3 */
+	if ((iRec & 4) == 4)
+		mfdr_bits |= 0x10;	/* FDR 4 */
+	/* FDR 5,1,0 */
+	if ((jRec & 1) == 1)
+		mfdr_bits |= 0x01;	/* FDR 0 */
+	if ((jRec & 2) == 2)
+		mfdr_bits |= 0x02;	/* FDR 1 */
+	if ((jRec & 4) == 4)
+		mfdr_bits |= 0x20;	/* FDR 5 */
+
+	I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0));
+
+	pi2cRegs->fdr = mfdr_bits;
+
+	return OK;
+}
diff --git a/cpu/mpc8220/i2cCore.h b/cpu/mpc8220/i2cCore.h
new file mode 100644
index 0000000..72783fd
--- /dev/null
+++ b/cpu/mpc8220/i2cCore.h
@@ -0,0 +1,103 @@
+/*
+ * i2cCore.h
+ *
+ * Prototypes, etc. for the Motorola MPC8220
+ * embedded cpu chips
+ *
+ * 2004 (c) Freescale, Inc.
+ * Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __INCi2ccoreh
+#define __INCi2ccoreh
+#ifndef __ASSEMBLY__
+/* device types */
+#define I2C_DEVICE_TYPE_EEPROM 0
+#define I2C_EEPROM_ADRS 0xa0
+#define I2C_CTRL_ADRS   I2C_EEPROM_ADRS
+#define EEPROM_ADDR0    0xA2	/* on Dimm SPD eeprom */
+#define EEPROM_ADDR1    0xA4	/* on Board SPD eeprom */
+#define EEPROM_ADDR2    0xD2	/* non-standard eeprom - clock generator */
+/* Control Register */
+#define I2C_CTL_EN      0x80	/* I2C Enable                   */
+#define I2C_CTL_IEN     0x40	/* I2C Interrupt Enable         */
+#define I2C_CTL_STA     0x20	/* Master/Slave Mode select     */
+#define I2C_CTL_TX      0x10	/* Transmit/Receive Mode Select */
+#define I2C_CTL_TXAK    0x08	/* Transmit Acknowledge Enable  */
+#define I2C_CTL_RSTA    0x04	/* Repeat Start                 */
+/* Status Register */
+#define I2C_STA_CF      0x80	/* Data Transfer       */
+#define I2C_STA_AAS     0x40	/* Adressed As Slave   */
+#define I2C_STA_BB      0x20	/* Bus Busy            */
+#define I2C_STA_AL      0x10	/* Arbitration Lost    */
+#define I2C_STA_SRW     0x04	/* Slave Read/Write    */
+#define I2C_STA_IF      0x02	/* I2C Interrupt       */
+#define I2C_STA_RXAK    0x01	/* Receive Acknowledge */
+/* Interrupt Contol Register */
+#define I2C_INT_BNBE2   0x80	/* Bus Not Busy Enable 2 */
+#define I2C_INT_TE2     0x40	/* Transmit Enable 2     */
+#define I2C_INT_RE2     0x20	/* Receive Enable 2      */
+#define I2C_INT_IE2     0x10	/* Interrupt Enable 2    */
+#define I2C_INT_BNBE1   0x08	/* Bus Not Busy Enable 1 */
+#define I2C_INT_TE1     0x04	/* Transmit Enable 1     */
+#define I2C_INT_RE1     0x02	/* Receive Enable 1      */
+#define I2C_INT_IE1     0x01	/* Interrupt Enable 1    */
+#define I2C_POLL_COUNT 0x100000
+#define I2C_ENABLE      0x00000001
+#define I2C_DISABLE     0x00000002
+#define I2C_START       0x00000004
+#define I2C_REPSTART    0x00000008
+#define I2C_STOP        0x00000010
+#define I2C_BITRATE     0x00000020
+#define I2C_SLAVEADR    0x00000040
+#define I2C_STARTADR    0x00000080
+#undef TWOBYTES
+typedef struct i2c_settings {
+	/* Device settings */
+	int bit_rate;		/* Device bit rate */
+	u8 i2c_adr;		/* I2C address */
+	u8 slv_adr;		/* Slave address */
+#ifdef TWOBYTES
+	u16 str_adr;		/* Start address */
+#else
+	u8 str_adr;		/* Start address */
+#endif
+	int xfer_size;		/* Transfer Size */
+
+	int bI2c_en;		/* Enable or Disable */
+	int cmdFlag;		/* I2c Command Flags */
+} i2cset_t;
+
+/*
+int check_status(PSI2C pi2c, u8 sta_bit, u8 truefalse);
+int i2c_enable(PSI2C pi2c, PI2CSET pi2cSet);
+int i2c_disable(PSI2C pi2c);
+int i2c_start(PSI2C pi2c, PI2CSET pi2cSet);
+int i2c_stop(PSI2C pi2c);
+int i2c_clear(PSI2C pi2c);
+int i2c_readblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data);
+int i2c_writeblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data);
+int i2c_readbyte(PSI2C pi2c, u8 *readb, int *index);
+int i2c_writebyte(PSI2C pi2c, u8 *writeb);
+int SetI2cFDR( PSI2C pi2cRegs, int bitrate );
+*/
+#endif /* __ASSEMBLY__ */
+
+#endif /* __INCi2ccoreh */
diff --git a/cpu/mpc8220/interrupts.c b/cpu/mpc8220/interrupts.c
new file mode 100644
index 0000000..036378c
--- /dev/null
+++ b/cpu/mpc8220/interrupts.c
@@ -0,0 +1,80 @@
+/*
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * interrupts.c - just enough support for the decrementer/timer
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <command.h>
+
+int interrupt_init_cpu (ulong * decrementer_count)
+{
+	*decrementer_count = get_tbclk () / CFG_HZ;
+
+	return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	puts ("external_interrupt (oops!)\n");
+}
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	/* nothing to do here */
+	return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+
+}
+
+void irq_free_handler (int vec)
+{
+
+}
+
+/****************************************************************************/
+
+void
+do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+	puts ("IRQ related functions are unimplemented currently.\n");
+}
diff --git a/cpu/mpc8220/io.S b/cpu/mpc8220/io.S
new file mode 100644
index 0000000..5ecdf55
--- /dev/null
+++ b/cpu/mpc8220/io.S
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2001	Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *			Andreas Heppel <aheppel@sysgo.de>
+ *  Copyright (C) 2003	Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in8 */
+/*  Description:  Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	in8
+in8:
+	lbz	r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in16 */
+/*  Description:  Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	in16
+in16:
+	lhz	r3,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in16r */
+/*  Description:  Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+	.globl	in16r
+in16r:
+	lhbrx	r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in32 */
+/*  Description:  Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	in32
+in32:
+	lwz	3,0(3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  in32r */
+/*  Description:  Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+	.globl	in32r
+in32r:
+	lwbrx	r3,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out8 */
+/*  Description:  Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out8
+out8:
+	stb	r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out16 */
+/*  Description:  Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out16
+out16:
+	sth	r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out16r */
+/*  Description:  Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out16r
+out16r:
+	sthbrx	r4,0,r3
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out32 */
+/*  Description:  Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out32
+out32:
+	stw	r4,0(r3)
+	sync
+	blr
+
+/* ------------------------------------------------------------------------------- */
+/*  Function:	  out32r */
+/*  Description:  Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+	.globl	out32r
+out32r:
+	stwbrx	r4,0,r3
+	sync
+	blr
diff --git a/cpu/mpc8220/loadtask.c b/cpu/mpc8220/loadtask.c
new file mode 100644
index 0000000..6d8b627
--- /dev/null
+++ b/cpu/mpc8220/loadtask.c
@@ -0,0 +1,78 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+/* Multichannel DMA microcode */
+extern int taskTable;
+
+void loadtask (int basetask, int tasks)
+{
+	int *sram = (int *) (MMAP_SRAM + 512);
+	int *task_org = &taskTable;
+	unsigned int start, offset, end;
+	int i;
+
+#ifdef DEBUG
+	printf ("basetask = %d, tasks = %d\n", basetask, tasks);
+	printf ("task_org = 0x%08x\n", (unsigned int) task_org);
+#endif
+
+	/* setup TaskBAR register */
+	*(vu_long *) MMAP_DMA = (MMAP_SRAM + 512);
+
+	/* relocate task table entries */
+	offset = (unsigned int) sram;
+	for (i = basetask; i < basetask + tasks; i++) {
+		sram[i * 8 + 0] = task_org[i * 8 + 0] + offset;
+		sram[i * 8 + 1] = task_org[i * 8 + 1] + offset;
+		sram[i * 8 + 2] = task_org[i * 8 + 2] + offset;
+		sram[i * 8 + 3] = task_org[i * 8 + 3] + offset;
+		sram[i * 8 + 4] = task_org[i * 8 + 4];
+		sram[i * 8 + 5] = task_org[i * 8 + 5];
+		sram[i * 8 + 6] = task_org[i * 8 + 6] + offset;
+		sram[i * 8 + 7] = task_org[i * 8 + 7];
+	}
+
+	/* relocate task descriptors */
+	start = (sram[basetask * 8] - (unsigned int) sram);
+	end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int) sram);
+
+#ifdef DEBUG
+	printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end);
+#endif
+
+	start /= 4;
+	end /= 4;
+	for (i = start; i <= end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	/* relocate variables */
+	start = (sram[basetask * 8 + 2] - (unsigned int) sram);
+	end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 -
+	       (unsigned int) sram);
+	start /= 4;
+	end /= 4;
+	for (i = start; i < end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	/* relocate function decriptors */
+	start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int) sram);
+	end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 -
+	       (unsigned int) sram);
+	start /= 4;
+	end /= 4;
+	for (i = start; i < end; i++) {
+		sram[i] = task_org[i];
+	}
+
+	asm volatile ("sync");
+}
diff --git a/cpu/mpc8220/speed.c b/cpu/mpc8220/speed.c
new file mode 100644
index 0000000..bd79911
--- /dev/null
+++ b/cpu/mpc8220/speed.c
@@ -0,0 +1,119 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+#include <asm/processor.h>
+
+typedef struct pllmultiplier {
+	u8 hid1;
+	int multi;
+	int vco_div;
+} pllcfg_t;
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	pllcfg_t bus2core[] = {
+		{0x10, 2, 8},	/* 1 */
+		{0x08, 2, 4},
+		{0x60, 3, 8},	/* 1.5 */
+		{0x00, 3, 4},
+		{0xc0, 3, 2},
+		{0x28, 4, 4},	/* 2 */
+		{0x20, 4, 2},
+		{0x88, 5, 4},	/* 2.5 */
+		{0x30, 5, 2},
+		{0x80, 6, 4},	/* 3 */
+		{0x40, 6, 2},
+		{0x70, 7, 2},	/* 3.5 */
+		{0x50, 8, 2},	/* 4 */
+		{0x38, 9, 2},	/* 4.5 */
+		{0x58, 10, 2},	/* 5 */
+		{0x48, 11, 2},	/* 5.5 */
+		{0x68, 12, 2},	/* 6 */
+		{0x90, 13, 2},	/* 6.5 */
+		{0xa0, 14, 2},	/* 7 */
+		{0xb0, 15, 2},	/* 7.5 */
+		{0xe0, 16, 2}	/* 8 */
+	};
+	u32 hid1;
+	int i, size;
+
+#if !defined(CFG_MPC8220_CLKIN)
+#error clock measuring not implemented yet - define CFG_MPC8220_CLKIN
+#endif
+
+	gd->inp_clk = CFG_MPC8220_CLKIN;
+
+	/* Bus clock is fixed at 120Mhz for now */
+	/* will do dynamic in the future */
+	gd->bus_clk = CFG_MPC8220_CLKIN * 4;
+
+	/* PCI clock is same as input clock */
+	gd->pci_clk = CFG_MPC8220_CLKIN;
+
+	/* FlexBus is temporary set as the same as input clock */
+	/* will do dynamic in the future */
+	gd->flb_clk = CFG_MPC8220_CLKIN;
+
+	/* CPU Clock - Read HID1 */
+	asm volatile ("mfspr %0, 1009":"=r" (hid1):);
+
+	size = sizeof (bus2core) / sizeof (pllcfg_t);
+	hid1 >>= 24;
+
+	for (i = 0; i < size; i++)
+		if (hid1 == bus2core[i].hid1) {
+			gd->cpu_clk = (bus2core[i].multi * gd->bus_clk) >> 1;
+			/* Input Multiplier is determined by MPLL,
+			   hardcoded for now at 16 */
+			gd->vco_clk = gd->pci_clk * 16;
+			break;
+		}
+
+	/* hardcoded 81MHz for now */
+	gd->pev_clk = 81000000;
+
+	return (0);
+}
+
+int prt_mpc8220_clks (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	printf ("       Bus %ld MHz, CPU %ld MHz, PCI %ld MHz, VCO %ld MHz\n",
+		gd->bus_clk / 1000000, gd->cpu_clk / 1000000,
+		gd->pci_clk / 1000000, gd->vco_clk / 1000000);
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/cpu/mpc8220/start.S b/cpu/mpc8220/start.S
new file mode 100644
index 0000000..6072374
--- /dev/null
+++ b/cpu/mpc8220/start.S
@@ -0,0 +1,774 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000 - 2003 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ *  U-Boot - Startup Code for MPC8220 CPUs
+ */
+#include <config.h>
+#include <mpc8220.h>
+#include <version.h>
+
+#define _LINUX_CONFIG_H 1   /* avoid reading Linux autoconf.h file  */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef	 CONFIG_IDENT_STRING
+#define	 CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * Version string
+ */
+	.data
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION
+	.ascii " (", __DATE__, " - ", __TIME__, ")"
+	.ascii CONFIG_IDENT_STRING, "\0"
+
+/*
+ * Exception vectors
+ */
+	.text
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	li	r21, BOOTFLAG_COLD  /* Normal Power-On	    */
+	nop
+	b	boot_cold
+
+	. = EXC_OFF_SYS_RESET + 0x10
+
+	.globl	_start_warm
+_start_warm:
+	li	r21, BOOTFLAG_WARM  /* Software reboot	    */
+	b	boot_warm
+
+boot_cold:
+boot_warm:
+	mfmsr	r5		    /* save msr contents    */
+
+	/* replace default MBAR base address from 0x80000000
+	    to 0xf0000000 */
+
+#if defined(CFG_DEFAULT_MBAR) && !defined(CFG_RAMBOOT)
+	lis	r3, CFG_MBAR@h
+	ori	r3, r3, CFG_MBAR@l
+
+	/* MBAR is mirrored into the MBAR SPR */
+	mtspr	MBAR,r3
+	lis	r4, CFG_DEFAULT_MBAR@h
+	stw	r3, 0(r4)
+#endif /* CFG_DEFAULT_MBAR */
+
+	/* Initialise the MPC8220 processor core			*/
+	/*--------------------------------------------------------------*/
+
+	bl  init_8220_core
+
+	/* initialize some things that are hard to access from C	*/
+	/*--------------------------------------------------------------*/
+
+	/* set up stack in on-chip SRAM */
+	lis	r3, CFG_INIT_RAM_ADDR@h
+	ori	r3, r3, CFG_INIT_RAM_ADDR@l
+	ori	r1, r3, CFG_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
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16	    /* copy EE bit from saved MSR */
+	rlwimi	r20,r23,0,25,25	    /* copy IP bit from saved MSR */
+	lwz	r6,GOT(transfer_to_handler)
+	mtlr	r6
+	blrl
+.L_Alignment:
+	.long	AlignmentException - _start + EXC_OFF_SYS_RESET
+	.long	int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16	    /* copy EE bit from saved MSR */
+	rlwimi	r20,r23,0,25,25	    /* copy IP bit from saved MSR */
+	lwz	r6,GOT(transfer_to_handler)
+	mtlr	r6
+	blrl
+.L_ProgramCheck:
+	.long	ProgramCheckException - _start + EXC_OFF_SYS_RESET
+	.long	int_return - _start + EXC_OFF_SYS_RESET
+
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+	. = 0x1300
+	/*
+	 * This exception occurs when the program counter matches the
+	 * Instruction Address Breakpoint Register (IABR).
+	 *
+	 * I want the cpu to halt if this occurs so I can hunt around
+	 * with the debugger and look at things.
+	 *
+	 * When DEBUG is defined, both machine check enable (in the MSR)
+	 * and checkstop reset enable (in the reset mode register) are
+	 * turned off and so a checkstop condition will result in the cpu
+	 * halting.
+	 *
+	 * I force the cpu into a checkstop condition by putting an illegal
+	 * instruction here (at least this is the theory).
+	 *
+	 * well - that didnt work, so just do an infinite loop!
+	 */
+1:	b	1b
+#else
+	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+	STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+	STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+	. = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW@h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00	    /* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi			    /* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28		    /* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC			    /* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	    /* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+/*
+ * This code initialises the MPC8220 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+	.globl	init_8220_core
+init_8220_core:
+
+	/* Initialize machine status; enable machine check interrupt	*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, MSR_KERNEL	    /* Set ME and RI flags		*/
+	rlwimi	r3, r5, 0, 25, 25   /* preserve IP bit set by HRCW	*/
+#ifdef DEBUG
+	rlwimi	r3, r5, 0, 21, 22   /* debugger might set SE & BE bits	*/
+#endif
+	SYNC			    /* Some chip revs need this...	*/
+	mtmsr	r3
+	SYNC
+	mtspr	SRR1, r3	    /* Make SRR1 match MSR		*/
+
+	/* Initialize the Hardware Implementation-dependent Registers	*/
+	/* HID0 also contains cache control				*/
+	/*--------------------------------------------------------------*/
+
+	lis	r3, CFG_HID0_INIT@h
+	ori	r3, r3, CFG_HID0_INIT@l
+	SYNC
+	mtspr	HID0, r3
+
+	lis	r3, CFG_HID0_FINAL@h
+	ori	r3, r3, CFG_HID0_FINAL@l
+	SYNC
+	mtspr	HID0, r3
+
+	/* Enable Extra BATs */
+	mfspr	r3, 1011    /* HID2 */
+	lis	r4, 0x0004
+	ori	r4, r4, 0x0000
+	or	r4, r4, r3
+	mtspr	1011, r4
+	sync
+
+	/* clear all BAT's						*/
+	/*--------------------------------------------------------------*/
+
+	li	r0, 0
+	mtspr	DBAT0U, r0
+	mtspr	DBAT0L, r0
+	mtspr	DBAT1U, r0
+	mtspr	DBAT1L, r0
+	mtspr	DBAT2U, r0
+	mtspr	DBAT2L, r0
+	mtspr	DBAT3U, r0
+	mtspr	DBAT3L, r0
+	mtspr	DBAT4U, r0
+	mtspr	DBAT4L, r0
+	mtspr	DBAT5U, r0
+	mtspr	DBAT5L, r0
+	mtspr	DBAT6U, r0
+	mtspr	DBAT6L, r0
+	mtspr	DBAT7U, r0
+	mtspr	DBAT7L, r0
+	mtspr	IBAT0U, r0
+	mtspr	IBAT0L, r0
+	mtspr	IBAT1U, r0
+	mtspr	IBAT1L, r0
+	mtspr	IBAT2U, r0
+	mtspr	IBAT2L, r0
+	mtspr	IBAT3U, r0
+	mtspr	IBAT3L, r0
+	mtspr	IBAT4U, r0
+	mtspr	IBAT4L, r0
+	mtspr	IBAT5U, r0
+	mtspr	IBAT5L, r0
+	mtspr	IBAT6U, r0
+	mtspr	IBAT6L, r0
+	mtspr	IBAT7U, r0
+	mtspr	IBAT7L, r0
+	SYNC
+
+	/* invalidate all tlb's						*/
+	/*								*/
+	/* From the 603e User Manual: "The 603e provides the ability to */
+	/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)	*/
+	/* instruction invalidates the TLB entry indexed by the EA, and */
+	/* operates on both the instruction and data TLBs simultaneously*/
+	/* invalidating four TLB entries (both sets in each TLB). The	*/
+	/* index corresponds to bits 15-19 of the EA. To invalidate all */
+	/* entries within both TLBs, 32 tlbie instructions should be	*/
+	/* issued, incrementing this field by one each time."		*/
+	/*								*/
+	/* "Note that the tlbia instruction is not implemented on the	*/
+	/* 603e."							*/
+	/*								*/
+	/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000	*/
+	/* incrementing by 0x1000 each time. The code below is sort of	*/
+	/* based on code in "flush_tlbs" from arch/ppc/kernel/head.S	*/
+	/*								*/
+	/*--------------------------------------------------------------*/
+
+	li	r3, 32
+	mtctr	r3
+	li	r3, 0
+1:	tlbie	r3
+	addi	r3, r3, 0x1000
+	bdnz	1b
+	SYNC
+
+	/* Done!							*/
+	/*--------------------------------------------------------------*/
+
+	blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+	.globl	icache_enable
+icache_enable:
+	lis	r4, 0
+	ori	r4, r4, CFG_HID0_INIT /* set ICE & ICFI bit		*/
+	rlwinm	r3, r4, 0, 21, 19     /* clear the ICFI bit		*/
+
+	/*
+	 * The setting of the instruction cache enable (ICE) bit must be
+	 * preceded by an isync instruction to prevent the cache from being
+	 * enabled or disabled while an instruction access is in progress.
+	 */
+	isync
+	mtspr	HID0, r4	      /* Enable Instr Cache & Inval cache */
+	mtspr	HID0, r3	      /* using 2 consec instructions	*/
+	isync
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, 0, 17, 15     /* clear the ICE bit		*/
+	mtspr	HID0, r3
+	isync
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+	lis	r4, 0
+	ori	r4, r4, HID0_DCE|HID0_DCFI /* set DCE & DCFI bit	*/
+	rlwinm	r3, r4, 0, 22, 20     /* clear the DCFI bit		*/
+
+	/* Enable address translation in MSR bit */
+	mfmsr	r5
+	ori	r5, r5, 0x
+
+
+	/*
+	 * The setting of the instruction cache enable (ICE) bit must be
+	 * preceded by an isync instruction to prevent the cache from being
+	 * enabled or disabled while an instruction access is in progress.
+	 */
+	isync
+	mtspr	HID0, r4	      /* Enable Data Cache & Inval cache*/
+	mtspr	HID0, r3	      /* using 2 consec instructions	*/
+	isync
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, 0, 18, 16     /* clear the DCE bit */
+	mtspr	HID0, r3
+	isync
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, HID0
+	rlwinm	r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+	blr
+
+	.globl	get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3	    /* Set new stack pointer		*/
+	mr	r9,  r4	    /* Save copy of Global Data pointer */
+	mr	r10, r5	    /* Save copy of Destination Address */
+
+	mr	r3,  r5	    /* Destination Address		*/
+	lis	r4, CFG_MONITOR_BASE@h	/* Source Address	*/
+	ori	r4, r4, CFG_MONITOR_BASE@l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CFG_CACHELINE_SIZE	/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r14, r14, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f	    /* In place copy is not necessary	*/
+	beq	7f	    /* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+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, r14 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries@sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	add	r0,r0,r11
+	stw	r0,0(r3)
+	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+2:	li	r0,__fixup_entries@sectoff@l
+	lwz	r3,GOT(_FIXUP_TABLE_)
+	cmpwi	r0,0
+	mtctr	r0
+	addi	r3,r3,-4
+	beq	4f
+3:	lwzu	r4,4(r3)
+	lwzux	r0,r4,r11
+	add	r0,r0,r11
+	stw	r10,0(r3)
+	stw	r0,0(r4)
+	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	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:
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100   /* reset vector always at 0x100	*/
+
+	cmplw	0, r7, r8
+	bgelr		    /* return if r7>=r8 - just in case	*/
+
+	mflr	r4	    /* save link register		*/
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100	    /* next exception vector	    */
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100	    /* next exception vector	    */
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100	    /* next exception vector	    */
+	cmplw	0, r7, r8
+	blt	4b
+
+	mfmsr	r3		    /* now that the vectors have    */
+	lis	r7, MSR_IP@h	    /* relocated into low memory    */
+	ori	r7, r7, MSR_IP@l    /* MSR[IP] can be turned off    */
+	andc	r3, r3, r7	    /* (if it was on)		    */
+	SYNC			    /* Some chip revs need this...  */
+	mtmsr	r3
+	SYNC
+
+	mtlr	r4		    /* restore link register	    */
+	blr
+
+	/*
+	 * Function: relocate entries for one exception vector
+	 */
+trap_reloc:
+	lwz	r0, 0(r7)	    /* hdlr ...			    */
+	add	r0, r0, r3	    /*	... += dest_addr	    */
+	stw	r0, 0(r7)
+
+	lwz	r0, 4(r7)	    /* int_return ...		    */
+	add	r0, r0, r3	    /*	... += dest_addr	    */
+	stw	r0, 4(r7)
+
+	blr
diff --git a/cpu/mpc8220/traps.c b/cpu/mpc8220/traps.c
new file mode 100644
index 0000000..cdee2be
--- /dev/null
+++ b/cpu/mpc8220/traps.c
@@ -0,0 +1,239 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de)
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler) (struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table (unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM      0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void print_backtrace (unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+
+	printf ("Call backtrace: ");
+	while (sp) {
+		if ((uint) sp > END_OF_MEM)
+			break;
+
+		i = sp[1];
+		if (cnt++ % 7 == 0)
+			printf ("\n");
+		printf ("%08lX ", i);
+		if (cnt > 32)
+			break;
+		sp = (unsigned long *) *sp;
+	}
+	printf ("\n");
+}
+
+void show_regs (struct pt_regs *regs)
+{
+	int i;
+
+	printf ("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+		regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+	printf ("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+		regs->msr,
+		regs->msr & MSR_EE ? 1 : 0, regs->msr & MSR_PR ? 1 : 0,
+		regs->msr & MSR_FP ? 1 : 0, regs->msr & MSR_ME ? 1 : 0,
+		regs->msr & MSR_IR ? 1 : 0, regs->msr & MSR_DR ? 1 : 0);
+
+	printf ("\n");
+	for (i = 0; i < 32; i++) {
+		if ((i % 8) == 0) {
+			printf ("GPR%02d: ", i);
+		}
+
+		printf ("%08lX ", regs->gpr[i]);
+		if ((i % 8) == 7) {
+			printf ("\n");
+		}
+	}
+}
+
+
+void _exception (int signr, struct pt_regs *regs)
+{
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Exception in kernel pc %lx signal %d", regs->nip, signr);
+}
+
+void MachineCheckException (struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table (regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+#if (CONFIG_COMMANDS & CFG_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 (CONFIG_COMMANDS & CFG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Alignment Exception");
+}
+
+void ProgramCheckException (struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Program Check Exception");
+}
+
+void SoftEmuException (struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	show_regs (regs);
+	print_backtrace ((unsigned long *) regs->gpr[1]);
+	panic ("Software Emulation Exception");
+}
+
+
+void UnknownException (struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+	if (debugger_exception_handler
+	    && (*debugger_exception_handler) (regs))
+		return;
+#endif
+	printf ("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+		regs->nip, regs->msr, regs->trap);
+	_exception (0, regs);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint (struct pt_regs *);
+#endif
+
+void DebugException (struct pt_regs *regs)
+{
+
+	printf ("Debugger trap at @ %lx\n", regs->nip);
+	show_regs (regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+	do_bedbug_breakpoint (regs);
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe (uint * addr)
+{
+#if 0
+	int retval;
+
+	__asm__ __volatile__ ("1: lwz %0,0(%1)\n"
+			      "   eieio\n"
+			      "   li %0,0\n"
+			      "2:\n"
+			      ".section .fixup,\"ax\"\n"
+			      "3: li %0,-1\n"
+			      "   b 2b\n"
+			      ".section __ex_table,\"a\"\n"
+			      "   .align 2\n"
+			      "   .long 1b,3b\n"
+			      ".text":"=r" (retval):"r" (addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/cpu/mpc8220/uart.c b/cpu/mpc8220/uart.c
new file mode 100644
index 0000000..fcf947d
--- /dev/null
+++ b/cpu/mpc8220/uart.c
@@ -0,0 +1,128 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+#define PSC_BASE   MMAP_PSC1
+
+#if defined(CONFIG_PSC_CONSOLE)
+int psc_serial_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+	u32 counter;
+
+	/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
+	psc->cr = 0;
+	psc->ipcr_acr = 0;
+	psc->isr_imr = 0;
+
+	/* write to CSR: RX/TX baud rate from timers */
+	psc->sr_csr = 0xdd000000;
+
+	psc->mr1_2 = PSC_MR1_BITS_CHAR_8 | PSC_MR1_NO_PARITY | PSC_MR1_RX_RTS;
+	psc->mr1_2 = PSC_MR2_STOP_BITS_1 | PSC_MR2_TX_CTS;
+
+	/* Setting up BaudRate */
+	counter = ((gd->bus_clk / gd->baudrate)) >> 5;
+	counter++;
+
+	/* write to CTUR: divide counter upper byte */
+	psc->ctur = ((counter & 0xff00) << 16);
+	/* write to CTLR: divide counter lower byte */
+	psc->ctlr = ((counter & 0x00ff) << 24);
+
+	psc->cr = PSC_CR_RST_RX_CMD;
+	psc->cr = PSC_CR_RST_TX_CMD;
+	psc->cr = PSC_CR_RST_ERR_STS_CMD;
+	psc->cr = PSC_CR_RST_BRK_INT_CMD;
+	psc->cr = PSC_CR_RST_MR_PTR_CMD;
+
+	psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE;
+	return (0);
+}
+
+void psc_serial_putc (const char c)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	/* Wait for last character to go. */
+	while (!(psc->sr_csr & PSC_SR_TXEMT));
+
+	psc->xmitbuf[0] = c;
+}
+
+void psc_serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+int psc_serial_getc (void)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+	/* Wait for a character to arrive. */
+	while (!(psc->sr_csr & PSC_SR_RXRDY));
+	return psc->xmitbuf[2];
+}
+
+int psc_serial_tstc (void)
+{
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+	return (psc->sr_csr & PSC_SR_RXRDY);
+}
+
+void psc_serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+	u32 counter;
+
+	counter = ((gd->bus_clk / gd->baudrate)) >> 5;
+	counter++;
+
+	/* write to CTUR: divide counter upper byte */
+	psc->ctur = ((counter & 0xff00) << 16);
+	/* write to CTLR: divide counter lower byte */
+	psc->ctlr = ((counter & 0x00ff) << 24);
+
+	psc->cr = PSC_CR_RST_RX_CMD;
+	psc->cr = PSC_CR_RST_TX_CMD;
+
+	psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE;
+}
+#endif /* CONFIG_PSC_CONSOLE */