Initial revision
diff --git a/common/cmd_doc.c b/common/cmd_doc.c
new file mode 100644
index 0000000..37d0fbd
--- /dev/null
+++ b/common/cmd_doc.c
@@ -0,0 +1,1563 @@
+/*
+ * Driver for Disk-On-Chip 2000 and Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/doc2000.h>
+#include <linux/mtd/nftl.h>
+
+#ifdef CFG_DOC_SUPPORT_2000
+#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
+#else
+#define DoC_is_2000(doc) (0)
+#endif
+
+#ifdef CFG_DOC_SUPPORT_MILLENNIUM
+#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
+#else
+#define DoC_is_Millennium(doc) (0)
+#endif
+
+/* CFG_DOC_PASSIVE_PROBE:
+   In order to ensure that the BIOS checksum is correct at boot time, and
+   hence that the onboard BIOS extension gets executed, the DiskOnChip
+   goes into reset mode when it is read sequentially: all registers
+   return 0xff until the chip is woken up again by writing to the
+   DOCControl register.
+
+   Unfortunately, this means that the probe for the DiskOnChip is unsafe,
+   because one of the first things it does is write to where it thinks
+   the DOCControl register should be - which may well be shared memory
+   for another device. I've had machines which lock up when this is
+   attempted. Hence the possibility to do a passive probe, which will fail
+   to detect a chip in reset mode, but is at least guaranteed not to lock
+   the machine.
+
+   If you have this problem, uncomment the following line:
+#define CFG_DOC_PASSIVE_PROBE
+*/
+
+#undef	DOC_DEBUG
+#undef	ECC_DEBUG
+#undef	PSYCHO_DEBUG
+#undef	NFTL_DEBUG
+
+static struct DiskOnChip doc_dev_desc[CFG_MAX_DOC_DEVICE];
+
+/* Current DOC Device	*/
+static int curr_device = -1;
+
+/* ------------------------------------------------------------------------- */
+
+int do_doc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    int rcode = 0;
+
+    switch (argc) {
+    case 0:
+    case 1:
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    case 2:
+        if (strcmp(argv[1],"info") == 0) {
+		int i;
+
+		putc ('\n');
+
+		for (i=0; i<CFG_MAX_DOC_DEVICE; ++i) {
+			if(doc_dev_desc[i].ChipID == DOC_ChipID_UNKNOWN)
+				continue; /* list only known devices */
+			printf ("Device %d: ", i);
+			doc_print(&doc_dev_desc[i]);
+		}
+		return 0;
+
+	} else if (strcmp(argv[1],"device") == 0) {
+		if ((curr_device < 0) || (curr_device >= CFG_MAX_DOC_DEVICE)) {
+			puts ("\nno devices available\n");
+			return 1;
+		}
+		printf ("\nDevice %d: ", curr_device);
+		doc_print(&doc_dev_desc[curr_device]);
+		return 0;
+	}
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    case 3:
+	if (strcmp(argv[1],"device") == 0) {
+		int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+		printf ("\nDevice %d: ", dev);
+		if (dev >= CFG_MAX_DOC_DEVICE) {
+			puts ("unknown device\n");
+			return 1;
+		}
+		doc_print(&doc_dev_desc[dev]);
+		/*doc_print (dev);*/
+
+		if (doc_dev_desc[dev].ChipID == DOC_ChipID_UNKNOWN) {
+			return 1;
+		}
+
+		curr_device = dev;
+
+		puts ("... is now current device\n");
+
+		return 0;
+	}
+
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    default:
+	/* at least 4 args */
+
+	if (strcmp(argv[1],"read") == 0 || strcmp(argv[1],"write") == 0) {
+		ulong addr = simple_strtoul(argv[2], NULL, 16);
+		ulong off  = simple_strtoul(argv[3], NULL, 16);
+		ulong size = simple_strtoul(argv[4], NULL, 16);
+		int cmd    = (strcmp(argv[1],"read") == 0);
+		int ret, total;
+
+		printf ("\nDOC %s: device %d offset %ld, size %ld ... ",
+			cmd ? "read" : "write", curr_device, off, size);
+
+		ret = doc_rw(doc_dev_desc + curr_device, cmd, off, size,
+			     &total, (u_char*)addr);
+
+		printf ("%d bytes %s: %s\n", total, cmd ? "read" : "write",
+			ret ? "ERROR" : "OK");
+
+		return ret;
+	} else if (strcmp(argv[1],"erase") == 0) {
+		ulong off = simple_strtoul(argv[2], NULL, 16);
+		ulong size = simple_strtoul(argv[3], NULL, 16);
+		int ret;
+
+		printf ("\nDOC erase: device %d offset %ld, size %ld ... ",
+			curr_device, off, size);
+
+		ret = doc_erase (doc_dev_desc + curr_device, off, size);
+
+		printf("%s\n", ret ? "ERROR" : "OK");
+
+		return ret;
+	} else {
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		rcode = 1;
+	}
+
+	return rcode;
+    }
+}
+
+int do_docboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *boot_device = NULL;
+	char *ep;
+	int dev;
+	ulong cnt;
+	ulong addr;
+	ulong offset = 0;
+	image_header_t *hdr;
+	int rcode = 0;
+
+	switch (argc) {
+	case 1:
+		addr = CFG_LOAD_ADDR;
+		boot_device = getenv ("bootdevice");
+		break;
+	case 2:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = getenv ("bootdevice");
+		break;
+	case 3:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = argv[2];
+		break;
+	case 4:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = argv[2];
+		offset = simple_strtoul(argv[3], NULL, 16);
+		break;
+	default:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (!boot_device) {
+		puts ("\n** No boot device **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	dev = simple_strtoul(boot_device, &ep, 16);
+
+	if ((dev >= CFG_MAX_DOC_DEVICE) ||
+	    (doc_dev_desc[dev].ChipID == DOC_ChipID_UNKNOWN)) {
+		printf ("\n** Device %d not available\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	printf ("\nLoading from device %d: %s at 0x%lX (offset 0x%lX)\n",
+		dev, doc_dev_desc[dev].name, doc_dev_desc[dev].physadr,
+		offset);
+
+	if (doc_rw (doc_dev_desc + dev, 1, offset,
+		    SECTORSIZE, NULL, (u_char *)addr)) {
+		printf ("** Read error on %d\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	hdr = (image_header_t *)addr;
+
+	if (hdr->ih_magic == IH_MAGIC) {
+
+		print_image_hdr (hdr);
+
+		cnt = (hdr->ih_size + sizeof(image_header_t));
+		cnt -= SECTORSIZE;
+	} else {
+		puts ("\n** Bad Magic Number **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (doc_rw (doc_dev_desc + dev, 1, offset + SECTORSIZE, cnt,
+		    NULL, (u_char *)(addr+SECTORSIZE))) {
+		printf ("** Read error on %d\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	/* Loading ok, update default load address */
+
+	load_addr = addr;
+
+	/* Check if we should attempt an auto-start */
+	if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+		char *local_args[2];
+		extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
+
+		local_args[0] = argv[0];
+		local_args[1] = NULL;
+
+		printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+
+		do_bootm (cmdtp, 0, 1, local_args);
+		rcode = 1;
+	}
+	return rcode;
+}
+
+int doc_rw (struct DiskOnChip* this, int cmd,
+	    loff_t from, size_t len,
+	    size_t * retlen, u_char * buf)
+{
+	int noecc, ret = 0, n, total = 0;
+	char eccbuf[6];
+
+	while(len) {
+		/* The ECC will not be calculated correctly if
+		   less than 512 is written or read */
+		noecc = (from != (from | 0x1ff) + 1) ||	(len < 0x200);
+
+		if (cmd)
+			ret = doc_read_ecc(this, from, len,
+					   &n, (u_char*)buf,
+					   noecc ? NULL : eccbuf);
+		else
+			ret = doc_write_ecc(this, from, len,
+					    &n, (u_char*)buf,
+					    noecc ? NULL : eccbuf);
+
+		if (ret)
+			break;
+
+		from  += n;
+		buf   += n;
+		total += n;
+		len   -= n;
+	}
+
+	if (retlen)
+		*retlen = total;
+
+	return ret;
+}
+
+void doc_print(struct DiskOnChip *this) {
+	printf("%s at 0x%lX,\n"
+	       "\t  %d chip%s %s, size %d MB, \n"
+	       "\t  total size %ld MB, sector size %ld kB\n",
+	       this->name, this->physadr, this->numchips,
+	       this->numchips>1 ? "s" : "", this->chips_name,
+	       1 << (this->chipshift - 20),
+	       this->totlen >> 20, this->erasesize >> 10);
+
+	if (this->nftl_found) {
+		struct NFTLrecord *nftl = &this->nftl;
+		unsigned long bin_size, flash_size;
+
+		bin_size = nftl->nb_boot_blocks * this->erasesize;
+		flash_size = (nftl->nb_blocks - nftl->nb_boot_blocks) * this->erasesize;
+
+		printf("\t  NFTL boot record:\n"
+		       "\t    Binary partition: size %ld%s\n"
+		       "\t    Flash disk partition: size %ld%s, offset 0x%lx\n",
+		       bin_size > (1 << 20) ? bin_size >> 20 : bin_size >> 10,
+		       bin_size > (1 << 20) ? "MB" : "kB",
+		       flash_size > (1 << 20) ? flash_size >> 20 : flash_size >> 10,
+		       flash_size > (1 << 20) ? "MB" : "kB", bin_size);
+	} else {
+		puts ("\t  No NFTL boot record found.\n");
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* This function is needed to avoid calls of the __ashrdi3 function. */
+static int shr(int val, int shift) {
+	return val >> shift;
+}
+
+/* Perform the required delay cycles by reading from the appropriate register */
+static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles)
+{
+	volatile char dummy;
+	int i;
+
+	for (i = 0; i < cycles; i++) {
+		if (DoC_is_Millennium(doc))
+			dummy = ReadDOC(doc->virtadr, NOP);
+		else
+			dummy = ReadDOC(doc->virtadr, DOCStatus);
+	}
+
+}
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(struct DiskOnChip *doc)
+{
+	unsigned long docptr = doc->virtadr;
+	unsigned long start = get_timer(0);
+
+#ifdef PSYCHO_DEBUG
+	puts ("_DoC_WaitReady called for out-of-line wait\n");
+#endif
+
+	/* Out-of-line routine to wait for chip response */
+	while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+#ifdef CFG_DOC_SHORT_TIMEOUT
+		/* it seems that after a certain time the DoC deasserts
+		 * the CDSN_CTRL_FR_B although it is not ready...
+		 * using a short timout solve this (timer increments every ms) */
+		if (get_timer(start) > 10) {
+			return DOC_ETIMEOUT;
+		}
+#else
+		if (get_timer(start) > 10 * 1000) {
+			puts ("_DoC_WaitReady timed out.\n");
+			return DOC_ETIMEOUT;
+		}
+#endif
+		udelay(1);
+        }
+
+	return 0;
+}
+
+static int DoC_WaitReady(struct DiskOnChip *doc)
+{
+	unsigned long docptr = doc->virtadr;
+	/* This is inline, to optimise the common case, where it's ready instantly */
+	int ret = 0;
+
+	/* 4 read form NOP register should be issued in prior to the read from CDSNControl
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(doc, 4);
+
+	if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+		/* Call the out-of-line routine to wait */
+		ret = _DoC_WaitReady(doc);
+
+	/* issue 2 read from NOP register after reading from CDSNControl register
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(doc, 2);
+
+	return ret;
+}
+
+/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+			      unsigned char xtraflags)
+{
+	unsigned long docptr = doc->virtadr;
+
+	if (DoC_is_2000(doc))
+		xtraflags |= CDSN_CTRL_FLASH_IO;
+
+	/* Assert the CLE (Command Latch Enable) line to the flash chip */
+	WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	if (DoC_is_Millennium(doc))
+		WriteDOC(command, docptr, CDSNSlowIO);
+
+	/* Send the command */
+	WriteDOC_(command, docptr, doc->ioreg);
+
+	/* Lower the CLE line */
+	WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
+	return DoC_WaitReady(doc);
+}
+
+/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
+		       unsigned char xtraflags1, unsigned char xtraflags2)
+{
+	unsigned long docptr;
+	int i;
+
+	docptr = doc->virtadr;
+
+	if (DoC_is_2000(doc))
+		xtraflags1 |= CDSN_CTRL_FLASH_IO;
+
+	/* Assert the ALE (Address Latch Enable) line to the flash chip */
+	WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Send the address */
+	/* Devices with 256-byte page are addressed as:
+	   Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+	   * there is no device on the market with page256
+	   and more than 24 bits.
+	   Devices with 512-byte page are addressed as:
+	   Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+	   * 25-31 is sent only if the chip support it.
+	   * bit 8 changes the read command to be sent
+	   (NAND_CMD_READ0 or NAND_CMD_READ1).
+	 */
+
+	if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) {
+		if (DoC_is_Millennium(doc))
+			WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+		WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+	}
+
+	if (doc->page256) {
+		ofs = ofs >> 8;
+	} else {
+		ofs = ofs >> 9;
+	}
+
+	if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+		for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) {
+			if (DoC_is_Millennium(doc))
+				WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+			WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+		}
+	}
+
+	DoC_Delay(doc, 2);	/* Needed for some slow flash chips. mf. */
+
+	/* FIXME: The SlowIO's for millennium could be replaced by
+	   a single WritePipeTerm here. mf. */
+
+	/* Lower the ALE line */
+	WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr,
+		 CDSNControl);
+
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Wait for the chip to respond - Software requirement 11.4.1 */
+	return DoC_WaitReady(doc);
+}
+
+/* Read a buffer from DoC, taking care of Millennium odditys */
+static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len)
+{
+	volatile int dummy;
+	int modulus = 0xffff;
+	unsigned long docptr;
+	int i;
+
+	docptr = doc->virtadr;
+
+	if (len <= 0)
+		return;
+
+	if (DoC_is_Millennium(doc)) {
+		/* Read the data via the internal pipeline through CDSN IO register,
+		   see Pipelined Read Operations 11.3 */
+		dummy = ReadDOC(docptr, ReadPipeInit);
+
+		/* Millennium should use the LastDataRead register - Pipeline Reads */
+		len--;
+
+		/* This is needed for correctly ECC calculation */
+		modulus = 0xff;
+	}
+
+	for (i = 0; i < len; i++)
+		buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus));
+
+	if (DoC_is_Millennium(doc)) {
+		buf[i] = ReadDOC(docptr, LastDataRead);
+	}
+}
+
+/* Write a buffer to DoC, taking care of Millennium odditys */
+static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len)
+{
+	unsigned long docptr;
+	int i;
+
+	docptr = doc->virtadr;
+
+	if (len <= 0)
+		return;
+
+	for (i = 0; i < len; i++)
+		WriteDOC_(buf[i], docptr, doc->ioreg + i);
+
+	if (DoC_is_Millennium(doc)) {
+		WriteDOC(0x00, docptr, WritePipeTerm);
+	}
+}
+
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+
+static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
+{
+	unsigned long docptr = doc->virtadr;
+
+	/* Software requirement 11.4.4 before writing DeviceSelect */
+	/* Deassert the CE line to eliminate glitches on the FCE# outputs */
+	WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Select the individual flash chip requested */
+	WriteDOC(chip, docptr, CDSNDeviceSelect);
+	DoC_Delay(doc, 4);
+
+	/* Reassert the CE line */
+	WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr,
+		 CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Wait for it to be ready */
+	return DoC_WaitReady(doc);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+
+static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
+{
+	unsigned long docptr = doc->virtadr;
+
+	/* Select the floor (bank) of chips required */
+	WriteDOC(floor, docptr, FloorSelect);
+
+	/* Wait for the chip to be ready */
+	return DoC_WaitReady(doc);
+}
+
+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
+
+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
+{
+	int mfr, id, i;
+	volatile char dummy;
+
+	/* Page in the required floor/chip */
+	DoC_SelectFloor(doc, floor);
+	DoC_SelectChip(doc, chip);
+
+	/* Reset the chip */
+	if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+#ifdef DOC_DEBUG
+		printf("DoC_Command (reset) for %d,%d returned true\n",
+		       floor, chip);
+#endif
+		return 0;
+	}
+
+
+	/* Read the NAND chip ID: 1. Send ReadID command */
+	if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {
+#ifdef DOC_DEBUG
+		printf("DoC_Command (ReadID) for %d,%d returned true\n",
+		       floor, chip);
+#endif
+		return 0;
+	}
+
+	/* Read the NAND chip ID: 2. Send address byte zero */
+	DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0);
+
+	/* Read the manufacturer and device id codes from the device */
+
+	/* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+	dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+	DoC_Delay(doc, 2);
+	mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+	/* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+	dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+	DoC_Delay(doc, 2);
+	id = ReadDOC_(doc->virtadr, doc->ioreg);
+
+	/* No response - return failure */
+	if (mfr == 0xff || mfr == 0)
+		return 0;
+
+	/* Check it's the same as the first chip we identified.
+	 * M-Systems say that any given DiskOnChip device should only
+	 * contain _one_ type of flash part, although that's not a
+	 * hardware restriction. */
+	if (doc->mfr) {
+		if (doc->mfr == mfr && doc->id == id)
+			return 1;	/* This is another the same the first */
+		else
+			printf("Flash chip at floor %d, chip %d is different:\n",
+			       floor, chip);
+	}
+
+	/* Print and store the manufacturer and ID codes. */
+	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+		if (mfr == nand_flash_ids[i].manufacture_id &&
+		    id == nand_flash_ids[i].model_id) {
+#ifdef DOC_DEBUG
+			printf("Flash chip found: Manufacturer ID: %2.2X, "
+			       "Chip ID: %2.2X (%s)\n", mfr, id,
+			       nand_flash_ids[i].name);
+#endif
+			if (!doc->mfr) {
+				doc->mfr = mfr;
+				doc->id = id;
+				doc->chipshift =
+				    nand_flash_ids[i].chipshift;
+				doc->page256 = nand_flash_ids[i].page256;
+				doc->pageadrlen =
+				    nand_flash_ids[i].pageadrlen;
+				doc->erasesize =
+				    nand_flash_ids[i].erasesize;
+				doc->chips_name =
+				    nand_flash_ids[i].name;
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+
+#ifdef DOC_DEBUG
+	/* We haven't fully identified the chip. Print as much as we know. */
+	printf("Unknown flash chip found: %2.2X %2.2X\n",
+	       id, mfr);
+#endif
+
+	return 0;
+}
+
+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
+
+static void DoC_ScanChips(struct DiskOnChip *this)
+{
+	int floor, chip;
+	int numchips[MAX_FLOORS];
+	int maxchips = MAX_CHIPS;
+	int ret = 1;
+
+	this->numchips = 0;
+	this->mfr = 0;
+	this->id = 0;
+
+	if (DoC_is_Millennium(this))
+		maxchips = MAX_CHIPS_MIL;
+
+	/* For each floor, find the number of valid chips it contains */
+	for (floor = 0; floor < MAX_FLOORS; floor++) {
+		ret = 1;
+		numchips[floor] = 0;
+		for (chip = 0; chip < maxchips && ret != 0; chip++) {
+
+			ret = DoC_IdentChip(this, floor, chip);
+			if (ret) {
+				numchips[floor]++;
+				this->numchips++;
+			}
+		}
+	}
+
+	/* If there are none at all that we recognise, bail */
+	if (!this->numchips) {
+		puts ("No flash chips recognised.\n");
+		return;
+	}
+
+	/* Allocate an array to hold the information for each chip */
+	this->chips = malloc(sizeof(struct Nand) * this->numchips);
+	if (!this->chips) {
+		puts ("No memory for allocating chip info structures\n");
+		return;
+	}
+
+	ret = 0;
+
+	/* Fill out the chip array with {floor, chipno} for each
+	 * detected chip in the device. */
+	for (floor = 0; floor < MAX_FLOORS; floor++) {
+		for (chip = 0; chip < numchips[floor]; chip++) {
+			this->chips[ret].floor = floor;
+			this->chips[ret].chip = chip;
+			this->chips[ret].curadr = 0;
+			this->chips[ret].curmode = 0x50;
+			ret++;
+		}
+	}
+
+	/* Calculate and print the total size of the device */
+	this->totlen = this->numchips * (1 << this->chipshift);
+
+#ifdef DOC_DEBUG
+	printf("%d flash chips found. Total DiskOnChip size: %ld MB\n",
+	       this->numchips, this->totlen >> 20);
+#endif
+}
+
+/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
+ *	various device information of the NFTL partition and Bad Unit Table. Update
+ *	the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
+ *	is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
+ */
+static int find_boot_record(struct NFTLrecord *nftl)
+{
+	struct nftl_uci1 h1;
+	struct nftl_oob oob;
+	unsigned int block, boot_record_count = 0;
+	int retlen;
+	u8 buf[SECTORSIZE];
+	struct NFTLMediaHeader *mh = &nftl->MediaHdr;
+	unsigned int i;
+
+	nftl->MediaUnit = BLOCK_NIL;
+	nftl->SpareMediaUnit = BLOCK_NIL;
+
+	/* search for a valid boot record */
+	for (block = 0; block < nftl->nb_blocks; block++) {
+		int ret;
+
+		/* Check for ANAND header first. Then can whinge if it's found but later
+		   checks fail */
+		if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
+					&retlen, buf, NULL))) {
+			static int warncount = 5;
+
+			if (warncount) {
+				printf("Block read at 0x%x failed\n", block * nftl->EraseSize);
+				if (!--warncount)
+					puts ("Further failures for this block will not be printed\n");
+			}
+			continue;
+		}
+
+		if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
+			/* ANAND\0 not found. Continue */
+#ifdef PSYCHO_DEBUG
+			printf("ANAND header not found at 0x%x\n", block * nftl->EraseSize);
+#endif
+			continue;
+		}
+
+#ifdef NFTL_DEBUG
+		printf("ANAND header found at 0x%x\n", block * nftl->EraseSize);
+#endif
+
+		/* To be safer with BIOS, also use erase mark as discriminant */
+		if ((ret = doc_read_oob(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+				8, &retlen, (char *)&h1) < 0)) {
+#ifdef NFTL_DEBUG
+			printf("ANAND header found at 0x%x, but OOB data read failed\n",
+			       block * nftl->EraseSize);
+#endif
+			continue;
+		}
+
+		/* OK, we like it. */
+
+		if (boot_record_count) {
+			/* We've already processed one. So we just check if
+			   this one is the same as the first one we found */
+			if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
+#ifdef NFTL_DEBUG
+				printf("NFTL Media Headers at 0x%x and 0x%x disagree.\n",
+				       nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
+#endif
+				/* if (debug) Print both side by side */
+				return -1;
+			}
+			if (boot_record_count == 1)
+				nftl->SpareMediaUnit = block;
+
+			boot_record_count++;
+			continue;
+		}
+
+		/* This is the first we've seen. Copy the media header structure into place */
+		memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
+
+		/* Do some sanity checks on it */
+		if (mh->UnitSizeFactor != 0xff) {
+			puts ("Sorry, we don't support UnitSizeFactor "
+			      "of != 1 yet.\n");
+			return -1;
+		}
+
+		nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
+		if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
+			printf ("NFTL Media Header sanity check failed:\n"
+				"nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
+				nftl->nb_boot_blocks, nftl->nb_blocks);
+			return -1;
+		}
+
+		nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
+		if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
+			printf ("NFTL Media Header sanity check failed:\n"
+				"numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
+				nftl->numvunits,
+				nftl->nb_blocks,
+				nftl->nb_boot_blocks);
+			return -1;
+		}
+
+		nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
+
+		/* If we're not using the last sectors in the device for some reason,
+		   reduce nb_blocks accordingly so we forget they're there */
+		nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
+
+		/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
+		for (i = 0; i < nftl->nb_blocks; i++) {
+			if ((i & (SECTORSIZE - 1)) == 0) {
+				/* read one sector for every SECTORSIZE of blocks */
+				if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize +
+						       i + SECTORSIZE, SECTORSIZE,
+						       &retlen, buf, (char *)&oob)) < 0) {
+					puts ("Read of bad sector table failed\n");
+					return -1;
+				}
+			}
+			/* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
+			if (buf[i & (SECTORSIZE - 1)] != 0xff)
+				nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+		}
+
+		nftl->MediaUnit = block;
+		boot_record_count++;
+
+	} /* foreach (block) */
+
+	return boot_record_count?0:-1;
+}
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoC2k_init(struct DiskOnChip* this)
+{
+	struct NFTLrecord *nftl;
+
+	switch (this->ChipID) {
+	case DOC_ChipID_Doc2k:
+		this->name = "DiskOnChip 2000";
+		this->ioreg = DoC_2k_CDSN_IO;
+		break;
+	case DOC_ChipID_DocMil:
+		this->name = "DiskOnChip Millennium";
+		this->ioreg = DoC_Mil_CDSN_IO;
+		break;
+	}
+
+#ifdef DOC_DEBUG
+	printf("%s found at address 0x%lX\n", this->name,
+	       this->physadr);
+#endif
+
+	this->totlen = 0;
+	this->numchips = 0;
+
+	this->curfloor = -1;
+	this->curchip = -1;
+
+	/* Ident all the chips present. */
+	DoC_ScanChips(this);
+
+	nftl = &this->nftl;
+
+	/* Get physical parameters */
+	nftl->EraseSize = this->erasesize;
+        nftl->nb_blocks = this->totlen / this->erasesize;
+	nftl->mtd = this;
+
+	if (find_boot_record(nftl) != 0)
+		this->nftl_found = 0;
+	else
+		this->nftl_found = 1;
+
+	printf("%s @ 0x%lX, %ld MB\n", this->name, this->physadr, this->totlen >> 20);
+}
+
+int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len,
+		 size_t * retlen, u_char * buf, u_char * eccbuf)
+{
+	unsigned long docptr;
+	struct Nand *mychip;
+	unsigned char syndrome[6];
+	volatile char dummy;
+	int i, len256 = 0, ret=0;
+
+	docptr = this->virtadr;
+
+	/* Don't allow read past end of device */
+	if (from >= this->totlen) {
+		puts ("Out of flash\n");
+		return DOC_EINVAL;
+	}
+
+	/* Don't allow a single read to cross a 512-byte block boundary */
+	if (from + len > ((from | 0x1ff) + 1))
+		len = ((from | 0x1ff) + 1) - from;
+
+	/* The ECC will not be calculated correctly if less than 512 is read */
+	if (len != 0x200 && eccbuf)
+		printf("ECC needs a full sector read (adr: %lx size %lx)\n",
+		       (long) from, (long) len);
+
+#ifdef PHYCH_DEBUG
+	printf("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len);
+#endif
+
+	/* Find the chip which is to be used and select it */
+	mychip = &this->chips[shr(from, this->chipshift)];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	DoC_Command(this,
+		    (!this->page256
+		     && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+		    CDSN_CTRL_WP);
+	DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+		    CDSN_CTRL_ECC_IO);
+
+	if (eccbuf) {
+		/* Prime the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	}
+
+	/* treat crossing 256-byte sector for 2M x 8bits devices */
+	if (this->page256 && from + len > (from | 0xff) + 1) {
+		len256 = (from | 0xff) + 1 - from;
+		DoC_ReadBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+		DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+			    CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
+	}
+
+	DoC_ReadBuf(this, &buf[len256], len - len256);
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+
+	if (eccbuf) {
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		/* Note: this will work even with 2M x 8bit devices as   */
+		/*       they have 8 bytes of OOB per 256 page. mf.      */
+		DoC_ReadBuf(this, eccbuf, 6);
+
+		/* Flush the pipeline */
+		if (DoC_is_Millennium(this)) {
+			dummy = ReadDOC(docptr, ECCConf);
+			dummy = ReadDOC(docptr, ECCConf);
+			i = ReadDOC(docptr, ECCConf);
+		} else {
+			dummy = ReadDOC(docptr, 2k_ECCStatus);
+			dummy = ReadDOC(docptr, 2k_ECCStatus);
+			i = ReadDOC(docptr, 2k_ECCStatus);
+		}
+
+		/* Check the ECC Status */
+		if (i & 0x80) {
+			int nb_errors;
+			/* There was an ECC error */
+#ifdef ECC_DEBUG
+			printf("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+#endif
+			/* Read the ECC syndrom through the DiskOnChip ECC logic.
+			   These syndrome will be all ZERO when there is no error */
+			for (i = 0; i < 6; i++) {
+				syndrome[i] =
+				    ReadDOC(docptr, ECCSyndrome0 + i);
+			}
+                        nb_errors = doc_decode_ecc(buf, syndrome);
+
+#ifdef ECC_DEBUG
+			printf("Errors corrected: %x\n", nb_errors);
+#endif
+                        if (nb_errors < 0) {
+				/* We return error, but have actually done the read. Not that
+				   this can be told to user-space, via sys_read(), but at least
+				   MTD-aware stuff can know about it by checking *retlen */
+				printf("ECC Errors at %lx\n", (long)from);
+				ret = DOC_EECC;
+                        }
+		}
+
+#ifdef PSYCHO_DEBUG
+		printf("ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+			     (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+			     eccbuf[3], eccbuf[4], eccbuf[5]);
+#endif
+
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+	}
+
+	/* according to 11.4.1, we need to wait for the busy line
+         * drop if we read to the end of the page.  */
+	if(0 == ((from + *retlen) & 0x1ff))
+	{
+	    DoC_WaitReady(this);
+	}
+
+	return ret;
+}
+
+int doc_write_ecc(struct DiskOnChip* this, loff_t to, size_t len,
+		  size_t * retlen, const u_char * buf,
+		  u_char * eccbuf)
+{
+	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+	unsigned long docptr;
+	volatile char dummy;
+	int len256 = 0;
+	struct Nand *mychip;
+
+	docptr = this->virtadr;
+
+	/* Don't allow write past end of device */
+	if (to >= this->totlen) {
+		puts ("Out of flash\n");
+		return DOC_EINVAL;
+	}
+
+	/* Don't allow a single write to cross a 512-byte block boundary */
+	if (to + len > ((to | 0x1ff) + 1))
+		len = ((to | 0x1ff) + 1) - to;
+
+	/* The ECC will not be calculated correctly if less than 512 is written */
+	if (len != 0x200 && eccbuf)
+		printf("ECC needs a full sector write (adr: %lx size %lx)\n",
+		       (long) to, (long) len);
+
+	/* printf("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+
+	/* Find the chip which is to be used and select it */
+	mychip = &this->chips[shr(to, this->chipshift)];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Set device to main plane of flash */
+	DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+	DoC_Command(this,
+		    (!this->page256
+		     && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+		    CDSN_CTRL_WP);
+
+	DoC_Command(this, NAND_CMD_SEQIN, 0);
+	DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+
+	if (eccbuf) {
+		/* Prime the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	}
+
+	/* treat crossing 256-byte sector for 2M x 8bits devices */
+	if (this->page256 && to + len > (to | 0xff) + 1) {
+		len256 = (to | 0xff) + 1 - to;
+		DoC_WriteBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+		DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+		/* There's an implicit DoC_WaitReady() in DoC_Command */
+
+		dummy = ReadDOC(docptr, CDSNSlowIO);
+		DoC_Delay(this, 2);
+
+		if (ReadDOC_(docptr, this->ioreg) & 1) {
+			puts ("Error programming flash\n");
+			/* Error in programming */
+			*retlen = 0;
+			return DOC_EIO;
+		}
+
+		DoC_Command(this, NAND_CMD_SEQIN, 0);
+		DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+			    CDSN_CTRL_ECC_IO);
+	}
+
+	DoC_WriteBuf(this, &buf[len256], len - len256);
+
+	if (eccbuf) {
+		WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+			 CDSNControl);
+
+		if (DoC_is_Millennium(this)) {
+			WriteDOC(0, docptr, NOP);
+			WriteDOC(0, docptr, NOP);
+			WriteDOC(0, docptr, NOP);
+		} else {
+			WriteDOC_(0, docptr, this->ioreg);
+			WriteDOC_(0, docptr, this->ioreg);
+			WriteDOC_(0, docptr, this->ioreg);
+		}
+
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		for (di = 0; di < 6; di++) {
+			eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+		}
+
+		/* Reset the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#ifdef PSYCHO_DEBUG
+		printf
+		    ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+		     (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+		     eccbuf[4], eccbuf[5]);
+#endif
+	}
+
+	DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+	DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+	/* There's an implicit DoC_WaitReady() in DoC_Command */
+
+	dummy = ReadDOC(docptr, CDSNSlowIO);
+	DoC_Delay(this, 2);
+
+	if (ReadDOC_(docptr, this->ioreg) & 1) {
+		puts ("Error programming flash\n");
+		/* Error in programming */
+		*retlen = 0;
+		return DOC_EIO;
+	}
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+
+	if (eccbuf) {
+		unsigned char x[8];
+		size_t dummy;
+		int ret;
+
+		/* Write the ECC data to flash */
+		for (di=0; di<6; di++)
+			x[di] = eccbuf[di];
+
+		x[6]=0x55;
+		x[7]=0x55;
+
+		ret = doc_write_oob(this, to, 8, &dummy, x);
+		return ret;
+	}
+	return 0;
+}
+
+int doc_read_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+		 size_t * retlen, u_char * buf)
+{
+	int len256 = 0, ret;
+	unsigned long docptr;
+	struct Nand *mychip;
+
+	docptr = this->virtadr;
+
+	mychip = &this->chips[shr(ofs, this->chipshift)];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* update address for 2M x 8bit devices. OOB starts on the second */
+	/* page to maintain compatibility with doc_read_ecc. */
+	if (this->page256) {
+		if (!(ofs & 0x8))
+			ofs += 0x100;
+		else
+			ofs -= 0x8;
+	}
+
+	DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+	DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0);
+
+	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
+	/* Note: datasheet says it should automaticaly wrap to the */
+	/*       next OOB block, but it didn't work here. mf.      */
+	if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+		len256 = (ofs | 0x7) + 1 - ofs;
+		DoC_ReadBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+		DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff),
+			    CDSN_CTRL_WP, 0);
+	}
+
+	DoC_ReadBuf(this, &buf[len256], len - len256);
+
+	*retlen = len;
+	/* Reading the full OOB data drops us off of the end of the page,
+         * causing the flash device to go into busy mode, so we need
+         * to wait until ready 11.4.1 and Toshiba TC58256FT docs */
+
+	ret = DoC_WaitReady(this);
+
+	return ret;
+
+}
+
+int doc_write_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+		  size_t * retlen, const u_char * buf)
+{
+	int len256 = 0;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[shr(ofs, this->chipshift)];
+	volatile int dummy;
+
+#ifdef PSYCHO_DEBUG
+	printf("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
+	       (long)ofs, len, buf[0], buf[1], buf[2], buf[3],
+	       buf[8], buf[9], buf[14],buf[15]);
+#endif
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* disable the ECC engine */
+	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+
+	/* issue the Read2 command to set the pointer to the Spare Data Area. */
+	DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+	/* update address for 2M x 8bit devices. OOB starts on the second */
+	/* page to maintain compatibility with doc_read_ecc. */
+	if (this->page256) {
+		if (!(ofs & 0x8))
+			ofs += 0x100;
+		else
+			ofs -= 0x8;
+	}
+
+	/* issue the Serial Data In command to initial the Page Program process */
+	DoC_Command(this, NAND_CMD_SEQIN, 0);
+	DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0);
+
+	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
+	/* Note: datasheet says it should automaticaly wrap to the */
+	/*       next OOB block, but it didn't work here. mf.      */
+	if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+		len256 = (ofs | 0x7) + 1 - ofs;
+		DoC_WriteBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+		DoC_Command(this, NAND_CMD_STATUS, 0);
+		/* DoC_WaitReady() is implicit in DoC_Command */
+
+		dummy = ReadDOC(docptr, CDSNSlowIO);
+		DoC_Delay(this, 2);
+
+		if (ReadDOC_(docptr, this->ioreg) & 1) {
+			puts ("Error programming oob data\n");
+			/* There was an error */
+			*retlen = 0;
+			return DOC_EIO;
+		}
+		DoC_Command(this, NAND_CMD_SEQIN, 0);
+		DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0);
+	}
+
+	DoC_WriteBuf(this, &buf[len256], len - len256);
+
+	DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+	DoC_Command(this, NAND_CMD_STATUS, 0);
+	/* DoC_WaitReady() is implicit in DoC_Command */
+
+	dummy = ReadDOC(docptr, CDSNSlowIO);
+	DoC_Delay(this, 2);
+
+	if (ReadDOC_(docptr, this->ioreg) & 1) {
+		puts ("Error programming oob data\n");
+		/* There was an error */
+		*retlen = 0;
+		return DOC_EIO;
+	}
+
+	*retlen = len;
+	return 0;
+
+}
+
+int doc_erase(struct DiskOnChip* this, loff_t ofs, size_t len)
+{
+	volatile int dummy;
+	unsigned long docptr;
+	struct Nand *mychip;
+
+	if (ofs & (this->erasesize-1) || len & (this->erasesize-1)) {
+		puts ("Offset and size must be sector aligned\n");
+		return DOC_EINVAL;
+	}
+
+	docptr = this->virtadr;
+
+	/* FIXME: Do this in the background. Use timers or schedule_task() */
+	while(len) {
+		mychip = &this->chips[shr(ofs, this->chipshift)];
+
+		if (this->curfloor != mychip->floor) {
+			DoC_SelectFloor(this, mychip->floor);
+			DoC_SelectChip(this, mychip->chip);
+		} else if (this->curchip != mychip->chip) {
+			DoC_SelectChip(this, mychip->chip);
+		}
+		this->curfloor = mychip->floor;
+		this->curchip = mychip->chip;
+
+		DoC_Command(this, NAND_CMD_ERASE1, 0);
+		DoC_Address(this, ADDR_PAGE, ofs, 0, 0);
+		DoC_Command(this, NAND_CMD_ERASE2, 0);
+
+		DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+
+		dummy = ReadDOC(docptr, CDSNSlowIO);
+		DoC_Delay(this, 2);
+
+		if (ReadDOC_(docptr, this->ioreg) & 1) {
+			printf("Error erasing at 0x%lx\n", (long)ofs);
+			/* There was an error */
+			goto callback;
+		}
+		ofs += this->erasesize;
+		len -= this->erasesize;
+	}
+
+ callback:
+	return 0;
+}
+
+static inline int doccheck(unsigned long potential, unsigned long physadr)
+{
+	unsigned long window=potential;
+	unsigned char tmp, ChipID;
+#ifndef DOC_PASSIVE_PROBE
+	unsigned char tmp2;
+#endif
+
+	/* Routine copied from the Linux DOC driver */
+
+#ifdef CFG_DOCPROBE_55AA
+	/* Check for 0x55 0xAA signature at beginning of window,
+	   this is no longer true once we remove the IPL (for Millennium */
+	if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
+		return 0;
+#endif /* CFG_DOCPROBE_55AA */
+
+#ifndef DOC_PASSIVE_PROBE
+	/* It's not possible to cleanly detect the DiskOnChip - the
+	 * bootup procedure will put the device into reset mode, and
+	 * it's not possible to talk to it without actually writing
+	 * to the DOCControl register. So we store the current contents
+	 * of the DOCControl register's location, in case we later decide
+	 * that it's not a DiskOnChip, and want to put it back how we
+	 * found it.
+	 */
+	tmp2 = ReadDOC(window, DOCControl);
+
+	/* Reset the DiskOnChip ASIC */
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
+		 window, DOCControl);
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
+		 window, DOCControl);
+
+	/* Enable the DiskOnChip ASIC */
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
+		 window, DOCControl);
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
+		 window, DOCControl);
+#endif /* !DOC_PASSIVE_PROBE */
+
+	ChipID = ReadDOC(window, ChipID);
+
+	switch (ChipID) {
+	case DOC_ChipID_Doc2k:
+		/* Check the TOGGLE bit in the ECC register */
+		tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+		if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
+				return ChipID;
+		break;
+
+	case DOC_ChipID_DocMil:
+		/* Check the TOGGLE bit in the ECC register */
+		tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+		if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
+				return ChipID;
+		break;
+
+	default:
+#ifndef CFG_DOCPROBE_55AA
+/*
+ * if the ID isn't the DoC2000 or DoCMillenium ID, so we can assume
+ * the DOC is missing
+ */
+# if 0
+		printf("Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+		       ChipID, physadr);
+# endif
+#endif
+#ifndef DOC_PASSIVE_PROBE
+		/* Put back the contents of the DOCControl register, in case it's not
+		 * actually a DiskOnChip.
+		 */
+		WriteDOC(tmp2, window, DOCControl);
+#endif
+		return 0;
+	}
+
+	puts ("DiskOnChip failed TOGGLE test, dropping.\n");
+
+#ifndef DOC_PASSIVE_PROBE
+	/* Put back the contents of the DOCControl register: it's not a DiskOnChip */
+	WriteDOC(tmp2, window, DOCControl);
+#endif
+	return 0;
+}
+
+void doc_probe(unsigned long physadr)
+{
+	struct DiskOnChip *this = NULL;
+	int i=0, ChipID;
+
+	if ((ChipID = doccheck(physadr, physadr))) {
+
+		for (i=0; i<CFG_MAX_DOC_DEVICE; i++) {
+			if (doc_dev_desc[i].ChipID == DOC_ChipID_UNKNOWN) {
+				this = doc_dev_desc + i;
+				break;
+			}
+		}
+
+		if (!this) {
+			puts ("Cannot allocate memory for data structures.\n");
+			return;
+		}
+
+		if (curr_device == -1)
+			curr_device = i;
+
+		memset((char *)this, 0, sizeof(struct DiskOnChip));
+
+		this->virtadr = physadr;
+		this->physadr = physadr;
+		this->ChipID = ChipID;
+
+		DoC2k_init(this);
+	} else {
+		puts ("No DiskOnChip found\n");
+	}
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
diff --git a/common/cmd_ide.c b/common/cmd_ide.c
new file mode 100644
index 0000000..9cbfe1b
--- /dev/null
+++ b/common/cmd_ide.c
@@ -0,0 +1,1563 @@
+/*
+ * (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
+ *
+ */
+
+/*
+ * IDE support
+ */
+#include <common.h>
+#include <config.h>
+#include <watchdog.h>
+#include <command.h>
+#include <image.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_IDE_8xx_DIRECT) || defined(CONFIG_IDE_PCMCIA)
+# include <pcmcia.h>
+#endif
+#ifdef CONFIG_8xx
+# include <mpc8xx.h>
+#endif
+#include <ide.h>
+#include <ata.h>
+#include <cmd_ide.h>
+#include <cmd_disk.h>
+#ifdef CONFIG_STATUS_LED
+# include <status_led.h>
+#endif
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+
+#undef	IDE_DEBUG
+
+#ifdef	IDE_DEBUG
+#define	PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+
+/* Timings for IDE Interface
+ *
+ * SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk
+ * 70	   165	    30	   PIO-Mode 0, [ns]
+ *  4	     9	     2		       [Cycles]
+ * 50	   125	    20	   PIO-Mode 1, [ns]
+ *  3	     7	     2		       [Cycles]
+ * 30	   100	    15	   PIO-Mode 2, [ns]
+ *  2	     6	     1		       [Cycles]
+ * 30	    80	    10	   PIO-Mode 3, [ns]
+ *  2	     5	     1		       [Cycles]
+ * 25	    70	    10	   PIO-Mode 4, [ns]
+ *  2	     4	     1		       [Cycles]
+ */
+
+const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] =
+{
+    /*	Setup  Length  Hold  */
+	{ 70,	165,	30 },		/* PIO-Mode 0, [ns]	*/
+	{ 50,	125,	20 },		/* PIO-Mode 1, [ns]	*/
+	{ 30,	101,	15 },		/* PIO-Mode 2, [ns]	*/
+	{ 30,	 80,	10 },		/* PIO-Mode 3, [ns]	*/
+	{ 25,	 70,	10 },		/* PIO-Mode 4, [ns]	*/
+};
+
+static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1];
+
+#ifndef	CFG_PIO_MODE
+#define	CFG_PIO_MODE	0		/* use a relaxed default */
+#endif
+static int pio_mode = CFG_PIO_MODE;
+
+/* Make clock cycles and always round up */
+
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
+
+/* ------------------------------------------------------------------------- */
+
+/* Current I/O Device	*/
+static int curr_device = -1;
+
+/* Current offset for IDE0 / IDE1 bus access	*/
+ulong ide_bus_offset[CFG_IDE_MAXBUS] = {
+#if defined(CFG_ATA_IDE0_OFFSET)
+	CFG_ATA_IDE0_OFFSET,
+#endif
+#if defined(CFG_ATA_IDE1_OFFSET) && (CFG_IDE_MAXBUS > 1)
+	CFG_ATA_IDE1_OFFSET,
+#endif
+};
+
+#define	ATA_CURR_BASE(dev)	(CFG_ATA_BASE_ADDR+ide_bus_offset[IDE_BUS(dev)])
+
+static int	    ide_bus_ok[CFG_IDE_MAXBUS];
+
+static  block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+static void  ide_led   (uchar led, uchar status);
+#else
+#define ide_led(a,b)	/* dummy */
+#endif
+
+#ifdef CONFIG_IDE_RESET
+static void  ide_reset (void);
+#else
+#define ide_reset()	/* dummy */
+#endif
+
+static void  ide_ident (block_dev_desc_t *dev_desc);
+static uchar ide_wait  (int dev, ulong t);
+
+#define IDE_TIME_OUT	2000	/* 2 sec timeout */
+
+#define ATAPI_TIME_OUT	7000	/* 7 sec timeout (5 sec seems to work...) */
+
+#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
+
+static void __inline__ outb(int dev, int port, unsigned char val);
+static unsigned char __inline__ inb(int dev, int port);
+static void input_swap_data(int dev, ulong *sect_buf, int words);
+static void input_data(int dev, ulong *sect_buf, int words);
+static void output_data(int dev, ulong *sect_buf, int words);
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
+
+
+#ifdef CONFIG_ATAPI
+static void	atapi_inquiry(block_dev_desc_t *dev_desc);
+ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer);
+#endif
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+static void set_pcmcia_timing (int pmode);
+#else
+#define set_pcmcia_timing(a)	/* dummy */
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    int rcode = 0;
+
+    switch (argc) {
+    case 0:
+    case 1:
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    case 2:
+	if (strncmp(argv[1],"res",3) == 0) {
+		puts ("\nReset IDE"
+#ifdef CONFIG_IDE_8xx_DIRECT
+			" on PCMCIA " PCMCIA_SLOT_MSG
+#endif
+			": ");
+
+		ide_init ();
+		return 0;
+	} else if (strncmp(argv[1],"inf",3) == 0) {
+		int i;
+
+		putc ('\n');
+
+		for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
+			if (ide_dev_desc[i].type==DEV_TYPE_UNKNOWN)
+				continue; /* list only known devices */
+			printf ("IDE device %d: ", i);
+			dev_print(&ide_dev_desc[i]);
+		}
+		return 0;
+
+	} else if (strncmp(argv[1],"dev",3) == 0) {
+		if ((curr_device < 0) || (curr_device >= CFG_IDE_MAXDEVICE)) {
+			puts ("\nno IDE devices available\n");
+			return 1;
+		}
+		printf ("\nIDE device %d: ", curr_device);
+		dev_print(&ide_dev_desc[curr_device]);
+		return 0;
+	} else if (strncmp(argv[1],"part",4) == 0) {
+		int dev, ok;
+
+		for (ok=0, dev=0; dev<CFG_IDE_MAXDEVICE; ++dev) {
+			if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+				++ok;
+				if (dev)
+					putc ('\n');
+				print_part(&ide_dev_desc[dev]);
+			}
+		}
+		if (!ok) {
+			puts ("\nno IDE devices available\n");
+			rcode ++;
+		}
+		return rcode;
+	}
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    case 3:
+	if (strncmp(argv[1],"dev",3) == 0) {
+		int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+		printf ("\nIDE device %d: ", dev);
+		if (dev >= CFG_IDE_MAXDEVICE) {
+			puts ("unknown device\n");
+			return 1;
+		}
+		dev_print(&ide_dev_desc[dev]);
+		/*ide_print (dev);*/
+
+		if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
+			return 1;
+		}
+
+		curr_device = dev;
+
+		puts ("... is now current device\n");
+
+		return 0;
+	} else if (strncmp(argv[1],"part",4) == 0) {
+		int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+		if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+				print_part(&ide_dev_desc[dev]);
+		} else {
+			printf ("\nIDE device %d not available\n", dev);
+			rcode = 1;
+		}
+		return rcode;
+#if 0
+	} else if (strncmp(argv[1],"pio",4) == 0) {
+		int mode = (int)simple_strtoul(argv[2], NULL, 10);
+
+		if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) {
+			puts ("\nSetting ");
+			pio_mode = mode;
+			ide_init ();
+		} else {
+			printf ("\nInvalid PIO mode %d (0 ... %d only)\n",
+				mode, IDE_MAX_PIO_MODE);
+		}
+		return;
+#endif
+	}
+
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+    default:
+	/* at least 4 args */
+
+	if (strcmp(argv[1],"read") == 0) {
+		ulong addr = simple_strtoul(argv[2], NULL, 16);
+		ulong blk  = simple_strtoul(argv[3], NULL, 16);
+		ulong cnt  = simple_strtoul(argv[4], NULL, 16);
+		ulong n;
+
+		printf ("\nIDE read: device %d block # %ld, count %ld ... ",
+			curr_device, blk, cnt);
+
+		n = ide_dev_desc[curr_device].block_read (curr_device,
+							  blk, cnt,
+							  (ulong *)addr);
+		/* flush cache after read */
+		flush_cache (addr, cnt*ide_dev_desc[curr_device].blksz);
+
+		printf ("%ld blocks read: %s\n",
+			n, (n==cnt) ? "OK" : "ERROR");
+		if (n==cnt) {
+			return 0;
+		} else {
+			return 1;
+		}
+	} else if (strcmp(argv[1],"write") == 0) {
+		ulong addr = simple_strtoul(argv[2], NULL, 16);
+		ulong blk  = simple_strtoul(argv[3], NULL, 16);
+		ulong cnt  = simple_strtoul(argv[4], NULL, 16);
+		ulong n;
+
+		printf ("\nIDE write: device %d block # %ld, count %ld ... ",
+			curr_device, blk, cnt);
+
+		n = ide_write (curr_device, blk, cnt, (ulong *)addr);
+
+		printf ("%ld blocks written: %s\n",
+			n, (n==cnt) ? "OK" : "ERROR");
+		if (n==cnt) {
+			return 0;
+		} else {
+			return 1;
+		}
+	} else {
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		rcode = 1;
+	}
+
+	return rcode;
+    }
+}
+
+int do_diskboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *boot_device = NULL;
+	char *ep;
+	int dev, part = 0;
+	ulong cnt;
+	ulong addr;
+	disk_partition_t info;
+	image_header_t *hdr;
+	int rcode = 0;
+
+	switch (argc) {
+	case 1:
+		addr = CFG_LOAD_ADDR;
+		boot_device = getenv ("bootdevice");
+		break;
+	case 2:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = getenv ("bootdevice");
+		break;
+	case 3:
+		addr = simple_strtoul(argv[1], NULL, 16);
+		boot_device = argv[2];
+		break;
+	default:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (!boot_device) {
+		puts ("\n** No boot device **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	dev = simple_strtoul(boot_device, &ep, 16);
+
+	if (ide_dev_desc[dev].type==DEV_TYPE_UNKNOWN) {
+		printf ("\n** Device %d not available\n", dev);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (*ep) {
+		if (*ep != ':') {
+			puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+			SHOW_BOOT_PROGRESS (-1);
+			return 1;
+		}
+		part = simple_strtoul(++ep, NULL, 16);
+	}
+	if (get_partition_info (&ide_dev_desc[dev], part, &info)) {
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+	if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) {
+		printf ("\n** Invalid partition type \"%.32s\""
+			" (expect \"" BOOT_PART_TYPE "\")\n",
+			info.type);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	printf ("\nLoading from IDE device %d, partition %d: "
+		"Name: %.32s  Type: %.32s\n",
+		dev, part, info.name, info.type);
+
+	PRINTF ("First Block: %ld,  # of blocks: %ld, Block Size: %ld\n",
+		info.start, info.size, info.blksz);
+
+	if (ide_dev_desc[dev].block_read (dev, info.start, 1, (ulong *)addr) != 1) {
+		printf ("** Read error on %d:%d\n", dev, part);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	hdr = (image_header_t *)addr;
+
+	if (ntohl(hdr->ih_magic) == IH_MAGIC) {
+
+		print_image_hdr (hdr);
+
+		cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
+		cnt += info.blksz - 1;
+		cnt /= info.blksz;
+		cnt -= 1;
+	} else {
+		printf("\n** Bad Magic Number **\n");
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+	if (ide_dev_desc[dev].block_read (dev, info.start+1, cnt,
+		      (ulong *)(addr+info.blksz)) != cnt) {
+		printf ("** Read error on %d:%d\n", dev, part);
+		SHOW_BOOT_PROGRESS (-1);
+		return 1;
+	}
+
+
+	/* Loading ok, update default load address */
+
+	load_addr = addr;
+
+	/* Check if we should attempt an auto-start */
+	if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+		char *local_args[2];
+		extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
+
+		local_args[0] = argv[0];
+		local_args[1] = NULL;
+
+		printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+
+		do_bootm (cmdtp, 0, 1, local_args);
+		rcode = 1;
+	}
+	return rcode;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void ide_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+	volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+#endif
+	unsigned char c;
+	int i, bus;
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	extern int pcmcia_on (void);
+
+	WATCHDOG_RESET();
+
+	/* initialize the PCMCIA IDE adapter card */
+	if (pcmcia_on())
+		return;
+	udelay (1000000);	/* 1 s */
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+	WATCHDOG_RESET();
+
+	/* Initialize PIO timing tables */
+	for (i=0; i <= IDE_MAX_PIO_MODE; ++i) {
+	    pio_config_clk[i].t_setup  = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup,
+							    gd->bus_clk);
+	    pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length,
+							    gd->bus_clk);
+	    pio_config_clk[i].t_hold   = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold,
+							    gd->bus_clk);
+	    PRINTF ("PIO Mode %d: setup=%2d ns/%d clk"
+		    "  len=%3d ns/%d clk"
+		    "  hold=%2d ns/%d clk\n",
+		    i,
+		    pio_config_ns[i].t_setup,  pio_config_clk[i].t_setup,
+		    pio_config_ns[i].t_length, pio_config_clk[i].t_length,
+		    pio_config_ns[i].t_hold,   pio_config_clk[i].t_hold);
+	}
+
+	/* Reset the IDE just to be sure.
+	 * Light LED's to show
+	 */
+	ide_led ((LED_IDE1 | LED_IDE2), 1);		/* LED's on	*/
+	ide_reset (); /* ATAPI Drives seems to need a proper IDE Reset */
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+	/* PCMCIA / IDE initialization for common mem space */
+	pcmp->pcmc_pgcrb = 0;
+#endif
+
+	/* start in PIO mode 0 - most relaxed timings */
+	pio_mode = 0;
+	set_pcmcia_timing (pio_mode);
+
+	/*
+	 * Wait for IDE to get ready.
+	 * According to spec, this can take up to 31 seconds!
+	 */
+	for (bus=0; bus<CFG_IDE_MAXBUS; ++bus) {
+		int dev = bus * (CFG_IDE_MAXDEVICE / CFG_IDE_MAXBUS);
+
+		printf ("Bus %d: ", bus);
+
+		ide_bus_ok[bus] = 0;
+
+		/* Select device
+		 */
+		udelay (100000);		/* 100 ms */
+		outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
+		udelay (100000);		/* 100 ms */
+
+		i = 0;
+		do {
+			udelay (10000);		/* 10 ms */
+
+			c = inb (dev, ATA_STATUS);
+			i++;
+			if (i > (ATA_RESET_TIME * 100)) {
+				puts ("** Timeout **\n");
+				ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+				return;
+			}
+			if ((i >= 100) && ((i%100)==0)) {
+				putc ('.');
+			}
+		} while (c & ATA_STAT_BUSY);
+
+		if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
+			puts ("not available  ");
+			PRINTF ("Status = 0x%02X ", c);
+#ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */
+		} else  if ((c & ATA_STAT_READY) == 0) {
+			puts ("not available  ");
+			PRINTF ("Status = 0x%02X ", c);
+#endif
+		} else {
+			puts ("OK ");
+			ide_bus_ok[bus] = 1;
+		}
+		WATCHDOG_RESET();
+	}
+	putc ('\n');
+
+	ide_led ((LED_IDE1 | LED_IDE2), 0);	/* LED's off	*/
+
+	curr_device = -1;
+	for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
+#ifdef CONFIG_IDE_LED
+		int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
+#endif
+		ide_dev_desc[i].if_type=IF_TYPE_IDE;
+		ide_dev_desc[i].dev=i;
+		ide_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+		ide_dev_desc[i].blksz=0;
+		ide_dev_desc[i].lba=0;
+		ide_dev_desc[i].block_read=ide_read;
+		if (!ide_bus_ok[IDE_BUS(i)])
+			continue;
+		ide_led (led, 1);		/* LED on	*/
+		ide_ident(&ide_dev_desc[i]);
+		ide_led (led, 0);		/* LED off	*/
+		dev_print(&ide_dev_desc[i]);
+/*		ide_print (i); */
+		if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
+			init_part (&ide_dev_desc[i]);			/* initialize partition type */
+			if (curr_device < 0)
+				curr_device = i;
+		}
+	}
+	WATCHDOG_RESET();
+}
+
+/* ------------------------------------------------------------------------- */
+
+block_dev_desc_t * ide_get_dev(int dev)
+{
+	return ((block_dev_desc_t *)&ide_dev_desc[dev]);
+}
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+
+static void
+set_pcmcia_timing (int pmode)
+{
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+	volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+	ulong timings;
+
+	PRINTF ("Set timing for PIO Mode %d\n", pmode);
+
+	timings = PCMCIA_SHT(pio_config_clk[pmode].t_hold)
+		| PCMCIA_SST(pio_config_clk[pmode].t_setup)
+		| PCMCIA_SL (pio_config_clk[pmode].t_length)
+		;
+
+	/* IDE 0
+	 */
+	pcmp->pcmc_pbr0 = CFG_PCMCIA_PBR0;
+	pcmp->pcmc_por0 = CFG_PCMCIA_POR0
+#if (CFG_PCMCIA_POR0 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR0: %08x  POR0: %08x\n", pcmp->pcmc_pbr0, pcmp->pcmc_por0);
+
+	pcmp->pcmc_pbr1 = CFG_PCMCIA_PBR1;
+	pcmp->pcmc_por1 = CFG_PCMCIA_POR1
+#if (CFG_PCMCIA_POR1 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR1: %08x  POR1: %08x\n", pcmp->pcmc_pbr1, pcmp->pcmc_por1);
+
+	pcmp->pcmc_pbr2 = CFG_PCMCIA_PBR2;
+	pcmp->pcmc_por2 = CFG_PCMCIA_POR2
+#if (CFG_PCMCIA_POR2 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR2: %08x  POR2: %08x\n", pcmp->pcmc_pbr2, pcmp->pcmc_por2);
+
+	pcmp->pcmc_pbr3 = CFG_PCMCIA_PBR3;
+	pcmp->pcmc_por3 = CFG_PCMCIA_POR3
+#if (CFG_PCMCIA_POR3 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR3: %08x  POR3: %08x\n", pcmp->pcmc_pbr3, pcmp->pcmc_por3);
+
+	/* IDE 1
+	 */
+	pcmp->pcmc_pbr4 = CFG_PCMCIA_PBR4;
+	pcmp->pcmc_por4 = CFG_PCMCIA_POR4
+#if (CFG_PCMCIA_POR4 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR4: %08x  POR4: %08x\n", pcmp->pcmc_pbr4, pcmp->pcmc_por4);
+
+	pcmp->pcmc_pbr5 = CFG_PCMCIA_PBR5;
+	pcmp->pcmc_por5 = CFG_PCMCIA_POR5
+#if (CFG_PCMCIA_POR5 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR5: %08x  POR5: %08x\n", pcmp->pcmc_pbr5, pcmp->pcmc_por5);
+
+	pcmp->pcmc_pbr6 = CFG_PCMCIA_PBR6;
+	pcmp->pcmc_por6 = CFG_PCMCIA_POR6
+#if (CFG_PCMCIA_POR6 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR6: %08x  POR6: %08x\n", pcmp->pcmc_pbr6, pcmp->pcmc_por6);
+
+	pcmp->pcmc_pbr7 = CFG_PCMCIA_PBR7;
+	pcmp->pcmc_por7 = CFG_PCMCIA_POR7
+#if (CFG_PCMCIA_POR7 != 0)
+			| timings
+#endif
+			;
+	PRINTF ("PBR7: %08x  POR7: %08x\n", pcmp->pcmc_pbr7, pcmp->pcmc_por7);
+
+}
+
+#endif	/* CONFIG_IDE_8xx_DIRECT */
+
+/* ------------------------------------------------------------------------- */
+
+static void __inline__
+outb(int dev, int port, unsigned char val)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	*((uchar *)(ATA_CURR_BASE(dev)+port)) = val;
+#if 0
+	printf ("OUTB: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
+#endif
+}
+
+static unsigned char __inline__
+inb(int dev, int port)
+{
+	uchar val;
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	val = *((uchar *)(ATA_CURR_BASE(dev)+port));
+#if 0
+	printf ("INB: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
+#endif
+	return (val);
+}
+
+__inline__ unsigned ld_le16(const volatile unsigned short *addr)
+{
+	unsigned val;
+
+	__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r"(val) : "r"(addr), "m"(*addr));
+	return val;
+}
+
+static void
+input_swap_data(int dev, ulong *sect_buf, int words)
+{
+	volatile ushort	*pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	ushort	*dbuf = (ushort *)sect_buf;
+
+	while (words--) {
+		*dbuf++ = ld_le16(pbuf);
+		*dbuf++ = ld_le16(pbuf);
+	}
+}
+
+static void
+output_data(int dev, ulong *sect_buf, int words)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (words--) {
+		__asm__ volatile ("eieio");
+		*pbuf = *dbuf++;
+		__asm__ volatile ("eieio");
+		*pbuf = *dbuf++;
+	}
+}
+
+static void
+input_data(int dev, ulong *sect_buf, int words)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (words--) {
+		__asm__ volatile ("eieio");
+		*dbuf++ = *pbuf;
+		__asm__ volatile ("eieio");
+		*dbuf++ = *pbuf;
+	}
+}
+
+/* -------------------------------------------------------------------------
+ */
+static void ide_ident (block_dev_desc_t *dev_desc)
+{
+	ulong iobuf[ATA_SECTORWORDS];
+	unsigned char c;
+	hd_driveid_t *iop = (hd_driveid_t *)iobuf;
+
+#if 0
+	int mode, cycle_time;
+#endif
+	int device;
+	device=dev_desc->dev;
+	printf ("  Device %d: ", device);
+
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+	/* Select device
+	 */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	dev_desc->if_type=IF_TYPE_IDE;
+#ifdef CONFIG_ATAPI
+	/* check signature */
+	if ((inb(device,ATA_SECT_CNT)==0x01) &&
+		 (inb(device,ATA_SECT_NUM)==0x01) &&
+		 (inb(device,ATA_CYL_LOW)==0x14) &&
+		 (inb(device,ATA_CYL_HIGH)==0xEB)) {
+		/* ATAPI Signature found */
+		dev_desc->if_type=IF_TYPE_ATAPI;
+		/* Start Ident Command
+		 */
+		outb (device, ATA_COMMAND, ATAPI_CMD_IDENT);
+		/*
+		 * Wait for completion - ATAPI devices need more time
+		 * to become ready
+		 */
+		c = ide_wait (device, ATAPI_TIME_OUT);
+	}
+	else
+#endif
+	{
+		/* Start Ident Command
+		 */
+		outb (device, ATA_COMMAND, ATA_CMD_IDENT);
+
+		/* Wait for completion
+		 */
+		c = ide_wait (device, IDE_TIME_OUT);
+	}
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+
+	if (((c & ATA_STAT_DRQ) == 0) ||
+	    ((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) {
+		dev_desc->type=DEV_TYPE_UNKNOWN;
+		return;
+	}
+
+	input_swap_data (device, iobuf, ATA_SECTORWORDS);
+
+	ident_cpy (dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision));
+	ident_cpy (dev_desc->vendor, iop->model, sizeof(dev_desc->vendor));
+	ident_cpy (dev_desc->product, iop->serial_no, sizeof(dev_desc->product));
+
+	if ((iop->config & 0x0080)==0x0080)
+		dev_desc->removable = 1;
+	else
+		dev_desc->removable = 0;
+
+#if 0
+	/*
+	 * Drive PIO mode autoselection
+	 */
+	mode = iop->tPIO;
+
+	printf ("tPIO = 0x%02x = %d\n",mode, mode);
+	if (mode > 2) {		/* 2 is maximum allowed tPIO value */
+		mode = 2;
+		PRINTF ("Override tPIO -> 2\n");
+	}
+	if (iop->field_valid & 2) {	/* drive implements ATA2? */
+		PRINTF ("Drive implements ATA2\n");
+		if (iop->capability & 8) {	/* drive supports use_iordy? */
+			cycle_time = iop->eide_pio_iordy;
+		} else {
+			cycle_time = iop->eide_pio;
+		}
+		PRINTF ("cycle time = %d\n", cycle_time);
+		mode = 4;
+		if (cycle_time > 120) mode = 3;	/* 120 ns for PIO mode 4 */
+		if (cycle_time > 180) mode = 2;	/* 180 ns for PIO mode 3 */
+		if (cycle_time > 240) mode = 1;	/* 240 ns for PIO mode 4 */
+		if (cycle_time > 383) mode = 0;	/* 383 ns for PIO mode 4 */
+	}
+	printf ("PIO mode to use: PIO %d\n", mode);
+#endif /* 0 */
+
+#ifdef CONFIG_ATAPI
+	if (dev_desc->if_type==IF_TYPE_ATAPI) {
+		atapi_inquiry(dev_desc);
+		return;
+	}
+#endif /* CONFIG_ATAPI */
+
+	/* swap shorts */
+	dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
+	/* assuming HD */
+	dev_desc->type=DEV_TYPE_HARDDISK;
+	dev_desc->blksz=ATA_BLOCKSIZE;
+	dev_desc->lun=0; /* just to fill something in... */
+
+#if 0 	/* only used to test the powersaving mode,
+	 * if enabled, the drive goes after 5 sec
+	 * in standby mode */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = ide_wait (device, IDE_TIME_OUT);
+	outb (device, ATA_SECT_CNT, 1);
+	outb (device, ATA_LBA_LOW,  0);
+	outb (device, ATA_LBA_MID,  0);
+	outb (device, ATA_LBA_HIGH, 0);
+	outb (device, ATA_DEV_HD,   ATA_LBA		|
+				    ATA_DEVICE(device));
+	outb (device, ATA_COMMAND,  0xe3);
+	udelay (50);
+	c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+	ulong n = 0;
+	unsigned char c;
+	unsigned char pwrsave=0; /* power save */
+
+	PRINTF ("ide_read dev %d start %lX, blocks %lX buffer at %lX\n",
+		device, blknr, blkcnt, (ulong)buffer);
+
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+
+	/* Select device
+	 */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = ide_wait (device, IDE_TIME_OUT);
+
+	if (c & ATA_STAT_BUSY) {
+		printf ("IDE read: device %d not ready\n", device);
+		goto IDE_READ_E;
+	}
+
+	/* first check if the drive is in Powersaving mode, if yes,
+	 * increase the timeout value */
+	outb (device, ATA_COMMAND,  ATA_CMD_CHK_PWR);
+	udelay (50);
+
+	c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+
+	if (c & ATA_STAT_BUSY) {
+		printf ("IDE read: device %d not ready\n", device);
+		goto IDE_READ_E;
+	}
+	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+		printf ("No Powersaving mode %X\n", c);
+	} else {
+		c = inb(device,ATA_SECT_CNT);
+		PRINTF("Powersaving %02X\n",c);
+		if(c==0)
+			pwrsave=1;
+	}
+
+
+	while (blkcnt-- > 0) {
+
+		c = ide_wait (device, IDE_TIME_OUT);
+
+		if (c & ATA_STAT_BUSY) {
+			printf ("IDE read: device %d not ready\n", device);
+			break;
+		}
+
+		outb (device, ATA_SECT_CNT, 1);
+		outb (device, ATA_LBA_LOW,  (blknr >>  0) & 0xFF);
+		outb (device, ATA_LBA_MID,  (blknr >>  8) & 0xFF);
+		outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+		outb (device, ATA_DEV_HD,   ATA_LBA		|
+					    ATA_DEVICE(device)	|
+					    ((blknr >> 24) & 0xF) );
+		outb (device, ATA_COMMAND,  ATA_CMD_READ);
+
+		udelay (50);
+
+		if(pwrsave) {
+			c = ide_wait (device, IDE_SPIN_UP_TIME_OUT);	/* may take up to 4 sec */
+			pwrsave=0;
+		} else {
+			c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+		}
+
+		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+				device, blknr, c);
+			break;
+		}
+
+		input_data (device, buffer, ATA_SECTORWORDS);
+		(void) inb (device, ATA_STATUS);	/* clear IRQ */
+
+		++n;
+		++blknr;
+		buffer += ATA_SECTORWORDS;
+	}
+IDE_READ_E:
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+	return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+	ulong n = 0;
+	unsigned char c;
+
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+
+	/* Select device
+	 */
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+	while (blkcnt-- > 0) {
+
+		c = ide_wait (device, IDE_TIME_OUT);
+
+		if (c & ATA_STAT_BUSY) {
+			printf ("IDE read: device %d not ready\n", device);
+			goto WR_OUT;
+		}
+
+		outb (device, ATA_SECT_CNT, 1);
+		outb (device, ATA_LBA_LOW,  (blknr >>  0) & 0xFF);
+		outb (device, ATA_LBA_MID,  (blknr >>  8) & 0xFF);
+		outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+		outb (device, ATA_DEV_HD,   ATA_LBA		|
+					    ATA_DEVICE(device)	|
+					    ((blknr >> 24) & 0xF) );
+		outb (device, ATA_COMMAND,  ATA_CMD_WRITE);
+
+		udelay (50);
+
+		c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
+
+		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+				device, blknr, c);
+			goto WR_OUT;
+		}
+
+		output_data (device, buffer, ATA_SECTORWORDS);
+		c = inb (device, ATA_STATUS);	/* clear IRQ */
+		++n;
+		++blknr;
+		buffer += ATA_SECTORWORDS;
+	}
+WR_OUT:
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+	return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * copy src to dest, skipping leading and trailing blanks and null
+ * terminate the string
+ */
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len)
+{
+	int start,end;
+
+	start=0;
+	while (start<len) {
+		if (src[start]!=' ')
+			break;
+		start++;
+	}
+	end=len-1;
+	while (end>start) {
+		if (src[end]!=' ')
+			break;
+		end--;
+	}
+	for ( ; start<=end; start++) {
+		*dest++=src[start];
+	}
+	*dest='\0';
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Wait until Busy bit is off, or timeout (in ms)
+ * Return last status
+ */
+static uchar ide_wait (int dev, ulong t)
+{
+	ulong delay = 10 * t;		/* poll every 100 us */
+	uchar c;
+
+	while ((c = inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
+		udelay (100);
+		if (delay-- == 0) {
+			break;
+		}
+	}
+	return (c);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_RESET
+extern void ide_set_reset(int idereset);
+
+static void ide_reset (void)
+{
+#if defined(CFG_PB_12V_ENABLE) || defined(CFG_PB_IDE_MOTOR)
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int i;
+
+	curr_device = -1;
+	for (i=0; i<CFG_IDE_MAXBUS; ++i)
+		ide_bus_ok[i] = 0;
+	for (i=0; i<CFG_IDE_MAXDEVICE; ++i)
+		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+
+	ide_set_reset (1); /* assert reset */
+
+	WATCHDOG_RESET();
+
+#ifdef CFG_PB_12V_ENABLE
+	immr->im_cpm.cp_pbdat &= ~(CFG_PB_12V_ENABLE);	/* 12V Enable output OFF */
+	immr->im_cpm.cp_pbpar &= ~(CFG_PB_12V_ENABLE);
+	immr->im_cpm.cp_pbodr &= ~(CFG_PB_12V_ENABLE);
+	immr->im_cpm.cp_pbdir |=   CFG_PB_12V_ENABLE;
+
+	/* wait 500 ms for the voltage to stabilize
+	 */
+	for (i=0; i<500; ++i) {
+		udelay (1000);
+	}
+
+	immr->im_cpm.cp_pbdat |=   CFG_PB_12V_ENABLE;	/* 12V Enable output ON */
+#endif	/* CFG_PB_12V_ENABLE */
+
+#ifdef CFG_PB_IDE_MOTOR
+	/* configure IDE Motor voltage monitor pin as input */
+	immr->im_cpm.cp_pbpar &= ~(CFG_PB_IDE_MOTOR);
+	immr->im_cpm.cp_pbodr &= ~(CFG_PB_IDE_MOTOR);
+	immr->im_cpm.cp_pbdir &= ~(CFG_PB_IDE_MOTOR);
+
+	/* wait up to 1 s for the motor voltage to stabilize
+	 */
+	for (i=0; i<1000; ++i) {
+		if ((immr->im_cpm.cp_pbdat & CFG_PB_IDE_MOTOR) != 0) {
+			break;
+		}
+		udelay (1000);
+	}
+
+	if (i == 1000) {	/* Timeout */
+		printf ("\nWarning: 5V for IDE Motor missing\n");
+# ifdef CONFIG_STATUS_LED
+#  ifdef STATUS_LED_YELLOW
+		status_led_set  (STATUS_LED_YELLOW, STATUS_LED_ON );
+#  endif
+#  ifdef STATUS_LED_GREEN
+		status_led_set  (STATUS_LED_GREEN,  STATUS_LED_OFF);
+#  endif
+# endif	/* CONFIG_STATUS_LED */
+	}
+#endif	/* CFG_PB_IDE_MOTOR */
+
+	WATCHDOG_RESET();
+
+	/* de-assert RESET signal */
+	ide_set_reset(0);
+
+	/* wait 250 ms */
+	for (i=0; i<250; ++i) {
+		udelay (1000);
+	}
+}
+
+#endif	/* CONFIG_IDE_RESET */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+
+static	uchar	led_buffer = 0;		/* Buffer for current LED status	*/
+
+static void ide_led (uchar led, uchar status)
+{
+	uchar *led_port = LED_PORT;
+
+	if (status)	{		/* switch LED on	*/
+		led_buffer |=  led;
+	} else {			/* switch LED off	*/
+		led_buffer &= ~led;
+	}
+
+	*led_port = led_buffer;
+}
+
+#endif	/* CONFIG_IDE_LED */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATAPI
+/****************************************************************************
+ * ATAPI Support
+ */
+
+
+
+#undef	ATAPI_DEBUG
+
+#ifdef	ATAPI_DEBUG
+#define	AT_PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define AT_PRINTF(fmt,args...)
+#endif
+
+/* since ATAPI may use commands with not 4 bytes alligned length
+ * we have our own transfer functions, 2 bytes alligned */
+static void
+output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (shorts--) {
+		__asm__ volatile ("eieio");
+		*pbuf = *dbuf++;
+	}
+}
+
+static void
+input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	ushort	*dbuf;
+	volatile ushort	*pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (shorts--) {
+		__asm__ volatile ("eieio");
+		*dbuf++ = *pbuf;
+	}
+}
+
+/*
+ * Wait until (Status & mask) == res, or timeout (in ms)
+ * Return last status
+ * This is used since some ATAPI CD ROMs clears their Busy Bit first
+ * and then they set their DRQ Bit
+ */
+static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res)
+{
+	ulong delay = 10 * t;		/* poll every 100 us */
+	uchar c;
+
+	c = inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */
+	while (((c = inb(dev, ATA_STATUS)) & mask)
+			!= res) {
+		/* break if error occurs (doesn't make sense to wait more) */
+		if((c & ATA_STAT_ERR)==ATA_STAT_ERR)
+			break;
+		udelay (100);
+		if (delay-- == 0) {
+			break;
+		}
+	}
+	return (c);
+}
+
+/*
+ * issue an atapi command
+ */
+unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen)
+{
+	unsigned char c,err,mask,res;
+	int n;
+	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
+
+	/* Select device
+	 */
+	mask = ATA_STAT_BUSY|ATA_STAT_DRQ;
+	res = 0;
+	outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+	if ((c & mask) != res) {
+		printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c);
+		err=0xFF;
+		goto AI_OUT;
+	}
+	/* write taskfile */
+	outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */
+	outb (device, ATA_CYL_LOW,  (unsigned char)(buflen & 0xFF));
+	outb (device, ATA_CYL_HIGH, (unsigned char)((buflen<<8) & 0xFF));
+	outb (device, ATA_DEV_HD,   ATA_LBA | ATA_DEVICE(device));
+
+	outb (device, ATA_COMMAND,  ATAPI_CMD_PACKET);
+	udelay (50);
+
+	mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+	res = ATA_STAT_DRQ;
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+
+	if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */
+		printf ("ATTAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c);
+		err=0xFF;
+		goto AI_OUT;
+	}
+
+	output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */
+ 	/* ATAPI Command written wait for completition */
+	udelay (5000); /* device must set bsy */
+
+	mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+	/* if no data wait for DRQ = 0 BSY = 0
+	 * if data wait for DRQ = 1 BSY = 0 */
+	res=0;
+	if(buflen)
+		res = ATA_STAT_DRQ;
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+	if ((c & mask) != res ) {
+		if (c & ATA_STAT_ERR) {
+			err=(inb(device,ATA_ERROR_REG))>>4;
+			AT_PRINTF("atapi_issue 1 returned sense key %X status %02X\n",err,c);
+		} else {
+			printf ("ATTAPI_ISSUE: (no DRQ) after sending ccb (%x)  status 0x%02x\n", ccb[0],c);
+			err=0xFF;
+		}
+		goto AI_OUT;
+	}
+	n=inb(device, ATA_CYL_HIGH);
+	n<<=8;
+	n+=inb(device, ATA_CYL_LOW);
+	if(n>buflen) {
+		printf("ERROR, transfer bytes %d requested only %d\n",n,buflen);
+		err=0xff;
+		goto AI_OUT;
+	}
+	if((n==0)&&(buflen<0)) {
+		printf("ERROR, transfer bytes %d requested %d\n",n,buflen);
+		err=0xff;
+		goto AI_OUT;
+	}
+	if(n!=buflen) {
+		AT_PRINTF("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen);
+	}
+	if(n!=0) { /* data transfer */
+		AT_PRINTF("ATAPI_ISSUE: %d Bytes to transfer\n",n);
+		 /* we transfer shorts */
+		n>>=1;
+		/* ok now decide if it is an in or output */
+		if ((inb(device, ATA_SECT_CNT)&0x02)==0) {
+			AT_PRINTF("Write to device\n");
+			output_data_shorts(device,(unsigned short *)buffer,n);
+		} else {
+			AT_PRINTF("Read from device @ %p shorts %d\n",buffer,n);
+			input_data_shorts(device,(unsigned short *)buffer,n);
+		}
+	}
+	udelay(5000); /* seems that some CD ROMs need this... */
+	mask = ATA_STAT_BUSY|ATA_STAT_ERR;
+	res=0;
+	c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+		err=(inb(device,ATA_ERROR_REG) >> 4);
+		AT_PRINTF("atapi_issue 2 returned sense key %X status %X\n",err,c);
+	} else {
+		err = 0;
+	}
+AI_OUT:
+	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
+	return (err);
+}
+
+/*
+ * sending the command to atapi_issue. If an status other than good
+ * returns, an request_sense will be issued
+ */
+
+#define ATAPI_DRIVE_NOT_READY 	100
+#define ATAPI_UNIT_ATTN		10
+
+unsigned char atapi_issue_autoreq (int device,
+				   unsigned char* ccb,
+				   int ccblen,
+				   unsigned char *buffer,
+				   int buflen)
+{
+	unsigned char sense_data[18],sense_ccb[12];
+	unsigned char res,key,asc,ascq;
+	int notready,unitattn;
+
+	unitattn=ATAPI_UNIT_ATTN;
+	notready=ATAPI_DRIVE_NOT_READY;
+
+retry:
+	res= atapi_issue(device,ccb,ccblen,buffer,buflen);
+	if (res==0)
+		return (0); /* Ok */
+
+	if (res==0xFF)
+		return (0xFF); /* error */
+
+	AT_PRINTF("(auto_req)atapi_issue returned sense key %X\n",res);
+
+	memset(sense_ccb,0,sizeof(sense_ccb));
+	memset(sense_data,0,sizeof(sense_data));
+	sense_ccb[0]=ATAPI_CMD_REQ_SENSE;
+	sense_ccb[4]=18; /* allocation Legnth */
+
+	res=atapi_issue(device,sense_ccb,12,sense_data,18);
+	key=(sense_data[2]&0xF);
+	asc=(sense_data[12]);
+	ascq=(sense_data[13]);
+
+	AT_PRINTF("ATAPI_CMD_REQ_SENSE returned %x\n",res);
+	AT_PRINTF(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
+		sense_data[0],
+		key,
+		asc,
+		ascq);
+
+	if((key==0))
+		return 0; /* ok device ready */
+
+	if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */
+		if(unitattn-->0) {
+			udelay(200*1000);
+			goto retry;
+		}
+		printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN);
+		goto error;
+	}
+	if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */
+		if (notready-->0) {
+			udelay(200*1000);
+			goto retry;
+		}
+		printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY);
+		goto error;
+	}
+	if(asc==0x3a) {
+		AT_PRINTF("Media not present\n");
+		goto error;
+	}
+	printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+error:
+	AT_PRINTF ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+	return (0xFF);
+}
+
+
+
+static void	atapi_inquiry(block_dev_desc_t * dev_desc)
+{
+	unsigned char ccb[12]; /* Command descriptor block */
+	unsigned char iobuf[64]; /* temp buf */
+	unsigned char c;
+	int device;
+
+	device=dev_desc->dev;
+	dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */
+	dev_desc->block_read=atapi_read;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+
+	ccb[0]=ATAPI_CMD_INQUIRY;
+	ccb[4]=40; /* allocation Legnth */
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40);
+
+	AT_PRINTF("ATAPI_CMD_INQUIRY returned %x\n",c);
+	if (c!=0)
+		return;
+
+	/* copy device ident strings */
+	ident_cpy(dev_desc->vendor,&iobuf[8],8);
+	ident_cpy(dev_desc->product,&iobuf[16],16);
+	ident_cpy(dev_desc->revision,&iobuf[32],5);
+
+	dev_desc->lun=0;
+	dev_desc->lba=0;
+	dev_desc->blksz=0;
+	dev_desc->type=iobuf[0] & 0x1f;
+
+	if ((iobuf[1]&0x80)==0x80)
+		dev_desc->removable = 1;
+	else
+		dev_desc->removable = 0;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+	ccb[0]=ATAPI_CMD_START_STOP;
+	ccb[4]=0x03; /* start */
+
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+	AT_PRINTF("ATAPI_CMD_START_STOP returned %x\n",c);
+	if (c!=0)
+		return;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+	AT_PRINTF("ATAPI_CMD_UNIT_TEST_READY returned %x\n",c);
+	if (c!=0)
+		return;
+
+	memset(ccb,0,sizeof(ccb));
+	memset(iobuf,0,sizeof(iobuf));
+	ccb[0]=ATAPI_CMD_READ_CAP;
+	c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,8);
+	AT_PRINTF("ATAPI_CMD_READ_CAP returned %x\n",c);
+	if (c!=0)
+		return;
+
+	AT_PRINTF("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
+		iobuf[0],iobuf[1],iobuf[2],iobuf[3],
+		iobuf[4],iobuf[5],iobuf[6],iobuf[7]);
+
+	dev_desc->lba  =((unsigned long)iobuf[0]<<24) +
+			((unsigned long)iobuf[1]<<16) +
+			((unsigned long)iobuf[2]<< 8) +
+			((unsigned long)iobuf[3]);
+	dev_desc->blksz=((unsigned long)iobuf[4]<<24) +
+			((unsigned long)iobuf[5]<<16) +
+			((unsigned long)iobuf[6]<< 8) +
+			((unsigned long)iobuf[7]);
+	return;
+}
+
+
+/*
+ * atapi_read:
+ * we transfer only one block per command, since the multiple DRQ per
+ * command is not yet implemented
+ */
+#define ATAPI_READ_MAX_BYTES	2048	/* we read max 2kbytes */
+#define ATAPI_READ_BLOCK_SIZE	2048	/* assuming CD part */
+#define ATAPI_READ_MAX_BLOCK ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE	/* max blocks */
+
+ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+	ulong n = 0;
+	unsigned char ccb[12]; /* Command descriptor block */
+	ulong cnt;
+
+	AT_PRINTF("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n",
+		device, blknr, blkcnt, (ulong)buffer);
+
+	do {
+		if (blkcnt>ATAPI_READ_MAX_BLOCK) {
+			cnt=ATAPI_READ_MAX_BLOCK;
+		} else {
+			cnt=blkcnt;
+		}
+		ccb[0]=ATAPI_CMD_READ_12;
+		ccb[1]=0; /* reserved */
+		ccb[2]=(unsigned char) (blknr>>24) & 0xFF; /* MSB Block */
+		ccb[3]=(unsigned char) (blknr>>16) & 0xFF; /*  */
+		ccb[4]=(unsigned char) (blknr>> 8) & 0xFF;
+		ccb[5]=(unsigned char)  blknr      & 0xFF; /* LSB Block */
+		ccb[6]=(unsigned char) (cnt  >>24) & 0xFF; /* MSB Block count */
+		ccb[7]=(unsigned char) (cnt  >>16) & 0xFF;
+		ccb[8]=(unsigned char) (cnt  >> 8) & 0xFF;
+		ccb[9]=(unsigned char)  cnt	   & 0xFF; /* LSB Block */
+		ccb[10]=0; /* reserved */
+		ccb[11]=0; /* reserved */
+
+		if (atapi_issue_autoreq(device,ccb,12,
+					(unsigned char *)buffer,
+					cnt*ATAPI_READ_BLOCK_SIZE) == 0xFF) {
+			return (n);
+		}
+		n+=cnt;
+		blkcnt-=cnt;
+		blknr+=cnt;
+		buffer+=cnt*(ATAPI_READ_BLOCK_SIZE/4); /* ulong blocksize in ulong */
+	} while (blkcnt > 0);
+	return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CONFIG_ATAPI */
+
+#endif	/* CONFIG_COMMANDS & CFG_CMD_IDE */
diff --git a/common/cmd_immap.c b/common/cmd_immap.c
new file mode 100644
index 0000000..443335b
--- /dev/null
+++ b/common/cmd_immap.c
@@ -0,0 +1,578 @@
+/*
+ * (C) Copyright 2000
+ * 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
+ */
+
+/*
+ * MPC8xx/MPC8260 Internal Memory Map Functions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cmd_immap.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_IMMAP) && \
+    (defined(CONFIG_8xx) || defined(CONFIG_8260))
+
+#if defined(CONFIG_8xx)
+#include <asm/8xx_immap.h>
+#include <commproc.h>
+#elif defined(CONFIG_8260)
+#include <asm/immap_8260.h>
+#include <asm/cpm_8260.h>
+#include <asm/iopin_8260.h>
+#endif
+
+static void
+unimplemented ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	printf ("Sorry, but the '%s' command has not been implemented\n",
+		cmdtp->name);
+}
+
+int
+do_siuinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile sysconf8xx_t *sc = &immap->im_siu_conf;
+#elif defined(CONFIG_8260)
+	volatile sysconf8260_t *sc = &immap->im_siu_conf;
+#endif
+
+	printf ("SIUMCR= %08x SYPCR = %08x\n", sc->sc_siumcr, sc->sc_sypcr);
+#if defined(CONFIG_8xx)
+	printf ("SWT   = %08x\n", sc->sc_swt);
+	printf ("SIPEND= %08x SIMASK= %08x\n", sc->sc_sipend, sc->sc_simask);
+	printf ("SIEL  = %08x SIVEC = %08x\n", sc->sc_siel, sc->sc_sivec);
+	printf ("TESR  = %08x SDCR  = %08x\n", sc->sc_tesr, sc->sc_sdcr);
+#elif defined(CONFIG_8260)
+	printf ("BCR   = %08x\n", sc->sc_bcr);
+	printf ("P_ACR =       %02x P_ALRH= %08x P_ALRL= %08x\n",
+		sc->sc_ppc_acr, sc->sc_ppc_alrh, sc->sc_ppc_alrl);
+	printf ("L_ACR =       %02x L_ALRH= %08x L_ALRL= %08x\n",
+		sc->sc_lcl_acr, sc->sc_lcl_alrh, sc->sc_lcl_alrl);
+	printf ("PTESR1= %08x PTESR2= %08x\n", sc->sc_tescr1, sc->sc_tescr2);
+	printf ("LTESR1= %08x LTESR2= %08x\n", sc->sc_ltescr1, sc->sc_ltescr2);
+	printf ("PDTEA = %08x PDTEM =       %02x\n", sc->sc_pdtea, sc->sc_pdtem);
+	printf ("LDTEA = %08x LDTEM =       %02x\n", sc->sc_ldtea, sc->sc_ldtem);
+#endif
+	return 0;
+}
+
+int
+do_memcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	int nbanks = 8;
+#elif defined(CONFIG_8260)
+	volatile memctl8260_t *memctl = &immap->im_memctl;
+	int nbanks = 12;
+#endif
+	volatile uint *p = &memctl->memc_br0;
+	int i;
+
+	for (i = 0; i < nbanks; i++, p += 2) {
+		if (i < 10) {
+			printf ("BR%d   = %08x OR%d   = %08x\n",
+				i, p[0], i, p[1]);
+		} else {
+			printf ("BR%d  = %08x OR%d  = %08x\n",
+				i, p[0], i, p[1]);
+		}
+	}
+
+	printf ("MAR   = %08x", memctl->memc_mar);
+#if defined(CONFIG_8xx)
+	printf (" MCR   = %08x\n", memctl->memc_mcr);
+#elif defined(CONFIG_8260)
+	printf ("\n");
+#endif
+	printf ("MAMR  = %08x MBMR  = %08x",
+		memctl->memc_mamr, memctl->memc_mbmr);
+#if defined(CONFIG_8xx)
+	printf ("\nMSTAT =     %04x\n", memctl->memc_mstat);
+#elif defined(CONFIG_8260)
+	printf (" MCMR  = %08x\n", memctl->memc_mcmr);
+#endif
+	printf ("MPTPR =     %04x MDR   = %08x\n",
+		memctl->memc_mptpr, memctl->memc_mdr);
+#if defined(CONFIG_8260)
+	printf ("PSDMR = %08x LSDMR = %08x\n",
+		memctl->memc_psdmr, memctl->memc_lsdmr);
+	printf ("PURT  =       %02x PSRT  =       %02x\n",
+		memctl->memc_purt, memctl->memc_psrt);
+	printf ("LURT  =       %02x LSRT  =       %02x\n",
+		memctl->memc_lurt, memctl->memc_lsrt);
+	printf ("IMMR  = %08x\n", memctl->memc_immr);
+#endif
+	return 0;
+}
+
+int
+do_sitinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+#ifdef CONFIG_8260
+int
+do_icinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+#endif
+
+int
+do_carinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+static int counter;
+
+static void
+header(void)
+{
+	char *data = "\
+       --------------------------------        --------------------------------\
+       00000000001111111111222222222233        00000000001111111111222222222233\
+       01234567890123456789012345678901        01234567890123456789012345678901\
+       --------------------------------        --------------------------------\
+    ";
+	int i;
+
+	if (counter % 2)
+	putc('\n');
+	counter = 0;
+
+	for (i = 0; i < 4; i++, data += 79)
+		printf("%.79s\n", data);
+}
+
+static void binary (char *label, uint value, int nbits)
+{
+	uint mask = 1 << (nbits - 1);
+	int i, second = (counter++ % 2);
+
+	if (second)
+		putc (' ');
+	puts (label);
+	for (i = 32 + 1; i != nbits; i--)
+		putc (' ');
+
+	while (mask != 0) {
+		if (value & mask)
+			putc ('1');
+		else
+			putc ('0');
+		mask >>= 1;
+	}
+
+	if (second)
+		putc ('\n');
+}
+
+#if defined(CONFIG_8xx)
+#define PA_NBITS	16
+#define PA_NB_ODR	 8
+#define PB_NBITS	18
+#define PB_NB_ODR	16
+#define PC_NBITS	12
+#define PD_NBITS	13
+#elif defined(CONFIG_8260)
+#define PA_NBITS	32
+#define PA_NB_ODR	32
+#define PB_NBITS	28
+#define PB_NB_ODR	28
+#define PC_NBITS	32
+#define PD_NBITS	28
+#endif
+
+int
+do_iopinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile iop8xx_t *iop = &immap->im_ioport;
+	volatile ushort *l, *r;
+#elif defined(CONFIG_8260)
+	volatile iop8260_t *iop = &immap->im_ioport;
+	volatile uint *l, *r;
+#endif
+	volatile uint *R;
+
+	counter = 0;
+	header ();
+
+	/*
+	 * Ports A & B
+	 */
+
+#if defined(CONFIG_8xx)
+	l = &iop->iop_padir;
+	R = &immap->im_cpm.cp_pbdir;
+#elif defined(CONFIG_8260)
+	l = &iop->iop_pdira;
+	R = &iop->iop_pdirb;
+#endif
+	binary ("PA_DIR", *l++, PA_NBITS);
+	binary ("PB_DIR", *R++, PB_NBITS);
+	binary ("PA_PAR", *l++, PA_NBITS);
+	binary ("PB_PAR", *R++, PB_NBITS);
+#if defined(CONFIG_8260)
+	binary ("PA_SOR", *l++, PA_NBITS);
+	binary ("PB_SOR", *R++, PB_NBITS);
+#endif
+	binary ("PA_ODR", *l++, PA_NB_ODR);
+	binary ("PB_ODR", *R++, PB_NB_ODR);
+	binary ("PA_DAT", *l++, PA_NBITS);
+	binary ("PB_DAT", *R++, PB_NBITS);
+
+	header ();
+
+	/*
+	 * Ports C & D
+	 */
+
+#if defined(CONFIG_8xx)
+	l = &iop->iop_pcdir;
+	r = &iop->iop_pddir;
+#elif defined(CONFIG_8260)
+	l = &iop->iop_pdirc;
+	r = &iop->iop_pdird;
+#endif
+	binary ("PC_DIR", *l++, PC_NBITS);
+	binary ("PD_DIR", *r++, PD_NBITS);
+	binary ("PC_PAR", *l++, PC_NBITS);
+	binary ("PD_PAR", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+	binary ("PC_SO ", *l++, PC_NBITS);
+	binary ("      ", 0, 0);
+	r++;
+#elif defined(CONFIG_8260)
+	binary ("PC_SOR", *l++, PC_NBITS);
+	binary ("PD_SOR", *r++, PD_NBITS);
+	binary ("PC_ODR", *l++, PC_NBITS);
+	binary ("PD_ODR", *r++, PD_NBITS);
+#endif
+	binary ("PC_DAT", *l++, PC_NBITS);
+	binary ("PD_DAT", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+	binary ("PC_INT", *l++, PC_NBITS);
+#endif
+
+	header ();
+	return 0;
+}
+
+/*
+ * set the io pins
+ * this needs a clean up for smaller tighter code
+ * use *uint and set the address based on cmd + port
+ */
+int
+do_iopset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_8260)
+	uint rcode = 0;
+	static uint port = 0;
+	static uint pin = 0;
+	static uint value = 0;
+	static enum { DIR, PAR, SOR, ODR, DAT } cmd = DAT;
+	iopin_t iopin;
+
+	if (argc != 5) {
+		printf ("iopset PORT PIN CMD VALUE\n");
+		return 1;
+	}
+	port = argv[1][0] - 'A';
+	if (port > 3)
+		port -= 0x20;
+	if (port > 3)
+		rcode = 1;
+	pin = simple_strtol (argv[2], NULL, 10);
+	if (pin > 31)
+		rcode = 1;
+
+
+	switch (argv[3][0]) {
+	case 'd':
+		if (argv[3][1] == 'a')
+			cmd = DAT;
+		else if (argv[3][1] == 'i')
+			cmd = DIR;
+		else
+			rcode = 1;
+		break;
+	case 'p':
+		cmd = PAR;
+		break;
+	case 'o':
+		cmd = ODR;
+		break;
+	case 's':
+		cmd = SOR;
+		break;
+	default:
+		printf ("iopset: unknown command %s\n", argv[3]);
+		rcode = 1;
+	}
+	if (argv[4][0] == '1')
+		value = 1;
+	else if (argv[4][0] == '0')
+		value = 0;
+	else
+		rcode = 1;
+	if (rcode == 0) {
+		iopin.port = port;
+		iopin.pin = pin;
+		switch (cmd) {
+		case DIR:
+			if (value)
+				iopin_set_out (&iopin);
+			else
+				iopin_set_in (&iopin);
+			break;
+		case PAR:
+			if (value)
+				iopin_set_ded (&iopin);
+			else
+				iopin_set_gen (&iopin);
+			break;
+		case SOR:
+			if (value)
+				iopin_set_opt2 (&iopin);
+			else
+				iopin_set_opt1 (&iopin);
+			break;
+		case ODR:
+			if (value)
+				iopin_set_odr (&iopin);
+			else
+				iopin_set_act (&iopin);
+			break;
+		case DAT:
+			if (value)
+				iopin_set_high (&iopin);
+			else
+				iopin_set_low (&iopin);
+			break;
+		}
+
+	}
+	return rcode;
+#else
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+#endif
+}
+
+int
+do_dmainfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_fccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+static void prbrg (int n, uint val)
+{
+	uint extc = (val >> 14) & 3;
+	uint cd = (val & CPM_BRG_CD_MASK) >> 1;
+	uint div16 = (val & CPM_BRG_DIV16) != 0;
+
+#if defined(CONFIG_8xx)
+	DECLARE_GLOBAL_DATA_PTR;
+	ulong clock = gd->cpu_clk;
+#elif defined(CONFIG_8260)
+	DECLARE_GLOBAL_DATA_PTR;
+	ulong clock = gd->brg_clk;
+#endif
+
+	printf ("BRG%d:", n);
+
+	if (val & CPM_BRG_RST)
+		puts (" RESET");
+	else
+		puts ("      ");
+
+	if (val & CPM_BRG_EN)
+		puts ("  ENABLED");
+	else
+		puts (" DISABLED");
+
+	printf (" EXTC=%d", extc);
+
+	if (val & CPM_BRG_ATB)
+		puts (" ATB");
+	else
+		puts ("    ");
+
+	printf (" DIVIDER=%4d", cd);
+	if (extc == 0 && cd != 0) {
+		uint baudrate;
+
+		if (div16)
+			baudrate = (clock / 16) / (cd + 1);
+		else
+			baudrate = clock / (cd + 1);
+
+		printf ("=%6d bps", baudrate);
+	} else {
+		puts ("           ");
+	}
+
+	if (val & CPM_BRG_DIV16)
+		puts (" DIV16");
+	else
+		puts ("      ");
+
+	putc ('\n');
+}
+
+int
+do_brginfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile cpm8xx_t *cp = &immap->im_cpm;
+	volatile uint *p = &cp->cp_brgc1;
+#elif defined(CONFIG_8260)
+	volatile uint *p = &immap->im_brgc1;
+#endif
+	int i = 1;
+
+	while (i <= 4)
+		prbrg (i++, *p++);
+
+#if defined(CONFIG_8260)
+	p = &immap->im_brgc5;
+	while (i <= 8)
+		prbrg (i++, *p++);
+#endif
+	return 0;
+}
+
+int
+do_i2cinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+	volatile i2c8xx_t *i2c = &immap->im_i2c;
+	volatile cpm8xx_t *cp = &immap->im_cpm;
+	volatile iic_t *iip = (iic_t *) & cp->cp_dparam[PROFF_IIC];
+#elif defined(CONFIG_8260)
+	volatile i2c8260_t *i2c = &immap->im_i2c;
+	volatile iic_t *iip;
+	uint dpaddr;
+
+	dpaddr = *((unsigned short *) (&immap->im_dprambase[PROFF_I2C_BASE]));
+	if (dpaddr == 0)
+		iip = NULL;
+	else
+		iip = (iic_t *) & immap->im_dprambase[dpaddr];
+#endif
+
+	printf ("I2MOD = %02x I2ADD = %02x\n", i2c->i2c_i2mod, i2c->i2c_i2add);
+	printf ("I2BRG = %02x I2COM = %02x\n", i2c->i2c_i2brg, i2c->i2c_i2com);
+	printf ("I2CER = %02x I2CMR = %02x\n", i2c->i2c_i2cer, i2c->i2c_i2cmr);
+
+	if (iip == NULL)
+		printf ("i2c parameter ram not allocated\n");
+	else {
+		printf ("RBASE = %08x TBASE = %08x\n",
+			iip->iic_rbase, iip->iic_tbase);
+		printf ("RFCR  =       %02x TFCR  =       %02x\n",
+			iip->iic_rfcr, iip->iic_tfcr);
+		printf ("MRBLR =     %04x\n", iip->iic_mrblr);
+		printf ("RSTATE= %08x RDP   = %08x\n",
+			iip->iic_rstate, iip->iic_rdp);
+		printf ("RBPTR =     %04x RBC   =     %04x\n",
+			iip->iic_rbptr, iip->iic_rbc);
+		printf ("RXTMP = %08x\n", iip->iic_rxtmp);
+		printf ("TSTATE= %08x TDP   = %08x\n",
+			iip->iic_tstate, iip->iic_tdp);
+		printf ("TBPTR =     %04x TBC   =     %04x\n",
+			iip->iic_tbptr, iip->iic_tbc);
+		printf ("TXTMP = %08x\n", iip->iic_txtmp);
+	}
+	return 0;
+}
+
+int
+do_sccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_smcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_spiinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_muxinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_siinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+
+int
+do_mccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unimplemented (cmdtp, flag, argc, argv);
+	return 0;
+}
+#endif	/* CFG_CMD_IMMAP && (CONFIG_8xx || CONFIG_8260) */
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
new file mode 100644
index 0000000..fc1d9c4
--- /dev/null
+++ b/common/cmd_jffs2.c
@@ -0,0 +1,179 @@
+/*
+ * (C) Copyright 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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <cmd_autoscript.h>
+#include <s_record.h>
+#include <net.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+
+#include <jffs2/jffs2.h>
+static int part_num=0;
+
+#ifndef CFG_JFFS_CUSTOM_PART
+
+static struct part_info part;
+
+struct part_info*
+jffs2_part_info(int part_num)
+{
+	extern flash_info_t flash_info[];	/* info for FLASH chips */
+	int i;
+
+	if(part_num==0){
+
+		if(part.usr_priv==(void*)1)
+			return &part;
+
+		memset(&part, 0, sizeof(part));
+
+#if defined(CFG_JFFS2_FIRST_SECTOR)
+		part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR];
+#else
+		part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#endif
+
+		/* Figure out flash partition size */
+		for (i = CFG_JFFS2_FIRST_BANK; i < CFG_JFFS2_NUM_BANKS+CFG_JFFS2_FIRST_BANK; i++)
+			part.size += flash_info[i].size;
+
+#if defined(CFG_JFFS2_FIRST_SECTOR) && (CFG_JFFS2_FIRST_SECTOR > 0)
+		part.size -=
+			flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR] -
+			flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#endif
+
+		/* unused in current jffs2 loader */
+		part.erasesize = 0;
+
+		/* Mark the struct as ready */
+		part.usr_priv=(void*)1;
+
+		return &part;
+	}
+	return 0;
+}
+#endif /* ifndef CFG_JFFS_CUSTOM_PART */
+int
+do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *filename = "pImage";
+	ulong offset = CFG_LOAD_ADDR;
+	int size;
+	struct part_info *part;
+
+	if (argc == 2) {
+		filename = argv[1];
+	}
+	if (argc == 3) {
+		offset = simple_strtoul(argv[1], NULL, 16);
+		filename = argv[2];
+	}
+
+	if (0 != (part=jffs2_part_info(part_num))){
+
+		printf("### JFFS2 loading '%s' to 0x%lx\n", filename, offset);
+		size = jffs2_1pass_load((char *)offset, part, filename);
+
+		if (size > 0) {
+			char buf[10];
+			printf("### JFFS2 load complete: %d bytes loaded to 0x%lx\n",
+				size, offset);
+			sprintf(buf, "%x", size);
+			setenv("filesize", buf);
+		} else {
+			printf("### JFFS2 LOAD ERROR<%x> for %s!\n", size, filename);
+		}
+
+		return !(size > 0);
+	}
+	printf("Active partition not valid\n");
+	return 0;
+}
+
+int
+do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *filename = "/";
+	int ret;
+	struct part_info *part;
+
+	if (argc == 2)
+		filename = argv[1];
+
+	if (0 != (part=jffs2_part_info(part_num))){
+
+		ret = jffs2_1pass_ls(jffs2_part_info(part_num), filename);
+
+		return (ret == 1);
+	}
+	printf("Active partition not valid\n");
+	return 0;
+}
+
+int
+do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int ret;
+	struct part_info *part;
+
+	if (0 != (part=jffs2_part_info(part_num))){
+
+		ret = jffs2_1pass_info(jffs2_part_info(part_num));
+
+		return (ret == 1);
+	}
+	printf("Active partition not valid\n");
+	return 0;
+}
+
+int
+do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int tmp_part;
+
+	if (argc >= 2) {
+		tmp_part = simple_strtoul(argv[1], NULL, 16);
+	}else{
+		printf("Need partition number in argument list\n");
+		return 0;
+
+	}
+
+	if (jffs2_part_info(tmp_part)){
+		printf("Partiton changed to %d\n",tmp_part);
+		part_num=tmp_part;
+		return 0;
+	}
+
+	printf("Partition %d is not valid partiton\n",tmp_part);
+	return 0;
+
+}
+#endif /* CFG_CMD_JFFS2 */
diff --git a/common/cmd_pci.c b/common/cmd_pci.c
new file mode 100644
index 0000000..22e4b9a
--- /dev/null
+++ b/common/cmd_pci.c
@@ -0,0 +1,477 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Wolfgang Grandegger, DENX Software Engineering, wg@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
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <command.h>
+#include <cmd_boot.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <cmd_pci.h>
+#include <pci.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCI)
+
+extern int cmd_get_data_size(char* arg, int default_size);
+
+unsigned char	ShortPCIListing = 1;
+
+/*
+ * Follows routines for the output of infos about devices on PCI bus.
+ */
+
+void pci_header_show(pci_dev_t dev);
+void pci_header_show_brief(pci_dev_t dev);
+
+/*
+ * Subroutine:  pciinfo
+ *
+ * Description: Show information about devices on PCI bus.
+ *				Depending on the define CFG_SHORT_PCI_LISTING
+ *				the output will be more or less exhaustive.
+ *
+ * Inputs:	bus_no		the number of the bus to be scanned.
+ *
+ * Return:      None
+ *
+ */
+void pciinfo(int BusNum, int ShortPCIListing)
+{
+	int Device;
+	int Function;
+	unsigned char HeaderType;
+	unsigned short VendorID;
+	pci_dev_t dev;
+
+	printf("Scanning PCI devices on bus %d\n", BusNum);
+
+	if (ShortPCIListing) {
+		printf("BusDevFun  VendorId   DeviceId   Device Class       Sub-Class\n");
+		printf("_____________________________________________________________\n");
+	}
+
+	for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
+		HeaderType = 0;
+		VendorID = 0;
+		for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
+			/*
+			 * If this is not a multi-function device, we skip the rest.
+			 */
+			if (Function && !(HeaderType & 0x80))
+				break;
+
+			dev = PCI_BDF(BusNum, Device, Function);
+
+			pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
+			if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
+				continue;
+
+			pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
+
+			if (ShortPCIListing)
+			{
+				printf("%02x.%02x.%02x   ", BusNum, Device, Function);
+				pci_header_show_brief(dev);
+			}
+			else
+			{
+				printf("\nFound PCI device %02x.%02x.%02x:\n",
+				       BusNum, Device, Function);
+				pci_header_show(dev);
+			}
+	    }
+    }
+}
+
+char* pci_classes_str(u8 class)
+{
+	static char *pci_classes[] = {
+		"Build before PCI Rev2.0",
+		"Mass storage controller",
+		"Network controller     ",
+		"Display controller     ",
+		"Multimedia device      ",
+		"Memory controller      ",
+		"Bridge device          ",
+		"Simple comm. controller",
+		"Base system peripheral ",
+		"Input device           ",
+		"Docking station        ",
+		"Processor              ",
+		"Serial bus controller  ",
+		"Reserved entry         ",
+		"Does not fit any class "
+	};
+
+	if (class < (sizeof pci_classes / sizeof *pci_classes))
+		return pci_classes[(int) class];
+
+	return  "???                    ";
+}
+
+/*
+ * Subroutine:  pci_header_show_brief
+ *
+ * Description: Reads and prints the header of the
+ * 		specified PCI device in short form.
+ *
+ * Inputs:	dev      Bus+Device+Function number
+ *
+ * Return:      None
+ *
+ */
+void pci_header_show_brief(pci_dev_t dev)
+{
+	u16 vendor, device;
+	u8 class, subclass;
+
+	pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
+	pci_read_config_word(dev, PCI_DEVICE_ID, &device);
+	pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
+	pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
+
+	printf("0x%.4x     0x%.4x     %s 0x%.2x\n",
+	       vendor, device,
+	       pci_classes_str(class), subclass);
+}
+
+/*
+ * Subroutine:  PCI_Header_Show
+ *
+ * Description: Reads the header of the specified PCI device.
+ *
+ * Inputs:		BusDevFunc      Bus+Device+Function number
+ *
+ * Return:      None
+ *
+ */
+void pci_header_show(pci_dev_t dev)
+{
+	u8 _byte, header_type;
+	u16 _word;
+	u32 _dword;
+
+#define PRINT(msg, type, reg) \
+	pci_read_config_##type(dev, reg, &_##type); \
+	printf(msg, _##type)
+
+#define PRINT2(msg, type, reg, func) \
+	pci_read_config_##type(dev, reg, &_##type); \
+	printf(msg, _##type, func(_##type))
+
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+	PRINT ("  vendor ID =                   0x%.4x\n", word, PCI_VENDOR_ID);
+	PRINT ("  device ID =                   0x%.4x\n", word, PCI_DEVICE_ID);
+	PRINT ("  command register =            0x%.4x\n", word, PCI_COMMAND);
+	PRINT ("  status register =             0x%.4x\n", word, PCI_STATUS);
+	PRINT ("  revision ID =                 0x%.2x\n", byte, PCI_REVISION_ID);
+	PRINT2("  class code =                  0x%.2x (%s)\n", byte, PCI_CLASS_CODE,
+	       							pci_classes_str);
+	PRINT ("  sub class code =              0x%.2x\n", byte, PCI_CLASS_SUB_CODE);
+	PRINT ("  programming interface =       0x%.2x\n", byte, PCI_CLASS_PROG);
+	PRINT ("  cache line =                  0x%.2x\n", byte, PCI_CACHE_LINE_SIZE);
+	PRINT ("  latency time =                0x%.2x\n", byte, PCI_LATENCY_TIMER);
+	PRINT ("  header type =                 0x%.2x\n", byte, PCI_HEADER_TYPE);
+	PRINT ("  BIST =                        0x%.2x\n", byte, PCI_BIST);
+	PRINT ("  base address 0 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_0);
+	PRINT ("  base address 1 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_1);
+
+	if (header_type & 0x01) {		/* PCI-to-PCI bridge */
+		PRINT ("  primary bus number =          0x%.2x\n", byte, PCI_PRIMARY_BUS);
+		PRINT ("  secondary bus number =        0x%.2x\n", byte, PCI_SECONDARY_BUS);
+		PRINT ("  subordinate bus number =      0x%.2x\n", byte, PCI_SUBORDINATE_BUS);
+		PRINT ("  secondary latency timer =     0x%.2x\n", byte, PCI_SEC_LATENCY_TIMER);
+		PRINT ("  IO base =                     0x%.2x\n", byte, PCI_IO_BASE);
+		PRINT ("  IO limit =                    0x%.2x\n", byte, PCI_IO_LIMIT);
+		PRINT ("  secondary status =            0x%.4x\n", word, PCI_SEC_STATUS);
+		PRINT ("  memory base =                 0x%.4x\n", word, PCI_MEMORY_BASE);
+		PRINT ("  memory limit =                0x%.4x\n", word, PCI_MEMORY_LIMIT);
+		PRINT ("  prefetch memory base =        0x%.4x\n", word, PCI_PREF_MEMORY_BASE);
+		PRINT ("  prefetch memory limit =       0x%.4x\n", word, PCI_PREF_MEMORY_LIMIT);
+		PRINT ("  prefetch memory base upper =  0x%.8x\n", dword, PCI_PREF_BASE_UPPER32);
+		PRINT ("  prefetch memory limit upper = 0x%.8x\n", dword, PCI_PREF_LIMIT_UPPER32);
+		PRINT ("  IO base upper 16 bits =       0x%.4x\n", word, PCI_IO_BASE_UPPER16);
+		PRINT ("  IO limit upper 16 bits =      0x%.4x\n", word, PCI_IO_LIMIT_UPPER16);
+		PRINT ("  expansion ROM base address =  0x%.8x\n", dword, PCI_ROM_ADDRESS1);
+		PRINT ("  interrupt line =              0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+		PRINT ("  interrupt pin =               0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+		PRINT ("  bridge control =              0x%.4x\n", word, PCI_BRIDGE_CONTROL);
+    } else {					/* PCI device */
+		PRINT("  base address 2 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_2);
+		PRINT("  base address 3 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_3);
+		PRINT("  base address 4 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_4);
+		PRINT("  base address 5 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_5);
+		PRINT("  cardBus CIS pointer =         0x%.8x\n", dword, PCI_CARDBUS_CIS);
+		PRINT("  sub system vendor ID =        0x%.4x\n", word, PCI_SUBSYSTEM_VENDOR_ID);
+		PRINT("  sub system ID =               0x%.4x\n", word, PCI_SUBSYSTEM_ID);
+		PRINT("  expansion ROM base address =  0x%.8x\n", dword, PCI_ROM_ADDRESS);
+		PRINT("  interrupt line =              0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+		PRINT("  interrupt pin =               0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+		PRINT("  min Grant =                   0x%.2x\n", byte, PCI_MIN_GNT);
+		PRINT("  max Latency =                 0x%.2x\n", byte, PCI_MAX_LAT);
+    }
+
+#undef PRINT
+#undef PRINT2
+}
+
+/* Convert the "bus.device.function" identifier into a number.
+ */
+static pci_dev_t get_pci_dev(char* name)
+{
+	char cnum[12];
+	int len, i, iold, n;
+	int bdfs[3] = {0,0,0};
+
+	len = strlen(name);
+	if (len > 8)
+		return -1;
+	for (i = 0, iold = 0, n = 0; i < len; i++) {
+		if (name[i] == '.') {
+			memcpy(cnum, &name[iold], i - iold);
+			cnum[i - iold] = '\0';
+			bdfs[n++] = simple_strtoul(cnum, NULL, 16);
+			iold = i + 1;
+		}
+	}
+	strcpy(cnum, &name[iold]);
+	if (n == 0)
+		n = 1;
+	bdfs[n] = simple_strtoul(cnum, NULL, 16);
+	return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
+}
+
+static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
+{
+#define DISP_LINE_LEN	16
+	ulong i, nbytes, linebytes;
+	int rc = 0;
+
+	if (length == 0)
+		length = 0x40 / size; /* Standard PCI configuration space */
+
+	/* Print the lines.
+	 * once, and all accesses are with the specified bus width.
+	 */
+	nbytes = length * size;
+	do {
+		uint	val4;
+		ushort  val2;
+		u_char	val1;
+
+		printf("%08lx:", addr);
+		linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
+		for (i=0; i<linebytes; i+= size) {
+			if (size == 4) {
+				pci_read_config_dword(bdf, addr, &val4);
+				printf(" %08x", val4);
+			} else if (size == 2) {
+				pci_read_config_word(bdf, addr, &val2);
+				printf(" %04x", val2);
+			} else {
+				pci_read_config_byte(bdf, addr, &val1);
+				printf(" %02x", val1);
+			}
+			addr += size;
+		}
+		printf("\n");
+		nbytes -= linebytes;
+		if (ctrlc()) {
+			rc = 1;
+			break;
+		}
+	} while (nbytes > 0);
+
+	return (rc);
+}
+
+static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
+{
+	if (size == 4) {
+		pci_write_config_dword(bdf, addr, value);
+	}
+	else if (size == 2) {
+		ushort val = value & 0xffff;
+		pci_write_config_word(bdf, addr, val);
+	}
+	else {
+		u_char val = value & 0xff;
+		pci_write_config_byte(bdf, addr, val);
+	}
+	return 0;
+}
+
+static int
+pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
+{
+	ulong	i;
+	int	nbytes;
+	extern char console_buffer[];
+	uint	val4;
+	ushort  val2;
+	u_char	val1;
+
+	/* Print the address, followed by value.  Then accept input for
+	 * the next value.  A non-converted value exits.
+	 */
+	do {
+		printf("%08lx:", addr);
+		if (size == 4) {
+			pci_read_config_dword(bdf, addr, &val4);
+			printf(" %08x", val4);
+		}
+		else if (size == 2) {
+			pci_read_config_word(bdf, addr, &val2);
+			printf(" %04x", val2);
+		}
+		else {
+			pci_read_config_byte(bdf, addr, &val1);
+			printf(" %02x", val1);
+		}
+
+		nbytes = readline (" ? ");
+		if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+			/* <CR> pressed as only input, don't modify current
+			 * location and move to next. "-" pressed will go back.
+			 */
+			if (incrflag)
+				addr += nbytes ? -size : size;
+			nbytes = 1;
+#ifdef CONFIG_BOOT_RETRY_TIME
+			reset_cmd_timeout(); /* good enough to not time out */
+#endif
+		}
+#ifdef CONFIG_BOOT_RETRY_TIME
+		else if (nbytes == -2) {
+			break;	/* timed out, exit the command	*/
+		}
+#endif
+		else {
+			char *endp;
+			i = simple_strtoul(console_buffer, &endp, 16);
+			nbytes = endp - console_buffer;
+			if (nbytes) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+				/* good enough to not time out
+				 */
+				reset_cmd_timeout();
+#endif
+				pci_cfg_write (bdf, addr, size, i);
+				if (incrflag)
+					addr += size;
+			}
+		}
+	} while (nbytes);
+
+	return 0;
+}
+
+/* PCI Configuration Space access commands
+ *
+ * Syntax:
+ *	pci display[.b, .w, .l] bus.device.function} [addr] [len]
+ *	pci next[.b, .w, .l] bus.device.function [addr]
+ *      pci modify[.b, .w, .l] bus.device.function [addr]
+ *      pci write[.b, .w, .l] bus.device.function addr value
+ */
+int do_pci (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	ulong addr = 0, value = 0, size = 0;
+	pci_dev_t bdf = 0;
+	char cmd = 's';
+
+	if (argc > 1)
+		cmd = argv[1][0];
+
+	switch (cmd) {
+	case 'd':		/* display */
+	case 'n':		/* next */
+	case 'm':		/* modify */
+	case 'w':		/* write */
+		/* Check for a size specification. */
+		size = cmd_get_data_size(argv[1], 4);
+		if (argc > 3)
+			addr = simple_strtoul(argv[3], NULL, 16);
+		if (argc > 4)
+			value = simple_strtoul(argv[4], NULL, 16);
+	case 'h':		/* header */
+		if (argc < 3)
+			goto usage;
+		if ((bdf = get_pci_dev(argv[2])) == -1)
+			return 1;
+		break;
+	default:		/* scan bus */
+		value = 1; /* short listing */
+		bdf = 0;   /* bus number  */
+		if (argc > 1) {
+			if (argv[argc-1][0] == 'l') {
+				value = 0;
+				argc--;
+			}
+			if (argc > 1)
+				bdf = simple_strtoul(argv[1], NULL, 16);
+		}
+		pciinfo(bdf, value);
+		return 0;
+	}
+
+	switch (argv[1][0]) {
+	case 'h':		/* header */
+		pci_header_show(bdf);
+		return 0;
+	case 'd':		/* display */
+		return pci_cfg_display(bdf, addr, size, value);
+	case 'n':		/* next */
+		if (argc < 4)
+			goto usage;
+		return pci_cfg_modify(bdf, addr, size, value, 0);
+	case 'm':		/* modify */
+		if (argc < 4)
+			goto usage;
+		return pci_cfg_modify(bdf, addr, size, value, 1);
+	case 'w':		/* write */
+		if (argc < 5)
+			goto usage;
+		return pci_cfg_write(bdf, addr, size, value);
+	}
+
+	return 1;
+ usage:
+	printf ("Usage:\n%s\n", cmdtp->usage);
+	return 1;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_PCI) */
+
+#endif /* CONFIG_PCI */
diff --git a/common/cmd_pcmcia.c b/common/cmd_pcmcia.c
new file mode 100644
index 0000000..ccf21a9
--- /dev/null
+++ b/common/cmd_pcmcia.c
@@ -0,0 +1,2243 @@
+/*
+ * (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
+ *
+ ********************************************************************
+ *
+ * Lots of code copied from:
+ *
+ * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
+ * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
+ *
+ * "The ExCA standard specifies that socket controllers should provide
+ * two IO and five memory windows per socket, which can be independently
+ * configured and positioned in the host address space and mapped to
+ * arbitrary segments of card address space. " - David A Hinds. 1999
+ *
+ * This controller does _not_ meet the ExCA standard.
+ *
+ * m8xx pcmcia controller brief info:
+ * + 8 windows (attrib, mem, i/o)
+ * + up to two slots (SLOT_A and SLOT_B)
+ * + inputpins, outputpins, event and mask registers.
+ * - no offset register. sigh.
+ *
+ * Because of the lacking offset register we must map the whole card.
+ * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
+ * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
+ * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
+ * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
+ * They are maximum 64KByte each...
+ */
+
+/* #define DEBUG	1	*/
+
+/*
+ * PCMCIA support
+ */
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <pcmcia.h>
+#include <cmd_pcmcia.h>
+#if defined(CONFIG_IDE_8xx_PCCARD) && defined(CONFIG_8xx)
+#include <mpc8xx.h>
+#endif
+#if defined(CONFIG_LWMON)
+#include <i2c.h>
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
+    ((CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD))
+
+int pcmcia_on (void);
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int  pcmcia_off (void);
+static int  hardware_disable(int slot);
+#endif
+static int  hardware_enable (int slot);
+static int  voltage_set(int slot, int vcc, int vpp);
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_funcid (int func);
+static void print_fixed  (volatile uchar *p);
+static int  identify     (volatile uchar *p);
+static int  check_ide_device (void);
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+static u_int m8xx_get_graycode(u_int size);
+#if 0
+static u_int m8xx_get_speed(u_int ns, u_int is_io);
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* look up table for pgcrx registers */
+
+static u_int *pcmcia_pgcrx[2] = {
+	&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcra,
+	&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcrb,
+};
+
+#define PCMCIA_PGCRX(slot)	(*pcmcia_pgcrx[slot])
+
+const char *indent = "\t   ";
+
+/* ------------------------------------------------------------------------- */
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+
+int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int rcode = 0;
+
+	if (argc != 2) {
+		printf ("Usage: pinit {on | off}\n");
+		return 1;
+	}
+	if (strcmp(argv[1],"on") == 0) {
+	     	rcode = pcmcia_on ();
+	} else if (strcmp(argv[1],"off") == 0) {
+		rcode = pcmcia_off ();
+	} else {
+		printf ("Usage: pinit {on | off}\n");
+		return 1;
+	}
+
+	return rcode;
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LWMON)
+# define  CFG_PCMCIA_TIMING	(PCMCIA_SHT(9) | PCMCIA_SST(3) | PCMCIA_SL(12))
+#else
+# define  CFG_PCMCIA_TIMING	(PCMCIA_SHT(2) | PCMCIA_SST(4) | PCMCIA_SL(9))
+#endif
+
+int pcmcia_on (void)
+{
+	int i;
+	u_long reg, base;
+	pcmcia_win_t *win;
+
+	debug ("Enable PCMCIA " PCMCIA_SLOT_MSG "\n");
+
+	/* intialize the fixed memory windows */
+	win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+	base = CFG_PCMCIA_MEM_ADDR;
+
+	if((reg = m8xx_get_graycode(CFG_PCMCIA_MEM_SIZE)) == -1) {
+		printf ("Cannot set window size to 0x%08x\n",
+			CFG_PCMCIA_MEM_SIZE);
+		return (1);
+	}
+
+	for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
+		win->br = base;
+
+		switch (i) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+		case 0:	{	/* map attribute memory */
+			win->or = (	PCMCIA_BSIZE_64M
+				|	PCMCIA_PPS_8
+				|	PCMCIA_PRS_ATTR
+				|	PCMCIA_SLOT_x
+				|	PCMCIA_PV
+				|	CFG_PCMCIA_TIMING );
+			break;
+		    }
+
+		case 1: {	/* map I/O window for data reg */
+			win->or = (	PCMCIA_BSIZE_1K
+				|	PCMCIA_PPS_16
+				|	PCMCIA_PRS_IO
+				|	PCMCIA_SLOT_x
+				|	PCMCIA_PV
+				|	CFG_PCMCIA_TIMING );
+			break;
+		    }
+
+		case 2: {	/* map I/O window for command/ctrl reg block */
+			win->or = (	PCMCIA_BSIZE_1K
+				|	PCMCIA_PPS_8
+				|	PCMCIA_PRS_IO
+				|	PCMCIA_SLOT_x
+				|	PCMCIA_PV
+				|	CFG_PCMCIA_TIMING );
+			break;
+		    }
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+		default:	/* set to not valid */
+			win->or = 0;
+			break;
+		}
+
+		debug ("MemWin %d: PBR 0x%08lX  POR %08lX\n",
+			i, win->br, win->or);
+		base += CFG_PCMCIA_MEM_SIZE;
+		++win;
+	}
+
+	/* turn off voltage */
+	if (voltage_set(_slot_, 0, 0))
+		return (1);
+
+	/* Enable external hardware */
+	if (hardware_enable(_slot_))
+		return (1);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	if (check_ide_device())
+		return (1);
+#endif
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+
+static int pcmcia_off (void)
+{
+	int i;
+	pcmcia_win_t *win;
+
+	printf ("Disable PCMCIA " PCMCIA_SLOT_MSG "\n");
+
+	/* clear interrupt state, and disable interrupts */
+	((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pscr =  PCMCIA_MASK(_slot_);
+	((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* turn off interrupt and disable CxOE */
+	PCMCIA_PGCRX(_slot_) = __MY_PCMCIA_GCRX_CXOE;
+
+	/* turn off memory windows */
+	win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+
+	for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
+		/* disable memory window */
+		win->or = 0;
+		++win;
+	}
+
+	/* turn off voltage */
+	voltage_set(_slot_, 0, 0);
+
+	/* disable external hardware */
+	printf ("Shutdown and Poweroff " PCMCIA_SLOT_MSG "\n");
+	hardware_disable(_slot_);
+	return 0;
+}
+
+#endif	/* CFG_CMD_PCMCIA */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#define	MAX_TUPEL_SZ	512
+#define MAX_FEATURES	4
+
+static int check_ide_device (void)
+{
+	volatile uchar *ident = NULL;
+	volatile uchar *feature_p[MAX_FEATURES];
+	volatile uchar *p, *start;
+	int n_features = 0;
+	uchar func_id = ~0;
+	uchar code, len;
+	ushort config_base = 0;
+	int found = 0;
+	int i;
+
+	debug ("PCMCIA MEM: %08X\n", CFG_PCMCIA_MEM_ADDR);
+
+	start = p = (volatile uchar *) CFG_PCMCIA_MEM_ADDR;
+
+	while ((p - start) < MAX_TUPEL_SZ) {
+
+		code = *p; p += 2;
+
+		if (code == 0xFF) { /* End of chain */
+			break;
+		}
+
+		len = *p; p += 2;
+#if defined(DEBUG) && (DEBUG > 1)
+		{ volatile uchar *q = p;
+			printf ("\nTuple code %02x  length %d\n\tData:",
+				code, len);
+
+			for (i = 0; i < len; ++i) {
+				printf (" %02x", *q);
+				q+= 2;
+			}
+		}
+#endif	/* DEBUG */
+		switch (code) {
+		case CISTPL_VERS_1:
+			ident = p + 4;
+			break;
+		case CISTPL_FUNCID:
+			/* Fix for broken SanDisk which may have 0x80 bit set */
+			func_id = *p & 0x7F;
+			break;
+		case CISTPL_FUNCE:
+			if (n_features < MAX_FEATURES)
+				feature_p[n_features++] = p;
+			break;
+		case CISTPL_CONFIG:
+			config_base = (*(p+6) << 8) + (*(p+4));
+			debug ("\n## Config_base = %04x ###\n", config_base);
+		default:
+			break;
+		}
+		p += 2 * len;
+	}
+
+	found = identify (ident);
+
+	if (func_id != ((uchar)~0)) {
+		print_funcid (func_id);
+
+		if (func_id == CISTPL_FUNCID_FIXED)
+			found = 1;
+		else
+			return (1);	/* no disk drive */
+	}
+
+	for (i=0; i<n_features; ++i) {
+		print_fixed (feature_p[i]);
+	}
+
+	if (!found) {
+		printf ("unknown card type\n");
+		return (1);
+	}
+
+	/* set I/O area in config reg -> only valid for ARGOSY D5!!! */
+	*((uchar *)(CFG_PCMCIA_MEM_ADDR + config_base)) = 1;
+
+	return (0);
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* board specific stuff:							*/
+/* voltage_set(), hardware_enable() and hardware_disable()			*/
+/* ---------------------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------------------- */
+/* RPX Boards from Embedded Planet						*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
+
+/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks.
+ * SYPCR is write once only, therefore must the slowest memory be faster
+ * than the bus monitor or we will get a machine check due to the bus timeout.
+ */
+
+#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE"
+
+#undef PCMCIA_BMT_LIMIT
+#define PCMCIA_BMT_LIMIT (6*8)
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	u_long reg = 0;
+
+	switch(vcc) {
+	case 0: break;
+	case 33: reg |= BCSR1_PCVCTL4; break;
+	case 50: reg |= BCSR1_PCVCTL5; break;
+	default: return 1;
+	}
+
+	switch(vpp) {
+	case 0: break;
+	case 33:
+	case 50:
+		if(vcc == vpp)
+			reg |= BCSR1_PCVCTL6;
+		else
+			return 1;
+		break;
+	case 120:
+		reg |= BCSR1_PCVCTL7;
+	default: return 1;
+	}
+
+	if(vcc == 120)
+	   return 1;
+
+	/* first, turn off all power */
+
+	*((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5
+				     | BCSR1_PCVCTL6 | BCSR1_PCVCTL7);
+
+	/* enable new powersettings */
+
+	*((uint *)RPX_CSR_ADDR) |= reg;
+
+	return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+static int hardware_enable (int slot)
+{
+	return 0;	/* No hardware to enable */
+}
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	return 0;	/* No hardware to disable */
+}
+#endif	/* CFG_CMD_PCMCIA */
+#endif	/* CONFIG_RPXCLASSIC */
+
+/* ---------------------------------------------------------------------------- */
+/* (F)ADS Boards from Motorola							*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_ADS) || defined(CONFIG_FADS)
+
+#ifdef CONFIG_ADS
+#define PCMCIA_BOARD_MSG "ADS"
+#define PCMCIA_GLITCHY_CD  /* My ADS board needs this */
+#else
+#define PCMCIA_BOARD_MSG "FADS"
+#endif
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	u_long reg = 0;
+
+	switch(vpp) {
+	case 0: reg = 0; break;
+	case 50: reg = 1; break;
+	case 120: reg = 2; break;
+	default: return 1;
+	}
+
+	switch(vcc) {
+	case 0: reg = 0; break;
+#ifdef CONFIG_ADS
+	case 50: reg = BCSR1_PCCVCCON; break;
+#endif
+#ifdef CONFIG_FADS
+	case 33: reg = BCSR1_PCCVCC0 | BCSR1_PCCVCC1; break;
+	case 50: reg = BCSR1_PCCVCC1; break;
+#endif
+	default: return 1;
+	}
+
+	/* first, turn off all power */
+
+#ifdef CONFIG_ADS
+	*((uint *)BCSR1) |= BCSR1_PCCVCCON;
+#endif
+#ifdef CONFIG_FADS
+	*((uint *)BCSR1) &= ~(BCSR1_PCCVCC0 | BCSR1_PCCVCC1);
+#endif
+	*((uint *)BCSR1) &= ~BCSR1_PCCVPP_MASK;
+
+	/* enable new powersettings */
+
+#ifdef CONFIG_ADS
+	*((uint *)BCSR1) &= ~reg;
+#endif
+#ifdef CONFIG_FADS
+	*((uint *)BCSR1) |= reg;
+#endif
+
+ 	*((uint *)BCSR1) |= reg << 20;
+
+	return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+
+static int hardware_enable(int slot)
+{
+	*((uint *)BCSR1) &= ~BCSR1_PCCEN;
+	return 0;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	*((uint *)BCSR1) &= ~BCSR1_PCCEN;
+	return 0;
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+#endif	/* (F)ADS */
+
+/* ---------------------------------------------------------------------------- */
+/* TQM8xxL Boards by TQ Components						*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_TQM8xxL)
+
+#define PCMCIA_BOARD_MSG "TQM8xxL"
+
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable
+	 */
+	immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
+	immap->im_ioport.iop_pcso  &= ~(0x0002 | 0x0004);
+	/* remove all power */
+
+	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		immap->im_ioport.iop_pcdat |= 0x0004;
+		puts (" 5.0V card found: ");
+	} else {
+		immap->im_ioport.iop_pcdat |= 0x0002;
+		puts (" 3.3V card found: ");
+	}
+	immap->im_ioport.iop_pcdir |=  (0x0002 | 0x0004);
+#if 0
+	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
+	cp->cp_pbdir &= ~(0x0020 | 0x0010);
+	cp->cp_pbpar &= ~(0x0020 | 0x0010);
+	udelay(500000);
+#endif
+	udelay(1000);
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* remove all power */
+	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn off all power
+	 */
+	debug ("PCMCIA power OFF\n");
+	immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
+	immap->im_ioport.iop_pcso  &= ~(0x0002 | 0x0004);
+	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+	reg = 0;
+	switch(vcc) {
+	case  0: 		break;
+	case 33: reg |= 0x0002;	break;
+	case 50: reg |= 0x0004;	break;
+	default: 		goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	immap->im_ioport.iop_pcdat |= reg;
+	immap->im_ioport.iop_pcdir |=  (0x0002 | 0x0004);
+	if (reg) {
+		debug ("PCMCIA powered at %sV\n",
+			(reg&0x0004) ? "5.0" : "3.3");
+	} else {
+		debug ("PCMCIA powered down\n");
+	}
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* TQM8xxL */
+
+
+/* ---------------------------------------------------------------------------- */
+/* LWMON Board									*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LWMON)
+
+#define PCMCIA_BOARD_MSG "LWMON"
+
+/* #define's for MAX1604 Power Switch */
+#define MAX1604_OP_SUS		0x80
+#define MAX1604_VCCBON		0x40
+#define MAX1604_VCC_35		0x20
+#define MAX1604_VCCBHIZ		0x10
+#define MAX1604_VPPBON		0x08
+#define MAX1604_VPPBPBPGM	0x04
+#define MAX1604_VPPBHIZ		0x02
+/* reserved			0x01	*/
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+	uchar val;
+
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	/* Switch on PCMCIA port in PIC register 0x60 */
+	reg = pic_read  (0x60);
+	debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+	reg &= ~0x10;
+	/* reg |=  0x08; Vpp not needed */
+	pic_write (0x60, reg);
+#ifdef DEBUG
+	reg = pic_read  (0x60);
+	printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+#endif
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		val = 0;		/* VCCB3/5 = 0 ==> use Vx = 5.0 V */
+		puts (" 5.0V card found: ");
+	} else {
+		val = MAX1604_VCC_35;	/* VCCB3/5 = 1 ==> use Vy = 3.3 V */
+		puts (" 3.3V card found: ");
+	}
+
+	/*  switch VCC on */
+	val |=  MAX1604_OP_SUS | MAX1604_VCCBON;
+	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+	udelay(500000);
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+	uchar val;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* remove all power, put output in high impedance state */
+	val  = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
+	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	/* Switch off PCMCIA port in PIC register 0x60 */
+	reg = pic_read  (0x60);
+	debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+	reg |=  0x10;
+	reg &= ~0x08;
+	pic_write (0x60, reg);
+#ifdef DEBUG
+	reg = pic_read  (0x60);
+	printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+#endif
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+	uchar val;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Turn off all power (switch to high impedance)
+	 */
+	debug ("PCMCIA power OFF\n");
+	val  = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
+	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+	val = 0;
+	switch(vcc) {
+	case  0: 			break;
+	case 33: val = MAX1604_VCC_35;	break;
+	case 50: 			break;
+	default: 			goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+	if (val) {
+		debug ("PCMCIA powered at %sV\n",
+			(val & MAX1604_VCC_35) ? "3.3" : "5.0");
+	} else {
+		debug ("PCMCIA powered down\n");
+	}
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* LWMON */
+
+/* ---------------------------------------------------------------------------- */
+/* GTH board by Corelatus AB                                                    */
+/* ---------------------------------------------------------------------------- */
+#if defined(CONFIG_GTH)
+
+#define PCMCIA_BOARD_MSG "GTH COMPACT FLASH"
+
+static int voltage_set(int slot, int vcc, int vpp)
+{  /* Do nothing */
+  return 0;
+}
+
+static int hardware_enable (int slot)
+{
+  volatile immap_t	*immap;
+  volatile cpm8xx_t	*cp;
+  volatile pcmconf8xx_t	*pcmp;
+  volatile sysconf8xx_t	*sysp;
+  uint reg, mask;
+
+  debug ("hardware_enable: GTH Slot %c\n", 'A'+slot);
+
+  immap = (immap_t *)CFG_IMMR;
+  sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+  pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+  cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+  /* clear interrupt state, and disable interrupts */
+  pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+  pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+  /* disable interrupts & DMA */
+  PCMCIA_PGCRX(_slot_) = 0;
+
+  /*
+   * Disable PCMCIA buffers (isolate the interface)
+   * and assert RESET signal
+   */
+  debug ("Disable PCMCIA buffers and assert RESET\n");
+  reg  =  PCMCIA_PGCRX(_slot_);
+  reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+  reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+  PCMCIA_PGCRX(_slot_) = reg;
+  udelay(500);
+
+  /*
+   * Make sure there is a card in the slot, then configure the interface.
+   */
+  udelay(10000);
+  debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+  if (pcmp->pcmc_pipr & 0x98000000) {
+    printf ("   No Card found\n");
+    return (1);
+  }
+
+  mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+  reg  = pcmp->pcmc_pipr;
+  debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+
+  debug ("Enable PCMCIA buffers and stop RESET\n");
+  reg  =  PCMCIA_PGCRX(_slot_);
+  reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+  reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+  PCMCIA_PGCRX(_slot_) = reg;
+
+  udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+  debug ("# hardware_enable done\n");
+
+  return 0;
+}
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	return 0;	/* No hardware to disable */
+}
+#endif	/* CFG_CMD_PCMCIA */
+#endif	/* CONFIG_GTH */
+
+/* ---------------------------------------------------------------------------- */
+/* ICU862 Boards by Cambridge Broadband Ltd.					*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_ICU862)
+
+#define PCMCIA_BOARD_MSG "ICU862"
+
+static void cfg_port_B (void);
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, pipr, mask;
+	int i;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/* Configure Port B for TPS2205 PC-Card Power-Interface Switch */
+	cfg_port_B ();
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	pipr = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		pipr,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+
+	reg  = cp->cp_pbdat;
+	if ((pipr & mask) == mask) {
+		reg |=  (TPS2205_VPP_PGM | TPS2205_VPP_VCC |	/* VAVPP => Hi-Z */
+			 TPS2205_VCC3);				/* 3V off	*/
+		reg &= ~(TPS2205_VCC5);				/* 5V on	*/
+		puts (" 5.0V card found: ");
+	} else {
+		reg |=  (TPS2205_VPP_PGM | TPS2205_VPP_VCC |	/* VAVPP => Hi-Z */
+			 TPS2205_VCC5);				/* 5V off	*/
+		reg &= ~(TPS2205_VCC3);				/* 3V on	*/
+		puts (" 3.3V card found: ");
+	}
+
+	debug ("\nPB DAT: %08x -> 3.3V %s 5.0V %s VPP_PGM %s VPP_VCC %s\n",
+		reg,
+		(reg & TPS2205_VCC3)    ? "off" : "on",
+		(reg & TPS2205_VCC5)    ? "off" : "on",
+		(reg & TPS2205_VPP_PGM) ? "off" : "on",
+		(reg & TPS2205_VPP_VCC) ? "off" : "on" );
+
+	cp->cp_pbdat = reg;
+
+	/*  Wait 500 ms; use this to check for over-current */
+	for (i=0; i<5000; ++i) {
+		if ((cp->cp_pbdat & TPS2205_OC) == 0) {
+			printf ("   *** Overcurrent - Safety shutdown ***\n");
+			cp->cp_pbdat &= ~(TPS2205_SHDN);
+			return (1);
+		}
+		udelay (100);
+	}
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* Shut down */
+	cp->cp_pbdat &= ~(TPS2205_SHDN);
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn all power pins to Hi-Z
+	 */
+	debug ("PCMCIA power OFF\n");
+	cfg_port_B ();	/* Enables switch, but all in Hi-Z */
+
+	reg  = cp->cp_pbdat;
+
+	switch(vcc) {
+	case  0: 			break;	/* Switch off		*/
+	case 33: reg &= ~TPS2205_VCC3;	break;	/* Switch on 3.3V	*/
+	case 50: reg &= ~TPS2205_VCC5;	break;	/* Switch on 5.0V	*/
+	default: 			goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	cp->cp_pbdat = reg;
+
+#ifdef DEBUG
+    {
+	char *s;
+
+	if ((reg & TPS2205_VCC3) == 0) {
+		s = "at 3.3V";
+	} else if ((reg & TPS2205_VCC5) == 0) {
+		s = "at 5.0V";
+	} else {
+		s = "down";
+	}
+	printf ("PCMCIA powered %s\n", s);
+    }
+#endif
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+static void cfg_port_B (void)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	uint reg;
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure Port B for TPS2205 PC-Card Power-Interface Switch
+	 *
+	 * Switch off all voltages, assert shutdown
+	 */
+	reg  = cp->cp_pbdat;
+	reg |=  (TPS2205_VPP_PGM | TPS2205_VPP_VCC |	/* VAVPP => Hi-Z */
+		 TPS2205_VCC3    | TPS2205_VCC5    |	/* VAVCC => Hi-Z */
+		 TPS2205_SHDN);				/* enable switch */
+	cp->cp_pbdat = reg;
+
+	cp->cp_pbpar &= ~(TPS2205_INPUTS | TPS2205_OUTPUTS);
+
+	reg = cp->cp_pbdir & ~(TPS2205_INPUTS);
+	cp->cp_pbdir = reg | TPS2205_OUTPUTS;
+
+	debug ("Set Port B: PAR: %08x DIR: %08x DAT: %08x\n",
+		cp->cp_pbpar, cp->cp_pbdir, cp->cp_pbdat);
+}
+
+#endif	/* ICU862 */
+
+
+/* ---------------------------------------------------------------------------- */
+/* C2MON Boards by TTTech Computertechnik AG					*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_C2MON)
+
+#define PCMCIA_BOARD_MSG "C2MON"
+
+static void cfg_ports (void);
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, pipr, mask;
+	ushort sreg;
+	int i;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/* Configure Ports for TPS2211A PC-Card Power-Interface Switch */
+	cfg_ports ();
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	pipr = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		pipr,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+
+	sreg = immap->im_ioport.iop_pcdat;
+	if ((pipr & mask) == mask) {
+		sreg |=  (TPS2211_VPPD0 | TPS2211_VPPD1 |	/* VAVPP => Hi-Z */
+			  TPS2211_VCCD1);			/* 5V on	*/
+		sreg &= ~(TPS2211_VCCD0);			/* 3V off	*/
+		puts (" 5.0V card found: ");
+	} else {
+		sreg |=  (TPS2211_VPPD0 | TPS2211_VPPD1 |	/* VAVPP => Hi-Z */
+			  TPS2211_VCCD0);			/* 3V on	*/
+		sreg &= ~(TPS2211_VCCD1);			/* 5V off	*/
+		puts (" 3.3V card found: ");
+	}
+
+	debug ("\nPC DAT: %04x -> 3.3V %s 5.0V %s\n",
+		sreg,
+		( (sreg & TPS2211_VCCD0) && !(sreg & TPS2211_VCCD1)) ? "on" : "off",
+		(!(sreg & TPS2211_VCCD0) &&  (sreg & TPS2211_VCCD1)) ? "on" : "off"
+	);
+
+	immap->im_ioport.iop_pcdat = sreg;
+
+	/*  Wait 500 ms; use this to check for over-current */
+	for (i=0; i<5000; ++i) {
+		if ((cp->cp_pbdat & TPS2211_OC) == 0) {
+		    printf ("   *** Overcurrent - Safety shutdown ***\n");
+		    immap->im_ioport.iop_pcdat &= ~(TPS2211_VCCD0|TPS2211_VCCD1);
+		    return (1);
+		}
+		udelay (100);
+	}
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	/* ALl voltages off / Hi-Z */
+	immap->im_ioport.iop_pcdat |= (TPS2211_VPPD0 | TPS2211_VPPD1 |
+				       TPS2211_VCCD0 | TPS2211_VCCD1 );
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+	ushort sreg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn all power pins to Hi-Z
+	 */
+	debug ("PCMCIA power OFF\n");
+	cfg_ports ();	/* Enables switch, but all in Hi-Z */
+
+	sreg  = immap->im_ioport.iop_pcdat;
+	sreg |= TPS2211_VPPD0 | TPS2211_VPPD1;		/* VAVPP always Hi-Z */
+
+	switch(vcc) {
+	case  0: 			break;	/* Switch off		*/
+	case 33: sreg |=  TPS2211_VCCD0;	/* Switch on 3.3V	*/
+		 sreg &= ~TPS2211_VCCD1;
+		 			break;
+	case 50: sreg &= ~TPS2211_VCCD0;	/* Switch on 5.0V	*/
+		 sreg |=  TPS2211_VCCD1;
+		 			break;
+	default: 			goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	immap->im_ioport.iop_pcdat = sreg;
+
+#ifdef DEBUG
+    {
+	char *s;
+
+	if ((sreg & TPS2211_VCCD0) && !(sreg & TPS2211_VCCD1)) {
+		s = "at 3.3V";
+	} else if (!(sreg & TPS2211_VCCD0) &&  (sreg & TPS2211_VCCD1)) {
+		s = "at 5.0V";
+	} else {
+		s = "down";
+	}
+	printf ("PCMCIA powered %s\n", s);
+    }
+#endif
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+static void cfg_ports (void)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	ushort sreg;
+
+	immap = (immap_t *)CFG_IMMR;
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure Port C for TPS2211 PC-Card Power-Interface Switch
+	 *
+	 * Switch off all voltages, assert shutdown
+	 */
+	sreg = immap->im_ioport.iop_pcdat;
+	sreg |=  (TPS2211_VPPD0 | TPS2211_VPPD1);	/* VAVPP => Hi-Z */
+	sreg &= ~(TPS2211_VCCD0 | TPS2211_VCCD1);	/* 3V and 5V off */
+	immap->im_ioport.iop_pcdat = sreg;
+
+	immap->im_ioport.iop_pcpar &= ~(TPS2211_OUTPUTS);
+	immap->im_ioport.iop_pcdir |=   TPS2211_OUTPUTS;
+
+	debug ("Set Port C: PAR:     %04x DIR:     %04x DAT:     %04x\n",
+		immap->im_ioport.iop_pcpar,
+		immap->im_ioport.iop_pcdir,
+		immap->im_ioport.iop_pcdat);
+
+	/*
+	 * Configure Port B for TPS2211 PC-Card Power-Interface Switch
+	 *
+	 * Over-Current Input only
+	 */
+	cp->cp_pbpar &= ~(TPS2211_INPUTS);
+	cp->cp_pbdir &= ~(TPS2211_INPUTS);
+
+	debug ("Set Port B: PAR: %08x DIR: %08x DAT: %08x\n",
+		cp->cp_pbpar, cp->cp_pbdir, cp->cp_pbdat);
+}
+
+#endif	/* C2MON */
+
+/* ----------------------------------------------------------------------------
+   MBX board from Morotola
+   ---------------------------------------------------------------------------- */
+
+#if defined( CONFIG_MBX )
+#include <../board/mbx8xx/csr.h>
+
+/* A lot of this has been taken from the RPX code in this file it works from me.
+   I have added the voltage selection for the MBX board. */
+
+/* MBX voltage bit in control register #2 */
+#define CR2_VPP12       ((uchar)0x10)
+#define CR2_VPPVDD      ((uchar)0x20)
+#define CR2_VDD5        ((uchar)0x40)
+#define CR2_VDD3        ((uchar)0x80)
+
+#define PCMCIA_BOARD_MSG "MBX860"
+
+static int voltage_set (int slot, int vcc, int vpp)
+{
+	uchar reg = 0;
+
+	debug ("voltage_set: PCMCIA_BOARD_MSG Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		 'A' + slot, vcc / 10, vcc % 10, vpp / 10, vcc % 10);
+
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= CR2_VDD3;
+		break;
+	case 50:
+		reg |= CR2_VDD5;
+		break;
+	default:
+		return 1;
+	}
+
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp) {
+			reg |= CR2_VPPVDD;
+		} else {
+			return 1;
+		}
+		break;
+	case 120:
+		reg |= CR2_VPP12;
+		break;
+	default:
+		return 1;
+	}
+
+	/* first, turn off all power */
+	MBX_CSR2 &= ~(CR2_VDDSEL | CR2_VPPSEL);
+
+	/* enable new powersettings */
+	MBX_CSR2 |= reg;
+	debug ("MBX_CSR2 read = 0x%02x\n", MBX_CSR2);
+
+	return (0);
+}
+
+static int hardware_enable (int slot)
+{
+	volatile immap_t *immap;
+	volatile cpm8xx_t *cp;
+	volatile pcmconf8xx_t *pcmp;
+	volatile sysconf8xx_t *sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n",
+				  'A' + slot);
+
+	udelay (10000);
+
+	immap = (immap_t *) CFG_IMMR;
+	sysp = (sysconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_siu_conf));
+	pcmp = (pcmconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_pcmcia));
+	cp = (cpm8xx_t *) (&(((immap_t *) CFG_IMMR)->im_cpm));
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr = PCMCIA_MASK (_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK (_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX (_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg = PCMCIA_PGCRX (_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;	/* active low  */
+	PCMCIA_PGCRX (_slot_) = reg;
+	udelay (500);
+
+	/* remove all power */
+	voltage_set (slot, 0, 0);
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay (10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n", __LINE__, __FUNCTION__,
+		  &(pcmp->pcmc_pipr), pcmp->pcmc_pipr);
+
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1 (_slot_) | PCMCIA_VS2 (_slot_);
+	reg = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n", reg,
+		  (reg & PCMCIA_VS1 (slot)) ? "n" : "ff",
+		  (reg & PCMCIA_VS2 (slot)) ? "n" : "ff");
+
+	if ((reg & mask) == mask) {
+		voltage_set (_slot_, 50, 0);
+		printf (" 5.0V card found: ");
+	} else {
+		voltage_set (_slot_, 33, 0);
+		printf (" 3.3V card found: ");
+	}
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg = PCMCIA_PGCRX (_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;	/* active low  */
+	PCMCIA_PGCRX (_slot_) = reg;
+
+	udelay (250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable (int slot)
+{
+	return 0;	/* No hardware to disable */
+}
+#endif /* CFG_CMD_PCMCIA */
+#endif /* CONFIG_MBX */
+/* ---------------------------------------------------------------------------- */
+/* R360MPI Board								*/
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_R360MPI)
+
+#define PCMCIA_BOARD_MSG "R360MPI"
+
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Ports A, B & C pins for
+	 * 5 Volts Enable and 3 Volts enable
+	 */
+	immap->im_ioport.iop_pcpar &= ~(0x0400);
+	immap->im_ioport.iop_pcso  &= ~(0x0400);/*
+	immap->im_ioport.iop_pcdir |= 0x0400;*/
+
+	immap->im_ioport.iop_papar &= ~(0x0200);/*
+	immap->im_ioport.iop_padir |= 0x0200;*/
+#if 0
+	immap->im_ioport.iop_pbpar &= ~(0xC000);
+	immap->im_ioport.iop_pbdir &= ~(0xC000);
+#endif
+	/* remove all power */
+
+	immap->im_ioport.iop_pcdat |= 0x0400;
+	immap->im_ioport.iop_padat |= 0x0200;
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		immap->im_ioport.iop_pcdat &= ~(0x4000);
+		puts (" 5.0V card found: ");
+	} else {
+		immap->im_ioport.iop_padat &= ~(0x0002);
+		puts (" 3.3V card found: ");
+	}
+	immap->im_ioport.iop_pcdir |= 0x0400;
+	immap->im_ioport.iop_padir |= 0x0200;
+#if 0
+	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
+	cp->cp_pbdir &= ~(0x0020 | 0x0010);
+	cp->cp_pbpar &= ~(0x0020 | 0x0010);
+	udelay(500000);
+#endif
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+	/* remove all power */
+	immap->im_ioport.iop_pcdat |= 0x0400;
+	immap->im_ioport.iop_padat |= 0x0200;
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "
+		PCMCIA_BOARD_MSG
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Ports A & C pins for
+	 * 5 Volts Enable and 3 Volts enable,
+	 * Turn off all power
+	 */
+	debug ("PCMCIA power OFF\n");
+	immap->im_ioport.iop_pcpar &= ~(0x0400);
+	immap->im_ioport.iop_pcso  &= ~(0x0400);/*
+	immap->im_ioport.iop_pcdir |= 0x0400;*/
+
+	immap->im_ioport.iop_papar &= ~(0x0200);/*
+	immap->im_ioport.iop_padir |= 0x0200;*/
+
+	immap->im_ioport.iop_pcdat |= 0x0400;
+	immap->im_ioport.iop_padat |= 0x0200;
+
+	reg = 0;
+	switch(vcc) {
+	case  0: 		break;
+	case 33: reg |= 0x0200;	break;
+	case 50: reg |= 0x0400;	break;
+	default: 		goto done;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+	if (reg & 0x0200)
+		immap->im_ioport.iop_pcdat &= !reg;
+	if (reg & 0x0400)
+		immap->im_ioport.iop_padat &= !reg;
+	immap->im_ioport.iop_pcdir |=  0x0200;
+	immap->im_ioport.iop_padir |=  0x0400;
+	if (reg) {
+		debug ("PCMCIA powered at %sV\n",
+			(reg&0x0400) ? "5.0" : "3.3");
+	} else {
+		debug ("PCMCIA powered down\n");
+	}
+
+done:
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* R360MPI */
+
+
+/* ---------------------------------------------------------------------------- */
+/* End of Board Specific Stuff							*/
+/* ---------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* MPC8xx Specific Stuff - should go to MPC8xx directory			*/
+/* ---------------------------------------------------------------------------- */
+
+/*
+ * Search this table to see if the windowsize is
+ * supported...
+ */
+
+#define M8XX_SIZES_NO 32
+
+static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
+{ 0x00000001, 0x00000002, 0x00000008, 0x00000004,
+  0x00000080, 0x00000040, 0x00000010, 0x00000020,
+  0x00008000, 0x00004000, 0x00001000, 0x00002000,
+  0x00000100, 0x00000200, 0x00000800, 0x00000400,
+
+  0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+  0x01000000, 0x02000000, 0xffffffff, 0x04000000,
+  0x00010000, 0x00020000, 0x00080000, 0x00040000,
+  0x00800000, 0x00400000, 0x00100000, 0x00200000 };
+
+
+/* ---------------------------------------------------------------------------- */
+
+static u_int m8xx_get_graycode(u_int size)
+{
+	u_int k;
+
+	for (k = 0; k < M8XX_SIZES_NO; k++) {
+		if(m8xx_size_to_gray[k] == size)
+			break;
+	}
+
+	if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
+		k = -1;
+
+	return k;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if 0
+static u_int m8xx_get_speed(u_int ns, u_int is_io)
+{
+	u_int reg, clocks, psst, psl, psht;
+
+	if(!ns) {
+
+		/*
+		 * We get called with IO maps setup to 0ns
+		 * if not specified by the user.
+		 * They should be 255ns.
+		 */
+
+		if(is_io)
+			ns = 255;
+		else
+			ns = 100;  /* fast memory if 0 */
+	}
+
+	/*
+	 * In PSST, PSL, PSHT fields we tell the controller
+	 * timing parameters in CLKOUT clock cycles.
+	 * CLKOUT is the same as GCLK2_50.
+	 */
+
+/* how we want to adjust the timing - in percent */
+
+#define ADJ 180 /* 80 % longer accesstime - to be sure */
+
+	clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
+	clocks = (clocks * ADJ) / (100*1000);
+
+	if(clocks >= PCMCIA_BMT_LIMIT) {
+		DEBUG(0, "Max access time limit reached\n");
+		clocks = PCMCIA_BMT_LIMIT-1;
+	}
+
+	psst = clocks / 7;          /* setup time */
+	psht = clocks / 7;          /* hold time */
+	psl  = (clocks * 5) / 7;    /* strobe length */
+
+	psst += clocks - (psst + psht + psl);
+
+	reg =  psst << 12;
+	reg |= psl  << 7;
+	reg |= psht << 16;
+
+	return reg;
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_funcid (int func)
+{
+	puts (indent);
+	switch (func) {
+	case CISTPL_FUNCID_MULTI:
+		puts (" Multi-Function");
+		break;
+	case CISTPL_FUNCID_MEMORY:
+		puts (" Memory");
+		break;
+	case CISTPL_FUNCID_SERIAL:
+		puts (" Serial Port");
+		break;
+	case CISTPL_FUNCID_PARALLEL:
+		puts (" Parallel Port");
+		break;
+	case CISTPL_FUNCID_FIXED:
+		puts (" Fixed Disk");
+		break;
+	case CISTPL_FUNCID_VIDEO:
+		puts (" Video Adapter");
+		break;
+	case CISTPL_FUNCID_NETWORK:
+		puts (" Network Adapter");
+		break;
+	case CISTPL_FUNCID_AIMS:
+		puts (" AIMS Card");
+		break;
+	case CISTPL_FUNCID_SCSI:
+		puts (" SCSI Adapter");
+		break;
+	default:
+		puts (" Unknown");
+		break;
+	}
+	puts (" Card\n");
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_fixed (volatile uchar *p)
+{
+	if (p == NULL)
+		return;
+
+	puts(indent);
+
+	switch (*p) {
+	case CISTPL_FUNCE_IDE_IFACE:
+	    {   uchar iface = *(p+2);
+
+		puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+		puts (" interface ");
+		break;
+	    }
+	case CISTPL_FUNCE_IDE_MASTER:
+	case CISTPL_FUNCE_IDE_SLAVE:
+	    {   uchar f1 = *(p+2);
+		uchar f2 = *(p+4);
+
+		puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+		if (f1 & CISTPL_IDE_UNIQUE)
+			puts (" [unique]");
+
+		puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+		if (f2 & CISTPL_IDE_HAS_SLEEP)
+			puts (" [sleep]");
+
+		if (f2 & CISTPL_IDE_HAS_STANDBY)
+			puts (" [standby]");
+
+		if (f2 & CISTPL_IDE_HAS_IDLE)
+			puts (" [idle]");
+
+		if (f2 & CISTPL_IDE_LOW_POWER)
+			puts (" [low power]");
+
+		if (f2 & CISTPL_IDE_REG_INHIBIT)
+			puts (" [reg inhibit]");
+
+		if (f2 & CISTPL_IDE_HAS_INDEX)
+			puts (" [index]");
+
+		if (f2 & CISTPL_IDE_IOIS16)
+			puts (" [IOis16]");
+
+		break;
+	    }
+	}
+	putc ('\n');
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#define MAX_IDENT_CHARS		64
+#define	MAX_IDENT_FIELDS	4
+
+static uchar *known_cards[] = {
+	"ARGOSY PnPIDE D5",
+	NULL
+};
+
+static int identify  (volatile uchar *p)
+{
+	uchar id_str[MAX_IDENT_CHARS];
+	uchar data;
+	uchar *t;
+	uchar **card;
+	int i, done;
+
+	if (p == NULL)
+		return (0);	/* Don't know */
+
+	t = id_str;
+	done =0;
+
+	for (i=0; i<=4 && !done; ++i, p+=2) {
+		while ((data = *p) != '\0') {
+			if (data == 0xFF) {
+				done = 1;
+				break;
+			}
+			*t++ = data;
+			if (t == &id_str[MAX_IDENT_CHARS-1]) {
+				done = 1;
+				break;
+			}
+			p += 2;
+		}
+		if (!done)
+			*t++ = ' ';
+	}
+	*t = '\0';
+	while (--t > id_str) {
+		if (*t == ' ')
+			*t = '\0';
+		else
+			break;
+	}
+	puts (id_str);
+	putc ('\n');
+
+	for (card=known_cards; *card; ++card) {
+		debug ("## Compare against \"%s\"\n", *card);
+		if (strcmp(*card, id_str) == 0) {	/* found! */
+			debug ("## CARD FOUND ##\n");
+			return (1);
+		}
+	}
+
+	return (0);	/* don't know */
+}
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CFG_CMD_PCMCIA || (CFG_CMD_IDE && CONFIG_IDE_8xx_PCCARD) */
diff --git a/common/env_flash.c b/common/env_flash.c
new file mode 100644
index 0000000..1593d2c
--- /dev/null
+++ b/common/env_flash.c
@@ -0,0 +1,377 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH) /* Environment is in Flash */
+
+#include <command.h>
+#include <environment.h>
+#include <cmd_nvedit.h>
+#include <linux/stddef.h>
+
+#if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_FLASH)) == (CFG_CMD_ENV|CFG_CMD_FLASH))
+#define CMD_SAVEENV
+#elif defined(CFG_ENV_ADDR_REDUND)
+#error Cannot use CFG_ENV_ADDR_REDUND without CFG_CMD_ENV & CFG_CMD_FLASH
+#endif
+
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE) && \
+    defined(CFG_ENV_ADDR_REDUND)
+#error CFG_ENV_ADDR_REDUND should not be used when CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
+#endif
+
+#if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND < CFG_ENV_SIZE)
+#error CFG_ENV_SIZE_REDUND should not be less then CFG_ENV_SIZE
+#endif
+
+#ifdef CONFIG_INFERNO
+# ifdef CFG_ENV_ADDR_REDUND
+#error CFG_ENV_ADDR_REDUND is not implemented for CONFIG_INFERNO
+# endif
+#endif
+
+char * env_name_spec = "Flash";
+
+#ifdef ENV_IS_EMBEDDED
+
+extern uchar environment[];
+env_t *env_ptr = (env_t *)(&environment[0]);
+
+#ifdef CMD_SAVEENV
+/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
+static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+#else /* ! ENV_IS_EMBEDDED */
+
+env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
+#ifdef CMD_SAVEENV
+static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+#endif /* ENV_IS_EMBEDDED */
+
+#ifdef CFG_ENV_ADDR_REDUND
+static env_t *flash_addr_new = (env_t *)CFG_ENV_ADDR_REDUND;
+
+static ulong end_addr = CFG_ENV_ADDR + CFG_ENV_SIZE - 1;
+static ulong end_addr_new = CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1;
+
+static uchar active_flag = 1;
+static uchar obsolete_flag = 0;
+#endif
+
+extern uchar default_environment[];
+extern int default_environment_size;
+
+
+uchar env_get_char_spec (int index)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	return ( *((uchar *)(gd->env_addr + index)) );
+}
+
+#ifdef CFG_ENV_ADDR_REDUND
+
+int  env_init(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	int crc1_ok =
+		(crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc);
+	int crc2_ok =
+		(crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);
+
+	uchar flag1 = flash_addr->flags;
+	uchar flag2 = flash_addr_new->flags;
+
+	ulong addr_default = (ulong)&default_environment[0];
+	ulong addr1 = (ulong)&(flash_addr->data);
+	ulong addr2 = (ulong)&(flash_addr_new->data);
+
+	if (crc1_ok && ! crc2_ok)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 1;
+	}
+	else if (! crc1_ok && crc2_ok)
+	{
+		gd->env_addr  = addr2;
+		gd->env_valid = 1;
+	}
+	else if (! crc1_ok && ! crc2_ok)
+	{
+		gd->env_addr  = addr_default;
+		gd->env_valid = 0;
+	}
+	else if (flag1 == active_flag && flag2 == obsolete_flag)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 1;
+	}
+	else if (flag1 == obsolete_flag && flag2 == active_flag)
+	{
+		gd->env_addr  = addr2;
+		gd->env_valid = 1;
+	}
+	else if (flag1 == flag2)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 2;
+	}
+	else if (flag1 == 0xFF)
+	{
+		gd->env_addr  = addr1;
+		gd->env_valid = 2;
+	}
+	else if (flag2 == 0xFF)
+	{
+		gd->env_addr  = addr2;
+		gd->env_valid = 2;
+	}
+
+	return (0);
+}
+
+#ifdef CMD_SAVEENV
+int saveenv(void)
+{
+	int rc = 1;
+
+	debug ("Protect off %08lX ... %08lX\n",
+		(ulong)flash_addr, end_addr);
+
+	if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
+		goto Done;
+	}
+
+	debug ("Protect off %08lX ... %08lX\n",
+		(ulong)flash_addr_new, end_addr_new);
+
+	if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
+		goto Done;
+	}
+
+	puts ("Erasing Flash...");
+	debug (" %08lX ... %08lX ...",
+		(ulong)flash_addr_new, end_addr_new);
+
+	if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
+		goto Done;
+	}
+
+	puts ("Writing to Flash... ");
+	debug (" %08lX ... %08lX ...",
+		(ulong)&(flash_addr_new->data),
+		sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
+	if (flash_write(env_ptr->data,
+	                (ulong)&(flash_addr_new->data),
+			sizeof(env_ptr->data)) ||
+
+	    flash_write((char *)&(env_ptr->crc),
+	                (ulong)&(flash_addr_new->crc),
+			sizeof(env_ptr->crc)) ||
+
+	    flash_write((char *)&obsolete_flag,
+	                (ulong)&(flash_addr->flags),
+			sizeof(flash_addr->flags)) ||
+
+	    flash_write((char *)&active_flag,
+	                (ulong)&(flash_addr_new->flags),
+			sizeof(flash_addr_new->flags)))
+	{
+		flash_perror (rc);
+		goto Done;
+	}
+	puts ("done\n");
+
+	{
+		env_t * etmp = flash_addr;
+		ulong ltmp = end_addr;
+
+		flash_addr = flash_addr_new;
+		flash_addr_new = etmp;
+
+		end_addr = end_addr_new;
+		end_addr_new = ltmp;
+	}
+
+	rc = 0;
+Done:
+
+	/* try to re-protect */
+	(void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
+	(void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+
+	return rc;
+}
+#endif /* CMD_SAVEENV */
+
+#else /* ! CFG_ENV_ADDR_REDUND */
+
+int  env_init(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+		gd->env_addr  = (ulong)&(env_ptr->data);
+		gd->env_valid = 1;
+	} else {
+		gd->env_addr  = (ulong)&default_environment[0];
+		gd->env_valid = 0;
+	}
+
+	return (0);
+}
+
+#ifdef CMD_SAVEENV
+
+int saveenv(void)
+{
+	int	len, rc;
+	ulong	end_addr;
+	ulong	flash_sect_addr;
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
+	ulong	flash_offset;
+	uchar	env_buffer[CFG_ENV_SECT_SIZE];
+#else
+	uchar *env_buffer = (char *)env_ptr;
+#endif	/* CFG_ENV_SECT_SIZE */
+	int rcode = 0;
+
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
+
+	flash_offset    = ((ulong)flash_addr) & (CFG_ENV_SECT_SIZE-1);
+	flash_sect_addr = ((ulong)flash_addr) & ~(CFG_ENV_SECT_SIZE-1);
+
+	debug ( "copy old content: "
+		"sect_addr: %08lX  env_addr: %08lX  offset: %08lX\n",
+		flash_sect_addr, (ulong)flash_addr, flash_offset);
+
+	/* copy old contents to temporary buffer */
+	memcpy (env_buffer, (void *)flash_sect_addr, CFG_ENV_SECT_SIZE);
+
+	/* copy current environment to temporary buffer */
+	memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
+		env_ptr,
+		CFG_ENV_SIZE);
+
+	len	 = CFG_ENV_SECT_SIZE;
+#else
+	flash_sect_addr = (ulong)flash_addr;
+	len	 = CFG_ENV_SIZE;
+#endif	/* CFG_ENV_SECT_SIZE */
+
+#ifndef CONFIG_INFERNO
+	end_addr = flash_sect_addr + len - 1;
+#else
+	/* this is the last sector, and the size is hardcoded here */
+	/* otherwise we will get stack problems on loading 128 KB environment */
+	end_addr = flash_sect_addr + 0x20000 - 1;
+#endif
+
+	debug ("Protect off %08lX ... %08lX\n",
+		(ulong)flash_sect_addr, end_addr);
+
+	if (flash_sect_protect (0, flash_sect_addr, end_addr))
+		return 1;
+
+	puts ("Erasing Flash...");
+	if (flash_sect_erase (flash_sect_addr, end_addr))
+		return 1;
+
+	puts ("Writing to Flash... ");
+	rc = flash_write(env_buffer, flash_sect_addr, len);
+	if (rc != 0) {
+		flash_perror (rc);
+		rcode = 1;
+	} else {
+		puts ("done\n");
+	}
+
+	/* try to re-protect */
+	(void) flash_sect_protect (1, flash_sect_addr, end_addr);
+	return rcode;
+}
+
+#endif /* CMD_SAVEENV */
+
+#endif /* CFG_ENV_ADDR_REDUND */
+
+void env_relocate_spec (void)
+{
+#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
+#ifdef CFG_ENV_ADDR_REDUND
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->env_addr != (ulong)&(flash_addr->data))
+	{
+		env_t * etmp = flash_addr;
+		ulong ltmp = end_addr;
+
+		flash_addr = flash_addr_new;
+		flash_addr_new = etmp;
+
+		end_addr = end_addr_new;
+		end_addr_new = ltmp;
+	}
+
+	if (flash_addr_new->flags != obsolete_flag &&
+	    crc32(0, flash_addr_new->data, ENV_SIZE) ==
+	    flash_addr_new->crc)
+	{
+		gd->env_valid = 2;
+		flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
+		flash_write((char *)&obsolete_flag,
+                    	    (ulong)&(flash_addr_new->flags),
+	        	    sizeof(flash_addr_new->flags));
+		flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+	}
+
+	if (flash_addr->flags != active_flag &&
+	    (flash_addr->flags & active_flag) == active_flag)
+	{
+		gd->env_valid = 2;
+		flash_sect_protect (0, (ulong)flash_addr, end_addr);
+		flash_write((char *)&active_flag,
+                    	    (ulong)&(flash_addr->flags),
+	        	    sizeof(flash_addr->flags));
+		flash_sect_protect (1, (ulong)flash_addr, end_addr);
+	}
+
+	if (gd->env_valid == 2)
+		puts ("*** Warning - some problems detected "
+		      "reading environment; recovered successfully\n\n");
+#endif /* CFG_ENV_ADDR_REDUND */
+	memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE);
+#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
+}
+
+#endif /* CFG_ENV_IS_IN_FLASH) */
diff --git a/common/env_nvram.c b/common/env_nvram.c
new file mode 100644
index 0000000..fdfa4fc
--- /dev/null
+++ b/common/env_nvram.c
@@ -0,0 +1,138 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@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
+ */
+
+/*
+ * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH <aheppel@sysgo.de>
+ *
+ * It might not be possible in all cases to use 'memcpy()' to copy
+ * the environment to NVRAM, as the NVRAM might not be mapped into
+ * the memory space. (I.e. this is the case for the BAB750). In those
+ * cases it might be possible to access the NVRAM using a different
+ * method. For example, the RTC on the BAB750 is accessible in IO
+ * space using its address and data registers. To enable usage of
+ * NVRAM in those cases I invented the functions 'nvram_read()' and
+ * 'nvram_write()', which will be activated upon the configuration
+ * #define CFG_NVRAM_ACCESS_ROUTINE. Note, that those functions are
+ * strongly dependent on the used HW, and must be redefined for each
+ * board that wants to use them.
+ */
+
+#include <common.h>
+
+#ifdef CFG_ENV_IS_IN_NVRAM /* Environment is in NVRAM */
+
+#include <command.h>
+#include <environment.h>
+#include <cmd_nvedit.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+extern void *nvram_read(void *dest, const long src, size_t count);
+extern void nvram_write(long dest, const void *src, size_t count);
+env_t *env_ptr = NULL;
+#else
+env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+char * env_name_spec = "NVRAM";
+
+extern uchar default_environment[];
+extern int default_environment_size;
+
+extern uchar (*env_get_char)(int);
+extern uchar env_get_char_memory (int index);
+
+
+uchar env_get_char_spec (int index)
+{
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+	uchar c;
+
+	nvram_read(&c, CFG_ENV_ADDR+index, 1);
+
+	return c;
+#else
+	DECLARE_GLOBAL_DATA_PTR;
+
+	return *((uchar *)(gd->env_addr + index));
+#endif
+}
+
+void env_relocate_spec (void)
+{
+#if defined(CFG_NVRAM_ACCESS_ROUTINE)
+	nvram_read(env_ptr, CFG_ENV_ADDR, CFG_ENV_SIZE);
+#else
+	memcpy (env_ptr, (void*)CFG_ENV_ADDR, CFG_ENV_SIZE);
+#endif
+}
+
+int saveenv (void)
+{
+	int rcode = 0;
+
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+	nvram_write(CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE);
+#else
+	if (memcpy ((char *)CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE) == NULL)
+		    rcode = 1 ;
+#endif
+	return rcode;
+}
+
+
+/************************************************************************
+ * Initialize Environment use
+ *
+ * We are still running from ROM, so data use is limited
+ */
+int env_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CFG_NVRAM_ACCESS_ROUTINE)
+	ulong crc;
+	uchar data[ENV_SIZE];
+	nvram_read (&crc, CFG_ENV_ADDR, sizeof(ulong));
+	nvram_read (data, CFG_ENV_ADDR+sizeof(ulong), ENV_SIZE);
+
+	if (crc32(0, data, ENV_SIZE) == crc) {
+		gd->env_addr  = (ulong)CFG_ENV_ADDR + sizeof(long);
+#else
+	if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+		gd->env_addr  = (ulong)&(env_ptr->data);
+#endif
+		gd->env_valid = 1;
+	} else {
+		gd->env_addr  = (ulong)&default_environment[0];
+		gd->env_valid = 0;
+	}
+
+	return (0);
+}
+
+#endif /* CFG_ENV_IS_IN_NVRAM */
diff --git a/common/environment.c b/common/environment.c
new file mode 100644
index 0000000..74bfd62
--- /dev/null
+++ b/common/environment.c
@@ -0,0 +1,198 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen,  Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <environment.h>
+
+/*
+ * Handle HOSTS that have prepended
+ * crap on symbol names, not TARGETS.
+ */
+#if defined(__APPLE__)
+/* Leading underscore on symbols */
+#  define SYM_CHAR "_"
+#else /* No leading character on symbols */
+#  define SYM_CHAR
+#endif
+
+/*
+ * Generate embedded environment table
+ * inside U-Boot image, if needed.
+ */
+#if defined(ENV_IS_EMBEDDED)
+/*
+ * Only put the environment in it's own section when we are building
+ * U-Boot proper.  The host based program "tools/envcrc" does not need
+ * a seperate section.  Note that ENV_CRC is only defined when building
+ * U-Boot itself.
+ */
+#if (defined(CONFIG_FADS)	|| \
+     defined(CONFIG_HYMOD)	|| \
+     defined(CONFIG_ICU862)	|| \
+     defined(CONFIG_R360MPI)	|| \
+     defined(CONFIG_TQM8xxL)	|| \
+     defined(CONFIG_RRVISION)	|| \
+     defined(CONFIG_TRAB)   )	&& \
+     defined(ENV_CRC) /* Environment embedded in U-Boot .ppcenv section */
+/* XXX - This only works with GNU C */
+#  define __PPCENV__ __attribute__ ((section(".ppcenv")))
+#  define __PPCTEXT__ __attribute__ ((section(".text")))
+
+#elif defined(USE_HOSTCC) /* Native for 'tools/envcrc' */
+#  define __PPCENV__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+#  define __PPCTEXT__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+
+#else /* Environment is embedded in U-Boot's .text section */
+/* XXX - This only works with GNU C */
+#  define __PPCENV__ __attribute__ ((section(".text")))
+#  define __PPCTEXT__ __attribute__ ((section(".text")))
+#endif
+
+/*
+ * Macros to generate global absolutes.
+ */
+#define GEN_SYMNAME(str) SYM_CHAR #str
+#define GEN_VALUE(str) #str
+#define GEN_ABS(name, value) \
+		asm (".globl " GEN_SYMNAME(name)); \
+		asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x)	#x
+#define MK_STR(x)	XMK_STR(x)
+
+/*
+ * Check to see if we are building with a
+ * computed CRC.  Otherwise define it as ~0.
+ */
+#if !defined(ENV_CRC)
+#  define ENV_CRC	~0
+#endif
+
+env_t environment __PPCENV__ = {
+	ENV_CRC,	/* CRC Sum */
+#ifdef CFG_REDUNDAND_ENVIRONMENT
+	1,		/* Flags: valid */
+#endif
+	{
+#if defined(CONFIG_BOOTARGS)
+	"bootargs="	CONFIG_BOOTARGS			"\0"
+#endif
+#if defined(CONFIG_BOOTCOMMAND)
+	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_RAMBOOTCOMMAND)
+	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_NFSBOOTCOMMAND)
+	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
+#endif
+#ifdef	CONFIG_LOADS_ECHO
+	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
+#endif
+#ifdef	CONFIG_ETHADDR
+	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH1ADDR
+	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH2ADDR
+	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETHPRIME
+	"ethprime="	CONFIG_ETHPRIME			"\0"
+#endif
+#ifdef	CONFIG_IPADDR
+	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
+#endif
+#ifdef	CONFIG_SERVERIP
+	"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
+#endif
+#ifdef	CFG_AUTOLOAD
+	"autoload="	CFG_AUTOLOAD			"\0"
+#endif
+#ifdef	CONFIG_ROOTPATH
+	"rootpath="	MK_STR(CONFIG_ROOTPATH)		"\0"
+#endif
+#ifdef	CONFIG_GATEWAYIP
+	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
+#endif
+#ifdef	CONFIG_NETMASK
+	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
+#endif
+#ifdef	CONFIG_HOSTNAME
+	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
+#endif
+#ifdef	CONFIG_BOOTFILE
+	"bootfile="	MK_STR(CONFIG_BOOTFILE)		"\0"
+#endif
+#ifdef	CONFIG_LOADADDR
+	"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
+#endif
+#ifdef	CONFIG_PREBOOT
+	"preboot="	CONFIG_PREBOOT			"\0"
+#endif
+#ifdef	CONFIG_CLOCKS_IN_MHZ
+	"clocks_in_mhz=" "1"				"\0"
+#endif
+#ifdef  CONFIG_EXTRA_ENV_SETTINGS
+	CONFIG_EXTRA_ENV_SETTINGS
+#endif
+	"\0"		/* Term. env_t.data with 2 NULLs */
+	}
+};
+#ifdef CFG_ENV_ADDR_REDUND
+env_t redundand_environment __PPCENV__ = {
+	0,		/* CRC Sum: invalid */
+	0,		/* Flags:   invalid */
+	{
+	"\0"
+	}
+};
+#endif	/* CFG_ENV_ADDR_REDUND */
+
+/*
+ * These will end up in the .text section
+ * if the environment strings are embedded
+ * in the image.  When this is used for
+ * tools/envcrc, they are placed in the
+ * .data/.sdata section.
+ *
+ */
+unsigned long env_size __PPCTEXT__ = sizeof(env_t);
+
+/*
+ * Add in absolutes.
+ */
+GEN_ABS(env_offset, CFG_ENV_OFFSET);
+
+#endif /* ENV_IS_EMBEDDED */
diff --git a/common/main.c b/common/main.c
new file mode 100644
index 0000000..014804b
--- /dev/null
+++ b/common/main.c
@@ -0,0 +1,817 @@
+/*
+ * (C) Copyright 2000
+ * 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 <watchdog.h>
+#include <command.h>
+#include <cmd_nvedit.h>
+#include <cmd_bootm.h>
+#include <malloc.h>
+#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
+#include <cmd_boot.h>		/* for do_reset() prototype */
+#endif
+
+#ifdef CFG_HUSH_PARSER
+#include <hush.h>
+#endif
+
+#define MAX_DELAY_STOP_STR 32
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
+static int parse_line (char *, char *[]);
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+static int abortboot(int);
+#endif
+
+#undef DEBUG_PARSER
+
+char        console_buffer[CFG_CBSIZE];		/* console I/O buffer	*/
+
+static char erase_seq[] = "\b \b";		/* erase sequence	*/
+static char   tab_seq[] = "        ";		/* used to expand TABs	*/
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+static uint64_t endtime = 0;  /* must be set, default is instant timeout */
+static int      retry_time = -1; /* -1 so can call readline before main_loop */
+#endif
+
+#define	endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
+
+#ifndef CONFIG_BOOT_RETRY_MIN
+#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
+#endif
+
+#ifdef CONFIG_MODEM_SUPPORT
+int do_mdm_init = 0;
+extern void mdm_init(void); /* defined in board.c */
+#endif
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
+ * returns: 0 -  no key string, allow autoboot
+ *          1 - got key string, abort
+ */
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+# if defined(CONFIG_AUTOBOOT_KEYED)
+static __inline__ int abortboot(int bootdelay)
+{
+	int abort = 0;
+	uint64_t etime = endtick(bootdelay);
+	struct
+	{
+		char* str;
+		u_int len;
+		int retry;
+	}
+	delaykey [] =
+	{
+		{ str: getenv ("bootdelaykey"),  retry: 1 },
+		{ str: getenv ("bootdelaykey2"), retry: 1 },
+		{ str: getenv ("bootstopkey"),   retry: 0 },
+		{ str: getenv ("bootstopkey2"),  retry: 0 },
+	};
+
+	char presskey [MAX_DELAY_STOP_STR];
+	u_int presskey_len = 0;
+	u_int presskey_max = 0;
+	u_int i;
+
+#  ifdef CONFIG_AUTOBOOT_PROMPT
+	printf (CONFIG_AUTOBOOT_PROMPT, bootdelay);
+#  endif
+
+#  ifdef CONFIG_AUTOBOOT_DELAY_STR
+	if (delaykey[0].str == NULL)
+		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
+#  endif
+#  ifdef CONFIG_AUTOBOOT_DELAY_STR2
+	if (delaykey[1].str == NULL)
+		delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
+#  endif
+#  ifdef CONFIG_AUTOBOOT_STOP_STR
+	if (delaykey[2].str == NULL)
+		delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
+#  endif
+#  ifdef CONFIG_AUTOBOOT_STOP_STR2
+	if (delaykey[3].str == NULL)
+		delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
+#  endif
+
+	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+		delaykey[i].len = delaykey[i].str == NULL ?
+				    0 : strlen (delaykey[i].str);
+		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
+				    MAX_DELAY_STOP_STR : delaykey[i].len;
+
+		presskey_max = presskey_max > delaykey[i].len ?
+				    presskey_max : delaykey[i].len;
+
+#  if DEBUG_BOOTKEYS
+		printf("%s key:<%s>\n",
+		       delaykey[i].retry ? "delay" : "stop",
+		       delaykey[i].str ? delaykey[i].str : "NULL");
+#  endif
+	}
+
+	/* In order to keep up with incoming data, check timeout only
+	 * when catch up.
+	 */
+	while (!abort && get_ticks() <= etime) {
+		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+			if (delaykey[i].len > 0 &&
+			    presskey_len >= delaykey[i].len &&
+			    memcmp (presskey + presskey_len - delaykey[i].len,
+		        	    delaykey[i].str,
+				    delaykey[i].len) == 0) {
+#  if DEBUG_BOOTKEYS
+				printf("got %skey\n",
+				       delaykey[i].retry ? "delay" : "stop");
+#  endif
+
+#  ifdef CONFIG_BOOT_RETRY_TIME
+				/* don't retry auto boot */
+				if (! delaykey[i].retry)
+					retry_time = -1;
+#  endif
+				abort = 1;
+			}
+		}
+
+		if (tstc()) {
+			if (presskey_len < presskey_max) {
+				presskey [presskey_len ++] = getc();
+			}
+			else {
+				for (i = 0; i < presskey_max - 1; i ++)
+					presskey [i] = presskey [i + 1];
+
+				presskey [i] = getc();
+			}
+		}
+	}
+#  if DEBUG_BOOTKEYS
+	if (!abort)
+		printf("key timeout\n");
+#  endif
+
+	return abort;
+}
+
+# else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
+
+static __inline__ int abortboot(int bootdelay)
+{
+	int abort = 0;
+
+	printf("Hit any key to stop autoboot: %2d ", bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+        /*
+         * Check if key already pressed
+         * Don't check if bootdelay < 0
+         */
+	if (bootdelay >= 0) {
+		if (tstc()) {	/* we got a key press	*/
+			(void) getc();  /* consume input	*/
+			printf ("\b\b\b 0\n");
+			return 1; 	/* don't auto boot	*/
+		}
+        }
+#endif
+
+	while (bootdelay > 0) {
+		int i;
+
+		--bootdelay;
+		/* delay 100 * 10ms */
+		for (i=0; !abort && i<100; ++i) {
+			if (tstc()) {	/* we got a key press	*/
+				abort  = 1;	/* don't auto boot	*/
+				bootdelay = 0;	/* no more delay	*/
+				(void) getc();  /* consume input	*/
+				break;
+			}
+			udelay (10000);
+		}
+
+		printf ("\b\b\b%2d ", bootdelay);
+	}
+
+	putc ('\n');
+
+	return abort;
+}
+# endif	/* CONFIG_AUTOBOOT_KEYED */
+#endif	/* CONFIG_BOOTDELAY >= 0  */
+
+/****************************************************************************/
+
+void main_loop (void)
+{
+#ifndef CFG_HUSH_PARSER
+	static char lastcommand[CFG_CBSIZE] = { 0, };
+	int len;
+	int rc = 1;
+	int flag;
+#endif
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	char *s;
+	int bootdelay;
+#endif
+#ifdef CONFIG_PREBOOT
+	char *p;
+#endif
+
+#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
+	ulong bmp = 0;		/* default bitmap */
+	extern int trab_vfd (ulong bitmap);
+
+#ifdef CONFIG_MODEM_SUPPORT
+	if (do_mdm_init)
+		bmp = 1;	/* alternate bitmap */
+#endif
+	trab_vfd (bmp);
+#endif	/* CONFIG_VFD && VFD_TEST_LOGO */
+
+#ifdef CONFIG_MODEM_SUPPORT
+	debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
+	if (do_mdm_init) {
+		uchar *str = strdup(getenv("mdm_cmd"));
+		setenv ("preboot", str);  /* set or delete definition */
+		if (str != NULL)
+			free (str);
+		mdm_init(); /* wait for modem connection */
+	}
+#endif  /* CONFIG_MODEM_SUPPORT */
+
+#ifdef CFG_HUSH_PARSER
+	u_boot_hush_start ();
+#endif
+
+#ifdef CONFIG_PREBOOT
+	if ((p = getenv ("preboot")) != NULL) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+		int prev = disable_ctrlc(1);	/* disable Control C checking */
+# endif
+
+# ifndef CFG_HUSH_PARSER
+		run_command (p, 0);
+# else
+		parse_string_outer(p, FLAG_PARSE_SEMICOLON |
+				    FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+		disable_ctrlc(prev);	/* restore Control C checking */
+# endif
+	}
+#endif /* CONFIG_PREBOOT */
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	s = getenv ("bootdelay");
+	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+
+#if 0
+	printf ("### main_loop entered:\n\n");
+#endif
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+	s = getenv ("bootretry");
+	if (s != NULL)
+		retry_time = (int)simple_strtoul(s, NULL, 10);
+	else
+		retry_time =  CONFIG_BOOT_RETRY_TIME;
+	if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
+		retry_time = CONFIG_BOOT_RETRY_MIN;
+# endif	/* CONFIG_BOOT_RETRY_TIME */
+
+	s = getenv ("bootcmd");
+	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+		int prev = disable_ctrlc(1);	/* disable Control C checking */
+# endif
+
+# ifndef CFG_HUSH_PARSER
+		run_command (s, 0);
+# else
+		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
+				    FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+		disable_ctrlc(prev);	/* restore Control C checking */
+# endif
+	}
+#endif	/* CONFIG_BOOTDELAY */
+
+	/*
+	 * Main Loop for Monitor Command Processing
+	 */
+#ifdef CFG_HUSH_PARSER
+	parse_file_outer();
+	/* This point is never reached */
+	for (;;);
+#else
+	for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+		if (rc >= 0) {
+			/* Saw enough of a valid command to
+			 * restart the timeout.
+			 */
+			reset_cmd_timeout();
+		}
+#endif
+		len = readline (CFG_PROMPT);
+
+		flag = 0;	/* assume no special flags for now */
+		if (len > 0)
+			strcpy (lastcommand, console_buffer);
+		else if (len == 0)
+			flag |= CMD_FLAG_REPEAT;
+#ifdef CONFIG_BOOT_RETRY_TIME
+		else if (len == -2) {
+			/* -2 means timed out, retry autoboot
+			 */
+			printf("\nTimed out waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+			/* Reinit board to run initialization code again */
+			do_reset (NULL, 0, 0, NULL);
+# else
+			return;		/* retry autoboot */
+# endif
+		}
+#endif
+
+		if (len == -1)
+			printf ("<INTERRUPT>\n");
+		else
+			rc = run_command (lastcommand, flag);
+
+		if (rc <= 0) {
+			/* invalid command or not repeatable, forget it */
+			lastcommand[0] = 0;
+		}
+	}
+#endif /*CFG_HUSH_PARSER*/
+}
+
+/***************************************************************************
+ * reset command line timeout to retry_time seconds
+ */
+#ifdef CONFIG_BOOT_RETRY_TIME
+void reset_cmd_timeout(void)
+{
+	endtime = endtick(retry_time);
+}
+#endif
+
+/****************************************************************************/
+
+/*
+ * Prompt for input and read a line.
+ * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
+ * time out when time goes past endtime (timebase time in ticks).
+ * Return:	number of read characters
+ *		-1 if break
+ *		-2 if timed out
+ */
+int readline (const char *const prompt)
+{
+	char   *p = console_buffer;
+	int	n = 0;				/* buffer index		*/
+	int	plen = 0;			/* prompt length	*/
+	int	col;				/* output column cnt	*/
+	char	c;
+
+	/* print prompt */
+	if (prompt) {
+		plen = strlen (prompt);
+		puts (prompt);
+	}
+	col = plen;
+
+	for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+		while (!tstc()) {	/* while no incoming data */
+			if (retry_time >= 0 && get_ticks() > endtime)
+				return (-2);	/* timed out */
+		}
+#endif
+		WATCHDOG_RESET();		/* Trigger watchdog, if needed */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+		while (!tstc()) {
+			extern void show_activity(int arg);
+			show_activity(0);
+		}
+#endif
+		c = getc();
+
+		/*
+		 * Special character handling
+		 */
+		switch (c) {
+		case '\r':				/* Enter		*/
+		case '\n':
+			*p = '\0';
+			puts ("\r\n");
+			return (p - console_buffer);
+
+		case 0x03:				/* ^C - break		*/
+			console_buffer[0] = '\0';	/* discard input */
+			return (-1);
+
+		case 0x15:				/* ^U - erase line	*/
+			while (col > plen) {
+				puts (erase_seq);
+				--col;
+			}
+			p = console_buffer;
+			n = 0;
+			continue;
+
+		case 0x17:				/* ^W - erase word 	*/
+			p=delete_char(console_buffer, p, &col, &n, plen);
+			while ((n > 0) && (*p != ' ')) {
+				p=delete_char(console_buffer, p, &col, &n, plen);
+			}
+			continue;
+
+		case 0x08:				/* ^H  - backspace	*/
+		case 0x7F:				/* DEL - backspace	*/
+			p=delete_char(console_buffer, p, &col, &n, plen);
+			continue;
+
+		default:
+			/*
+			 * Must be a normal character then
+			 */
+			if (n < CFG_CBSIZE-2) {
+				if (c == '\t') {	/* expand TABs		*/
+					puts (tab_seq+(col&07));
+					col += 8 - (col&07);
+				} else {
+					++col;		/* echo input		*/
+					putc (c);
+				}
+				*p++ = c;
+				++n;
+			} else {			/* Buffer full		*/
+				putc ('\a');
+			}
+		}
+	}
+}
+
+/****************************************************************************/
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+	char *s;
+
+	if (*np == 0) {
+		return (p);
+	}
+
+	if (*(--p) == '\t') {			/* will retype the whole line	*/
+		while (*colp > plen) {
+			puts (erase_seq);
+			(*colp)--;
+		}
+		for (s=buffer; s<p; ++s) {
+			if (*s == '\t') {
+				puts (tab_seq+((*colp) & 07));
+				*colp += 8 - ((*colp) & 07);
+			} else {
+				++(*colp);
+				putc (*s);
+			}
+		}
+	} else {
+		puts (erase_seq);
+		(*colp)--;
+	}
+	(*np)--;
+	return (p);
+}
+
+/****************************************************************************/
+
+int parse_line (char *line, char *argv[])
+{
+	int nargs = 0;
+
+#ifdef DEBUG_PARSER
+	printf ("parse_line: \"%s\"\n", line);
+#endif
+	while (nargs < CFG_MAXARGS) {
+
+		/* skip any white space */
+		while ((*line == ' ') || (*line == '\t')) {
+			++line;
+		}
+
+		if (*line == '\0') {	/* end of line, no more args	*/
+			argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+		printf ("parse_line: nargs=%d\n", nargs);
+#endif
+			return (nargs);
+		}
+
+		argv[nargs++] = line;	/* begin of argument string	*/
+
+		/* find end of string */
+		while (*line && (*line != ' ') && (*line != '\t')) {
+			++line;
+		}
+
+		if (*line == '\0') {	/* end of line, no more args	*/
+			argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+		printf ("parse_line: nargs=%d\n", nargs);
+#endif
+			return (nargs);
+		}
+
+		*line++ = '\0';		/* terminate current arg	 */
+	}
+
+	printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
+
+#ifdef DEBUG_PARSER
+	printf ("parse_line: nargs=%d\n", nargs);
+#endif
+	return (nargs);
+}
+
+/****************************************************************************/
+
+static void process_macros (const char *input, char *output)
+{
+	char c, prev;
+	const char *varname_start = NULL;
+	int inputcnt  = strlen (input);
+	int outputcnt = CFG_CBSIZE;
+	int state = 0;	/* 0 = waiting for '$'	*/
+			/* 1 = waiting for '('	*/
+			/* 2 = waiting for ')'	*/
+
+#ifdef DEBUG_PARSER
+	char *output_start = output;
+
+	printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
+#endif
+
+	prev = '\0';			/* previous character	*/
+
+	while (inputcnt && outputcnt) {
+	    c = *input++;
+	    inputcnt--;
+
+	    /* remove one level of escape characters */
+	    if ((c == '\\') && (prev != '\\')) {
+		if (inputcnt-- == 0)
+			break;
+		prev = c;
+	    	c = *input++;
+	    }
+
+	    switch (state) {
+	    case 0:			/* Waiting for (unescaped) $	*/
+		if ((c == '$') && (prev != '\\')) {
+			state++;
+		} else {
+			*(output++) = c;
+			outputcnt--;
+		}
+		break;
+	    case 1:			/* Waiting for (	*/
+		if (c == '(') {
+			state++;
+			varname_start = input;
+		} else {
+			state = 0;
+			*(output++) = '$';
+			outputcnt--;
+
+			if (outputcnt) {
+				*(output++) = c;
+				outputcnt--;
+			}
+		}
+		break;
+	    case 2:			/* Waiting for )	*/
+		if (c == ')') {
+			int i;
+			char envname[CFG_CBSIZE], *envval;
+			int envcnt = input-varname_start-1; /* Varname # of chars */
+
+			/* Get the varname */
+			for (i = 0; i < envcnt; i++) {
+				envname[i] = varname_start[i];
+			}
+			envname[i] = 0;
+
+			/* Get its value */
+			envval = getenv (envname);
+
+			/* Copy into the line if it exists */
+			if (envval != NULL)
+				while ((*envval) && outputcnt) {
+					*(output++) = *(envval++);
+					outputcnt--;
+				}
+			/* Look for another '$' */
+			state = 0;
+		}
+		break;
+	    }
+
+	    prev = c;
+	}
+
+	if (outputcnt)
+		*output = 0;
+
+#ifdef DEBUG_PARSER
+	printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+		strlen(output_start), output_start);
+#endif
+}
+
+/****************************************************************************
+ * returns:
+ *	1  - command executed, repeatable
+ *	0  - command executed but not repeatable, interrupted commands are
+ *	     always considered not repeatable
+ *	-1 - not executed (unrecognized, bootd recursion or too many args)
+ *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
+ *           considered unrecognized)
+ *
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ */
+
+int run_command (const char *cmd, int flag)
+{
+	cmd_tbl_t *cmdtp;
+	char cmdbuf[CFG_CBSIZE];	/* working copy of cmd		*/
+	char *token;			/* start of token in cmdbuf	*/
+	char *sep;			/* end of token (separator) in cmdbuf */
+	char finaltoken[CFG_CBSIZE];
+	char *str = cmdbuf;
+	char *argv[CFG_MAXARGS + 1];	/* NULL terminated	*/
+	int argc;
+	int repeatable = 1;
+
+#ifdef DEBUG_PARSER
+	printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
+	puts (cmd ? cmd : "NULL");	/* use puts - string may be loooong */
+	puts ("\"\n");
+#endif
+
+	clear_ctrlc();		/* forget any previous Control C */
+
+	if (!cmd || !*cmd) {
+		return -1;	/* empty command */
+	}
+
+	if (strlen(cmd) >= CFG_CBSIZE) {
+		puts ("## Command too long!\n");
+		return -1;
+	}
+
+	strcpy (cmdbuf, cmd);
+
+	/* Process separators and check for invalid
+	 * repeatable commands
+	 */
+
+#ifdef DEBUG_PARSER
+	printf ("[PROCESS_SEPARATORS] %s\n", cmd);
+#endif
+	while (*str) {
+
+		/*
+		 * Find separator, or string end
+		 * Allow simple escape of ';' by writing "\;"
+		 */
+		for (sep = str; *sep; sep++) {
+			if ((*sep == ';') &&	/* separator		*/
+			    ( sep != str) &&	/* past string start	*/
+			    (*(sep-1) != '\\'))	/* and NOT escaped	*/
+				break;
+		}
+
+		/*
+		 * Limit the token to data between separators
+		 */
+		token = str;
+		if (*sep) {
+			str = sep + 1;	/* start of command for next pass */
+			*sep = '\0';
+		}
+		else
+			str = sep;	/* no more commands for next pass */
+#ifdef DEBUG_PARSER
+		printf ("token: \"%s\"\n", token);
+#endif
+
+		/* find macros in this token and replace them */
+		process_macros (token, finaltoken);
+
+		/* Extract arguments */
+		argc = parse_line (finaltoken, argv);
+
+		/* Look up command in command table */
+		if ((cmdtp = find_cmd(argv[0])) == NULL) {
+			printf ("Unknown command '%s' - try 'help'\n", argv[0]);
+			return -1;	/* give up after bad command */
+		}
+
+		/* found - check max args */
+		if (argc > cmdtp->maxargs) {
+			printf ("Usage:\n%s\n", cmdtp->usage);
+			return -1;
+		}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
+		/* avoid "bootd" recursion */
+		if (cmdtp->cmd == do_bootd) {
+#ifdef DEBUG_PARSER
+			printf ("[%s]\n", finaltoken);
+#endif
+			if (flag & CMD_FLAG_BOOTD) {
+				printf ("'bootd' recursion detected\n");
+				return -1;
+			}
+			else
+				flag |= CMD_FLAG_BOOTD;
+		}
+#endif	/* CFG_CMD_BOOTD */
+
+		/* OK - call function to do the command */
+		if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
+			return (-1);
+		}
+
+		repeatable &= cmdtp->repeatable;
+
+		/* Did the user stop this? */
+		if (had_ctrlc ())
+			return 0;	/* if stopped then not repeatable */
+	}
+
+	return repeatable;
+}
+
+/****************************************************************************/
+
+#if (CONFIG_COMMANDS & CFG_CMD_RUN)
+int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int i;
+	int rcode = 1;
+
+	if (argc < 2) {
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	for (i=1; i<argc; ++i) {
+#ifndef CFG_HUSH_PARSER
+	    if (run_command (getenv (argv[i]), flag) != -1) ++rcode;
+#else
+   	    if (parse_string_outer(getenv (argv[i]),
+		    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) ++rcode;
+#endif
+	}
+	return ((rcode == i) ? 0 : 1);
+}
+#endif
diff --git a/common/miiphyutil.c b/common/miiphyutil.c
new file mode 100644
index 0000000..6b2425f
--- /dev/null
+++ b/common/miiphyutil.c
@@ -0,0 +1,172 @@
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <miiphy.h>
+
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+
+/*****************************************************************************
+ *
+ * Read the OUI, manufacture's model number, and revision number.
+ *
+ * OUI:     22 bits (unsigned int)
+ * Model:    6 bits (unsigned char)
+ * Revision: 4 bits (unsigned char)
+ *
+ * Returns:
+ *   0 on success
+ */
+int miiphy_info (unsigned char addr,
+		 unsigned int *oui,
+		 unsigned char *model, unsigned char *rev)
+{
+	unsigned int reg = 0;
+
+	/*
+	 * Trick: we are reading two 16 registers into a 32 bit variable
+	 * so we do a 16 read into the high order bits of the variable (big
+	 * endian, you know), shift it down 16 bits, and the read the rest.
+	 */
+	if (miiphy_read (addr, PHY_PHYIDR2, (unsigned short *) &reg) != 0) {
+#ifdef DEBUG
+		printf ("PHY ID register 2 read failed\n");
+#endif
+		return (-1);
+	}
+	reg >>= 16;
+
+#ifdef DEBUG
+	printf ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg);
+#endif
+	if (reg == 0xFFFF) {
+		/* No physical device present at this address */
+		return (-1);
+	}
+
+	if (miiphy_read (addr, PHY_PHYIDR1, (unsigned short *) &reg) != 0) {
+#ifdef DEBUG
+		printf ("PHY ID register 1 read failed\n");
+#endif
+		return (-1);
+	}
+#ifdef DEBUG
+	printf ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
+#endif
+	*oui   =                 ( reg >> 10);
+	*model = (unsigned char) ((reg >>  4) & 0x0000003F);
+	*rev   = (unsigned char) ( reg        & 0x0000000F);
+	return (0);
+}
+
+
+/*****************************************************************************
+ *
+ * Reset the PHY.
+ * Returns:
+ *   0 on success
+ */
+int miiphy_reset (unsigned char addr)
+{
+	unsigned short reg;
+	int loop_cnt;
+
+	if (miiphy_write (addr, PHY_BMCR, 0x8000) != 0) {
+#ifdef DEBUG
+		printf ("PHY reset failed\n");
+#endif
+		return (-1);
+	}
+
+	/*
+	 * Poll the control register for the reset bit to go to 0 (it is
+	 * auto-clearing).  This should happen within 0.5 seconds per the
+	 * IEEE spec.
+	 */
+	loop_cnt = 0;
+	reg = 0x8000;
+	while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) {
+		if (miiphy_read (addr, PHY_BMCR, &reg) != 0) {
+#     ifdef DEBUG
+			printf ("PHY status read failed\n");
+#     endif
+			return (-1);
+		}
+	}
+	if ((reg & 0x8000) == 0) {
+		return (0);
+	} else {
+		printf ("PHY reset timed out\n");
+		return (-1);
+	}
+	return (0);
+}
+
+
+/*****************************************************************************
+ *
+ * Determine the ethernet speed (10/100).
+ */
+int miiphy_speed (unsigned char addr)
+{
+	unsigned short reg;
+
+	if (miiphy_read (addr, PHY_ANLPAR, &reg)) {
+		printf ("PHY speed1 read failed, assuming 10bT\n");
+		return (_10BASET);
+	}
+
+	if ((reg & PHY_ANLPAR_100) != 0) {
+		return (_100BASET);
+	} else {
+		return (_10BASET);
+	}
+}
+
+
+/*****************************************************************************
+ *
+ * Determine full/half duplex.
+ */
+int miiphy_duplex (unsigned char addr)
+{
+	unsigned short reg;
+
+	if (miiphy_read (addr, PHY_ANLPAR, &reg)) {
+		printf ("PHY duplex read failed, assuming half duplex\n");
+		return (HALF);
+	}
+
+	if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) {
+		return (FULL);
+	} else {
+		return (HALF);
+	}
+}
+
+#endif /* CONFIG_MII || (CONFIG_COMMANDS & CFG_CMD_MII) */
diff --git a/common/soft_i2c.c b/common/soft_i2c.c
new file mode 100644
index 0000000..7777480
--- /dev/null
+++ b/common/soft_i2c.c
@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 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
+ *
+ * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
+ * vanbaren@cideas.com.  It was heavily influenced by LiMon, written by
+ * Neil Russell.
+ */
+
+#include <common.h>
+#ifdef	CONFIG_MPC8260			/* only valid for MPC8260 */
+#include <ioports.h>
+#endif
+#include <i2c.h>
+
+#if defined(CONFIG_SOFT_I2C)
+
+/* #define	DEBUG_I2C	*/
+
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define RETRIES		0
+
+
+#define I2C_ACK		0		/* PD_SDA level to ack a byte */
+#define I2C_NOACK	1		/* PD_SDA level to noack a byte */
+
+
+#ifdef DEBUG_I2C
+#define PRINTD(fmt,args...)	do {	\
+	DECLARE_GLOBAL_DATA_PTR;	\
+	if (gd->have_console)		\
+		printf (fmt ,##args);	\
+	} while (0)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+/*-----------------------------------------------------------------------
+ * Local functions
+ */
+static void  send_reset	(void);
+static void  send_start	(void);
+static void  send_stop	(void);
+static void  send_ack	(int);
+static int   write_byte	(uchar byte);
+static uchar read_byte	(int);
+
+
+/*-----------------------------------------------------------------------
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state.  Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void send_reset(void)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int j;
+
+	I2C_ACTIVE;
+	I2C_SDA(1);
+	for(j = 0; j < 9; j++) {
+		I2C_SCL(0);
+		I2C_DELAY;
+		I2C_DELAY;
+		I2C_SCL(1);
+		I2C_DELAY;
+		I2C_DELAY;
+	}
+	send_stop();
+	I2C_TRISTATE;
+}
+
+/*-----------------------------------------------------------------------
+ * START: High -> Low on SDA while SCL is High
+ */
+static void send_start(void)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+	I2C_DELAY;
+	I2C_SDA(1);
+	I2C_ACTIVE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_SDA(0);
+	I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
+ * STOP: Low -> High on SDA while SCL is High
+ */
+static void send_stop(void)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+	I2C_SCL(0);
+	I2C_DELAY;
+	I2C_SDA(0);
+	I2C_ACTIVE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_SDA(1);
+	I2C_DELAY;
+	I2C_TRISTATE;
+}
+
+
+/*-----------------------------------------------------------------------
+ * ack should be I2C_ACK or I2C_NOACK
+ */
+static void send_ack(int ack)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+	I2C_ACTIVE;
+	I2C_SCL(0);
+	I2C_DELAY;
+
+	I2C_SDA(ack);
+
+	I2C_ACTIVE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_DELAY;
+	I2C_SCL(0);
+	I2C_DELAY;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Send 8 bits and look for an acknowledgement.
+ */
+static int write_byte(uchar data)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int j;
+	int nack;
+
+	I2C_ACTIVE;
+	for(j = 0; j < 8; j++) {
+		I2C_SCL(0);
+		I2C_DELAY;
+		I2C_SDA(data & 0x80);
+		I2C_DELAY;
+		I2C_SCL(1);
+		I2C_DELAY;
+		I2C_DELAY;
+
+		data <<= 1;
+	}
+
+	/*
+	 * Look for an <ACK>(negative logic) and return it.
+	 */
+	I2C_SCL(0);
+	I2C_DELAY;
+	I2C_SDA(1);
+	I2C_TRISTATE;
+	I2C_DELAY;
+	I2C_SCL(1);
+	I2C_DELAY;
+	I2C_DELAY;
+	nack = I2C_READ;
+	I2C_SCL(0);
+	I2C_DELAY;
+	I2C_ACTIVE;
+
+	return(nack);	/* not a nack is an ack */
+}
+
+
+/*-----------------------------------------------------------------------
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar read_byte(int ack)
+{
+#ifdef	CONFIG_MPC8260
+	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+	int  data;
+	int  j;
+
+	/*
+	 * Read 8 bits, MSB first.
+	 */
+	I2C_TRISTATE;
+	data = 0;
+	for(j = 0; j < 8; j++) {
+		I2C_SCL(0);
+		I2C_DELAY;
+		I2C_SCL(1);
+		I2C_DELAY;
+		data <<= 1;
+		data |= I2C_READ;
+		I2C_DELAY;
+	}
+	send_ack(ack);
+
+	return(data);
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+void i2c_init (int speed, int slaveaddr)
+{
+#ifdef	CONFIG_8xx
+	volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+#ifdef	I2C_INIT
+	I2C_INIT;
+#endif
+	/*
+         * WARNING: Do NOT save speed in a static variable: if the
+         * I2C routines are called before RAM is initialized (to read
+         * the DIMM SPD, for instance), RAM won't be usable and your
+         * system will crash.
+	 */
+	send_reset ();
+}
+
+/*-----------------------------------------------------------------------
+ * Probe to see if a chip is present.  Also good for checking for the
+ * completion of EEPROM writes since the chip stops responding until
+ * the write completes (typically 10mSec).
+ */
+int i2c_probe(uchar addr)
+{
+	int rc;
+
+	send_start();
+	rc = write_byte ((addr << 1) | 1);
+	send_stop();
+
+	return (rc ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------------
+ * Read bytes
+ */
+int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	int shift;
+	PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
+		chip, addr, alen, buffer, len);
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+	/*
+	 * EEPROM chips that implement "address overflow" are ones
+	 * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+	 * address and the extra bits end up in the "chip address"
+	 * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+	 * four 256 byte chips.
+	 *
+	 * Note that we consider the length of the address field to
+	 * still be one byte because the extra address bits are
+	 * hidden in the chip address.
+	 */
+	chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+
+	PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
+		chip, addr);
+#endif
+
+	/*
+	 * Do the addressing portion of a write cycle to set the
+	 * chip's address pointer.  If the address length is zero,
+	 * don't do the normal write cycle to set the address pointer,
+	 * there is no address pointer in this chip.
+	 */
+	send_start();
+	if(alen > 0) {
+		if(write_byte(chip << 1)) {	/* write cycle */
+			send_stop();
+			PRINTD("i2c_read, no chip responded %02X\n", chip);
+			return(1);
+		}
+		shift = (alen-1) * 8;
+		while(alen-- > 0) {
+			if(write_byte(addr >> shift)) {
+				PRINTD("i2c_read, address not <ACK>ed\n");
+				return(1);
+			}
+			shift -= 8;
+		}
+		send_stop();	/* reportedly some chips need a full stop */
+		send_start();
+	}
+	/*
+	 * Send the chip address again, this time for a read cycle.
+	 * Then read the data.  On the last byte, we do a NACK instead
+	 * of an ACK(len == 0) to terminate the read.
+	 */
+	write_byte((chip << 1) | 1);	/* read cycle */
+	while(len-- > 0) {
+		*buffer++ = read_byte(len == 0);
+	}
+	send_stop();
+	return(0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write bytes
+ */
+int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	int shift, failures = 0;
+
+	PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
+		chip, addr, alen, buffer, len);
+
+	send_start();
+	if(write_byte(chip << 1)) {	/* write cycle */
+		send_stop();
+		PRINTD("i2c_write, no chip responded %02X\n", chip);
+		return(1);
+	}
+	shift = (alen-1) * 8;
+	while(alen-- > 0) {
+		if(write_byte(addr >> shift)) {
+			PRINTD("i2c_write, address not <ACK>ed\n");
+			return(1);
+		}
+		shift -= 8;
+	}
+
+	while(len-- > 0) {
+		if(write_byte(*buffer++)) {
+			failures++;
+		}
+	}
+	send_stop();
+	return(failures);
+}
+
+/*-----------------------------------------------------------------------
+ * Read a register
+ */
+uchar i2c_reg_read(uchar i2c_addr, uchar reg)
+{
+	char buf;
+
+	i2c_read(i2c_addr, reg, 1, &buf, 1);
+
+	return(buf);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a register
+ */
+void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
+{
+	i2c_write(i2c_addr, reg, 1, &val, 1);
+}
+
+
+#endif	/* CONFIG_SOFT_I2C */