Patchwork [5/6] mips_malta: generate SMBUS EEPROM data

login
register
mail settings
Submitter Leon Alrae
Date June 14, 2013, 7:30 a.m.
Message ID <1371195048-19618-6-git-send-email-leon.alrae@imgtec.com>
Download mbox | patch
Permalink /patch/251254/
State New
Headers show

Comments

Leon Alrae - June 14, 2013, 7:30 a.m.
From: Paul Burton <paul.burton@imgtec.com>

The malta contains 2 EEPROMs, one containing SPD data for the SDRAM and
another containing board information such as serial number and MAC
address. These are both exposed via the PIIX4 SMBUS. Generating this
data and providing it to smbus_eeprom_init will allow YAMON to read a
serial number for the board and prevent it from warning that the EEPROM
data is invalid.

We already have the contents of the SPD EEPROM which are exposed via
FPGA I2C accesses, this is provided as part of the SMBUS EEPROM data
too for consistency.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 hw/mips/mips_malta.c |  133 ++++++++++++++++++++++++++++++++-----------------
 1 files changed, 87 insertions(+), 46 deletions(-)

Patch

diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 6d43e86..467c38e 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -145,7 +145,7 @@  struct _eeprom24c0x_t {
 
 typedef struct _eeprom24c0x_t eeprom24c0x_t;
 
-static eeprom24c0x_t eeprom = {
+static eeprom24c0x_t spd_eeprom = {
     .contents = {
         /* 00000000: */ 0x80,0x08,0xff,0x0D,0x0A,0xff,0x40,0x00,
         /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
@@ -166,10 +166,10 @@  static eeprom24c0x_t eeprom = {
     },
 };
 
-static void eeprom_generate(eeprom24c0x_t *eeprom, ram_addr_t ram_size)
+static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
 {
     enum { SDR = 0x4, DDR2 = 0x8 } type;
-    uint8_t *spd = eeprom->contents;
+    uint8_t *spd = spd_eeprom.contents;
     uint8_t nbanks = 0;
     uint16_t density = 0;
     int i;
@@ -214,71 +214,109 @@  static void eeprom_generate(eeprom24c0x_t *eeprom, ram_addr_t ram_size)
     for (i = 0; i < 63; i++) {
         spd[63] += spd[i];
     }
+
+    /* copy for SMBUS */
+    memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
+}
+
+static void generate_eeprom_serial(uint8_t *eeprom)
+{
+    int i, pos = 0;
+    uint8_t mac[6] = { 0x00 };
+    uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
+
+    /* version */
+    eeprom[pos++] = 0x01;
+
+    /* count */
+    eeprom[pos++] = 0x02;
+
+    /* MAC address */
+    eeprom[pos++] = 0x01; /* MAC */
+    eeprom[pos++] = 0x06; /* length */
+    memcpy(&eeprom[pos], mac, sizeof(mac));
+    pos += sizeof(mac);
+
+    /* serial number */
+    eeprom[pos++] = 0x02; /* serial */
+    eeprom[pos++] = 0x05; /* length */
+    memcpy(&eeprom[pos], sn, sizeof(sn));
+    pos += sizeof(sn);
+
+    /* checksum */
+    eeprom[pos] = 0;
+    for (i = 0; i < pos; i++) {
+        eeprom[pos] += eeprom[i];
+    }
 }
 
-static uint8_t eeprom24c0x_read(void)
+static uint8_t eeprom24c0x_read(eeprom24c0x_t *eeprom)
 {
     logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
-        eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
-    return eeprom.sda;
+        eeprom->tick, eeprom->scl, eeprom->sda, eeprom->data);
+    return eeprom->sda;
 }
 
-static void eeprom24c0x_write(int scl, int sda)
+static void eeprom24c0x_write(eeprom24c0x_t *eeprom, int scl, int sda)
 {
-    if (eeprom.scl && scl && (eeprom.sda != sda)) {
+    if (eeprom->scl && scl && (eeprom->sda != sda)) {
         logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
-                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
+                eeprom->tick, eeprom->scl, scl, eeprom->sda, sda,
+                sda ? "stop" : "start");
         if (!sda) {
-            eeprom.tick = 1;
-            eeprom.command = 0;
+            eeprom->tick = 1;
+            eeprom->command = 0;
         }
-    } else if (eeprom.tick == 0 && !eeprom.ack) {
+    } else if (eeprom->tick == 0 && !eeprom->ack) {
         /* Waiting for start. */
         logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
-                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
-    } else if (!eeprom.scl && scl) {
+                eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
+    } else if (!eeprom->scl && scl) {
         logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
-                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
-        if (eeprom.ack) {
+                eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
+        if (eeprom->ack) {
             logout("\ti2c ack bit = 0\n");
             sda = 0;
-            eeprom.ack = 0;
-        } else if (eeprom.sda == sda) {
+            eeprom->ack = 0;
+        } else if (eeprom->sda == sda) {
             uint8_t bit = (sda != 0);
             logout("\ti2c bit = %d\n", bit);
-            if (eeprom.tick < 9) {
-                eeprom.command <<= 1;
-                eeprom.command += bit;
-                eeprom.tick++;
-                if (eeprom.tick == 9) {
-                    logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
-                    eeprom.ack = 1;
+            if (eeprom->tick < 9) {
+                eeprom->command <<= 1;
+                eeprom->command += bit;
+                eeprom->tick++;
+                if (eeprom->tick == 9) {
+                    logout("\tcommand 0x%04x, %s\n", eeprom->command,
+                           bit ? "read" : "write");
+                    eeprom->ack = 1;
                 }
-            } else if (eeprom.tick < 17) {
-                if (eeprom.command & 1) {
-                    sda = ((eeprom.data & 0x80) != 0);
+            } else if (eeprom->tick < 17) {
+                if (eeprom->command & 1) {
+                    sda = ((eeprom->data & 0x80) != 0);
                 }
-                eeprom.address <<= 1;
-                eeprom.address += bit;
-                eeprom.tick++;
-                eeprom.data <<= 1;
-                if (eeprom.tick == 17) {
-                    eeprom.data = eeprom.contents[eeprom.address];
-                    logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
-                    eeprom.ack = 1;
-                    eeprom.tick = 0;
+                eeprom->address <<= 1;
+                eeprom->address += bit;
+                eeprom->tick++;
+                eeprom->data <<= 1;
+                if (eeprom->tick == 17) {
+                    eeprom->data = eeprom->contents[eeprom->address];
+                    logout("\taddress 0x%04x, data 0x%02x\n",
+                           eeprom->address, eeprom->data);
+                    eeprom->ack = 1;
+                    eeprom->tick = 0;
                 }
-            } else if (eeprom.tick >= 17) {
+            } else if (eeprom->tick >= 17) {
                 sda = 0;
             }
         } else {
             logout("\tsda changed with raising scl\n");
         }
     } else {
-        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom->tick, eeprom->scl,
+               scl, eeprom->sda, sda);
     }
-    eeprom.scl = scl;
-    eeprom.sda = sda;
+    eeprom->scl = scl;
+    eeprom->sda = sda;
 }
 
 static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
@@ -341,7 +379,7 @@  static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
 
     /* I2CINP Register */
     case 0x00b00:
-        val = ((s->i2cin & ~1) | eeprom24c0x_read());
+        val = ((s->i2cin & ~1) | eeprom24c0x_read(&spd_eeprom));
         break;
 
     /* I2COE Register */
@@ -437,7 +475,7 @@  static void malta_fpga_write(void *opaque, hwaddr addr,
 
     /* I2COUT Register */
     case 0x00b10:
-        eeprom24c0x_write(val & 0x02, val & 0x01);
+        eeprom24c0x_write(&spd_eeprom, val & 0x02, val & 0x01);
         s->i2cout = val;
         break;
 
@@ -842,6 +880,8 @@  void mips_malta_init(QEMUMachineInitArgs *args)
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1);
     target_long bios_size = FLASH_SIZE;
+    const size_t smbus_eeprom_size = 8 * 256;
+    uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
     int64_t kernel_entry;
     PCIBus *pci_bus;
     ISABus *isa_bus;
@@ -909,7 +949,8 @@  void mips_malta_init(QEMUMachineInitArgs *args)
     memory_region_add_subregion(system_memory, 0, ram);
 
     /* generate SPD EEPROM data */
-    eeprom_generate(&eeprom, ram_size);
+    generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
+    generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
@@ -1031,8 +1072,8 @@  void mips_malta_init(QEMUMachineInitArgs *args)
     pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
     smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
                           isa_get_irq(NULL, 9), NULL, 0, NULL);
-    /* TODO: Populate SPD eeprom data.  */
-    smbus_eeprom_init(smbus, 8, NULL, 0);
+    smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
+    g_free(smbus_eeprom_buf);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);