Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / mtd / mw_eeprom.c
diff --git a/qemu/roms/u-boot/drivers/mtd/mw_eeprom.c b/qemu/roms/u-boot/drivers/mtd/mw_eeprom.c
new file mode 100644 (file)
index 0000000..f7791b5
--- /dev/null
@@ -0,0 +1,236 @@
+/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
+
+#include <common.h>
+#include <asm/ic/ssi.h>
+
+/*
+ * 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;
+}