[U-Boot] [PATCH v5] powerpc: Partialy restore core of mpc8xx

Christophe Leroy christophe.leroy at c-s.fr
Thu Jun 29 16:52:15 UTC 2017


CS Systemes d'Information (CSSI) manufactures 8xx boards for
critical communication systems. Those boards have been
running U-Boot since 2010 and will have to be maintained
until at least 2027.

commit 5b8e76c35ec312a3f73126bd1a2d2c0965b98a9f
("powerpc, 8xx: remove support for 8xx") orphaned those boards
by removing support for the mpc8xx CPU.

This commit partially restores support for the 8xx, with the
following limitations:
- Restores support for MPC866 and MPC885 only
- Does not restore IDE, PCMCIA, I2C, USB
- Does not restore examples
- Does not restore POST
- Does not restore Ethernet on SCC
- Does not restore bedbug and kgdb support

As the 866 and 885 do not support the following features,
they are not restored either:
- VIDEO / LCD
- RTC clock

The CPM uCODE patch is not restored either, because:
- 866 and 885 already have support for I2C and SPI relocation
without a uCODE patch
- relocation of SMC, I2C or SPI is only needed for using SCCs
for Ethernet or QMC

The dynamic setup/calculation of clocks is removed, we
expect the target being use with the clock and PLPRCR register
defined in the configuration.
All the clock settings for 8xx prior to 866 is removed as
well as we now only support 866 and 885.

The following files are not restored by this patch:

- arch/powerpc/cpu/mpc8xx/bedbug_860.c
- arch/powerpc/cpu/mpc8xx/fec.h
- arch/powerpc/cpu/mpc8xx/kgdb.S
- arch/powerpc/cpu/mpc8xx/plprcr_write.S
- arch/powerpc/cpu/mpc8xx/scc.c
- arch/powerpc/cpu/mpc8xx/upatch.c
- arch/powerpc/cpu/mpc8xx/video.c
- arch/powerpc/include/asm/status_led.h
- arch/powerpc/lib/ide.c
- arch/powerpc/lib/ide.h
- doc/README.MPC866
- drivers/pcmcia/mpc8xx_pcmcia.c
- drivers/rtc/mpc8xx.c
- drivers/usb/gadget/mpc8xx_udc.c
- drivers/video/mpc8xx_lcd.c
- examples/standalone/test_burst.c
- examples/standalone/test_burst.h
- examples/standalone/test_burst_lib.S
- examples/standalone/timer.c
- include/mpc823_lcd.h
- include/usb/mpc8xx_udc.h
- post/cpu/mpc8xx/Makefile
- post/cpu/mpc8xx/cache.c
- post/cpu/mpc8xx/cache_8xx.S
- post/cpu/mpc8xx/ether.c
- post/cpu/mpc8xx/spr.c
- post/cpu/mpc8xx/uart.c
- post/cpu/mpc8xx/usb.c
- post/cpu/mpc8xx/watchdog.c

Some of the restored files are not located in a proper location.
In order to keep traceability of the changes, they will be
moved to their correct location and moved to Kconfig in a
followup patch.

This patch also declares CSSI as point of contact for the update
of the 8xx platform, as those boards are the only ones still
being maintained on the 8xx area. A later patch will add
those boards to the tree.

Signed-off-by: Christophe Leroy <christophe.leroy at c-s.fr>
---
 Applies after the patch "powerpc: remove 4xx support" from Heiko

 v5: Only restore the needed parts.

 v4: Restored some common CONFIG_ removed by 5xx removal in README and config_whitelist
     Removed all impacts on 4xx; Removed a few remaining references to 82xx
     Fixed unbalanced #ifdef in i2c

 v3: Fixed build error in arch/powerpc/include/asm/ppc.h ; removed commproc.h from 4xx

 v2: Tom squashed patches 1-10 of the serie

 .travis.yml                            |   2 +
 MAINTAINERS                            |   2 +-
 README                                 |  62 ++-
 api/api_platform-powerpc.c             |   3 +-
 arch/powerpc/Kconfig                   |   6 +
 arch/powerpc/cpu/mpc8xx/Kconfig        |  13 +
 arch/powerpc/cpu/mpc8xx/Makefile       |  20 +
 arch/powerpc/cpu/mpc8xx/config.mk      |   8 +
 arch/powerpc/cpu/mpc8xx/cpu.c          | 354 +++++++++++++
 arch/powerpc/cpu/mpc8xx/cpu_init.c     | 180 +++++++
 arch/powerpc/cpu/mpc8xx/fdt.c          |  27 +
 arch/powerpc/cpu/mpc8xx/fec.c          | 933 +++++++++++++++++++++++++++++++++
 arch/powerpc/cpu/mpc8xx/interrupts.c   | 278 ++++++++++
 arch/powerpc/cpu/mpc8xx/serial.c       | 564 ++++++++++++++++++++
 arch/powerpc/cpu/mpc8xx/speed.c        |  62 +++
 arch/powerpc/cpu/mpc8xx/spi.c          | 424 +++++++++++++++
 arch/powerpc/cpu/mpc8xx/start.S        | 645 +++++++++++++++++++++++
 arch/powerpc/cpu/mpc8xx/traps.c        | 187 +++++++
 arch/powerpc/include/asm/8xx_immap.h   | 468 +++++++++++++++++
 arch/powerpc/include/asm/cache.h       |  41 +-
 arch/powerpc/include/asm/global_data.h |   3 +
 arch/powerpc/include/asm/iopin_8xx.h   | 379 +++++++++++++
 arch/powerpc/include/asm/ppc.h         |  11 +
 arch/powerpc/include/asm/processor.h   |   5 +-
 arch/powerpc/lib/Kconfig               |   8 +
 arch/powerpc/lib/Makefile              |   1 +
 arch/powerpc/lib/immap.c               | 564 ++++++++++++++++++++
 arch/powerpc/lib/time.c                |  11 +
 cmd/bdinfo.c                           |   3 +-
 cmd/reginfo.c                          |  59 ++-
 include/asm-generic/u-boot.h           |   3 +-
 include/commproc.h                     | 687 ++++++++++++++++++++++++
 include/mpc8xx.h                       |  14 -
 include/ppc_asm.tmpl                   |  46 ++
 include/watchdog.h                     |   5 +
 scripts/config_whitelist.txt           |  33 +-
 36 files changed, 6072 insertions(+), 39 deletions(-)
 create mode 100644 arch/powerpc/cpu/mpc8xx/Kconfig
 create mode 100644 arch/powerpc/cpu/mpc8xx/Makefile
 create mode 100644 arch/powerpc/cpu/mpc8xx/config.mk
 create mode 100644 arch/powerpc/cpu/mpc8xx/cpu.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/cpu_init.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/fdt.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/fec.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/interrupts.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/serial.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/speed.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/spi.c
 create mode 100644 arch/powerpc/cpu/mpc8xx/start.S
 create mode 100644 arch/powerpc/cpu/mpc8xx/traps.c
 create mode 100644 arch/powerpc/include/asm/8xx_immap.h
 create mode 100644 arch/powerpc/include/asm/iopin_8xx.h
 create mode 100644 arch/powerpc/lib/Kconfig
 create mode 100644 arch/powerpc/lib/immap.c
 create mode 100644 include/commproc.h

diff --git a/.travis.yml b/.travis.yml
index a534743911..c4d96a0338 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -210,6 +210,8 @@ matrix:
     - env:
         - BUILDMAN="mpc86xx"
     - env:
+        - BUILDMAN="mpc8xx"
+    - env:
         - BUILDMAN="siemens"
     - env:
         - BUILDMAN="tegra"
diff --git a/MAINTAINERS b/MAINTAINERS
index 957e27c40d..f5fdb0c92a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -324,7 +324,7 @@ S:	Maintained
 F:	arch/powerpc/
 
 POWERPC MPC8XX
-M:	Wolfgang Denk <wd at denx.de>
+M:	Christophe Leroy <christophe.leroy at c-s.fr>
 S:	Maintained
 T:	git git://git.denx.de/u-boot-mpc8xx.git
 F:	arch/powerpc/cpu/mpc8xx/
diff --git a/README b/README
index 5f4f97cb01..fd8465085b 100644
--- a/README
+++ b/README
@@ -328,6 +328,9 @@ The following options need to be configured:
 					  multiple fs option at one time
 					  for marvell soc family
 
+- 8xx CPU Options: (if using an MPC8xx CPU)
+		CONFIG_8xx_GCLK_FREQ	- CPU clock
+
 - 85xx CPU Options:
 		CONFIG_SYS_PPC64
 
@@ -691,10 +694,29 @@ The following options need to be configured:
 		Define this variable to enable hw flow control in serial driver.
 		Current user of this option is drivers/serial/nsl16550.c driver
 
+- Console Interface:
+		Depending on board, define exactly one serial port
+		(like CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2,
+		CONFIG_8xx_CONS_SCC1, ...), or switch off the serial
+		console by defining CONFIG_8xx_CONS_NONE
+
+		Note: if CONFIG_8xx_CONS_NONE is defined, the serial
+		port routines must be defined elsewhere
+		(i.e. serial_init(), serial_getc(), ...)
+
 - Console Baudrate:
 		CONFIG_BAUDRATE - in bps
 		Select one of the baudrates listed in
 		CONFIG_SYS_BAUDRATE_TABLE, see below.
+		CONFIG_SYS_BRGCLK_PRESCALE, baudrate prescale
+
+- Console Rx buffer length
+		With CONFIG_SYS_SMC_RXBUFLEN it is possible to define
+		the maximum receive buffer length for the SMC.
+		This option is actual only for 8xx possible.
+		If using CONFIG_SYS_SMC_RXBUFLEN also CONFIG_SYS_MAXIDLE
+		must be defined, to setup the maximum idle timeout for
+		the SMC.
 
 - Autoboot Command:
 		CONFIG_BOOTCOMMAND
@@ -860,7 +882,7 @@ The following options need to be configured:
 		(configuration option CONFIG_CMD_CACHE) unless you know
 		what you (and your U-Boot users) are doing. Data
 		cache cannot be enabled on systems like the
-		8260 (where accesses to the IMMR region must be
+		8xx (where accesses to the IMMR region must be
 		uncached), and it cannot be disabled on all other
 		systems where we (mis-) use the data cache to hold an
 		initial stack and some data.
@@ -923,9 +945,11 @@ The following options need to be configured:
 		CONFIG_WATCHDOG
 		If this variable is defined, it enables watchdog
 		support for the SoC. There must be support in the SoC
-		specific code for a watchdog. When supported for a
-		specific SoC is available, then no further board specific
-		code should be needed to use it.
+		specific code for a watchdog. For the 8xx
+		CPUs, the SIU Watchdog feature is enabled in the SYPCR
+		register.  When supported for a specific SoC is
+		available, then no further board specific code should
+		be needed to use it.
 
 		CONFIG_HW_WATCHDOG
 		When using a watchdog circuitry external to the used
@@ -3936,7 +3960,7 @@ Low Level (hardware related) configuration options:
 
 - CONFIG_SYS_IMMR:	Physical address of the Internal Memory.
 		DO NOT CHANGE unless you know exactly what you're
-		doing! (11-4) [82xx systems only]
+		doing! (11-4) [MPC8xx systems only]
 
 - CONFIG_SYS_INIT_RAM_ADDR:
 
@@ -3949,6 +3973,7 @@ Low Level (hardware related) configuration options:
 		sequences.
 
 		U-Boot uses the following memory types:
+		- MPC8xx: IMMR (internal memory of the CPU)
 
 - CONFIG_SYS_GBL_DATA_OFFSET:
 
@@ -3968,6 +3993,16 @@ Low Level (hardware related) configuration options:
 		point to an otherwise UNUSED address space between
 		the top of RAM and the start of the PCI space.
 
+- CONFIG_SYS_SIUMCR:	SIU Module Configuration (11-6)
+
+- CONFIG_SYS_SYPCR:	System Protection Control (11-9)
+
+- CONFIG_SYS_TBSCR:	Time Base Status and Control (11-26)
+
+- CONFIG_SYS_PISCR:	Periodic Interrupt Status and Control (11-31)
+
+- CONFIG_SYS_PLPRCR:	PLL, Low-Power, and Reset Control Register (15-30)
+
 - CONFIG_SYS_SCCR:	System Clock and reset Control Register (15-27)
 
 - CONFIG_SYS_OR_TIMING_SDRAM:
@@ -3976,6 +4011,8 @@ Low Level (hardware related) configuration options:
 - CONFIG_SYS_MAMR_PTA:
 		periodic timer for refresh
 
+- CONFIG_SYS_DER:	Debug Event Register (37-47)
+
 - FLASH_BASE0_PRELIM, FLASH_BASE1_PRELIM, CONFIG_SYS_REMAP_OR_AM,
   CONFIG_SYS_PRELIM_OR_AM, CONFIG_SYS_OR_TIMING_FLASH, CONFIG_SYS_OR0_REMAP,
   CONFIG_SYS_OR0_PRELIM, CONFIG_SYS_BR0_PRELIM, CONFIG_SYS_OR1_REMAP, CONFIG_SYS_OR1_PRELIM,
@@ -4061,6 +4098,21 @@ Low Level (hardware related) configuration options:
 		Only for 83xx systems. If specified, then DDR should
 		be configured using CS0 and CS1 instead of CS2 and CS3.
 
+- CONFIG_ETHER_ON_FEC[12]
+		Define to enable FEC[12] on a 8xx series processor.
+
+- CONFIG_FEC[12]_PHY
+		Define to the hardcoded PHY address which corresponds
+		to the given FEC; i. e.
+			#define CONFIG_FEC1_PHY 4
+		means that the PHY with address 4 is connected to FEC1
+
+		When set to -1, means to probe for first available.
+
+- CONFIG_FEC[12]_PHY_NORXERR
+		The PHY does not have a RXERR line (RMII only).
+		(so program the FEC to ignore it).
+
 - CONFIG_RMII
 		Enable RMII mode for all FECs.
 		Note that this is a global option, we can't
diff --git a/api/api_platform-powerpc.c b/api/api_platform-powerpc.c
index d1b54ea4e1..fcfa2ad8ff 100644
--- a/api/api_platform-powerpc.c
+++ b/api/api_platform-powerpc.c
@@ -30,7 +30,8 @@ int platform_sys_info(struct sys_info *si)
 	si->clk_bus = gd->bus_clk;
 	si->clk_cpu = gd->cpu_clk;
 
-#if defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#if defined(CONFIG_8xx) || \
+    defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
 #define bi_bar	bi_immr_base
 #elif defined(CONFIG_MPC83xx)
 #define bi_bar	bi_immrbar
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index c3dba8955d..a7558d59b2 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -29,10 +29,16 @@ config MPC86xx
 	select SYS_FSL_DDR
 	select SYS_FSL_DDR_BE
 
+config 8xx
+	bool "MPC8xx"
+
 endchoice
 
+source "arch/powerpc/lib/Kconfig"
+
 source "arch/powerpc/cpu/mpc83xx/Kconfig"
 source "arch/powerpc/cpu/mpc85xx/Kconfig"
 source "arch/powerpc/cpu/mpc86xx/Kconfig"
+source "arch/powerpc/cpu/mpc8xx/Kconfig"
 
 endmenu
diff --git a/arch/powerpc/cpu/mpc8xx/Kconfig b/arch/powerpc/cpu/mpc8xx/Kconfig
new file mode 100644
index 0000000000..a425cba8aa
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/Kconfig
@@ -0,0 +1,13 @@
+menu "mpc8xx CPU"
+	depends on 8xx
+
+config SYS_CPU
+	default "mpc8xx"
+
+choice
+	prompt "Target select"
+	optional
+
+endchoice
+
+endmenu
diff --git a/arch/powerpc/cpu/mpc8xx/Makefile b/arch/powerpc/cpu/mpc8xx/Makefile
new file mode 100644
index 0000000000..af1f87cb6f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/Makefile
@@ -0,0 +1,20 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+# ccflags-y += -DET_DEBUG
+
+extra-y += start.o
+extra-y += traps.o
+obj-y	+= cpu.o
+obj-y	+= cpu_init.o
+obj-y	+= fec.o
+obj-$(CONFIG_OF_LIBFDT) += fdt.o
+obj-y	+= interrupts.o
+obj-y	+= serial.o
+obj-y	+= speed.o
+obj-y	+= spi.o
+obj-y	+= plprcr_write.o
diff --git a/arch/powerpc/cpu/mpc8xx/config.mk b/arch/powerpc/cpu/mpc8xx/config.mk
new file mode 100644
index 0000000000..485e43d2de
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/config.mk
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2010
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -mstring -mcpu=860 -msoft-float
diff --git a/arch/powerpc/cpu/mpc8xx/cpu.c b/arch/powerpc/cpu/mpc8xx/cpu.c
new file mode 100644
index 0000000000..19392de168
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/cpu.c
@@ -0,0 +1,354 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * m8xx.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm at bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd at denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <netdev.h>
+#include <asm/cache.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char *cpu_warning = "\n         " \
+	"*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***";
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+	char *id_str =
+	NULL;
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint k, m;
+	char buf[32];
+	char pre = 'X';
+	char *mid = "xx";
+	char *suf;
+
+	/* the highest 16 bits should be 0x0050 for a 860 */
+
+	if ((pvr >> 16) != 0x0050)
+		return -1;
+
+	k = (immr << 16) |
+		immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)];
+	m = 0;
+	suf = "";
+
+	/*
+	 * Some boards use sockets so different CPUs can be used.
+	 * We have to check chip version in run time.
+	 */
+	switch (k) {
+	case 0x00020001: pre = 'P'; break;
+	case 0x00030001: break;
+	case 0x00120003: suf = "A"; break;
+	case 0x00130003: suf = "A3"; break;
+
+	case 0x00200004: suf = "B"; break;
+
+	case 0x00300004: suf = "C"; break;
+	case 0x00310004: suf = "C1"; m = 1; break;
+
+	case 0x00200064: mid = "SR"; suf = "B"; break;
+	case 0x00300065: mid = "SR"; suf = "C"; break;
+	case 0x00310065: mid = "SR"; suf = "C1"; m = 1; break;
+	case 0x05010000: suf = "D3"; m = 1; break;
+	case 0x05020000: suf = "D4"; m = 1; break;
+		/* this value is not documented anywhere */
+	case 0x40000000: pre = 'P'; suf = "D"; m = 1; break;
+		/* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */
+	case 0x08010004:		/* Rev. A.0 */
+		suf = "A";
+		/* fall through */
+	case 0x08000003:		/* Rev. 0.3 */
+		pre = 'M'; m = 1;
+		if (id_str == NULL)
+			id_str =
+		"PC866x"; /* Unknown chip from MPC866 family */
+		break;
+	case 0x09000000: pre = 'M'; mid = suf = ""; m = 1;
+		if (id_str == NULL)
+			id_str = "PC885"; /* 870/875/880/885 */
+		break;
+
+	default: suf = NULL; break;
+	}
+
+	if (id_str == NULL)
+		id_str = "PC86x";	/* Unknown 86x chip */
+	if (suf)
+		printf ("%c%s%sZPnn%s", pre, id_str, mid, suf);
+	else
+		printf ("unknown M%s (0x%08x)", id_str, k);
+
+	printf (" at %s MHz: ", strmhz (buf, clock));
+
+	print_size(checkicache(), " I-Cache ");
+	print_size(checkdcache(), " D-Cache");
+
+	/* do we have a FEC (860T/P or 852/859/866/885)? */
+
+	immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+	if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+		printf (" FEC present");
+	}
+
+	if (!m) {
+		puts (cpu_warning);
+	}
+
+	putc ('\n');
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int checkcpu (void)
+{
+	ulong clock = gd->cpu_clk;
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	uint pvr = get_pvr ();
+
+	puts ("CPU:   ");
+
+	/* 850 has PARTNUM 20 */
+	/* 801 has PARTNUM 10 */
+	return check_CPU (clock, pvr, immr);
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache                                                                */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB)              */
+/* the 860 P (plus) has 256 sets of 16 bytes in 4 ways (= 16 kB)             */
+
+int checkicache (void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	u32 cacheon = rd_ic_cst () & IDC_ENABLED;
+
+	u32 k = memctl->memc_br0 & ~0x00007fff;	/* probe in flash memoryarea */
+	u32 m;
+	u32 lines = -1;
+
+	wr_ic_cst (IDC_UNALL);
+	wr_ic_cst (IDC_INVALL);
+	wr_ic_cst (IDC_DISABLE);
+	__asm__ volatile ("isync");
+
+	while (!((m = rd_ic_cst ()) & IDC_CERR2)) {
+		wr_ic_adr (k);
+		wr_ic_cst (IDC_LDLCK);
+		__asm__ volatile ("isync");
+
+		lines++;
+		k += 0x10;				/* the number of bytes in a cacheline */
+	}
+
+	wr_ic_cst (IDC_UNALL);
+	wr_ic_cst (IDC_INVALL);
+
+	if (cacheon)
+		wr_ic_cst (IDC_ENABLE);
+	else
+		wr_ic_cst (IDC_DISABLE);
+
+	__asm__ volatile ("isync");
+
+	return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache                                                                */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB)              */
+/* the 860 P (plus) has 256 sets of 16 bytes in 2 ways (= 8 kB)              */
+/* call with cache disabled                                                  */
+
+int checkdcache (void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	u32 cacheon = rd_dc_cst () & IDC_ENABLED;
+
+	u32 k = memctl->memc_br0 & ~0x00007fff;	/* probe in flash memoryarea */
+	u32 m;
+	u32 lines = -1;
+
+	wr_dc_cst (IDC_UNALL);
+	wr_dc_cst (IDC_INVALL);
+	wr_dc_cst (IDC_DISABLE);
+
+	while (!((m = rd_dc_cst ()) & IDC_CERR2)) {
+		wr_dc_adr (k);
+		wr_dc_cst (IDC_LDLCK);
+		lines++;
+		k += 0x10;	/* the number of bytes in a cacheline */
+	}
+
+	wr_dc_cst (IDC_UNALL);
+	wr_dc_cst (IDC_INVALL);
+
+	if (cacheon)
+		wr_dc_cst (IDC_ENABLE);
+	else
+		wr_dc_cst (IDC_DISABLE);
+
+	return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+	uint i;
+	uint addr = 0;
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+	for (i = 0; i < size; i++) {
+		memctl->memc_mdr = table[i];	/* (16-15) */
+		memctl->memc_mcr = addr | upm;	/* (16-16) */
+		addr++;
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	ulong msr, addr;
+
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	immap->im_clkrst.car_plprcr |= PLPRCR_CSR;	/* Checkstop Reset enable */
+
+	/* Interrupts and MMU off */
+	__asm__ volatile ("mtspr    81, 0");
+	__asm__ volatile ("mfmsr    %0":"=r" (msr));
+
+	msr &= ~0x1030;
+	__asm__ volatile ("mtmsr    %0"::"r" (msr));
+
+	/*
+	 * Trying to execute the next instruction at a non-existing address
+	 * should cause a machine check, resulting in reset
+	 */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+	addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+	/*
+	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
+	 * - sizeof (ulong) is usually a valid address. Better pick an address
+	 * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+	 * "(ulong)-1" used to be a good choice for many systems...
+	 */
+	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+	((void (*)(void)) addr) ();
+	return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ * See sections 14.2 and 14.6 of the User's Manual
+ */
+unsigned long get_tbclk (void)
+{
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	volatile immap_t *immap = (volatile immap_t *)(immr & 0xFFFF0000);
+	ulong oscclk, factor, pll;
+
+	if (immap->im_clkrst.car_sccr & SCCR_TBS) {
+		return (gd->cpu_clk / 16);
+	}
+
+	pll = immap->im_clkrst.car_plprcr;
+
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+
+	/*
+	 * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication
+	 * factor is calculated as follows:
+	 *
+	 *		     MFN
+	 *	     MFI + -------
+	 *		   MFD + 1
+	 * factor =  -----------------
+	 *	     (PDF + 1) * 2^S
+	 *
+	 */
+		factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN)/(PLPRCR_val(MFD)+1))/
+			(PLPRCR_val(PDF)+1) / (1<<PLPRCR_val(S));
+
+	oscclk = gd->cpu_clk / factor;
+
+	if ((immap->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
+		return (oscclk / 4);
+	}
+	return (oscclk / 16);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+	int re_enable = disable_interrupts ();
+
+	reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+	if (re_enable)
+		enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_WATCHDOG)
+
+void reset_8xx_watchdog (volatile immap_t * immr)
+{
+	/*
+	 * All other boards use the MPC8xx Internal Watchdog
+	 */
+	immr->im_siu_conf.sc_swsr = 0x556c;	/* write magic1 */
+	immr->im_siu_conf.sc_swsr = 0xaa39;	/* write magic2 */
+}
+#endif /* CONFIG_WATCHDOG */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(FEC_ENET)
+	fec_initialize(bis);
+#endif
+	return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xx/cpu_init.c b/arch/powerpc/cpu/mpc8xx/cpu_init.c
new file mode 100644
index 0000000000..0f935aff9e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/cpu_init.c
@@ -0,0 +1,180 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <watchdog.h>
+
+#include <mpc8xx.h>
+#include <commproc.h>
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+	volatile memctl8xx_t *memctl = &immr->im_memctl;
+# ifdef CONFIG_SYS_PLPRCR
+	ulong mfmask;
+# endif
+	ulong reg;
+
+	/* SYPCR - contains watchdog control (11-9) */
+
+	immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+	reset_8xx_watchdog (immr);
+#endif /* CONFIG_WATCHDOG */
+
+	/* SIUMCR - contains debug pin configuration (11-6) */
+	immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR;
+	/* initialize timebase status and control register (11-26) */
+	/* unlock TBSCRK */
+
+	immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+	immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR;
+
+	/* initialize the PIT (11-31) */
+
+	immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+	immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+	/* System integration timers. Don't change EBDF! (15-27) */
+
+	immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+	reg = immr->im_clkrst.car_sccr;
+	reg &= SCCR_MASK;
+	reg |= CONFIG_SYS_SCCR;
+	immr->im_clkrst.car_sccr = reg;
+
+	/* PLL (CPU clock) settings (15-30) */
+
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+	/* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
+	 * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
+	 * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the current MF
+	 * field value.
+	 *
+	 * For newer (starting MPC866) chips PLPRCR layout is different.
+	 */
+#ifdef CONFIG_SYS_PLPRCR
+	   mfmask = PLPRCR_MFACT_MSK;
+
+	if ((CONFIG_SYS_PLPRCR & mfmask) != 0)
+	   reg = CONFIG_SYS_PLPRCR;			/* reset control bits   */
+	else {
+	   reg = immr->im_clkrst.car_plprcr;
+	   reg &= mfmask;			/* isolate MF-related fields */
+	   reg |= CONFIG_SYS_PLPRCR;			/* reset control bits   */
+	}
+	immr->im_clkrst.car_plprcr = reg;
+#endif
+
+	/*
+	 * Memory Controller:
+	 */
+
+	/* perform BR0 reset that MPC850 Rev. A can't guarantee */
+	reg = memctl->memc_br0;
+	reg &= BR_PS_MSK;	/* Clear everything except Port Size bits */
+	reg |= BR_V;		/* then add just the "Bank Valid" bit     */
+	memctl->memc_br0 = reg;
+
+	/* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
+	 * preliminary addresses - these have to be modified later
+	 * when FLASH size has been determined
+	 *
+	 * Depending on the size of the memory region defined by
+	 * CONFIG_SYS_OR0_REMAP some boards (wide address mask) allow to map the
+	 * CONFIG_SYS_MONITOR_BASE, while others (narrower address mask) can't
+	 * map CONFIG_SYS_MONITOR_BASE.
+	 *
+	 * For example, for CONFIG_IVMS8, the CONFIG_SYS_MONITOR_BASE is
+	 * 0xff000000, but CONFIG_SYS_OR0_REMAP's address mask is 0xfff80000.
+	 *
+	 * If BR0 wasn't loaded with address base 0xff000000, then BR0's
+	 * base address remains as 0x00000000. However, the address mask
+	 * have been narrowed to 512Kb, so CONFIG_SYS_MONITOR_BASE wasn't mapped
+	 * into the Bank0.
+	 *
+	 * This is why CONFIG_IVMS8 and similar boards must load BR0 with
+	 * CONFIG_SYS_BR0_PRELIM in advance.
+	 *
+	 * [Thanks to Michael Liao for this explanation.
+	 *  I owe him a free beer. - wd]
+	 */
+
+#if defined(CONFIG_SYS_OR0_REMAP)
+	memctl->memc_or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+	memctl->memc_or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR5_REMAP)
+	memctl->memc_or5 = CONFIG_SYS_OR5_REMAP;
+#endif
+
+	/* now restrict to preliminary range */
+	memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+	memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
+	memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+	memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
+	memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+	memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
+	memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+	memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR4_PRELIM) && defined(CONFIG_SYS_BR4_PRELIM)
+	memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
+	memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR5_PRELIM) && defined(CONFIG_SYS_BR5_PRELIM)
+	memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
+	memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR6_PRELIM) && defined(CONFIG_SYS_BR6_PRELIM)
+	memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
+	memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR7_PRELIM) && defined(CONFIG_SYS_BR7_PRELIM)
+	memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
+	memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+	/*
+	 * Reset CPM
+	 */
+	immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG;
+	do {			/* Spin until command processed     */
+		__asm__ ("eieio");
+	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+	return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/fdt.c b/arch/powerpc/cpu/mpc8xx/fdt.c
new file mode 100644
index 0000000000..34d36478d3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fdt.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2008 (C) Bryan O'Donoghue
+ *
+ * Code copied & edited from Freescale mpc85xx stuff.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"timebase-frequency", get_tbclk(), 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"bus-frequency", bd->bi_busfreq, 1);
+	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+		"clock-frequency", bd->bi_intfreq, 1);
+	do_fixup_by_compat_u32(blob, "fsl,cpm-brg", "clock-frequency",
+		gd->arch.brg_clk, 1);
+
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/fec.c b/arch/powerpc/cpu/mpc8xx/fec.c
new file mode 100644
index 0000000000..b27310fffb
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fec.c
@@ -0,0 +1,933 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <commproc.h>
+#include <malloc.h>
+#include <net.h>
+
+#include <phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#undef	ET_DEBUG
+
+#if defined(CONFIG_CMD_NET) && \
+	(defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2))
+
+/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */
+#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2)
+#define CONFIG_ETHER_ON_FEC1 1
+#endif
+
+/* define WANT_MII when MII support is required */
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY)
+#define WANT_MII
+#else
+#undef WANT_MII
+#endif
+
+#if defined(WANT_MII)
+#include <miiphy.h>
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#endif
+
+#if defined(CONFIG_RMII) && !defined(WANT_MII)
+#error RMII support is unusable without a working PHY.
+#endif
+
+#ifdef CONFIG_SYS_DISCOVER_PHY
+static int mii_discover_phy(struct eth_device *dev);
+#endif
+
+int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg);
+int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
+			u16 value);
+
+static struct ether_fcc_info_s
+{
+	int ether_index;
+	int fecp_offset;
+	int phy_addr;
+	int actual_phy_addr;
+	int initialized;
+}
+	ether_fcc_info[] = {
+#if defined(CONFIG_ETHER_ON_FEC1)
+	{
+		0,
+		offsetof(immap_t, im_cpm.cp_fec1),
+#if defined(CONFIG_FEC1_PHY)
+		CONFIG_FEC1_PHY,
+#else
+		-1,	/* discover */
+#endif
+		-1,
+		0,
+
+	},
+#endif
+#if defined(CONFIG_ETHER_ON_FEC2)
+	{
+		1,
+		offsetof(immap_t, im_cpm.cp_fec2),
+#if defined(CONFIG_FEC2_PHY)
+		CONFIG_FEC2_PHY,
+#else
+		-1,
+#endif
+		-1,
+		0,
+	},
+#endif
+};
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH  1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 100
+
+#define PKT_MAXBUF_SIZE		1518
+#define PKT_MINBUF_SIZE		64
+#define PKT_MAXBLR_SIZE		1520
+
+#ifdef __GNUC__
+static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8)));
+#else
+#error txbuf must be aligned.
+#endif
+
+static uint rxIdx;	/* index of the current RX buffer */
+static uint txIdx;	/* index of the current TX buffer */
+
+/*
+  * FEC Ethernet Tx and Rx buffer descriptors allocated at the
+  *  immr->udata_bd address on Dual-Port RAM
+  * Provide for Double Buffering
+  */
+
+typedef volatile struct CommonBufferDescriptor {
+    cbd_t rxbd[PKTBUFSRX];		/* Rx BD */
+    cbd_t txbd[TX_BUF_CNT];		/* Tx BD */
+} RTXBD;
+
+static RTXBD *rtx = NULL;
+
+static int fec_send(struct eth_device *dev, void *packet, int length);
+static int fec_recv(struct eth_device* dev);
+static int fec_init(struct eth_device* dev, bd_t * bd);
+static void fec_halt(struct eth_device* dev);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static void __mii_init(void);
+#endif
+
+int fec_initialize(bd_t *bis)
+{
+	struct eth_device* dev;
+	struct ether_fcc_info_s *efis;
+	int             i;
+
+	for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++) {
+
+		dev = malloc(sizeof(*dev));
+		if (dev == NULL)
+			hang();
+
+		memset(dev, 0, sizeof(*dev));
+
+		/* for FEC1 make sure that the name of the interface is the same
+		   as the old one for compatibility reasons */
+		if (i == 0) {
+			strcpy(dev->name, "FEC");
+		} else {
+			sprintf (dev->name, "FEC%d",
+				ether_fcc_info[i].ether_index + 1);
+		}
+
+		efis = &ether_fcc_info[i];
+
+		/*
+		 * reset actual phy addr
+		 */
+		efis->actual_phy_addr = -1;
+
+		dev->priv = efis;
+		dev->init = fec_init;
+		dev->halt = fec_halt;
+		dev->send = fec_send;
+		dev->recv = fec_recv;
+
+		eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+		int retval;
+		struct mii_dev *mdiodev = mdio_alloc();
+		if (!mdiodev)
+			return -ENOMEM;
+		strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+		mdiodev->read = fec8xx_miiphy_read;
+		mdiodev->write = fec8xx_miiphy_write;
+
+		retval = mdio_register(mdiodev);
+		if (retval < 0)
+			return retval;
+#endif
+	}
+	return 1;
+}
+
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+	int j, rc;
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+	/* section 16.9.23.3
+	 * Wait for ready
+	 */
+	j = 0;
+	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+		udelay(1);
+		j++;
+	}
+	if (j>=TOUT_LOOP) {
+		printf("TX not ready\n");
+	}
+
+	rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
+	rtx->txbd[txIdx].cbd_datlen  = length;
+	rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST;
+	__asm__ ("eieio");
+
+	/* Activate transmit Buffer Descriptor polling */
+	fecp->fec_x_des_active = 0x01000000;	/* Descriptor polling active	*/
+
+	j = 0;
+	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+		udelay(1);
+		j++;
+	}
+	if (j>=TOUT_LOOP) {
+		printf("TX timeout\n");
+	}
+#ifdef ET_DEBUG
+	printf("%s[%d] %s: cycles: %d    status: %x  retry cnt: %d\n",
+	__FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc,
+	(rtx->txbd[txIdx].cbd_sc & 0x003C)>>2);
+#endif
+	/* return only status bits */;
+	rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS);
+
+	txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+	return rc;
+}
+
+static int fec_recv (struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp =
+		(volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+	int length;
+
+	for (;;) {
+		/* section 16.9.23.2 */
+		if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+			length = -1;
+			break;	/* nothing received - leave for() loop */
+		}
+
+		length = rtx->rxbd[rxIdx].cbd_datlen;
+
+		if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
+#ifdef ET_DEBUG
+			printf ("%s[%d] err: %x\n",
+				__FUNCTION__, __LINE__,
+				rtx->rxbd[rxIdx].cbd_sc);
+#endif
+		} else {
+			uchar *rx = net_rx_packets[rxIdx];
+
+			length -= 4;
+
+#if defined(CONFIG_CMD_CDP)
+			if ((rx[0] & 1) != 0 &&
+			    memcmp((uchar *)rx, net_bcast_ethaddr, 6) != 0 &&
+			    !is_cdp_packet((uchar *)rx))
+				rx = NULL;
+#endif
+			/*
+			 * Pass the packet up to the protocol layers.
+			 */
+			if (rx != NULL)
+				net_process_received_packet(rx, length);
+		}
+
+		/* Give the buffer back to the FEC. */
+		rtx->rxbd[rxIdx].cbd_datlen = 0;
+
+		/* wrap around buffer index when necessary */
+		if ((rxIdx + 1) >= PKTBUFSRX) {
+			rtx->rxbd[PKTBUFSRX - 1].cbd_sc =
+				(BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+			rxIdx = 0;
+		} else {
+			rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+			rxIdx++;
+		}
+
+		__asm__ ("eieio");
+
+		/* Try to fill Buffer Descriptors */
+		fecp->fec_r_des_active = 0x01000000;	/* Descriptor polling active    */
+	}
+
+	return length;
+}
+
+/**************************************************************
+ *
+ * FEC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+#define	FEC_ECNTRL_PINMUX	0x00000004
+#define FEC_ECNTRL_ETHER_EN	0x00000002
+#define FEC_ECNTRL_RESET	0x00000001
+
+#define FEC_RCNTRL_BC_REJ	0x00000010
+#define FEC_RCNTRL_PROM		0x00000008
+#define FEC_RCNTRL_MII_MODE	0x00000004
+#define FEC_RCNTRL_DRT		0x00000002
+#define FEC_RCNTRL_LOOP		0x00000001
+
+#define FEC_TCNTRL_FDEN		0x00000004
+#define FEC_TCNTRL_HBC		0x00000002
+#define FEC_TCNTRL_GTS		0x00000001
+
+#define	FEC_RESET_DELAY		50
+
+#if defined(CONFIG_RMII)
+
+static inline void fec_10Mbps(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	int fecidx = efis->ether_index;
+	uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+	if ((unsigned int)fecidx >= 2)
+		hang();
+
+	((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr |=  mask;
+}
+
+static inline void fec_100Mbps(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	int fecidx = efis->ether_index;
+	uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+	if ((unsigned int)fecidx >= 2)
+		hang();
+
+	((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr &= ~mask;
+}
+
+#endif
+
+static inline void fec_full_duplex(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+	fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT;
+	fecp->fec_x_cntrl |=  FEC_TCNTRL_FDEN;	/* FD enable */
+}
+
+static inline void fec_half_duplex(struct eth_device *dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+	fecp->fec_r_cntrl |=  FEC_RCNTRL_DRT;
+	fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN;	/* FD disable */
+}
+
+static void fec_pin_init(int fecidx)
+{
+	bd_t           *bd = gd->bd;
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	/*
+	 * Set MII speed to 2.5 MHz or slightly below.
+	 *
+	 * According to the MPC860T (Rev. D) Fast ethernet controller user
+	 * manual (6.2.14),
+	 * the MII management interface clock must be less than or equal
+	 * to 2.5 MHz.
+	 * This MDC frequency is equal to system clock / (2 * MII_SPEED).
+	 * Then MII_SPEED = system_clock / 2 * 2,5 MHz.
+	 *
+	 * All MII configuration is done via FEC1 registers:
+	 */
+	immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII)
+	/* use MDC for MII */
+	immr->im_ioport.iop_pdpar |=  0x0080;
+	immr->im_ioport.iop_pddir &= ~0x0080;
+#endif
+
+	if (fecidx == 0) {
+#if defined(CONFIG_ETHER_ON_FEC1)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+
+		immr->im_ioport.iop_papar |=  0xf830;
+		immr->im_ioport.iop_padir |=  0x0830;
+		immr->im_ioport.iop_padir &= ~0xf000;
+
+		immr->im_cpm.cp_pbpar     |=  0x00001001;
+		immr->im_cpm.cp_pbdir     &= ~0x00001001;
+
+		immr->im_ioport.iop_pcpar |=  0x000c;
+		immr->im_ioport.iop_pcdir &= ~0x000c;
+
+		immr->im_cpm.cp_pepar     |=  0x00000003;
+		immr->im_cpm.cp_pedir     |=  0x00000003;
+		immr->im_cpm.cp_peso      &= ~0x00000003;
+
+		immr->im_cpm.cp_cptr      &= ~0x00000100;
+
+#else
+
+#if !defined(CONFIG_FEC1_PHY_NORXERR)
+		immr->im_ioport.iop_papar |=  0x1000;
+		immr->im_ioport.iop_padir &= ~0x1000;
+#endif
+		immr->im_ioport.iop_papar |=  0xe810;
+		immr->im_ioport.iop_padir |=  0x0810;
+		immr->im_ioport.iop_padir &= ~0xe000;
+
+		immr->im_cpm.cp_pbpar     |=  0x00000001;
+		immr->im_cpm.cp_pbdir     &= ~0x00000001;
+
+		immr->im_cpm.cp_cptr      |=  0x00000100;
+		immr->im_cpm.cp_cptr      &= ~0x00000050;
+
+#endif /* !CONFIG_RMII */
+
+#else
+		/*
+		 * Configure all of port D for MII.
+		 */
+		immr->im_ioport.iop_pdpar = 0x1fff;
+
+		/*
+		 * Bits moved from Rev. D onward
+		 */
+		if ((get_immr(0) & 0xffff) < 0x0501)
+			immr->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
+		else
+			immr->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
+#endif
+
+#endif	/* CONFIG_ETHER_ON_FEC1 */
+	} else if (fecidx == 1) {
+
+#if defined(CONFIG_ETHER_ON_FEC2)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+		immr->im_cpm.cp_pepar     |=  0x0003fffc;
+		immr->im_cpm.cp_pedir     |=  0x0003fffc;
+		immr->im_cpm.cp_peso      &= ~0x000087fc;
+		immr->im_cpm.cp_peso      |=  0x00037800;
+
+		immr->im_cpm.cp_cptr      &= ~0x00000080;
+#else
+
+#if !defined(CONFIG_FEC2_PHY_NORXERR)
+		immr->im_cpm.cp_pepar     |=  0x00000010;
+		immr->im_cpm.cp_pedir     |=  0x00000010;
+		immr->im_cpm.cp_peso      &= ~0x00000010;
+#endif
+		immr->im_cpm.cp_pepar     |=  0x00039620;
+		immr->im_cpm.cp_pedir     |=  0x00039620;
+		immr->im_cpm.cp_peso      |=  0x00031000;
+		immr->im_cpm.cp_peso      &= ~0x00008620;
+
+		immr->im_cpm.cp_cptr      |=  0x00000080;
+		immr->im_cpm.cp_cptr      &= ~0x00000028;
+#endif /* CONFIG_RMII */
+
+#endif /* CONFIG_MPC885_FAMILY */
+
+#endif /* CONFIG_ETHER_ON_FEC2 */
+
+	}
+}
+
+static int fec_reset(volatile fec_t *fecp)
+{
+	int i;
+
+	/* Whack a reset.
+	 * A delay is required between a reset of the FEC block and
+	 * initialization of other FEC registers because the reset takes
+	 * some time to complete. If you don't delay, subsequent writes
+	 * to FEC registers might get killed by the reset routine which is
+	 * still in progress.
+	 */
+
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay (1);
+	}
+	if (i == FEC_RESET_DELAY)
+		return -1;
+
+	return 0;
+}
+
+static int fec_init (struct eth_device *dev, bd_t * bd)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile fec_t *fecp =
+		(volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+	int i;
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	/* the MII interface is connected to FEC1
+	 * so for the miiphy_xxx function to work we must
+	 * call mii_init since fec_halt messes the thing up
+	 */
+	if (efis->ether_index != 0)
+		__mii_init();
+#endif
+
+	if (fec_reset(fecp) < 0)
+		printf ("FEC_RESET_DELAY timeout\n");
+
+	/* We use strictly polling mode only
+	 */
+	fecp->fec_imask = 0;
+
+	/* Clear any pending interrupt
+	 */
+	fecp->fec_ievent = 0xffc0;
+
+	/* No need to set the IVEC register */
+
+	/* Set station address
+	 */
+#define ea dev->enetaddr
+	fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+	fecp->fec_addr_high = (ea[4] << 8) | (ea[5]);
+#undef ea
+
+#if defined(CONFIG_CMD_CDP)
+	/*
+	 * Turn on multicast address hash table
+	 */
+	fecp->fec_hash_table_high = 0xffffffff;
+	fecp->fec_hash_table_low = 0xffffffff;
+#else
+	/* Clear multicast address hash table
+	 */
+	fecp->fec_hash_table_high = 0;
+	fecp->fec_hash_table_low = 0;
+#endif
+
+	/* Set maximum receive buffer size.
+	 */
+	fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+
+	/* Set maximum frame length
+	 */
+	fecp->fec_r_hash = PKT_MAXBUF_SIZE;
+
+	/*
+	 * Setup Buffers and Buffer Desriptors
+	 */
+	rxIdx = 0;
+	txIdx = 0;
+
+	if (!rtx)
+		rtx = (RTXBD *)(immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
+	/*
+	 * Setup Receiver Buffer Descriptors (13.14.24.18)
+	 * Settings:
+	 *     Empty, Wrap
+	 */
+	for (i = 0; i < PKTBUFSRX; i++) {
+		rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+		rtx->rxbd[i].cbd_datlen = 0;	/* Reset */
+		rtx->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i];
+	}
+	rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+	/*
+	 * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+	 * Settings:
+	 *    Last, Tx CRC
+	 */
+	for (i = 0; i < TX_BUF_CNT; i++) {
+		rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+		rtx->txbd[i].cbd_datlen = 0;	/* Reset */
+		rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
+	}
+	rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+	/* Set receive and transmit descriptor base
+	 */
+	fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]);
+	fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]);
+
+	/* Enable MII mode
+	 */
+#if 0				/* Full duplex mode */
+	fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;
+	fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;
+#else  /* Half duplex mode */
+	fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
+	fecp->fec_x_cntrl = 0;
+#endif
+
+	/* Enable big endian and don't care about SDMA FC.
+	 */
+	fecp->fec_fun_code = 0x78000000;
+
+	/*
+	 * Setup the pin configuration of the FEC
+	 */
+	fec_pin_init (efis->ether_index);
+
+	rxIdx = 0;
+	txIdx = 0;
+
+	/*
+	 * Now enable the transmit and receive processing
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+
+	if (efis->phy_addr == -1) {
+#ifdef CONFIG_SYS_DISCOVER_PHY
+		/*
+		 * wait for the PHY to wake up after reset
+		 */
+		efis->actual_phy_addr = mii_discover_phy (dev);
+
+		if (efis->actual_phy_addr == -1) {
+			printf ("Unable to discover phy!\n");
+			return -1;
+		}
+#else
+		efis->actual_phy_addr = -1;
+#endif
+	} else {
+		efis->actual_phy_addr = efis->phy_addr;
+	}
+
+#if defined(CONFIG_MII) && defined(CONFIG_RMII)
+	/*
+	 * adapt the RMII speed to the speed of the phy
+	 */
+	if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) {
+		fec_100Mbps (dev);
+	} else {
+		fec_10Mbps (dev);
+	}
+#endif
+
+#if defined(CONFIG_MII)
+	/*
+	 * adapt to the half/full speed settings
+	 */
+	if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) {
+		fec_full_duplex (dev);
+	} else {
+		fec_half_duplex (dev);
+	}
+#endif
+
+	/* And last, try to fill Rx Buffer Descriptors */
+	fecp->fec_r_des_active = 0x01000000;	/* Descriptor polling active    */
+
+	efis->initialized = 1;
+
+	return 0;
+}
+
+
+static void fec_halt(struct eth_device* dev)
+{
+	struct ether_fcc_info_s *efis = dev->priv;
+	volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+	int i;
+
+	/* avoid halt if initialized; mii gets stuck otherwise */
+	if (!efis->initialized)
+		return;
+
+	/* Whack a reset.
+	 * A delay is required between a reset of the FEC block and
+	 * initialization of other FEC registers because the reset takes
+	 * some time to complete. If you don't delay, subsequent writes
+	 * to FEC registers might get killed by the reset routine which is
+	 * still in progress.
+	 */
+
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay (1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printf ("FEC_RESET_DELAY timeout\n");
+		return;
+	}
+
+	efis->initialized = 0;
+}
+
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+/* Make MII read/write commands for the FEC.
+*/
+
+#define mk_mii_read(ADDR, REG)	(0x60020000 | ((ADDR << 23) | \
+						(REG & 0x1f) << 18))
+
+#define mk_mii_write(ADDR, REG, VAL)	(0x50020000 | ((ADDR << 23) | \
+						(REG & 0x1f) << 18) | \
+						(VAL & 0xffff))
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
+#define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
+#define FEC_ENET_BABT	((uint)0x20000000)	/* Babbling transmitter */
+#define FEC_ENET_GRA	((uint)0x10000000)	/* Graceful stop complete */
+#define FEC_ENET_TXF	((uint)0x08000000)	/* Full frame transmitted */
+#define FEC_ENET_TXB	((uint)0x04000000)	/* A buffer was transmitted */
+#define FEC_ENET_RXF	((uint)0x02000000)	/* Full frame received */
+#define FEC_ENET_RXB	((uint)0x01000000)	/* A buffer was received */
+#define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
+#define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
+
+/* PHY identification
+ */
+#define PHY_ID_LXT970		0x78100000	/* LXT970 */
+#define PHY_ID_LXT971		0x001378e0	/* LXT971 and 972 */
+#define PHY_ID_82555		0x02a80150	/* Intel 82555 */
+#define PHY_ID_QS6612		0x01814400	/* QS6612 */
+#define PHY_ID_AMD79C784	0x00225610	/* AMD 79C784 */
+#define PHY_ID_LSI80225		0x0016f870	/* LSI 80225 */
+#define PHY_ID_LSI80225B	0x0016f880	/* LSI 80225/B */
+#define PHY_ID_DM9161		0x0181B880	/* Davicom DM9161 */
+#define PHY_ID_KSM8995M		0x00221450	/* MICREL KS8995MA */
+
+/* send command to phy using mii, wait for result */
+static uint
+mii_send(uint mii_cmd)
+{
+	uint mii_reply;
+	volatile fec_t	*ep;
+	int cnt;
+
+	ep = &(((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_fec);
+
+	ep->fec_mii_data = mii_cmd;	/* command to phy */
+
+	/* wait for mii complete */
+	cnt = 0;
+	while (!(ep->fec_ievent & FEC_ENET_MII)) {
+		if (++cnt > 1000) {
+			printf("mii_send STUCK!\n");
+			break;
+		}
+	}
+	mii_reply = ep->fec_mii_data;		/* result from phy */
+	ep->fec_ievent = FEC_ENET_MII;		/* clear MII complete */
+#if 0
+	printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
+		__FILE__,__LINE__,__FUNCTION__,mii_cmd,mii_reply);
+#endif
+	return (mii_reply & 0xffff);		/* data read from phy */
+}
+#endif
+
+#if defined(CONFIG_SYS_DISCOVER_PHY)
+static int mii_discover_phy(struct eth_device *dev)
+{
+#define MAX_PHY_PASSES 11
+	uint phyno;
+	int  pass;
+	uint phytype;
+	int phyaddr;
+
+	phyaddr = -1;	/* didn't find a PHY yet */
+	for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
+		if (pass > 1) {
+			/* PHY may need more time to recover from reset.
+			 * The LXT970 needs 50ms typical, no maximum is
+			 * specified, so wait 10ms before try again.
+			 * With 11 passes this gives it 100ms to wake up.
+			 */
+			udelay(10000);	/* wait 10ms */
+		}
+		for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
+			phytype = mii_send(mk_mii_read(phyno, MII_PHYSID2));
+#ifdef ET_DEBUG
+			printf("PHY type 0x%x pass %d type ", phytype, pass);
+#endif
+			if (phytype != 0xffff) {
+				phyaddr = phyno;
+				phytype |= mii_send(mk_mii_read(phyno,
+								MII_PHYSID1)) << 16;
+
+#ifdef ET_DEBUG
+				printf("PHY @ 0x%x pass %d type ",phyno,pass);
+				switch (phytype & 0xfffffff0) {
+				case PHY_ID_LXT970:
+					printf("LXT970\n");
+					break;
+				case PHY_ID_LXT971:
+					printf("LXT971\n");
+					break;
+				case PHY_ID_82555:
+					printf("82555\n");
+					break;
+				case PHY_ID_QS6612:
+					printf("QS6612\n");
+					break;
+				case PHY_ID_AMD79C784:
+					printf("AMD79C784\n");
+					break;
+				case PHY_ID_LSI80225B:
+					printf("LSI L80225/B\n");
+					break;
+				case PHY_ID_DM9161:
+					printf("Davicom DM9161\n");
+					break;
+				case PHY_ID_KSM8995M:
+					printf("MICREL KS8995M\n");
+					break;
+				default:
+					printf("0x%08x\n", phytype);
+					break;
+				}
+#endif
+			}
+		}
+	}
+	if (phyaddr < 0) {
+		printf("No PHY device found.\n");
+	}
+	return phyaddr;
+}
+#endif	/* CONFIG_SYS_DISCOVER_PHY */
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
+
+/****************************************************************************
+ * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet
+ * This function is a subset of eth_init
+ ****************************************************************************
+ */
+static void __mii_init(void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+	if (fec_reset(fecp) < 0)
+		printf ("FEC_RESET_DELAY timeout\n");
+
+	/* We use strictly polling mode only
+	 */
+	fecp->fec_imask = 0;
+
+	/* Clear any pending interrupt
+	 */
+	fecp->fec_ievent = 0xffc0;
+
+	/* Now enable the transmit and receive processing
+	 */
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+}
+
+void mii_init (void)
+{
+	int i;
+
+	__mii_init();
+
+	/* Setup the pin configuration of the FEC(s)
+	*/
+	for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++)
+		fec_pin_init(ether_fcc_info[i].ether_index);
+}
+
+/*****************************************************************************
+ * Read and write a MII PHY register, routines used by MII Utilities
+ *
+ * FIXME: These routines are expected to return 0 on success, but mii_send
+ *	  does _not_ return an error code. Maybe 0xFFFF means error, i.e.
+ *	  no PHY connected...
+ *	  For now always return 0.
+ * FIXME: These routines only work after calling eth_init() at least once!
+ *	  Otherwise they hang in mii_send() !!! Sorry!
+ *****************************************************************************/
+
+int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	unsigned short value = 0;
+	short rdreg;    /* register working value */
+
+#ifdef MII_DEBUG
+	printf ("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
+#endif
+	rdreg = mii_send(mk_mii_read(addr, reg));
+
+	value = rdreg;
+#ifdef MII_DEBUG
+	printf ("0x%04x\n", value);
+#endif
+	return value;
+}
+
+int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
+			u16 value)
+{
+#ifdef MII_DEBUG
+	printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+#endif
+	(void)mii_send(mk_mii_write(addr, reg, value));
+
+#ifdef MII_DEBUG
+	printf ("0x%04x\n", value);
+#endif
+	return 0;
+}
+#endif
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/interrupts.c b/arch/powerpc/cpu/mpc8xx/interrupts.c
new file mode 100644
index 0000000000..482ceecb9f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/interrupts.c
@@ -0,0 +1,278 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <asm/processor.h>
+#include <commproc.h>
+
+/************************************************************************/
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct interrupt_action {
+	interrupt_handler_t *handler;
+	void *arg;
+};
+
+static struct interrupt_action cpm_vecs[CPMVEC_NR];
+static struct interrupt_action irq_vecs[NR_IRQS];
+
+static void cpm_interrupt_init (void);
+static void cpm_interrupt (void *regs);
+
+/************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+	/* disable all interrupts */
+	immr->im_siu_conf.sc_simask = 0;
+
+	/* Configure CPM interrupts */
+	cpm_interrupt_init ();
+
+	return (0);
+}
+
+/************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	int irq;
+	ulong simask, newmask;
+	ulong vec, v_bit;
+
+	/*
+	 * read the SIVEC register and shift the bits down
+	 * to get the irq number
+	 */
+	vec = immr->im_siu_conf.sc_sivec;
+	irq = vec >> 26;
+	v_bit = 0x80000000UL >> irq;
+
+	/*
+	 * Read Interrupt Mask Register and Mask Interrupts
+	 */
+	simask = immr->im_siu_conf.sc_simask;
+	newmask = simask & (~(0xFFFF0000 >> irq));
+	immr->im_siu_conf.sc_simask = newmask;
+
+	if (!(irq & 0x1)) {		/* External Interrupt ?     */
+		ulong siel;
+
+		/*
+		 * Read Interrupt Edge/Level Register
+		 */
+		siel = immr->im_siu_conf.sc_siel;
+
+		if (siel & v_bit) {	/* edge triggered interrupt ?   */
+			/*
+			 * Rewrite SIPEND Register to clear interrupt
+			 */
+			immr->im_siu_conf.sc_sipend = v_bit;
+		}
+	}
+
+	if (irq_vecs[irq].handler != NULL) {
+		irq_vecs[irq].handler (irq_vecs[irq].arg);
+	} else {
+		printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+				irq, vec);
+		/* turn off the bogus interrupt to avoid it from now */
+		simask &= ~v_bit;
+	}
+	/*
+	 * Re-Enable old Interrupt Mask
+	 */
+	immr->im_siu_conf.sc_simask = simask;
+}
+
+/************************************************************************/
+
+/*
+ * CPM interrupt handler
+ */
+static void cpm_interrupt (void *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	uint vec;
+
+	/*
+	 * Get the vector by setting the ACK bit
+	 * and then reading the register.
+	 */
+	immr->im_cpic.cpic_civr = 1;
+	vec = immr->im_cpic.cpic_civr;
+	vec >>= 11;
+
+	if (cpm_vecs[vec].handler != NULL) {
+		(*cpm_vecs[vec].handler) (cpm_vecs[vec].arg);
+	} else {
+		immr->im_cpic.cpic_cimr &= ~(1 << vec);
+		printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
+	}
+	/*
+	 * After servicing the interrupt,
+	 * we have to remove the status indicator.
+	 */
+	immr->im_cpic.cpic_cisr |= (1 << vec);
+}
+
+/*
+ * The CPM can generate the error interrupt when there is a race
+ * condition between generating and masking interrupts. All we have
+ * to do is ACK it and return. This is a no-op function so we don't
+ * need any special tests in the interrupt handler.
+ */
+static void cpm_error_interrupt (void *dummy)
+{
+}
+
+/************************************************************************/
+/*
+ * Install and free an interrupt handler
+ */
+void irq_install_handler (int vec, interrupt_handler_t * handler,
+						  void *arg)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	if ((vec & CPMVEC_OFFSET) != 0) {
+		/* CPM interrupt */
+		vec &= 0xffff;
+		if (cpm_vecs[vec].handler != NULL) {
+			printf ("CPM interrupt 0x%x replacing 0x%x\n",
+				(uint) handler,
+				(uint) cpm_vecs[vec].handler);
+		}
+		cpm_vecs[vec].handler = handler;
+		cpm_vecs[vec].arg = arg;
+		immr->im_cpic.cpic_cimr |= (1 << vec);
+#if 0
+		printf ("Install CPM interrupt for vector %d ==> %p\n",
+			vec, handler);
+#endif
+	} else {
+		/* SIU interrupt */
+		if (irq_vecs[vec].handler != NULL) {
+			printf ("SIU interrupt %d 0x%x replacing 0x%x\n",
+				vec,
+				(uint) handler,
+				(uint) cpm_vecs[vec].handler);
+		}
+		irq_vecs[vec].handler = handler;
+		irq_vecs[vec].arg = arg;
+		immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
+#if 0
+		printf ("Install SIU interrupt for vector %d ==> %p\n",
+			vec, handler);
+#endif
+	}
+}
+
+void irq_free_handler (int vec)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	if ((vec & CPMVEC_OFFSET) != 0) {
+		/* CPM interrupt */
+		vec &= 0xffff;
+#if 0
+		printf ("Free CPM interrupt for vector %d ==> %p\n",
+			vec, cpm_vecs[vec].handler);
+#endif
+		immr->im_cpic.cpic_cimr &= ~(1 << vec);
+		cpm_vecs[vec].handler = NULL;
+		cpm_vecs[vec].arg = NULL;
+	} else {
+		/* SIU interrupt */
+#if 0
+		printf ("Free CPM interrupt for vector %d ==> %p\n",
+			vec, cpm_vecs[vec].handler);
+#endif
+		immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
+		irq_vecs[vec].handler = NULL;
+		irq_vecs[vec].arg = NULL;
+	}
+}
+
+/************************************************************************/
+
+static void cpm_interrupt_init (void)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+	/*
+	 * Initialize the CPM interrupt controller.
+	 */
+
+	immr->im_cpic.cpic_cicr =
+		(CICR_SCD_SCC4 |
+		 CICR_SCC_SCC3 |
+		 CICR_SCB_SCC2 |
+		 CICR_SCA_SCC1) | ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK;
+
+	immr->im_cpic.cpic_cimr = 0;
+
+	/*
+	 * Install the error handler.
+	 */
+	irq_install_handler (CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+	immr->im_cpic.cpic_cicr |= CICR_IEN;
+
+	/*
+	 * Install the cpm interrupt handler
+	 */
+	irq_install_handler (CPM_INTERRUPT, cpm_interrupt, NULL);
+}
+
+/************************************************************************/
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if 0
+	printf ("*** Timer Interrupt *** ");
+#endif
+	/* Reset Timer Expired and Timers Interrupt Status */
+	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+	__asm__ ("nop");
+	/*
+	  Clear TEXPS (and TMIST on older chips). SPLSS (on older
+	  chips) is cleared too.
+
+	  Bitwise OR is a read-modify-write operation so ALL bits
+	  which are cleared by writing `1' would be cleared by
+	  operations like
+
+	  immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
+
+	  The same can be achieved by simple writing of the PLPRCR
+	  to itself. If a bit value should be preserved, read the
+	  register, ZERO the bit and write, not OR, the result back.
+	*/
+	immr->im_clkrst.car_plprcr = immr->im_clkrst.car_plprcr;
+}
+
+/************************************************************************/
diff --git a/arch/powerpc/cpu/mpc8xx/serial.c b/arch/powerpc/cpu/mpc8xx/serial.c
new file mode 100644
index 0000000000..2519156d4b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/serial.c
@@ -0,0 +1,564 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <command.h>
+#include <serial.h>
+#include <watchdog.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CONS_NONE)	/* No Console at all */
+
+#if defined(CONFIG_8xx_CONS_SMC1)	/* Console on SMC1 */
+#define	SMC_INDEX	0
+#define PROFF_SMC	PROFF_SMC1
+#define CPM_CR_CH_SMC	CPM_CR_CH_SMC1
+
+#elif defined(CONFIG_8xx_CONS_SMC2)	/* Console on SMC2 */
+#define SMC_INDEX	1
+#define PROFF_SMC	PROFF_SMC2
+#define CPM_CR_CH_SMC	CPM_CR_CH_SMC2
+
+#endif /* CONFIG_8xx_CONS_SMCx */
+
+#if defined(CONFIG_8xx_CONS_SCC1)	/* Console on SCC1 */
+#define SCC_INDEX	0
+#define PROFF_SCC	PROFF_SCC1
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC1
+
+#elif defined(CONFIG_8xx_CONS_SCC2)	/* Console on SCC2 */
+#define SCC_INDEX	1
+#define PROFF_SCC	PROFF_SCC2
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC2
+
+#elif defined(CONFIG_8xx_CONS_SCC3)	/* Console on SCC3 */
+#define SCC_INDEX	2
+#define PROFF_SCC	PROFF_SCC3
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC3
+
+#elif defined(CONFIG_8xx_CONS_SCC4)	/* Console on SCC4 */
+#define SCC_INDEX	3
+#define PROFF_SCC	PROFF_SCC4
+#define CPM_CR_CH_SCC	CPM_CR_CH_SCC4
+
+#endif /* CONFIG_8xx_CONS_SCCx */
+
+#if !defined(CONFIG_SYS_SMC_RXBUFLEN)
+#define CONFIG_SYS_SMC_RXBUFLEN	1
+#define CONFIG_SYS_MAXIDLE	0
+#else
+#if !defined(CONFIG_SYS_MAXIDLE)
+#error "you must define CONFIG_SYS_MAXIDLE"
+#endif
+#endif
+
+typedef volatile struct serialbuffer {
+	cbd_t	rxbd;		/* Rx BD */
+	cbd_t	txbd;		/* Tx BD */
+	uint	rxindex;	/* index for next character to read */
+	volatile uchar	rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
+	volatile uchar	txbuf;	/* tx buffers */
+} serialbuffer_t;
+
+static void serial_setdivisor(volatile cpm8xx_t *cp)
+{
+	int divisor=(gd->cpu_clk + 8*gd->baudrate)/16/gd->baudrate;
+
+	if(divisor/16>0x1000) {
+		/* bad divisor, assume 50MHz clock and 9600 baud */
+		divisor=(50*1000*1000 + 8*9600)/16/9600;
+	}
+
+#ifdef CONFIG_SYS_BRGCLK_PRESCALE
+	divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
+#endif
+
+	if(divisor<=0x1000) {
+		cp->cp_brgc1=((divisor-1)<<1) | CPM_BRG_EN;
+	} else {
+		cp->cp_brgc1=((divisor/16-1)<<1) | CPM_BRG_EN | CPM_BRG_DIV16;
+	}
+}
+
+#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2))
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+static void smc_setbrg (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+
+	/* Set up the baud rate generator.
+	 * See 8xx_io/commproc.c for details.
+	 *
+	 * Wire BRG1 to SMCx
+	 */
+
+	cp->cp_simode = 0x00000000;
+
+	serial_setdivisor(cp);
+}
+
+static int smc_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile smc_t *sp;
+	volatile smc_uart_t *up;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+	uint	dpaddr;
+	volatile serialbuffer_t *rtx;
+
+	/* initialize pointers to SMC */
+
+	sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]);
+	up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC];
+	/* Disable relocation */
+	up->smc_rpbase = 0;
+
+	/* Disable transmitter/receiver. */
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+	/* Enable SDMA. */
+	im->im_siu_conf.sc_sdcr = 1;
+
+	/* clear error conditions */
+#ifdef	CONFIG_SYS_SDSR
+	im->im_sdma.sdma_sdsr = CONFIG_SYS_SDSR;
+#else
+	im->im_sdma.sdma_sdsr = 0x83;
+#endif
+
+	/* clear SDMA interrupt mask */
+#ifdef	CONFIG_SYS_SDMR
+	im->im_sdma.sdma_sdmr = CONFIG_SYS_SDMR;
+#else
+	im->im_sdma.sdma_sdmr = 0x00;
+#endif
+
+#if defined(CONFIG_8xx_CONS_SMC1)
+	/* Use Port B for SMC1 instead of other functions. */
+	cp->cp_pbpar |=  0x000000c0;
+	cp->cp_pbdir &= ~0x000000c0;
+	cp->cp_pbodr &= ~0x000000c0;
+#else	/* CONFIG_8xx_CONS_SMC2 */
+	/* Use Port B for SMC2 instead of other functions.
+	 */
+	cp->cp_pbpar |=  0x00000c00;
+	cp->cp_pbdir &= ~0x00000c00;
+	cp->cp_pbodr &= ~0x00000c00;
+#endif
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	dpaddr = CPM_SERIAL_BASE;
+
+	rtx = (serialbuffer_t *)&cp->cp_dpmem[dpaddr];
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * For now, this address seems OK, but it may have to
+	 * change with newer versions of the firmware.
+	 * damm: allocating space after the two buffers for rx/tx data
+	 */
+
+	rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
+	rtx->rxbd.cbd_sc      = 0;
+
+	rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
+	rtx->txbd.cbd_sc      = 0;
+
+	/* Set up the uart parameters in the parameter ram. */
+	up->smc_rbase = dpaddr;
+	up->smc_tbase = dpaddr+sizeof(cbd_t);
+	up->smc_rfcr = SMC_EB;
+	up->smc_tfcr = SMC_EB;
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->smc_smcm = 0;
+	sp->smc_smce = 0xff;
+
+	/* Set up the baud rate generator */
+	smc_setbrg ();
+
+	/* Make the first buffer the only buffer. */
+	rtx->txbd.cbd_sc |= BD_SC_WRAP;
+	rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* single/multi character receive. */
+	up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN;
+	up->smc_maxidl = CONFIG_SYS_MAXIDLE;
+	rtx->rxindex = 0;
+
+	/* Initialize Tx/Rx parameters.	*/
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+	  ;
+
+	/* Enable transmitter/receiver.	*/
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+	return (0);
+}
+
+static void
+smc_putc(const char c)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	volatile serialbuffer_t	*rtx;
+
+	if (c == '\n')
+		smc_putc ('\r');
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+	rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	/* Wait for last character to go. */
+	rtx->txbuf = c;
+	rtx->txbd.cbd_datlen = 1;
+	rtx->txbd.cbd_sc |= BD_SC_READY;
+	__asm__("eieio");
+
+	while (rtx->txbd.cbd_sc & BD_SC_READY) {
+		WATCHDOG_RESET ();
+		__asm__("eieio");
+	}
+}
+
+static void
+smc_puts (const char *s)
+{
+	while (*s) {
+		smc_putc (*s++);
+	}
+}
+
+static int
+smc_getc(void)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	volatile serialbuffer_t	*rtx;
+	unsigned char  c;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+	rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	/* Wait for character to show up. */
+	while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
+		WATCHDOG_RESET ();
+
+	/* the characters are read one by one,
+	 * use the rxindex to know the next char to deliver
+	 */
+	c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr+rtx->rxindex);
+	rtx->rxindex++;
+
+	/* check if all char are readout, then make prepare for next receive */
+	if (rtx->rxindex >= rtx->rxbd.cbd_datlen) {
+		rtx->rxindex = 0;
+		rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+	}
+	return(c);
+}
+
+static int
+smc_tstc(void)
+{
+	volatile smc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	volatile serialbuffer_t	*rtx;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+	rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
+}
+
+struct serial_device serial_smc_device =
+{
+	.name	= "serial_smc",
+	.start	= smc_init,
+	.stop	= NULL,
+	.setbrg	= smc_setbrg,
+	.getc	= smc_getc,
+	.tstc	= smc_tstc,
+	.putc	= smc_putc,
+	.puts	= smc_puts,
+};
+
+#endif /* CONFIG_8xx_CONS_SMC1 || CONFIG_8xx_CONS_SMC2 */
+
+#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
+    defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+
+static void
+scc_setbrg (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+
+	/* Set up the baud rate generator.
+	 * See 8xx_io/commproc.c for details.
+	 *
+	 * Wire BRG1 to SCCx
+	 */
+
+	cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX));
+
+	serial_setdivisor(cp);
+}
+
+static int scc_init (void)
+{
+	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile scc_t *sp;
+	volatile scc_uart_t *up;
+	volatile cbd_t *tbdf, *rbdf;
+	volatile cpm8xx_t *cp = &(im->im_cpm);
+	uint	 dpaddr;
+	volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+
+	/* initialize pointers to SCC */
+
+	sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]);
+	up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC];
+
+	/* Disable transmitter/receiver. */
+	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/*
+	 * Standard configuration for SCC's is on Part A
+	 */
+	ip->iop_papar |=  ((3 << (2 * SCC_INDEX)));
+	ip->iop_padir &= ~((3 << (2 * SCC_INDEX)));
+	ip->iop_paodr &= ~((3 << (2 * SCC_INDEX)));
+
+	/* Allocate space for two buffer descriptors in the DP ram. */
+	dpaddr = dpram_alloc_align(sizeof(cbd_t)*2 + 2, 8);
+
+	/* Enable SDMA.	*/
+	im->im_siu_conf.sc_sdcr = 0x0001;
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+
+	rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+	rbdf->cbd_bufaddr = (uint) (rbdf+2);
+	rbdf->cbd_sc = 0;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+	tbdf->cbd_sc = 0;
+
+	/* Set up the baud rate generator. */
+	scc_setbrg ();
+
+	/* Set up the uart parameters in the parameter ram. */
+	up->scc_genscc.scc_rbase = dpaddr;
+	up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+
+	/* Initialize Tx/Rx parameters. */
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+		;
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+		;
+
+	up->scc_genscc.scc_rfcr  = SCC_EB | 0x05;
+	up->scc_genscc.scc_tfcr  = SCC_EB | 0x05;
+
+	up->scc_genscc.scc_mrblr = 1;	/* Single character receive */
+	up->scc_maxidl = 0;		/* disable max idle */
+	up->scc_brkcr  = 1;		/* send one break character on stop TX */
+	up->scc_parec  = 0;
+	up->scc_frmec  = 0;
+	up->scc_nosec  = 0;
+	up->scc_brkec  = 0;
+	up->scc_uaddr1 = 0;
+	up->scc_uaddr2 = 0;
+	up->scc_toseq  = 0;
+	up->scc_char1  = 0x8000;
+	up->scc_char2  = 0x8000;
+	up->scc_char3  = 0x8000;
+	up->scc_char4  = 0x8000;
+	up->scc_char5  = 0x8000;
+	up->scc_char6  = 0x8000;
+	up->scc_char7  = 0x8000;
+	up->scc_char8  = 0x8000;
+	up->scc_rccm   = 0xc0ff;
+
+	/* Set low latency / small fifo. */
+	sp->scc_gsmrh = SCC_GSMRH_RFW;
+
+	/* Set SCC(x) clock mode to 16x
+	 * See 8xx_io/commproc.c for details.
+	 *
+	 * Wire BRG1 to SCCn
+	 */
+
+	/* Set UART mode, clock divider 16 on Tx and Rx */
+	sp->scc_gsmrl &= ~0xF;
+	sp->scc_gsmrl |=
+		(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+	sp->scc_psmr  = 0;
+	sp->scc_psmr  |= SCU_PSMR_CL;
+
+	/* Mask all interrupts and remove anything pending. */
+	sp->scc_sccm = 0;
+	sp->scc_scce = 0xffff;
+	sp->scc_dsr  = 0x7e7e;
+	sp->scc_psmr = 0x3000;
+
+	/* Make the first buffer the only buffer. */
+	tbdf->cbd_sc |= BD_SC_WRAP;
+	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* Enable transmitter/receiver.	*/
+	sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	return (0);
+}
+
+static void
+scc_putc(const char c)
+{
+	volatile cbd_t		*tbdf;
+	volatile char		*buf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+
+	if (c == '\n')
+		scc_putc ('\r');
+
+	up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+	tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase];
+
+	/* Wait for last character to go. */
+
+	buf = (char *)tbdf->cbd_bufaddr;
+
+	*buf = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+	__asm__("eieio");
+
+	while (tbdf->cbd_sc & BD_SC_READY) {
+		__asm__("eieio");
+		WATCHDOG_RESET ();
+	}
+}
+
+static void
+scc_puts (const char *s)
+{
+	while (*s) {
+		scc_putc (*s++);
+	}
+}
+
+static int
+scc_getc(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile unsigned char	*buf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+	unsigned char		c;
+
+	up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+	rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+	/* Wait for character to show up. */
+	buf = (unsigned char *)rbdf->cbd_bufaddr;
+
+	while (rbdf->cbd_sc & BD_SC_EMPTY)
+		WATCHDOG_RESET ();
+
+	c = *buf;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return(c);
+}
+
+static int
+scc_tstc(void)
+{
+	volatile cbd_t		*rbdf;
+	volatile scc_uart_t	*up;
+	volatile immap_t	*im = (immap_t *)CONFIG_SYS_IMMR;
+	volatile cpm8xx_t	*cpmp = &(im->im_cpm);
+
+	up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+	rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+struct serial_device serial_scc_device =
+{
+	.name	= "serial_scc",
+	.start	= scc_init,
+	.stop	= NULL,
+	.setbrg	= scc_setbrg,
+	.getc	= scc_getc,
+	.tstc	= scc_tstc,
+	.putc	= scc_putc,
+	.puts	= scc_puts,
+};
+
+#endif	/* CONFIG_8xx_CONS_SCCx */
+
+__weak struct serial_device *default_serial_console(void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
+	return &serial_smc_device;
+#else
+	return &serial_scc_device;
+#endif
+}
+
+void mpc8xx_serial_initialize(void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
+	serial_register(&serial_smc_device);
+#endif
+#if	defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
+	defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+	serial_register(&serial_scc_device);
+#endif
+}
+
+#endif	/* CONFIG_8xx_CONS_NONE */
diff --git a/arch/powerpc/cpu/mpc8xx/speed.c b/arch/powerpc/cpu/mpc8xx/speed.c
new file mode 100644
index 0000000000..751c089a6d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/speed.c
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void get_brgclk(uint sccr)
+{
+	uint divider = 0;
+
+	switch((sccr&SCCR_DFBRG11)>>11){
+		case 0:
+			divider = 1;
+			break;
+		case 1:
+			divider = 4;
+			break;
+		case 2:
+			divider = 16;
+			break;
+		case 3:
+			divider = 64;
+			break;
+	}
+	gd->arch.brg_clk = gd->cpu_clk/divider;
+}
+
+/*
+ * get_clocks() fills in gd->cpu_clock depending on CONFIG_8xx_GCLK_FREQ
+ */
+int get_clocks (void)
+{
+	uint immr = get_immr (0);	/* Return full IMMR contents */
+	volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+	uint sccr = immap->im_clkrst.car_sccr;
+	/*
+	 * If for some reason measuring the gclk frequency won't
+	 * work, we return the hardwired value.
+	 * (For example, the cogent CMA286-60 CPU module has no
+	 * separate oscillator for PITRTCLK)
+	 */
+	gd->cpu_clk = CONFIG_8xx_GCLK_FREQ;
+
+	if ((sccr & SCCR_EBDF11) == 0) {
+		/* No Bus Divider active */
+		gd->bus_clk = gd->cpu_clk;
+	} else {
+		/* The MPC8xx has only one BDF: half clock speed */
+		gd->bus_clk = gd->cpu_clk / 2;
+	}
+
+	get_brgclk(sccr);
+
+	return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/spi.c b/arch/powerpc/cpu/mpc8xx/spi.c
new file mode 100644
index 0000000000..f39ce22632
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/spi.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2001 Navin Boppuri / Prashant Patel
+ *	<nboppuri at trinetcommunication.com>,
+ *	<pmpatel at trinetcommunication.com>
+ * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen at icn.siemens.de>
+ * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd at denx.de>.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * MPC8xx CPM SPI interface.
+ *
+ * Parts of this code are probably not portable and/or specific to
+ * the board which I used for the tests. Please send fixes/complaints
+ * to wd at denx.de
+ *
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <serial.h>
+
+#ifdef CONFIG_SPI
+
+/* Warning:
+ * You cannot enable DEBUG for early system initalization, i. e. when
+ * this driver is used to read environment parameters like "baudrate"
+ * from EEPROM which are used to initialize the serial port which is
+ * needed to print the debug messages...
+ */
+#undef	DEBUG
+
+#define SPI_EEPROM_WREN		0x06
+#define SPI_EEPROM_RDSR		0x05
+#define SPI_EEPROM_READ		0x03
+#define SPI_EEPROM_WRITE	0x02
+
+/* ---------------------------------------------------------------
+ * Offset for initial SPI buffers in DPRAM:
+ * We need a 520 byte scratch DPRAM area to use at an early stage.
+ * It is used between the two initialization calls (spi_init_f()
+ * and spi_init_r()).
+ * The value 0xb00 makes it far enough from the start of the data
+ * area (as well as from the stack pointer).
+ * --------------------------------------------------------------- */
+#ifndef	CONFIG_SYS_SPI_INIT_OFFSET
+#define	CONFIG_SYS_SPI_INIT_OFFSET	0xB00
+#endif
+
+#ifdef	DEBUG
+
+#define	DPRINT(a)	printf a;
+/* -----------------------------------------------
+ * Helper functions to peek into tx and rx buffers
+ * ----------------------------------------------- */
+static const char * const hex_digit = "0123456789ABCDEF";
+
+static char quickhex (int i)
+{
+	return hex_digit[i];
+}
+
+static void memdump (void *pv, int num)
+{
+	int i;
+	unsigned char *pc = (unsigned char *) pv;
+
+	for (i = 0; i < num; i++)
+		printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
+	printf ("\t");
+	for (i = 0; i < num; i++)
+		printf ("%c", isprint (pc[i]) ? pc[i] : '.');
+	printf ("\n");
+}
+#else	/* !DEBUG */
+
+#define	DPRINT(a)
+
+#endif	/* DEBUG */
+
+/* -------------------
+ * Function prototypes
+ * ------------------- */
+void spi_init (void);
+
+ssize_t spi_read (uchar *, int, uchar *, int);
+ssize_t spi_write (uchar *, int, uchar *, int);
+ssize_t spi_xfer (size_t);
+
+/* -------------------
+ * Variables
+ * ------------------- */
+
+#define MAX_BUFFER	0x104
+
+/* ----------------------------------------------------------------------
+ * Initially we place the RX and TX buffers at a fixed location in DPRAM!
+ * ---------------------------------------------------------------------- */
+static uchar *rxbuf =
+  (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+			[CONFIG_SYS_SPI_INIT_OFFSET];
+static uchar *txbuf =
+  (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+			[CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
+
+/* **************************************************************************
+ *
+ *  Function:    spi_init_f
+ *
+ *  Description: Init SPI-Controller (ROM part)
+ *
+ *  return:      ---
+ *
+ * *********************************************************************** */
+void spi_init_f (void)
+{
+	unsigned int dpaddr;
+
+	volatile spi_t *spi;
+	volatile immap_t *immr;
+	volatile cpm8xx_t *cp;
+	volatile cbd_t *tbdf, *rbdf;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+	spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+	/* Disable relocation */
+	spi->spi_rpbase = 0;
+
+/* 1 */
+	/* ------------------------------------------------
+	 * Initialize Port B SPI pins -> page 34-8 MPC860UM
+	 * (we are only in Master Mode !)
+	 * ------------------------------------------------ */
+
+	/* --------------------------------------------
+	 * GPIO or per. Function
+	 * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
+	 * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
+	 * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
+	 * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
+	 * -------------------------------------------- */
+	cp->cp_pbpar |=  0x0000000E;	/* set  bits	*/
+	cp->cp_pbpar &= ~0x00000001;	/* reset bit	*/
+
+	/* ----------------------------------------------
+	 * In/Out or per. Function 0/1
+	 * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
+	 * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
+	 * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
+	 * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
+	 * ---------------------------------------------- */
+	cp->cp_pbdir |= 0x0000000F;
+
+	/* ----------------------------------------------
+	 * open drain or active output
+	 * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
+	 * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
+	 * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
+	 * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
+	 * ---------------------------------------------- */
+
+	cp->cp_pbodr |=  0x00000008;
+	cp->cp_pbodr &= ~0x00000007;
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero
+	 */
+	spi->spi_rstate	= 0;
+	spi->spi_rdp	= 0;
+	spi->spi_rbptr	= 0;
+	spi->spi_rbc	= 0;
+	spi->spi_rxtmp	= 0;
+	spi->spi_tstate	= 0;
+	spi->spi_tdp	= 0;
+	spi->spi_tbptr	= 0;
+	spi->spi_tbc	= 0;
+	spi->spi_txtmp	= 0;
+
+	dpaddr = CPM_SPI_BASE;
+
+/* 3 */
+	/* Set up the SPI parameters in the parameter ram */
+	spi->spi_rbase = dpaddr;
+	spi->spi_tbase = dpaddr + sizeof (cbd_t);
+
+	/***********IMPORTANT******************/
+
+	/*
+	 * Setting transmit and receive buffer descriptor pointers
+	 * initially to rbase and tbase. Only the microcode patches
+	 * documentation talks about initializing this pointer. This
+	 * is missing from the sample I2C driver. If you dont
+	 * initialize these pointers, the kernel hangs.
+	 */
+	spi->spi_rbptr = spi->spi_rbase;
+	spi->spi_tbptr = spi->spi_tbase;
+
+/* 4 */
+	/* Init SPI Tx + Rx Parameters */
+	while (cp->cp_cpcr & CPM_CR_FLG)
+		;
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG)
+		;
+
+/* 5 */
+	/* Set SDMA configuration register */
+	immr->im_siu_conf.sc_sdcr = 0x0001;
+
+/* 6 */
+	/* Set to big endian. */
+	spi->spi_tfcr = SMC_EB;
+	spi->spi_rfcr = SMC_EB;
+
+/* 7 */
+	/* Set maximum receive size. */
+	spi->spi_mrblr = MAX_BUFFER;
+
+/* 8 + 9 */
+	/* tx and rx buffer descriptors */
+	tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+	rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+	tbdf->cbd_sc &= ~BD_SC_READY;
+	rbdf->cbd_sc &= ~BD_SC_EMPTY;
+
+	/* Set the bd's rx and tx buffer address pointers */
+	rbdf->cbd_bufaddr = (ulong) rxbuf;
+	tbdf->cbd_bufaddr = (ulong) txbuf;
+
+/* 10 + 11 */
+	cp->cp_spim = 0;			/* Mask  all SPI events */
+	cp->cp_spie = SPI_EMASK;		/* Clear all SPI events	*/
+
+	return;
+}
+
+/* **************************************************************************
+ *
+ *  Function:    spi_init_r
+ *
+ *  Description: Init SPI-Controller (RAM part) -
+ *		 The malloc engine is ready and we can move our buffers to
+ *		 normal RAM
+ *
+ *  return:      ---
+ *
+ * *********************************************************************** */
+void spi_init_r (void)
+{
+	volatile cpm8xx_t *cp;
+	volatile spi_t *spi;
+	volatile immap_t *immr;
+	volatile cbd_t *tbdf, *rbdf;
+
+	immr = (immap_t *)  CONFIG_SYS_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+	spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+	/* Disable relocation */
+	spi->spi_rpbase = 0;
+
+	/* tx and rx buffer descriptors */
+	tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+	rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+	/* Allocate memory for RX and TX buffers */
+	rxbuf = (uchar *) malloc (MAX_BUFFER);
+	txbuf = (uchar *) malloc (MAX_BUFFER);
+
+	rbdf->cbd_bufaddr = (ulong) rxbuf;
+	tbdf->cbd_bufaddr = (ulong) txbuf;
+
+	return;
+}
+
+/****************************************************************************
+ *  Function:    spi_write
+ **************************************************************************** */
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+	int i;
+
+	memset(rxbuf, 0, MAX_BUFFER);
+	memset(txbuf, 0, MAX_BUFFER);
+	*txbuf = SPI_EEPROM_WREN;		/* write enable		*/
+	spi_xfer(1);
+	memcpy(txbuf, addr, alen);
+	*txbuf = SPI_EEPROM_WRITE;		/* WRITE memory array	*/
+	memcpy(alen + txbuf, buffer, len);
+	spi_xfer(alen + len);
+						/* ignore received data	*/
+	for (i = 0; i < 1000; i++) {
+		*txbuf = SPI_EEPROM_RDSR;	/* read status		*/
+		txbuf[1] = 0;
+		spi_xfer(2);
+		if (!(rxbuf[1] & 1)) {
+			break;
+		}
+		udelay(1000);
+	}
+	if (i >= 1000) {
+		printf ("*** spi_write: Time out while writing!\n");
+	}
+
+	return len;
+}
+
+/****************************************************************************
+ *  Function:    spi_read
+ **************************************************************************** */
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+	memset(rxbuf, 0, MAX_BUFFER);
+	memset(txbuf, 0, MAX_BUFFER);
+	memcpy(txbuf, addr, alen);
+	*txbuf = SPI_EEPROM_READ;		/* READ memory array	*/
+
+	/*
+	 * There is a bug in 860T (?) that cuts the last byte of input
+	 * if we're reading into DPRAM. The solution we choose here is
+	 * to always read len+1 bytes (we have one extra byte at the
+	 * end of the buffer).
+	 */
+	spi_xfer(alen + len + 1);
+	memcpy(buffer, alen + rxbuf, len);
+
+	return len;
+}
+
+/****************************************************************************
+ *  Function:    spi_xfer
+ **************************************************************************** */
+ssize_t spi_xfer (size_t count)
+{
+	volatile immap_t *immr;
+	volatile cpm8xx_t *cp;
+	volatile spi_t *spi;
+	cbd_t *tbdf, *rbdf;
+	ushort loop;
+	int tm;
+
+	DPRINT (("*** spi_xfer entered ***\n"));
+
+	immr = (immap_t *) CONFIG_SYS_IMMR;
+	cp   = (cpm8xx_t *) &immr->im_cpm;
+
+	spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+	/* Disable relocation */
+	spi->spi_rpbase = 0;
+
+	tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+	rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+	/* Set CS for device */
+	cp->cp_pbdat &= ~0x0001;
+
+	/* Setting tx bd status and data length */
+	tbdf->cbd_sc  = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
+	tbdf->cbd_datlen = count;
+
+	DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
+							tbdf->cbd_datlen));
+
+	/* Setting rx bd status and data length */
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	rbdf->cbd_datlen = 0;	 /* rx length has no significance */
+
+	loop = cp->cp_spmode & SPMODE_LOOP;
+	cp->cp_spmode = /*SPMODE_DIV16	|*/	/* BRG/16 mode not used here */
+			loop		|
+			SPMODE_REV	|
+			SPMODE_MSTR	|
+			SPMODE_EN	|
+			SPMODE_LEN(8)	|	/* 8 Bits per char */
+			SPMODE_PM(0x8) ;	/* medium speed */
+	cp->cp_spim = 0;			/* Mask  all SPI events */
+	cp->cp_spie = SPI_EMASK;		/* Clear all SPI events	*/
+
+	/* start spi transfer */
+	DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+	cp->cp_spcom |= SPI_STR;		/* Start transmit */
+
+	/* --------------------------------
+	 * Wait for SPI transmit to get out
+	 * or time out (1 second = 1000 ms)
+	 * -------------------------------- */
+	for (tm=0; tm<1000; ++tm) {
+		if (cp->cp_spie & SPI_TXB) {	/* Tx Buffer Empty */
+			DPRINT (("*** spi_xfer: Tx buffer empty\n"));
+			break;
+		}
+		if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
+			DPRINT (("*** spi_xfer: Tx BD done\n"));
+			break;
+		}
+		udelay (1000);
+	}
+	if (tm >= 1000) {
+		printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
+	}
+	DPRINT (("*** spi_xfer: ... transfer ended\n"));
+
+#ifdef	DEBUG
+	printf ("\nspi_xfer: txbuf after xfer\n");
+	memdump ((void *) txbuf, 16);	/* dump of txbuf before transmit */
+	printf ("spi_xfer: rxbuf after xfer\n");
+	memdump ((void *) rxbuf, 16);	/* dump of rxbuf after transmit */
+	printf ("\n");
+#endif
+
+	/* Clear CS for device */
+	cp->cp_pbdat |= 0x0001;
+
+	return count;
+}
+#endif	/* CONFIG_SPI */
diff --git a/arch/powerpc/cpu/mpc8xx/start.S b/arch/powerpc/cpu/mpc8xx/start.S
new file mode 100644
index 0000000000..ae8c8c2eb1
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/start.S
@@ -0,0 +1,645 @@
+/*
+ *  Copyright (C) 1998	Dan Malek <dmalek at jlc.net>
+ *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000,2001,2002 Wolfgang Denk <wd at denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*  U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ *  The processor starts at 0x00000100 and the code is executed
+ *  from flash. The code is organized to be at an other address
+ *  in memory, but as long we don't jump around before relocating,
+ *  board_init lies at a quite high address and when the cpu has
+ *  jumped there, everything is ok.
+ *  This works because the cpu gives the FLASH (CS0) the whole
+ *  address space at startup, and board_init lies as a echo of
+ *  the flash somewhere up there in the memory map.
+ *
+ *  board_init will change CS0 to be positioned at the correct
+ *  address and (s)dram will be positioned at address 0
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc8xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/* We don't want the  MMU yet.
+*/
+#undef	MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI )	/* Machine Check and Recoverable Interr. */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+	START_GOT
+	GOT_ENTRY(_GOT2_TABLE_)
+	GOT_ENTRY(_FIXUP_TABLE_)
+
+	GOT_ENTRY(_start)
+	GOT_ENTRY(_start_of_vectors)
+	GOT_ENTRY(_end_of_vectors)
+	GOT_ENTRY(transfer_to_handler)
+
+	GOT_ENTRY(__init_end)
+	GOT_ENTRY(__bss_end)
+	GOT_ENTRY(__bss_start)
+	END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+	.text
+	.long	0x27051956		/* U-Boot Magic Number			*/
+	.globl	version_string
+version_string:
+	.ascii U_BOOT_VERSION_STRING, "\0"
+
+	. = EXC_OFF_SYS_RESET
+	.globl	_start
+_start:
+	lis	r3, CONFIG_SYS_IMMR at h		/* position IMMR */
+	mtspr	638, r3
+
+	/* Initialize machine status; enable machine check interrupt		*/
+	/*----------------------------------------------------------------------*/
+	li	r3, MSR_KERNEL		/* Set ME, RI flags */
+	mtmsr	r3
+	mtspr	SRR1, r3		/* Make SRR1 match MSR */
+
+	mfspr	r3, ICR			/* clear Interrupt Cause Register */
+
+	/* Initialize debug port registers					*/
+	/*----------------------------------------------------------------------*/
+	xor	r0, r0, r0		/* Clear R0 */
+	mtspr	LCTRL1, r0		/* Initialize debug port regs */
+	mtspr	LCTRL2, r0
+	mtspr	COUNTA, r0
+	mtspr	COUNTB, r0
+
+	/* Reset the caches							*/
+	/*----------------------------------------------------------------------*/
+
+	mfspr	r3, IC_CST		/* Clear error bits */
+	mfspr	r3, DC_CST
+
+	lis	r3, IDC_UNALL at h		/* Unlock all */
+	mtspr	IC_CST, r3
+	mtspr	DC_CST, r3
+
+	lis	r3, IDC_INVALL at h	/* Invalidate all */
+	mtspr	IC_CST, r3
+	mtspr	DC_CST, r3
+
+	lis	r3, IDC_DISABLE at h	/* Disable data cache */
+	mtspr	DC_CST, r3
+
+	lis	r3, IDC_ENABLE at h	/* Enable instruction cache */
+	mtspr	IC_CST, r3
+
+	/* invalidate all tlb's							*/
+	/*----------------------------------------------------------------------*/
+
+	tlbia
+	isync
+
+	/*
+	 * Calculate absolute address in FLASH and jump there
+	 *----------------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_MONITOR_BASE at h
+	ori	r3, r3, CONFIG_SYS_MONITOR_BASE at l
+	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+	mtlr	r3
+	blr
+
+in_flash:
+
+	/* initialize some SPRs that are hard to access from C			*/
+	/*----------------------------------------------------------------------*/
+
+	lis	r3, CONFIG_SYS_IMMR at h		/* pass IMMR as arg1 to C routine */
+	ori	r1, r3, CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in internal DPRAM */
+	/* Note: R0 is still 0 here */
+	stwu	r0, -4(r1)		/* clear final stack frame so that	*/
+	stwu	r0, -4(r1)		/* stack backtraces terminate cleanly	*/
+
+	/*
+	 * Disable serialized ifetch and show cycles
+	 * (i.e. set processor to normal mode).
+	 * This is also a silicon bug workaround, see errata
+	 */
+
+	li	r2, 0x0007
+	mtspr	ICTRL, r2
+
+	/* Set up debug mode entry */
+
+	lis	r2, CONFIG_SYS_DER at h
+	ori	r2, r2, CONFIG_SYS_DER at l
+	mtspr	DER, r2
+
+	/* let the C-code set up the rest					*/
+	/*									*/
+	/* Be careful to keep code relocatable !				*/
+	/*----------------------------------------------------------------------*/
+
+	GET_GOT			/* initialize GOT access			*/
+
+	/* r3: IMMR */
+	bl	cpu_init_f	/* run low-level CPU init code     (from Flash)	*/
+
+	bl	board_init_f	/* run 1st part of board init code (from Flash) */
+
+	/* NOTREACHED - board_init_f() does not return */
+
+
+	.globl	_start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception.  "Never" generated on the 860. */
+	STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG(SRR0, SRR1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+		MSR_KERNEL, COPY_EE)
+
+	/* No FPU on MPC8xx.  This exception is not supposed to happen.
+	*/
+	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+	/* I guess we could implement decrementer, and may have
+	 * to someday for timekeeping.
+	 */
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+	STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+	STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+	/* On the MPC8xx, this is a software emulation interrupt.  It occurs
+	 * for all unimplemented and illegal instructions.
+	 */
+	STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+	STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+	STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+	STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+	STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+	STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+	STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+	STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+	STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+	STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+	STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
+	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+	.globl	_end_of_vectors
+_end_of_vectors:
+
+
+	. = 0x2000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	lis	r22,MSR_POW at h
+	andc	r23,r23,r22
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRG2,r22		/* r1 is now kernel sp */
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
+
+int_return:
+	mfmsr	r28			/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r28,r28,r4
+	SYNC				/* Some chip revs need this... */
+	mtmsr	r28
+	SYNC
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)		/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
+
+/* Cache functions.
+*/
+	.globl	icache_enable
+icache_enable:
+	SYNC
+	lis	r3, IDC_INVALL at h
+	mtspr	IC_CST, r3
+	lis	r3, IDC_ENABLE at h
+	mtspr	IC_CST, r3
+	blr
+
+	.globl	icache_disable
+icache_disable:
+	SYNC
+	lis	r3, IDC_DISABLE at h
+	mtspr	IC_CST, r3
+	blr
+
+	.globl	icache_status
+icache_status:
+	mfspr	r3, IC_CST
+	srwi	r3, r3, 31	/* >>31 => select bit 0 */
+	blr
+
+	.globl	dcache_enable
+dcache_enable:
+#if 0
+	SYNC
+#endif
+#if 1
+	lis	r3, 0x0400		/* Set cache mode with MMU off */
+	mtspr	MD_CTR, r3
+#endif
+
+	lis	r3, IDC_INVALL at h
+	mtspr	DC_CST, r3
+#if 0
+	lis	r3, DC_SFWT at h
+	mtspr	DC_CST, r3
+#endif
+	lis	r3, IDC_ENABLE at h
+	mtspr	DC_CST, r3
+	blr
+
+	.globl	dcache_disable
+dcache_disable:
+	SYNC
+	lis	r3, IDC_DISABLE at h
+	mtspr	DC_CST, r3
+	lis	r3, IDC_INVALL at h
+	mtspr	DC_CST, r3
+	blr
+
+	.globl	dcache_status
+dcache_status:
+	mfspr	r3, DC_CST
+	srwi	r3, r3, 31	/* >>31 => select bit 0 */
+	blr
+
+	.globl	dc_read
+dc_read:
+	mtspr	DC_ADR, r3
+	mfspr	r3, DC_DAT
+	blr
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+	.globl	get_immr
+get_immr:
+	mr	r4,r3		/* save mask */
+	mfspr	r3, IMMR	/* IMMR */
+	cmpwi	0,r4,0		/* mask != 0 ? */
+	beq	4f
+	and	r3,r3,r4	/* IMMR & mask */
+4:
+	blr
+
+	.globl get_pvr
+get_pvr:
+	mfspr	r3, PVR
+	blr
+
+
+	.globl wr_ic_cst
+wr_ic_cst:
+	mtspr	IC_CST, r3
+	blr
+
+	.globl rd_ic_cst
+rd_ic_cst:
+	mfspr	r3, IC_CST
+	blr
+
+	.globl wr_ic_adr
+wr_ic_adr:
+	mtspr	IC_ADR, r3
+	blr
+
+
+	.globl wr_dc_cst
+wr_dc_cst:
+	mtspr	DC_CST, r3
+	blr
+
+	.globl rd_dc_cst
+rd_dc_cst:
+	mfspr	r3, DC_CST
+	blr
+
+	.globl wr_dc_adr
+wr_dc_adr:
+	mtspr	DC_ADR, r3
+	blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+	.globl	relocate_code
+relocate_code:
+	mr	r1,  r3		/* Set new stack pointer		*/
+	mr	r9,  r4		/* Save copy of Global Data pointer	*/
+	mr	r10, r5		/* Save copy of Destination Address	*/
+
+	GET_GOT
+	mr	r3,  r5				/* Destination Address	*/
+	lis	r4, CONFIG_SYS_MONITOR_BASE at h		/* Source      Address	*/
+	ori	r4, r4, CONFIG_SYS_MONITOR_BASE at l
+	lwz	r5, GOT(__init_end)
+	sub	r5, r5, r4
+	li	r6, CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/
+
+	/*
+	 * Fix GOT pointer:
+	 *
+	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+	 *
+	 * Offset:
+	 */
+	sub	r15, r10, r4
+
+	/* First our own GOT */
+	add	r12, r12, r15
+	/* then the one used by the C code */
+	add	r30, r30, r15
+
+	/*
+	 * Now relocate code
+	 */
+
+	cmplw	cr1,r3,r4
+	addi	r0,r5,3
+	srwi.	r0,r0,2
+	beq	cr1,4f		/* In place copy is not necessary	*/
+	beq	7f		/* Protect against 0 count		*/
+	mtctr	r0
+	bge	cr1,2f
+
+	la	r8,-4(r4)
+	la	r7,-4(r3)
+1:	lwzu	r0,4(r8)
+	stwu	r0,4(r7)
+	bdnz	1b
+	b	4f
+
+2:	slwi	r0,r0,2
+	add	r8,r4,r0
+	add	r7,r3,r0
+3:	lwzu	r0,-4(r8)
+	stwu	r0,-4(r7)
+	bdnz	3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4:	cmpwi	r6,0
+	add	r5,r3,r5
+	beq	7f		/* Always flush prefetch queue in any case */
+	subi	r0,r6,1
+	andc	r3,r3,r0
+	mr	r4,r3
+5:	dcbst	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	5b
+	sync			/* Wait for all dcbst to complete on bus */
+	mr	r4,r3
+6:	icbi	0,r4
+	add	r4,r4,r6
+	cmplw	r4,r5
+	blt	6b
+7:	sync			/* Wait for all icbi to complete on bus	*/
+	isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+	mtlr	r0
+	blr
+
+in_ram:
+
+	/*
+	 * Relocation Function, r12 point to got2+0x8000
+	 *
+	 * Adjust got2 pointers, no need to check for 0, this code
+	 * already puts a few entries in the table.
+	 */
+	li	r0,__got2_entries at sectoff@l
+	la	r3,GOT(_GOT2_TABLE_)
+	lwz	r11,GOT(_GOT2_TABLE_)
+	mtctr	r0
+	sub	r11,r3,r11
+	addi	r3,r3,-4
+1:	lwzu	r0,4(r3)
+	cmpwi	r0,0
+	beq-	2f
+	add	r0,r0,r11
+	stw	r0,0(r3)
+2:	bdnz	1b
+
+	/*
+	 * Now adjust the fixups and the pointers to the fixups
+	 * in case we need to move ourselves again.
+	 */
+	li	r0,__fixup_entries at 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
+	cmpwi	r0,0
+	add	r0,r0,r11
+	stw	r4,0(r3)
+	beq-	5f
+	stw	r0,0(r4)
+5:	bdnz	3b
+4:
+clear_bss:
+	/*
+	 * Now clear BSS segment
+	 */
+	lwz	r3,GOT(__bss_start)
+	lwz	r4,GOT(__bss_end)
+
+	cmplw	0, r3, r4
+	beq	6f
+
+	li	r0, 0
+5:
+	stw	r0, 0(r3)
+	addi	r3, r3, 4
+	cmplw	0, r3, r4
+	bne	5b
+6:
+
+	mr	r3, r9		/* Global Data pointer		*/
+	mr	r4, r10		/* Destination Address		*/
+	bl	board_init_r
+
+	/*
+	 * Copy exception vector code to low memory
+	 *
+	 * r3: dest_addr
+	 * r7: source address, r8: end address, r9: target address
+	 */
+	.globl	trap_init
+trap_init:
+	mflr	r4			/* save link register		*/
+	GET_GOT
+	lwz	r7, GOT(_start)
+	lwz	r8, GOT(_end_of_vectors)
+
+	li	r9, 0x100		/* reset vector always at 0x100 */
+
+	cmplw	0, r7, r8
+	bgelr				/* return if r7>=r8 - just in case */
+1:
+	lwz	r0, 0(r7)
+	stw	r0, 0(r9)
+	addi	r7, r7, 4
+	addi	r9, r9, 4
+	cmplw	0, r7, r8
+	bne	1b
+
+	/*
+	 * relocate `hdlr' and `int_return' entries
+	 */
+	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+	li	r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	2b
+
+	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+	bl	trap_reloc
+
+	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	3b
+
+	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+	bl	trap_reloc
+	addi	r7, r7, 0x100		/* next exception vector	*/
+	cmplw	0, r7, r8
+	blt	4b
+
+	mtlr	r4			/* restore link register	*/
+	blr
diff --git a/arch/powerpc/cpu/mpc8xx/traps.c b/arch/powerpc/cpu/mpc8xx/traps.c
new file mode 100644
index 0000000000..c6f43baf33
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/traps.c
@@ -0,0 +1,187 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt at linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort at cs.nmt.edu)
+ * and Paul Mackerras (paulus at cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM	0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+static 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");
+		}
+	}
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/* Probing PCI using config cycles cause this exception
+	 * when a device is not present.  Catch it and return to
+	 * the PCI exception handler.
+	 */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+	printf("Machine check in kernel mode.\n");
+	printf("Caused by (from msr): ");
+	printf("regs %p ",regs);
+	switch( regs->msr & 0x000F0000) {
+	case (0x80000000>>12):
+		printf("Machine check signal - probably due to mm fault\n"
+			"with mmu off\n");
+		break;
+	case (0x80000000>>13):
+		printf("Transfer error ack signal\n");
+		break;
+	case (0x80000000>>14):
+		printf("Data parity signal\n");
+		break;
+	case (0x80000000>>15):
+		printf("Address parity signal\n");
+		break;
+	default:
+		printf("Unknown values in msr\n");
+	}
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(0, regs);
+}
+
+void DebugException(struct pt_regs *regs)
+{
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+	int	retval;
+
+	__asm__ __volatile__(			\
+		"1:	lwz %0,0(%1)\n"		\
+		"	eieio\n"		\
+		"	li %0,0\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:	li %0,-1\n"		\
+		"	b 2b\n"			\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 2\n"		\
+		"	.long 1b,3b\n"		\
+		".text"				\
+		: "=r" (retval) : "r"(addr));
+
+	return (retval);
+#endif
+	return 0;
+}
diff --git a/arch/powerpc/include/asm/8xx_immap.h b/arch/powerpc/include/asm/8xx_immap.h
new file mode 100644
index 0000000000..3999a02b9c
--- /dev/null
+++ b/arch/powerpc/include/asm/8xx_immap.h
@@ -0,0 +1,468 @@
+/*
+ * MPC8xx Internal Memory Map
+ * Copyright (c) 1997 Dan Malek (dmalek at jlc.net)
+ *
+ * The I/O on the MPC860 is comprised of blocks of special registers
+ * and the dual port ram for the Communication Processor Module.
+ * Within this space are functional units such as the SIU, memory
+ * controller, system timers, and other control functions.  It is
+ * a combination that I found difficult to separate into logical
+ * functional files.....but anyone else is welcome to try.  -- Dan
+ */
+#ifndef __IMMAP_8XX__
+#define __IMMAP_8XX__
+
+/* System configuration registers.
+*/
+typedef	struct sys_conf {
+	uint	sc_siumcr;
+	uint	sc_sypcr;
+	uint	sc_swt;
+	char	res1[2];
+	ushort	sc_swsr;
+	uint	sc_sipend;
+	uint	sc_simask;
+	uint	sc_siel;
+	uint	sc_sivec;
+	uint	sc_tesr;
+	char	res2[0xc];
+	uint	sc_sdcr;
+	char	res3[0x4c];
+} sysconf8xx_t;
+
+/* PCMCIA configuration registers.
+*/
+typedef struct pcmcia_conf {
+	uint	pcmc_pbr0;
+	uint	pcmc_por0;
+	uint	pcmc_pbr1;
+	uint	pcmc_por1;
+	uint	pcmc_pbr2;
+	uint	pcmc_por2;
+	uint	pcmc_pbr3;
+	uint	pcmc_por3;
+	uint	pcmc_pbr4;
+	uint	pcmc_por4;
+	uint	pcmc_pbr5;
+	uint	pcmc_por5;
+	uint	pcmc_pbr6;
+	uint	pcmc_por6;
+	uint	pcmc_pbr7;
+	uint	pcmc_por7;
+	char	res1[0x20];
+	uint	pcmc_pgcra;
+	uint	pcmc_pgcrb;
+	uint	pcmc_pscr;
+	char	res2[4];
+	uint	pcmc_pipr;
+	char	res3[4];
+	uint	pcmc_per;
+	char	res4[4];
+} pcmconf8xx_t;
+
+/* Memory controller registers.
+*/
+typedef struct	mem_ctlr {
+	uint	memc_br0;
+	uint	memc_or0;
+	uint	memc_br1;
+	uint	memc_or1;
+	uint	memc_br2;
+	uint	memc_or2;
+	uint	memc_br3;
+	uint	memc_or3;
+	uint	memc_br4;
+	uint	memc_or4;
+	uint	memc_br5;
+	uint	memc_or5;
+	uint	memc_br6;
+	uint	memc_or6;
+	uint	memc_br7;
+	uint	memc_or7;
+	char	res1[0x24];
+	uint	memc_mar;
+	uint	memc_mcr;
+	char	res2[4];
+	uint	memc_mamr;
+	uint	memc_mbmr;
+	ushort	memc_mstat;
+	ushort	memc_mptpr;
+	uint	memc_mdr;
+	char	res3[0x80];
+} memctl8xx_t;
+
+/* System Integration Timers.
+*/
+typedef struct	sys_int_timers {
+	ushort	sit_tbscr;
+	char	res0[0x02];
+	uint	sit_tbreff0;
+	uint	sit_tbreff1;
+	char	res1[0x14];
+	ushort	sit_rtcsc;
+	char	res2[0x02];
+	uint	sit_rtc;
+	uint	sit_rtsec;
+	uint	sit_rtcal;
+	char	res3[0x10];
+	ushort	sit_piscr;
+	char	res4[2];
+	uint	sit_pitc;
+	uint	sit_pitr;
+	char	res5[0x34];
+} sit8xx_t;
+
+#define TBSCR_TBIRQ_MASK	((ushort)0xff00)
+#define TBSCR_REFA		((ushort)0x0080)
+#define TBSCR_REFB		((ushort)0x0040)
+#define TBSCR_REFAE		((ushort)0x0008)
+#define TBSCR_REFBE		((ushort)0x0004)
+#define TBSCR_TBF		((ushort)0x0002)
+#define TBSCR_TBE		((ushort)0x0001)
+
+#define RTCSC_RTCIRQ_MASK	((ushort)0xff00)
+#define RTCSC_SEC		((ushort)0x0080)
+#define RTCSC_ALR		((ushort)0x0040)
+#define RTCSC_38K		((ushort)0x0010)
+#define RTCSC_SIE		((ushort)0x0008)
+#define RTCSC_ALE		((ushort)0x0004)
+#define RTCSC_RTF		((ushort)0x0002)
+#define RTCSC_RTE		((ushort)0x0001)
+
+#define PISCR_PIRQ_MASK		((ushort)0xff00)
+#define PISCR_PS		((ushort)0x0080)
+#define PISCR_PIE		((ushort)0x0004)
+#define PISCR_PTF		((ushort)0x0002)
+#define PISCR_PTE		((ushort)0x0001)
+
+/* Clocks and Reset.
+*/
+typedef struct clk_and_reset {
+	uint	car_sccr;
+	uint	car_plprcr;
+	uint	car_rsr;
+	char	res[0x74];        /* Reserved area                  */
+} car8xx_t;
+
+/* System Integration Timers keys.
+*/
+typedef struct sitk {
+	uint	sitk_tbscrk;
+	uint	sitk_tbreff0k;
+	uint	sitk_tbreff1k;
+	uint	sitk_tbk;
+	char	res1[0x10];
+	uint	sitk_rtcsck;
+	uint	sitk_rtck;
+	uint	sitk_rtseck;
+	uint	sitk_rtcalk;
+	char	res2[0x10];
+	uint	sitk_piscrk;
+	uint	sitk_pitck;
+	char	res3[0x38];
+} sitk8xx_t;
+
+/* Clocks and reset keys.
+*/
+typedef struct cark {
+	uint	cark_sccrk;
+	uint	cark_plprcrk;
+	uint	cark_rsrk;
+	char	res[0x474];
+} cark8xx_t;
+
+/* The key to unlock registers maintained by keep-alive power.
+*/
+#define KAPWR_KEY	((unsigned int)0x55ccaa33)
+
+/* I2C
+*/
+typedef struct i2c {
+	u_char	i2c_i2mod;
+	char	res1[3];
+	u_char	i2c_i2add;
+	char	res2[3];
+	u_char	i2c_i2brg;
+	char	res3[3];
+	u_char	i2c_i2com;
+	char	res4[3];
+	u_char	i2c_i2cer;
+	char	res5[3];
+	u_char	i2c_i2cmr;
+	char	res6[0x8b];
+} i2c8xx_t;
+
+/* DMA control/status registers.
+*/
+typedef struct sdma_csr {
+	char	res1[4];
+	uint	sdma_sdar;
+	u_char	sdma_sdsr;
+	char	res3[3];
+	u_char	sdma_sdmr;
+	char	res4[3];
+	u_char	sdma_idsr1;
+	char	res5[3];
+	u_char	sdma_idmr1;
+	char	res6[3];
+	u_char	sdma_idsr2;
+	char	res7[3];
+	u_char	sdma_idmr2;
+	char	res8[0x13];
+} sdma8xx_t;
+
+/* Communication Processor Module Interrupt Controller.
+*/
+typedef struct cpm_ic {
+	ushort	cpic_civr;
+	char	res[0xe];
+	uint	cpic_cicr;
+	uint	cpic_cipr;
+	uint	cpic_cimr;
+	uint	cpic_cisr;
+} cpic8xx_t;
+
+/* Input/Output Port control/status registers.
+*/
+typedef struct io_port {
+	ushort	iop_padir;
+	ushort	iop_papar;
+	ushort	iop_paodr;
+	ushort	iop_padat;
+	char	res1[8];
+	ushort	iop_pcdir;
+	ushort	iop_pcpar;
+	ushort	iop_pcso;
+	ushort	iop_pcdat;
+	ushort	iop_pcint;
+	char	res2[6];
+	ushort	iop_pddir;
+	ushort	iop_pdpar;
+	char	res3[2];
+	ushort	iop_pddat;
+	uint	utmode;
+	char	res4[4];
+} iop8xx_t;
+
+/* Communication Processor Module Timers
+*/
+typedef struct cpm_timers {
+	ushort	cpmt_tgcr;
+	char	res1[0xe];
+	ushort	cpmt_tmr1;
+	ushort	cpmt_tmr2;
+	ushort	cpmt_trr1;
+	ushort	cpmt_trr2;
+	ushort	cpmt_tcr1;
+	ushort	cpmt_tcr2;
+	ushort	cpmt_tcn1;
+	ushort	cpmt_tcn2;
+	ushort	cpmt_tmr3;
+	ushort	cpmt_tmr4;
+	ushort	cpmt_trr3;
+	ushort	cpmt_trr4;
+	ushort	cpmt_tcr3;
+	ushort	cpmt_tcr4;
+	ushort	cpmt_tcn3;
+	ushort	cpmt_tcn4;
+	ushort	cpmt_ter1;
+	ushort	cpmt_ter2;
+	ushort	cpmt_ter3;
+	ushort	cpmt_ter4;
+	char	res2[8];
+} cpmtimer8xx_t;
+
+/* Finally, the Communication Processor stuff.....
+*/
+typedef struct scc {		/* Serial communication channels */
+	uint	scc_gsmrl;
+	uint	scc_gsmrh;
+	ushort	scc_psmr;
+	char	res1[2];
+	ushort	scc_todr;
+	ushort	scc_dsr;
+	ushort	scc_scce;
+	char	res2[2];
+	ushort	scc_sccm;
+	char	res3;
+	u_char	scc_sccs;
+	char	res4[8];
+} scc_t;
+
+typedef struct smc {		/* Serial management channels */
+	char	res1[2];
+	ushort	smc_smcmr;
+	char	res2[2];
+	u_char	smc_smce;
+	char	res3[3];
+	u_char	smc_smcm;
+	char	res4[5];
+} smc_t;
+
+/* MPC860T Fast Ethernet Controller.  It isn't part of the CPM, but
+ * it fits within the address space.
+ */
+
+typedef struct fec {
+	uint	fec_addr_low;		/* lower 32 bits of station address	*/
+	ushort	fec_addr_high;		/* upper 16 bits of station address	*/
+	ushort	res1;			/* reserved				*/
+	uint	fec_hash_table_high;	/* upper 32-bits of hash table		*/
+	uint	fec_hash_table_low;	/* lower 32-bits of hash table		*/
+	uint	fec_r_des_start;	/* beginning of Rx descriptor ring	*/
+	uint	fec_x_des_start;	/* beginning of Tx descriptor ring	*/
+	uint	fec_r_buff_size;	/* Rx buffer size			*/
+	uint	res2[9];		/* reserved				*/
+	uint	fec_ecntrl;		/* ethernet control register		*/
+	uint	fec_ievent;		/* interrupt event register		*/
+	uint	fec_imask;		/* interrupt mask register		*/
+	uint	fec_ivec;		/* interrupt level and vector status	*/
+	uint	fec_r_des_active;	/* Rx ring updated flag			*/
+	uint	fec_x_des_active;	/* Tx ring updated flag			*/
+	uint	res3[10];		/* reserved				*/
+	uint	fec_mii_data;		/* MII data register			*/
+	uint	fec_mii_speed;		/* MII speed control register		*/
+	uint	res4[17];		/* reserved				*/
+	uint	fec_r_bound;		/* end of RAM (read-only)		*/
+	uint	fec_r_fstart;		/* Rx FIFO start address		*/
+	uint	res5[6];		/* reserved				*/
+	uint	fec_x_fstart;		/* Tx FIFO start address		*/
+	uint	res6[17];		/* reserved				*/
+	uint	fec_fun_code;		/* fec SDMA function code		*/
+	uint	res7[3];		/* reserved				*/
+	uint	fec_r_cntrl;		/* Rx control register			*/
+	uint	fec_r_hash;		/* Rx hash register			*/
+	uint	res8[14];		/* reserved				*/
+	uint	fec_x_cntrl;		/* Tx control register			*/
+	uint	res9[0x1e];		/* reserved				*/
+} fec_t;
+
+typedef struct comm_proc {
+	/* General control and status registers.
+	*/
+	ushort	cp_cpcr;
+	u_char	res1[2];
+	ushort	cp_rccr;
+	u_char	res2;
+	u_char	cp_rmds;
+	u_char	res3[4];
+	ushort	cp_cpmcr1;
+	ushort	cp_cpmcr2;
+	ushort	cp_cpmcr3;
+	ushort	cp_cpmcr4;
+	u_char	res4[2];
+	ushort	cp_rter;
+	u_char	res5[2];
+	ushort	cp_rtmr;
+	u_char	res6[0x14];
+
+	/* Baud rate generators.
+	*/
+	uint	cp_brgc1;
+	uint	cp_brgc2;
+	uint	cp_brgc3;
+	uint	cp_brgc4;
+
+	/* Serial Communication Channels.
+	*/
+	scc_t	cp_scc[4];
+
+	/* Serial Management Channels.
+	*/
+	smc_t	cp_smc[2];
+
+	/* Serial Peripheral Interface.
+	*/
+	ushort	cp_spmode;
+	u_char	res7[4];
+	u_char	cp_spie;
+	u_char	res8[3];
+	u_char	cp_spim;
+	u_char	res9[2];
+	u_char	cp_spcom;
+	u_char	res10[2];
+
+	/* Parallel Interface Port.
+	*/
+	u_char	res11[2];
+	ushort	cp_pipc;
+	u_char	res12[2];
+	ushort	cp_ptpr;
+	uint	cp_pbdir;
+	uint	cp_pbpar;
+	u_char	res13[2];
+	ushort	cp_pbodr;
+	uint	cp_pbdat;
+
+	/* Port E - MPC87x/88x only.
+	 */
+	uint	cp_pedir;
+	uint	cp_pepar;
+	uint	cp_peso;
+	uint	cp_peodr;
+	uint	cp_pedat;
+
+	/* Communications Processor Timing Register -
+	   Contains RMII Timing for the FECs on MPC87x/88x only.
+	*/
+	uint	cp_cptr;
+
+	/* Serial Interface and Time Slot Assignment.
+	*/
+	uint	cp_simode;
+	u_char	cp_sigmr;
+	u_char	res15;
+	u_char	cp_sistr;
+	u_char	cp_sicmr;
+	u_char	res16[4];
+	uint	cp_sicr;
+	uint	cp_sirp;
+	u_char	res17[0xc];
+
+	u_char	res19[0x100];
+	u_char	cp_siram[0x200];
+
+	/* The fast ethernet controller is not really part of the CPM,
+	 * but it resides in the address space.
+	 */
+	fec_t	cp_fec;
+	char	res18[0xE00];
+
+	/* The MPC885 family has a second FEC here */
+	fec_t	cp_fec2;
+#define cp_fec1	cp_fec	/* consistency macro */
+
+	/* Dual Ported RAM follows.
+	 * There are many different formats for this memory area
+	 * depending upon the devices used and options chosen.
+	 * Some processors don't have all of it populated.
+	 */
+	u_char	cp_dpmem[0x1C00];	/* BD / Data / ucode */
+
+	/* Parameter RAM */
+	union {
+		u_char	cp_dparam[0x400];
+		u16	cp_dparam16[0x200];
+	};
+} cpm8xx_t;
+
+/* Internal memory map.
+*/
+typedef struct immap {
+	sysconf8xx_t	im_siu_conf;	/* SIU Configuration */
+	pcmconf8xx_t	im_pcmcia;	/* PCMCIA Configuration */
+	memctl8xx_t	im_memctl;	/* Memory Controller */
+	sit8xx_t	im_sit;		/* System integration timers */
+	car8xx_t	im_clkrst;	/* Clocks and reset */
+	sitk8xx_t	im_sitk;	/* Sys int timer keys */
+	cark8xx_t	im_clkrstk;	/* Clocks and reset keys */
+	char		res[96];
+	i2c8xx_t	im_i2c;		/* I2C control/status */
+	sdma8xx_t	im_sdma;	/* SDMA control/status */
+	cpic8xx_t	im_cpic;	/* CPM Interrupt Controller */
+	iop8xx_t	im_ioport;	/* IO Port control/status */
+	cpmtimer8xx_t	im_cpmtimer;	/* CPM timers */
+	cpm8xx_t	im_cpm;		/* Communication processor */
+} immap_t;
+
+#endif /* __IMMAP_8XX__ */
diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 20c52fcddc..d3a83910b6 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -7,7 +7,9 @@
 #include <asm/processor.h>
 
 /* bytes per L1 cache line */
-#if defined(CONFIG_PPC64BRIDGE)
+#if defined(CONFIG_8xx)
+#define	L1_CACHE_SHIFT	4
+#elif defined(CONFIG_PPC64BRIDGE)
 #define L1_CACHE_SHIFT	7
 #elif defined(CONFIG_E500MC)
 #define L1_CACHE_SHIFT	6
@@ -70,4 +72,41 @@ void disable_cpc_sram(void);
 #define L2CACHE_NONE	0x03	/* NONE */
 #define L2CACHE_PARITY  0x08    /* Mask for L2 Cache Parity Protected bit */
 
+#ifdef CONFIG_8xx
+/* Cache control on the MPC8xx is provided through some additional
+ * special purpose registers.
+ */
+#define IC_CST		560	/* Instruction cache control/status */
+#define IC_ADR		561	/* Address needed for some commands */
+#define IC_DAT		562	/* Read-only data register */
+#define DC_CST		568	/* Data cache control/status */
+#define DC_ADR		569	/* Address needed for some commands */
+#define DC_DAT		570	/* Read-only data register */
+
+/* Commands.  Only the first few are available to the instruction cache.
+*/
+#define	IDC_ENABLE	0x02000000	/* Cache enable */
+#define IDC_DISABLE	0x04000000	/* Cache disable */
+#define IDC_LDLCK	0x06000000	/* Load and lock */
+#define IDC_UNLINE	0x08000000	/* Unlock line */
+#define IDC_UNALL	0x0a000000	/* Unlock all */
+#define IDC_INVALL	0x0c000000	/* Invalidate all */
+
+#define DC_FLINE	0x0e000000	/* Flush data cache line */
+#define DC_SFWT		0x01000000	/* Set forced writethrough mode */
+#define DC_CFWT		0x03000000	/* Clear forced writethrough mode */
+#define DC_SLES		0x05000000	/* Set little endian swap mode */
+#define DC_CLES		0x07000000	/* Clear little endian swap mode */
+
+/* Status.
+*/
+#define IDC_ENABLED	0x80000000	/* Cache is enabled */
+#define IDC_CERR1	0x00200000	/* Cache error 1 */
+#define IDC_CERR2	0x00100000	/* Cache error 2 */
+#define IDC_CERR3	0x00080000	/* Cache error 3 */
+
+#define DC_DFWT		0x40000000	/* Data cache is forced write through */
+#define DC_LES		0x20000000	/* Caches are little endian mode */
+#endif /* CONFIG_8xx */
+
 #endif
diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
index 1c4a82ca99..35a02b61a4 100644
--- a/arch/powerpc/include/asm/global_data.h
+++ b/arch/powerpc/include/asm/global_data.h
@@ -19,6 +19,9 @@ struct arch_global_data {
 	u8 sdhc_adapter;
 #endif
 #endif
+#if defined(CONFIG_8xx)
+	unsigned long brg_clk;
+#endif
 #if defined(CONFIG_CPM2)
 	/* There are many clocks on the MPC8260 - see page 9-5 */
 	unsigned long vco_out;
diff --git a/arch/powerpc/include/asm/iopin_8xx.h b/arch/powerpc/include/asm/iopin_8xx.h
new file mode 100644
index 0000000000..8db0fa2a1c
--- /dev/null
+++ b/arch/powerpc/include/asm/iopin_8xx.h
@@ -0,0 +1,379 @@
+/*
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * MPC8xx I/O port pin manipulation functions
+ * Roughly based on iopin_8260.h
+ */
+
+#ifndef _ASM_IOPIN_8XX_H_
+#define _ASM_IOPIN_8XX_H_
+
+#include <linux/types.h>
+#include <asm/8xx_immap.h>
+
+#ifdef __KERNEL__
+
+typedef struct {
+	u_char port:2;	/* port number (A=0, B=1, C=2, D=3) */
+	u_char pin:5;	/* port pin (0-31) */
+	u_char flag:1;	/* for whatever */
+} iopin_t;
+
+#define IOPIN_PORTA	0
+#define IOPIN_PORTB	1
+#define IOPIN_PORTC	2
+#define IOPIN_PORTD	3
+
+static __inline__ void
+iopin_set_high(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat;
+		*datp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat;
+		*datp |= (1 << (31 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat;
+		*datp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat;
+		*datp |= (1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ void
+iopin_set_low(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat;
+		*datp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat;
+		*datp &= ~(1 << (31 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat;
+		*datp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat;
+		*datp &= ~(1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ uint
+iopin_is_high(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat;
+		return (*datp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat;
+		return (*datp >> (31 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat;
+		return (*datp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat;
+		return (*datp >> (15 - iopin->pin)) & 1;
+	}
+	return 0;
+}
+
+static __inline__ uint
+iopin_is_low(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat;
+		return ((*datp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat;
+		return ((*datp >> (31 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat;
+		return ((*datp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat;
+		return ((*datp >> (15 - iopin->pin)) & 1) ^ 1;
+	}
+	return 0;
+}
+
+static __inline__ void
+iopin_set_out(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir;
+		*dirp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir;
+		*dirp |= (1 << (31 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir;
+		*dirp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir;
+		*dirp |= (1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ void
+iopin_set_in(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir;
+		*dirp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir;
+		*dirp &= ~(1 << (31 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir;
+		*dirp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir;
+		*dirp &= ~(1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ uint
+iopin_is_out(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir;
+		return (*dirp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir;
+		return (*dirp >> (31 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir;
+		return (*dirp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir;
+		return (*dirp >> (15 - iopin->pin)) & 1;
+	}
+	return 0;
+}
+
+static __inline__ uint
+iopin_is_in(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir;
+		return ((*dirp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir;
+		return ((*dirp >> (31 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir;
+		return ((*dirp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir;
+		return ((*dirp >> (15 - iopin->pin)) & 1) ^ 1;
+	}
+	return 0;
+}
+
+static __inline__ void
+iopin_set_odr(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr;
+		*odrp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr;
+		*odrp |= (1 << (31 - iopin->pin));
+	}
+}
+
+static __inline__ void
+iopin_set_act(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr;
+		*odrp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr;
+		*odrp &= ~(1 << (31 - iopin->pin));
+	}
+}
+
+static __inline__ uint
+iopin_is_odr(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr;
+		return (*odrp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr;
+		return (*odrp >> (31 - iopin->pin)) & 1;
+	}
+	return 0;
+}
+
+static __inline__ uint
+iopin_is_act(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr;
+		return ((*odrp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr;
+		return ((*odrp >> (31 - iopin->pin)) & 1) ^ 1;
+	}
+	return 0;
+}
+
+static __inline__ void
+iopin_set_ded(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar;
+		*parp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar;
+		*parp |= (1 << (31 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar;
+		*parp |= (1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar;
+		*parp |= (1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ void
+iopin_set_gen(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar;
+		*parp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar;
+		*parp &= ~(1 << (31 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar;
+		*parp &= ~(1 << (15 - iopin->pin));
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar;
+		*parp &= ~(1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ uint
+iopin_is_ded(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar;
+		return (*parp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar;
+		return (*parp >> (31 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar;
+		return (*parp >> (15 - iopin->pin)) & 1;
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar;
+		return (*parp >> (15 - iopin->pin)) & 1;
+	}
+	return 0;
+}
+
+static __inline__ uint
+iopin_is_gen(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTA) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar;
+		return ((*parp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTB) {
+		volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar;
+		return ((*parp >> (31 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar;
+		return ((*parp >> (15 - iopin->pin)) & 1) ^ 1;
+	} else if (iopin->port == IOPIN_PORTD) {
+		volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar;
+		return ((*parp >> (15 - iopin->pin)) & 1) ^ 1;
+	}
+	return 0;
+}
+
+static __inline__ void
+iopin_set_opt2(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso;
+		*sorp |= (1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ void
+iopin_set_opt1(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso;
+		*sorp &= ~(1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ uint
+iopin_is_opt2(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso;
+		return (*sorp >> (15 - iopin->pin)) & 1;
+	}
+	return 0;
+}
+
+static __inline__ uint
+iopin_is_opt1(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso;
+		return ((*sorp >> (15 - iopin->pin)) & 1) ^ 1;
+	}
+	return 0;
+}
+
+static __inline__ void
+iopin_set_falledge(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint;
+		*intp |= (1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ void
+iopin_set_anyedge(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint;
+		*intp &= ~(1 << (15 - iopin->pin));
+	}
+}
+
+static __inline__ uint
+iopin_is_falledge(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint;
+		return (*intp >> (15 - iopin->pin)) & 1;
+	}
+	return 0;
+}
+
+static __inline__ uint
+iopin_is_anyedge(iopin_t *iopin)
+{
+	if (iopin->port == IOPIN_PORTC) {
+		volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint;
+		return ((*intp >> (15 - iopin->pin)) & 1) ^ 1;
+	}
+	return 0;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_IOPIN_8XX_H_ */
diff --git a/arch/powerpc/include/asm/ppc.h b/arch/powerpc/include/asm/ppc.h
index aa6c304d2d..9a8afe1132 100644
--- a/arch/powerpc/include/asm/ppc.h
+++ b/arch/powerpc/include/asm/ppc.h
@@ -13,6 +13,14 @@
 
 #ifndef __ASSEMBLY__
 
+#if defined(CONFIG_8xx)
+#include <asm/8xx_immap.h>
+#if defined(CONFIG_MPC866)
+# define CONFIG_MPC866_FAMILY 1
+#elif defined(CONFIG_MPC885)
+# define CONFIG_MPC885_FAMILY   1
+#endif
+#endif
 #ifdef CONFIG_MPC86xx
 #include <mpc86xx.h>
 #include <asm/immap_86xx.h>
@@ -35,6 +43,9 @@
 #include <asm/arch/immap_lsch2.h>
 #endif
 
+#if defined(CONFIG_8xx)
+uint get_immr(uint);
+#endif
 uint get_pvr(void);
 uint get_svr(void);
 uint rd_ic_cst(void);
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 30ac4f8c10..a1a2962a96 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -1351,7 +1351,10 @@ int prt_8260_clks(void);
 #endif /* ndef ASSEMBLY*/
 
 #ifdef CONFIG_MACH_SPECIFIC
-#if defined(CONFIG_WALNUT)
+#if defined(CONFIG_8xx)
+#define _machine _MACH_8xx
+#define have_of 0
+#elif defined(CONFIG_WALNUT)
 #define _machine _MACH_walnut
 #define have_of 0
 #else
diff --git a/arch/powerpc/lib/Kconfig b/arch/powerpc/lib/Kconfig
new file mode 100644
index 0000000000..987cec99cb
--- /dev/null
+++ b/arch/powerpc/lib/Kconfig
@@ -0,0 +1,8 @@
+config CMD_IMMAP
+	bool "Enable various commands to dump IMMR information"
+	help
+	  This enables various commands such as:
+
+	    siuinfo - print System Interface Unit (SIU) registers
+	    memcinfo - print Memory Controller registers
+	    sitinfo - print System Integration Timers (SIT) registers
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 9a3043abf8..4aa41836a2 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_BAT_RW) += bat_rw.o
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
 obj-y	+= cache.o
 obj-y	+= extable.o
+obj-$(CONFIG_CMD_IMMAP) += immap.o
 obj-y	+= interrupts.o
 obj-$(CONFIG_CMD_KGDB) += kgdb.o
 obj-y	+= stack.o
diff --git a/arch/powerpc/lib/immap.c b/arch/powerpc/lib/immap.c
new file mode 100644
index 0000000000..24ac899d2e
--- /dev/null
+++ b/arch/powerpc/lib/immap.c
@@ -0,0 +1,564 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * MPC8xx Internal Memory Map Functions
+ */
+
+#include <common.h>
+#include <command.h>
+
+#if defined(CONFIG_8xx)
+
+#include <asm/8xx_immap.h>
+#include <commproc.h>
+#include <asm/iopin_8xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void
+unimplemented ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	printf ("Sorry, but the '%s' command has not been implemented\n",
+		cmdtp->name);
+}
+
+int
+do_siuinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	volatile sysconf8xx_t *sc = &immap->im_siu_conf;
+
+	printf ("SIUMCR= %08x SYPCR = %08x\n", sc->sc_siumcr, sc->sc_sypcr);
+	printf ("SWT   = %08x\n", sc->sc_swt);
+	printf ("SIPEND= %08x SIMASK= %08x\n", sc->sc_sipend, sc->sc_simask);
+	printf ("SIEL  = %08x SIVEC = %08x\n", sc->sc_siel, sc->sc_sivec);
+	printf ("TESR  = %08x SDCR  = %08x\n", sc->sc_tesr, sc->sc_sdcr);
+	return 0;
+}
+
+int
+do_memcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	int nbanks = 8;
+	volatile uint *p = &memctl->memc_br0;
+	int i;
+
+	for (i = 0; i < nbanks; i++, p += 2) {
+		if (i < 10) {
+			printf ("BR%d   = %08x OR%d   = %08x\n",
+				i, p[0], i, p[1]);
+		} else {
+			printf ("BR%d  = %08x OR%d  = %08x\n",
+				i, p[0], i, p[1]);
+		}
+	}
+
+	printf ("MAR   = %08x", memctl->memc_mar);
+	printf (" MCR   = %08x\n", memctl->memc_mcr);
+	printf ("MAMR  = %08x MBMR  = %08x",
+		memctl->memc_mamr, memctl->memc_mbmr);
+	printf ("\nMSTAT =     %04x\n", memctl->memc_mstat);
+	printf ("MPTPR =     %04x MDR   = %08x\n",
+		memctl->memc_mptpr, memctl->memc_mdr);
+	return 0;
+}
+
+int
+do_sitinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_carinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	volatile car8xx_t *car = &immap->im_clkrst;
+
+	printf ("SCCR  = %08x\n", car->car_sccr);
+	printf ("PLPRCR= %08x\n", car->car_plprcr);
+	printf ("RSR   = %08x\n", car->car_rsr);
+	return 0;
+}
+
+static int counter;
+
+static void
+header(void)
+{
+	char *data = "\
+       --------------------------------        --------------------------------\
+       00000000001111111111222222222233        00000000001111111111222222222233\
+       01234567890123456789012345678901        01234567890123456789012345678901\
+       --------------------------------        --------------------------------\
+    ";
+	int i;
+
+	if (counter % 2)
+		putc('\n');
+	counter = 0;
+
+	for (i = 0; i < 4; i++, data += 79)
+		printf("%.79s\n", data);
+}
+
+static void binary (char *label, uint value, int nbits)
+{
+	uint mask = 1 << (nbits - 1);
+	int i, second = (counter++ % 2);
+
+	if (second)
+		putc (' ');
+	puts (label);
+	for (i = 32 + 1; i != nbits; i--)
+		putc (' ');
+
+	while (mask != 0) {
+		if (value & mask)
+			putc ('1');
+		else
+			putc ('0');
+		mask >>= 1;
+	}
+
+	if (second)
+		putc ('\n');
+}
+
+#define PA_NBITS	16
+#define PA_NB_ODR	 8
+#define PB_NBITS	18
+#define PB_NB_ODR	16
+#define PC_NBITS	12
+#define PD_NBITS	13
+
+int
+do_iopinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	volatile iop8xx_t *iop = &immap->im_ioport;
+	volatile ushort *l, *r;
+	volatile uint *R;
+
+	counter = 0;
+	header ();
+
+	/*
+	 * Ports A & B
+	 */
+
+	l = &iop->iop_padir;
+	R = &immap->im_cpm.cp_pbdir;
+	binary ("PA_DIR", *l++, PA_NBITS);
+	binary ("PB_DIR", *R++, PB_NBITS);
+	binary ("PA_PAR", *l++, PA_NBITS);
+	binary ("PB_PAR", *R++, PB_NBITS);
+	binary ("PA_ODR", *l++, PA_NB_ODR);
+	binary ("PB_ODR", *R++, PB_NB_ODR);
+	binary ("PA_DAT", *l++, PA_NBITS);
+	binary ("PB_DAT", *R++, PB_NBITS);
+
+	header ();
+
+	/*
+	 * Ports C & D
+	 */
+
+	l = &iop->iop_pcdir;
+	r = &iop->iop_pddir;
+	binary ("PC_DIR", *l++, PC_NBITS);
+	binary ("PD_DIR", *r++, PD_NBITS);
+	binary ("PC_PAR", *l++, PC_NBITS);
+	binary ("PD_PAR", *r++, PD_NBITS);
+	binary ("PC_SO ", *l++, PC_NBITS);
+	binary ("      ", 0, 0);
+	r++;
+	binary ("PC_DAT", *l++, PC_NBITS);
+	binary ("PD_DAT", *r++, PD_NBITS);
+	binary ("PC_INT", *l++, PC_NBITS);
+
+	header ();
+	return 0;
+}
+
+/*
+ * set the io pins
+ * this needs a clean up for smaller tighter code
+ * use *uint and set the address based on cmd + port
+ */
+int
+do_iopset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	uint rcode = 0;
+	iopin_t iopin;
+	static uint port = 0;
+	static uint pin = 0;
+	static uint value = 0;
+	static enum {
+		DIR,
+		PAR,
+		SOR,
+		ODR,
+		DAT,
+		INT
+	} cmd = DAT;
+
+	if (argc != 5) {
+		puts ("iopset PORT PIN CMD VALUE\n");
+		return 1;
+	}
+	port = argv[1][0] - 'A';
+	if (port > 3)
+		port -= 0x20;
+	if (port > 3)
+		rcode = 1;
+	pin = simple_strtol (argv[2], NULL, 10);
+	if (pin > 31)
+		rcode = 1;
+
+
+	switch (argv[3][0]) {
+	case 'd':
+		if (argv[3][1] == 'a')
+			cmd = DAT;
+		else if (argv[3][1] == 'i')
+			cmd = DIR;
+		else
+			rcode = 1;
+		break;
+	case 'p':
+		cmd = PAR;
+		break;
+	case 'o':
+		cmd = ODR;
+		break;
+	case 's':
+		cmd = SOR;
+		break;
+	case 'i':
+		cmd = INT;
+		break;
+	default:
+		printf ("iopset: unknown command %s\n", argv[3]);
+		rcode = 1;
+	}
+	if (argv[4][0] == '1')
+		value = 1;
+	else if (argv[4][0] == '0')
+		value = 0;
+	else
+		rcode = 1;
+	if (rcode == 0) {
+		iopin.port = port;
+		iopin.pin = pin;
+		iopin.flag = 0;
+		switch (cmd) {
+		case DIR:
+			if (value)
+				iopin_set_out (&iopin);
+			else
+				iopin_set_in (&iopin);
+			break;
+		case PAR:
+			if (value)
+				iopin_set_ded (&iopin);
+			else
+				iopin_set_gen (&iopin);
+			break;
+		case SOR:
+			if (value)
+				iopin_set_opt2 (&iopin);
+			else
+				iopin_set_opt1 (&iopin);
+			break;
+		case ODR:
+			if (value)
+				iopin_set_odr (&iopin);
+			else
+				iopin_set_act (&iopin);
+			break;
+		case DAT:
+			if (value)
+				iopin_set_high (&iopin);
+			else
+				iopin_set_low (&iopin);
+			break;
+		case INT:
+			if (value)
+				iopin_set_falledge (&iopin);
+			else
+				iopin_set_anyedge (&iopin);
+			break;
+		}
+
+	}
+	return rcode;
+}
+
+int
+do_dmainfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_fccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+static void prbrg (int n, uint val)
+{
+	uint extc = (val >> 14) & 3;
+	uint cd = (val & CPM_BRG_CD_MASK) >> 1;
+	uint div16 = (val & CPM_BRG_DIV16) != 0;
+
+	ulong clock = gd->cpu_clk;
+
+	printf ("BRG%d:", n);
+
+	if (val & CPM_BRG_RST)
+		puts (" RESET");
+	else
+		puts ("      ");
+
+	if (val & CPM_BRG_EN)
+		puts ("  ENABLED");
+	else
+		puts (" DISABLED");
+
+	printf (" EXTC=%d", extc);
+
+	if (val & CPM_BRG_ATB)
+		puts (" ATB");
+	else
+		puts ("    ");
+
+	printf (" DIVIDER=%4d", cd);
+	if (extc == 0 && cd != 0) {
+		uint baudrate;
+
+		if (div16)
+			baudrate = (clock / 16) / (cd + 1);
+		else
+			baudrate = clock / (cd + 1);
+
+		printf ("=%6d bps", baudrate);
+	} else {
+		puts ("           ");
+	}
+
+	if (val & CPM_BRG_DIV16)
+		puts (" DIV16");
+	else
+		puts ("      ");
+
+	putc ('\n');
+}
+
+int
+do_brginfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	volatile cpm8xx_t *cp = &immap->im_cpm;
+	volatile uint *p = &cp->cp_brgc1;
+	int i = 1;
+
+	while (i <= 4)
+		prbrg (i++, *p++);
+
+	return 0;
+}
+
+int
+do_i2cinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	volatile i2c8xx_t *i2c = &immap->im_i2c;
+	volatile cpm8xx_t *cp = &immap->im_cpm;
+	volatile iic_t *iip = (iic_t *) & cp->cp_dparam[PROFF_IIC];
+
+	printf ("I2MOD = %02x I2ADD = %02x\n", i2c->i2c_i2mod, i2c->i2c_i2add);
+	printf ("I2BRG = %02x I2COM = %02x\n", i2c->i2c_i2brg, i2c->i2c_i2com);
+	printf ("I2CER = %02x I2CMR = %02x\n", i2c->i2c_i2cer, i2c->i2c_i2cmr);
+
+	if (iip == NULL)
+		puts ("i2c parameter ram not allocated\n");
+	else {
+		printf ("RBASE = %08x TBASE = %08x\n",
+			iip->iic_rbase, iip->iic_tbase);
+		printf ("RFCR  =       %02x TFCR  =       %02x\n",
+			iip->iic_rfcr, iip->iic_tfcr);
+		printf ("MRBLR =     %04x\n", iip->iic_mrblr);
+		printf ("RSTATE= %08x RDP   = %08x\n",
+			iip->iic_rstate, iip->iic_rdp);
+		printf ("RBPTR =     %04x RBC   =     %04x\n",
+			iip->iic_rbptr, iip->iic_rbc);
+		printf ("RXTMP = %08x\n", iip->iic_rxtmp);
+		printf ("TSTATE= %08x TDP   = %08x\n",
+			iip->iic_tstate, iip->iic_tdp);
+		printf ("TBPTR =     %04x TBC   =     %04x\n",
+			iip->iic_tbptr, iip->iic_tbc);
+		printf ("TXTMP = %08x\n", iip->iic_txtmp);
+	}
+	return 0;
+}
+
+int
+do_sccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_smcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_spiinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_muxinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_siinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_mccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+	siuinfo,	1,	1,	do_siuinfo,
+	"print System Interface Unit (SIU) registers",
+	""
+);
+
+U_BOOT_CMD(
+	memcinfo,	1,	1,	do_memcinfo,
+	"print Memory Controller registers",
+	""
+);
+
+U_BOOT_CMD(
+	sitinfo,	1,	1,	do_sitinfo,
+	"print System Integration Timers (SIT) registers",
+	""
+);
+
+
+U_BOOT_CMD(
+	carinfo,	1,	1,	do_carinfo,
+	"print Clocks and Reset registers",
+	""
+);
+
+U_BOOT_CMD(
+	iopinfo,	1,	1,	do_iopinfo,
+	"print I/O Port registers",
+	""
+);
+
+U_BOOT_CMD(
+	iopset,	5,	0,	do_iopset,
+	"set I/O Port registers",
+	"PORT PIN CMD VALUE\nPORT: A-D, PIN: 0-31, CMD: [dat|dir|odr|sor], VALUE: 0|1"
+);
+
+U_BOOT_CMD(
+	dmainfo,	1,	1,	do_dmainfo,
+	"print SDMA/IDMA registers",
+	""
+);
+
+U_BOOT_CMD(
+	fccinfo,	1,	1,	do_fccinfo,
+	"print FCC registers",
+	""
+);
+
+U_BOOT_CMD(
+	brginfo,	1,	1,	do_brginfo,
+	"print Baud Rate Generator (BRG) registers",
+	""
+);
+
+U_BOOT_CMD(
+	i2cinfo,	1,	1,	do_i2cinfo,
+	"print I2C registers",
+	""
+);
+
+U_BOOT_CMD(
+	sccinfo,	1,	1,	do_sccinfo,
+	"print SCC registers",
+	""
+);
+
+U_BOOT_CMD(
+	smcinfo,	1,	1,	do_smcinfo,
+	"print SMC registers",
+	""
+);
+
+U_BOOT_CMD(
+	spiinfo,	1,	1,	do_spiinfo,
+	"print Serial Peripheral Interface (SPI) registers",
+	""
+);
+
+U_BOOT_CMD(
+	muxinfo,	1,	1,	do_muxinfo,
+	"print CPM Multiplexing registers",
+	""
+);
+
+U_BOOT_CMD(
+	siinfo,	1,	1,	do_siinfo,
+	"print Serial Interface (SI) registers",
+	""
+);
+
+U_BOOT_CMD(
+	mccinfo,	1,	1,	do_mccinfo,
+	"print MCC registers",
+	""
+);
+
+#endif
diff --git a/arch/powerpc/lib/time.c b/arch/powerpc/lib/time.c
index 3a5ad4d8d2..4cbb65eb68 100644
--- a/arch/powerpc/lib/time.c
+++ b/arch/powerpc/lib/time.c
@@ -64,10 +64,21 @@ int timer_init(void)
 {
 	unsigned long temp;
 
+#if defined(CONFIG_8xx)
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+	/* unlock */
+	immap->im_sitk.sitk_tbk = KAPWR_KEY;
+#endif
+
 	/* reset */
 	asm volatile("li %0,0 ; mttbu %0 ; mttbl %0;"
 	     : "=&r"(temp) );
 
+#if defined(CONFIG_8xx)
+	/* enable */
+	immap->im_sit.sit_tbscr |= TBSCR_TBE;
+#endif
 	return (0);
 }
 /* ------------------------------------------------------------------------- */
diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c
index 89b73f4fb9..1599b8be0d 100644
--- a/cmd/bdinfo.c
+++ b/cmd/bdinfo.c
@@ -183,7 +183,8 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	print_bi_flash(bd);
 	print_num("sramstart",		bd->bi_sramstart);
 	print_num("sramsize",		bd->bi_sramsize);
-#if	defined(CONFIG_E500)
+#if	defined(CONFIG_8xx) || \
+	defined(CONFIG_E500)
 	print_num("immr_base",		bd->bi_immr_base);
 #endif
 	print_num("bootflags",		bd->bi_bootflags);
diff --git a/cmd/reginfo.c b/cmd/reginfo.c
index 8e4bec8c4b..96a7542d2d 100644
--- a/cmd/reginfo.c
+++ b/cmd/reginfo.c
@@ -7,7 +7,9 @@
 
 #include <common.h>
 #include <command.h>
-#if defined(CONFIG_MPC86xx)
+#if defined(CONFIG_8xx)
+#include <mpc8xx.h>
+#elif defined (CONFIG_MPC86xx)
 extern void mpc86xx_reginfo(void);
 #elif defined(CONFIG_MPC85xx)
 extern void mpc85xx_reginfo(void);
@@ -16,7 +18,60 @@ extern void mpc85xx_reginfo(void);
 static int do_reginfo(cmd_tbl_t *cmdtp, int flag, int argc,
 		       char * const argv[])
 {
-#if defined(CONFIG_MPC86xx)
+#if defined(CONFIG_8xx)
+	volatile immap_t     *immap  = (immap_t *)CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	volatile sysconf8xx_t *sysconf = &immap->im_siu_conf;
+	volatile sit8xx_t *timers = &immap->im_sit;
+
+	/* Hopefully more PowerPC  knowledgable people will add code to display
+	 * other useful registers
+	 */
+
+	printf ("\nSystem Configuration registers\n"
+
+		"\tIMMR\t0x%08X\n", get_immr(0));
+
+	printf("\tSIUMCR\t0x%08X", sysconf->sc_siumcr);
+	printf("\tSYPCR\t0x%08X\n",sysconf->sc_sypcr);
+
+	printf("\tSWT\t0x%08X",    sysconf->sc_swt);
+	printf("\tSWSR\t0x%04X\n", sysconf->sc_swsr);
+
+	printf("\tSIPEND\t0x%08X\tSIMASK\t0x%08X\n",
+		sysconf->sc_sipend, sysconf->sc_simask);
+	printf("\tSIEL\t0x%08X\tSIVEC\t0x%08X\n",
+		sysconf->sc_siel, sysconf->sc_sivec);
+	printf("\tTESR\t0x%08X\tSDCR\t0x%08X\n",
+		sysconf->sc_tesr, sysconf->sc_sdcr);
+
+	printf ("Memory Controller Registers\n"
+
+		"\tBR0\t0x%08X\tOR0\t0x%08X \n", memctl->memc_br0, memctl->memc_or0);
+	printf("\tBR1\t0x%08X\tOR1\t0x%08X \n", memctl->memc_br1, memctl->memc_or1);
+	printf("\tBR2\t0x%08X\tOR2\t0x%08X \n", memctl->memc_br2, memctl->memc_or2);
+	printf("\tBR3\t0x%08X\tOR3\t0x%08X \n", memctl->memc_br3, memctl->memc_or3);
+	printf("\tBR4\t0x%08X\tOR4\t0x%08X \n", memctl->memc_br4, memctl->memc_or4);
+	printf("\tBR5\t0x%08X\tOR5\t0x%08X \n", memctl->memc_br5, memctl->memc_or5);
+	printf("\tBR6\t0x%08X\tOR6\t0x%08X \n", memctl->memc_br6, memctl->memc_or6);
+	printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", memctl->memc_br7, memctl->memc_or7);
+	printf ("\n"
+		"\tmamr\t0x%08X\tmbmr\t0x%08X \n",
+		memctl->memc_mamr, memctl->memc_mbmr );
+	printf("\tmstat\t0x%08X\tmptpr\t0x%08X \n",
+		memctl->memc_mstat, memctl->memc_mptpr );
+	printf("\tmdr\t0x%08X \n", memctl->memc_mdr);
+
+	printf ("\nSystem Integration Timers\n"
+		"\tTBSCR\t0x%08X\tRTCSC\t0x%08X \n",
+		timers->sit_tbscr, timers->sit_rtcsc);
+	printf("\tPISCR\t0x%08X \n", timers->sit_piscr);
+
+	/*
+	 * May be some CPM info here?
+	 */
+
+#elif defined(CONFIG_MPC86xx)
 	mpc86xx_reginfo();
 
 #elif defined(CONFIG_MPC85xx)
diff --git a/include/asm-generic/u-boot.h b/include/asm-generic/u-boot.h
index b8f9c7aedb..cc232d92a6 100644
--- a/include/asm-generic/u-boot.h
+++ b/include/asm-generic/u-boot.h
@@ -41,7 +41,8 @@ typedef struct bd_info {
 	unsigned long	bi_dsp_freq; /* dsp core frequency */
 	unsigned long	bi_ddr_freq; /* ddr frequency */
 #endif
-#if defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#if defined(CONFIG_8xx) \
+	|| defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
 	unsigned long	bi_immr_base;	/* base of IMMR register */
 #endif
 #if defined(CONFIG_M68K)
diff --git a/include/commproc.h b/include/commproc.h
new file mode 100644
index 0000000000..5518cb325d
--- /dev/null
+++ b/include/commproc.h
@@ -0,0 +1,687 @@
+/*
+ * MPC8xx Communication Processor Module.
+ * Copyright (c) 1997 Dan Malek (dmalek at jlc.net)
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * This file contains structures and information for the communication
+ * processor channels.  Some CPM control and status is available
+ * throught the MPC8xx internal memory map.  See immap.h for details.
+ * This file only contains what I need for the moment, not the total
+ * CPM capabilities.  I (or someone else) will add definitions as they
+ * are needed.  -- Dan
+ *
+ */
+#ifndef __CPM_8XX__
+#define __CPM_8XX__
+
+#include <asm/8xx_immap.h>
+
+/* CPM Command register.
+*/
+#define CPM_CR_RST		((ushort)0x8000)
+#define CPM_CR_OPCODE		((ushort)0x0f00)
+#define CPM_CR_CHAN		((ushort)0x00f0)
+#define CPM_CR_FLG		((ushort)0x0001)
+
+/* Some commands (there are more...later)
+*/
+#define CPM_CR_INIT_TRX		((ushort)0x0000)
+#define CPM_CR_INIT_RX		((ushort)0x0001)
+#define CPM_CR_INIT_TX		((ushort)0x0002)
+#define CPM_CR_HUNT_MODE	((ushort)0x0003)
+#define CPM_CR_STOP_TX		((ushort)0x0004)
+#define CPM_CR_RESTART_TX	((ushort)0x0006)
+#define CPM_CR_SET_GADDR	((ushort)0x0008)
+
+/* Channel numbers.
+*/
+#define CPM_CR_CH_SCC1		((ushort)0x0000)
+#define CPM_CR_CH_I2C		((ushort)0x0001)    /* I2C and IDMA1 */
+#define CPM_CR_CH_SCC2		((ushort)0x0004)
+#define CPM_CR_CH_SPI		((ushort)0x0005)    /* SPI/IDMA2/Timers */
+#define CPM_CR_CH_SCC3		((ushort)0x0008)
+#define CPM_CR_CH_SMC1		((ushort)0x0009)    /* SMC1 / DSP1 */
+#define CPM_CR_CH_SCC4		((ushort)0x000c)
+#define CPM_CR_CH_SMC2		((ushort)0x000d)    /* SMC2 / DSP2 */
+
+#define mk_cr_cmd(CH, CMD)	((CMD << 8) | (CH << 4))
+
+/*
+ * DPRAM defines and allocation functions
+ */
+#define CPM_SERIAL_BASE		0x0800
+#define CPM_I2C_BASE		0x0820
+#define CPM_SPI_BASE		0x0840
+#define CPM_FEC_BASE		0x0860
+#define CPM_SERIAL2_BASE	0x08E0
+#define CPM_SCC_BASE		0x0900
+#define CPM_POST_BASE		0x0980
+#define CPM_WLKBD_BASE		0x0a00
+
+#define BD_IIC_START	((uint) 0x0400) /* <- please use CPM_I2C_BASE !! */
+
+/* Export the base address of the communication processor registers
+ * and dual port ram.
+ */
+extern	cpm8xx_t	*cpmp;		/* Pointer to comm processor */
+
+/* Buffer descriptors used by many of the CPM protocols.
+*/
+typedef struct cpm_buf_desc {
+	ushort	cbd_sc;		/* Status and Control */
+	ushort	cbd_datlen;	/* Data length in buffer */
+	uint	cbd_bufaddr;	/* Buffer address in host memory */
+} cbd_t;
+
+#define BD_SC_EMPTY	((ushort)0x8000)	/* Receive is empty */
+#define BD_SC_READY	((ushort)0x8000)	/* Transmit is ready */
+#define BD_SC_WRAP	((ushort)0x2000)	/* Last buffer descriptor */
+#define BD_SC_INTRPT	((ushort)0x1000)	/* Interrupt on change */
+#define BD_SC_LAST	((ushort)0x0800)	/* Last buffer in frame */
+#define BD_SC_TC	((ushort)0x0400)	/* Transmit CRC */
+#define BD_SC_CM	((ushort)0x0200)	/* Continous mode */
+#define BD_SC_ID	((ushort)0x0100)	/* Rec'd too many idles */
+#define BD_SC_P		((ushort)0x0100)	/* xmt preamble */
+#define BD_SC_BR	((ushort)0x0020)	/* Break received */
+#define BD_SC_FR	((ushort)0x0010)	/* Framing error */
+#define BD_SC_PR	((ushort)0x0008)	/* Parity error */
+#define BD_SC_OV	((ushort)0x0002)	/* Overrun */
+#define BD_SC_CD	((ushort)0x0001)	/* Carrier Detect lost */
+
+/* Parameter RAM offsets.
+*/
+#define PROFF_SCC1	((uint)0x0000)
+#define PROFF_IIC	((uint)0x0080)
+#define PROFF_REVNUM	((uint)0x00b0)
+#define PROFF_SCC2	((uint)0x0100)
+#define PROFF_SPI	((uint)0x0180)
+#define PROFF_SCC3	((uint)0x0200)
+#define PROFF_SMC1	((uint)0x0280)
+#define PROFF_SCC4	((uint)0x0300)
+#define PROFF_SMC2	((uint)0x0380)
+
+/* Define enough so I can at least use the serial port as a UART.
+ */
+typedef struct smc_uart {
+	ushort	smc_rbase;	/* Rx Buffer descriptor base address */
+	ushort	smc_tbase;	/* Tx Buffer descriptor base address */
+	u_char	smc_rfcr;	/* Rx function code */
+	u_char	smc_tfcr;	/* Tx function code */
+	ushort	smc_mrblr;	/* Max receive buffer length */
+	uint	smc_rstate;	/* Internal */
+	uint	smc_idp;	/* Internal */
+	ushort	smc_rbptr;	/* Internal */
+	ushort	smc_ibc;	/* Internal */
+	uint	smc_rxtmp;	/* Internal */
+	uint	smc_tstate;	/* Internal */
+	uint	smc_tdp;	/* Internal */
+	ushort	smc_tbptr;	/* Internal */
+	ushort	smc_tbc;	/* Internal */
+	uint	smc_txtmp;	/* Internal */
+	ushort	smc_maxidl;	/* Maximum idle characters */
+	ushort	smc_tmpidl;	/* Temporary idle counter */
+	ushort	smc_brklen;	/* Last received break length */
+	ushort	smc_brkec;	/* rcv'd break condition counter */
+	ushort	smc_brkcr;	/* xmt break count register */
+	ushort	smc_rmask;	/* Temporary bit mask */
+	u_char	res1[8];
+	ushort	smc_rpbase;	/* Relocation pointer */
+} smc_uart_t;
+
+/* Function code bits.
+*/
+#define SMC_EB	((u_char)0x10)	/* Set big endian byte order */
+
+/* SMC uart mode register.
+*/
+#define	SMCMR_REN	((ushort)0x0001)
+#define SMCMR_TEN	((ushort)0x0002)
+#define SMCMR_DM	((ushort)0x000c)
+#define SMCMR_SM_GCI	((ushort)0x0000)
+#define SMCMR_SM_UART	((ushort)0x0020)
+#define SMCMR_SM_TRANS	((ushort)0x0030)
+#define SMCMR_SM_MASK	((ushort)0x0030)
+#define SMCMR_PM_EVEN	((ushort)0x0100)	/* Even parity, else odd */
+#define SMCMR_REVD	SMCMR_PM_EVEN
+#define SMCMR_PEN	((ushort)0x0200)	/* Parity enable */
+#define SMCMR_BS	SMCMR_PEN
+#define SMCMR_SL	((ushort)0x0400)	/* Two stops, else one */
+#define SMCR_CLEN_MASK	((ushort)0x7800)	/* Character length */
+#define smcr_mk_clen(C)	(((C) << 11) & SMCR_CLEN_MASK)
+
+/* SMC2 as Centronics parallel printer.  It is half duplex, in that
+ * it can only receive or transmit.  The parameter ram values for
+ * each direction are either unique or properly overlap, so we can
+ * include them in one structure.
+ */
+typedef struct smc_centronics {
+	ushort	scent_rbase;
+	ushort	scent_tbase;
+	u_char	scent_cfcr;
+	u_char	scent_smask;
+	ushort	scent_mrblr;
+	uint	scent_rstate;
+	uint	scent_r_ptr;
+	ushort	scent_rbptr;
+	ushort	scent_r_cnt;
+	uint	scent_rtemp;
+	uint	scent_tstate;
+	uint	scent_t_ptr;
+	ushort	scent_tbptr;
+	ushort	scent_t_cnt;
+	uint	scent_ttemp;
+	ushort	scent_max_sl;
+	ushort	scent_sl_cnt;
+	ushort	scent_character1;
+	ushort	scent_character2;
+	ushort	scent_character3;
+	ushort	scent_character4;
+	ushort	scent_character5;
+	ushort	scent_character6;
+	ushort	scent_character7;
+	ushort	scent_character8;
+	ushort	scent_rccm;
+	ushort	scent_rccr;
+} smc_cent_t;
+
+/* Centronics Status Mask Register.
+*/
+#define SMC_CENT_F	((u_char)0x08)
+#define SMC_CENT_PE	((u_char)0x04)
+#define SMC_CENT_S	((u_char)0x02)
+
+/* SMC Event and Mask register.
+*/
+#define	SMCM_BRKE	((unsigned char)0x40)	/* When in UART Mode */
+#define	SMCM_BRK	((unsigned char)0x10)	/* When in UART Mode */
+#define	SMCM_TXE	((unsigned char)0x10)	/* When in Transparent Mode */
+#define	SMCM_BSY	((unsigned char)0x04)
+#define	SMCM_TX		((unsigned char)0x02)
+#define	SMCM_RX		((unsigned char)0x01)
+
+/* Baud rate generators.
+*/
+#define CPM_BRG_RST		((uint)0x00020000)
+#define CPM_BRG_EN		((uint)0x00010000)
+#define CPM_BRG_EXTC_INT	((uint)0x00000000)
+#define CPM_BRG_EXTC_CLK2	((uint)0x00004000)
+#define CPM_BRG_EXTC_CLK6	((uint)0x00008000)
+#define CPM_BRG_ATB		((uint)0x00002000)
+#define CPM_BRG_CD_MASK		((uint)0x00001ffe)
+#define CPM_BRG_DIV16		((uint)0x00000001)
+
+/* SI Clock Route Register
+*/
+#define SICR_RCLK_SCC1_BRG1	((uint)0x00000000)
+#define SICR_TCLK_SCC1_BRG1	((uint)0x00000000)
+#define SICR_RCLK_SCC2_BRG2	((uint)0x00000800)
+#define SICR_TCLK_SCC2_BRG2	((uint)0x00000100)
+#define SICR_RCLK_SCC3_BRG3	((uint)0x00100000)
+#define SICR_TCLK_SCC3_BRG3	((uint)0x00020000)
+#define SICR_RCLK_SCC4_BRG4	((uint)0x18000000)
+#define SICR_TCLK_SCC4_BRG4	((uint)0x03000000)
+
+/* SCCs.
+*/
+#define SCC_GSMRH_IRP		((uint)0x00040000)
+#define SCC_GSMRH_GDE		((uint)0x00010000)
+#define SCC_GSMRH_TCRC_CCITT	((uint)0x00008000)
+#define SCC_GSMRH_TCRC_BISYNC	((uint)0x00004000)
+#define SCC_GSMRH_TCRC_HDLC	((uint)0x00000000)
+#define SCC_GSMRH_REVD		((uint)0x00002000)
+#define SCC_GSMRH_TRX		((uint)0x00001000)
+#define SCC_GSMRH_TTX		((uint)0x00000800)
+#define SCC_GSMRH_CDP		((uint)0x00000400)
+#define SCC_GSMRH_CTSP		((uint)0x00000200)
+#define SCC_GSMRH_CDS		((uint)0x00000100)
+#define SCC_GSMRH_CTSS		((uint)0x00000080)
+#define SCC_GSMRH_TFL		((uint)0x00000040)
+#define SCC_GSMRH_RFW		((uint)0x00000020)
+#define SCC_GSMRH_TXSY		((uint)0x00000010)
+#define SCC_GSMRH_SYNL16	((uint)0x0000000c)
+#define SCC_GSMRH_SYNL8		((uint)0x00000008)
+#define SCC_GSMRH_SYNL4		((uint)0x00000004)
+#define SCC_GSMRH_RTSM		((uint)0x00000002)
+#define SCC_GSMRH_RSYN		((uint)0x00000001)
+
+#define SCC_GSMRL_SIR		((uint)0x80000000)	/* SCC2 only */
+#define SCC_GSMRL_EDGE_NONE	((uint)0x60000000)
+#define SCC_GSMRL_EDGE_NEG	((uint)0x40000000)
+#define SCC_GSMRL_EDGE_POS	((uint)0x20000000)
+#define SCC_GSMRL_EDGE_BOTH	((uint)0x00000000)
+#define SCC_GSMRL_TCI		((uint)0x10000000)
+#define SCC_GSMRL_TSNC_3	((uint)0x0c000000)
+#define SCC_GSMRL_TSNC_4	((uint)0x08000000)
+#define SCC_GSMRL_TSNC_14	((uint)0x04000000)
+#define SCC_GSMRL_TSNC_INF	((uint)0x00000000)
+#define SCC_GSMRL_RINV		((uint)0x02000000)
+#define SCC_GSMRL_TINV		((uint)0x01000000)
+#define SCC_GSMRL_TPL_128	((uint)0x00c00000)
+#define SCC_GSMRL_TPL_64	((uint)0x00a00000)
+#define SCC_GSMRL_TPL_48	((uint)0x00800000)
+#define SCC_GSMRL_TPL_32	((uint)0x00600000)
+#define SCC_GSMRL_TPL_16	((uint)0x00400000)
+#define SCC_GSMRL_TPL_8		((uint)0x00200000)
+#define SCC_GSMRL_TPL_NONE	((uint)0x00000000)
+#define SCC_GSMRL_TPP_ALL1	((uint)0x00180000)
+#define SCC_GSMRL_TPP_01	((uint)0x00100000)
+#define SCC_GSMRL_TPP_10	((uint)0x00080000)
+#define SCC_GSMRL_TPP_ZEROS	((uint)0x00000000)
+#define SCC_GSMRL_TEND		((uint)0x00040000)
+#define SCC_GSMRL_TDCR_32	((uint)0x00030000)
+#define SCC_GSMRL_TDCR_16	((uint)0x00020000)
+#define SCC_GSMRL_TDCR_8	((uint)0x00010000)
+#define SCC_GSMRL_TDCR_1	((uint)0x00000000)
+#define SCC_GSMRL_RDCR_32	((uint)0x0000c000)
+#define SCC_GSMRL_RDCR_16	((uint)0x00008000)
+#define SCC_GSMRL_RDCR_8	((uint)0x00004000)
+#define SCC_GSMRL_RDCR_1	((uint)0x00000000)
+#define SCC_GSMRL_RENC_DFMAN	((uint)0x00003000)
+#define SCC_GSMRL_RENC_MANCH	((uint)0x00002000)
+#define SCC_GSMRL_RENC_FM0	((uint)0x00001000)
+#define SCC_GSMRL_RENC_NRZI	((uint)0x00000800)
+#define SCC_GSMRL_RENC_NRZ	((uint)0x00000000)
+#define SCC_GSMRL_TENC_DFMAN	((uint)0x00000600)
+#define SCC_GSMRL_TENC_MANCH	((uint)0x00000400)
+#define SCC_GSMRL_TENC_FM0	((uint)0x00000200)
+#define SCC_GSMRL_TENC_NRZI	((uint)0x00000100)
+#define SCC_GSMRL_TENC_NRZ	((uint)0x00000000)
+#define SCC_GSMRL_DIAG_LE	((uint)0x000000c0)	/* Loop and echo */
+#define SCC_GSMRL_DIAG_ECHO	((uint)0x00000080)
+#define SCC_GSMRL_DIAG_LOOP	((uint)0x00000040)
+#define SCC_GSMRL_DIAG_NORM	((uint)0x00000000)
+#define SCC_GSMRL_ENR		((uint)0x00000020)
+#define SCC_GSMRL_ENT		((uint)0x00000010)
+#define SCC_GSMRL_MODE_ENET	((uint)0x0000000c)
+#define SCC_GSMRL_MODE_DDCMP	((uint)0x00000009)
+#define SCC_GSMRL_MODE_BISYNC	((uint)0x00000008)
+#define SCC_GSMRL_MODE_V14	((uint)0x00000007)
+#define SCC_GSMRL_MODE_AHDLC	((uint)0x00000006)
+#define SCC_GSMRL_MODE_PROFIBUS	((uint)0x00000005)
+#define SCC_GSMRL_MODE_UART	((uint)0x00000004)
+#define SCC_GSMRL_MODE_SS7	((uint)0x00000003)
+#define SCC_GSMRL_MODE_ATALK	((uint)0x00000002)
+#define SCC_GSMRL_MODE_HDLC	((uint)0x00000000)
+
+#define SCC_TODR_TOD		((ushort)0x8000)
+
+/* SCC Event and Mask register.
+*/
+#define	SCCM_TXE	((unsigned char)0x10)
+#define	SCCM_BSY	((unsigned char)0x04)
+#define	SCCM_TX		((unsigned char)0x02)
+#define	SCCM_RX		((unsigned char)0x01)
+
+typedef struct scc_param {
+	ushort	scc_rbase;	/* Rx Buffer descriptor base address */
+	ushort	scc_tbase;	/* Tx Buffer descriptor base address */
+	u_char	scc_rfcr;	/* Rx function code */
+	u_char	scc_tfcr;	/* Tx function code */
+	ushort	scc_mrblr;	/* Max receive buffer length */
+	uint	scc_rstate;	/* Internal */
+	uint	scc_idp;	/* Internal */
+	ushort	scc_rbptr;	/* Internal */
+	ushort	scc_ibc;	/* Internal */
+	uint	scc_rxtmp;	/* Internal */
+	uint	scc_tstate;	/* Internal */
+	uint	scc_tdp;	/* Internal */
+	ushort	scc_tbptr;	/* Internal */
+	ushort	scc_tbc;	/* Internal */
+	uint	scc_txtmp;	/* Internal */
+	uint	scc_rcrc;	/* Internal */
+	uint	scc_tcrc;	/* Internal */
+} sccp_t;
+
+/* Function code bits.
+*/
+#define SCC_EB	((u_char)0x10)	/* Set big endian byte order */
+
+/* CPM Ethernet through SCCx.
+ */
+typedef struct scc_enet {
+	sccp_t	sen_genscc;
+	uint	sen_cpres;	/* Preset CRC */
+	uint	sen_cmask;	/* Constant mask for CRC */
+	uint	sen_crcec;	/* CRC Error counter */
+	uint	sen_alec;	/* alignment error counter */
+	uint	sen_disfc;	/* discard frame counter */
+	ushort	sen_pads;	/* Tx short frame pad character */
+	ushort	sen_retlim;	/* Retry limit threshold */
+	ushort	sen_retcnt;	/* Retry limit counter */
+	ushort	sen_maxflr;	/* maximum frame length register */
+	ushort	sen_minflr;	/* minimum frame length register */
+	ushort	sen_maxd1;	/* maximum DMA1 length */
+	ushort	sen_maxd2;	/* maximum DMA2 length */
+	ushort	sen_maxd;	/* Rx max DMA */
+	ushort	sen_dmacnt;	/* Rx DMA counter */
+	ushort	sen_maxb;	/* Max BD byte count */
+	ushort	sen_gaddr1;	/* Group address filter */
+	ushort	sen_gaddr2;
+	ushort	sen_gaddr3;
+	ushort	sen_gaddr4;
+	uint	sen_tbuf0data0;	/* Save area 0 - current frame */
+	uint	sen_tbuf0data1;	/* Save area 1 - current frame */
+	uint	sen_tbuf0rba;	/* Internal */
+	uint	sen_tbuf0crc;	/* Internal */
+	ushort	sen_tbuf0bcnt;	/* Internal */
+	ushort	sen_paddrh;	/* physical address (MSB) */
+	ushort	sen_paddrm;
+	ushort	sen_paddrl;	/* physical address (LSB) */
+	ushort	sen_pper;	/* persistence */
+	ushort	sen_rfbdptr;	/* Rx first BD pointer */
+	ushort	sen_tfbdptr;	/* Tx first BD pointer */
+	ushort	sen_tlbdptr;	/* Tx last BD pointer */
+	uint	sen_tbuf1data0;	/* Save area 0 - current frame */
+	uint	sen_tbuf1data1;	/* Save area 1 - current frame */
+	uint	sen_tbuf1rba;	/* Internal */
+	uint	sen_tbuf1crc;	/* Internal */
+	ushort	sen_tbuf1bcnt;	/* Internal */
+	ushort	sen_txlen;	/* Tx Frame length counter */
+	ushort	sen_iaddr1;	/* Individual address filter */
+	ushort	sen_iaddr2;
+	ushort	sen_iaddr3;
+	ushort	sen_iaddr4;
+	ushort	sen_boffcnt;	/* Backoff counter */
+
+	/* NOTE: Some versions of the manual have the following items
+	 * incorrectly documented.  Below is the proper order.
+	 */
+	ushort	sen_taddrh;	/* temp address (MSB) */
+	ushort	sen_taddrm;
+	ushort	sen_taddrl;	/* temp address (LSB) */
+} scc_enet_t;
+
+/*********************************************************************/
+
+/* SCC Event register as used by Ethernet.
+*/
+#define SCCE_ENET_GRA	((ushort)0x0080)	/* Graceful stop complete */
+#define SCCE_ENET_TXE	((ushort)0x0010)	/* Transmit Error */
+#define SCCE_ENET_RXF	((ushort)0x0008)	/* Full frame received */
+#define SCCE_ENET_BSY	((ushort)0x0004)	/* All incoming buffers full */
+#define SCCE_ENET_TXB	((ushort)0x0002)	/* A buffer was transmitted */
+#define SCCE_ENET_RXB	((ushort)0x0001)	/* A buffer was received */
+
+/* SCC Mode Register (PSMR) as used by Ethernet.
+*/
+#define SCC_PSMR_HBC	((ushort)0x8000)	/* Enable heartbeat */
+#define SCC_PSMR_FC	((ushort)0x4000)	/* Force collision */
+#define SCC_PSMR_RSH	((ushort)0x2000)	/* Receive short frames */
+#define SCC_PSMR_IAM	((ushort)0x1000)	/* Check individual hash */
+#define SCC_PSMR_ENCRC	((ushort)0x0800)	/* Ethernet CRC mode */
+#define SCC_PSMR_PRO	((ushort)0x0200)	/* Promiscuous mode */
+#define SCC_PSMR_BRO	((ushort)0x0100)	/* Catch broadcast pkts */
+#define SCC_PSMR_SBT	((ushort)0x0080)	/* Special backoff timer */
+#define SCC_PSMR_LPB	((ushort)0x0040)	/* Set Loopback mode */
+#define SCC_PSMR_SIP	((ushort)0x0020)	/* Sample Input Pins */
+#define SCC_PSMR_LCW	((ushort)0x0010)	/* Late collision window */
+#define SCC_PSMR_NIB22	((ushort)0x000a)	/* Start frame search */
+#define SCC_PSMR_FDE	((ushort)0x0001)	/* Full duplex enable */
+
+/* Buffer descriptor control/status used by Ethernet receive.
+*/
+#define BD_ENET_RX_EMPTY	((ushort)0x8000)
+#define BD_ENET_RX_WRAP		((ushort)0x2000)
+#define BD_ENET_RX_INTR		((ushort)0x1000)
+#define BD_ENET_RX_LAST		((ushort)0x0800)
+#define BD_ENET_RX_FIRST	((ushort)0x0400)
+#define BD_ENET_RX_MISS		((ushort)0x0100)
+#define BD_ENET_RX_LG		((ushort)0x0020)
+#define BD_ENET_RX_NO		((ushort)0x0010)
+#define BD_ENET_RX_SH		((ushort)0x0008)
+#define BD_ENET_RX_CR		((ushort)0x0004)
+#define BD_ENET_RX_OV		((ushort)0x0002)
+#define BD_ENET_RX_CL		((ushort)0x0001)
+#define BD_ENET_RX_STATS	((ushort)0x013f)	/* All status bits */
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+*/
+#define BD_ENET_TX_READY	((ushort)0x8000)
+#define BD_ENET_TX_PAD		((ushort)0x4000)
+#define BD_ENET_TX_WRAP		((ushort)0x2000)
+#define BD_ENET_TX_INTR		((ushort)0x1000)
+#define BD_ENET_TX_LAST		((ushort)0x0800)
+#define BD_ENET_TX_TC		((ushort)0x0400)
+#define BD_ENET_TX_DEF		((ushort)0x0200)
+#define BD_ENET_TX_HB		((ushort)0x0100)
+#define BD_ENET_TX_LC		((ushort)0x0080)
+#define BD_ENET_TX_RL		((ushort)0x0040)
+#define BD_ENET_TX_RCMASK	((ushort)0x003c)
+#define BD_ENET_TX_UN		((ushort)0x0002)
+#define BD_ENET_TX_CSL		((ushort)0x0001)
+#define BD_ENET_TX_STATS	((ushort)0x03ff)	/* All status bits */
+
+/* SCC as UART
+*/
+typedef struct scc_uart {
+	sccp_t	scc_genscc;
+	uint	scc_res1;	/* Reserved */
+	uint	scc_res2;	/* Reserved */
+	ushort	scc_maxidl;	/* Maximum idle chars */
+	ushort	scc_idlc;	/* temp idle counter */
+	ushort	scc_brkcr;	/* Break count register */
+	ushort	scc_parec;	/* receive parity error counter */
+	ushort	scc_frmec;	/* receive framing error counter */
+	ushort	scc_nosec;	/* receive noise counter */
+	ushort	scc_brkec;	/* receive break condition counter */
+	ushort	scc_brkln;	/* last received break length */
+	ushort	scc_uaddr1;	/* UART address character 1 */
+	ushort	scc_uaddr2;	/* UART address character 2 */
+	ushort	scc_rtemp;	/* Temp storage */
+	ushort	scc_toseq;	/* Transmit out of sequence char */
+	ushort	scc_char1;	/* control character 1 */
+	ushort	scc_char2;	/* control character 2 */
+	ushort	scc_char3;	/* control character 3 */
+	ushort	scc_char4;	/* control character 4 */
+	ushort	scc_char5;	/* control character 5 */
+	ushort	scc_char6;	/* control character 6 */
+	ushort	scc_char7;	/* control character 7 */
+	ushort	scc_char8;	/* control character 8 */
+	ushort	scc_rccm;	/* receive control character mask */
+	ushort	scc_rccr;	/* receive control character register */
+	ushort	scc_rlbc;	/* receive last break character */
+} scc_uart_t;
+
+/* SCC Event and Mask registers when it is used as a UART.
+*/
+#define UART_SCCM_GLR		((ushort)0x1000)
+#define UART_SCCM_GLT		((ushort)0x0800)
+#define UART_SCCM_AB		((ushort)0x0200)
+#define UART_SCCM_IDL		((ushort)0x0100)
+#define UART_SCCM_GRA		((ushort)0x0080)
+#define UART_SCCM_BRKE		((ushort)0x0040)
+#define UART_SCCM_BRKS		((ushort)0x0020)
+#define UART_SCCM_CCR		((ushort)0x0008)
+#define UART_SCCM_BSY		((ushort)0x0004)
+#define UART_SCCM_TX		((ushort)0x0002)
+#define UART_SCCM_RX		((ushort)0x0001)
+
+/* The SCC PSMR when used as a UART.
+*/
+#define SCU_PSMR_FLC		((ushort)0x8000)
+#define SCU_PSMR_SL		((ushort)0x4000)
+#define SCU_PSMR_CL		((ushort)0x3000)
+#define SCU_PSMR_UM		((ushort)0x0c00)
+#define SCU_PSMR_FRZ		((ushort)0x0200)
+#define SCU_PSMR_RZS		((ushort)0x0100)
+#define SCU_PSMR_SYN		((ushort)0x0080)
+#define SCU_PSMR_DRT		((ushort)0x0040)
+#define SCU_PSMR_PEN		((ushort)0x0010)
+#define SCU_PSMR_RPM		((ushort)0x000c)
+#define SCU_PSMR_REVP		((ushort)0x0008)
+#define SCU_PSMR_TPM		((ushort)0x0003)
+#define SCU_PSMR_TEVP		((ushort)0x0003)
+
+/* CPM Transparent mode SCC.
+ */
+typedef struct scc_trans {
+	sccp_t	st_genscc;
+	uint	st_cpres;	/* Preset CRC */
+	uint	st_cmask;	/* Constant mask for CRC */
+} scc_trans_t;
+
+#define BD_SCC_TX_LAST		((ushort)0x0800)
+
+/* IIC parameter RAM.
+*/
+typedef struct iic {
+	ushort	iic_rbase;	/* Rx Buffer descriptor base address */
+	ushort	iic_tbase;	/* Tx Buffer descriptor base address */
+	u_char	iic_rfcr;	/* Rx function code */
+	u_char	iic_tfcr;	/* Tx function code */
+	ushort	iic_mrblr;	/* Max receive buffer length */
+	uint	iic_rstate;	/* Internal */
+	uint	iic_rdp;	/* Internal */
+	ushort	iic_rbptr;	/* Internal */
+	ushort	iic_rbc;	/* Internal */
+	uint	iic_rxtmp;	/* Internal */
+	uint	iic_tstate;	/* Internal */
+	uint	iic_tdp;	/* Internal */
+	ushort	iic_tbptr;	/* Internal */
+	ushort	iic_tbc;	/* Internal */
+	uint	iic_txtmp;	/* Internal */
+	uint	iic_res;	/* reserved */
+	ushort	iic_rpbase;	/* Relocation pointer */
+	ushort	iic_res2;	/* reserved */
+} iic_t;
+
+/* SPI parameter RAM.
+*/
+typedef struct spi {
+	ushort	spi_rbase;	/* Rx Buffer descriptor base address */
+	ushort	spi_tbase;	/* Tx Buffer descriptor base address */
+	u_char	spi_rfcr;	/* Rx function code */
+	u_char	spi_tfcr;	/* Tx function code */
+	ushort	spi_mrblr;	/* Max receive buffer length */
+	uint	spi_rstate;	/* Internal */
+	uint	spi_rdp;	/* Internal */
+	ushort	spi_rbptr;	/* Internal */
+	ushort	spi_rbc;	/* Internal */
+	uint	spi_rxtmp;	/* Internal */
+	uint	spi_tstate;	/* Internal */
+	uint	spi_tdp;	/* Internal */
+	ushort	spi_tbptr;	/* Internal */
+	ushort	spi_tbc;	/* Internal */
+	uint	spi_txtmp;	/* Internal */
+	uint	spi_res;
+	ushort	spi_rpbase;	/* Relocation pointer */
+	ushort	spi_res2;
+} spi_t;
+
+/* SPI Mode register.
+*/
+#define SPMODE_LOOP	((ushort)0x4000)	/* Loopback */
+#define SPMODE_CI	((ushort)0x2000)	/* Clock Invert */
+#define SPMODE_CP	((ushort)0x1000)	/* Clock Phase */
+#define SPMODE_DIV16	((ushort)0x0800)	/* BRG/16 mode */
+#define SPMODE_REV	((ushort)0x0400)	/* Reversed Data */
+#define SPMODE_MSTR	((ushort)0x0200)	/* SPI Master */
+#define SPMODE_EN	((ushort)0x0100)	/* Enable */
+#define SPMODE_LENMSK	((ushort)0x00f0)	/* character length */
+#define SPMODE_PMMSK	((ushort)0x000f)	/* prescale modulus */
+
+#define SPMODE_LEN(x)	((((x)-1)&0xF)<<4)
+#define SPMODE_PM(x)	((x) &0xF)
+
+/* HDLC parameter RAM.
+*/
+
+typedef struct hdlc_pram_s {
+	/*
+	 * SCC parameter RAM
+	 */
+	ushort	rbase;		/* Rx Buffer descriptor base address */
+	ushort	tbase;		/* Tx Buffer descriptor base address */
+	uchar	rfcr;		/* Rx function code */
+	uchar	tfcr;		/* Tx function code */
+	ushort	mrblr;		/* Rx buffer length */
+	ulong	rstate;		/* Rx internal state */
+	ulong	rptr;		/* Rx internal data pointer */
+	ushort	rbptr;		/* rb BD Pointer */
+	ushort	rcount;		/* Rx internal byte count */
+	ulong	rtemp;		/* Rx temp */
+	ulong	tstate;		/* Tx internal state */
+	ulong	tptr;		/* Tx internal data pointer */
+	ushort	tbptr;		/* Tx BD pointer */
+	ushort	tcount;		/* Tx byte count */
+	ulong	ttemp;		/* Tx temp */
+	ulong	rcrc;		/* temp receive CRC */
+	ulong	tcrc;		/* temp transmit CRC */
+	/*
+	 * HDLC specific parameter RAM
+	 */
+	uchar	res[4];		/* reserved */
+	ulong	c_mask;		/* CRC constant */
+	ulong	c_pres;		/* CRC preset */
+	ushort	disfc;		/* discarded frame counter */
+	ushort	crcec;		/* CRC error counter */
+	ushort	abtsc;		/* abort sequence counter */
+	ushort	nmarc;		/* nonmatching address rx cnt */
+	ushort	retrc;		/* frame retransmission cnt */
+	ushort	mflr;		/* maximum frame length reg */
+	ushort	max_cnt;	/* maximum length counter */
+	ushort	rfthr;		/* received frames threshold */
+	ushort	rfcnt;		/* received frames count */
+	ushort	hmask;		/* user defined frm addr mask */
+	ushort	haddr1;		/* user defined frm address 1 */
+	ushort	haddr2;		/* user defined frm address 2 */
+	ushort	haddr3;		/* user defined frm address 3 */
+	ushort	haddr4;		/* user defined frm address 4 */
+	ushort	tmp;		/* temp */
+	ushort	tmp_mb;		/* temp */
+} hdlc_pram_t;
+
+/* CPM interrupts.  There are nearly 32 interrupts generated by CPM
+ * channels or devices.  All of these are presented to the PPC core
+ * as a single interrupt.  The CPM interrupt handler dispatches its
+ * own handlers, in a similar fashion to the PPC core handler.  We
+ * use the table as defined in the manuals (i.e. no special high
+ * priority and SCC1 == SCCa, etc...).
+ */
+#define CPMVEC_NR		32
+#define CPMVEC_OFFSET           0x00010000
+#define CPMVEC_PIO_PC15		((ushort)0x1f | CPMVEC_OFFSET)
+#define CPMVEC_SCC1		((ushort)0x1e | CPMVEC_OFFSET)
+#define CPMVEC_SCC2		((ushort)0x1d | CPMVEC_OFFSET)
+#define CPMVEC_SCC3		((ushort)0x1c | CPMVEC_OFFSET)
+#define CPMVEC_SCC4		((ushort)0x1b | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC14		((ushort)0x1a | CPMVEC_OFFSET)
+#define CPMVEC_TIMER1		((ushort)0x19 | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC13		((ushort)0x18 | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC12		((ushort)0x17 | CPMVEC_OFFSET)
+#define CPMVEC_SDMA_CB_ERR	((ushort)0x16 | CPMVEC_OFFSET)
+#define CPMVEC_IDMA1		((ushort)0x15 | CPMVEC_OFFSET)
+#define CPMVEC_IDMA2		((ushort)0x14 | CPMVEC_OFFSET)
+#define CPMVEC_TIMER2		((ushort)0x12 | CPMVEC_OFFSET)
+#define CPMVEC_RISCTIMER	((ushort)0x11 | CPMVEC_OFFSET)
+#define CPMVEC_I2C		((ushort)0x10 | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC11		((ushort)0x0f | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC10		((ushort)0x0e | CPMVEC_OFFSET)
+#define CPMVEC_TIMER3		((ushort)0x0c | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC9		((ushort)0x0b | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC8		((ushort)0x0a | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC7		((ushort)0x09 | CPMVEC_OFFSET)
+#define CPMVEC_TIMER4		((ushort)0x07 | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC6		((ushort)0x06 | CPMVEC_OFFSET)
+#define CPMVEC_SPI		((ushort)0x05 | CPMVEC_OFFSET)
+#define CPMVEC_SMC1		((ushort)0x04 | CPMVEC_OFFSET)
+#define CPMVEC_SMC2		((ushort)0x03 | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC5		((ushort)0x02 | CPMVEC_OFFSET)
+#define CPMVEC_PIO_PC4		((ushort)0x01 | CPMVEC_OFFSET)
+#define CPMVEC_ERROR		((ushort)0x00 | CPMVEC_OFFSET)
+
+extern void irq_install_handler(int vec, void (*handler)(void *), void *dev_id);
+
+/* CPM interrupt configuration vector.
+*/
+#define	CICR_SCD_SCC4		((uint)0x00c00000)	/* SCC4 @ SCCd */
+#define	CICR_SCC_SCC3		((uint)0x00200000)	/* SCC3 @ SCCc */
+#define	CICR_SCB_SCC2		((uint)0x00040000)	/* SCC2 @ SCCb */
+#define	CICR_SCA_SCC1		((uint)0x00000000)	/* SCC1 @ SCCa */
+#define CICR_IRL_MASK		((uint)0x0000e000)	/* Core interrrupt */
+#define CICR_HP_MASK		((uint)0x00001f00)	/* Hi-pri int. */
+#define CICR_IEN		((uint)0x00000080)	/* Int. enable */
+#define CICR_SPS		((uint)0x00000001)	/* SCC Spread */
+#endif /* __CPM_8XX__ */
diff --git a/include/mpc8xx.h b/include/mpc8xx.h
index 33a2cd8057..fc081ab756 100644
--- a/include/mpc8xx.h
+++ b/include/mpc8xx.h
@@ -145,20 +145,6 @@
 			  PLPRCR_MFI_MSK | \
 			  PLPRCR_PDF_MSK)
 
-/* Older chips (MPC860/862 et al) defines */
-#define PLPRCR_MF_MSK	0xFFF00000	/* Multiplication factor bits		*/
-#define PLPRCR_MF_SHIFT		20	/* Multiplication factor shift value	*/
-
-#define PLPRCR_SPLSS	0x00008000	/* SPLL Lock Status Sticky bit		*/
-#define PLPRCR_TMIST	0x00001000	/* Timers Interrupt Status		*/
-
-#define PLPRCR_LPM_MSK	0x00000300	/* Low Power Mode mask			*/
-#define PLPRCR_LPM_NORMAL 0x00000000	/* normal power management mode		*/
-#define PLPRCR_LPM_DOZE	  0x00000100	/* doze power management mode		*/
-#define PLPRCR_LPM_SLEEP  0x00000200	/* sleep power management mode		*/
-#define PLPRCR_LPM_DEEP_SLEEP 0x00000300 /* deep sleep power mgt mode		*/
-#define PLPRCR_LPM_DOWN	  0x00000300	/* down power management mode		*/
-
 /* Common defines */
 #define PLPRCR_TEXPS	0x00004000	/* TEXP Status				*/
 #define PLPRCR_CSRC	0x00000400	/* Clock Source				*/
diff --git a/include/ppc_asm.tmpl b/include/ppc_asm.tmpl
index ce71ee9bc9..18783340d9 100644
--- a/include/ppc_asm.tmpl
+++ b/include/ppc_asm.tmpl
@@ -81,6 +81,52 @@
 #define	r30	30
 #define	r31	31
 
+#if defined(CONFIG_8xx)
+
+/* Some special registers */
+
+#define ICR	148	/* Interrupt Cause Register (37-44) */
+#define DER	149
+#define COUNTA	150	/* Breakpoint Counter	    (37-44) */
+#define COUNTB	151	/* Breakpoint Counter	    (37-44) */
+#define LCTRL1	156	/* Load/Store Support	    (37-40) */
+#define LCTRL2	157	/* Load/Store Support	    (37-41) */
+#define ICTRL	158
+
+#endif	/* CONFIG_8xx */
+
+
+#if defined(CONFIG_8xx)
+
+/* Registers in the processor's internal memory map that we use.
+*/
+#define SYPCR	0x00000004
+#define BR0	0x00000100
+#define OR0	0x00000104
+#define BR1	0x00000108
+#define OR1	0x0000010c
+#define BR2	0x00000110
+#define OR2	0x00000114
+#define BR3	0x00000118
+#define OR3	0x0000011c
+#define BR4	0x00000120
+#define OR4	0x00000124
+
+#define MAR	0x00000164
+#define MCR	0x00000168
+#define MAMR	0x00000170
+#define MBMR	0x00000174
+#define MSTAT	0x00000178
+#define MPTPR	0x0000017a
+#define MDR	0x0000017c
+
+#define TBSCR	0x00000200
+#define TBREFF0	0x00000204
+
+#define PLPRCR	0x00000284
+
+#endif
+
 #define curptr r2
 
 #define SYNC \
diff --git a/include/watchdog.h b/include/watchdog.h
index 52f4c506b0..a3a2eeaf1b 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -72,6 +72,11 @@ int init_func_watchdog_reset(void);
  * Prototypes from $(CPU)/cpu.c.
  */
 
+/* MPC 8xx */
+#if defined(CONFIG_8xx) && !defined(__ASSEMBLY__)
+	void reset_8xx_watchdog(volatile immap_t *immr);
+#endif
+
 #if defined(CONFIG_HW_WATCHDOG) && !defined(__ASSEMBLY__)
 	void hw_watchdog_init(void);
 #endif
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index 684520f365..8259c17171 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -12,6 +12,12 @@ CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES
 CONFIG_83XX_PCICLK
 CONFIG_83XX_PCI_STREAMING
 CONFIG_88F5182
+CONFIG_8xx_CONS_NONE
+CONFIG_8xx_CONS_SCCx
+CONFIG_8xx_CONS_SMC1
+CONFIG_8xx_CONS_SMC2
+CONFIG_8xx_CONS_SMCx
+CONFIG_8xx_GCLK_FREQ
 CONFIG_A003399_NOR_WORKAROUND
 CONFIG_A008044_WORKAROUND
 CONFIG_ACADIA
@@ -734,6 +740,8 @@ CONFIG_ETHER_ON_FCC
 CONFIG_ETHER_ON_FCC1
 CONFIG_ETHER_ON_FCC2
 CONFIG_ETHER_ON_FCC3
+CONFIG_ETHER_ON_FEC1
+CONFIG_ETHER_ON_FEC2
 CONFIG_ETHPRIME
 CONFIG_ETH_BUFSIZE
 CONFIG_ETH_RXSIZE
@@ -790,6 +798,8 @@ CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
 CONFIG_FEATURE_SH_EXTRA_QUIET
 CONFIG_FEATURE_SH_FANCY_PROMPT
 CONFIG_FEATURE_SH_STANDALONE_SHELL
+CONFIG_FEC1_PHY
+CONFIG_FEC2_PHY
 CONFIG_FEC_ENET
 CONFIG_FEC_ENET_DEV
 CONFIG_FEC_FIXED_SPEED
@@ -1591,11 +1601,10 @@ CONFIG_MPC83XX_PCI2
 CONFIG_MPC85XX_FEC
 CONFIG_MPC85XX_FEC_NAME
 CONFIG_MPC85XX_PCI2
-CONFIG_MPC860
-CONFIG_MPC860T
 CONFIG_MPC866
 CONFIG_MPC866_FAMILY
 CONFIG_MPC885
+CONFIG_MPC885_FAMILY
 CONFIG_MPC8XXX_SPI
 CONFIG_MPC8xxx_DISABLE_BPTR
 CONFIG_MPLL_FREQ
@@ -2660,6 +2669,7 @@ CONFIG_SYS_BR6_64M
 CONFIG_SYS_BR6_8M
 CONFIG_SYS_BR6_PRELIM
 CONFIG_SYS_BR7_PRELIM
+CONFIG_SYS_BRGCLK_PRESCALE
 CONFIG_SYS_BUSCLK
 CONFIG_SYS_CACHELINE_SHIFT
 CONFIG_SYS_CACHE_ACR0
@@ -3073,6 +3083,7 @@ CONFIG_SYS_DEBUG_SERVER_FW_IN_NOR
 CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS
 CONFIG_SYS_DEFAULT_VIDEO_MODE
 CONFIG_SYS_DEF_EEPROM_ADDR
+CONFIG_SYS_DER
 CONFIG_SYS_DEVICE_NULLDEV
 CONFIG_SYS_DFU_DATA_BUF_SIZE
 CONFIG_SYS_DFU_MAX_FILE_SIZE
@@ -4898,6 +4909,7 @@ CONFIG_SYS_PIOC_PPUDR_VAL
 CONFIG_SYS_PIOD_PDR_VAL1
 CONFIG_SYS_PIOD_PPUDR_VAL
 CONFIG_SYS_PIO_MODE
+CONFIG_SYS_PISCR
 CONFIG_SYS_PIT_BASE
 CONFIG_SYS_PIT_PRESCALE
 CONFIG_SYS_PIXIS_VBOOT_ENABLE
@@ -4919,6 +4931,7 @@ CONFIG_SYS_PLL_BYPASS
 CONFIG_SYS_PLL_FDR
 CONFIG_SYS_PLL_ODR
 CONFIG_SYS_PLL_SETTLING_TIME
+CONFIG_SYS_PLPRCR
 CONFIG_SYS_PLUG_BASE
 CONFIG_SYS_PMAN
 CONFIG_SYS_PMC_BASE
@@ -5086,6 +5099,7 @@ CONFIG_SYS_SDIO_BASE0
 CONFIG_SYS_SDIO_BASE1
 CONFIG_SYS_SDIO_BASE2
 CONFIG_SYS_SDIO_BASE3
+CONFIG_SYS_SDMR
 CONFIG_SYS_SDRAM
 CONFIG_SYS_SDRAM1
 CONFIG_SYS_SDRAM_BANKS
@@ -5134,6 +5148,7 @@ CONFIG_SYS_SDRC_MR_VAL5
 CONFIG_SYS_SDRC_TR_VAL
 CONFIG_SYS_SDRC_TR_VAL1
 CONFIG_SYS_SDRC_TR_VAL2
+CONFIG_SYS_SDSR
 CONFIG_SYS_SD_VOLTAGE
 CONFIG_SYS_SEC_MON_ADDR
 CONFIG_SYS_SEC_MON_OFFSET
@@ -5161,6 +5176,7 @@ CONFIG_SYS_SH_SDHI_NR_CHANNEL
 CONFIG_SYS_SICRH
 CONFIG_SYS_SICRL
 CONFIG_SYS_SIL1178_I2C
+CONFIG_SYS_SIUMCR
 CONFIG_SYS_SJA1000_BASE
 CONFIG_SYS_SMALL_FLASH
 CONFIG_SYS_SMC0_CYCLE0_VAL
@@ -5168,6 +5184,7 @@ CONFIG_SYS_SMC0_MODE0_VAL
 CONFIG_SYS_SMC0_PULSE0_VAL
 CONFIG_SYS_SMC0_SETUP0_VAL
 CONFIG_SYS_SMC_CSR0_VAL
+CONFIG_SYS_SMC_RXBUFLEN
 CONFIG_SYS_SMI_BASE
 CONFIG_SYS_SPANSION_BASE
 CONFIG_SYS_SPANSION_BOOT
@@ -5237,9 +5254,11 @@ CONFIG_SYS_STATUS_OK
 CONFIG_SYS_STMICRO_BOOT
 CONFIG_SYS_SUPPORT_64BIT_DATA
 CONFIG_SYS_SXCNFG_VAL
+CONFIG_SYS_SYPCR
 CONFIG_SYS_SYSTEMACE_BASE
 CONFIG_SYS_SYSTEMACE_WIDTH
 CONFIG_SYS_TBIPA_VALUE
+CONFIG_SYS_TBSCR
 CONFIG_SYS_TCLK
 CONFIG_SYS_TEXT_ADDR
 CONFIG_SYS_TEXT_BASE_NOR
@@ -5469,17 +5488,7 @@ CONFIG_TPL_DRIVERS_MISC_SUPPORT
 CONFIG_TPL_PAD_TO
 CONFIG_TPM_TIS_BASE_ADDRESS
 CONFIG_TPS6586X_POWER
-CONFIG_TQM823L
-CONFIG_TQM823M
 CONFIG_TQM834X
-CONFIG_TQM850L
-CONFIG_TQM850M
-CONFIG_TQM855L
-CONFIG_TQM855M
-CONFIG_TQM860L
-CONFIG_TQM860M
-CONFIG_TQM862L
-CONFIG_TQM862M
 CONFIG_TRACE
 CONFIG_TRACE_BUFFER_SIZE
 CONFIG_TRACE_EARLY
-- 
2.12.0




More information about the U-Boot mailing list