Initial revision
diff --git a/board/siemens/CCM/flash.c b/board/siemens/CCM/flash.c
new file mode 100644
index 0000000..e56114f
--- /dev/null
+++ b/board/siemens/CCM/flash.c
@@ -0,0 +1,553 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+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);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+	volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	unsigned long size_b0, size_b1;
+	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_b0 = 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_b0, size_b0<<20);
+	}
+
+	size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+	if (size_b1 > size_b0) {
+		printf ("## ERROR: "
+			"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+			size_b1, size_b1<<20,
+			size_b0, size_b0<<20
+		);
+		flash_info[0].flash_id	= FLASH_UNKNOWN;
+		flash_info[1].flash_id	= FLASH_UNKNOWN;
+		flash_info[0].sector_count	= -1;
+		flash_info[1].sector_count	= -1;
+		flash_info[0].size		= 0;
+		flash_info[1].size		= 0;
+		return (0);
+	}
+
+	/* Remap FLASH according to real size */
+	memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+	memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+	/* Re-do sizing to get full correct info */
+	size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+	flash_get_offsets (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
+
+	if (size_b1) {
+		memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+		memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+				    BR_MS_GPCM | BR_V;
+
+		/* Re-do sizing to get full correct info */
+		size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+					  &flash_info[1]);
+
+		flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#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[1]);
+#endif
+	} else {
+		memctl->memc_br1 = 0;		/* invalidate bank */
+
+		flash_info[1].flash_id = FLASH_UNKNOWN;
+		flash_info[1].sector_count = -1;
+	}
+
+	flash_info[0].size = size_b0;
+	flash_info[1].size = size_b1;
+
+	return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+	int i;
+
+	/* set up sector start address table */
+	if (info->flash_id & FLASH_BTYPE) {
+		/* 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;
+		}
+	} else {
+		/* 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;
+		}
+	}
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_AMD:	printf ("AMD ");		break;
+	case FLASH_MAN_FUJ:	printf ("FUJITSU ");		break;
+	default:		printf ("Unknown Vendor ");	break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_AM400B:	printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM400T:	printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM800B:	printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM800T:	printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM160B:	printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM160T:	printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM320B:	printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM320T:	printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+				break;
+	default:		printf ("Unknown Chip Type\n");
+				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");
+	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		*/
+#if 0	/* enable when device IDs are available */
+	case AMD_ID_LV320T:
+		info->flash_id += FLASH_AM320T;
+		info->sector_count = 67;
+		info->size = 0x00800000;
+		break;				/* => 8 MB		*/
+
+	case AMD_ID_LV320B:
+		info->flash_id += FLASH_AM320B;
+		info->sector_count = 67;
+		info->size = 0x00800000;
+		break;				/* => 8 MB		*/
+#endif
+	default:
+		info->flash_id = FLASH_UNKNOWN;
+		return (0);			/* => no or unknown flash */
+
+	}
+
+	/* set up sector start address table */
+	if (info->flash_id & FLASH_BTYPE) {
+		/* 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;
+		}
+	} else {
+		/* 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;
+		}
+	}
+
+	/* 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) {
+			printf ("- missing\n");
+		} else {
+			printf ("- 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 {
+		printf ("\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) {
+			printf ("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 */
+
+	printf (" 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/siemens/IAD210/atm.c b/board/siemens/IAD210/atm.c
new file mode 100644
index 0000000..c77e359
--- /dev/null
+++ b/board/siemens/IAD210/atm.c
@@ -0,0 +1,653 @@
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#include "atm.h"
+#include <linux/stddef.h>
+
+#define SYNC __asm__("sync")
+#define ALIGN(p, a) ((char *)(((uint32)(p)+(a)-1) & ~((uint32)(a)-1)))
+
+#define FALSE  1
+#define TRUE   0
+#define OK     0
+#define ERROR -1
+
+struct atm_connection_t g_conn[NUM_CONNECTIONS] =
+{
+  { NULL, 10, NULL, 10,  NULL, NULL, NULL, NULL }, /* OAM  */
+};
+
+struct atm_driver_t g_atm =
+{
+  FALSE,   /* loaded */
+  FALSE,   /* started */
+  NULL,    /* csram */
+  0,       /* csram_size */
+  NULL,    /* am_top */
+  NULL,    /* ap_top */
+  NULL,    /* int_reload_ptr */
+  NULL,    /* int_serv_ptr */
+  NULL,    /* rbd_base_ptr */
+  NULL,    /* tbd_base_ptr */
+  0        /* linerate */
+};
+
+char csram[1024]; /* more than enough for doing nothing*/
+
+int    atmLoad(void);
+void   atmUnload(void);
+int    atmMemInit(void);
+void   atmIntInit(void);
+void   atmApcInit(void);
+void   atmAmtInit(void);
+void   atmCpmInit(void);
+void   atmUtpInit(void);
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmLoad
+ *
+ * DESCRIPTION: Basic ATM initialization.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: OK or ERROR
+ *
+ ****************************************************************************/
+int atmLoad()
+{
+  volatile immap_t       *immap  = (immap_t *)CFG_IMMR;
+  volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
+  volatile iop8xx_t      *iop    = &immap->im_ioport;
+
+  timers->cpmt_tgcr &=  0x0FFF; SYNC;             /* Disable Timer 4 */
+  immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC; /* Disable SCC4 */
+  iop->iop_pdpar &= 0x3FFF; SYNC;                 /* Disable SAR and UTOPIA */
+
+  if ( atmMemInit() != OK ) return ERROR;
+
+  atmIntInit();
+  atmApcInit();
+  atmAmtInit();
+  atmCpmInit();
+  atmUtpInit();
+
+  g_atm.loaded = TRUE;
+
+  return OK;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmUnload
+ *
+ * DESCRIPTION: Disables ATM and UTOPIA.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmUnload()
+{
+  volatile immap_t       *immap  = (immap_t *)CFG_IMMR;
+  volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
+  volatile iop8xx_t      *iop    = &immap->im_ioport;
+
+  timers->cpmt_tgcr &=  0x0FFF; SYNC;             /* Disable Timer 4 */
+  immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC;  /* Disable SCC4 */
+  iop->iop_pdpar &= 0x3FFF; SYNC;                 /* Disable SAR and UTOPIA */
+  g_atm.loaded = FALSE;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmMemInit
+ *
+ * DESCRIPTION:
+ *
+ * The ATM driver uses the following resources:
+ *
+ * A. Memory in DPRAM to hold
+ *
+ *     1/ CT          = Connection Table ( RCT & TCT )
+ *     2/ TCTE        = Transmit Connection Table Extension
+ *     3/ MPHYPT      = Multi-PHY Pointing Table
+ *     4/ APCP        = APC Parameter Table
+ *     5/ APCT_PRIO_1 = APC Table ( priority 1 for AAL1/2 )
+ *     6/ APCT_PRIO_2 = APC Table ( priority 2 for VBR )
+ *     7/ APCT_PRIO_3 = APC Table ( priority 3 for UBR )
+ *     8/ TQ          = Transmit Queue
+ *     9/ AM          = Address Matching Table
+ *    10/ AP          = Address Pointing Table
+ *
+ * B. Memory in cache safe RAM to hold
+ *
+ *     1/ INT         = Interrupt Queue
+ *     2/ RBD         = Receive Buffer Descriptors
+ *     3/ TBD         = Transmit Buffer Descriptors
+ *
+ * This function
+ * 1. clears the ATM DPRAM area,
+ * 2. Allocates and clears cache safe memory,
+ * 3. Initializes 'g_conn'.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: OK or ERROR
+ *
+ ****************************************************************************/
+int atmMemInit()
+{
+  int i;
+  unsigned immr = CFG_IMMR;
+  int total_num_rbd = 0;
+  int total_num_tbd = 0;
+
+  memset((char *)CFG_IMMR + 0x2000 + ATM_DPRAM_BEGIN, 0x00, ATM_DPRAM_SIZE);
+
+  g_atm.csram_size = NUM_INT_ENTRIES * SIZE_OF_INT_ENTRY;
+
+  for ( i = 0; i < NUM_CONNECTIONS; ++i ) {
+    total_num_rbd += g_conn[i].num_rbd;
+    total_num_tbd += g_conn[i].num_tbd;
+  }
+
+  g_atm.csram_size += total_num_rbd * SIZE_OF_RBD + total_num_tbd * SIZE_OF_TBD + 4;
+
+  g_atm.csram = &csram[0];
+  memset(&(g_atm.csram), 0x00, g_atm.csram_size);
+
+  g_atm.int_reload_ptr = (uint32 *)ALIGN(g_atm.csram, 4);
+  g_atm.rbd_base_ptr = (struct atm_bd_t *)(g_atm.int_reload_ptr + NUM_INT_ENTRIES);
+  g_atm.tbd_base_ptr = (struct atm_bd_t *)(g_atm.rbd_base_ptr + total_num_rbd);
+
+  g_conn[0].rbd_ptr = g_atm.rbd_base_ptr;
+  g_conn[0].tbd_ptr = g_atm.tbd_base_ptr;
+  g_conn[0].ct_ptr = CT_PTR(immr);
+  g_conn[0].tcte_ptr = TCTE_PTR(immr);
+
+  return OK;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmIntInit
+ *
+ * DESCRIPTION:
+ *
+ * Initialization of the MPC860 ESAR Interrupt Queue.
+ * This function
+ * - clears all entries in the INT,
+ * - sets the WRAP bit of the last INT entry,
+ * - initializes the 'int_serv_ptr' attribuut of the AtmDriver structure
+ *   to the first INT entry.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARKS:
+ *
+ * - The INT resides in external cache safe memory.
+ * - The base address of the INT is stored in g_atm.int_reload_ptr.
+ * - The number of entries in the INT is given by NUM_INT_ENTRIES.
+ * - The INTBASE field in SAR Parameter RAM is set by atmCpmInit().
+ *
+ ****************************************************************************/
+void atmIntInit()
+{
+  int i;
+  for ( i = 0; i < NUM_INT_ENTRIES - 1; ++i) g_atm.int_reload_ptr[i] = 0;
+  g_atm.int_reload_ptr[i] = INT_WRAP;
+  g_atm.int_serv_ptr = g_atm.int_reload_ptr;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmApcInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the following ATM Pace Controller related
+ * data structures:
+ *
+ * - 1 MPHY Pointing Table (contains only one entry)
+ * - 3 APC Parameter Tables (one PHY with 3 priorities)
+ * - 3 APC Tables (one table for each priority)
+ * - 1 Transmit Queue (one transmit queue per PHY)
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmApcInit()
+{
+  int i;
+  /* unsigned immr = CFG_IMMR; */
+  uint16 * mphypt_ptr = MPHYPT_PTR(CFG_IMMR);
+  struct apc_params_t * apcp_ptr = APCP_PTR(CFG_IMMR);
+  uint16 * apct_prio1_ptr = APCT1_PTR(CFG_IMMR);
+  uint16 * tq_ptr = TQ_PTR(CFG_IMMR);
+  /***************************************************/
+  /* Initialize MPHY Pointing Table (only one entry) */
+  /***************************************************/
+  *mphypt_ptr = APCP_BASE;
+
+  /********************************************/
+  /* Initialize APC parameters for priority 1 */
+  /********************************************/
+  apcp_ptr->apct_base1 = APCT_PRIO_1_BASE;
+  apcp_ptr->apct_end1  =  APCT_PRIO_1_BASE + NUM_APCT_PRIO_1_ENTRIES * 2;
+  apcp_ptr->apct_ptr1  =  APCT_PRIO_1_BASE;
+  apcp_ptr->apct_sptr1 = APCT_PRIO_1_BASE;
+  apcp_ptr->etqbase    = TQ_BASE;
+  apcp_ptr->etqend     =  TQ_BASE + ( NUM_TQ_ENTRIES - 1 ) * 2;
+  apcp_ptr->etqaptr    = TQ_BASE;
+  apcp_ptr->etqtptr    = TQ_BASE;
+  apcp_ptr->apc_mi     = 8;
+  apcp_ptr->ncits      = 0x0100;   /* NCITS = 1 */
+  apcp_ptr->apcnt      = 0;
+  apcp_ptr->reserved1  = 0;
+  apcp_ptr->eapcst     = 0x2009;  /* LAST, ESAR, MPHY */
+  apcp_ptr->ptp_counter = 0;
+  apcp_ptr->ptp_txch   = 0;
+  apcp_ptr->reserved2  = 0;
+
+
+  /***************************************************/
+  /* Initialize APC Tables with empty slots (0xFFFF) */
+  /***************************************************/
+  for ( i = 0; i < NUM_APCT_PRIO_1_ENTRIES; ++i ) *(apct_prio1_ptr++) = 0xFFFF;
+
+  /************************/
+  /* Clear Transmit Queue */
+  /************************/
+  for ( i = 0; i < NUM_TQ_ENTRIES; ++i ) *(tq_ptr++) = 0;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmAmtInit
+ *
+ * DESCRIPTION:
+ *
+ * This function clears the first entry in the Address Matching Table and
+ * lets the first entry in the Address Pointing table point to the first
+ * entry in the TCT table (i.e. the raw cell channel).
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARKS:
+ *
+ * The values for the AMBASE, AMEND and APBASE registers in SAR parameter
+ * RAM are initialized by atmCpmInit().
+ *
+ ****************************************************************************/
+void atmAmtInit()
+{
+  unsigned immr = CFG_IMMR;
+
+  g_atm.am_top = AM_PTR(immr);
+  g_atm.ap_top = AP_PTR(immr);
+
+  *(g_atm.ap_top--) = CT_BASE;
+  *(g_atm.am_top--) = 0;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmCpmInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the Utopia Interface Parameter RAM Map
+ * (SCC4, ATM Protocol) of the Communication Processor Modudule.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmCpmInit()
+{
+  unsigned immr = CFG_IMMR;
+
+  memset((char *)immr + 0x3F00, 0x00, 0xC0);
+
+  /*-----------------------------------------------------------------*/
+  /* RBDBASE - Receive buffer descriptors base address               */
+  /* The RBDs reside in cache safe external memory.                  */
+  /*-----------------------------------------------------------------*/
+  *RBDBASE(immr) = (uint32)g_atm.rbd_base_ptr;
+
+  /*-----------------------------------------------------------------*/
+  /* SRFCR - SAR receive function code                               */
+  /* 0-2 rsvd = 000                                                  */
+  /* 3-4 BO   = 11  Byte ordering (big endian).                      */
+  /* 5-7 FC   = 000 Value driven on the address type signals AT[1-3] */
+  /*                when the SDMA channel accesses memory.           */
+  /*-----------------------------------------------------------------*/
+  *SRFCR(immr) = 0x18;
+
+  /*-----------------------------------------------------------------*/
+  /* SRSTATE - SAR receive status                                    */
+  /* 0 EXT  = 0 Extended mode off.                                   */
+  /* 1 ACP  = 0 Valid only if EXT = 1.                               */
+  /* 2 EC   = 0 Standard 53-byte ATM cell.                           */
+  /* 3 SNC  = 0 In sync. Must be set to 0 during initialization.     */
+  /* 4 ESAR = 1 Enhanced SAR functionality enabled.                  */
+  /* 5 MCF  = 1 Management Cell Filter active.                       */
+  /* 6 SER  = 0 UTOPIA mode.                                         */
+  /* 7 MPY  = 1 Multiple PHY mode.                                   */
+  /*-----------------------------------------------------------------*/
+  *SRSTATE(immr) = 0x0D;
+
+  /*-----------------------------------------------------------------*/
+  /* MRBLR - Maximum receive buffer length register.                 */
+  /* Must be cleared for ATM operation (see also SMRBLR).            */
+  /*-----------------------------------------------------------------*/
+  *MRBLR(immr) = 0;
+
+  /*-----------------------------------------------------------------*/
+  /* RSTATE - SCC internal receive state parameters                  */
+  /* The first byte must be initialized with the value of SRFCR.     */
+  /*-----------------------------------------------------------------*/
+  *RSTATE(immr) = (uint32)(*SRFCR(immr)) << 24;
+
+  /*-----------------------------------------------------------------*/
+  /* STFCR - SAR transmit function code                              */
+  /* 0-2 rsvd = 000                                                  */
+  /* 3-4 BO   = 11  Byte ordering (big endian).                      */
+  /* 5-7 FC   = 000 Value driven on the address type signals AT[1-3] */
+  /*                when the SDMA channel accesses memory.           */
+  /*-----------------------------------------------------------------*/
+  *STFCR(immr) = 0x18;
+
+  /*-----------------------------------------------------------------*/
+  /* SRSTATE - SAR transmit status                                   */
+  /* 0 EXT  = 0 : Extended mode off                                  */
+  /* 1 rsvd = 0 :                                                    */
+  /* 2 EC   = 0 : Standard 53-byte ATM cell                          */
+  /* 3 rsvd = 0 :                                                    */
+  /* 4 ESAR = 1 : Enhanced SAR functionality enabled                 */
+  /* 5 rsvd = 0 :                                                    */
+  /* 6 SER  = 0 : UTOPIA mode                                        */
+  /* 7 MPY  = 1 : Multiple PHY mode                                  */
+  /*-----------------------------------------------------------------*/
+  *STSTATE(immr) = 0x09;
+
+  /*-----------------------------------------------------------------*/
+  /* TBDBASE - Transmit buffer descriptors base address              */
+  /* The TBDs reside in cache safe external memory.                  */
+  /*-----------------------------------------------------------------*/
+  *TBDBASE(immr) = (uint32)g_atm.tbd_base_ptr;
+
+  /*-----------------------------------------------------------------*/
+  /* TSTATE - SCC internal transmit state parameters                 */
+  /* The first byte must be initialized with the value of STFCR.     */
+  /*-----------------------------------------------------------------*/
+  *TSTATE(immr) = (uint32)(*STFCR(immr)) << 24;
+
+  /*-----------------------------------------------------------------*/
+  /* CTBASE - Connection table base address                          */
+  /* Offset from the beginning of DPRAM (64-byte aligned).           */
+  /*-----------------------------------------------------------------*/
+  *CTBASE(immr) = CT_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* INTBASE - Interrupt queue base pointer.                         */
+  /* The interrupt queue resides in cache safe external memory.      */
+  /*-----------------------------------------------------------------*/
+  *INTBASE(immr) = (uint32)g_atm.int_reload_ptr;
+
+  /*-----------------------------------------------------------------*/
+  /* INTPTR - Pointer into interrupt queue.                          */
+  /* Initialize to INTBASE.                                          */
+  /*-----------------------------------------------------------------*/
+  *INTPTR(immr) = *INTBASE(immr);
+
+  /*-----------------------------------------------------------------*/
+  /* C_MASK - Constant mask for CRC32                                */
+  /* Must be initialized to 0xDEBB20E3.                              */
+  /*-----------------------------------------------------------------*/
+  *C_MASK(immr) = 0xDEBB20E3;
+
+  /*-----------------------------------------------------------------*/
+  /* INT_ICNT - Interrupt threshold value                            */
+  /*-----------------------------------------------------------------*/
+  *INT_ICNT(immr) = 1;
+
+  /*-----------------------------------------------------------------*/
+  /* INT_CNT - Interrupt counter                                     */
+  /* Initalize to INT_ICNT. Decremented for each interrupt entry     */
+  /* reported in the interrupt queue. On zero an interrupt is        */
+  /* signaled to the host by setting the GINT bit in the event       */
+  /* register. The counter is reinitialized with INT_ICNT.           */
+  /*-----------------------------------------------------------------*/
+  *INT_CNT(immr) = *INT_ICNT(immr);
+
+  /*-----------------------------------------------------------------*/
+  /* SMRBLR - SAR maximum receive buffer length register.            */
+  /* Must be a multiple of 48 bytes. Common for all ATM connections. */
+  /*-----------------------------------------------------------------*/
+  *SMRBLR(immr) = SAR_RXB_SIZE;
+
+  /*-----------------------------------------------------------------*/
+  /* APCST - APC status register.                                    */
+  /* 0     rsvd 0                                                    */
+  /* 1-2   CSER 11  Initialize with the same value as NSER.          */
+  /* 3-4   NSER 11  Next serial or UTOPIA channel.                   */
+  /* 5-7   rsvd 000                                                  */
+  /* 8-10  rsvd 000                                                  */
+  /* 11    rsvd 0                                                    */
+  /* 12    ESAR 1   UTOPIA Level 2 MPHY enabled.                     */
+  /* 13    DIS  0   APC disable. Must be initiazed to 0.             */
+  /* 14    PL2  0   Not used.                                        */
+  /* 15    MPY  1   Multiple PHY mode on.                            */
+  /*-----------------------------------------------------------------*/
+  *APCST(immr) = 0x7809;
+
+  /*-----------------------------------------------------------------*/
+  /* APCPTR - Pointer to the APC parameter table                     */
+  /* In MPHY master mode this parameter points to the MPHY pointing  */
+  /* table. 2-byte aligned.                                          */
+  /*-----------------------------------------------------------------*/
+  *APCPTR(immr) = MPHYPT_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* HMASK - Header mask                                             */
+  /* Each incoming cell is masked with HMASK before being compared   */
+  /* to the entries in the address matching table.                   */
+  /*-----------------------------------------------------------------*/
+  *HMASK(immr) = AM_HMASK;
+
+  /*-----------------------------------------------------------------*/
+  /* AMBASE - Address matching table base address                    */
+  /*-----------------------------------------------------------------*/
+  *AMBASE(immr) = AM_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* AMEND - Address matching table end address                      */
+  /*-----------------------------------------------------------------*/
+  *AMEND(immr) = AM_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* APBASE - Address pointing table base address                    */
+  /*-----------------------------------------------------------------*/
+  *APBASE(immr) = AP_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* MPHYST - MPHY status register                                   */
+  /* 0-1   rsvd  00                                                  */
+  /* 2-6   NMPHY 00000 1 PHY                                         */
+  /* 7-9   rsvd  000                                                 */
+  /* 10-14 CMPHY 00000 Initialize with same value as NMPHY           */
+  /*-----------------------------------------------------------------*/
+  *MPHYST(immr) = 0x0000;
+
+  /*-----------------------------------------------------------------*/
+  /* TCTEBASE - Transmit connection table extension base address     */
+  /* Offset from the beginning of DPRAM (32-byte aligned).           */
+  /*-----------------------------------------------------------------*/
+  *TCTEBASE(immr) = TCTE_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* Clear not used registers.                                       */
+  /*-----------------------------------------------------------------*/
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmUtpInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the ATM interface for
+ *
+ * - UTOPIA mode
+ * - muxed bus
+ * - master operation
+ * - multi PHY (because of a bug in the MPC860P rev. E.0)
+ * - internal clock = SYSCLK / 2
+ *
+ * EXTERNAL EFFECTS:
+ *
+ * After calling this function, the MPC860ESAR UTOPIA bus is
+ * active and uses the following ports/pins:
+ *
+ * Port    Pin  Signal   Description
+ * ------  ---  -------  -------------------------------------------
+ * PB[15]  R17  TxClav   Transmit cell available input/output signal
+ * PC[15]  D16  RxClav   Receive cell available input/output signal
+ * PD[15]  U17  UTPB[0]  UTOPIA bus bit 0 input/output signal
+ * PD[14]  V19  UTPB[1]  UTOPIA bus bit 1 input/output signal
+ * PD[13]  V18  UTPB[2]  UTOPIA bus bit 2 input/output signal
+ * PD[12]  R16  UTPB[3]  UTOPIA bus bit 3 input/output signal
+ * PD[11]  T16  RXENB    Receive enable input/output signal
+ * PD[10]  W18  TXENB    Transmit enable input/output signal
+ * PD[9]   V17  UTPCLK   UTOPIA clock input/output signal
+ * PD[7]   T15  UTPB[4]  UTOPIA bus bit 4 input/output signal
+ * PD[6]   V16  UTPB[5]  UTOPIA bus bit 5 input/output signal
+ * PD[5]   U15  UTPB[6]  UTOPIA bus bit 6 input/output signal
+ * PD[4]   U16  UTPB[7]  UTOPIA bus bit 7 input/output signal
+ * PD[3]   W16  SOC      Start of cell input/output signal
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARK:
+ *
+ * The ATM parameters and data structures must be configured before
+ * initializing the UTOPIA port. The UTOPIA port activates immediately
+ * upon initialization, and if its associated data structures are not
+ * initialized, the CPM will lock up.
+ *
+ ****************************************************************************/
+void atmUtpInit()
+{
+  volatile immap_t       *immap  = (immap_t *)CFG_IMMR;
+  volatile iop8xx_t      *iop    = &immap->im_ioport;
+  volatile car8xx_t	 *car    = &immap->im_clkrst;
+  volatile cpm8xx_t	 *cpm    = &immap->im_cpm;
+  int flag;
+
+  flag = disable_interrupts();
+
+  /*-----------------------------------------------------------------*/
+  /* SCCR - System Clock Control Register                            */
+  /*                                                                 */
+  /* The UTOPIA clock can be selected to be internal clock or        */
+  /* external clock (selected by the UTOPIA mode register).          */
+  /* In case of internal clock, the UTOPIA clock is derived from     */
+  /* the system frequency divided by two dividers.                   */
+  /* Bits 27-31 of the SCCR register are defined to control the      */
+  /* UTOPIA clock.                                                   */
+  /*                                                                 */
+  /* SCCR[27:29] DFUTP  Division factor. Divide the system clock     */
+  /*                    by 2^DFUTP.                                  */
+  /* SCCR[30:31] DFAUTP Additional division factor. Divide the       */
+  /*                    system clock by the following value:         */
+  /*                    00 = divide by 1                             */
+  /*                    00 = divide by 3                             */
+  /*                    10 = divide by 5                             */
+  /*                    11 = divide by 7                             */
+  /*                                                                 */
+  /* Note that the UTOPIA clock must be programmed as to operate     */
+  /* within the range SYSCLK/10 .. 50Mhz.                            */
+  /*-----------------------------------------------------------------*/
+  car->car_sccr &= 0xFFFFFFE0;
+  car->car_sccr |= 0x00000008; /* UTPCLK = SYSCLK / 4 */
+
+  /*-----------------------------------------------------------------*/
+  /* RCCR - RISC Controller Configuration Register                   */
+  /*                                                                 */
+  /* RCCR[8]     DR1M IDMA Request 0 Mode                            */
+  /*                  0 = edge sensitive                             */
+  /*                  1 = level sensitive                            */
+  /* RCCR[9]     DR0M IDMA Request 0 Mode                            */
+  /*                  0 = edge sensitive                             */
+  /*                  1 = level sensitive                            */
+  /* RCCR[10:11] DRQP IDMA Request Priority                          */
+  /*                  00 = IDMA req. have more prio. than SCCs       */
+  /*                  01 = IDMA req. have less prio. then SCCs       */
+  /*                  10 = IDMA requests have the lowest prio.       */
+  /*                  11 = reserved                                  */
+  /*                                                                 */
+  /* The RCCR[DR0M] and RCCR[DR1M] bits must be set to enable UTOPIA */
+  /* operation. Also, program RCCR[DPQP] to 01 to give SCC transfers */
+  /* higher priority.                                                */
+  /*-----------------------------------------------------------------*/
+  cpm->cp_rccr &= 0xFF0F;
+  cpm->cp_rccr |= 0x00D0;
+
+  /*-----------------------------------------------------------------*/
+  /* Port B - TxClav Signal                                          */
+  /*-----------------------------------------------------------------*/
+  cpm->cp_pbpar |= 0x00010000; /* PBPAR[15] = 1 */
+  cpm->cp_pbdir &= 0xFFFEFFFF; /* PBDIR[15] = 0 */
+
+  /*-----------------------------------------------------------------*/
+  /* UTOPIA Mode Register                                            */
+  /*                                                                 */
+  /* - muxed bus (master operation only)                             */
+  /* - multi PHY (because of a bug in the MPC860P rev.E.0)           */
+  /* - internal clock                                                */
+  /* - no loopback                                                   */
+  /* - do no activate statistical counters                           */
+  /*-----------------------------------------------------------------*/
+  iop->utmode = 0x00000004; SYNC;
+
+  /*-----------------------------------------------------------------*/
+  /* Port D - UTOPIA Data and Control Signals                        */
+  /*                                                                 */
+  /* 15-12 UTPB[0:3] UTOPIA bus bit 0 - 3 input/output signals       */
+  /* 11    RXENB     UTOPIA receive enable input/output signal       */
+  /* 10    TXENB     UTOPIA transmit enable input/output signal      */
+  /* 9     TUPCLK    UTOPIA clock input/output signal                */
+  /* 8     MII-MDC   Used by MII in simult. MII and UTOPIA operation */
+  /* 7-4   UTPB[4:7] UTOPIA bus bit 4 - 7 input/output signals       */
+  /* 3     SOC       UTOPIA Start of cell input/output signal        */
+  /* 2               Reserved                                        */
+  /* 1               Enable UTOPIA mode                              */
+  /* 0               Enable SAR                                      */
+  /*-----------------------------------------------------------------*/
+  iop->iop_pdpar |= 0xDF7F; SYNC;
+  iop->iop_pddir &= 0x2080; SYNC;
+
+  /*-----------------------------------------------------------------*/
+  /* Port C - RxClav Signal                                          */
+  /*-----------------------------------------------------------------*/
+  iop->iop_pcpar  |= 0x0001; /* PCPAR[15] = 1 */
+  iop->iop_pcdir  &= 0xFFFE; /* PCDIR[15] = 0 */
+  iop->iop_pcso   &= 0xFFFE; /* PCSO[15]  = 0 */
+
+  if (flag)
+    enable_interrupts();
+}
diff --git a/board/siemens/IAD210/flash.c b/board/siemens/IAD210/flash.c
new file mode 100644
index 0000000..1ed5262
--- /dev/null
+++ b/board/siemens/IAD210/flash.c
@@ -0,0 +1,502 @@
+/*
+ * (C) Copyright 2000, 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+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);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+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 & 0xFFFF8000);
+  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]);
+
+  flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+  flash_info[0].size = size;
+
+  return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+  int i;
+
+  /* set up sector start address table */
+  if (info->flash_id & FLASH_BTYPE) {
+    /* 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;
+    }
+  } else {
+    /* 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;
+    }
+  }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+  int i;
+
+  if (info->flash_id == FLASH_UNKNOWN) {
+    printf ("missing or unknown FLASH type\n");
+    return;
+  }
+
+  switch (info->flash_id & FLASH_VENDMASK) {
+  case FLASH_MAN_AMD:	printf ("AMD ");		break;
+  case FLASH_MAN_FUJ:	printf ("FUJITSU ");		break;
+  default:		printf ("Unknown Vendor ");	break;
+  }
+
+  switch (info->flash_id & FLASH_TYPEMASK) {
+  case FLASH_AM400B:	printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM400T:	printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+    break;
+  case FLASH_AM800B:	printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM800T:	printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+    break;
+  case FLASH_AM160B:	printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM160T:	printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+    break;
+  case FLASH_AM320B:	printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM320T:	printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+    break;
+  default:		printf ("Unknown Chip Type\n");
+    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");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * 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		*/
+#if 0	/* enable when device IDs are available */
+  case AMD_ID_LV320T:
+    info->flash_id += FLASH_AM320T;
+    info->sector_count = 67;
+    info->size = 0x00800000;
+    break;				/* => 8 MB		*/
+
+  case AMD_ID_LV320B:
+    info->flash_id += FLASH_AM320B;
+    info->sector_count = 67;
+    info->size = 0x00800000;
+    break;				/* => 8 MB		*/
+#endif
+  default:
+    info->flash_id = FLASH_UNKNOWN;
+    return (0);			/* => no or unknown flash */
+
+  }
+
+  /* set up sector start address table */
+  if (info->flash_id & FLASH_BTYPE) {
+    /* 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;
+    }
+  } else {
+    /* 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;
+    }
+  }
+
+  /* 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) {
+      printf ("- missing\n");
+    } else {
+      printf ("- 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 {
+    printf ("\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) {
+      printf ("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 */
+
+  printf (" 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/siemens/SCM/flash.c b/board/siemens/SCM/flash.c
new file mode 100644
index 0000000..dd7a4cc
--- /dev/null
+++ b/board/siemens/SCM/flash.c
@@ -0,0 +1,488 @@
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD devices on the TQM8260 board
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#define V_ULONG(a)	(*(volatile unsigned long *)( a ))
+#define V_BYTE(a)	(*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset (void)
+{
+	if (flash_info[0].flash_id != FLASH_UNKNOWN) {
+		V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
+		V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
+	}
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size (ulong baseaddr, flash_info_t * info)
+{
+	short i;
+	unsigned long flashtest_h, flashtest_l;
+
+	/* Write auto select command sequence and test FLASH answer */
+	V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
+	V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
+	V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
+	V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
+
+	flashtest_h = V_ULONG (baseaddr);	/* manufacturer ID     */
+	flashtest_l = V_ULONG (baseaddr + 4);
+
+	switch ((int) flashtest_h) {
+	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     */
+	}
+
+	flashtest_h = V_ULONG (baseaddr + 8);	/* device ID           */
+	flashtest_l = V_ULONG (baseaddr + 12);
+	if (flashtest_h != flashtest_l) {
+		info->flash_id = FLASH_UNKNOWN;
+	} else {
+		switch (flashtest_h) {
+		case AMD_ID_LV800T:
+			info->flash_id += FLASH_AM800T;
+			info->sector_count = 19;
+			info->size = 0x00400000;
+			break;			/* 4 * 1 MB = 4 MB  */
+		case AMD_ID_LV800B:
+			info->flash_id += FLASH_AM800B;
+			info->sector_count = 19;
+			info->size = 0x00400000;
+			break;			/* 4 * 1 MB = 4 MB  */
+		case AMD_ID_LV160T:
+			info->flash_id += FLASH_AM160T;
+			info->sector_count = 35;
+			info->size = 0x00800000;
+			break;			/* 4 * 2 MB = 8 MB  */
+		case AMD_ID_LV160B:
+			info->flash_id += FLASH_AM160B;
+			info->sector_count = 35;
+			info->size = 0x00800000;
+			break;			/* 4 * 2 MB = 8 MB  */
+		case AMD_ID_DL322T:
+			info->flash_id += FLASH_AMDL322T;
+			info->sector_count = 71;
+			info->size = 0x01000000;
+			break;			/* 4 * 4 MB = 16 MB */
+		case AMD_ID_DL322B:
+			info->flash_id += FLASH_AMDL322B;
+			info->sector_count = 71;
+			info->size = 0x01000000;
+			break;			/* 4 * 4 MB = 16 MB */
+		case AMD_ID_DL323T:
+			info->flash_id += FLASH_AMDL323T;
+			info->sector_count = 71;
+			info->size = 0x01000000;
+			break;			/* 4 * 4 MB = 16 MB */
+		case AMD_ID_DL323B:
+			info->flash_id += FLASH_AMDL323B;
+			info->sector_count = 71;
+			info->size = 0x01000000;
+			break;			/* 4 * 4 MB = 16 MB */
+		case AMD_ID_LV640U:
+			info->flash_id += FLASH_AM640U;
+			info->sector_count = 128;
+			info->size = 0x02000000;
+			break;			/* 4 * 8 MB = 32 MB */
+		default:
+			info->flash_id = FLASH_UNKNOWN;
+			return (0);		/* no or unknown flash     */
+		}
+	}
+
+	if (flashtest_h == AMD_ID_LV640U) {
+
+		/* set up sector start adress table (uniform sector type) */
+		for (i = 0; i < info->sector_count; i++)
+			info->start[i] = baseaddr + (i * 0x00040000);
+
+	} else if (info->flash_id & FLASH_BTYPE) {
+
+		/* set up sector start adress table (bottom sector type) */
+		info->start[0] = baseaddr + 0x00000000;
+		info->start[1] = baseaddr + 0x00010000;
+		info->start[2] = baseaddr + 0x00018000;
+		info->start[3] = baseaddr + 0x00020000;
+		for (i = 4; i < info->sector_count; i++) {
+			info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
+		}
+
+	} else {
+
+		/* set up sector start adress table (top sector type) */
+		i = info->sector_count - 1;
+		info->start[i--] = baseaddr + info->size - 0x00010000;
+		info->start[i--] = baseaddr + info->size - 0x00018000;
+		info->start[i--] = baseaddr + info->size - 0x00020000;
+		for (; i >= 0; i--) {
+			info->start[i] = baseaddr + i * 0x00040000;
+		}
+	}
+
+	/* check for protected sectors */
+	for (i = 0; i < info->sector_count; i++) {
+		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
+		if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
+			(V_ULONG (info->start[i] + 20) & 0x00010001)) {
+			info->protect[i] = 1;	/* D0 = 1 if protected */
+		} else {
+			info->protect[i] = 0;
+		}
+	}
+
+	flash_reset ();
+	return (info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+	unsigned long size_b0 = 0;
+	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 (only one bank) */
+
+	size_b0 = flash_get_size (CFG_FLASH0_BASE, &flash_info[0]);
+	if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+		printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+				size_b0, size_b0 >> 20);
+	}
+
+	/*
+	 * protect monitor and environment sectors
+	 */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_MONITOR_BASE,
+		       CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE	CFG_ENV_SECT_SIZE
+# endif
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_ENV_ADDR,
+		       CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+#endif
+
+	return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_AMD:
+		printf ("AMD ");
+		break;
+	case FLASH_MAN_FUJ:
+		printf ("FUJITSU ");
+		break;
+	default:
+		printf ("Unknown Vendor ");
+		break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_AM800T:
+		printf ("29LV800T (8 M, top sector)\n");
+		break;
+	case FLASH_AM800B:
+		printf ("29LV800T (8 M, bottom sector)\n");
+		break;
+	case FLASH_AM160T:
+		printf ("29LV160T (16 M, top sector)\n");
+		break;
+	case FLASH_AM160B:
+		printf ("29LV160B (16 M, bottom sector)\n");
+		break;
+	case FLASH_AMDL322T:
+		printf ("29DL322T (32 M, top sector)\n");
+		break;
+	case FLASH_AMDL322B:
+		printf ("29DL322B (32 M, bottom sector)\n");
+		break;
+	case FLASH_AMDL323T:
+		printf ("29DL323T (32 M, top sector)\n");
+		break;
+	case FLASH_AMDL323B:
+		printf ("29DL323B (32 M, bottom sector)\n");
+		break;
+	case FLASH_AM640U:
+		printf ("29LV640D (64 M, uniform sector)\n");
+		break;
+	default:
+		printf ("Unknown Chip Type\n");
+		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");
+	return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+	int flag, prot, sect, l_sect;
+	ulong start, now, last;
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		if (info->flash_id == FLASH_UNKNOWN) {
+			printf ("- missing\n");
+		} else {
+			printf ("- no sectors to erase\n");
+		}
+		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 {
+		printf ("\n");
+	}
+
+	l_sect = -1;
+
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts ();
+
+	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
+	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
+	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+	udelay (1000);
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect <= s_last; sect++) {
+		if (info->protect[sect] == 0) {	/* not protected */
+			V_ULONG (info->start[sect]) = 0x00300030;
+			V_ULONG (info->start[sect] + 4) = 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;
+	while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
+	       (V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
+	{
+		if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
+			printf ("Timeout\n");
+			return 1;
+		}
+		/* show that we're waiting */
+		if ((now - last) > 1000) {	/* every second */
+			serial_putc ('.');
+			last = now;
+		}
+	}
+
+  DONE:
+	/* reset to read mode */
+	flash_reset ();
+
+	printf (" done\n");
+	return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * 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 dp;
+	static unsigned char bb[8];
+	int i, l, rc, cc = cnt;
+
+	dp = (addr & ~7);		/* get lower dword aligned address */
+
+	/*
+	 * handle unaligned start bytes
+	 */
+	if ((l = addr - dp) != 0) {
+		for (i = 0; i < 8; i++)
+			bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
+		if ((rc = write_dword (info, dp, bb)) != 0) {
+			return (rc);
+		}
+		dp += 8;
+		cc -= 8 - l;
+	}
+
+	/*
+	 * handle word aligned part
+	 */
+	while (cc >= 8) {
+		if ((rc = write_dword (info, dp, src)) != 0) {
+			return (rc);
+		}
+		dp += 8;
+		src += 8;
+		cc -= 8;
+	}
+
+	if (cc <= 0) {
+		return (0);
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	for (i = 0; i < 8; i++) {
+		bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
+	}
+	return (write_dword (info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
+{
+	ulong start, cl, ch;
+	int flag, i;
+
+	for (ch = 0, i = 0; i < 4; i++)
+		ch = (ch << 8) + *pdata++;	/* high word    */
+	for (cl = 0, i = 0; i < 4; i++)
+		cl = (cl << 8) + *pdata++;	/* low word */
+
+	/* Check if Flash is (sufficiently) erased */
+	if ((*((vu_long *) dest) & ch) != ch
+		|| (*((vu_long *) (dest + 4)) & cl) != cl) {
+		return (2);
+	}
+
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts ();
+
+	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
+	V_ULONG (dest) = ch;
+	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+	V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
+	V_ULONG (dest + 4) = cl;
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts ();
+
+	/* data polling for D7 */
+	start = get_timer (0);
+	while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
+		   ((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
+		if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+			return (1);
+		}
+	}
+	return (0);
+}
diff --git a/board/siemens/pcu_e/flash.c b/board/siemens/pcu_e/flash.c
new file mode 100644
index 0000000..b8c0df7
--- /dev/null
+++ b/board/siemens/pcu_e/flash.c
@@ -0,0 +1,700 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR	(CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE	CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#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_data (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ *
+ * The PCU E uses an address map where flash banks are aligned top
+ * down, so that the "first" flash bank ends at top of memory, and
+ * the monitor entry point is at address (0xFFF00100). The second
+ * flash bank is mapped immediately below bank 0.
+ *
+ * This is NOT in conformance to the "official" memory map!
+ *
+ */
+
+#define PCU_MONITOR_BASE   ( (flash_info[0].start[0] + flash_info[0].size - 1) \
+			   - (0xFFFFFFFF - CFG_MONITOR_BASE) )
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+	volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	unsigned long base, size_b0, size_b1;
+	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 */
+
+	/*
+	 * Warning:
+	 *
+	 * Since the PCU E memory map assigns flash banks top down,
+	 * we swap the numbering later if both banks are equipped,
+	 * so they look like a contiguous area of memory.
+	 */
+	DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+	size_b0 = 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_b0, size_b0<<20);
+	}
+
+	DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE6_PRELIM);
+	size_b1 = flash_get_size((vu_long *)FLASH_BASE6_PRELIM, &flash_info[1]);
+
+	DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n", size_b0, size_b1);
+
+	if (size_b1 > size_b0) {
+		printf ("## ERROR: "
+			"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+			size_b1, size_b1<<20,
+			size_b0, size_b0<<20
+		);
+		flash_info[0].flash_id	= FLASH_UNKNOWN;
+		flash_info[1].flash_id	= FLASH_UNKNOWN;
+		flash_info[0].sector_count	= -1;
+		flash_info[1].sector_count	= -1;
+		flash_info[0].size		= 0;
+		flash_info[1].size		= 0;
+		return (0);
+	}
+
+	DEBUGF ("## Before remap: "
+		"BR0: 0x%08x    OR0: 0x%08x    "
+		"BR6: 0x%08x    OR6: 0x%08x\n",
+		memctl->memc_br0, memctl->memc_or0,
+		memctl->memc_br6, memctl->memc_or6);
+
+	/* Remap FLASH according to real size */
+	base = 0 - size_b0;
+	memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+	memctl->memc_br0 = (base & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+	DEBUGF("## BR0: 0x%08x    OR0: 0x%08x\n",
+		memctl->memc_br0, memctl->memc_or0);
+
+	/* Re-do sizing to get full correct info */
+	size_b0 = flash_get_size((vu_long *)base, &flash_info[0]);
+	base = 0 - size_b0;
+
+	flash_info[0].size = size_b0;
+
+	flash_get_offsets (base, &flash_info[0]);
+
+	/* monitor protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      PCU_MONITOR_BASE,
+		      PCU_MONITOR_BASE+CFG_MONITOR_LEN-1,
+		      &flash_info[0]);
+
+#ifdef	CFG_ENV_IS_IN_FLASH
+	/* ENV protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_ENV_ADDR,
+		      CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+		      &flash_info[0]);
+#endif
+
+	if (size_b1) {
+		flash_info_t tmp_info;
+
+		memctl->memc_or6 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+		memctl->memc_br6 = ((base - size_b1) & BR_BA_MSK) |
+				    BR_PS_16 | BR_MS_GPCM | BR_V;
+
+		DEBUGF("## New BR6: 0x%08x    OR6: 0x%08x\n",
+			memctl->memc_br6, memctl->memc_or6);
+
+		/* Re-do sizing to get full correct info */
+		size_b1 = flash_get_size((vu_long *)(base - size_b1),
+					  &flash_info[1]);
+		base -= size_b1;
+
+		flash_get_offsets (base, &flash_info[1]);
+
+		flash_info[1].size = size_b1;
+
+#ifdef	CFG_ENV_IS_IN_FLASH
+		/* ENV protection ON by default */
+		flash_protect(FLAG_PROTECT_SET,
+			      CFG_ENV_ADDR,
+			      CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+			      &flash_info[1]);
+#endif
+		/*
+		 * Swap bank numbers so that addresses are in ascending order
+		 */
+		tmp_info = flash_info[0];
+		flash_info[0] = flash_info[1];
+		flash_info[1] = tmp_info;
+	} else {
+		memctl->memc_br1 = 0;		/* invalidate bank */
+
+		flash_info[1].flash_id = FLASH_UNKNOWN;
+		flash_info[1].sector_count = -1;
+	}
+
+
+	DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+	return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+	int i;
+	short n;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		return;
+	}
+
+	if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_AMD) {
+		return;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_AMDL322T:
+	case FLASH_AMDL323T:
+	case FLASH_AMDL324T:
+		/* set sector offsets for top boot block type		*/
+
+		base += info->size;
+		i = info->sector_count;
+		for (n=0; n<8; ++n) {		/*  8 x 8k boot sectors	*/
+			base -= 8 << 10;
+			--i;
+			info->start[i] = base;
+		}
+		while (i > 0) {			/* 64k regular sectors	*/
+			base -= 64 << 10;
+			--i;
+			info->start[i] = base;
+		}
+		return;
+	case FLASH_AMDL322B:
+	case FLASH_AMDL323B:
+	case FLASH_AMDL324B:
+		/* set sector offsets for bottom boot block type	*/
+		for (i=0; i<8; ++i) {		/*  8 x 8k boot sectors	*/
+			info->start[i] = base;
+			base += 8 << 10;
+		}
+		while (base < info->size) {	/* 64k regular sectors	*/
+			info->start[i] = base;
+			base += 64 << 10;
+			++i;
+		}
+		return;
+	case FLASH_AMDL640:
+		/* set sector offsets for dual boot block type		*/
+		for (i=0; i<8; ++i) {		/*  8 x 8k boot sectors	*/
+			info->start[i] = base;
+			base += 8 << 10;
+		}
+		n = info->sector_count - 8;
+		while (i < n) {			/* 64k regular sectors	*/
+			info->start[i] = base;
+			base += 64 << 10;
+			++i;
+		}
+		while (i < info->sector_count) { /* 8 x 8k boot sectors	*/
+			info->start[i] = base;
+			base += 8 << 10;
+			++i;
+		}
+		return;
+	default:
+		return;
+	}
+	/* NOTREACHED */
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_AMD:	printf ("AMD ");		break;
+	case FLASH_MAN_FUJ:	printf ("FUJITSU ");		break;
+	default:		printf ("Unknown Vendor ");	break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_AMDL322B:	printf ("AM29DL322B (32 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AMDL322T:	printf ("AM29DL322T (32 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AMDL323B:	printf ("AM29DL323B (32 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AMDL323T:	printf ("AM29DL323T (32 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AMDL324B:	printf ("AM29DL324B (32 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AMDL324T:	printf ("AM29DL324T (32 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AMDL640:	printf ("AM29DL640D (64 Mbit, dual boot sector)\n");
+				break;
+	default:		printf ("Unknown Chip Type 0x%lX\n",
+					info->flash_id);
+				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");
+	return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+	short i;
+	ushort value;
+	vu_short *saddr = (vu_short *)addr;
+
+	/* Write auto select command: read Manufacturer ID */
+	saddr[0x0555] = 0x00AA;
+	saddr[0x02AA] = 0x0055;
+	saddr[0x0555] = 0x0090;
+
+	value = saddr[0];
+
+	DEBUGF("Manuf. ID @ 0x%08lx: 0x%04x\n", (ulong)addr, value);
+
+	switch (value) {
+	case (AMD_MANUFACT & 0xFFFF):
+		info->flash_id = FLASH_MAN_AMD;
+		break;
+	case (FUJ_MANUFACT & 0xFFFF):
+		info->flash_id = FLASH_MAN_FUJ;
+		break;
+	default:
+		DEBUGF("Unknown Manufacturer ID\n");
+		info->flash_id = FLASH_UNKNOWN;
+		info->sector_count = 0;
+		info->size = 0;
+		return (0);			/* no or unknown flash	*/
+	}
+
+	value = saddr[1];			/* device ID		*/
+
+	DEBUGF("Device ID @ 0x%08lx: 0x%04x\n", (ulong)(&addr[1]), value);
+
+	switch (value) {
+
+	case (AMD_ID_DL322T & 0xFFFF):
+		info->flash_id += FLASH_AMDL322T;
+		info->sector_count = 71;
+		info->size = 0x00400000;
+		break;				/* => 8 MB		*/
+
+	case (AMD_ID_DL322B & 0xFFFF):
+		info->flash_id += FLASH_AMDL322B;
+		info->sector_count = 71;
+		info->size = 0x00400000;
+		break;				/* => 8 MB		*/
+
+	case (AMD_ID_DL323T & 0xFFFF):
+		info->flash_id += FLASH_AMDL323T;
+		info->sector_count = 71;
+		info->size = 0x00400000;
+		break;				/* => 8 MB		*/
+
+	case (AMD_ID_DL323B & 0xFFFF):
+		info->flash_id += FLASH_AMDL323B;
+		info->sector_count = 71;
+		info->size = 0x00400000;
+		break;				/* => 8 MB		*/
+
+	case (AMD_ID_DL324T & 0xFFFF):
+		info->flash_id += FLASH_AMDL324T;
+		info->sector_count = 71;
+		info->size = 0x00400000;
+		break;				/* => 8 MB		*/
+
+	case (AMD_ID_DL324B & 0xFFFF):
+		info->flash_id += FLASH_AMDL324B;
+		info->sector_count = 71;
+		info->size = 0x00400000;
+		break;				/* => 8 MB		*/
+	case (AMD_ID_DL640  & 0xFFFF):
+		info->flash_id += FLASH_AMDL640;
+		info->sector_count = 142;
+		info->size = 0x00800000;
+		break;
+	default:
+		DEBUGF("Unknown Device ID\n");
+		info->flash_id = FLASH_UNKNOWN;
+		return (0);			/* => no or unknown flash */
+
+	}
+
+	flash_get_offsets ((ulong)addr, info);
+
+	/* check for protected sectors */
+	for (i = 0; i < info->sector_count; i++) {
+#if 0
+		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
+		/* D0 = 1 if protected */
+		saddr = (vu_short *)(info->start[i]);
+		info->protect[i] = saddr[2] & 1;
+#else
+		info->protect[i] =0;
+#endif
+	}
+
+	if (info->sector_count > CFG_MAX_FLASH_SECT) {
+		printf ("** ERROR: sector count %d > max (%d) **\n",
+			info->sector_count, CFG_MAX_FLASH_SECT);
+		info->sector_count = CFG_MAX_FLASH_SECT;
+	}
+
+	saddr = (vu_short *)info->start[0];
+	*saddr = 0x00F0;	/* restore read mode */
+
+	return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int	flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+	vu_short *addr = (vu_short*)(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) {
+			printf ("- missing\n");
+		} else {
+			printf ("- 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 {
+		printf ("\n");
+	}
+
+	l_sect = -1;
+
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	addr[0x0555] = 0x00AA;
+	addr[0x02AA] = 0x0055;
+	addr[0x0555] = 0x0080;
+	addr[0x0555] = 0x00AA;
+	addr[0x02AA] = 0x0055;
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect<=s_last; sect++) {
+		if (info->protect[sect] == 0) {	/* not protected */
+			addr = (vu_short*)(info->start[sect]);
+			addr[0] = 0x0030;
+			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_short*)(info->start[l_sect]);
+	while ((addr[0] & 0x0080) != 0x0080) {
+		if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+			printf ("Timeout\n");
+			return 1;
+		}
+		/* show that we're waiting */
+		if ((now - last) > 1000) {	/* every second */
+			putc ('.');
+			last = now;
+		}
+	}
+
+DONE:
+	/* reset to read mode */
+	addr = (vu_short *)info->start[0];
+	addr[0] = 0x00F0;	/* reset bank */
+
+	printf (" done\n");
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+#define FLASH_WIDTH	2	/* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+	ulong cp, wp, data;
+	int i, l, rc;
+
+	wp = (addr & ~(FLASH_WIDTH-1));	/* get lower FLASH_WIDTH 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<FLASH_WIDTH && cnt>0; ++i) {
+			data = (data << 8) | *src++;
+			--cnt;
+			++cp;
+		}
+		for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
+			data = (data << 8) | (*(uchar *)cp);
+		}
+
+		if ((rc = write_data(info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp += FLASH_WIDTH;
+	}
+
+	/*
+	 * handle FLASH_WIDTH aligned part
+	 */
+	while (cnt >= FLASH_WIDTH) {
+		data = 0;
+		for (i=0; i<FLASH_WIDTH; ++i) {
+			data = (data << 8) | *src++;
+		}
+		if ((rc = write_data(info, wp, data)) != 0) {
+			return (rc);
+		}
+		wp  += FLASH_WIDTH;
+		cnt -= FLASH_WIDTH;
+	}
+
+	if (cnt == 0) {
+		return (0);
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	data = 0;
+	for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
+		data = (data << 8) | *src++;
+		--cnt;
+	}
+	for (; i<FLASH_WIDTH; ++i, ++cp) {
+		data = (data << 8) | (*(uchar *)cp);
+	}
+
+	return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong data)
+{
+	vu_short *addr  = (vu_short*)(info->start[0]);
+	vu_short *sdest = (vu_short *)dest;
+	ushort sdata = (ushort)data;
+	ushort sval;
+	ulong start, passed;
+	int flag, rc;
+
+	/* Check if Flash is (sufficiently) erased */
+	if ((*sdest & sdata) != sdata) {
+		return (2);
+	}
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	addr[0x0555] = 0x00AA;
+	addr[0x02AA] = 0x0055;
+	addr[0x0555] = 0x00A0;
+
+#ifdef WORKAROUND_FOR_BROKEN_HARDWARE
+	/* work around the timeout bugs */
+	udelay(20);
+#endif
+
+	*sdest = sdata;
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts();
+
+	rc = 0;
+	/* data polling for D7 */
+	start = get_timer (0);
+
+	for (passed=0; passed < CFG_FLASH_WRITE_TOUT; passed=get_timer(start)) {
+
+		sval = *sdest;
+
+		if ((sval & 0x0080) == (sdata & 0x0080))
+			break;
+
+		if ((sval & 0x0020) == 0)	/* DQ5: Timeout? */
+			continue;
+
+		sval = *sdest;
+
+		if ((sval & 0x0080) != (sdata & 0x0080))
+			rc = 1;
+
+		break;
+	}
+
+	if (rc) {
+	    DEBUGF ("Program cycle failed @ addr 0x%08lX: val %04X data %04X\n",
+		 dest, sval, sdata);
+	}
+
+	if (passed >= CFG_FLASH_WRITE_TOUT) {
+		DEBUGF ("Timeout @ addr 0x%08lX: val %04X data %04X\n",
+			dest, sval, sdata);
+		rc = 1;
+	}
+
+	/* reset to read mode */
+	addr = (vu_short *)info->start[0];
+	addr[0] = 0x00F0;	/* reset bank */
+
+	return (rc);
+}
+
+/*-----------------------------------------------------------------------
+ */