* Patch by Marc Singer, 29 May 2003:
  Fixed rarp boot method for IA32 and other little-endian CPUs.

* Patch by Marc Singer, 28 May 2003:
  Added port I/O commands.

* Patch by Matthew McClintock, 28 May 2003
  - cpu/mpc824x/start.S: fix relocation code when booting from RAM
  - minor patches for utx8245

* Patch by Daniel Engström, 28 May 2003:
  x86 update

* Patch by Dave Ellis, 9 May 2003 + 27 May 2003:
  add nand flash support to SXNI855T configuration
  fix/extend nand flash support:
  - fix 'nand erase' command so does not erase bad blocks
  - fix 'nand write' command so does not write to bad blocks
  - fix nand_probe() so handles no flash detected properly
  - add doc/README.nand
  - add .jffs2 and .oob options to nand read/write
  - add 'nand bad' command to list bad blocks
  - add 'clean' option to 'nand erase' to write JFFS2 clean markers
  - make NAND read/write faster

* Patch by Rune Torgersen, 23 May 2003:
  Update for MPC8266ADS board
diff --git a/drivers/mw_eeprom.c b/drivers/mw_eeprom.c
new file mode 100644
index 0000000..30a51fa
--- /dev/null
+++ b/drivers/mw_eeprom.c
@@ -0,0 +1,242 @@
+/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
+
+#include <common.h>
+#include <ssi.h>
+
+
+#ifdef CONFIG_MW_EEPROM
+
+/*
+ * Serial EEPROM opcodes, including start bit
+ */
+#define EEP_OPC_ERASE	0x7  /* 3-bit opcode */
+#define EEP_OPC_WRITE	0x5  /* 3-bit opcode */
+#define EEP_OPC_READ	        0x6  /* 3-bit opcode */
+
+#define EEP_OPC_ERASE_ALL	0x12 /* 5-bit opcode */
+#define EEP_OPC_ERASE_EN	0x13 /* 5-bit opcode */
+#define EEP_OPC_WRITE_ALL	0x11 /* 5-bit opcode */
+#define EEP_OPC_ERASE_DIS	0x10 /* 5-bit opcode */
+
+static int addrlen;
+
+static void mw_eeprom_select(int dev)
+{
+	ssi_set_interface(2048, 0, 0, 0);
+	ssi_chip_select(0);
+	udelay(1);
+	ssi_chip_select(dev);
+	udelay(1);
+}
+
+static int mw_eeprom_size(int dev)
+{
+	int x;
+	u16 res;
+		
+	mw_eeprom_select(dev);
+	ssi_tx_byte(EEP_OPC_READ);
+	
+	res = ssi_txrx_byte(0) << 8;
+	res |= ssi_rx_byte();
+	for (x = 0; x < 16; x++) {
+		if (! (res & 0x8000)) {
+			break;
+		}
+		res <<= 1;
+	}
+	ssi_chip_select(0);
+	
+	return x;
+}
+
+int mw_eeprom_erase_enable(int dev)
+{
+	mw_eeprom_select(dev);
+	ssi_tx_byte(EEP_OPC_ERASE_EN);
+	ssi_tx_byte(0);
+	udelay(1);
+	ssi_chip_select(0);
+		
+	return 0;
+}
+
+int mw_eeprom_erase_disable(int dev)
+{	
+	mw_eeprom_select(dev);
+	ssi_tx_byte(EEP_OPC_ERASE_DIS);
+	ssi_tx_byte(0);
+	udelay(1);
+	ssi_chip_select(0);
+		
+	return 0;
+}
+
+
+u32 mw_eeprom_read_word(int dev, int addr)
+{
+	u16 rcv;
+	u16 res;
+	int bits;
+	
+	mw_eeprom_select(dev);
+	ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f));
+	rcv = ssi_txrx_byte(addr << (13 - addrlen));
+	res = rcv << (16 - addrlen);
+	bits = 4 + addrlen;
+	
+	while (bits>0) {
+		rcv = ssi_rx_byte();
+		if (bits > 7) {
+			res |= rcv << (bits - 8);
+		} else {
+			res |= rcv >> (8 - bits);
+		}
+		bits -= 8;
+	}
+	
+	ssi_chip_select(0);
+	
+	return res;
+}
+
+int mw_eeprom_write_word(int dev, int addr, u16 data)
+{
+	u8 byte1=0;
+	u8 byte2=0;
+	
+	mw_eeprom_erase_enable(dev);
+	mw_eeprom_select(dev);
+	
+	switch (addrlen) {
+	 case 6:
+		byte1 = EEP_OPC_WRITE >> 2;
+		byte2 = (EEP_OPC_WRITE << 6)&0xc0;
+		byte2 |= addr;
+		break;
+	 case 7:
+		byte1 = EEP_OPC_WRITE >> 1;
+		byte2 = (EEP_OPC_WRITE << 7)&0x80;
+		byte2 |= addr;
+		break;
+	 case 8:
+		byte1 = EEP_OPC_WRITE;
+		byte2 = addr;
+		break;
+	 case 9:
+		byte1 = EEP_OPC_WRITE << 1;
+		byte1 |= addr >> 8;
+		byte2 = addr & 0xff;
+		break;
+	 case 10:
+		byte1 = EEP_OPC_WRITE << 2;
+		byte1 |= addr >> 8;
+		byte2 = addr & 0xff;
+		break;
+	 default:
+		printf("Unsupported number of address bits: %d\n", addrlen);
+		return -1;
+		
+	}
+	
+	ssi_tx_byte(byte1);
+	ssi_tx_byte(byte2);
+	ssi_tx_byte(data >> 8);	
+	ssi_tx_byte(data & 0xff);
+	ssi_chip_select(0);	
+	udelay(10000); /* Worst case */
+	mw_eeprom_erase_disable(dev);
+
+	return 0;
+}
+
+
+int mw_eeprom_write(int dev, int addr, u8 *buffer, int len)
+{
+	int done;
+	
+	done = 0;
+	if (addr & 1) {
+		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
+		temp &= 0xff00;
+		temp |= buffer[0];
+		
+		mw_eeprom_write_word(dev, addr >> 1, temp);
+		len--;
+		addr++;
+		buffer++;
+		done++;
+	}
+	
+	while (len <= 2) {
+		mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer);
+		len-=2;
+		addr+=2;
+		buffer+=2;
+		done+=2;
+	}
+
+	if (len) {
+		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
+		temp &= 0x00ff;
+		temp |= buffer[0] << 8;
+		
+		mw_eeprom_write_word(dev, addr >> 1, temp);
+		len--;
+		addr++;
+		buffer++;
+		done++;
+	}
+
+	return done;
+}
+
+
+
+int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
+{
+	int done;
+	
+	done = 0;
+	if (addr & 1) {
+		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
+		buffer[0]= temp & 0xff;
+		
+		len--;
+		addr++;
+		buffer++;
+		done++;
+	}
+	
+	while (len <= 2) {
+		*(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1);
+		len-=2;
+		addr+=2;
+		buffer+=2;
+		done+=2;
+	}
+
+	if (len) {
+		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
+		buffer[0] = temp >> 8;
+		
+		len--;
+		addr++;
+		buffer++;
+		done++;
+	}
+
+	return done;
+}
+
+int mw_eeprom_probe(int dev)
+{
+	addrlen = mw_eeprom_size(dev);
+	
+	if (addrlen < 6 || addrlen > 10) {
+		return -1;
+	}
+	return 0;
+}
+
+#endif