diff mbox series

[RFC] WIP macio/cuda: Attempt to add i2c support

Message ID alpine.BSF.2.22.395.2006281432290.95193@zero.eik.bme.hu
State New
Headers show
Series [RFC] WIP macio/cuda: Attempt to add i2c support | expand

Commit Message

BALATON Zoltan June 28, 2020, 12:37 p.m. UTC
This is a non-working RFC patch attempt to implement i2c bus in CUDA
needed for firmware to access SPD data of installed RAM. The skeleton
is there but actual operation fails because I don't know how this is
supposed to work and the i2c bus state becomes invalid quickly. Also
sending back results may be missing or wrong. Help fixing and
finishing this is welcome, I don't plan to spend more time with this
so just submitted it for whoever picks this up.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
This is still RFC and only for testing but with this the ROM seems to 
detect some RAM now:

cuda_packet_receive length 5
cuda_packet_receive_data [0] 0x01
cuda_packet_receive_data [1] 0x25
cuda_packet_receive_data [2] 0xa0
cuda_packet_receive_data [3] 0x02
cuda_packet_receive_data [4] 0xa1
cuda_receive_packet_cmd handling command COMBINED_FORMAT_IIC
i2c_event start(addr:0x50)
smbus(50): Incoming data
i2c_send send(addr:0x50) data:0x02
smbus(50): Write data 02
i2c_event finish(addr:0x50)
smbus(50): Command 2 len 1
eeprom_write_byte: addr=0x50 cmd=0x02 val=0x00
i2c_event start(addr:0x50)
smbus(50): Read mode
eeprom_receive_byte: addr=0x50 val=0x04
smbus(50): Read data 04
i2c_recv recv(addr:0x50) data:0x04
eeprom_receive_byte: addr=0x50 val=0x0d
smbus(50): Read data 0d
i2c_recv recv(addr:0x50) data:0x0d
eeprom_receive_byte: addr=0x50 val=0x0a
smbus(50): Read data 0a
i2c_recv recv(addr:0x50) data:0x0a
eeprom_receive_byte: addr=0x50 val=0x02
smbus(50): Read data 02
i2c_recv recv(addr:0x50) data:0x02
eeprom_receive_byte: addr=0x50 val=0x40
smbus(50): Read data 40
i2c_recv recv(addr:0x50) data:0x40
i2c_event finish(addr:0x50)
smbus(50): Quick Command 1
cuda_packet_send length 8
cuda_packet_send_data [0] 0x01
cuda_packet_send_data [1] 0x00
cuda_packet_send_data [2] 0x25
cuda_packet_send_data [3] 0x04
cuda_packet_send_data [4] 0x0d
cuda_packet_send_data [5] 0x0a
cuda_packet_send_data [6] 0x02
cuda_packet_send_data [7] 0x40
cuda_delay_set_sr_int
cuda_data_recv recv: 0x01
cuda_delay_set_sr_int
cuda_data_recv recv: 0x00
cuda_delay_set_sr_int
cuda_data_recv recv: 0x25
cuda_delay_set_sr_int
cuda_data_recv recv: 0x04
cuda_delay_set_sr_int
cuda_data_recv recv: 0x0d
cuda_delay_set_sr_int
cuda_data_recv recv: 0x0a
cuda_delay_set_sr_int
cuda_data_recv recv: 0x02
cuda_delay_set_sr_int
cuda_data_recv recv: 0x40
cuda_delay_set_sr_int
cuda_delay_set_sr_int
cuda_delay_set_sr_int
cuda_delay_set_sr_int
cuda_data_send send: 0x01
cuda_delay_set_sr_int
cuda_data_send send: 0x25
cuda_delay_set_sr_int
cuda_data_send send: 0xa2
cuda_delay_set_sr_int
cuda_data_send send: 0x02
cuda_delay_set_sr_int
cuda_data_send send: 0xa3
cuda_delay_set_sr_int
cuda_delay_set_sr_int
cuda_packet_receive length 5
cuda_packet_receive_data [0] 0x01
cuda_packet_receive_data [1] 0x25
cuda_packet_receive_data [2] 0xa2
cuda_packet_receive_data [3] 0x02
cuda_packet_receive_data [4] 0xa3
cuda_receive_packet_cmd handling command COMBINED_FORMAT_IIC
CUDA: COMBINED_FORMAT_IIC: wrong parameters 4
[...]
pci_cfg_write grackle 00:0 @0x80 <- 0xffff8000
pci_cfg_write grackle 00:0 @0x88 <- 0xffff0000
pci_cfg_write grackle 00:0 @0x90 <- 0xffffff7f
pci_cfg_write grackle 00:0 @0x98 <- 0xffff0000

^^^ these were all 0xffffffff before

pci_cfg_write grackle 00:0 @0x84 <- 0xffffffff
pci_cfg_write grackle 00:0 @0x8c <- 0xffffffff
pci_cfg_write grackle 00:0 @0x94 <- 0xffffffff
pci_cfg_write grackle 00:0 @0x9c <- 0xffffffff
pci_cfg_write grackle 00:0 @0xa0 <- 0x3
pci_cfg_read grackle 00:0 @0xf0 -> 0x12900000
pci_cfg_write grackle 00:0 @0xf0 <- 0x12900005
pci_cfg_read grackle 00:0 @0x8 -> 0x6000140
pci_cfg_read grackle 00:0 @0xf0 -> 0x12900005
pci_cfg_write grackle 00:0 @0xf0 <- 0x12940005
pci_cfg_write grackle 00:0 @0xf0 <- 0x12940005
pci_cfg_write grackle 00:0 @0xf4 <- 0x40010fe4
pci_cfg_write grackle 00:0 @0xf8 <- 0x7302293
pci_cfg_write grackle 00:0 @0xfc <- 0x25302220
pci_cfg_read grackle 00:0 @0xa0 -> 0x3
pci_cfg_write grackle 00:0 @0xa0 <- 0x67000003
pci_cfg_read grackle 00:0 @0xf0 -> 0x12940005
pci_cfg_write grackle 00:0 @0xf0 <- 0x129c0005

In my understanding after an I2C command CUDA should enter in a mode 
whereby reading the SR reg will return bytes from the I2C device but not 
sure what terminates that mode and how to model it correctly so I just 
return the expected number of bytes in this patch to make the ROM go 
further so I can test what else is needed. Then it crashes in screamer.

  hw/misc/macio/cuda.c         | 76 +++++++++++++++++++++++++++++++++++-
  include/hw/misc/macio/cuda.h |  1 +
  2 files changed, 76 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index 5bbc7770fa..3fc9773717 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -28,6 +28,7 @@ 
  #include "hw/ppc/mac.h"
  #include "hw/qdev-properties.h"
  #include "migration/vmstate.h"
+#include "hw/i2c/i2c.h"
  #include "hw/input/adb.h"
  #include "hw/misc/mos6522.h"
  #include "hw/misc/macio/cuda.h"
@@ -370,6 +371,75 @@  static bool cuda_cmd_set_time(CUDAState *s,
      return true;
  }

+static bool cuda_cmd_get_set_iic(CUDAState *s,
+                                 const uint8_t *in_data, int in_len,
+                                 uint8_t *out_data, int *out_len)
+{
+    int i;
+
+    qemu_log_mask(LOG_UNIMP, "CUDA: unimplemented GET_SET_IIC %s 0x%x %d\n",
+                  (in_data[0] & 1 ? "read" : "write"), in_data[0] >> 1,
+                  in_len);
+    if (i2c_start_transfer(s->i2c_bus, in_data[0] >> 1, in_data[0] & 1)) {
+        return false;
+    }
+    for (i = 0; i < in_len - 3; i++) {
+        if (i2c_send(s->i2c_bus, in_data[i])) {
+            i2c_end_transfer(s->i2c_bus);
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool cuda_cmd_combined_iic(CUDAState *s,
+                                  const uint8_t *in_data, int in_len,
+                                  uint8_t *out_data, int *out_len)
+{
+    int i;
+
+    if (in_len < 3) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CUDA: COMBINED_FORMAT_IIC too few input bytes\n");
+        return false;
+    }
+    if ((in_data[0] & 0xfe) != (in_data[2] & 0xfe)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CUDA: COMBINED_FORMAT_IIC address mismatch\n");
+        return false;
+    }
+
+    uint8_t data = in_data[1];
+    if (i2c_start_transfer(s->i2c_bus, in_data[0] >> 1, in_data[0] & 1) ||
+        i2c_send_recv(s->i2c_bus, &data, in_data[0] & 1)) {
+        return false;
+    }
+    i2c_end_transfer(s->i2c_bus);
+    if (in_data[2] & 1) {
+        if (i2c_start_transfer(s->i2c_bus, in_data[2] >> 1, in_data[2] & 1)) {
+            i2c_end_transfer(s->i2c_bus);
+            return false;
+        }
+        for (i = 0; i < 5; i++) {
+            if (i2c_send_recv(s->i2c_bus, &out_data[i], in_data[2] & 1)) {
+                i2c_end_transfer(s->i2c_bus);
+                return false;
+            }
+        }
+        *out_len = i;
+        i2c_end_transfer(s->i2c_bus);
+    } else {
+        for (i = 0; i < in_len - 3; i++) {
+            data = in_data[3 + i];
+            if (i2c_send_recv(s->i2c_bus, &data, in_data[2] & 1)) {
+                i2c_end_transfer(s->i2c_bus);
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
  static const CudaCommand handlers[] = {
      { CUDA_AUTOPOLL, "AUTOPOLL", cuda_cmd_autopoll },
      { CUDA_SET_AUTO_RATE, "SET_AUTO_RATE",  cuda_cmd_set_autorate },
@@ -382,6 +452,8 @@  static const CudaCommand handlers[] = {
        cuda_cmd_set_power_message },
      { CUDA_GET_TIME, "GET_TIME", cuda_cmd_get_time },
      { CUDA_SET_TIME, "SET_TIME", cuda_cmd_set_time },
+    { CUDA_GET_SET_IIC, "GET_SET_IIC", cuda_cmd_get_set_iic },
+    { CUDA_COMBINED_FORMAT_IIC, "COMBINED_FORMAT_IIC", cuda_cmd_combined_iic },
  };

  static void cuda_receive_packet(CUDAState *s,
@@ -549,6 +621,7 @@  static void cuda_init(Object *obj)
  {
      CUDAState *s = CUDA(obj);
      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    DeviceState *dev = DEVICE(obj);

      object_initialize_child(obj, "mos6522-cuda", &s->mos6522_cuda,
                              TYPE_MOS6522_CUDA);
@@ -557,7 +630,8 @@  static void cuda_init(Object *obj)
      sysbus_init_mmio(sbd, &s->mem);

      qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
-                        DEVICE(obj), "adb.0");
+                        dev, "adb.0");
+    s->i2c_bus = i2c_init_bus(dev, "i2c");
  }

  static Property cuda_properties[] = {
diff --git a/include/hw/misc/macio/cuda.h b/include/hw/misc/macio/cuda.h
index a8cf0be1ec..6856ed7704 100644
--- a/include/hw/misc/macio/cuda.h
+++ b/include/hw/misc/macio/cuda.h
@@ -79,6 +79,7 @@  typedef struct CUDAState {

      ADBBusState adb_bus;
      MOS6522CUDAState mos6522_cuda;
+    I2CBus *i2c_bus;

      uint32_t tick_offset;
      uint64_t tb_frequency;