Initial revision
diff --git a/board/RRvision/flash.c b/board/RRvision/flash.c
new file mode 100644
index 0000000..06f7c4b
--- /dev/null
+++ b/board/RRvision/flash.c
@@ -0,0 +1,522 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#define DEBUG
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#ifndef	CFG_ENV_ADDR
+#define CFG_ENV_ADDR	(CFG_FLASH_BASE + CFG_ENV_OFFSET)
+#endif
+
+flash_info_t	flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips	*/
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+	volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	unsigned long size;
+	int i;
+
+	/* Init: no FLASHes known */
+	for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+		flash_info[i].flash_id = FLASH_UNKNOWN;
+	}
+
+	/* Static FLASH Bank configuration here - FIXME XXX */
+
+	size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+	if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+		printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+			size, size<<20);
+	}
+
+	/* Remap FLASH according to real size */
+	memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & OR_AM_MSK);
+	memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+	/* Re-do sizing to get full correct info */
+	size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+	/* monitor protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_MONITOR_BASE,
+		      CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+		      &flash_info[0]);
+#endif
+
+#ifdef	CFG_ENV_IS_IN_FLASH
+	/* ENV protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_ENV_ADDR,
+		      CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+		      &flash_info[0]);
+#endif
+
+	flash_info[0].size = size;
+
+	return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		puts ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_AMD:	puts ("AMD ");			break;
+	case FLASH_MAN_FUJ:	puts ("FUJITSU ");		break;
+	default:		puts ("Unknown Vendor ");	break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_AM400B:	puts ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM400T:	puts ("AM29LV400T (4 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM800B:	puts ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM800T:	puts ("AM29LV800T (8 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM160B:	puts ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM160T:	puts ("AM29LV160T (16 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM320B:	puts ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM320T:	puts ("AM29LV320T (32 Mbit, top boot sector)\n");
+				break;
+	default:		puts ("Unknown Chip Type\n");
+				break;
+	}
+
+	printf ("  Size: %ld MB in %d Sectors\n",
+		info->size >> 20, info->sector_count);
+
+	puts ("  Sector Start Addresses:");
+	for (i=0; i<info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			puts ("\n   ");
+		printf (" %08lX%s",
+			info->start[i],
+			info->protect[i] ? " (RO)" : "     "
+		);
+	}
+	puts ("\n");
+	return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+	short i;
+	ulong value;
+	ulong base = (ulong)addr;
+
+	/* Write auto select command: read Manufacturer ID */
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+	addr[0x0555] = 0x00900090;
+
+	value = addr[0];
+
+	switch (value) {
+	case AMD_MANUFACT:
+		info->flash_id = FLASH_MAN_AMD;
+		break;
+	case FUJ_MANUFACT:
+		info->flash_id = FLASH_MAN_FUJ;
+		break;
+	default:
+		info->flash_id = FLASH_UNKNOWN;
+		info->sector_count = 0;
+		info->size = 0;
+		return (0);			/* no or unknown flash	*/
+	}
+
+	value = addr[1];			/* device ID		*/
+
+	switch (value) {
+	case AMD_ID_LV400T:
+		info->flash_id += FLASH_AM400T;
+		info->sector_count = 11;
+		info->size = 0x00100000;
+		break;				/* => 1 MB		*/
+
+	case AMD_ID_LV400B:
+		info->flash_id += FLASH_AM400B;
+		info->sector_count = 11;
+		info->size = 0x00100000;
+		break;				/* => 1 MB		*/
+
+	case AMD_ID_LV800T:
+		info->flash_id += FLASH_AM800T;
+		info->sector_count = 19;
+		info->size = 0x00200000;
+		break;				/* => 2 MB		*/
+
+	case AMD_ID_LV800B:
+		info->flash_id += FLASH_AM800B;
+		info->sector_count = 19;
+		info->size = 0x00200000;
+		break;				/* => 2 MB		*/
+
+	case AMD_ID_LV160T:
+		info->flash_id += FLASH_AM160T;
+		info->sector_count = 35;
+		info->size = 0x00400000;
+		break;				/* => 4 MB		*/
+
+	case AMD_ID_LV160B:
+		info->flash_id += FLASH_AM160B;
+		info->sector_count = 35;
+		info->size = 0x00400000;
+		break;				/* => 4 MB		*/
+	case AMD_ID_LV320T:
+		info->flash_id += FLASH_AM320T;
+		info->sector_count = 71;
+		info->size = 0x00800000;
+		break;				/* => 8 MB		*/
+
+	case AMD_ID_LV320B:
+		info->flash_id += FLASH_AM320B;
+		info->sector_count = 71;
+		info->size = 0x00800000;
+		break;				/* => 8 MB		*/
+	default:
+		info->flash_id = FLASH_UNKNOWN;
+		return (0);			/* => no or unknown flash */
+	}
+
+	/* set up sector start address table */
+	switch (value) {
+	case AMD_ID_LV400B:
+	case AMD_ID_LV800B:
+	case AMD_ID_LV160B:
+		/* set sector offsets for bottom boot block type	*/
+		info->start[0] = base + 0x00000000;
+		info->start[1] = base + 0x00008000;
+		info->start[2] = base + 0x0000C000;
+		info->start[3] = base + 0x00010000;
+		for (i = 4; i < info->sector_count; i++) {
+			info->start[i] = base + (i * 0x00020000) - 0x00060000;
+		}
+		break;
+	case AMD_ID_LV400T:
+	case AMD_ID_LV800T:
+	case AMD_ID_LV160T:
+		/* set sector offsets for top boot block type		*/
+		i = info->sector_count - 1;
+		info->start[i--] = base + info->size - 0x00008000;
+		info->start[i--] = base + info->size - 0x0000C000;
+		info->start[i--] = base + info->size - 0x00010000;
+		for (; i >= 0; i--) {
+			info->start[i] = base + i * 0x00020000;
+		}
+		break;
+	case AMD_ID_LV320B:
+		for (i = 0; i < info->sector_count; i++) {
+			info->start[i] = base;
+			/*
+			 * The first 8 sectors are 8 kB,
+			 * all the other ones  are 64 kB
+			 */
+			base += (i < 8)
+				?  2 * ( 8 << 10)
+				:  2 * (64 << 10);
+		}
+		break;
+	case AMD_ID_LV320T:
+		for (i = 0; i < info->sector_count; i++) {
+			info->start[i] = base;
+			/*
+			 * The last 8 sectors are 8 kB,
+			 * all the other ones  are 64 kB
+			 */
+			base += (i < (info->sector_count - 8))
+				?  2 * (64 << 10)
+				:  2 * ( 8 << 10);
+		}
+		break;
+	default:
+		return (0);
+		break;
+	}
+
+	/* check for protected sectors */
+	for (i = 0; i < info->sector_count; i++) {
+		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
+		/* D0 = 1 if protected */
+		addr = (volatile unsigned long *)(info->start[i]);
+		info->protect[i] = addr[2] & 1;
+	}
+
+	/*
+	 * Prevent writes to uninitialized FLASH.
+	 */
+	if (info->flash_id != FLASH_UNKNOWN) {
+		addr = (volatile unsigned long *)info->start[0];
+
+		*addr = 0x00F000F0;	/* reset bank */
+	}
+
+	return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int	flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+	vu_long *addr = (vu_long*)(info->start[0]);
+	int flag, prot, sect, l_sect;
+	ulong start, now, last;
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		if (info->flash_id == FLASH_UNKNOWN) {
+			puts ("- missing\n");
+		} else {
+			puts ("- no sectors to erase\n");
+		}
+		return 1;
+	}
+
+	if ((info->flash_id == FLASH_UNKNOWN) ||
+	    (info->flash_id > FLASH_AMD_COMP)) {
+		printf ("Can't erase unknown flash type %08lx - aborted\n",
+			info->flash_id);
+		return 1;
+	}
+
+	prot = 0;
+	for (sect=s_first; sect<=s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
+		}
+	}
+
+	if (prot) {
+		printf ("- Warning: %d protected sectors will not be erased!\n",
+			prot);
+	} else {
+		puts ("\n");
+	}
+
+	l_sect = -1;
+
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+	addr[0x0555] = 0x00800080;
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect<=s_last; sect++) {
+		if (info->protect[sect] == 0) {	/* not protected */
+			addr = (vu_long*)(info->start[sect]);
+			addr[0] = 0x00300030;
+			l_sect = sect;
+		}
+	}
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts();
+
+	/* wait at least 80us - let's wait 1 ms */
+	udelay (1000);
+
+	/*
+	 * We wait for the last triggered sector
+	 */
+	if (l_sect < 0)
+		goto DONE;
+
+	start = get_timer (0);
+	last  = start;
+	addr = (vu_long*)(info->start[l_sect]);
+	while ((addr[0] & 0x00800080) != 0x00800080) {
+		if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+			puts ("Timeout\n");
+			return 1;
+		}
+		/* show that we're waiting */
+		if ((now - last) > 1000) {	/* every second */
+			putc ('.');
+			last = now;
+		}
+	}
+
+DONE:
+	/* reset to read mode */
+	addr = (volatile unsigned long *)info->start[0];
+	addr[0] = 0x00F000F0;	/* reset bank */
+
+	puts (" done\n");
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+	ulong cp, wp, data;
+	int i, l, rc;
+
+	wp = (addr & ~3);	/* get lower word aligned address */
+
+	/*
+	 * handle unaligned start bytes
+	 */
+	if ((l = addr - wp) != 0) {
+		data = 0;
+		for (i=0, cp=wp; i<l; ++i, ++cp) {
+			data = (data << 8) | (*(uchar *)cp);
+		}
+		for (; i<4 && cnt>0; ++i) {
+			data = (data << 8) | *src++;
+			--cnt;
+			++cp;
+		}
+		for (; cnt==0 && i<4; ++i, ++cp) {
+			data = (data << 8) | (*(uchar *)cp);
+		}
+
+		if ((rc = write_word(info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp += 4;
+	}
+
+	/*
+	 * handle word aligned part
+	 */
+	while (cnt >= 4) {
+		data = 0;
+		for (i=0; i<4; ++i) {
+			data = (data << 8) | *src++;
+		}
+		if ((rc = write_word(info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp  += 4;
+		cnt -= 4;
+	}
+
+	if (cnt == 0) {
+		return (0);
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	data = 0;
+	for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+		data = (data << 8) | *src++;
+		--cnt;
+	}
+	for (; i<4; ++i, ++cp) {
+		data = (data << 8) | (*(uchar *)cp);
+	}
+
+	return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+	vu_long *addr = (vu_long*)(info->start[0]);
+	ulong start;
+	int flag;
+
+	/* Check if Flash is (sufficiently) erased */
+	if ((*((vu_long *)dest) & data) != data) {
+		return (2);
+	}
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	addr[0x0555] = 0x00AA00AA;
+	addr[0x02AA] = 0x00550055;
+	addr[0x0555] = 0x00A000A0;
+
+	*((vu_long *)dest) = data;
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts();
+
+	/* data polling for D7 */
+	start = get_timer (0);
+	while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+			return (1);
+		}
+	}
+	return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/bmw/Makefile b/board/bmw/Makefile
new file mode 100644
index 0000000..46fe791
--- /dev/null
+++ b/board/bmw/Makefile
@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2002
+# James F. Dougherty, Broadcom Corporation, jfd@broadcom.com
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= lib$(BOARD).a
+
+OBJS	= $(BOARD).o flash.o ns16550.o serial.o m48t59y.o
+
+SOBJS	= early_init.o
+
+$(LIB):	.depend $(OBJS) $(SOBJS)
+	$(AR) crv $@ $^
+
+#########################################################################
+
+.depend:	Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/board/bmw/README b/board/bmw/README
new file mode 100644
index 0000000..55ef56e
--- /dev/null
+++ b/board/bmw/README
@@ -0,0 +1,340 @@
+Broadcom 95xx BMW CPCI Platform
+
+Overview
+=========
+BMW is an MPC8245 system controller featuring:
+* 3U CPCI Form Factor
+* BCM5703 Gigabit Ethernet
+* M48T59Y NVRAM
+* 16MB DOC
+* DIP Socket for Socketed DOC up to 1GB
+* 64MB SDRAM
+* LCD Display
+* Configurable Jumper options for 66,85, and 100Mhz memory bus
+
+
+BMW System Address Map
+======================
+BMW uses the MPC8245 CHRP Address MAP B found in the MPC8245 Users Manual
+(P.121, Section 3.1 Address Maps, Address Map B). Other I/O devices found
+onboard the processor module are listed briefly below:
+
+0x00000000 - 0x40000000 - 64MB SDRAM SIMM
+                          (Unregistered PC-100 SDRAM DIMM Module)
+
+0xFF000000 - 0xFF001FFF - M-Systems DiskOnChip (TM) 2000
+                          TSOP 16MB (MD2211-D16-V3)
+
+0x70000000 - 0x70001FFF - M-Systems DiskOnChip (TM) 2000
+                          DIP32 (Socketed 16MB - 1GB ) *
+                          NOTE: this is not populated on all systems.
+
+0x7c000000 - 0x7c000000 - Reset Register
+                          (Write 0 to reset)
+
+0x7c000001 - 0x7c000001 - System LED
+                          (Clear Bit 7 to turn on, set to shut off)
+
+0x7c000002 - 0x7c000002 - M48T59 Watchdog IRQ3
+                          (Clear bit 7 to reset, set to assert IRQ3)
+
+0x7c000003 - 0x7c000003 - M48T59 Write-Protect Register
+                          (Clear bit 7 to make R/W, set to make R/O)
+
+0x7c002000 - 0x7c002003 - Infineon OSRAM DLR2416 4 Character
+                          5x7 Dot Matrix Alphanumeric Display
+                          (Each byte sets the appropriate character)
+
+0x7c004000 - 0x7c005FF0 - SGS-THOMSON M48T59Y 8K NVRAM/RTC
+                          NVRAM Memory Region
+
+0x7c005FF0 - 0x7c005FFF - SGS-THOMSON M48T59Y 8K NVRAM/RTC
+                          Realtime Clock Registers
+
+0xFFF00000 - 0xFFF80000 - 512K PLCC32 BootRom
+                          (AMD AM29F040, ST 29W040B)
+
+0xFFF00100 -              System Reset Vector
+
+
+IO/MMU (BAT) Configuration
+======================
+The following Block-Address-Translation (BAT) configuration
+is recommended to access all I/O devices.
+
+#define CFG_IBAT0L  (0x00000000 | BATL_PP_10 | BATL_MEMCOHERENCE)
+#define CFG_IBAT0U  (0x00000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT1L  (0x70000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_IBAT1U  (0x70000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT2L  (0x80000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_IBAT2U  (0x80000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT3L  (0xF0000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_IBAT3U  (0xF0000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_DBAT0L  CFG_IBAT0L
+#define CFG_DBAT0U  CFG_IBAT0U
+#define CFG_DBAT1L  CFG_IBAT1L
+#define CFG_DBAT1U  CFG_IBAT1U
+#define CFG_DBAT2L  CFG_IBAT2L
+#define CFG_DBAT2U  CFG_IBAT2U
+#define CFG_DBAT3L  CFG_IBAT3L
+#define CFG_DBAT3U  CFG_IBAT3U
+
+
+Interrupt Mappings
+======================
+BMW uses MPC8245 discrete mode interrupts. With the following
+hardwired mappings:
+
+BCM5701 10/100/1000 Ethernet 		IRQ1
+CompactPCI Interrupt A			IRQ2
+RTC/Watchdog Interrupt			IRQ3
+Internal NS16552 UART			IRQ4
+
+
+Jumper Settings
+======================
+
+BMW has a jumper (JP600) for selecting 66, 85, or 100Mhz memory bus.
+A jumper (X) is a 0 bit.
+
+Hence 66= 10110
+      85= 11000
+     100= 10000
+
+Jumper Settings for various Speeds
+=======================
+J1 J2 J3 J4 J5
+    X        X    66Mhz
+=======================
+J1 J2 J3 J4 J5
+       X  X  X    85Mhz
+=======================
+J1 J2 J3 J4 J5
+    X  X  X  X   100Mhz
+=======================
+
+Obviously, 100Mhz memory bus is recommended for optimum performance.
+
+
+U-Boot
+===============
+Broadcom BMW board is supported under config_BWM option.
+Supported features:
+
+- NVRAM setenv/getenv (used by Linux Kernel for configuration variables)
+- BCM570x TFTP file transfer support
+- LCD Display Support
+- DOC Support - (underway)
+
+
+
+U-Boot 1.2.0 (Aug  6 2002 - 17:44:48)
+
+CPU:   MPC8245 Revision 16.20 at 264 MHz: 16 kB I-Cache 16 kB D-Cache
+Board: BMW MPC8245/KAHLUA2 - CHRP (MAP B)
+Built: Aug  6 2002 at 17:44:37
+Local Bus at 66 MHz
+DRAM:  64 MB
+FLASH: 4095 MB
+In:    serial
+Out:   serial
+Err:   serial
+DOC:   No DiskOnChip found
+Hit any key to stop autoboot:  0
+=>printenv
+bootdelay=5
+baudrate=9600
+clocks_in_mhz=1
+hostname=switch-2
+bootcmd=tftp 100000 vmlinux.img;bootm
+gateway=10.16.64.1
+ethaddr=00:00:10:18:10:10
+nfsroot=172.16.40.111:/boot/root-fs
+filesize=5ec8c
+netmask=255.255.240.0
+ipaddr=172.16.40.114
+serverip=172.16.40.111
+root=/dev/nfs
+stdin=serial
+stdout=serial
+stderr=serial
+
+Environment size: 315/8172 bytes
+=>boot
+
+
+
+
+
+
+
+DevTools
+========
+ELDK
+        DENX Embedded Linux Development Kit
+
+ROM Emulator
+	Grammar Engine PROMICE P1160-90-AI21E (2MBx8bit, 90ns access time)
+	Grammar Engine PL32E 32Pin PLCC Emulation cables
+	Grammar Engine 3VA8CON (3Volt adapter with Short cables)
+	Grammar Engine FPNET PromICE Ethernet Adapters
+
+ICE
+	WRS/EST VisionICE-II (PPC8240)
+
+
+
+=>reset
+
+
+U-Boot 1.2.0 (Aug  6 2002 - 17:44:48)
+
+CPU:   MPC8245 Revision 16.20 at 264 MHz: 16 kB I-Cache 16 kB D-Cache
+Board: BMW MPC8245/KAHLUA2 - CHRP (MAP B)
+Built: Aug  6 2002 at 17:44:37
+Local Bus at 66 MHz
+DRAM:  64 MB
+FLASH: 4095 MB
+In:    serial
+Out:   serial
+Err:   serial
+DOC:   No DiskOnChip found
+Hit any key to stop autoboot:  0
+
+Broadcom BCM5701 1000Base-T: bus 0, device 13, function 0: MBAR=0x80100000
+BCM570x PCI Memory base address @0x80100000
+eth0:Broadcom BCM5701 1000Base-T: 100 Mbps half duplex link up, flow control OFF
+eth0: Broadcom BCM5701 1000Base-T @0x80100000,node addr 000010181010
+eth0: BCM5700 with Broadcom BCM5701 Integrated Copper transceiver found
+eth0: 32-bit PCI 33MHz, MTU: 1500,Rx Checksum ON
+ARP broadcast 1
+TFTP from server 172.16.40.111; our IP address is 172.16.40.114
+Filename 'vmlinux.img'.
+Load address: 0x100000
+Loading: #################################################################
+         ####################################T #############################
+         ######################
+done
+Bytes transferred = 777199 (bdbef hex)
+
+eth0:Broadcom BCM5701 1000Base-T,HALT,POWER DOWN,done - offline.
+## Booting image at 00100000 ...
+   Image Name:   vmlinux.bin.gz
+   Created:      2002-08-06   6:30:13 UTC
+   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+   Data Size:    777135 Bytes = 758 kB = 0 MB
+   Load Address: 00000000
+   Entry Point:  00000000
+   Verifying Checksum ... OK
+   Uncompressing Kernel Image ... OK
+Memory BAT mapping: BAT2=64Mb, BAT3=0Mb, residual: 0Mb
+Linux version 2.4.19-rc3 (jfd@que) (gcc version 2.95.3 20010111 (prerelease/franzo/20010111)) #168 Mon Aug 5 23:29:20 PDT 2002
+CPU:82xx: 32 I-Cache Block Size, 32 D-Cache Block Size PVR: 0x810000
+U-Boot Environment: 0xc01b08f0
+IP PNP: 802.3 Ethernet Address=<0:0:10:18:10:10>
+cpu0: MPC8245/KAHLUA-II : BMW Platform : 64MB RAM: BPLD Rev. 6e
+NOTICE: mounting root file system via NFS
+IP PNP: switch-2: eth0 IP 172.16.40.114/255.255.240.0 gateway 10.16.64.1 server 172.16.40.111
+On node 0 totalpages: 16384
+zone(0): 16384 pages.
+zone(1): 0 pages.
+zone(2): 0 pages.
+Kernel command line: console=ttyS0,9600 ip=172.16.40.114:172.16.40.111:10.16.64.1:255.255.240.0:switch-2:eth0 root=/dev/nfs rw nfsroot=172.16.40.111:/boot/root-fs,timeo=200,retrans=500 nfsaddrs=172.16.40.114:172.16.40.111
+root_dev_setup:/dev/nfs or 00:ff
+time_init: decrementer frequency = 16.501145 MHz
+Calibrating delay loop... 175.71 BogoMIPS
+Memory: 62572k available (1396k kernel code, 436k data, 100k init, 0k highmem)
+Dentry cache hash table entries: 8192 (order: 4, 65536 bytes)
+Inode cache hash table entries: 4096 (order: 3, 32768 bytes)
+Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)
+Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)
+Page-cache hash table entries: 16384 (order: 4, 65536 bytes)
+POSIX conformance testing by UNIFIX
+PCI: Probing PCI hardware
+Linux NET4.0 for Linux 2.4
+Based upon Swansea University Computer Society NET3.039
+Initializing RT netlink socket
+Starting kswapd
+devfs: v1.12a (20020514) Richard Gooch (rgooch@atnf.csiro.au)
+devfs: devfs_debug: 0x0
+devfs: boot_options: 0x1
+Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
+pty: 256 Unix98 ptys configured
+Serial driver version 5.05c (2001-07-08) with MANY_PORTS SHARE_IRQ SERIAL_PCI enabled
+Testing ttyS0 (0xf7f51500, 0xf7f51500)...
+Testing ttyS1 (0xfc004600, 0xfc004600)...
+ttyS00 at 0xf7f51500 (irq = 24) is a ST16650
+ttyS01 at 0xfc004600 (irq = 25) is a 16550A
+Real Time Clock Driver v1.10e
+RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
+loop: loaded (max 8 devices)
+TFFS 5.1.1 Flash disk driver for DiskOnChip
+Copyright (C) 1998,2001 M-Systems Flash Disk Pioneers Ltd.
+DOC device(s) found: 1
+fl_init: registered device at major: 100
+fl_geninit: registered device at major: 100
+Partition check:
+ fla: p1
+partition: /dev/fl/0: start_sect: 0,nr_sects: 32000 Fl_blk_size[]: 16000KB
+partition: /dev/fl/1: start_sect: 2,nr_sects: 31998 Fl_blk_size[]: 15999KB
+partition: /dev/fl/2: start_sect: 0,nr_sects: 0 Fl_blk_size[]: 0KB
+partition: /dev/fl/3: start_sect: 0,nr_sects: 0 Fl_blk_size[]: 0KB
+Broadcom Gigabit Ethernet Driver bcm5700 ver. 3.0.7 (07/17/02)
+eth0: Broadcom BCM5701 found at mem bfff0000, IRQ 1, node addr 000010181010
+eth0: Broadcom BCM5701 Integrated Copper transceiver found
+eth0: Scatter-gather ON, 64-bit DMA ON, Tx Checksum ON, Rx Checksum ON, 802.1Q VLAN ON
+bond0 registered without MII link monitoring, in bonding mode.
+rtc: unable to get misc minor
+NET4: Linux TCP/IP 1.0 for NET4.0
+IP Protocols: ICMP, UDP, TCP, IGMP
+IP: routing cache hash table of 512 buckets, 4Kbytes
+TCP: Hash tables configured (established 4096 bind 4096)
+bcm5700: eth0 NIC Link is UP, 100 Mbps half duplex
+IP-Config: Gateway not on directly connected network.
+NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
+802.1Q VLAN Support v1.7 Ben Greear <greearb@candelatech.com>
+All bugs added by David S. Miller <davem@redhat.com>
+Looking up port of RPC 100003/2 on 172.16.40.111
+Looking up port of RPC 100005/1 on 172.16.40.111
+VFS: Mounted root (nfs filesystem).
+Mounted devfs on /dev
+Freeing unused kernel memory: 100k init
+INIT: version 2.78 booting
+Mounting local filesystems...
+not mounted anything
+Setting up symlinks in /dev...done.
+Setting up extra devices in /dev...done.
+Starting devfsd...Started device management daemon for /dev
+INIT: Entering runlevel: 2
+Starting internet superserver: inetd.
+
+
+Welcome to Linux/PPC
+MPC8245/BMW
+
+
+
+switch-2 login: root
+Password:
+PAM_unix[49]: (login) session opened for user root by LOGIN(uid=0)
+Last login: Thu Nov 25 11:51:14 1920 on console
+
+
+Welcome to Linux/PPC
+MPC8245/BMW
+
+
+
+login[49]: ROOT LOGIN on `console'
+
+root@switch-2:~# cat /proc/cpuinfo
+cpu             : 82xx
+revision        : 16.20 (pvr 8081 1014)
+bogomips        : 175.71
+vendor          : Broadcom
+machine         : BMW/MPC8245
+root@switch-2:~#
diff --git a/board/bmw/m48t59y.c b/board/bmw/m48t59y.c
new file mode 100644
index 0000000..469f1ad
--- /dev/null
+++ b/board/bmw/m48t59y.c
@@ -0,0 +1,323 @@
+/*
+ * SGS M48-T59Y TOD/NVRAM Driver
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 1999, by Curt McDowell, 08-06-99, Broadcom Corp.
+ *
+ * (C) Copyright 2001, James Dougherty, 07/18/01, Broadcom Corp.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * SGS M48-T59Y TOD/NVRAM Driver
+ *
+ * The SGS M48 an 8K NVRAM starting at offset M48_BASE_ADDR and
+ * continuing for 8176 bytes. After that starts the Time-Of-Day (TOD)
+ * registers which are used to set/get the internal date/time functions.
+ *
+ * This module implements Y2K compliance by taking full year numbers
+ * and translating back and forth from the TOD 2-digit year.
+ *
+ * NOTE: for proper interaction with an operating system, the TOD should
+ * be used to store Universal Coordinated Time (GMT) and timezone
+ * conversions should be used.
+ *
+ * Here is a diagram of the memory layout:
+ *
+ * +---------------------------------------------+ 0xffe0a000
+ * | Non-volatile memory                         | .
+ * |                                             | .
+ * | (8176 bytes of Non-volatile memory)         | .
+ * |                                             | .
+ * +---------------------------------------------+ 0xffe0bff0
+ * | Flags                                       |
+ * +---------------------------------------------+ 0xffe0bff1
+ * | Unused                                      |
+ * +---------------------------------------------+ 0xffe0bff2
+ * | Alarm Seconds                               |
+ * +---------------------------------------------+ 0xffe0bff3
+ * | Alarm Minutes                               |
+ * +---------------------------------------------+ 0xffe0bff4
+ * | Alarm Date                                  |
+ * +---------------------------------------------+ 0xffe0bff5
+ * | Interrupts                                  |
+ * +---------------------------------------------+ 0xffe0bff6
+ * | WatchDog                                    |
+ * +---------------------------------------------+ 0xffe0bff7
+ * | Calibration                                 |
+ * +---------------------------------------------+ 0xffe0bff8
+ * | Seconds                                     |
+ * +---------------------------------------------+ 0xffe0bff9
+ * | Minutes                                     |
+ * +---------------------------------------------+ 0xffe0bffa
+ * | Hours                                       |
+ * +---------------------------------------------+ 0xffe0bffb
+ * | Day                                         |
+ * +---------------------------------------------+ 0xffe0bffc
+ * | Date                                        |
+ * +---------------------------------------------+ 0xffe0bffd
+ * | Month                                       |
+ * +---------------------------------------------+ 0xffe0bffe
+ * | Year (2 digits only)                        |
+ * +---------------------------------------------+ 0xffe0bfff
+ */
+#include <common.h>
+#include <rtc.h>
+#include "bmw.h"
+
+/*
+ * Imported from mousse.h:
+ *
+ *   TOD_REG_BASE		Base of m48t59y TOD registers
+ *   SYS_TOD_UNPROTECT()	Disable NVRAM write protect
+ *   SYS_TOD_PROTECT()		Re-enable NVRAM write protect
+ */
+
+#define YEAR		0xf
+#define MONTH		0xe
+#define DAY		0xd
+#define DAY_OF_WEEK	0xc
+#define HOUR		0xb
+#define MINUTE		0xa
+#define SECOND		0x9
+#define CONTROL		0x8
+#define WATCH		0x7
+#define INTCTL		0x6
+#define WD_DATE		0x5
+#define WD_HOUR		0x4
+#define WD_MIN		0x3
+#define WD_SEC		0x2
+#define _UNUSED		0x1
+#define FLAGS		0x0
+
+#define M48_ADDR	((volatile unsigned char *) TOD_REG_BASE)
+
+int m48_tod_init(void)
+{
+    SYS_TOD_UNPROTECT();
+
+    M48_ADDR[CONTROL] = 0;
+    M48_ADDR[WATCH] = 0;
+    M48_ADDR[INTCTL] = 0;
+
+    /*
+     * If the oscillator is currently stopped (as on a new part shipped
+     * from the factory), start it running.
+     *
+     * Here is an example of the TOD bytes on a brand new M48T59Y part:
+     *		00 00 00 00 00 00 00 00 00 88 8c c3 bf c8 f5 01
+     */
+
+    if (M48_ADDR[SECOND] & 0x80)
+	M48_ADDR[SECOND] = 0;
+
+    /* Is battery low */
+    if ( M48_ADDR[FLAGS] & 0x10) {
+	 printf("NOTICE: Battery low on Real-Time Clock (replace SNAPHAT).\n");
+    }
+
+    SYS_TOD_PROTECT();
+
+    return 0;
+}
+
+/*
+ * m48_tod_set
+ */
+
+static int to_bcd(int value)
+{
+    return value / 10 * 16 + value % 10;
+}
+
+static int from_bcd(int value)
+{
+    return value / 16 * 10 + value % 16;
+}
+
+static int day_of_week(int y, int m, int d)	/* 0-6 ==> Sun-Sat */
+{
+    static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+    y -= m < 3;
+    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
+}
+
+/*
+ * Note: the TOD should store the current GMT
+ */
+
+int m48_tod_set(int year,		/* 1980-2079 */
+		int month,		/* 01-12 */
+		int day,		/* 01-31 */
+		int hour,		/* 00-23 */
+		int minute,		/* 00-59 */
+		int second)		/* 00-59 */
+
+{
+    SYS_TOD_UNPROTECT();
+
+    M48_ADDR[CONTROL] |= 0x80;	/* Set WRITE bit */
+
+    M48_ADDR[YEAR] = to_bcd(year % 100);
+    M48_ADDR[MONTH] = to_bcd(month);
+    M48_ADDR[DAY] = to_bcd(day);
+    M48_ADDR[DAY_OF_WEEK] = day_of_week(year, month, day) + 1;
+    M48_ADDR[HOUR] = to_bcd(hour);
+    M48_ADDR[MINUTE] = to_bcd(minute);
+    M48_ADDR[SECOND] = to_bcd(second);
+
+    M48_ADDR[CONTROL] &= ~0x80;	/* Clear WRITE bit */
+
+    SYS_TOD_PROTECT();
+
+    return 0;
+}
+
+/*
+ * Note: the TOD should store the current GMT
+ */
+
+int m48_tod_get(int *year,		/* 1980-2079 */
+		int *month,		/* 01-12 */
+		int *day,		/* 01-31 */
+		int *hour,		/* 00-23 */
+		int *minute,		/* 00-59 */
+		int *second)		/* 00-59 */
+{
+    int y;
+
+    SYS_TOD_UNPROTECT();
+
+    M48_ADDR[CONTROL] |= 0x40;	/* Set READ bit */
+
+    y = from_bcd(M48_ADDR[YEAR]);
+    *year = y < 80 ? 2000 + y : 1900 + y;
+    *month = from_bcd(M48_ADDR[MONTH]);
+    *day = from_bcd(M48_ADDR[DAY]);
+    /* day_of_week = M48_ADDR[DAY_OF_WEEK] & 0xf; */
+    *hour = from_bcd(M48_ADDR[HOUR]);
+    *minute = from_bcd(M48_ADDR[MINUTE]);
+    *second = from_bcd(M48_ADDR[SECOND] & 0x7f);
+
+    M48_ADDR[CONTROL] &= ~0x40;	/* Clear READ bit */
+
+    SYS_TOD_PROTECT();
+
+    return 0;
+}
+
+int m48_tod_get_second(void)
+{
+    return from_bcd(M48_ADDR[SECOND] & 0x7f);
+}
+
+/*
+ * Watchdog function
+ *
+ *  If usec is 0, the watchdog timer is disarmed.
+ *
+ *  If usec is non-zero, the watchdog timer is armed (or re-armed) for
+ *    approximately usec microseconds (if the exact requested usec is
+ *    not supported by the chip, the next higher available value is used).
+ *
+ *  Minimum watchdog timeout = 62500 usec
+ *  Maximum watchdog timeout = 124 sec (124000000 usec)
+ */
+
+void m48_watchdog_arm(int usec)
+{
+    int		mpy, res;
+
+    SYS_TOD_UNPROTECT();
+
+    if (usec == 0) {
+	res = 0;
+	mpy = 0;
+    } else if (usec < 2000000) {	/* Resolution: 1/16s if below 2s */
+	res = 0;
+	mpy = (usec + 62499) / 62500;
+    } else if (usec < 8000000) {	/* Resolution: 1/4s if below 8s */
+	res = 1;
+	mpy = (usec + 249999) / 250000;
+    } else if (usec < 32000000) {	/* Resolution: 1s if below 32s */
+	res = 2;
+	mpy = (usec + 999999) / 1000000;
+    } else {				/* Resolution: 4s up to 124s */
+	res = 3;
+	mpy = (usec + 3999999) / 4000000;
+	if (mpy > 31)
+	    mpy = 31;
+    }
+
+    M48_ADDR[WATCH] = (0x80 |		/* Steer to RST signal (IRQ = N/C) */
+		       mpy << 2 |
+		       res);
+
+    SYS_TOD_PROTECT();
+}
+
+/*
+ * U-Boot RTC support.
+ */
+void
+rtc_get( struct rtc_time *tmp )
+{
+	m48_tod_get(&tmp->tm_year,
+		    &tmp->tm_mon,
+		    &tmp->tm_mday,
+		    &tmp->tm_hour,
+		    &tmp->tm_min,
+		    &tmp->tm_sec);
+	tmp->tm_yday = 0;
+	tmp->tm_isdst= 0;
+
+#ifdef RTC_DEBUG
+	printf( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+		tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
+#endif
+}
+
+void
+rtc_set( struct rtc_time *tmp )
+{
+	m48_tod_set(tmp->tm_year,		/* 1980-2079 */
+		    tmp->tm_mon,		/* 01-12 */
+		    tmp->tm_mday,              /* 01-31 */
+		    tmp->tm_hour,		/* 00-23 */
+		    tmp->tm_min,		/* 00-59 */
+		    tmp->tm_sec);		/* 00-59 */
+
+#ifdef RTC_DEBUG
+	printf( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+
+}
+
+void
+rtc_reset (void)
+{
+  m48_tod_init();
+}
+
diff --git a/board/csb226/config.mk b/board/csb226/config.mk
new file mode 100644
index 0000000..939ffff
--- /dev/null
+++ b/board/csb226/config.mk
@@ -0,0 +1,16 @@
+#
+# Linux-Kernel is expected to be at c000'8000, entry c000'8000
+#
+# we load ourself to c170'0000, the upper 1 MB of second bank
+#
+# download areas is c800'0000
+#
+
+# This is the address where U-Boot lives in flash:
+#TEXT_BASE = 0
+
+# FIXME: armboot does only work correctly when being compiled
+# for the addresses _after_ relocation to RAM!! Otherwhise the
+# .bss segment is assumed in flash...
+TEXT_BASE = 0xa1fe0000
+
diff --git a/board/csb226/flash.c b/board/csb226/flash.c
new file mode 100644
index 0000000..0b95648
--- /dev/null
+++ b/board/csb226/flash.c
@@ -0,0 +1,364 @@
+/*
+ * (C) Copyright 2002
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#define FLASH_BANK_SIZE 0x02000000
+#define MAIN_SECT_SIZE  0x40000         /* 2x16 = 256k per sector */
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+
+ulong flash_init(void)
+{
+    int i, j;
+    ulong size = 0;
+
+    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
+    {
+	ulong flashbase = 0;
+	flash_info[i].flash_id =
+	  (INTEL_MANUFACT & FLASH_VENDMASK) |
+	  (INTEL_ID_28F128J3 & FLASH_TYPEMASK);
+	flash_info[i].size = FLASH_BANK_SIZE;
+	flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
+	memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
+
+        switch (i)
+        {
+           case 0:
+	        flashbase = PHYS_FLASH_1;
+                break;
+           default:
+	        panic("configured to many flash banks!\n");
+                break;
+        }
+	for (j = 0; j < flash_info[i].sector_count; j++)
+	{
+	    flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE;
+	}
+	size += flash_info[i].size;
+    }
+
+    /* Protect monitor and environment sectors
+     */
+    flash_protect(FLAG_PROTECT_SET,
+		  CFG_FLASH_BASE,
+		  CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
+		  &flash_info[0]);
+
+    flash_protect(FLAG_PROTECT_SET,
+		  CFG_ENV_ADDR,
+		  CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+		  &flash_info[0]);
+
+    return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i, j;
+
+    for (j=0; j<CFG_MAX_FLASH_BANKS; j++)
+    {
+        switch (info->flash_id & FLASH_VENDMASK)
+        {
+        case (INTEL_MANUFACT & FLASH_VENDMASK):
+	        printf("Intel: ");
+	        break;
+        default:
+	        printf("Unknown Vendor ");
+	        break;
+        }
+
+        switch (info->flash_id & FLASH_TYPEMASK)
+        {
+        case (INTEL_ID_28F128J3 & FLASH_TYPEMASK):
+	        printf("28F128J3 (128Mbit)\n");
+	        break;
+        default:
+	        printf("Unknown Chip Type\n");
+	        goto Done;
+	        break;
+        }
+
+        printf("  Size: %ld MB in %d Sectors\n",
+	        info->size >> 20, info->sector_count);
+
+        printf("  Sector Start Addresses:");
+        for (i = 0; i < info->sector_count; i++)
+        {
+	        if ((i % 5) == 0)
+	        {
+	        printf ("\n   ");
+	        }
+	        printf (" %08lX%s", info->start[i],
+		        info->protect[i] ? " (RO)" : "     ");
+        }
+        printf ("\n");
+        info++;
+    }
+
+Done:
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int	flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    int flag, prot, sect;
+    int rc = ERR_OK;
+
+    if (info->flash_id == FLASH_UNKNOWN)
+	return ERR_UNKNOWN_FLASH_TYPE;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+	return ERR_INVAL;
+    }
+
+    if ((info->flash_id & FLASH_VENDMASK) !=
+	(INTEL_MANUFACT & FLASH_VENDMASK)) {
+	return ERR_UNKNOWN_FLASH_VENDOR;
+    }
+
+    prot = 0;
+    for (sect=s_first; sect<=s_last; ++sect) {
+	if (info->protect[sect]) {
+	    prot++;
+	}
+    }
+    if (prot)
+	return ERR_PROTECTED;
+
+    /*
+     * Disable interrupts which might cause a timeout
+     * here. Remember that our exception vectors are
+     * at address 0 in the flash, and we don't want a
+     * (ticker) exception to happen while the flash
+     * chip is in programming mode.
+     */
+    flag = disable_interrupts();
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last && !ctrlc(); sect++) {
+
+	printf("Erasing sector %2d ... ", sect);
+
+	/* arm simple, non interrupt dependent timer */
+	reset_timer_masked();
+
+	if (info->protect[sect] == 0) {	/* not protected */
+	    /* vushort *addr = (vushort *)(info->start[sect]); */
+	    ushort *addr = (ushort *)(info->start[sect]);
+
+	    *addr = 0x20;	/* erase setup */
+	    *addr = 0xD0;	/* erase confirm */
+
+	    while ((*addr & 0x80) != 0x80) {
+		if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) {
+		    *addr = 0xB0; /* suspend erase */
+		    *addr = 0xFF;	/* reset to read mode */
+		    rc = ERR_TIMOUT;
+		    goto outahere;
+		}
+	    }
+
+	    /* clear status register command */
+	    *addr = 0x50;
+	    /* reset to read mode */
+	    *addr = 0xFF;
+	}
+	printf("ok.\n");
+    }
+    if (ctrlc())
+      printf("User Interrupt!\n");
+
+outahere:
+
+    /* allow flash to settle - wait 10 ms */
+    udelay_masked(10000);
+
+    if (flag)
+      enable_interrupts();
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash
+ */
+
+static int write_word (flash_info_t *info, ulong dest, ushort data)
+{
+    /* vushort *addr = (vushort *)dest, val; */
+    ushort *addr = (ushort *)dest, val;
+    int rc = ERR_OK;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased
+     */
+    if ((*addr & data) != data)
+        return ERR_NOT_ERASED;
+
+    /*
+     * Disable interrupts which might cause a timeout
+     * here. Remember that our exception vectors are
+     * at address 0 in the flash, and we don't want a
+     * (ticker) exception to happen while the flash
+     * chip is in programming mode.
+     */
+    flag = disable_interrupts();
+
+    /* clear status register command */
+    *addr = 0x50;
+
+    /* program set-up command */
+    *addr = 0x40;
+
+    /* latch address/data */
+    *addr = data;
+
+    /* arm simple, non interrupt dependent timer */
+    reset_timer_masked();
+
+    /* wait while polling the status register */
+    while(((val = *addr) & 0x80) != 0x80)
+    {
+	if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) {
+	    rc = ERR_TIMOUT;
+	    /* suspend program command */
+	    *addr = 0xB0;
+	    goto outahere;
+	}
+    }
+
+    if(val & 0x1A) {	/* check for error */
+        printf("\nFlash write error %02x at address %08lx\n",
+    	   (int)val, (unsigned long)dest);
+        if(val & (1<<3)) {
+	    printf("Voltage range error.\n");
+	    rc = ERR_PROG_ERROR;
+	    goto outahere;
+        }
+        if(val & (1<<1)) {
+	    printf("Device protect error.\n");
+	    rc = ERR_PROTECTED;
+	    goto outahere;
+        }
+        if(val & (1<<4)) {
+	    printf("Programming error.\n");
+	    rc = ERR_PROG_ERROR;
+	    goto outahere;
+        }
+        rc = ERR_PROG_ERROR;
+        goto outahere;
+    }
+
+outahere:
+    /* read array command */
+    *addr = 0xFF;
+
+    if (flag)
+      enable_interrupts();
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp;
+    ushort data;
+    int l;
+    int i, rc;
+
+    wp = (addr & ~1);	/* get lower word aligned address */
+
+    /*
+     * handle unaligned start bytes
+     */
+    if ((l = addr - wp) != 0) {
+	data = 0;
+	for (i=0, cp=wp; i<l; ++i, ++cp) {
+	    data = (data >> 8) | (*(uchar *)cp << 8);
+	}
+	for (; i<2 && cnt>0; ++i) {
+	    data = (data >> 8) | (*src++ << 8);
+	    --cnt;
+	    ++cp;
+	}
+	for (; cnt==0 && i<2; ++i, ++cp) {
+	    data = (data >> 8) | (*(uchar *)cp << 8);
+	}
+
+	if ((rc = write_word(info, wp, data)) != 0) {
+	    return (rc);
+	}
+	wp += 2;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cnt >= 2) {
+	/* data = *((vushort*)src); */
+	data = *((ushort*)src);
+	if ((rc = write_word(info, wp, data)) != 0) {
+	    return (rc);
+	}
+	src += 2;
+	wp  += 2;
+	cnt -= 2;
+    }
+
+    if (cnt == 0) {
+	return ERR_OK;
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
+	data = (data >> 8) | (*src++ << 8);
+	--cnt;
+    }
+    for (; i<2; ++i, ++cp) {
+	data = (data >> 8) | (*(uchar *)cp << 8);
+    }
+
+    return write_word(info, wp, data);
+}