All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC
@ 2017-11-20  3:24 Michael Davidsaver
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 01/12] e500: add board config options Michael Davidsaver
                   ` (12 more replies)
  0 siblings, 13 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

This series adds simulation of MVME3100 powerpc SBCs, originally from Motorola,
and now sold by Artesyn[1].  There are two variants differing in CPU
speed and memory size.

I've been working on this sporadically for the past 2 year.  Recently I've
finished all the features which I have in mind.  If this series is accepted
there is a continuation which adds VME bus.  I've found it
useful in software compatibility testing.  I wonder if there is
any interest at large?


There are two main parts of this series.  1-5 are changing code common
with the "ppce500" and "mpc8544ds" boards, with the remainder being
additions.

The changes are to how the CCSR region is handled in order to support
the CCSRBAR register which allows the whole region to be relocated.
Also added are a couple of memory and clock configuration registers
which RTEMS guests read.

#3 is actually a minor issue I found recently with the mpc8544 PCI host bridge,
which I'm uncertain how to address.  The host bridge device 0:0 identifies
itself as a bridge, but doesn't properly implement the bridge config registers.
This confuses Linux, which then does a full re-enumeration (successfully).

The rest are additions of an I2C controller, an I2C eeprom, an I2C RTC,
and new board code.

My testing has been almost exclusively with an RTEMS guest[2].
Though I have recently done a little with Linux.

RTEMS guests (and Linux too for now) require a stub bootloader[3] to
put the system in the same state as the real bootloader.
RTEMS has an unfortunately strong dependence on bootloader
provided configuration (eg. it doesn't re-enumerate the PCI bus).


[1] https://www.artesyn.com/computing/products/product/mvme3100-vme-board-with-freescale-mpc8540-system-on-chip-processor

[2] https://www.rtems.org/

[3] https://github.com/mdavidsaver/qemu/wiki


Michael Davidsaver (12):
  e500: add board config options
  e500: consolidate mpc8540 guts with e500-ccsr
  e500: note possible bug with host bridge
  e500: additional CCSR registers
  e500: name openpic and pci host bridge
  i2c: add mpc8540 i2c controller
  qtest: add e500_i2c_create()
  e500: add mpc8540 i2c controller to ccsr
  nvram: add AT24Cx i2c eeprom
  timer: add ds1375 RTC
  ppc: add mvme3100 machine
  tests: add mvme3100-test

 default-configs/ppc-softmmu.mak |   1 +
 hw/i2c/Makefile.objs            |   1 +
 hw/i2c/mpc8540_i2c.c            | 287 +++++++++++++++++
 hw/nvram/Makefile.objs          |   1 +
 hw/nvram/eeprom_at24c.c         | 205 ++++++++++++
 hw/pci-host/ppce500.c           |  13 +-
 hw/ppc/Makefile.objs            |   4 +-
 hw/ppc/e500-ccsr.h              |  17 -
 hw/ppc/e500.c                   |  59 ++--
 hw/ppc/e500.h                   |   4 +
 hw/ppc/e500_ccsr.c              | 220 +++++++++++++
 hw/ppc/e500plat.c               |   2 +
 hw/ppc/mpc8544_guts.c           | 143 ---------
 hw/ppc/mpc8544ds.c              |   2 +
 hw/ppc/mvme3100.c               | 688 ++++++++++++++++++++++++++++++++++++++++
 hw/ppc/mvme3100_cpld.c          | 192 +++++++++++
 hw/timer/Makefile.objs          |   1 +
 hw/timer/ds1375-i2c.c           | 293 +++++++++++++++++
 tests/Makefile.include          |   4 +
 tests/libqos/i2c-e500.c         |  66 ++++
 tests/libqos/i2c.h              |   3 +
 tests/mvme3100-test.c           |  79 +++++
 22 files changed, 2083 insertions(+), 202 deletions(-)
 create mode 100644 hw/i2c/mpc8540_i2c.c
 create mode 100644 hw/nvram/eeprom_at24c.c
 delete mode 100644 hw/ppc/e500-ccsr.h
 create mode 100644 hw/ppc/e500_ccsr.c
 delete mode 100644 hw/ppc/mpc8544_guts.c
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c
 create mode 100644 hw/timer/ds1375-i2c.c
 create mode 100644 tests/libqos/i2c-e500.c
 create mode 100644 tests/mvme3100-test.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 01/12] e500: add board config options
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  3:28   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge Michael Davidsaver
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

allow board code to skip common NIC and guest image setup
and configure decrementor frequency.
Existing boards unchanged.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c      | 8 ++++++--
 hw/ppc/e500.h      | 3 +++
 hw/ppc/e500plat.c  | 1 +
 hw/ppc/mpc8544ds.c | 1 +
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 5cf0dabef3..9e7e1b29c4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -826,7 +826,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
         env->mpic_iack = params->ccsrbar_base +
                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
 
-        ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
+        ppc_booke_timers_init(cpu, params->decrementor_freq, PPC_TIMER_E500);
 
         /* Register reset handler */
         if (!i) {
@@ -899,7 +899,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     if (!pci_bus)
         printf("couldn't create PCI controller!\n");
 
-    if (pci_bus) {
+    if (pci_bus && !params->tsec_nic) {
         /* Register network interfaces. */
         for (i = 0; i < nb_nics; i++) {
             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
@@ -948,6 +948,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
                                     sysbus_mmio_get_region(s, 0));
     }
 
+    if (params->skip_load) {
+        return;
+    }
+
     /* Load kernel. */
     if (machine->kernel_filename) {
         kernel_base = cur_base;
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 70ba1d8f4f..40f72f2de2 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -22,6 +22,9 @@ typedef struct PPCE500Params {
     hwaddr pci_mmio_base;
     hwaddr pci_mmio_bus_base;
     hwaddr spin_base;
+    uint32_t decrementor_freq; /* in Hz */
+    bool skip_load;
+    bool tsec_nic;
 } PPCE500Params;
 
 void ppce500_init(MachineState *machine, PPCE500Params *params);
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index e59e80fb9e..3d07987bd1 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
         .pci_mmio_base = 0xC00000000ULL,
         .pci_mmio_bus_base = 0xE0000000ULL,
         .spin_base = 0xFEF000000ULL,
+        .decrementor_freq = 400000000,
     };
 
     /* Older KVM versions don't support EPR which breaks guests when we announce
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 1717953ec7..6d9931c475 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
         .pci_mmio_bus_base = 0xC0000000ULL,
         .pci_pio_base = 0xE1000000ULL,
         .spin_base = 0xEF000000ULL,
+        .decrementor_freq = 400000000,
     };
 
     if (machine->ram_size > 0xc0000000) {
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 01/12] e500: add board config options Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  3:46   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers Michael Davidsaver
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/pci-host/ppce500.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index f2d108bc8a..0e2833bd98 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -424,6 +424,9 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
     MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
 
     pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
+    /* BUG? identifies as PCI_HEADER_TYPE_BRIDGE but uses
+     * standard device config read/write
+     */
     d->config[PCI_HEADER_TYPE] =
         (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
         PCI_HEADER_TYPE_BRIDGE;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 01/12] e500: add board config options Michael Davidsaver
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  3:57   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge Michael Davidsaver
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Add CCSRBAR to allow CCSR region to be relocated.
Guest memory size introspection.
Dummy RAM error controls.
Guest clock introspection.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c      |  2 ++
 hw/ppc/e500.h      |  1 +
 hw/ppc/e500_ccsr.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 hw/ppc/e500plat.c  |  1 +
 hw/ppc/mpc8544ds.c |  1 +
 5 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 474a46a985..057be1751b 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -853,7 +853,9 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     dev = qdev_create(NULL, "e500-ccsr");
     object_property_add_child(qdev_get_machine(), "e500-ccsr",
                               OBJECT(dev), NULL);
+    qdev_prop_set_uint32(dev, "porpllsr", params->porpllsr);
     qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
+    qdev_prop_set_uint32(dev, "ram-size", ram_size);
     qdev_init_nofail(dev);
     ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 40f72f2de2..1f39095dfa 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -22,6 +22,7 @@ typedef struct PPCE500Params {
     hwaddr pci_mmio_base;
     hwaddr pci_mmio_bus_base;
     hwaddr spin_base;
+    uint32_t porpllsr; /* value of PORPLLSR register */
     uint32_t decrementor_freq; /* in Hz */
     bool skip_load;
     bool tsec_nic;
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index 1b586c3f42..c58b17f06b 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -31,6 +31,16 @@
 
 /* E500_ denotes registers common to all */
 
+#define E500_CCSRBAR     (0)
+
+#define E500_CS0_BNDS    (0x2000)
+
+#define E500_CS0_CONFIG  (0x2080)
+
+#define E500_ERR_DETECT  (0x2e40)
+#define E500_ERR_DISABLE (0x2e44)
+
+#define E500_PORPLLSR    (0xE0000)
 #define E500_PVR         (0xE00A0)
 #define E500_SVR         (0xE00A4)
 
@@ -44,7 +54,11 @@ typedef struct {
 
     MemoryRegion iomem;
 
-    uint32_t defbase;
+    uint32_t defbase, base;
+    uint32_t ram_size;
+    uint32_t merrd;
+
+    uint32_t porpllsr;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
@@ -53,10 +67,28 @@ typedef struct {
 static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
                                   unsigned size)
 {
+    CCSRState *ccsr = opaque;
     PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
     CPUPPCState *env = &cpu->env;
 
     switch (addr) {
+    case E500_CCSRBAR:
+        return ccsr->base >> 12;
+    case E500_CS0_BNDS:
+        /* we model all RAM in a single chip with addresses [0, ram_size) */
+        return (ccsr->ram_size - 1) >> 24;
+    case E500_CS0_CONFIG:
+        return 1 << 31;
+    case E500_ERR_DETECT:
+        return 0; /* (errors not modeled) */
+    case E500_ERR_DISABLE:
+        return ccsr->merrd;
+    case E500_PORPLLSR:
+        if (!ccsr->porpllsr) {
+            qemu_log_mask(LOG_UNIMP,
+                          "Machine does not provide valid PORPLLSR\n");
+        }
+        return ccsr->porpllsr;
     case E500_PVR:
         return env->spr[SPR_PVR];
     case E500_SVR:
@@ -72,10 +104,22 @@ static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
 static void e500_ccsr_write(void *opaque, hwaddr addr,
                                uint64_t value, unsigned size)
 {
+    CCSRState *ccsr = opaque;
     PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
     CPUPPCState *env = &cpu->env;
     uint32_t svr = env->spr[SPR_E500_SVR] >> 16;
 
+    switch (addr) {
+    case E500_CCSRBAR:
+        value &= 0x000fff00;
+        ccsr->base = value << 12;
+        sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
+        return;
+    case E500_ERR_DISABLE:
+        ccsr->merrd = value & 0xd;
+        return;
+    }
+
     switch (svr) {
     case 0: /* generic.  assumed to be mpc8544ds or e500plat board */
     case 0x8034: /* mpc8544 */
@@ -104,11 +148,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
     }
 };
 
+static int e500_ccsr_post_load(void *opaque, int version_id)
+{
+    CCSRState *ccsr = opaque;
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
+    return 0;
+}
+
 static void e500_ccsr_reset(DeviceState *dev)
 {
     CCSRState *ccsr = E500_CCSR(dev);
 
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ccsr->defbase);
+    ccsr->base = ccsr->defbase;
+    e500_ccsr_post_load(ccsr, 1);
 }
 
 static void e500_ccsr_initfn(Object *obj)
@@ -123,15 +176,30 @@ static void e500_ccsr_initfn(Object *obj)
 
 static Property e500_ccsr_props[] = {
     DEFINE_PROP_UINT32("base", CCSRState, defbase, 0xff700000),
+    DEFINE_PROP_UINT32("ram-size", CCSRState, ram_size, 0),
+    DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
     DEFINE_PROP_END_OF_LIST()
 };
 
+static const VMStateDescription vmstate_e500_ccsr = {
+    .name = TYPE_E500_CCSR,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = e500_ccsr_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(base, CCSRState),
+        VMSTATE_UINT32(merrd, CCSRState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static
 void e500_ccsr_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->props = e500_ccsr_props;
+    dc->vmsd = &vmstate_e500_ccsr;
     dc->reset = e500_ccsr_reset;
 }
 
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index 3d07987bd1..4e763d9c09 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
         .pci_mmio_base = 0xC00000000ULL,
         .pci_mmio_bus_base = 0xE0000000ULL,
         .spin_base = 0xFEF000000ULL,
+        .porpllsr = 0, /* TODO missing valid value */
         .decrementor_freq = 400000000,
     };
 
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 6d9931c475..f5e0042245 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
         .pci_mmio_bus_base = 0xC0000000ULL,
         .pci_pio_base = 0xE1000000ULL,
         .spin_base = 0xEF000000ULL,
+        .porpllsr = 0, /* TODO missing valid value */
         .decrementor_freq = 400000000,
     };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (2 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  3:58   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller Michael Davidsaver
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 057be1751b..6f77844303 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -685,6 +685,8 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
     int i, j, k;
 
     dev = qdev_create(NULL, TYPE_OPENPIC);
+    object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev),
+                              &error_fatal);
     qdev_prop_set_uint32(dev, "model", params->mpic_version);
     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
 
@@ -876,6 +878,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
 
     /* PCI */
     dev = qdev_create(NULL, "e500-pcihost");
+    object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
+                              &error_abort);
     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
     qdev_init_nofail(dev);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (3 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  4:06   ` David Gibson
  2017-11-23 15:39   ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 07/12] qtest: add e500_i2c_create() Michael Davidsaver
                   ` (7 subsequent siblings)
  12 siblings, 2 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/i2c/Makefile.objs |   1 +
 hw/i2c/mpc8540_i2c.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 288 insertions(+)
 create mode 100644 hw/i2c/mpc8540_i2c.c

diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 0594dea3ae..79af1dd901 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
 obj-$(CONFIG_OMAP) += omap_i2c.o
 obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
+obj-$(CONFIG_E500) += mpc8540_i2c.o
diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
new file mode 100644
index 0000000000..884052cc9b
--- /dev/null
+++ b/hw/i2c/mpc8540_i2c.c
@@ -0,0 +1,287 @@
+/*
+ * MPC8540 I2C bus interface
+ * As described in
+ * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
+ * Part 2 chapter 11
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_LVL 0 */
+
+#ifdef DEBUG_LVL
+#define DPRINTK(LVL, FMT, ...) do { if ((LVL) <= DEBUG_LVL) { \
+    printf(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); } } while (0)
+#else
+#define DPRINTK(LVL, FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
+    " : " FMT, ## __VA_ARGS__)
+
+#define TYPE_MPC8540_I2C "mpc8540-i2c"
+#define MPC8540_I2C(obj) OBJECT_CHECK(I2CState, (obj), TYPE_MPC8540_I2C)
+
+/* offsets relative to CCSR offset 0x3000 */
+#define R_I2CADR (0)
+#define R_I2CFDR (4)
+#define R_I2CCR  (8)
+#define R_I2CSR  (0xc)
+#define R_I2CDR  (0x10)
+#define R_I2CDFSRR (0x14)
+
+FIELD(I2CCR, MEN, 7, 1)
+FIELD(I2CCR, MIEN, 6, 1)
+FIELD(I2CCR, MSTA, 5, 1)
+FIELD(I2CCR, MTX, 4, 1)
+FIELD(I2CCR, TXAK, 3, 1)
+FIELD(I2CCR, RSTA, 2, 1)
+FIELD(I2CCR, BCST, 0, 1)
+
+FIELD(I2CSR, MCF, 7, 1)
+FIELD(I2CSR, MAAS, 6, 1)
+FIELD(I2CSR, MBB, 5, 1)
+FIELD(I2CSR, MAL, 4, 1)
+FIELD(I2CSR, BCSTM, 3, 1)
+FIELD(I2CSR, SRW, 2, 1)
+FIELD(I2CSR, MIF, 1, 1)
+FIELD(I2CSR, RXAK, 0, 1)
+
+typedef struct I2CState {
+    SysBusDevice parent_obj;
+
+    I2CBus *bus;
+
+    uint8_t ctrl, sts;
+    uint8_t freq, filt;
+    /* Reads are pipelined, this is the next data value */
+    uint8_t dbuf;
+
+    qemu_irq irq;
+
+    MemoryRegion mmio;
+} I2CState;
+
+#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
+#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
+
+#define I2CSR_SET(BIT, VAL) do {\
+        i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
+    } while (0)
+
+static
+void mpc8540_update_irq(I2CState *i2c)
+{
+    int ena = i2c->ctrl & 0x40,
+        sts = i2c->sts & 0x02,
+        act = !!(ena && sts);
+
+    DPRINTK(1, "IRQ %c ena %c sts %c\n",
+            act ? 'X' : '_',
+            ena ? 'X' : '_',
+            sts ? 'X' : '_');
+
+    qemu_set_irq(i2c->irq, act);
+}
+
+static
+uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+    I2CState *i2c = opaque;
+    uint32_t val, offset = addr;
+
+    switch (offset) {
+    case R_I2CADR: /* ADDR */
+        val = 0;
+        break;
+    case R_I2CFDR: /* Freq Div. */
+        val = i2c->freq;
+        break;
+    case R_I2CCR: /* CONTROL */
+        val = i2c->ctrl & ~0x06;
+        break;
+    case R_I2CSR: /* STATUS */
+        val = i2c->sts;
+        break;
+    case R_I2CDR: /* DATA */
+        /* Reads are "pipelined" and so return the previous value of the
+         * register
+         */
+        val = i2c->dbuf;
+        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
+            if (!i2c_bus_busy(i2c->bus) || I2CCR(MTX)) {
+                LOG(LOG_GUEST_ERROR, "Read during addr or tx\n");
+                i2c->dbuf = 0xff;
+            } else {
+                int ret = i2c_recv(i2c->bus);
+                i2c->dbuf = (uint8_t)ret;
+                DPRINTK(0, "READ %02x ('%c')\n", i2c->dbuf, (char)i2c->dbuf);
+                I2CSR_SET(MIF, 1);
+                I2CSR_SET(RXAK, 0);
+                mpc8540_update_irq(i2c);
+            }
+        } else {
+            i2c->dbuf = 0xff;
+            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy\n");
+        }
+        break;
+    case R_I2CDFSRR: /* FILTER */
+        val = i2c->filt;
+        break;
+    default:
+        val = 0xff;
+    }
+
+    DPRINTK(offset == 0xc ? 2 : 1, " read %08x -> %08x\n",
+            (unsigned)offset, (unsigned)val);
+    return val;
+}
+
+static
+void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    I2CState *i2c = opaque;
+    uint32_t offset = addr;
+
+    DPRINTK(1, " write %08x <- %08x\n", (unsigned)offset, (unsigned)val);
+
+    switch (offset) {
+    case R_I2CADR: /* ADDR */
+        break;
+    case R_I2CFDR: /* Freq Div. */
+        i2c->freq = val & 0x3f;
+        break;
+    case R_I2CCR: /* CONTROL CCR */
+        if (!FIELD_EX32(val, I2CCR, MEN)) {
+            DPRINTK(0, "Not Enabled\n");
+
+        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
+            /* MSTA 0 -> 1 is START */
+
+            I2CSR_SET(MBB, 1);
+            DPRINTK(0, "START\n");
+            i2c_end_transfer(i2c->bus); /* paranoia */
+
+        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
+            /* MSTA 1 -> 0 is STOP */
+
+            I2CSR_SET(MBB, 0);
+            DPRINTK(0, "STOP\n");
+            i2c_end_transfer(i2c->bus);
+
+        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
+            i2c_end_transfer(i2c->bus);
+            I2CSR_SET(MBB, 1);
+            DPRINTK(0, "REP START\n");
+
+        }
+        /* RSTA always reads zero, bit 1 unusd */
+        val &= 0xf9;
+        i2c->ctrl = val;
+        mpc8540_update_irq(i2c);
+        break;
+    case R_I2CSR: /* STATUS CSR */
+        /* only MAL and MIF are writable */
+        val &= 0x12;
+        i2c->sts &= ~0x12;
+        i2c->sts |= val;
+        mpc8540_update_irq(i2c);
+        break;
+    case R_I2CDR: /* DATA CDR */
+        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
+            if (!i2c_bus_busy(i2c->bus)) {
+                if (i2c_start_transfer(i2c->bus, val >> 1, val & 1)) {
+                    LOG(LOG_GUEST_ERROR, "I2C no device %02x\n",
+                        (unsigned)(val & 0xfe));
+                } else {
+                    DPRINTK(0, "ADDR %02x\n", (unsigned)(val & 0xfe));
+                }
+                I2CSR_SET(MIF, 1);
+                I2CSR_SET(RXAK, 0);
+
+            } else if (I2CCR(MTX)) {
+                DPRINTK(0, "WRITE %02x\n", (unsigned)val);
+                i2c_send(i2c->bus, val);
+                I2CSR_SET(MIF, 1);
+                I2CSR_SET(RXAK, 0);
+            } else {
+                LOG(LOG_GUEST_ERROR, "I2CDR Write during read\n");
+            }
+            mpc8540_update_irq(i2c);
+        } else {
+            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy\n");
+        }
+        break;
+    case R_I2CDFSRR: /* FILTER */
+        val &= 0x3f;
+        i2c->filt = val;
+        break;
+    }
+
+    DPRINTK(1, "I2CCR = %02x I2SCR = %02x\n", i2c->ctrl, i2c->sts);
+}
+
+static const MemoryRegionOps i2c_ops = {
+    .read = mpc8540_i2c_read,
+    .write = mpc8540_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static
+void mpc8540_i2c_reset(DeviceState *dev)
+{
+    I2CState *i2c = MPC8540_I2C(dev);
+
+    i2c->sts = 0x81; /* transfer complete and ack received */
+}
+
+static int mpc8540_i2c_inst_init(SysBusDevice *dev)
+{
+    I2CState *i2c = MPC8540_I2C(dev);
+
+    i2c->bus = i2c_init_bus(&dev->parent_obj, "bus");
+
+    memory_region_init_io(&i2c->mmio, &dev->parent_obj.parent_obj,
+                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
+
+    sysbus_init_mmio(dev, &i2c->mmio);
+    sysbus_init_irq(dev, &i2c->irq);
+    return 0;
+}
+
+static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = &mpc8540_i2c_inst_init;
+    dc->reset = &mpc8540_i2c_reset;
+}
+
+static const TypeInfo mpc8540_i2c_type = {
+    .name = TYPE_MPC8540_I2C,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(I2CState),
+    .class_size = sizeof(SysBusDeviceClass),
+    .class_init = mpc8540_i2c_class_init,
+};
+
+static void mpc8540_i2c_register(void)
+{
+    type_register_static(&mpc8540_i2c_type);
+}
+
+type_init(mpc8540_i2c_register)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 07/12] qtest: add e500_i2c_create()
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (4 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr Michael Davidsaver
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Add interface for testing i2c devices
with PPC e500.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 tests/Makefile.include  |  1 +
 tests/libqos/i2c-e500.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/i2c.h      |  3 +++
 3 files changed, 70 insertions(+)
 create mode 100644 tests/libqos/i2c-e500.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index c002352134..ad1c219423 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -721,6 +721,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
 libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
+libqos-e500-obj-y = $(libqos-obj-y) tests/libqos/i2c-e500.o
 libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
 
diff --git a/tests/libqos/i2c-e500.c b/tests/libqos/i2c-e500.c
new file mode 100644
index 0000000000..4272ada0a5
--- /dev/null
+++ b/tests/libqos/i2c-e500.c
@@ -0,0 +1,66 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2016 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "libqos/i2c.h"
+
+
+#include "qemu/bswap.h"
+#include "libqtest.h"
+
+typedef struct E500I2C {
+    I2CAdapter parent;
+
+    uint64_t addr;
+} E500I2C;
+
+static void e500_i2c_send(I2CAdapter *i2c, uint8_t addr,
+                          const uint8_t *buf, uint16_t len)
+{
+    E500I2C *s = (E500I2C *)i2c;
+
+    writeb(s->addr + 0x8, 0xb0); /* Enable and START a write */
+    writeb(s->addr + 0x10, addr & 0xfe); /* Send address for write */
+
+    while (len--) {
+        writeb(s->addr + 0x10, *buf++);
+    }
+
+    writeb(s->addr + 0x8, 0x80); /* STOP but leave enabled */
+}
+
+static void e500_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+                          uint8_t *buf, uint16_t len)
+{
+    E500I2C *s = (E500I2C *)i2c;
+
+    writeb(s->addr + 0x8, 0xa0); /* Enable and START a read */
+    writeb(s->addr + 0x10, addr | 1); /* Send address for read */
+
+    /* reads are "pipelined" so the initial value is junk */
+    readb(s->addr + 0x10);
+
+    while (len--) {
+        *buf++ = readb(s->addr + 0x10);
+    }
+
+    writeb(s->addr + 0x8, 0x80); /* STOP but leave enabled */
+}
+
+I2CAdapter *e500_i2c_create(uint64_t ccsr_base)
+{
+    E500I2C *s = g_malloc0(sizeof(*s));
+    I2CAdapter *i2c = (I2CAdapter *)s;
+
+    s->addr = ccsr_base + 0x3000;
+
+    i2c->send = e500_i2c_send;
+    i2c->recv = e500_i2c_recv;
+
+    return i2c;
+}
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 6e648f922a..40c59a7997 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -29,4 +29,7 @@ I2CAdapter *omap_i2c_create(uint64_t addr);
 /* libi2c-imx.c */
 I2CAdapter *imx_i2c_create(uint64_t addr);
 
+/* i2c-e500.c */
+I2CAdapter *e500_i2c_create(uint64_t ccsr_base);
+
 #endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (5 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 07/12] qtest: add e500_i2c_create() Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  4:08   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom Michael Davidsaver
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 6f77844303..bef7d313d4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -861,6 +861,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     qdev_init_nofail(dev);
     ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
+    dev = qdev_create(NULL, "mpc8540-i2c");
+    object_property_add_child(qdev_get_machine(), "i2c[*]",
+                              OBJECT(dev), NULL);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    memory_region_add_subregion(ccsr_addr_space, 0x3000,
+                                sysbus_mmio_get_region(s, 0));
+
     mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
 
     /* Serial */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (6 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  4:10   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC Michael Davidsaver
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/nvram/Makefile.objs  |   1 +
 hw/nvram/eeprom_at24c.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 206 insertions(+)
 create mode 100644 hw/nvram/eeprom_at24c.c

diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
index c018f6b2ff..0f4ee71dcb 100644
--- a/hw/nvram/Makefile.objs
+++ b/hw/nvram/Makefile.objs
@@ -1,5 +1,6 @@
 common-obj-$(CONFIG_DS1225Y) += ds1225y.o
 common-obj-y += eeprom93xx.o
+common-obj-y += eeprom_at24c.o
 common-obj-y += fw_cfg.o
 common-obj-y += chrp_nvram.o
 common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
new file mode 100644
index 0000000000..efa3621ac6
--- /dev/null
+++ b/hw/nvram/eeprom_at24c.c
@@ -0,0 +1,205 @@
+/*
+ * *AT24C* series I2C EEPROM
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+
+#include <string.h>
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "sysemu/block-backend.h"
+
+/* #define DEBUG_AT24C */
+
+#ifdef DEBUG_AT24C
+#define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
+                            ## __VA_ARGS__)
+
+#define TYPE_AT24C_EE "at24c-eeprom"
+#define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE)
+
+typedef struct EEPROMState {
+    I2CSlave parent_obj;
+
+    /* address counter */
+    uint16_t cur;
+    /* total size in bytes */
+    uint32_t rsize;
+    bool writable;
+    /* cells changed since last START? */
+    bool changed;
+    /* during WRITE, # of address bytes transfered */
+    uint8_t haveaddr;
+
+    uint8_t *mem;
+
+    BlockBackend *blk;
+} EEPROMState;
+
+static
+int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
+{
+    EEPROMState *ee = container_of(s, EEPROMState, parent_obj);
+
+    switch (event) {
+    case I2C_START_SEND:
+    case I2C_START_RECV:
+    case I2C_FINISH:
+        ee->haveaddr = 0;
+        DPRINTK("clear\n");
+        if (ee->blk && ee->changed) {
+            int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0);
+            if (len != ee->rsize) {
+                ERR(TYPE_AT24C_EE
+                        " : failed to write backing file\n");
+            }
+            DPRINTK("Wrote to backing file\n");
+        }
+        ee->changed = false;
+        break;
+    case I2C_NACK:
+        break;
+    }
+    return 0;
+}
+
+static
+int at24c_eeprom_recv(I2CSlave *s)
+{
+    EEPROMState *ee = AT24C_EE(s);
+    int ret;
+
+    ret = ee->mem[ee->cur];
+
+    ee->cur = (ee->cur + 1u) % ee->rsize;
+    DPRINTK("Recv %02x %c\n", ret, ret);
+
+    return ret;
+}
+
+static
+int at24c_eeprom_send(I2CSlave *s, uint8_t data)
+{
+    EEPROMState *ee = AT24C_EE(s);
+
+    if (ee->haveaddr < 2) {
+        ee->cur <<= 8;
+        ee->cur |= data;
+        ee->haveaddr++;
+        if (ee->haveaddr == 2) {
+            ee->cur %= ee->rsize;
+            DPRINTK("Set pointer %04x\n", ee->cur);
+        }
+
+    } else {
+        if (ee->writable) {
+            DPRINTK("Send %02x\n", data);
+            ee->mem[ee->cur] = data;
+            ee->changed = true;
+        } else {
+            DPRINTK("Send error %02x read-only\n", data);
+        }
+        ee->cur = (ee->cur + 1u) % ee->rsize;
+
+    }
+
+    return 0;
+}
+
+static
+int at24c_eeprom_init(I2CSlave *i2c)
+{
+    EEPROMState *ee = AT24C_EE(i2c);
+
+    ee->mem = g_malloc0(ee->rsize);
+
+    if (ee->blk) {
+        int64_t len = blk_getlength(ee->blk);
+
+        if (len != ee->rsize) {
+            ERR(TYPE_AT24C_EE " : Backing file size %lu != %u\n",
+                    (unsigned long)len, (unsigned)ee->rsize);
+            exit(1);
+        }
+
+        if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+                         BLK_PERM_ALL, &error_fatal) < 0)
+        {
+            ERR(TYPE_AT24C_EE
+                    " : Backing file incorrect permission\n");
+            exit(1);
+        }
+    }
+    return 0;
+}
+
+static
+void at24c_eeprom_reset(DeviceState *state)
+{
+    EEPROMState *ee = AT24C_EE(state);
+
+    ee->changed = false;
+    ee->cur = 0;
+    ee->haveaddr = 0;
+
+    memset(ee->mem, 0, ee->rsize);
+
+    if (ee->blk) {
+        int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize);
+
+        if (len != ee->rsize) {
+            ERR(TYPE_AT24C_EE
+                    " : Failed initial sync with backing file\n");
+        }
+        DPRINTK("Reset read backing file\n");
+    }
+}
+
+static Property at24c_eeprom_props[] = {
+    DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0),
+    DEFINE_PROP_BOOL("writable", EEPROMState, writable, true),
+    DEFINE_PROP_DRIVE("drive", EEPROMState, blk),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static
+void at24c_eeprom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = &at24c_eeprom_init;
+    k->event = &at24c_eeprom_event;
+    k->recv = &at24c_eeprom_recv;
+    k->send = &at24c_eeprom_send;
+
+    dc->props = at24c_eeprom_props;
+    dc->reset = at24c_eeprom_reset;
+}
+
+static
+const TypeInfo at24c_eeprom_type = {
+    .name = TYPE_AT24C_EE,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(EEPROMState),
+    .class_size = sizeof(I2CSlaveClass),
+    .class_init = at24c_eeprom_class_init,
+};
+
+static void at24c_eeprom_register(void)
+{
+    type_register_static(&at24c_eeprom_type);
+}
+
+type_init(at24c_eeprom_register)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (7 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-22  4:11   ` David Gibson
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 11/12] ppc: add mvme3100 machine Michael Davidsaver
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

only basic functionality implemented (read time and sram).
no set time or alarms.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 default-configs/ppc-softmmu.mak |   1 +
 hw/timer/Makefile.objs          |   1 +
 hw/timer/ds1375-i2c.c           | 293 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 295 insertions(+)
 create mode 100644 hw/timer/ds1375-i2c.c

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index bb225c6e46..04bfa79154 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -52,3 +52,4 @@ CONFIG_SERIAL_ISA=y
 CONFIG_MC146818RTC=y
 CONFIG_ISA_TESTDEV=y
 CONFIG_RS6000_MC=y
+CONFIG_DS1375=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8c19eac3b6..6521d47367 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -4,6 +4,7 @@ common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
 common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DS1375) += ds1375-i2c.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M48T59) += m48t59.o
diff --git a/hw/timer/ds1375-i2c.c b/hw/timer/ds1375-i2c.c
new file mode 100644
index 0000000000..dba9cc05c4
--- /dev/null
+++ b/hw/timer/ds1375-i2c.c
@@ -0,0 +1,293 @@
+/*
+ * Dallas/Maxim ds1375 I2C RTC w/ SRAM
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * Only basic functionality is modeled (time and user SRAM).
+ * Alarms not modeled.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "qemu/bcd.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+
+#define DEBUG_DS1375
+
+#ifdef DEBUG_DS1375
+#define DPRINTK(FMT, ...) printf(TYPE_DS1375 " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DS1375 " : " FMT, \
+                            ## __VA_ARGS__)
+
+#define TYPE_DS1375 "ds1375"
+#define DS1375(obj) OBJECT_CHECK(DS1375State, (obj), TYPE_DS1375)
+
+#define DS1375_REGSIZE 0x20
+
+#define R_SEC   (0x0)
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+#define R_WDAY  (0x3)
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+#define R_YEAR  (0x6)
+#define R_A1SEC   (0x7)
+#define R_A1MIN   (0x8)
+#define R_A1HOUR  (0x9)
+#define R_A1DAY   (0xa)
+#define R_A2SEC   (0xb)
+#define R_A2MIN   (0xc)
+#define R_A2HOUR  (0xd)
+#define R_CTRL  (0xe)
+#define R_STS   (0xf)
+
+FIELD(HOUR, SET12, 6, 1)
+FIELD(HOUR, HOUR24, 0, 6)
+FIELD(HOUR, AMPM, 5, 1)
+FIELD(HOUR, HOUR12, 0, 5)
+
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+FIELD(CTRL, ECLK, 7, 1)
+FIELD(CTRL, CLKSEL, 5, 2)
+FIELD(CTRL, RS, 3, 2)
+FIELD(CTRL, INTCN, 2, 1)
+FIELD(CTRL, A2IE, 1, 1)
+FIELD(CTRL, A1IE, 0, 1)
+
+typedef struct DS1375State {
+    I2CSlave parent_obj;
+
+    /* register address counter */
+    uint8_t addr;
+    /* when writing, whether the address has been sent */
+    bool addrd;
+
+    int time_offset;
+
+    uint8_t regs[DS1375_REGSIZE];
+} DS1375State;
+
+/* update current time register if clock enabled */
+static
+void ds1375_latch(DS1375State *ds)
+{
+    struct tm now;
+
+    if (!ARRAY_FIELD_EX32(ds->regs, CTRL, ECLK)) {
+        return;
+    }
+
+    qemu_get_timedate(&now, ds->time_offset);
+
+    DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)\n",
+            now.tm_year, now.tm_mon, now.tm_mday,
+            now.tm_hour, now.tm_min, now.tm_sec,
+            now.tm_wday);
+
+    /* ensure unused bits are zero */
+    memset(ds->regs, 0, R_YEAR + 1);
+
+    ds->regs[R_SEC] = to_bcd(now.tm_sec);
+    ds->regs[R_MIN] = to_bcd(now.tm_min);
+
+    if (ARRAY_FIELD_EX32(ds->regs, HOUR, SET12) == 0) {
+        /* 24 hour */
+        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour));
+    } else {
+        /* 12 hour am/pm */
+        ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12);
+        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12, to_bcd(now.tm_hour % 12u));
+    }
+
+    ds->regs[R_WDAY] = now.tm_wday; /* day of the week */
+    ds->regs[R_DATE] = to_bcd(now.tm_mday);
+
+    ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1));
+    ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year > 99);
+
+    ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+    DPRINTK("Latched time\n");
+}
+
+static
+void ds1375_update(DS1375State *ds)
+{
+    struct tm now;
+
+    now.tm_sec = from_bcd(ds->regs[R_SEC]);
+    now.tm_min = from_bcd(ds->regs[R_MIN]);
+
+    if (ARRAY_FIELD_EX32(ds->regs, HOUR, SET12)) {
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR12));
+        if (ARRAY_FIELD_EX32(ds->regs, HOUR, AMPM)) {
+            now.tm_hour += 12;
+        }
+
+    } else {
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR24));
+    }
+
+    now.tm_wday = from_bcd(ds->regs[R_WDAY]);
+    now.tm_mday = from_bcd(ds->regs[R_DATE]);
+    now.tm_mon = from_bcd(ARRAY_FIELD_EX32(ds->regs, MONTH, MONTH)) - 1;
+
+    now.tm_year = from_bcd(ds->regs[R_YEAR]) % 100u;
+    if (ARRAY_FIELD_EX32(ds->regs, MONTH, CENTURY)) {
+        now.tm_year += 100;
+    }
+
+    DPRINTK("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)\n",
+            now.tm_year, now.tm_mon, now.tm_mday,
+            now.tm_hour, now.tm_min, now.tm_sec,
+            now.tm_wday);
+
+    ds->time_offset = qemu_timedate_diff(&now);
+    DPRINTK("Update offset = %d\n", ds->time_offset);
+}
+
+static
+int ds1375_event(I2CSlave *s, enum i2c_event event)
+{
+    DS1375State *ds = container_of(s, DS1375State, parent_obj);
+
+    switch (event) {
+    case I2C_START_SEND:
+        ds->addrd = false;
+    case I2C_START_RECV:
+        ds1375_latch(ds);
+    case I2C_FINISH:
+        DPRINTK("Event %d\n", (int)event);
+    case I2C_NACK:
+        break;
+    }
+    return 0;
+}
+
+static
+int ds1375_recv(I2CSlave *s)
+{
+    DS1375State *ds = container_of(s, DS1375State, parent_obj);
+    int ret = 0;
+
+    switch (ds->addr) {
+    case R_SEC ... R_YEAR:
+    case R_CTRL:
+    case R_STS:
+    case 0x10 ... 0x1f:
+        ret = ds->regs[ds->addr];
+        break;
+    default:
+        LOG(LOG_UNIMP, "Read from unimplemented (%02x) %02x\n", ds->addr, ret);
+    }
+
+    DPRINTK("Recv (%02x) %02x\n", ds->addr, ret);
+
+    ds->addr++;
+    ds->addr &= 0x1f;
+    if (ds->addr == 0) {
+        ds1375_latch(ds);
+    }
+
+    return ret;
+}
+
+static
+int ds1375_send(I2CSlave *s, uint8_t data)
+{
+    DS1375State *ds = container_of(s, DS1375State, parent_obj);
+
+    if (!ds->addrd) {
+        data &= 0x1f;
+        ds->addr = data;
+        DPRINTK("Set address pointer %02x\n", data);
+        ds->addrd = true;
+        return 0;
+
+    } else {
+        DPRINTK("Send (%02x) %02x\n", ds->addr, data);
+        switch (ds->addr) {
+        case R_SEC ... R_YEAR:
+            ds->regs[ds->addr] = data;
+            ds1375_update(ds);
+            break;
+        case R_CTRL:
+            if (data & 0x7) {
+                LOG(LOG_UNIMP, "Alarm interrupt/output not modeled\n");
+            }
+            ds->regs[ds->addr] = data;
+            break;
+        case 0x10 ... 0x1f:
+            ds->regs[ds->addr] = data;
+            break;
+        default:
+            LOG(LOG_UNIMP, "Write to unimplemented (%02x) %02x\n",
+                ds->addr, data);
+        }
+
+        ds->addr++;
+        ds->addr &= 0x1f;
+        if (ds->addr == 0) {
+            ds1375_latch(ds);
+        }
+
+        return 0;
+    }
+}
+
+static
+void ds1375_reset(DeviceState *device)
+{
+    DS1375State *ds = DS1375(device);
+
+    memset(ds->regs, 0, sizeof(ds->regs));
+    /* TODO: not clear SRAM? */
+
+    /* Default to 12-hour mode */
+    ARRAY_FIELD_DP32(ds->regs, CTRL, ECLK, 1);
+
+    ds->addr = 0;
+
+    /* do not re-zero time offset */
+}
+
+static
+void ds1375_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->event = &ds1375_event;
+    k->recv = &ds1375_recv;
+    k->send = &ds1375_send;
+
+    dc->reset = &ds1375_reset;
+}
+
+static
+const TypeInfo ds1375_type = {
+    .name = TYPE_DS1375,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(DS1375State),
+    .class_size = sizeof(I2CSlaveClass),
+    .class_init = ds1375_class_init,
+};
+
+static void ds1375_register(void)
+{
+    type_register_static(&ds1375_type);
+}
+
+type_init(ds1375_register)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 11/12] ppc: add mvme3100 machine
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (8 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 12/12] tests: add mvme3100-test Michael Davidsaver
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/Makefile.objs   |   1 +
 hw/ppc/mvme3100.c      | 688 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ppc/mvme3100_cpld.c | 192 ++++++++++++++
 3 files changed, 881 insertions(+)
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c

diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index c1a63d0c39..c1118aaa42 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -26,5 +26,6 @@ obj-$(CONFIG_MAC) += mac_newworld.o
 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
 obj-$(CONFIG_E500) += ppce500_spin.o
 obj-$(CONFIG_E500) += e500_ccsr.o
+obj-$(CONFIG_E500) += mvme3100.o mvme3100_cpld.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-$(CONFIG_XILINX) += virtex_ml507.o
diff --git a/hw/ppc/mvme3100.c b/hw/ppc/mvme3100.c
new file mode 100644
index 0000000000..2e6d428533
--- /dev/null
+++ b/hw/ppc/mvme3100.c
@@ -0,0 +1,688 @@
+/*
+ * MVME3100 board emulation
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * This model was developed according to the
+ * MVME3100 Single Board Computer Programmer's Reference
+ * P/N: 6806800G37B
+ * July 2014
+ *
+ * mvme3100-1152
+ *   677MHz core, 256MB ram, 64MB flash
+ * mvme3100-1263
+ *   833MHz core, 512MB ram, 128MB flash
+ *
+ * MOTLoad on mvme3100-1152 says:
+ *   MPU-Type             =MPC8540
+ *   MPU-Int Clock Speed  =666MHz
+ *   MPU-CCB Clock Speed  =333MHz
+ *   MPU-DDR Clock Speed  =166MHz
+ *   MPU-PCI Clock Speed  =66MHz, PCI, 64-bit
+ *   MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ *   Reset/Boot Vector    =Flash0
+ *   Local Memory Found   =10000000 (&268435456)
+ *
+ * MOTLoad on mvme3100-1263 says:
+ *   MPU-Type             =MPC8540
+ *   MPU-Int Clock Speed  =833MHz
+ *   MPU-CCB Clock Speed  =333MHz
+ *   MPU-DDR Clock Speed  =166MHz
+ *   MPU-PCI Clock Speed  =66MHz, PCI, 64-bit
+ *   MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ *   Reset/Boot Vector    =Flash0
+ *   Local Memory Found   =20000000 (&536870912)
+ *
+ * Clock ratios
+ *   CCB/PCI  -> 5/1
+ *   core/CCB -> 2/1 (-1152)
+ *            -> 5/2 (-1263)
+ *
+ * The overall memory map is determined by the Local Address Windows.
+ * We do not model the LAWs explicitly.
+ *
+ * MOTLoad configures as follows (a super set of table 1-4)
+ *   (MOTLoad RTOS Version 2.0,  PAL Version 1.2 RM04)
+ * LAW 0, 7 - disabled
+ * LAW 1 - 0x00000000 -> 0x7fffffff - RAM 2G
+ * LAW 2 - 0x80000000 -> 0xbfffffff - PCI 1G
+ * LAW 3 - 0xc0000000 -> 0xdfffffff - PCI 512MB
+ * LAW 4 - 0xe0000000 -> 0xe0ffffff - PCI 16MB
+ * gap   - 0xe1000000 -> 0xbfffffff - CCSR @ 0xe1000000
+ * LAW 5 - 0xe2000000 -> 0xe2ffffff - LBC 16MB
+ * gap   - 0xe3000000 -> 0xefffffff
+ * LAW 6 - 0xf0000000 -> 0xffffffff - LBC 256MB
+ *
+ * And validated against the RTEMS 4.9.6 mvme3100 BSP
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "e500.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "cpu-qom.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "hw/pci/pci.h"
+#include "hw/boards.h"
+#include "hw/ppc/ppc.h"
+#include "hw/net/fsl_etsec/etsec.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/qtest.h"
+#include "hw/ppc/openpic.h"
+#include "qemu/error-report.h"
+
+/* Same as prep.c and other PPC boards */
+#define CFG_ADDR 0xf0000510
+
+#define TYPE_MVME3100 MACHINE_TYPE_NAME("mvme3100")
+#define MVME3100(obj) OBJECT_CHECK(MVME3100State, (obj), TYPE_MVME3100)
+#define MVME3100_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(MVME3100Class, (obj), TYPE_MVME3100)
+#define MVME3100_CLASS(klass) \
+    OBJECT_CLASS_CHECK(MVME3100Class, (klass), TYPE_MVME3100)
+
+
+typedef struct mvme3100_info {
+    const char *desc;
+    uint32_t cpu_freq;
+    uint32_t porpllsr;
+    uint32_t ram_size;
+} mvme3100_info;
+
+typedef struct MVME3100Class {
+    /*< private >*/
+    MachineClass parent_class;
+    /*< public >*/
+
+    const mvme3100_info *info;
+} MVME3100Class;
+
+typedef struct MVME3100State {
+    /*< private >*/
+    MachineState parent_obj;
+    /*< public >*/
+
+    uint32_t load_address,
+             entry_address;
+} MVME3100State;
+
+
+/* motload "global environment" variables */
+static
+const char *gev[] = {
+        /* TODO: somehow snoop in slirp_instances to pick up IP config? */
+        "mot-/dev/enet0-cipa=10.0.2.15",
+        "mot-/dev/enet0-gipa=10.0.2.2",
+        "mot-/dev/enet0-snma=255.255.255.0",
+        "mot-/dev/enet0-sipa=10.0.2.2",
+        /* RTEMS specific names for things motload doesn't have */
+        "rtems-dns-server=10.0.2.3",
+        "rtems-client-name=qemu",
+        NULL,
+};
+
+/* Prepare Motorola Vital Product Data eeprom image.
+ * Provided to bootloader for use as a default.
+ *
+ * Begins with constant "MOTLOAD" followed by variable length records
+ * with a two byte header (ID code then body length in bytes).
+ *
+ * | ID | Length | body .... | repeated until ID=0xFF
+ *
+ * ID Codes:
+ *  1 - Product ID (string)
+ *  2 - Assembly # (string)
+ *  3 - Serial # (string)
+ *  5 - CPU Speed (Hz, 4 byte integer + 1 nil)
+ *  6 - Bus Speed (Hz, 4 byte integer + 1 nil)
+ *  8 - Ethernet MAC (6 bytes + 1 nil)
+ *  9 - CPU type
+ *  A - VPD CRC (4 bytes)
+ *  B - Flash Config (??)
+ *  E - L2 Cache Config (??)
+ *  F - VPD Version (4 bytes)
+ * 19 - L3 Cache Config (??)
+ * FF - End of VPD (size zero)
+ *
+ * Repeat entries for repeated units.  eg. two ID=0x8 for two NICs
+ *
+ * MOTLoad uses the same eeprom to hold it's user configuration
+ * Global Environment Variable (GEV) list.
+ */
+typedef struct vpdeeprom {
+    char * const base;
+    char *cur;
+    size_t total;
+} vpdeeprom;
+
+static
+void append_gev_vpd(vpdeeprom *vpd, const char *str)
+{
+    const size_t remaining = vpd->total - (vpd->cur - vpd->base),
+                 len = strlen(str);
+
+    if ((len == 0 && remaining < 1)
+            || (remaining < len + 2))
+    {
+        fprintf(stderr, "VPD GEV overflow\n");
+        return;
+    }
+
+    memcpy(vpd->cur, str, len + 1);
+
+    vpd->cur += len + 1;
+}
+
+static
+void append_vpd(vpdeeprom *vpd, uint8_t id, size_t cnt, const void *val)
+{
+    const size_t remaining = vpd->total - (vpd->cur - vpd->base);
+
+    /* must have enough space for this entry and final ID=0xff */
+    if ((id == 0xff && remaining < 2)
+            || (remaining + 4 < cnt || cnt > 255))
+    {
+        fprintf(stderr, "VPD overflow\n");
+        return;
+    }
+
+    vpd->cur[0] = id;
+    vpd->cur[1] = cnt;
+    memcpy(vpd->cur + 2, val, cnt);
+
+    vpd->cur += 2 + cnt;
+}
+
+static
+void append_string_vpd(vpdeeprom *vpd, uint8_t id, const char *str)
+{
+    /* include trailing nil */
+    append_vpd(vpd, id, strlen(str) + 1, str);
+}
+
+static
+void append_mac_vpd(vpdeeprom *vpd, uint8_t id, const MACAddr *addr)
+{
+    char buf[7];
+    memcpy(buf, addr->a, 6);
+    buf[6] = 0;
+
+    append_vpd(vpd, id, 7, buf);
+}
+
+static
+void append_u32_vpd(vpdeeprom *vpd, uint8_t id, uint32_t val)
+{
+    union {
+        uint32_t ival;
+        char bytes[5]; /* include trailing nil */
+    } buf;
+    buf.ival = cpu_to_be32(val);
+    buf.bytes[4] = 0;
+
+    append_vpd(vpd, id, 5, buf.bytes);
+}
+
+static
+void build_vpd(const mvme3100_info *info, char *buf, size_t cnt,
+               const char *extra)
+{
+    vpdeeprom vpd = {buf, buf, cnt};
+    size_t i;
+
+    memset(buf, 0, cnt);
+
+    strcpy(buf, "MOTOROLA");
+    vpd.cur += 8;
+
+    /* Product ID (eg. "MVME3100-1152") */
+    append_string_vpd(&vpd, 1, info->desc);
+
+    /* serial number */
+    append_string_vpd(&vpd, 3, "E0120000");
+
+    /* CPU Freq. */
+    append_u32_vpd(&vpd, 5, info->cpu_freq);
+
+    /* PCI Bus Freq. */
+    append_u32_vpd(&vpd, 6, 66666666);
+
+    for (i = 0; i < MAX_NICS; i++) {
+        if (nd_table[i].used) {
+            append_mac_vpd(&vpd, 8, &nd_table[i].macaddr);
+        }
+    }
+
+    append_vpd(&vpd, 0xff, 0, NULL);
+
+    if (vpd.cur - vpd.base > 0x10f8) {
+        fprintf(stderr, "VPD overflows GEV area.\n");
+        return;
+    }
+
+    /* MOTLOAD's Global Environment Variables
+     * start at offset 0x10f8.
+     * This is a set of nil terminated strings of the form "name=value"
+     * with a zero length string signaling the end.
+     */
+    vpd.cur = vpd.base + 0x10f8;
+
+    for (i = 0; gev[i]; i++) {
+        append_gev_vpd(&vpd, gev[i]);
+    }
+
+    if (extra) {
+        char *E = g_strdup(extra);
+        char **opts = g_strsplit(E, " ", 0);
+        size_t i;
+
+        g_free(E);
+
+        for (i = 0; opts[i]; i++) {
+            char *opt = g_strstrip(opts[i]);
+            size_t olen = strlen(opt);
+
+            if (olen == 0) {
+                continue;
+            } else if (!strchr(opt, '=')) {
+                fprintf(stderr, "Missing '=' in -append %s\n", extra);
+                continue;
+            }
+
+            append_gev_vpd(&vpd, opt);
+        }
+
+        g_strfreev(opts);
+    }
+
+    /* zero length string signals end */
+    append_gev_vpd(&vpd, "");
+}
+
+static void mvme3100_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+    (void)params;
+    (void)fdt;
+}
+
+static
+void set_map(CPUPPCState *env, unsigned way,
+             target_ulong va, hwaddr pa,
+             unsigned size)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, way);
+
+    tlb->mas1 = MAS1_VALID | (size << MAS1_TSIZE_SHIFT);
+    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_I | MAS2_G;
+    tlb->mas7_3 = (pa & TARGET_PAGE_MASK) | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
+static
+void remap_tlb_bare(CPUPPCState *env)
+{
+    /* The MPC8540 ref. manual says only the upper 4KB (ROM)
+     * is mapped, but doesn't say exactly how this mapping
+     * is setup.  So we arbitrarily decide to use TLB1 entry 0.
+     */
+    set_map(env, 0, 0xfffff000, 0xfffff000, 0x02);
+
+    env->tlb_dirty = true;
+}
+
+/* runs after ppce500_cpu_reset() */
+static void mvme3100_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    /* We don't model HID0 functions.
+     * HID0[EMCP] (32) and HID0[TBEN] (TBEN) set
+     */
+    env->spr[SPR_HID0] = 0x80004000;
+
+    remap_tlb_bare(&cpu->env);
+    env->nip = 0xfffffffc;
+}
+
+/* PCI config from a real mvme3100 as configured by motload
+ *
+ *  BUS:SLOT:FUN  VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE
+ *  0:0x00:0    0x1057-0x0008:  0x0006 0x20B0 0x80000000 0x00000000       0 ->   0 (=0x00)
+ *  0:0x11:0    0x10E3-0x0148:  0x0146 0x02B0 0x80100004 0x00000000       1 ->   0 (=0x00)
+ *  0:0x12:0    0x10B5-0x6520:  0x0147 0x02B0 0x00000000 0x00000000       0 ->   0 (=0x00)
+ *  0:0x13:0    0x10B5-0x6520:  0x0147 0x02B0 0x00000000 0x00000000       0 ->   0 (=0x00)
+ *  0:0x14:0    0x8086-0x3200:  0x0145 0x02B0 0x00012001 0x00013001       1 ->   2 (=0x02)
+ *  2:0x00:0    0x1033-0x0035:  0x0146 0x0210 0x80300000 0x00000000       1 ->   4 (=0x04)
+ *  2:0x00:1    0x1033-0x0035:  0x0146 0x0210 0x80301000 0x00000000       2 ->   5 (=0x05)
+ *
+ * The modeled PCI host bridge differs.
+ *
+ * We don't model:
+ * # The SATA controller GD31244 (0x8086-0x3200)
+ * # The USB (OHCI) controller uPD740101 (0x1033-0x0035)
+ *
+ * (Note that the SATA controller found on newer boards is different)
+ */
+
+static void mvme3100_init(MachineState *machine)
+{
+    /* Config based on system state from MOTLoad, not power on */
+    static
+    PPCE500Params params = {
+        .pci_first_slot = 0,
+        .pci_nr_slots = 5,
+        .fixup_devtree = mvme3100_fixup_devtree,
+        .mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
+        .ccsrbar_base = 0xff700000ULL,
+        .pci_mmio_base = 0x80000000ULL,
+        .pci_mmio_bus_base = 0x80000000ULL,
+        .pci_pio_base = 0xE0000000ULL,
+        .spin_base = 0xE3000000ULL, /* not used */
+        .skip_load = 1,
+        .tsec_nic = true,
+        /* .porpllsr set from mvme3100_info */
+        /* Decrementor frequency actually controlled by HID0[SEL_TBCLK]
+         * or disabled by HID0[TBEN].
+         * We don't model and assume always enabled with CCB/8
+         */
+        .decrementor_freq = 41666666,
+    };
+    MVME3100State *mvme3100 = MVME3100(machine);
+    const mvme3100_info *info;
+    DeviceState *dev;
+    BusState *i2c;
+    SysBusDevice *cpld, *ccsr, *pic;
+    FWCfgState *fwinfo;
+    DriveInfo *drvinfo;
+
+    {
+        MVME3100Class *klass = MVME3100_GET_CLASS(machine);
+        info = klass->info;
+    }
+    params.porpllsr = info->porpllsr;
+
+    /* Setup CPU */
+    ppce500_init(machine, &params);
+
+    qemu_register_reset(mvme3100_cpu_reset, POWERPC_CPU(first_cpu));
+
+    pic = SYS_BUS_DEVICE(object_resolve_path("/machine/pic", NULL));
+    ccsr = SYS_BUS_DEVICE(object_resolve_path("/machine/e500-ccsr", NULL));
+
+    /* Setup mvme3100 specific CPLD device */
+    cpld = SYS_BUS_DEVICE(qdev_create(NULL, "mvme3100-cpld"));
+    object_property_add_child(qdev_get_machine(), "cpld",
+                              OBJECT(cpld), &error_fatal);
+    qdev_init_nofail(DEVICE(cpld));
+
+    memory_region_add_subregion(get_system_memory(),
+                                0xe2000000,
+                                sysbus_mmio_get_region(cpld, 0));
+
+    fwinfo = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i16(fwinfo, FW_CFG_NB_CPUS, 1);
+    fw_cfg_add_i16(fwinfo, FW_CFG_MAX_CPUS, 1);
+    fw_cfg_add_i64(fwinfo, FW_CFG_RAM_SIZE, machine->ram_size);
+
+    /* I2C Controller */
+    dev = DEVICE(object_resolve_path("/machine/i2c[0]", NULL));
+    assert(dev);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+                       qdev_get_gpio_in(DEVICE(pic), 16 + 27));
+    i2c = qdev_get_child_bus(dev, "bus");
+    assert(i2c);
+
+    dev = DEVICE(object_resolve_path("/machine/pci-host", NULL));
+    assert(dev);
+    /*TODO: add pci-to-pci bridge and fix host bridge IRQ mappings
+     *      to start from IRQ4
+     */
+
+    /* NIC */
+    if (nd_table[0].used) {
+        qemu_check_nic_model(&nd_table[0], "eTSEC");
+
+        dev = etsec_create(0x24000,
+                           sysbus_mmio_get_region(ccsr, 0),
+                           &nd_table[0],
+                qdev_get_gpio_in(DEVICE(pic), 16 + 13),
+                qdev_get_gpio_in(DEVICE(pic), 16 + 14),
+                qdev_get_gpio_in(DEVICE(pic), 16 + 18));
+
+    } else if (nd_table[1].used) {
+        qemu_check_nic_model(&nd_table[1], "eTSEC");
+
+        dev = etsec_create(0x25000,
+                           sysbus_mmio_get_region(ccsr, 0),
+                           &nd_table[1],
+                sysbus_get_connected_irq(pic, 16 + 19),
+                sysbus_get_connected_irq(pic, 16 + 20),
+                sysbus_get_connected_irq(pic, 16 + 23));
+    }
+
+    /* VPD EEPROM */
+    dev = qdev_create(i2c, "at24c-eeprom");
+    object_property_add_child(qdev_get_machine(), "vpd", OBJECT(dev),
+                              &error_fatal);
+    qdev_prop_set_uint8(dev, "address", 0xa8 >> 1);
+    qdev_prop_set_uint32(dev, "rom-size", 8192 * 8);
+
+    drvinfo = drive_get(IF_PFLASH, 0, 0);
+    if (drvinfo) {
+        qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(drvinfo),
+                            &error_fatal);
+    }
+
+    qdev_init_nofail(dev);
+
+    {
+        char *buf;
+
+        buf = g_malloc0(8192 * 8);
+
+        build_vpd(info, buf, 8192 * 8, machine->kernel_cmdline);
+
+        fw_cfg_add_file(fwinfo, "tomload/vpd", buf, 8192 * 8);
+    }
+
+    /* DS1375 RTC */
+    dev = qdev_create(i2c, "ds1375");
+    object_property_add_child(qdev_get_machine(), "rtc", OBJECT(dev),
+                              &error_fatal);
+    qdev_prop_set_uint8(dev, "address", 0xd0 >> 1);
+    qdev_init_nofail(dev);
+
+    /* TODO: unmodeled i2c devices.
+     * 0x90 - ds1621 temperature sensor
+     * 0xa0 - 256*8 byte DDR SPD (???)
+     * 0xa4 - 64k*8 byte eeprom for "user" configuration
+     * 0xa6 - 64k*8 byte eeprom for "user" configuration
+     * 0xaa -  8k*8 byte eeprom for VPD of rear expansion card
+     */
+
+    if (!bios_name) {
+        bios_name = "tomload.bin";
+    }
+
+    if (!qtest_enabled()) {
+        MemoryRegion *rom = g_malloc0(sizeof(*rom));
+        char *fullname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+        if (!fullname) {
+            fprintf(stderr, "qemu: could not find bios file '%s'\n",
+                    bios_name);
+            exit(1);
+        }
+
+        memory_region_init_ram(rom, OBJECT(cpld), "rom",
+                               0x800000, &error_fatal);
+
+        memory_region_add_subregion(get_system_memory(),
+                                    0xff800000, rom);
+
+        /* BIOS == image in rom (last 8MB of address space).
+         * Execution starts with the final word 0xfffffffc
+         */
+        int bsize = get_image_size(fullname);
+        if (bsize != 8 * 1024 * 1024 ||
+                -1 == load_image_targphys(fullname,
+                                          0xff800000, 8 * 1024 * 1024))
+        {
+            fprintf(stderr, "qemu: could not load bios file '%s'"
+                            " (%u bytes, requires 8MB)\n",
+                    fullname, (unsigned)bsize);
+            exit(1);
+        }
+
+        memory_region_set_readonly(rom, true);
+
+        g_free(fullname);
+    }
+
+    {
+        hwaddr image_addr = mvme3100->load_address;
+
+        int image_size = load_image_targphys(machine->kernel_filename,
+                                             image_addr, 0x01000000);
+        if (machine->kernel_filename &&
+                -1 == image_size)
+        {
+            fprintf(stderr, "qemu: could not load file '%s'\n",
+                    machine->kernel_filename);
+            exit(1);
+
+        } else if (mvme3100->entry_address == 0) {
+            mvme3100->entry_address = image_addr;
+
+        } else if (mvme3100->entry_address < image_addr
+                  || mvme3100->entry_address >= image_addr + image_size)
+        {
+            fprintf(stderr, "qemu: entry-address out of range\n");
+            exit(1);
+        }
+
+        if (machine->kernel_cmdline) {
+            fw_cfg_add_i32(fwinfo, FW_CFG_CMDLINE_SIZE,
+                           strlen(machine->kernel_cmdline) + 1);
+            fw_cfg_add_string(fwinfo, FW_CFG_CMDLINE_DATA,
+                              machine->kernel_cmdline);
+        }
+
+        fw_cfg_add_i32(fwinfo, FW_CFG_KERNEL_ADDR, image_addr);
+        fw_cfg_add_i32(fwinfo, FW_CFG_KERNEL_ENTRY, mvme3100->entry_address);
+        fw_cfg_add_i32(fwinfo, FW_CFG_KERNEL_SIZE, image_size);
+    }
+}
+
+static void mvme3100_inst_init(Object *obj)
+{
+    MVME3100State *mvme3100 = MVME3100(obj);
+    mvme3100->load_address = 0x10000;
+    mvme3100->entry_address = 0;
+}
+
+static void mvme3100_visit_addr(Object *obj,
+                                Visitor *v,
+                                const char *name,
+                                void *opaque,
+                                Error **errp)
+{
+    MVME3100State *mvme3100 = MVME3100(obj);
+    uint32_t *ptr;
+
+    if (strcmp(name, "load-address") == 0) {
+        ptr = &mvme3100->load_address;
+    } else if (strcmp(name, "entry-address") == 0) {
+        ptr = &mvme3100->entry_address;
+    } else {
+        fprintf(stderr, "logic error: mvme3100 has no prop '%s'\n", name);
+        exit(1);
+    }
+
+    visit_type_uint32(v, name, ptr, errp);
+}
+
+static void ppce500_machine_class_init(ObjectClass *klass, void *raw)
+{
+    mvme3100_info *info = raw;
+    MachineClass *mc = MACHINE_CLASS(klass);
+    MVME3100Class *m3c = MVME3100_CLASS(klass);
+
+    m3c->info = info;
+
+    mc->desc = info->desc;
+    mc->init = mvme3100_init;
+    mc->max_cpus = 1;
+    mc->default_ram_size = info->ram_size;
+    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("mpc8540_v21");
+
+    object_class_property_add(OBJECT_CLASS(mc), "load-address", "uint32",
+                              &mvme3100_visit_addr, &mvme3100_visit_addr, NULL,
+                              NULL, &error_fatal);
+    object_class_property_add(OBJECT_CLASS(mc), "entry-address", "uint32",
+                              &mvme3100_visit_addr, &mvme3100_visit_addr, NULL,
+                              NULL, &error_fatal);
+}
+
+static const TypeInfo mvme3100_type = {
+    .abstract = true,
+    .name = TYPE_MVME3100,
+    .parent = TYPE_MACHINE,
+    .instance_size = sizeof(MVME3100State),
+    .instance_init = mvme3100_inst_init,
+    .class_size = sizeof(MVME3100Class),
+};
+
+static mvme3100_info mvme3100_1152 = {
+    .desc = "MVME3100-1152",
+    .cpu_freq = 666666666u,
+    /* CCB/PCI  -> 5/1
+     * core/CCB -> 2/1
+     *
+     * plat ratio = 5 -> 5:1 CCB:PCI
+     * e500 ratio = 4 -> 4:1 e500:CCB
+     */
+    .porpllsr = 0x0004000a,
+    .ram_size = 256 * (1 << 20),
+};
+
+static const TypeInfo mvme3100_1152_type = {
+    .name = MACHINE_TYPE_NAME("mvme3100-1152"),
+    .parent = TYPE_MVME3100,
+    .class_init = ppce500_machine_class_init,
+    .class_data = &mvme3100_1152,
+};
+
+static mvme3100_info mvme3100_1263 = {
+    .desc = "MVME3100-1263",
+    .cpu_freq = 833333333u,
+    /* CCB/PCI  -> 5/1
+     * core/CCB -> 5/2
+     */
+    .porpllsr = 0x0005000a,
+    .ram_size = 512 * (1 << 20),
+};
+
+static const TypeInfo mvme3100_1263_type = {
+    .name = MACHINE_TYPE_NAME("mvme3100-1263"),
+    .parent = TYPE_MVME3100,
+    .class_init = ppce500_machine_class_init,
+    .class_data = &mvme3100_1263,
+};
+
+static void mvme3100_machine_init(void)
+{
+    type_register_static(&mvme3100_type);
+    type_register_static(&mvme3100_1152_type);
+    type_register_static(&mvme3100_1263_type);
+}
+
+type_init(mvme3100_machine_init)
diff --git a/hw/ppc/mvme3100_cpld.c b/hw/ppc/mvme3100_cpld.c
new file mode 100644
index 0000000000..41024566ce
--- /dev/null
+++ b/hw/ppc/mvme3100_cpld.c
@@ -0,0 +1,192 @@
+/*
+ * MVME3100 board CPLD (local logic)
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * This model was developed according to the
+ * MVME3100 Single Board Computer Programmer's Reference
+ * P/N: 6806800G37B
+ * July 2014
+ *
+ * And validated against the RTEMS 4.9.6 mvme3100 BSP
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "exec/address-spaces.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_3100CPLD */
+
+#define TYPE_CPLD "mvme3100-cpld"
+
+#define CPLD(obj) OBJECT_CHECK(MVMECPLD, (obj), TYPE_CPLD)
+
+#ifdef DEBUG_3100CPLD
+#define DPRINTK(FMT, ...) printf(TYPE_CPLD " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_CPLD " : " FMT, \
+    ## __VA_ARGS__)
+
+#define CPLD_SIZE 0x20
+
+typedef struct {
+    SysBusDevice parent_obj;
+
+    uint8_t mem[0x10];
+    uint32_t test;
+
+    MemoryRegion mmio;
+} MVMECPLD;
+
+static
+uint64_t cpld_read(void *opaque, hwaddr addr, unsigned size)
+{
+    MVMECPLD *self = opaque;
+    uint32_t offset = addr;
+    uint32_t val, A;
+
+    switch (offset) {
+    case 1 ... 0xf:
+        val = 0;
+        A = offset;
+        while (size--) {
+            val <<= 8;
+            val |= self->mem[A++];
+        }
+        break;
+    case 0x10:
+        val = self->test;
+        break;
+    case 0x14:
+        val = ~self->test;
+        break;
+    default:
+        LOG(LOG_UNIMP, "read from unimplimented register %08x\n",
+            (unsigned)offset);
+        val = 0;
+    }
+
+    DPRINTK("read %08x -> %08x\n", (unsigned)offset, (unsigned)val);
+
+    return val;
+}
+
+static
+void cpld_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    MVMECPLD *self = opaque;
+    uint32_t offset = addr;
+
+    DPRINTK("write %08x <- %08x\n", (unsigned)offset, (unsigned)val);
+
+    switch (offset) {
+    case 0:
+        break;
+    case 1:
+        /* TODO: TSTAT_MASK and EEPROM_WPEEPROM */
+        if ((val & 0xe0) == 0xa0) {
+            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        }
+        self->mem[offset >> 2] = val & 0x3;
+        break;
+    case 2:
+        self->mem[offset >> 2] = val & 0xf;
+        break;
+    case 3:
+        self->mem[offset >> 2] = val & 0x18;
+        break;
+    case 4 ... 9:
+        break;
+    case 10 ... 13:
+        /* TODO: allow date to be changed? */
+        break;
+    case 0x10:
+        self->test = val;
+        break;
+    case 0x11:
+        self->test = ~val;
+        break;
+    default:
+        LOG(LOG_UNIMP, "write to unimplimented register %08x\n",
+            (unsigned)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps cpld_ops = {
+    .read = cpld_read,
+    .write = cpld_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+static
+void mvme3100_cpld_realize(DeviceState *dev, Error **errp)
+{
+    MVMECPLD *self = CPLD(dev);
+
+    memory_region_init_io(&self->mmio, OBJECT(self), &cpld_ops, self,
+                          TYPE_CPLD, CPLD_SIZE);
+
+    sysbus_init_mmio(&self->parent_obj, &self->mmio);
+}
+
+static Property mvme3100_cpld_props[] = {
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static
+void mvme3100_cpld_reset(DeviceState *dev)
+{
+    MVMECPLD *self = CPLD(dev);
+
+    self->mem[0] = 0; /* Type VME SBC, SAFE_START==0 */
+    self->mem[1] = 3;
+    self->mem[2] = 1;
+    self->mem[3] = 9;
+    self->mem[4] = 9;
+    self->mem[5] = 0xa9;
+    self->mem[6] = 1;
+    self->mem[7] = 0xe0; /* TODO, TSEC phy irq status */
+    self->mem[8] = 1; /* TODO: PMC presence ...? */
+    self->mem[9] = 1; /* TODO: real rev. # */
+    self->mem[10] = 15; /* TODO: real date code */
+    self->mem[11] = 11;
+    self->mem[12] = 14;
+    self->mem[13] = 1;
+    self->test = 0;
+}
+
+static
+void mvme3100_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = &mvme3100_cpld_realize;
+    dc->reset = &mvme3100_cpld_reset;
+    dc->desc = "mvme3100 CPLD logic";
+    dc->props = mvme3100_cpld_props;
+}
+
+static const TypeInfo mvme3100_cpld_info = {
+    .name = TYPE_CPLD,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MVMECPLD),
+    .class_size = sizeof(SysBusDeviceClass),
+    .class_init = mvme3100_class_init,
+};
+
+static
+void mvme3100_cpld_register(void)
+{
+    type_register_static(&mvme3100_cpld_info);
+}
+
+type_init(mvme3100_cpld_register)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 12/12] tests: add mvme3100-test
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (9 preceding siblings ...)
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 11/12] ppc: add mvme3100 machine Michael Davidsaver
@ 2017-11-20  3:24 ` Michael Davidsaver
       [not found] ` <20171120032420.9134-3-mdavidsaver@gmail.com>
  2017-11-22  4:12 ` [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC David Gibson
  12 siblings, 0 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-20  3:24 UTC (permalink / raw)
  To: Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel, Michael Davidsaver

Exercise some features of the mvme3100 CPLD logic
and read from the eeprom w/ VPD.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 tests/Makefile.include |  3 ++
 tests/mvme3100-test.c  | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 tests/mvme3100-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ad1c219423..7ea041a885 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -372,6 +372,8 @@ check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-console-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF)
 
+check-qtest-ppc-$(CONFIG_E500) += tests/mvme3100-test$(EXESUF)
+
 check-qtest-generic-y += tests/qom-test$(EXESUF)
 check-qtest-generic-y += tests/test-hmp$(EXESUF)
 
@@ -781,6 +783,7 @@ tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
 tests/ac97-test$(EXESUF): tests/ac97-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
+tests/mvme3100-test$(EXESUF): tests/mvme3100-test.o $(libqos-e500-obj-y)
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
 tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
diff --git a/tests/mvme3100-test.c b/tests/mvme3100-test.c
new file mode 100644
index 0000000000..6dde8d1d29
--- /dev/null
+++ b/tests/mvme3100-test.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#define assert_equal(A, B) g_assert_cmphex((A), ==, (B))
+
+static
+I2CAdapter *i2c;
+
+static
+void test_ccsr(void)
+{
+    /* CCSRBAR is self referential */
+    assert_equal(readl(0xff700000), 0x000ff700);
+
+    /* introspect memory size */
+    assert_equal(readl(0xff702080), 0x80000000);
+    /* value is (ram_size-1)>>24 */
+    assert_equal(readl(0xff702000), 15);
+}
+
+static
+void test_cpld(void)
+{
+    /* read/write to test register */
+    assert_equal(readl(0xe2000010), 0x00000000);
+    assert_equal(readl(0xe2000014), 0xffffffff);
+
+    writel(0xe2000010, 0x12345678);
+
+    assert_equal(readl(0xe2000010), 0x12345678);
+    assert_equal(readl(0xe2000014), 0x12345678 ^ 0xffffffff);
+}
+
+static
+void test_eeprom(void)
+{
+    char buf[] = "\x00\x00MOTOROLA";
+
+    /* 1. zero address pointer
+     * 2. write 8 bytes,
+     * 3. re-zero address pointer
+     */
+    i2c_send(i2c, 0xa8, (uint8_t *)buf, 10);
+    i2c_send(i2c, 0xa8, (uint8_t *)buf, 2);
+
+    /* read 8 bytes */
+    i2c_recv(i2c, 0xa8, (uint8_t *)buf, 8);
+    buf[8] = '\0';
+
+    /* Read header for Motorola VPD info */
+    g_assert_cmpstr(buf, ==, "MOTOROLA");
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_start("-machine mvme3100-1152");
+
+    i2c = e500_i2c_create(0xff700000);
+
+    qtest_add_func("/mvme3100/ccsr", test_ccsr);
+    qtest_add_func("/mvme3100/cpld", test_cpld);
+    qtest_add_func("/mvme3100/eeprom", test_eeprom);
+
+    ret = g_test_run();
+
+    printf("Tests done\n");
+
+    qtest_end();
+    printf("Tests end\n");
+
+    return ret;
+}
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 01/12] e500: add board config options
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 01/12] e500: add board config options Michael Davidsaver
@ 2017-11-22  3:28   ` David Gibson
  2017-11-22 17:55     ` Michael Davidsaver
  0 siblings, 1 reply; 33+ messages in thread
From: David Gibson @ 2017-11-22  3:28 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3924 bytes --]

On Sun, Nov 19, 2017 at 09:24:09PM -0600, Michael Davidsaver wrote:
> allow board code to skip common NIC and guest image setup
> and configure decrementor frequency.
> Existing boards unchanged.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

So, it's spelled "decrementer".

Other than that, the patch looks correct.  However having a big common
function for overall init with a pile of ad-hoc configuration
parameters is usually not a great way to go.  I think what we want
instead is to eliminate ppce500_init(), instead doing the setup logic
separately in each of the e500 machines.   The large common slabs of
code can be helpers in e500.c, but the overall logic - including most
of the things controlled by the current params - would be under the
individual machine's control.

> ---
>  hw/ppc/e500.c      | 8 ++++++--
>  hw/ppc/e500.h      | 3 +++
>  hw/ppc/e500plat.c  | 1 +
>  hw/ppc/mpc8544ds.c | 1 +
>  4 files changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 5cf0dabef3..9e7e1b29c4 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -826,7 +826,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>          env->mpic_iack = params->ccsrbar_base +
>                           MPC8544_MPIC_REGS_OFFSET + 0xa0;
>  
> -        ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
> +        ppc_booke_timers_init(cpu, params->decrementor_freq, PPC_TIMER_E500);
>  
>          /* Register reset handler */
>          if (!i) {
> @@ -899,7 +899,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      if (!pci_bus)
>          printf("couldn't create PCI controller!\n");
>  
> -    if (pci_bus) {
> +    if (pci_bus && !params->tsec_nic) {
>          /* Register network interfaces. */
>          for (i = 0; i < nb_nics; i++) {
>              pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
> @@ -948,6 +948,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>                                      sysbus_mmio_get_region(s, 0));
>      }
>  
> +    if (params->skip_load) {
> +        return;
> +    }
> +
>      /* Load kernel. */
>      if (machine->kernel_filename) {
>          kernel_base = cur_base;
> diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
> index 70ba1d8f4f..40f72f2de2 100644
> --- a/hw/ppc/e500.h
> +++ b/hw/ppc/e500.h
> @@ -22,6 +22,9 @@ typedef struct PPCE500Params {
>      hwaddr pci_mmio_base;
>      hwaddr pci_mmio_bus_base;
>      hwaddr spin_base;
> +    uint32_t decrementor_freq; /* in Hz */
> +    bool skip_load;
> +    bool tsec_nic;
>  } PPCE500Params;
>  
>  void ppce500_init(MachineState *machine, PPCE500Params *params);
> diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
> index e59e80fb9e..3d07987bd1 100644
> --- a/hw/ppc/e500plat.c
> +++ b/hw/ppc/e500plat.c
> @@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
>          .pci_mmio_base = 0xC00000000ULL,
>          .pci_mmio_bus_base = 0xE0000000ULL,
>          .spin_base = 0xFEF000000ULL,
> +        .decrementor_freq = 400000000,
>      };
>  
>      /* Older KVM versions don't support EPR which breaks guests when we announce
> diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
> index 1717953ec7..6d9931c475 100644
> --- a/hw/ppc/mpc8544ds.c
> +++ b/hw/ppc/mpc8544ds.c
> @@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
>          .pci_mmio_bus_base = 0xC0000000ULL,
>          .pci_pio_base = 0xE1000000ULL,
>          .spin_base = 0xEF000000ULL,
> +        .decrementor_freq = 400000000,
>      };
>  
>      if (machine->ram_size > 0xc0000000) {

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr
       [not found] ` <20171120032420.9134-3-mdavidsaver@gmail.com>
@ 2017-11-22  3:36   ` David Gibson
  2017-12-06  3:12     ` David Gibson
  0 siblings, 1 reply; 33+ messages in thread
From: David Gibson @ 2017-11-22  3:36 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 16544 bytes --]

On Sun, Nov 19, 2017 at 09:24:10PM -0600, Michael Davidsaver wrote:
> Preparation for adding more MPCxxxx control
> registers.
> 
> Use e500 SVR to enable part specific registers.
> Only the mpc8544 reset register at present.
> 
> Expose CCSR as SysBusDevice region to eliminate
> e500-ccsr.h.
> 
> Track CCSR base address within device, and map on reset,
> in preparation for CCSRBAR.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Applied to ppc-for-2.12.

> ---
>  hw/pci-host/ppce500.c |  10 ++--
>  hw/ppc/Makefile.objs  |   3 +-
>  hw/ppc/e500-ccsr.h    |  17 ------
>  hw/ppc/e500.c         |  37 +-----------
>  hw/ppc/e500_ccsr.c    | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/ppc/mpc8544_guts.c | 143 -----------------------------------------------
>  6 files changed, 162 insertions(+), 200 deletions(-)
>  delete mode 100644 hw/ppc/e500-ccsr.h
>  create mode 100644 hw/ppc/e500_ccsr.c
>  delete mode 100644 hw/ppc/mpc8544_guts.c
> 
> diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
> index 39cd24464d..f2d108bc8a 100644
> --- a/hw/pci-host/ppce500.c
> +++ b/hw/pci-host/ppce500.c
> @@ -16,7 +16,6 @@
>  
>  #include "qemu/osdep.h"
>  #include "hw/hw.h"
> -#include "hw/ppc/e500-ccsr.h"
>  #include "hw/pci/pci.h"
>  #include "hw/pci/pci_host.h"
>  #include "qemu/bswap.h"
> @@ -420,16 +419,17 @@ static const VMStateDescription vmstate_ppce500_pci = {
>  static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
>  {
>      PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
> -    PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
> -                                  "/e500-ccsr"));
> +    SysBusDevice *ccsr = SYS_BUS_DEVICE(container_get(qdev_get_machine(),
> +                                                      "/e500-ccsr"));
> +    MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
>  
>      pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
>      d->config[PCI_HEADER_TYPE] =
>          (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
>          PCI_HEADER_TYPE_BRIDGE;
>  
> -    memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0", &ccsr->ccsr_space,
> -                             0, int128_get64(ccsr->ccsr_space.size));
> +    memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0", ccsr_mr,
> +                             0, memory_region_size(ccsr_mr));
>      pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
>  }
>  
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 7efc686748..c1a63d0c39 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -24,6 +24,7 @@ obj-$(CONFIG_MAC) += mac_oldworld.o
>  obj-$(CONFIG_MAC) += mac_newworld.o
>  # e500
>  obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
> -obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
> +obj-$(CONFIG_E500) += ppce500_spin.o
> +obj-$(CONFIG_E500) += e500_ccsr.o
>  # PowerPC 440 Xilinx ML507 reference board.
>  obj-$(CONFIG_XILINX) += virtex_ml507.o
> diff --git a/hw/ppc/e500-ccsr.h b/hw/ppc/e500-ccsr.h
> deleted file mode 100644
> index 12a2ba4b97..0000000000
> --- a/hw/ppc/e500-ccsr.h
> +++ /dev/null
> @@ -1,17 +0,0 @@
> -#ifndef E500_CCSR_H
> -#define E500_CCSR_H
> -
> -#include "hw/sysbus.h"
> -
> -typedef struct PPCE500CCSRState {
> -    /*< private >*/
> -    SysBusDevice parent;
> -    /*< public >*/
> -
> -    MemoryRegion ccsr_space;
> -} PPCE500CCSRState;
> -
> -#define TYPE_CCSR "e500-ccsr"
> -#define CCSR(obj) OBJECT_CHECK(PPCE500CCSRState, (obj), TYPE_CCSR)
> -
> -#endif /* E500_CCSR_H */
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 9e7e1b29c4..474a46a985 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -15,10 +15,10 @@
>   */
>  
>  #include "qemu/osdep.h"
> +#include "qemu/log.h"
>  #include "qapi/error.h"
>  #include "qemu-common.h"
>  #include "e500.h"
> -#include "e500-ccsr.h"
>  #include "net/net.h"
>  #include "qemu/config-file.h"
>  #include "hw/hw.h"
> @@ -795,7 +795,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      CPUPPCState *firstenv = NULL;
>      MemoryRegion *ccsr_addr_space;
>      SysBusDevice *s;
> -    PPCE500CCSRState *ccsr;
>  
>      irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
>      irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
> @@ -854,11 +853,9 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      dev = qdev_create(NULL, "e500-ccsr");
>      object_property_add_child(qdev_get_machine(), "e500-ccsr",
>                                OBJECT(dev), NULL);
> +    qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
>      qdev_init_nofail(dev);
> -    ccsr = CCSR(dev);
> -    ccsr_addr_space = &ccsr->ccsr_space;
> -    memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
> -                                ccsr_addr_space);
> +    ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>  
>      mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
>  
> @@ -875,13 +872,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>                         serial_hds[1], DEVICE_BIG_ENDIAN);
>      }
>  
> -    /* General Utility device */
> -    dev = qdev_create(NULL, "mpc8544-guts");
> -    qdev_init_nofail(dev);
> -    s = SYS_BUS_DEVICE(dev);
> -    memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
> -                                sysbus_mmio_get_region(s, 0));
> -
>      /* PCI */
>      dev = qdev_create(NULL, "e500-pcihost");
>      qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
> @@ -1039,24 +1029,3 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      boot_info->dt_base = dt_base;
>      boot_info->dt_size = dt_size;
>  }
> -
> -static void e500_ccsr_initfn(Object *obj)
> -{
> -    PPCE500CCSRState *ccsr = CCSR(obj);
> -    memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
> -                       MPC8544_CCSRBAR_SIZE);
> -}
> -
> -static const TypeInfo e500_ccsr_info = {
> -    .name          = TYPE_CCSR,
> -    .parent        = TYPE_SYS_BUS_DEVICE,
> -    .instance_size = sizeof(PPCE500CCSRState),
> -    .instance_init = e500_ccsr_initfn,
> -};
> -
> -static void e500_register_types(void)
> -{
> -    type_register_static(&e500_ccsr_info);
> -}
> -
> -type_init(e500_register_types)
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> new file mode 100644
> index 0000000000..1b586c3f42
> --- /dev/null
> +++ b/hw/ppc/e500_ccsr.c
> @@ -0,0 +1,152 @@
> +/*
> + * MPC8540 and MPC8544 specific control registers.
> + * Not really part of e500 spec, but common to many
> + * Freescale parts w/ e500 cores.
> + *
> + * Copyright (c) 2017 Michael Davidsaver
> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * Authors: Alexander Graf, <alex@csgraf.de>
> + *          Michael Davidsaver <mdavidsaver@gmail.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the LICENSE file in the top-level directory.
> + *
> + * This model was developed according to:
> + *
> + * MPC8544E PowerQUICC III Integrated Host Processor Family Reference Manual
> + * Rev. 1
> + *
> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/log.h"
> +#include "qemu/error-report.h"
> +#include "cpu.h"
> +#include "hw/hw.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/sysbus.h"
> +
> +/* E500_ denotes registers common to all */
> +
> +#define E500_PVR         (0xE00A0)
> +#define E500_SVR         (0xE00A4)
> +
> +#define MPC8544_RSTCR       (0xE00B0)
> +#define MPC8544_RSTCR_RESET      (0x02)
> +
> +typedef struct {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +    /*< public >*/
> +
> +    MemoryRegion iomem;
> +
> +    uint32_t defbase;
> +} CCSRState;
> +
> +#define TYPE_E500_CCSR "e500-ccsr"
> +#define E500_CCSR(obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR)
> +
> +static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
> +                                  unsigned size)
> +{
> +    PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    switch (addr) {
> +    case E500_PVR:
> +        return env->spr[SPR_PVR];
> +    case E500_SVR:
> +        return env->spr[SPR_E500_SVR];
> +    }
> +
> +    qemu_log_mask(LOG_GUEST_ERROR | LOG_UNIMP,
> +                  "can't read undefined ccsr regster %x\n",
> +                  (unsigned)addr);
> +    return 0;
> +}
> +
> +static void e500_ccsr_write(void *opaque, hwaddr addr,
> +                               uint64_t value, unsigned size)
> +{
> +    PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
> +    CPUPPCState *env = &cpu->env;
> +    uint32_t svr = env->spr[SPR_E500_SVR] >> 16;
> +
> +    switch (svr) {
> +    case 0: /* generic.  assumed to be mpc8544ds or e500plat board */
> +    case 0x8034: /* mpc8544 */
> +    case 0x803C: /* mpc8544E */
> +        switch (addr) {
> +        case MPC8544_RSTCR:
> +            if (value & MPC8544_RSTCR_RESET) {
> +                qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> +            }
> +            return;
> +        }
> +    }
> +
> +    qemu_log_mask(LOG_GUEST_ERROR | LOG_UNIMP,
> +                  "can't write undefined ccsr regster %x <- %08x\n",
> +                  (unsigned)addr, (unsigned)value);
> +}
> +
> +static const MemoryRegionOps e500_ccsr_ops = {
> +    .read = e500_ccsr_read,
> +    .write = e500_ccsr_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    }
> +};
> +
> +static void e500_ccsr_reset(DeviceState *dev)
> +{
> +    CCSRState *ccsr = E500_CCSR(dev);
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ccsr->defbase);
> +}
> +
> +static void e500_ccsr_initfn(Object *obj)
> +{
> +    CCSRState *ccsr = E500_CCSR(obj);
> +
> +    memory_region_init_io(&ccsr->iomem, obj, &e500_ccsr_ops,
> +                          ccsr, "e500-ccsr", 1024 * 1024);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &ccsr->iomem);
> +
> +}
> +
> +static Property e500_ccsr_props[] = {
> +    DEFINE_PROP_UINT32("base", CCSRState, defbase, 0xff700000),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static
> +void e500_ccsr_class_initfn(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = e500_ccsr_props;
> +    dc->reset = e500_ccsr_reset;
> +}
> +
> +static const TypeInfo e500_ccsr_info = {
> +    .name          = TYPE_E500_CCSR,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(CCSRState),
> +    .instance_init = e500_ccsr_initfn,
> +    .class_size    = sizeof(SysBusDeviceClass),
> +    .class_init    = e500_ccsr_class_initfn
> +};
> +
> +static void e500_ccsr_register_types(void)
> +{
> +    type_register_static(&e500_ccsr_info);
> +}
> +
> +type_init(e500_ccsr_register_types)
> diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c
> deleted file mode 100644
> index ce1254b5d4..0000000000
> --- a/hw/ppc/mpc8544_guts.c
> +++ /dev/null
> @@ -1,143 +0,0 @@
> -/*
> - * QEMU PowerPC MPC8544 global util pseudo-device
> - *
> - * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
> - *
> - * Author: Alexander Graf, <alex@csgraf.de>
> - *
> - * This 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.
> - *
> - * *****************************************************************
> - *
> - * The documentation for this device is noted in the MPC8544 documentation,
> - * file name "MPC8544ERM.pdf". You can easily find it on the web.
> - *
> - */
> -
> -#include "qemu/osdep.h"
> -#include "qemu-common.h"
> -#include "cpu.h"
> -#include "hw/hw.h"
> -#include "sysemu/sysemu.h"
> -#include "hw/sysbus.h"
> -
> -#define MPC8544_GUTS_MMIO_SIZE        0x1000
> -#define MPC8544_GUTS_RSTCR_RESET      0x02
> -
> -#define MPC8544_GUTS_ADDR_PORPLLSR    0x00
> -#define MPC8544_GUTS_ADDR_PORBMSR     0x04
> -#define MPC8544_GUTS_ADDR_PORIMPSCR   0x08
> -#define MPC8544_GUTS_ADDR_PORDEVSR    0x0C
> -#define MPC8544_GUTS_ADDR_PORDBGMSR   0x10
> -#define MPC8544_GUTS_ADDR_PORDEVSR2   0x14
> -#define MPC8544_GUTS_ADDR_GPPORCR     0x20
> -#define MPC8544_GUTS_ADDR_GPIOCR      0x30
> -#define MPC8544_GUTS_ADDR_GPOUTDR     0x40
> -#define MPC8544_GUTS_ADDR_GPINDR      0x50
> -#define MPC8544_GUTS_ADDR_PMUXCR      0x60
> -#define MPC8544_GUTS_ADDR_DEVDISR     0x70
> -#define MPC8544_GUTS_ADDR_POWMGTCSR   0x80
> -#define MPC8544_GUTS_ADDR_MCPSUMR     0x90
> -#define MPC8544_GUTS_ADDR_RSTRSCR     0x94
> -#define MPC8544_GUTS_ADDR_PVR         0xA0
> -#define MPC8544_GUTS_ADDR_SVR         0xA4
> -#define MPC8544_GUTS_ADDR_RSTCR       0xB0
> -#define MPC8544_GUTS_ADDR_IOVSELSR    0xC0
> -#define MPC8544_GUTS_ADDR_DDRCSR      0xB20
> -#define MPC8544_GUTS_ADDR_DDRCDR      0xB24
> -#define MPC8544_GUTS_ADDR_DDRCLKDR    0xB28
> -#define MPC8544_GUTS_ADDR_CLKOCR      0xE00
> -#define MPC8544_GUTS_ADDR_SRDS1CR1    0xF04
> -#define MPC8544_GUTS_ADDR_SRDS2CR1    0xF10
> -#define MPC8544_GUTS_ADDR_SRDS2CR3    0xF18
> -
> -#define TYPE_MPC8544_GUTS "mpc8544-guts"
> -#define MPC8544_GUTS(obj) OBJECT_CHECK(GutsState, (obj), TYPE_MPC8544_GUTS)
> -
> -struct GutsState {
> -    /*< private >*/
> -    SysBusDevice parent_obj;
> -    /*< public >*/
> -
> -    MemoryRegion iomem;
> -};
> -
> -typedef struct GutsState GutsState;
> -
> -static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
> -                                  unsigned size)
> -{
> -    uint32_t value = 0;
> -    PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
> -    CPUPPCState *env = &cpu->env;
> -
> -    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
> -    switch (addr) {
> -    case MPC8544_GUTS_ADDR_PVR:
> -        value = env->spr[SPR_PVR];
> -        break;
> -    case MPC8544_GUTS_ADDR_SVR:
> -        value = env->spr[SPR_E500_SVR];
> -        break;
> -    default:
> -        fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
> -        break;
> -    }
> -
> -    return value;
> -}
> -
> -static void mpc8544_guts_write(void *opaque, hwaddr addr,
> -                               uint64_t value, unsigned size)
> -{
> -    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
> -
> -    switch (addr) {
> -    case MPC8544_GUTS_ADDR_RSTCR:
> -        if (value & MPC8544_GUTS_RSTCR_RESET) {
> -            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> -        }
> -        break;
> -    default:
> -        fprintf(stderr, "guts: Unknown register write: %x = %x\n",
> -                (int)addr, (unsigned)value);
> -        break;
> -    }
> -}
> -
> -static const MemoryRegionOps mpc8544_guts_ops = {
> -    .read = mpc8544_guts_read,
> -    .write = mpc8544_guts_write,
> -    .endianness = DEVICE_BIG_ENDIAN,
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 4,
> -    },
> -};
> -
> -static void mpc8544_guts_initfn(Object *obj)
> -{
> -    SysBusDevice *d = SYS_BUS_DEVICE(obj);
> -    GutsState *s = MPC8544_GUTS(obj);
> -
> -    memory_region_init_io(&s->iomem, OBJECT(s), &mpc8544_guts_ops, s,
> -                          "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE);
> -    sysbus_init_mmio(d, &s->iomem);
> -}
> -
> -static const TypeInfo mpc8544_guts_info = {
> -    .name          = TYPE_MPC8544_GUTS,
> -    .parent        = TYPE_SYS_BUS_DEVICE,
> -    .instance_size = sizeof(GutsState),
> -    .instance_init = mpc8544_guts_initfn,
> -};
> -
> -static void mpc8544_guts_register_types(void)
> -{
> -    type_register_static(&mpc8544_guts_info);
> -}
> -
> -type_init(mpc8544_guts_register_types)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge Michael Davidsaver
@ 2017-11-22  3:46   ` David Gibson
  2017-11-22  4:57     ` Michael Davidsaver
  0 siblings, 1 reply; 33+ messages in thread
From: David Gibson @ 2017-11-22  3:46 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1185 bytes --]

On Sun, Nov 19, 2017 at 09:24:11PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

I'm not sure if you're saying you think there is a hardware bug which
we're faithfully emulating, or a software bug.

> ---
>  hw/pci-host/ppce500.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
> index f2d108bc8a..0e2833bd98 100644
> --- a/hw/pci-host/ppce500.c
> +++ b/hw/pci-host/ppce500.c
> @@ -424,6 +424,9 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
>      MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
>  
>      pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
> +    /* BUG? identifies as PCI_HEADER_TYPE_BRIDGE but uses
> +     * standard device config read/write
> +     */
>      d->config[PCI_HEADER_TYPE] =
>          (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
>          PCI_HEADER_TYPE_BRIDGE;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers Michael Davidsaver
@ 2017-11-22  3:57   ` David Gibson
  0 siblings, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-22  3:57 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 7235 bytes --]

On Sun, Nov 19, 2017 at 09:24:12PM -0600, Michael Davidsaver wrote:
> Add CCSRBAR to allow CCSR region to be relocated.
> Guest memory size introspection.
> Dummy RAM error controls.
> Guest clock introspection.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Looks fine from the POV of someone who doesn't know details about
e500.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  hw/ppc/e500.c      |  2 ++
>  hw/ppc/e500.h      |  1 +
>  hw/ppc/e500_ccsr.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  hw/ppc/e500plat.c  |  1 +
>  hw/ppc/mpc8544ds.c |  1 +
>  5 files changed, 75 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 474a46a985..057be1751b 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -853,7 +853,9 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      dev = qdev_create(NULL, "e500-ccsr");
>      object_property_add_child(qdev_get_machine(), "e500-ccsr",
>                                OBJECT(dev), NULL);
> +    qdev_prop_set_uint32(dev, "porpllsr", params->porpllsr);
>      qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
> +    qdev_prop_set_uint32(dev, "ram-size", ram_size);
>      qdev_init_nofail(dev);
>      ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>  
> diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
> index 40f72f2de2..1f39095dfa 100644
> --- a/hw/ppc/e500.h
> +++ b/hw/ppc/e500.h
> @@ -22,6 +22,7 @@ typedef struct PPCE500Params {
>      hwaddr pci_mmio_base;
>      hwaddr pci_mmio_bus_base;
>      hwaddr spin_base;
> +    uint32_t porpllsr; /* value of PORPLLSR register */
>      uint32_t decrementor_freq; /* in Hz */
>      bool skip_load;
>      bool tsec_nic;
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> index 1b586c3f42..c58b17f06b 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -31,6 +31,16 @@
>  
>  /* E500_ denotes registers common to all */
>  
> +#define E500_CCSRBAR     (0)
> +
> +#define E500_CS0_BNDS    (0x2000)
> +
> +#define E500_CS0_CONFIG  (0x2080)
> +
> +#define E500_ERR_DETECT  (0x2e40)
> +#define E500_ERR_DISABLE (0x2e44)
> +
> +#define E500_PORPLLSR    (0xE0000)
>  #define E500_PVR         (0xE00A0)
>  #define E500_SVR         (0xE00A4)
>  
> @@ -44,7 +54,11 @@ typedef struct {
>  
>      MemoryRegion iomem;
>  
> -    uint32_t defbase;
> +    uint32_t defbase, base;
> +    uint32_t ram_size;
> +    uint32_t merrd;
> +
> +    uint32_t porpllsr;
>  } CCSRState;
>  
>  #define TYPE_E500_CCSR "e500-ccsr"
> @@ -53,10 +67,28 @@ typedef struct {
>  static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
>                                    unsigned size)
>  {
> +    CCSRState *ccsr = opaque;
>      PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
>      CPUPPCState *env = &cpu->env;
>  
>      switch (addr) {
> +    case E500_CCSRBAR:
> +        return ccsr->base >> 12;
> +    case E500_CS0_BNDS:
> +        /* we model all RAM in a single chip with addresses [0, ram_size) */
> +        return (ccsr->ram_size - 1) >> 24;
> +    case E500_CS0_CONFIG:
> +        return 1 << 31;
> +    case E500_ERR_DETECT:
> +        return 0; /* (errors not modeled) */
> +    case E500_ERR_DISABLE:
> +        return ccsr->merrd;
> +    case E500_PORPLLSR:
> +        if (!ccsr->porpllsr) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "Machine does not provide valid PORPLLSR\n");
> +        }
> +        return ccsr->porpllsr;
>      case E500_PVR:
>          return env->spr[SPR_PVR];
>      case E500_SVR:
> @@ -72,10 +104,22 @@ static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
>  static void e500_ccsr_write(void *opaque, hwaddr addr,
>                                 uint64_t value, unsigned size)
>  {
> +    CCSRState *ccsr = opaque;
>      PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
>      CPUPPCState *env = &cpu->env;
>      uint32_t svr = env->spr[SPR_E500_SVR] >> 16;
>  
> +    switch (addr) {
> +    case E500_CCSRBAR:
> +        value &= 0x000fff00;
> +        ccsr->base = value << 12;
> +        sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
> +        return;
> +    case E500_ERR_DISABLE:
> +        ccsr->merrd = value & 0xd;
> +        return;
> +    }
> +
>      switch (svr) {
>      case 0: /* generic.  assumed to be mpc8544ds or e500plat board */
>      case 0x8034: /* mpc8544 */
> @@ -104,11 +148,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
>      }
>  };
>  
> +static int e500_ccsr_post_load(void *opaque, int version_id)
> +{
> +    CCSRState *ccsr = opaque;
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
> +    return 0;
> +}
> +
>  static void e500_ccsr_reset(DeviceState *dev)
>  {
>      CCSRState *ccsr = E500_CCSR(dev);
>  
> -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ccsr->defbase);
> +    ccsr->base = ccsr->defbase;
> +    e500_ccsr_post_load(ccsr, 1);
>  }
>  
>  static void e500_ccsr_initfn(Object *obj)
> @@ -123,15 +176,30 @@ static void e500_ccsr_initfn(Object *obj)
>  
>  static Property e500_ccsr_props[] = {
>      DEFINE_PROP_UINT32("base", CCSRState, defbase, 0xff700000),
> +    DEFINE_PROP_UINT32("ram-size", CCSRState, ram_size, 0),
> +    DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
>      DEFINE_PROP_END_OF_LIST()
>  };
>  
> +static const VMStateDescription vmstate_e500_ccsr = {
> +    .name = TYPE_E500_CCSR,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = e500_ccsr_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(base, CCSRState),
> +        VMSTATE_UINT32(merrd, CCSRState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  static
>  void e500_ccsr_class_initfn(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
>  
>      dc->props = e500_ccsr_props;
> +    dc->vmsd = &vmstate_e500_ccsr;
>      dc->reset = e500_ccsr_reset;
>  }
>  
> diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
> index 3d07987bd1..4e763d9c09 100644
> --- a/hw/ppc/e500plat.c
> +++ b/hw/ppc/e500plat.c
> @@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
>          .pci_mmio_base = 0xC00000000ULL,
>          .pci_mmio_bus_base = 0xE0000000ULL,
>          .spin_base = 0xFEF000000ULL,
> +        .porpllsr = 0, /* TODO missing valid value */
>          .decrementor_freq = 400000000,
>      };
>  
> diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
> index 6d9931c475..f5e0042245 100644
> --- a/hw/ppc/mpc8544ds.c
> +++ b/hw/ppc/mpc8544ds.c
> @@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
>          .pci_mmio_bus_base = 0xC0000000ULL,
>          .pci_pio_base = 0xE1000000ULL,
>          .spin_base = 0xEF000000ULL,
> +        .porpllsr = 0, /* TODO missing valid value */
>          .decrementor_freq = 400000000,
>      };
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge Michael Davidsaver
@ 2017-11-22  3:58   ` David Gibson
  0 siblings, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-22  3:58 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1432 bytes --]

On Sun, Nov 19, 2017 at 09:24:13PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Applied to ppc-for-2.12.

> ---
>  hw/ppc/e500.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 057be1751b..6f77844303 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -685,6 +685,8 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
>      int i, j, k;
>  
>      dev = qdev_create(NULL, TYPE_OPENPIC);
> +    object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev),
> +                              &error_fatal);
>      qdev_prop_set_uint32(dev, "model", params->mpic_version);
>      qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
>  
> @@ -876,6 +878,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>  
>      /* PCI */
>      dev = qdev_create(NULL, "e500-pcihost");
> +    object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
> +                              &error_abort);
>      qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
>      qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
>      qdev_init_nofail(dev);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller Michael Davidsaver
@ 2017-11-22  4:06   ` David Gibson
  2017-11-23 15:39   ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
  1 sibling, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-22  4:06 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 10134 bytes --]

On Sun, Nov 19, 2017 at 09:24:14PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

I can't speak to the accuracy of the emulation, but it's presumably
better than nothing at all.  Therefore, applied to ppc-for-2.12.

> ---
>  hw/i2c/Makefile.objs |   1 +
>  hw/i2c/mpc8540_i2c.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 288 insertions(+)
>  create mode 100644 hw/i2c/mpc8540_i2c.c
> 
> diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
> index 0594dea3ae..79af1dd901 100644
> --- a/hw/i2c/Makefile.objs
> +++ b/hw/i2c/Makefile.objs
> @@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
>  common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
>  obj-$(CONFIG_OMAP) += omap_i2c.o
>  obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
> +obj-$(CONFIG_E500) += mpc8540_i2c.o
> diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
> new file mode 100644
> index 0000000000..884052cc9b
> --- /dev/null
> +++ b/hw/i2c/mpc8540_i2c.c
> @@ -0,0 +1,287 @@
> +/*
> + * MPC8540 I2C bus interface
> + * As described in
> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
> + * Part 2 chapter 11
> + *
> + * Copyright (c) 2015 Michael Davidsaver
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the LICENSE file in the top-level directory.
> + */
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "hw/hw.h"
> +#include "hw/registerfields.h"
> +#include "hw/i2c/i2c.h"
> +#include "hw/sysbus.h"
> +
> +/* #define DEBUG_LVL 0 */
> +
> +#ifdef DEBUG_LVL
> +#define DPRINTK(LVL, FMT, ...) do { if ((LVL) <= DEBUG_LVL) { \
> +    printf(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); } } while (0)
> +#else
> +#define DPRINTK(LVL, FMT, ...) do {} while (0)
> +#endif
> +
> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
> +    " : " FMT, ## __VA_ARGS__)
> +
> +#define TYPE_MPC8540_I2C "mpc8540-i2c"
> +#define MPC8540_I2C(obj) OBJECT_CHECK(I2CState, (obj), TYPE_MPC8540_I2C)
> +
> +/* offsets relative to CCSR offset 0x3000 */
> +#define R_I2CADR (0)
> +#define R_I2CFDR (4)
> +#define R_I2CCR  (8)
> +#define R_I2CSR  (0xc)
> +#define R_I2CDR  (0x10)
> +#define R_I2CDFSRR (0x14)
> +
> +FIELD(I2CCR, MEN, 7, 1)
> +FIELD(I2CCR, MIEN, 6, 1)
> +FIELD(I2CCR, MSTA, 5, 1)
> +FIELD(I2CCR, MTX, 4, 1)
> +FIELD(I2CCR, TXAK, 3, 1)
> +FIELD(I2CCR, RSTA, 2, 1)
> +FIELD(I2CCR, BCST, 0, 1)
> +
> +FIELD(I2CSR, MCF, 7, 1)
> +FIELD(I2CSR, MAAS, 6, 1)
> +FIELD(I2CSR, MBB, 5, 1)
> +FIELD(I2CSR, MAL, 4, 1)
> +FIELD(I2CSR, BCSTM, 3, 1)
> +FIELD(I2CSR, SRW, 2, 1)
> +FIELD(I2CSR, MIF, 1, 1)
> +FIELD(I2CSR, RXAK, 0, 1)
> +
> +typedef struct I2CState {
> +    SysBusDevice parent_obj;
> +
> +    I2CBus *bus;
> +
> +    uint8_t ctrl, sts;
> +    uint8_t freq, filt;
> +    /* Reads are pipelined, this is the next data value */
> +    uint8_t dbuf;
> +
> +    qemu_irq irq;
> +
> +    MemoryRegion mmio;
> +} I2CState;
> +
> +#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
> +#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
> +
> +#define I2CSR_SET(BIT, VAL) do {\
> +        i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
> +    } while (0)
> +
> +static
> +void mpc8540_update_irq(I2CState *i2c)
> +{
> +    int ena = i2c->ctrl & 0x40,
> +        sts = i2c->sts & 0x02,
> +        act = !!(ena && sts);
> +
> +    DPRINTK(1, "IRQ %c ena %c sts %c\n",
> +            act ? 'X' : '_',
> +            ena ? 'X' : '_',
> +            sts ? 'X' : '_');
> +
> +    qemu_set_irq(i2c->irq, act);
> +}
> +
> +static
> +uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    I2CState *i2c = opaque;
> +    uint32_t val, offset = addr;
> +
> +    switch (offset) {
> +    case R_I2CADR: /* ADDR */
> +        val = 0;
> +        break;
> +    case R_I2CFDR: /* Freq Div. */
> +        val = i2c->freq;
> +        break;
> +    case R_I2CCR: /* CONTROL */
> +        val = i2c->ctrl & ~0x06;
> +        break;
> +    case R_I2CSR: /* STATUS */
> +        val = i2c->sts;
> +        break;
> +    case R_I2CDR: /* DATA */
> +        /* Reads are "pipelined" and so return the previous value of the
> +         * register
> +         */
> +        val = i2c->dbuf;
> +        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
> +            if (!i2c_bus_busy(i2c->bus) || I2CCR(MTX)) {
> +                LOG(LOG_GUEST_ERROR, "Read during addr or tx\n");
> +                i2c->dbuf = 0xff;
> +            } else {
> +                int ret = i2c_recv(i2c->bus);
> +                i2c->dbuf = (uint8_t)ret;
> +                DPRINTK(0, "READ %02x ('%c')\n", i2c->dbuf, (char)i2c->dbuf);
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +                mpc8540_update_irq(i2c);
> +            }
> +        } else {
> +            i2c->dbuf = 0xff;
> +            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy\n");
> +        }
> +        break;
> +    case R_I2CDFSRR: /* FILTER */
> +        val = i2c->filt;
> +        break;
> +    default:
> +        val = 0xff;
> +    }
> +
> +    DPRINTK(offset == 0xc ? 2 : 1, " read %08x -> %08x\n",
> +            (unsigned)offset, (unsigned)val);
> +    return val;
> +}
> +
> +static
> +void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    I2CState *i2c = opaque;
> +    uint32_t offset = addr;
> +
> +    DPRINTK(1, " write %08x <- %08x\n", (unsigned)offset, (unsigned)val);
> +
> +    switch (offset) {
> +    case R_I2CADR: /* ADDR */
> +        break;
> +    case R_I2CFDR: /* Freq Div. */
> +        i2c->freq = val & 0x3f;
> +        break;
> +    case R_I2CCR: /* CONTROL CCR */
> +        if (!FIELD_EX32(val, I2CCR, MEN)) {
> +            DPRINTK(0, "Not Enabled\n");
> +
> +        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
> +            /* MSTA 0 -> 1 is START */
> +
> +            I2CSR_SET(MBB, 1);
> +            DPRINTK(0, "START\n");
> +            i2c_end_transfer(i2c->bus); /* paranoia */
> +
> +        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
> +            /* MSTA 1 -> 0 is STOP */
> +
> +            I2CSR_SET(MBB, 0);
> +            DPRINTK(0, "STOP\n");
> +            i2c_end_transfer(i2c->bus);
> +
> +        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
> +            i2c_end_transfer(i2c->bus);
> +            I2CSR_SET(MBB, 1);
> +            DPRINTK(0, "REP START\n");
> +
> +        }
> +        /* RSTA always reads zero, bit 1 unusd */
> +        val &= 0xf9;
> +        i2c->ctrl = val;
> +        mpc8540_update_irq(i2c);
> +        break;
> +    case R_I2CSR: /* STATUS CSR */
> +        /* only MAL and MIF are writable */
> +        val &= 0x12;
> +        i2c->sts &= ~0x12;
> +        i2c->sts |= val;
> +        mpc8540_update_irq(i2c);
> +        break;
> +    case R_I2CDR: /* DATA CDR */
> +        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
> +            if (!i2c_bus_busy(i2c->bus)) {
> +                if (i2c_start_transfer(i2c->bus, val >> 1, val & 1)) {
> +                    LOG(LOG_GUEST_ERROR, "I2C no device %02x\n",
> +                        (unsigned)(val & 0xfe));
> +                } else {
> +                    DPRINTK(0, "ADDR %02x\n", (unsigned)(val & 0xfe));
> +                }
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +
> +            } else if (I2CCR(MTX)) {
> +                DPRINTK(0, "WRITE %02x\n", (unsigned)val);
> +                i2c_send(i2c->bus, val);
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +            } else {
> +                LOG(LOG_GUEST_ERROR, "I2CDR Write during read\n");
> +            }
> +            mpc8540_update_irq(i2c);
> +        } else {
> +            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy\n");
> +        }
> +        break;
> +    case R_I2CDFSRR: /* FILTER */
> +        val &= 0x3f;
> +        i2c->filt = val;
> +        break;
> +    }
> +
> +    DPRINTK(1, "I2CCR = %02x I2SCR = %02x\n", i2c->ctrl, i2c->sts);
> +}
> +
> +static const MemoryRegionOps i2c_ops = {
> +    .read = mpc8540_i2c_read,
> +    .write = mpc8540_i2c_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static
> +void mpc8540_i2c_reset(DeviceState *dev)
> +{
> +    I2CState *i2c = MPC8540_I2C(dev);
> +
> +    i2c->sts = 0x81; /* transfer complete and ack received */
> +}
> +
> +static int mpc8540_i2c_inst_init(SysBusDevice *dev)
> +{
> +    I2CState *i2c = MPC8540_I2C(dev);
> +
> +    i2c->bus = i2c_init_bus(&dev->parent_obj, "bus");
> +
> +    memory_region_init_io(&i2c->mmio, &dev->parent_obj.parent_obj,
> +                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
> +
> +    sysbus_init_mmio(dev, &i2c->mmio);
> +    sysbus_init_irq(dev, &i2c->irq);
> +    return 0;
> +}
> +
> +static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> +    k->init = &mpc8540_i2c_inst_init;
> +    dc->reset = &mpc8540_i2c_reset;
> +}
> +
> +static const TypeInfo mpc8540_i2c_type = {
> +    .name = TYPE_MPC8540_I2C,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(I2CState),
> +    .class_size = sizeof(SysBusDeviceClass),
> +    .class_init = mpc8540_i2c_class_init,
> +};
> +
> +static void mpc8540_i2c_register(void)
> +{
> +    type_register_static(&mpc8540_i2c_type);
> +}
> +
> +type_init(mpc8540_i2c_register)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr Michael Davidsaver
@ 2017-11-22  4:08   ` David Gibson
  2017-11-22 16:46     ` Michael Davidsaver
  0 siblings, 1 reply; 33+ messages in thread
From: David Gibson @ 2017-11-22  4:08 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1400 bytes --]

On Sun, Nov 19, 2017 at 09:24:16PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

You're adding what seems to be a fairly specific device to the general
e500 init - this again suggests that it should be split, putting
creation of devices under control of individual machines.

> ---
>  hw/ppc/e500.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 6f77844303..bef7d313d4 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -861,6 +861,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      qdev_init_nofail(dev);
>      ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>  
> +    dev = qdev_create(NULL, "mpc8540-i2c");
> +    object_property_add_child(qdev_get_machine(), "i2c[*]",
> +                              OBJECT(dev), NULL);
> +    qdev_init_nofail(dev);
> +    s = SYS_BUS_DEVICE(dev);
> +    memory_region_add_subregion(ccsr_addr_space, 0x3000,
> +                                sysbus_mmio_get_region(s, 0));
> +
>      mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
>  
>      /* Serial */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom Michael Davidsaver
@ 2017-11-22  4:10   ` David Gibson
  0 siblings, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-22  4:10 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 6770 bytes --]

On Sun, Nov 19, 2017 at 09:24:17PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Applied to ppc-for-2.12.

> ---
>  hw/nvram/Makefile.objs  |   1 +
>  hw/nvram/eeprom_at24c.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 206 insertions(+)
>  create mode 100644 hw/nvram/eeprom_at24c.c
> 
> diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
> index c018f6b2ff..0f4ee71dcb 100644
> --- a/hw/nvram/Makefile.objs
> +++ b/hw/nvram/Makefile.objs
> @@ -1,5 +1,6 @@
>  common-obj-$(CONFIG_DS1225Y) += ds1225y.o
>  common-obj-y += eeprom93xx.o
> +common-obj-y += eeprom_at24c.o
>  common-obj-y += fw_cfg.o
>  common-obj-y += chrp_nvram.o
>  common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
> diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
> new file mode 100644
> index 0000000000..efa3621ac6
> --- /dev/null
> +++ b/hw/nvram/eeprom_at24c.c
> @@ -0,0 +1,205 @@
> +/*
> + * *AT24C* series I2C EEPROM
> + *
> + * Copyright (c) 2015 Michael Davidsaver
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the LICENSE file in the top-level directory.
> + */
> +
> +#include <string.h>
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/hw.h"
> +#include "hw/i2c/i2c.h"
> +#include "sysemu/block-backend.h"
> +
> +/* #define DEBUG_AT24C */
> +
> +#ifdef DEBUG_AT24C
> +#define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__)
> +#else
> +#define DPRINTK(FMT, ...) do {} while (0)
> +#endif
> +
> +#define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
> +                            ## __VA_ARGS__)
> +
> +#define TYPE_AT24C_EE "at24c-eeprom"
> +#define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE)
> +
> +typedef struct EEPROMState {
> +    I2CSlave parent_obj;
> +
> +    /* address counter */
> +    uint16_t cur;
> +    /* total size in bytes */
> +    uint32_t rsize;
> +    bool writable;
> +    /* cells changed since last START? */
> +    bool changed;
> +    /* during WRITE, # of address bytes transfered */
> +    uint8_t haveaddr;
> +
> +    uint8_t *mem;
> +
> +    BlockBackend *blk;
> +} EEPROMState;
> +
> +static
> +int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
> +{
> +    EEPROMState *ee = container_of(s, EEPROMState, parent_obj);
> +
> +    switch (event) {
> +    case I2C_START_SEND:
> +    case I2C_START_RECV:
> +    case I2C_FINISH:
> +        ee->haveaddr = 0;
> +        DPRINTK("clear\n");
> +        if (ee->blk && ee->changed) {
> +            int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0);
> +            if (len != ee->rsize) {
> +                ERR(TYPE_AT24C_EE
> +                        " : failed to write backing file\n");
> +            }
> +            DPRINTK("Wrote to backing file\n");
> +        }
> +        ee->changed = false;
> +        break;
> +    case I2C_NACK:
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static
> +int at24c_eeprom_recv(I2CSlave *s)
> +{
> +    EEPROMState *ee = AT24C_EE(s);
> +    int ret;
> +
> +    ret = ee->mem[ee->cur];
> +
> +    ee->cur = (ee->cur + 1u) % ee->rsize;
> +    DPRINTK("Recv %02x %c\n", ret, ret);
> +
> +    return ret;
> +}
> +
> +static
> +int at24c_eeprom_send(I2CSlave *s, uint8_t data)
> +{
> +    EEPROMState *ee = AT24C_EE(s);
> +
> +    if (ee->haveaddr < 2) {
> +        ee->cur <<= 8;
> +        ee->cur |= data;
> +        ee->haveaddr++;
> +        if (ee->haveaddr == 2) {
> +            ee->cur %= ee->rsize;
> +            DPRINTK("Set pointer %04x\n", ee->cur);
> +        }
> +
> +    } else {
> +        if (ee->writable) {
> +            DPRINTK("Send %02x\n", data);
> +            ee->mem[ee->cur] = data;
> +            ee->changed = true;
> +        } else {
> +            DPRINTK("Send error %02x read-only\n", data);
> +        }
> +        ee->cur = (ee->cur + 1u) % ee->rsize;
> +
> +    }
> +
> +    return 0;
> +}
> +
> +static
> +int at24c_eeprom_init(I2CSlave *i2c)
> +{
> +    EEPROMState *ee = AT24C_EE(i2c);
> +
> +    ee->mem = g_malloc0(ee->rsize);
> +
> +    if (ee->blk) {
> +        int64_t len = blk_getlength(ee->blk);
> +
> +        if (len != ee->rsize) {
> +            ERR(TYPE_AT24C_EE " : Backing file size %lu != %u\n",
> +                    (unsigned long)len, (unsigned)ee->rsize);
> +            exit(1);
> +        }
> +
> +        if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
> +                         BLK_PERM_ALL, &error_fatal) < 0)
> +        {
> +            ERR(TYPE_AT24C_EE
> +                    " : Backing file incorrect permission\n");
> +            exit(1);
> +        }
> +    }
> +    return 0;
> +}
> +
> +static
> +void at24c_eeprom_reset(DeviceState *state)
> +{
> +    EEPROMState *ee = AT24C_EE(state);
> +
> +    ee->changed = false;
> +    ee->cur = 0;
> +    ee->haveaddr = 0;
> +
> +    memset(ee->mem, 0, ee->rsize);
> +
> +    if (ee->blk) {
> +        int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize);
> +
> +        if (len != ee->rsize) {
> +            ERR(TYPE_AT24C_EE
> +                    " : Failed initial sync with backing file\n");
> +        }
> +        DPRINTK("Reset read backing file\n");
> +    }
> +}
> +
> +static Property at24c_eeprom_props[] = {
> +    DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0),
> +    DEFINE_PROP_BOOL("writable", EEPROMState, writable, true),
> +    DEFINE_PROP_DRIVE("drive", EEPROMState, blk),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static
> +void at24c_eeprom_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> +
> +    k->init = &at24c_eeprom_init;
> +    k->event = &at24c_eeprom_event;
> +    k->recv = &at24c_eeprom_recv;
> +    k->send = &at24c_eeprom_send;
> +
> +    dc->props = at24c_eeprom_props;
> +    dc->reset = at24c_eeprom_reset;
> +}
> +
> +static
> +const TypeInfo at24c_eeprom_type = {
> +    .name = TYPE_AT24C_EE,
> +    .parent = TYPE_I2C_SLAVE,
> +    .instance_size = sizeof(EEPROMState),
> +    .class_size = sizeof(I2CSlaveClass),
> +    .class_init = at24c_eeprom_class_init,
> +};
> +
> +static void at24c_eeprom_register(void)
> +{
> +    type_register_static(&at24c_eeprom_type);
> +}
> +
> +type_init(at24c_eeprom_register)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC Michael Davidsaver
@ 2017-11-22  4:11   ` David Gibson
  0 siblings, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-22  4:11 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 10154 bytes --]

On Sun, Nov 19, 2017 at 09:24:18PM -0600, Michael Davidsaver wrote:
> only basic functionality implemented (read time and sram).
> no set time or alarms.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

I know there about a zillion different Dallas/Maxim sram/rtc chips,
many of which have a lot of similarities.  Is it possible to share any
code with the existing hw/timer/ds1338.c?

> ---
>  default-configs/ppc-softmmu.mak |   1 +
>  hw/timer/Makefile.objs          |   1 +
>  hw/timer/ds1375-i2c.c           | 293 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 295 insertions(+)
>  create mode 100644 hw/timer/ds1375-i2c.c
> 
> diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
> index bb225c6e46..04bfa79154 100644
> --- a/default-configs/ppc-softmmu.mak
> +++ b/default-configs/ppc-softmmu.mak
> @@ -52,3 +52,4 @@ CONFIG_SERIAL_ISA=y
>  CONFIG_MC146818RTC=y
>  CONFIG_ISA_TESTDEV=y
>  CONFIG_RS6000_MC=y
> +CONFIG_DS1375=y
> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> index 8c19eac3b6..6521d47367 100644
> --- a/hw/timer/Makefile.objs
> +++ b/hw/timer/Makefile.objs
> @@ -4,6 +4,7 @@ common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
>  common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
>  common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
>  common-obj-$(CONFIG_DS1338) += ds1338.o
> +common-obj-$(CONFIG_DS1375) += ds1375-i2c.o
>  common-obj-$(CONFIG_HPET) += hpet.o
>  common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
>  common-obj-$(CONFIG_M48T59) += m48t59.o
> diff --git a/hw/timer/ds1375-i2c.c b/hw/timer/ds1375-i2c.c
> new file mode 100644
> index 0000000000..dba9cc05c4
> --- /dev/null
> +++ b/hw/timer/ds1375-i2c.c
> @@ -0,0 +1,293 @@
> +/*
> + * Dallas/Maxim ds1375 I2C RTC w/ SRAM
> + *
> + * Copyright (c) 2017 Michael Davidsaver
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the LICENSE file in the top-level directory.
> + *
> + * Only basic functionality is modeled (time and user SRAM).
> + * Alarms not modeled.
> + */
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/log.h"
> +#include "qemu/timer.h"
> +#include "qemu/bcd.h"
> +#include "hw/hw.h"
> +#include "hw/registerfields.h"
> +#include "hw/i2c/i2c.h"
> +
> +#define DEBUG_DS1375
> +
> +#ifdef DEBUG_DS1375
> +#define DPRINTK(FMT, ...) printf(TYPE_DS1375 " : " FMT, ## __VA_ARGS__)
> +#else
> +#define DPRINTK(FMT, ...) do {} while (0)
> +#endif
> +
> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DS1375 " : " FMT, \
> +                            ## __VA_ARGS__)
> +
> +#define TYPE_DS1375 "ds1375"
> +#define DS1375(obj) OBJECT_CHECK(DS1375State, (obj), TYPE_DS1375)
> +
> +#define DS1375_REGSIZE 0x20
> +
> +#define R_SEC   (0x0)
> +#define R_MIN   (0x1)
> +#define R_HOUR  (0x2)
> +#define R_WDAY  (0x3)
> +#define R_DATE  (0x4)
> +#define R_MONTH (0x5)
> +#define R_YEAR  (0x6)
> +#define R_A1SEC   (0x7)
> +#define R_A1MIN   (0x8)
> +#define R_A1HOUR  (0x9)
> +#define R_A1DAY   (0xa)
> +#define R_A2SEC   (0xb)
> +#define R_A2MIN   (0xc)
> +#define R_A2HOUR  (0xd)
> +#define R_CTRL  (0xe)
> +#define R_STS   (0xf)
> +
> +FIELD(HOUR, SET12, 6, 1)
> +FIELD(HOUR, HOUR24, 0, 6)
> +FIELD(HOUR, AMPM, 5, 1)
> +FIELD(HOUR, HOUR12, 0, 5)
> +
> +FIELD(MONTH, MONTH, 0, 5)
> +FIELD(MONTH, CENTURY, 7, 1)
> +
> +FIELD(CTRL, ECLK, 7, 1)
> +FIELD(CTRL, CLKSEL, 5, 2)
> +FIELD(CTRL, RS, 3, 2)
> +FIELD(CTRL, INTCN, 2, 1)
> +FIELD(CTRL, A2IE, 1, 1)
> +FIELD(CTRL, A1IE, 0, 1)
> +
> +typedef struct DS1375State {
> +    I2CSlave parent_obj;
> +
> +    /* register address counter */
> +    uint8_t addr;
> +    /* when writing, whether the address has been sent */
> +    bool addrd;
> +
> +    int time_offset;
> +
> +    uint8_t regs[DS1375_REGSIZE];
> +} DS1375State;
> +
> +/* update current time register if clock enabled */
> +static
> +void ds1375_latch(DS1375State *ds)
> +{
> +    struct tm now;
> +
> +    if (!ARRAY_FIELD_EX32(ds->regs, CTRL, ECLK)) {
> +        return;
> +    }
> +
> +    qemu_get_timedate(&now, ds->time_offset);
> +
> +    DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)\n",
> +            now.tm_year, now.tm_mon, now.tm_mday,
> +            now.tm_hour, now.tm_min, now.tm_sec,
> +            now.tm_wday);
> +
> +    /* ensure unused bits are zero */
> +    memset(ds->regs, 0, R_YEAR + 1);
> +
> +    ds->regs[R_SEC] = to_bcd(now.tm_sec);
> +    ds->regs[R_MIN] = to_bcd(now.tm_min);
> +
> +    if (ARRAY_FIELD_EX32(ds->regs, HOUR, SET12) == 0) {
> +        /* 24 hour */
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour));
> +    } else {
> +        /* 12 hour am/pm */
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12);
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12, to_bcd(now.tm_hour % 12u));
> +    }
> +
> +    ds->regs[R_WDAY] = now.tm_wday; /* day of the week */
> +    ds->regs[R_DATE] = to_bcd(now.tm_mday);
> +
> +    ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1));
> +    ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year > 99);
> +
> +    ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u);
> +
> +    DPRINTK("Latched time\n");
> +}
> +
> +static
> +void ds1375_update(DS1375State *ds)
> +{
> +    struct tm now;
> +
> +    now.tm_sec = from_bcd(ds->regs[R_SEC]);
> +    now.tm_min = from_bcd(ds->regs[R_MIN]);
> +
> +    if (ARRAY_FIELD_EX32(ds->regs, HOUR, SET12)) {
> +        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR12));
> +        if (ARRAY_FIELD_EX32(ds->regs, HOUR, AMPM)) {
> +            now.tm_hour += 12;
> +        }
> +
> +    } else {
> +        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR24));
> +    }
> +
> +    now.tm_wday = from_bcd(ds->regs[R_WDAY]);
> +    now.tm_mday = from_bcd(ds->regs[R_DATE]);
> +    now.tm_mon = from_bcd(ARRAY_FIELD_EX32(ds->regs, MONTH, MONTH)) - 1;
> +
> +    now.tm_year = from_bcd(ds->regs[R_YEAR]) % 100u;
> +    if (ARRAY_FIELD_EX32(ds->regs, MONTH, CENTURY)) {
> +        now.tm_year += 100;
> +    }
> +
> +    DPRINTK("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)\n",
> +            now.tm_year, now.tm_mon, now.tm_mday,
> +            now.tm_hour, now.tm_min, now.tm_sec,
> +            now.tm_wday);
> +
> +    ds->time_offset = qemu_timedate_diff(&now);
> +    DPRINTK("Update offset = %d\n", ds->time_offset);
> +}
> +
> +static
> +int ds1375_event(I2CSlave *s, enum i2c_event event)
> +{
> +    DS1375State *ds = container_of(s, DS1375State, parent_obj);
> +
> +    switch (event) {
> +    case I2C_START_SEND:
> +        ds->addrd = false;
> +    case I2C_START_RECV:
> +        ds1375_latch(ds);
> +    case I2C_FINISH:
> +        DPRINTK("Event %d\n", (int)event);
> +    case I2C_NACK:
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static
> +int ds1375_recv(I2CSlave *s)
> +{
> +    DS1375State *ds = container_of(s, DS1375State, parent_obj);
> +    int ret = 0;
> +
> +    switch (ds->addr) {
> +    case R_SEC ... R_YEAR:
> +    case R_CTRL:
> +    case R_STS:
> +    case 0x10 ... 0x1f:
> +        ret = ds->regs[ds->addr];
> +        break;
> +    default:
> +        LOG(LOG_UNIMP, "Read from unimplemented (%02x) %02x\n", ds->addr, ret);
> +    }
> +
> +    DPRINTK("Recv (%02x) %02x\n", ds->addr, ret);
> +
> +    ds->addr++;
> +    ds->addr &= 0x1f;
> +    if (ds->addr == 0) {
> +        ds1375_latch(ds);
> +    }
> +
> +    return ret;
> +}
> +
> +static
> +int ds1375_send(I2CSlave *s, uint8_t data)
> +{
> +    DS1375State *ds = container_of(s, DS1375State, parent_obj);
> +
> +    if (!ds->addrd) {
> +        data &= 0x1f;
> +        ds->addr = data;
> +        DPRINTK("Set address pointer %02x\n", data);
> +        ds->addrd = true;
> +        return 0;
> +
> +    } else {
> +        DPRINTK("Send (%02x) %02x\n", ds->addr, data);
> +        switch (ds->addr) {
> +        case R_SEC ... R_YEAR:
> +            ds->regs[ds->addr] = data;
> +            ds1375_update(ds);
> +            break;
> +        case R_CTRL:
> +            if (data & 0x7) {
> +                LOG(LOG_UNIMP, "Alarm interrupt/output not modeled\n");
> +            }
> +            ds->regs[ds->addr] = data;
> +            break;
> +        case 0x10 ... 0x1f:
> +            ds->regs[ds->addr] = data;
> +            break;
> +        default:
> +            LOG(LOG_UNIMP, "Write to unimplemented (%02x) %02x\n",
> +                ds->addr, data);
> +        }
> +
> +        ds->addr++;
> +        ds->addr &= 0x1f;
> +        if (ds->addr == 0) {
> +            ds1375_latch(ds);
> +        }
> +
> +        return 0;
> +    }
> +}
> +
> +static
> +void ds1375_reset(DeviceState *device)
> +{
> +    DS1375State *ds = DS1375(device);
> +
> +    memset(ds->regs, 0, sizeof(ds->regs));
> +    /* TODO: not clear SRAM? */
> +
> +    /* Default to 12-hour mode */
> +    ARRAY_FIELD_DP32(ds->regs, CTRL, ECLK, 1);
> +
> +    ds->addr = 0;
> +
> +    /* do not re-zero time offset */
> +}
> +
> +static
> +void ds1375_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> +
> +    k->event = &ds1375_event;
> +    k->recv = &ds1375_recv;
> +    k->send = &ds1375_send;
> +
> +    dc->reset = &ds1375_reset;
> +}
> +
> +static
> +const TypeInfo ds1375_type = {
> +    .name = TYPE_DS1375,
> +    .parent = TYPE_I2C_SLAVE,
> +    .instance_size = sizeof(DS1375State),
> +    .class_size = sizeof(I2CSlaveClass),
> +    .class_init = ds1375_class_init,
> +};
> +
> +static void ds1375_register(void)
> +{
> +    type_register_static(&ds1375_type);
> +}
> +
> +type_init(ds1375_register)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC
  2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
                   ` (11 preceding siblings ...)
       [not found] ` <20171120032420.9134-3-mdavidsaver@gmail.com>
@ 2017-11-22  4:12 ` David Gibson
  2017-11-22  4:58   ` Michael Davidsaver
  12 siblings, 1 reply; 33+ messages in thread
From: David Gibson @ 2017-11-22  4:12 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2183 bytes --]

On Sun, Nov 19, 2017 at 09:24:08PM -0600, Michael Davidsaver wrote:
> This series adds simulation of MVME3100 powerpc SBCs, originally from Motorola,
> and now sold by Artesyn[1].  There are two variants differing in CPU
> speed and memory size.
> 
> I've been working on this sporadically for the past 2 year.  Recently I've
> finished all the features which I have in mind.  If this series is accepted
> there is a continuation which adds VME bus.  I've found it
> useful in software compatibility testing.  I wonder if there is
> any interest at large?
> 
> 
> There are two main parts of this series.  1-5 are changing code common
> with the "ppce500" and "mpc8544ds" boards, with the remainder being
> additions.
> 
> The changes are to how the CCSR region is handled in order to support
> the CCSRBAR register which allows the whole region to be relocated.
> Also added are a couple of memory and clock configuration registers
> which RTEMS guests read.
> 
> #3 is actually a minor issue I found recently with the mpc8544 PCI host bridge,
> which I'm uncertain how to address.  The host bridge device 0:0 identifies
> itself as a bridge, but doesn't properly implement the bridge config registers.
> This confuses Linux, which then does a full re-enumeration (successfully).
> 
> The rest are additions of an I2C controller, an I2C eeprom, an I2C RTC,
> and new board code.
> 
> My testing has been almost exclusively with an RTEMS guest[2].
> Though I have recently done a little with Linux.
> 
> RTEMS guests (and Linux too for now) require a stub bootloader[3] to
> put the system in the same state as the real bootloader.
> RTEMS has an unfortunately strong dependence on bootloader
> provided configuration (eg. it doesn't re-enumerate the PCI bus).

I've applied several patches from this series to ppc-for-2.12, others
I've commented on.  If you could address the comments and rebase
what's left on ppc-for-2.12, that would be great.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge
  2017-11-22  3:46   ` David Gibson
@ 2017-11-22  4:57     ` Michael Davidsaver
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-22  4:57 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1802 bytes --]

On 11/21/2017 09:46 PM, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:11PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> I'm not sure if you're saying you think there is a hardware bug which
> we're faithfully emulating, or a software bug.

I mean that the emulation is incorrect in that it just sets
config[PCI_HEADER_TYPE]==PCI_HEADER_TYPE_BRIDGE but does none of the
other initialization of the base-pci-bridge class.

I specifically observed Linux being confused by the fact that the
primary, secondary, and subordinate bus registers don't work right
because they're actually the BAR2 address register.

Further, it seems odd that a host bridge would identify itself as a
pci-to-pci bridge.  The mpc8540 doesn't.  The mpc8544 docs aren't clear,
and I don't have a real one to test.  My inclination is to remove the
line changing PCI_HEADER_TYPE, but I'm hesitant about breaking things.
Especially since this doesn't trigger mis-behavior in Linux or RTEMS.

>> ---
>>  hw/pci-host/ppce500.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
>> index f2d108bc8a..0e2833bd98 100644
>> --- a/hw/pci-host/ppce500.c
>> +++ b/hw/pci-host/ppce500.c
>> @@ -424,6 +424,9 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
>>      MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
>>  
>>      pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
>> +    /* BUG? identifies as PCI_HEADER_TYPE_BRIDGE but uses
>> +     * standard device config read/write
>> +     */
>>      d->config[PCI_HEADER_TYPE] =
>>          (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
>>          PCI_HEADER_TYPE_BRIDGE;
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC
  2017-11-22  4:12 ` [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC David Gibson
@ 2017-11-22  4:58   ` Michael Davidsaver
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-22  4:58 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 258 bytes --]

On 11/21/2017 10:12 PM, David Gibson wrote:
...
> I've applied several patches from this series to ppc-for-2.12, others
> I've commented on.  If you could address the comments and rebase
> what's left on ppc-for-2.12, that would be great.

Will do.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr
  2017-11-22  4:08   ` David Gibson
@ 2017-11-22 16:46     ` Michael Davidsaver
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-22 16:46 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1971 bytes --]

On 11/21/2017 10:08 PM, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:16PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> You're adding what seems to be a fairly specific device to the general
> e500 init - this again suggests that it should be split, putting
> creation of devices under control of individual machines.

I'll address the ppce500_init() part of this question separately.

In addition to the MPC8540, I find that documentation for the MPC8544
(modeled) and P2020 (un-modeled) show the same i2c controller registers.
 So I think it's reasonable for the generic ppce500 machine to have it
as well.

For what it's worth, the Linux driver for this unit
(drivers/i2c/busses/i2c-mpc.c) lists compatibility with a number of
other freescale SoCs with only some differences in clock selection (not
modeled).  The description for the module is:

> MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
>                    "MPC824x/83xx/85xx/86xx/512x/52xx processors");



>> ---
>>  hw/ppc/e500.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index 6f77844303..bef7d313d4 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -861,6 +861,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>      qdev_init_nofail(dev);
>>      ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>>  
>> +    dev = qdev_create(NULL, "mpc8540-i2c");
>> +    object_property_add_child(qdev_get_machine(), "i2c[*]",
>> +                              OBJECT(dev), NULL);
>> +    qdev_init_nofail(dev);
>> +    s = SYS_BUS_DEVICE(dev);
>> +    memory_region_add_subregion(ccsr_addr_space, 0x3000,
>> +                                sysbus_mmio_get_region(s, 0));
>> +
>>      mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
>>  
>>      /* Serial */
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 01/12] e500: add board config options
  2017-11-22  3:28   ` David Gibson
@ 2017-11-22 17:55     ` Michael Davidsaver
  2017-11-23 16:07       ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
  2017-11-24  0:21       ` [Qemu-devel] " David Gibson
  0 siblings, 2 replies; 33+ messages in thread
From: Michael Davidsaver @ 2017-11-22 17:55 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4865 bytes --]

On 11/21/2017 09:28 PM, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:09PM -0600, Michael Davidsaver wrote:
>> allow board code to skip common NIC and guest image setup
>> and configure decrementor frequency.
>> Existing boards unchanged.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> So, it's spelled "decrementer".
> 
> Other than that, the patch looks correct.  However having a big common
> function for overall init with a pile of ad-hoc configuration
> parameters is usually not a great way to go.  I think what we want
> instead is to eliminate ppce500_init(), instead doing the setup logic
> separately in each of the e500 machines.   The large common slabs of
> code can be helpers in e500.c, but the overall logic - including most
> of the things controlled by the current params - would be under the
> individual machine's control.

I agree that ppce500_init() is unwieldy, and am willing to spend some
time on cleanup.  I'm just not sure what to do.

I can see moving initialization of at least the serial, i2c, gpio, and
possibly MPIC and PCI host bridge into the e500-ccsr class.

I'm not sure what to do with all the device tree construction code in
e500.c, which has a bunch of hard coded register offsets.  A comment
here summarizes the problem nicely.

> /* TODO: parameterize */
> #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
> #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL

It seems desirable to avoid having these offsets appear in two different
files, which could allow them to get out of sync.

I had the idea of using an Interface to split up device tree
construction, and was encouraged to find PnvXScomInterfaceClass which
seems be a way of combining device tree construction in a device class.
Is this the way to go?

Some guidance would be appreciated.

Michael


>> ---
>>  hw/ppc/e500.c      | 8 ++++++--
>>  hw/ppc/e500.h      | 3 +++
>>  hw/ppc/e500plat.c  | 1 +
>>  hw/ppc/mpc8544ds.c | 1 +
>>  4 files changed, 11 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index 5cf0dabef3..9e7e1b29c4 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -826,7 +826,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>          env->mpic_iack = params->ccsrbar_base +
>>                           MPC8544_MPIC_REGS_OFFSET + 0xa0;
>>  
>> -        ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
>> +        ppc_booke_timers_init(cpu, params->decrementor_freq, PPC_TIMER_E500);
>>  
>>          /* Register reset handler */
>>          if (!i) {
>> @@ -899,7 +899,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>      if (!pci_bus)
>>          printf("couldn't create PCI controller!\n");
>>  
>> -    if (pci_bus) {
>> +    if (pci_bus && !params->tsec_nic) {
>>          /* Register network interfaces. */
>>          for (i = 0; i < nb_nics; i++) {
>>              pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
>> @@ -948,6 +948,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>                                      sysbus_mmio_get_region(s, 0));
>>      }
>>  
>> +    if (params->skip_load) {
>> +        return;
>> +    }
>> +
>>      /* Load kernel. */
>>      if (machine->kernel_filename) {
>>          kernel_base = cur_base;
>> diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
>> index 70ba1d8f4f..40f72f2de2 100644
>> --- a/hw/ppc/e500.h
>> +++ b/hw/ppc/e500.h
>> @@ -22,6 +22,9 @@ typedef struct PPCE500Params {
>>      hwaddr pci_mmio_base;
>>      hwaddr pci_mmio_bus_base;
>>      hwaddr spin_base;
>> +    uint32_t decrementor_freq; /* in Hz */
>> +    bool skip_load;
>> +    bool tsec_nic;
>>  } PPCE500Params;
>>  
>>  void ppce500_init(MachineState *machine, PPCE500Params *params);
>> diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
>> index e59e80fb9e..3d07987bd1 100644
>> --- a/hw/ppc/e500plat.c
>> +++ b/hw/ppc/e500plat.c
>> @@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
>>          .pci_mmio_base = 0xC00000000ULL,
>>          .pci_mmio_bus_base = 0xE0000000ULL,
>>          .spin_base = 0xFEF000000ULL,
>> +        .decrementor_freq = 400000000,
>>      };
>>  
>>      /* Older KVM versions don't support EPR which breaks guests when we announce
>> diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
>> index 1717953ec7..6d9931c475 100644
>> --- a/hw/ppc/mpc8544ds.c
>> +++ b/hw/ppc/mpc8544ds.c
>> @@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
>>          .pci_mmio_bus_base = 0xC0000000ULL,
>>          .pci_pio_base = 0xE1000000ULL,
>>          .spin_base = 0xEF000000ULL,
>> +        .decrementor_freq = 400000000,
>>      };
>>  
>>      if (machine->ram_size > 0xc0000000) {
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH 06/12] i2c: add mpc8540 i2c controller
  2017-11-20  3:24 ` [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller Michael Davidsaver
  2017-11-22  4:06   ` David Gibson
@ 2017-11-23 15:39   ` Cédric Le Goater
  2017-11-24  0:13     ` David Gibson
  1 sibling, 1 reply; 33+ messages in thread
From: Cédric Le Goater @ 2017-11-23 15:39 UTC (permalink / raw)
  To: Michael Davidsaver, Alexander Graf, David Gibson, qemu-ppc; +Cc: qemu-devel

Hello, 

The model should be QOM'ified. 

On 11/20/2017 04:24 AM, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  hw/i2c/Makefile.objs |   1 +
>  hw/i2c/mpc8540_i2c.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 288 insertions(+)
>  create mode 100644 hw/i2c/mpc8540_i2c.c
> 
> diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
> index 0594dea3ae..79af1dd901 100644
> --- a/hw/i2c/Makefile.objs
> +++ b/hw/i2c/Makefile.objs
> @@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
>  common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
>  obj-$(CONFIG_OMAP) += omap_i2c.o
>  obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
> +obj-$(CONFIG_E500) += mpc8540_i2c.o
> diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
> new file mode 100644
> index 0000000000..884052cc9b
> --- /dev/null
> +++ b/hw/i2c/mpc8540_i2c.c
> @@ -0,0 +1,287 @@
> +/*
> + * MPC8540 I2C bus interface
> + * As described in
> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
> + * Part 2 chapter 11
> + *
> + * Copyright (c) 2015 Michael Davidsaver
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the LICENSE file in the top-level directory.
> + */
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "hw/hw.h"
> +#include "hw/registerfields.h"
> +#include "hw/i2c/i2c.h"
> +#include "hw/sysbus.h"
> +
> +/* #define DEBUG_LVL 0 */
> +
> +#ifdef DEBUG_LVL
> +#define DPRINTK(LVL, FMT, ...) do { if ((LVL) <= DEBUG_LVL) { \
> +    printf(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); } } while (0)

hmm, I am not sure 'printfs' are welcomed in QEMU. 

> +#else
> +#define DPRINTK(LVL, FMT, ...) do {} while (0)
> +#endif
> +
> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
> +    " : " FMT, ## __VA_ARGS__)
>
> +#define TYPE_MPC8540_I2C "mpc8540-i2c"
> +#define MPC8540_I2C(obj) OBJECT_CHECK(I2CState, (obj), TYPE_MPC8540_I2C)
> +
> +/* offsets relative to CCSR offset 0x3000 */
> +#define R_I2CADR (0)
> +#define R_I2CFDR (4)
> +#define R_I2CCR  (8)
> +#define R_I2CSR  (0xc)
> +#define R_I2CDR  (0x10)
> +#define R_I2CDFSRR (0x14)
> +
> +FIELD(I2CCR, MEN, 7, 1)
> +FIELD(I2CCR, MIEN, 6, 1)
> +FIELD(I2CCR, MSTA, 5, 1)
> +FIELD(I2CCR, MTX, 4, 1)
> +FIELD(I2CCR, TXAK, 3, 1)
> +FIELD(I2CCR, RSTA, 2, 1)
> +FIELD(I2CCR, BCST, 0, 1)
> +
> +FIELD(I2CSR, MCF, 7, 1)
> +FIELD(I2CSR, MAAS, 6, 1)
> +FIELD(I2CSR, MBB, 5, 1)
> +FIELD(I2CSR, MAL, 4, 1)
> +FIELD(I2CSR, BCSTM, 3, 1)
> +FIELD(I2CSR, SRW, 2, 1)
> +FIELD(I2CSR, MIF, 1, 1)
> +FIELD(I2CSR, RXAK, 0, 1)
> +
> +typedef struct I2CState {
> +    SysBusDevice parent_obj;
> +
> +    I2CBus *bus;
> +
> +    uint8_t ctrl, sts;
> +    uint8_t freq, filt;
> +    /* Reads are pipelined, this is the next data value */
> +    uint8_t dbuf;
> +
> +    qemu_irq irq;
> +
> +    MemoryRegion mmio;
> +} I2CState;

May be use MPC8540I2CState ? I would put the definition in a header file  

> +#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
> +#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
> +
> +#define I2CSR_SET(BIT, VAL) do {\
> +        i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
> +    } while (0)
> +
> +static
> +void mpc8540_update_irq(I2CState *i2c)
> +{
> +    int ena = i2c->ctrl & 0x40,
> +        sts = i2c->sts & 0x02,
> +        act = !!(ena && sts);

OK. why not :) Three distinct lines would be better. This is minor.

> +    DPRINTK(1, "IRQ %c ena %c sts %c\n",
> +            act ? 'X' : '_',
> +            ena ? 'X' : '_',
> +            sts ? 'X' : '_');
> +
> +    qemu_set_irq(i2c->irq, act);
> +}
> +
> +static
> +uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    I2CState *i2c = opaque;
> +    uint32_t val, offset = addr;

This 'offset = addr' looks useless. do you really need it ? 


> +
> +    switch (offset) {
> +    case R_I2CADR: /* ADDR */
> +        val = 0;
> +        break;
> +    case R_I2CFDR: /* Freq Div. */
> +        val = i2c->freq;
> +        break;
> +    case R_I2CCR: /* CONTROL */
> +        val = i2c->ctrl & ~0x06;
> +        break;
> +    case R_I2CSR: /* STATUS */
> +        val = i2c->sts;
> +        break;
> +    case R_I2CDR: /* DATA */
> +        /* Reads are "pipelined" and so return the previous value of the
> +         * register
> +         */
> +        val = i2c->dbuf;
> +        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
> +            if (!i2c_bus_busy(i2c->bus) || I2CCR(MTX)) {
> +                LOG(LOG_GUEST_ERROR, "Read during addr or tx\n");
> +                i2c->dbuf = 0xff;
> +            } else {
> +                int ret = i2c_recv(i2c->bus);
> +                i2c->dbuf = (uint8_t)ret;
> +                DPRINTK(0, "READ %02x ('%c')\n", i2c->dbuf, (char)i2c->dbuf);
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +                mpc8540_update_irq(i2c);
> +            }
> +        } else {
> +            i2c->dbuf = 0xff;
> +            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy\n");
> +        }
> +        break;
> +    case R_I2CDFSRR: /* FILTER */
> +        val = i2c->filt;
> +        break;
> +    default:
> +        val = 0xff;
> +    }
> +
> +    DPRINTK(offset == 0xc ? 2 : 1, " read %08x -> %08x\n",
> +            (unsigned)offset, (unsigned)val);
> +    return val;
> +}
> +
> +static
> +void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    I2CState *i2c = opaque;
> +    uint32_t offset = addr;
> +
> +    DPRINTK(1, " write %08x <- %08x\n", (unsigned)offset, (unsigned)val);
> +
> +    switch (offset) {
> +    case R_I2CADR: /* ADDR */
> +        break;
> +    case R_I2CFDR: /* Freq Div. */
> +        i2c->freq = val & 0x3f;
> +        break;
> +    case R_I2CCR: /* CONTROL CCR */
> +        if (!FIELD_EX32(val, I2CCR, MEN)) {
> +            DPRINTK(0, "Not Enabled\n");
> +
> +        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
> +            /* MSTA 0 -> 1 is START */
> +
> +            I2CSR_SET(MBB, 1);
> +            DPRINTK(0, "START\n");
> +            i2c_end_transfer(i2c->bus); /* paranoia */
> +
> +        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
> +            /* MSTA 1 -> 0 is STOP */
> +
> +            I2CSR_SET(MBB, 0);
> +            DPRINTK(0, "STOP\n");
> +            i2c_end_transfer(i2c->bus);
> +
> +        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
> +            i2c_end_transfer(i2c->bus);
> +            I2CSR_SET(MBB, 1);
> +            DPRINTK(0, "REP START\n");
> +
> +        }
> +        /* RSTA always reads zero, bit 1 unusd */
> +        val &= 0xf9;
> +        i2c->ctrl = val;
> +        mpc8540_update_irq(i2c);
> +        break;
> +    case R_I2CSR: /* STATUS CSR */
> +        /* only MAL and MIF are writable */
> +        val &= 0x12;
> +        i2c->sts &= ~0x12;
> +        i2c->sts |= val;
> +        mpc8540_update_irq(i2c);
> +        break;
> +    case R_I2CDR: /* DATA CDR */
> +        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
> +            if (!i2c_bus_busy(i2c->bus)) {
> +                if (i2c_start_transfer(i2c->bus, val >> 1, val & 1)) {
> +                    LOG(LOG_GUEST_ERROR, "I2C no device %02x\n",
> +                        (unsigned)(val & 0xfe));
> +                } else {
> +                    DPRINTK(0, "ADDR %02x\n", (unsigned)(val & 0xfe));
> +                }
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +
> +            } else if (I2CCR(MTX)) {
> +                DPRINTK(0, "WRITE %02x\n", (unsigned)val);
> +                i2c_send(i2c->bus, val);
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +            } else {
> +                LOG(LOG_GUEST_ERROR, "I2CDR Write during read\n");
> +            }
> +            mpc8540_update_irq(i2c);
> +        } else {
> +            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy\n");
> +        }
> +        break;
> +    case R_I2CDFSRR: /* FILTER */
> +        val &= 0x3f;
> +        i2c->filt = val;
> +        break;
> +    }
> +
> +    DPRINTK(1, "I2CCR = %02x I2SCR = %02x\n", i2c->ctrl, i2c->sts);
> +}
> +
> +static const MemoryRegionOps i2c_ops = {
> +    .read = mpc8540_i2c_read,
> +    .write = mpc8540_i2c_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static
> +void mpc8540_i2c_reset(DeviceState *dev)
> +{
> +    I2CState *i2c = MPC8540_I2C(dev);
> +
> +    i2c->sts = 0x81; /* transfer complete and ack received */
> +}
> +
> +static int mpc8540_i2c_inst_init(SysBusDevice *dev)
> +{
> +    I2CState *i2c = MPC8540_I2C(dev);
> +
> +    i2c->bus = i2c_init_bus(&dev->parent_obj, "bus");
> +
> +    memory_region_init_io(&i2c->mmio, &dev->parent_obj.parent_obj,
> +                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
> +
> +    sysbus_init_mmio(dev, &i2c->mmio);
> +    sysbus_init_irq(dev, &i2c->irq);
> +    return 0;
> +}

This should be a realize routine.

C.


> +static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> +    k->init = &mpc8540_i2c_inst_init;
> +    dc->reset = &mpc8540_i2c_reset;
> +}
> +
> +static const TypeInfo mpc8540_i2c_type = {
> +    .name = TYPE_MPC8540_I2C,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(I2CState),
> +    .class_size = sizeof(SysBusDeviceClass),
> +    .class_init = mpc8540_i2c_class_init,
> +};
> +
> +static void mpc8540_i2c_register(void)
> +{
> +    type_register_static(&mpc8540_i2c_type);
> +}
> +
> +type_init(mpc8540_i2c_register)
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH 01/12] e500: add board config options
  2017-11-22 17:55     ` Michael Davidsaver
@ 2017-11-23 16:07       ` Cédric Le Goater
  2017-11-24  0:21       ` [Qemu-devel] " David Gibson
  1 sibling, 0 replies; 33+ messages in thread
From: Cédric Le Goater @ 2017-11-23 16:07 UTC (permalink / raw)
  To: Michael Davidsaver, David Gibson; +Cc: qemu-ppc, qemu-devel

On 11/22/2017 06:55 PM, Michael Davidsaver wrote:
> On 11/21/2017 09:28 PM, David Gibson wrote:
>> On Sun, Nov 19, 2017 at 09:24:09PM -0600, Michael Davidsaver wrote:
>>> allow board code to skip common NIC and guest image setup
>>> and configure decrementor frequency.
>>> Existing boards unchanged.
>>>
>>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
>>
>> So, it's spelled "decrementer".
>>
>> Other than that, the patch looks correct.  However having a big common
>> function for overall init with a pile of ad-hoc configuration
>> parameters is usually not a great way to go.  I think what we want
>> instead is to eliminate ppce500_init(), instead doing the setup logic
>> separately in each of the e500 machines.   The large common slabs of
>> code can be helpers in e500.c, but the overall logic - including most
>> of the things controlled by the current params - would be under the
>> individual machine's control.
> 
> I agree that ppce500_init() is unwieldy, and am willing to spend some
> time on cleanup.  I'm just not sure what to do.
> 
> I can see moving initialization of at least the serial, i2c, gpio, and
> possibly MPIC and PCI host bridge into the e500-ccsr class.

each of these controllers should have a QOM model possibly.

I think that the part above : 

	    /* Load kernel. */

is machine specific and the part below is generic and could be called 
from each machine init routine. You would still need some op/struct for 
the device tree.

> I'm not sure what to do with all the device tree construction code in
> e500.c, which has a bunch of hard coded register offsets.  A comment
> here summarizes the problem nicely.
> 
>> /* TODO: parameterize */
>> #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
>> #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
> 
> It seems desirable to avoid having these offsets appear in two different
> files, which could allow them to get out of sync.
> 
> I had the idea of using an Interface to split up device tree
> construction, and was encouraged to find PnvXScomInterfaceClass which
> seems be a way of combining device tree construction in a device class.
> Is this the way to go?

yes. You would need to QOM'ify the whole machine and have all controllers
be children of a 'board' object to loop on them.

> Some guidance would be appreciated.

The models of the ARM SoC are good examples to follow. You could check 
the Aspeed machines which have been slowly growing and which have had 
some good reviews from Peter. The ARM machines are all QOM'ified and 
that might be difficult to apply to the e500 boards quickly. At least, 
the models for the new controllers should follow QOM. It will ease the 
future work.      

Thanks,

C. 

> 
> Michael
> 
> 
>>> ---
>>>  hw/ppc/e500.c      | 8 ++++++--
>>>  hw/ppc/e500.h      | 3 +++
>>>  hw/ppc/e500plat.c  | 1 +
>>>  hw/ppc/mpc8544ds.c | 1 +
>>>  4 files changed, 11 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>>> index 5cf0dabef3..9e7e1b29c4 100644
>>> --- a/hw/ppc/e500.c
>>> +++ b/hw/ppc/e500.c
>>> @@ -826,7 +826,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>>          env->mpic_iack = params->ccsrbar_base +
>>>                           MPC8544_MPIC_REGS_OFFSET + 0xa0;
>>>  
>>> -        ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
>>> +        ppc_booke_timers_init(cpu, params->decrementor_freq, PPC_TIMER_E500);
>>>  
>>>          /* Register reset handler */
>>>          if (!i) {
>>> @@ -899,7 +899,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>>      if (!pci_bus)
>>>          printf("couldn't create PCI controller!\n");
>>>  
>>> -    if (pci_bus) {
>>> +    if (pci_bus && !params->tsec_nic) {
>>>          /* Register network interfaces. */
>>>          for (i = 0; i < nb_nics; i++) {
>>>              pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
>>> @@ -948,6 +948,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>>                                      sysbus_mmio_get_region(s, 0));
>>>      }
>>>  
>>> +    if (params->skip_load) {
>>> +        return;
>>> +    }
>>> +
>>>      /* Load kernel. */
>>>      if (machine->kernel_filename) {
>>>          kernel_base = cur_base;
>>> diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
>>> index 70ba1d8f4f..40f72f2de2 100644
>>> --- a/hw/ppc/e500.h
>>> +++ b/hw/ppc/e500.h
>>> @@ -22,6 +22,9 @@ typedef struct PPCE500Params {
>>>      hwaddr pci_mmio_base;
>>>      hwaddr pci_mmio_bus_base;
>>>      hwaddr spin_base;
>>> +    uint32_t decrementor_freq; /* in Hz */
>>> +    bool skip_load;
>>> +    bool tsec_nic;
>>>  } PPCE500Params;
>>>  
>>>  void ppce500_init(MachineState *machine, PPCE500Params *params);
>>> diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
>>> index e59e80fb9e..3d07987bd1 100644
>>> --- a/hw/ppc/e500plat.c
>>> +++ b/hw/ppc/e500plat.c
>>> @@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
>>>          .pci_mmio_base = 0xC00000000ULL,
>>>          .pci_mmio_bus_base = 0xE0000000ULL,
>>>          .spin_base = 0xFEF000000ULL,
>>> +        .decrementor_freq = 400000000,
>>>      };
>>>  
>>>      /* Older KVM versions don't support EPR which breaks guests when we announce
>>> diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
>>> index 1717953ec7..6d9931c475 100644
>>> --- a/hw/ppc/mpc8544ds.c
>>> +++ b/hw/ppc/mpc8544ds.c
>>> @@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
>>>          .pci_mmio_bus_base = 0xC0000000ULL,
>>>          .pci_pio_base = 0xE1000000ULL,
>>>          .spin_base = 0xEF000000ULL,
>>> +        .decrementor_freq = 400000000,
>>>      };
>>>  
>>>      if (machine->ram_size > 0xc0000000) {
>>
> 
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH 06/12] i2c: add mpc8540 i2c controller
  2017-11-23 15:39   ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
@ 2017-11-24  0:13     ` David Gibson
  0 siblings, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-24  0:13 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Michael Davidsaver, Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 11334 bytes --]

On Thu, Nov 23, 2017 at 04:39:10PM +0100, Cédric Le Goater wrote:
> Hello, 
> 
> The model should be QOM'ified. 
> 
> On 11/20/2017 04:24 AM, Michael Davidsaver wrote:
> > Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> > ---
> >  hw/i2c/Makefile.objs |   1 +
> >  hw/i2c/mpc8540_i2c.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 288 insertions(+)
> >  create mode 100644 hw/i2c/mpc8540_i2c.c
> > 
> > diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
> > index 0594dea3ae..79af1dd901 100644
> > --- a/hw/i2c/Makefile.objs
> > +++ b/hw/i2c/Makefile.objs
> > @@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
> >  common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
> >  obj-$(CONFIG_OMAP) += omap_i2c.o
> >  obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
> > +obj-$(CONFIG_E500) += mpc8540_i2c.o
> > diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
> > new file mode 100644
> > index 0000000000..884052cc9b
> > --- /dev/null
> > +++ b/hw/i2c/mpc8540_i2c.c
> > @@ -0,0 +1,287 @@
> > +/*
> > + * MPC8540 I2C bus interface
> > + * As described in
> > + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
> > + * Part 2 chapter 11
> > + *
> > + * Copyright (c) 2015 Michael Davidsaver
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2.  See
> > + * the LICENSE file in the top-level directory.
> > + */
> > +#include "qemu/osdep.h"
> > +#include "qemu/log.h"
> > +#include "hw/hw.h"
> > +#include "hw/registerfields.h"
> > +#include "hw/i2c/i2c.h"
> > +#include "hw/sysbus.h"
> > +
> > +/* #define DEBUG_LVL 0 */
> > +
> > +#ifdef DEBUG_LVL
> > +#define DPRINTK(LVL, FMT, ...) do { if ((LVL) <= DEBUG_LVL) { \
> > +    printf(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); } } while (0)
> 
> hmm, I am not sure 'printfs' are welcomed in QEMU.

They're not, tracepoints are preferred.  I tend to be ok with debug
macros like this, though, since they can be convenient.  It should at
least be fprintf(stderr, ...) though.
> 
> > +#else
> > +#define DPRINTK(LVL, FMT, ...) do {} while (0)
> > +#endif
> > +
> > +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
> > +    " : " FMT, ## __VA_ARGS__)
> >
> > +#define TYPE_MPC8540_I2C "mpc8540-i2c"
> > +#define MPC8540_I2C(obj) OBJECT_CHECK(I2CState, (obj), TYPE_MPC8540_I2C)
> > +
> > +/* offsets relative to CCSR offset 0x3000 */
> > +#define R_I2CADR (0)
> > +#define R_I2CFDR (4)
> > +#define R_I2CCR  (8)
> > +#define R_I2CSR  (0xc)
> > +#define R_I2CDR  (0x10)
> > +#define R_I2CDFSRR (0x14)
> > +
> > +FIELD(I2CCR, MEN, 7, 1)
> > +FIELD(I2CCR, MIEN, 6, 1)
> > +FIELD(I2CCR, MSTA, 5, 1)
> > +FIELD(I2CCR, MTX, 4, 1)
> > +FIELD(I2CCR, TXAK, 3, 1)
> > +FIELD(I2CCR, RSTA, 2, 1)
> > +FIELD(I2CCR, BCST, 0, 1)
> > +
> > +FIELD(I2CSR, MCF, 7, 1)
> > +FIELD(I2CSR, MAAS, 6, 1)
> > +FIELD(I2CSR, MBB, 5, 1)
> > +FIELD(I2CSR, MAL, 4, 1)
> > +FIELD(I2CSR, BCSTM, 3, 1)
> > +FIELD(I2CSR, SRW, 2, 1)
> > +FIELD(I2CSR, MIF, 1, 1)
> > +FIELD(I2CSR, RXAK, 0, 1)
> > +
> > +typedef struct I2CState {
> > +    SysBusDevice parent_obj;
> > +
> > +    I2CBus *bus;
> > +
> > +    uint8_t ctrl, sts;
> > +    uint8_t freq, filt;
> > +    /* Reads are pipelined, this is the next data value */
> > +    uint8_t dbuf;
> > +
> > +    qemu_irq irq;
> > +
> > +    MemoryRegion mmio;
> > +} I2CState;
> 
> May be use MPC8540I2CState ? I would put the definition in a header file  
> 
> > +#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
> > +#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
> > +
> > +#define I2CSR_SET(BIT, VAL) do {\
> > +        i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
> > +    } while (0)
> > +
> > +static
> > +void mpc8540_update_irq(I2CState *i2c)
> > +{
> > +    int ena = i2c->ctrl & 0x40,
> > +        sts = i2c->sts & 0x02,
> > +        act = !!(ena && sts);
> 
> OK. why not :) Three distinct lines would be better. This is minor.
> 
> > +    DPRINTK(1, "IRQ %c ena %c sts %c\n",
> > +            act ? 'X' : '_',
> > +            ena ? 'X' : '_',
> > +            sts ? 'X' : '_');
> > +
> > +    qemu_set_irq(i2c->irq, act);
> > +}
> > +
> > +static
> > +uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
> > +{
> > +    I2CState *i2c = opaque;
> > +    uint32_t val, offset = addr;
> 
> This 'offset = addr' looks useless. do you really need it ? 
> 
> 
> > +
> > +    switch (offset) {
> > +    case R_I2CADR: /* ADDR */
> > +        val = 0;
> > +        break;
> > +    case R_I2CFDR: /* Freq Div. */
> > +        val = i2c->freq;
> > +        break;
> > +    case R_I2CCR: /* CONTROL */
> > +        val = i2c->ctrl & ~0x06;
> > +        break;
> > +    case R_I2CSR: /* STATUS */
> > +        val = i2c->sts;
> > +        break;
> > +    case R_I2CDR: /* DATA */
> > +        /* Reads are "pipelined" and so return the previous value of the
> > +         * register
> > +         */
> > +        val = i2c->dbuf;
> > +        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
> > +            if (!i2c_bus_busy(i2c->bus) || I2CCR(MTX)) {
> > +                LOG(LOG_GUEST_ERROR, "Read during addr or tx\n");
> > +                i2c->dbuf = 0xff;
> > +            } else {
> > +                int ret = i2c_recv(i2c->bus);
> > +                i2c->dbuf = (uint8_t)ret;
> > +                DPRINTK(0, "READ %02x ('%c')\n", i2c->dbuf, (char)i2c->dbuf);
> > +                I2CSR_SET(MIF, 1);
> > +                I2CSR_SET(RXAK, 0);
> > +                mpc8540_update_irq(i2c);
> > +            }
> > +        } else {
> > +            i2c->dbuf = 0xff;
> > +            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy\n");
> > +        }
> > +        break;
> > +    case R_I2CDFSRR: /* FILTER */
> > +        val = i2c->filt;
> > +        break;
> > +    default:
> > +        val = 0xff;
> > +    }
> > +
> > +    DPRINTK(offset == 0xc ? 2 : 1, " read %08x -> %08x\n",
> > +            (unsigned)offset, (unsigned)val);
> > +    return val;
> > +}
> > +
> > +static
> > +void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> > +{
> > +    I2CState *i2c = opaque;
> > +    uint32_t offset = addr;
> > +
> > +    DPRINTK(1, " write %08x <- %08x\n", (unsigned)offset, (unsigned)val);
> > +
> > +    switch (offset) {
> > +    case R_I2CADR: /* ADDR */
> > +        break;
> > +    case R_I2CFDR: /* Freq Div. */
> > +        i2c->freq = val & 0x3f;
> > +        break;
> > +    case R_I2CCR: /* CONTROL CCR */
> > +        if (!FIELD_EX32(val, I2CCR, MEN)) {
> > +            DPRINTK(0, "Not Enabled\n");
> > +
> > +        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
> > +            /* MSTA 0 -> 1 is START */
> > +
> > +            I2CSR_SET(MBB, 1);
> > +            DPRINTK(0, "START\n");
> > +            i2c_end_transfer(i2c->bus); /* paranoia */
> > +
> > +        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
> > +            /* MSTA 1 -> 0 is STOP */
> > +
> > +            I2CSR_SET(MBB, 0);
> > +            DPRINTK(0, "STOP\n");
> > +            i2c_end_transfer(i2c->bus);
> > +
> > +        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
> > +            i2c_end_transfer(i2c->bus);
> > +            I2CSR_SET(MBB, 1);
> > +            DPRINTK(0, "REP START\n");
> > +
> > +        }
> > +        /* RSTA always reads zero, bit 1 unusd */
> > +        val &= 0xf9;
> > +        i2c->ctrl = val;
> > +        mpc8540_update_irq(i2c);
> > +        break;
> > +    case R_I2CSR: /* STATUS CSR */
> > +        /* only MAL and MIF are writable */
> > +        val &= 0x12;
> > +        i2c->sts &= ~0x12;
> > +        i2c->sts |= val;
> > +        mpc8540_update_irq(i2c);
> > +        break;
> > +    case R_I2CDR: /* DATA CDR */
> > +        if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
> > +            if (!i2c_bus_busy(i2c->bus)) {
> > +                if (i2c_start_transfer(i2c->bus, val >> 1, val & 1)) {
> > +                    LOG(LOG_GUEST_ERROR, "I2C no device %02x\n",
> > +                        (unsigned)(val & 0xfe));
> > +                } else {
> > +                    DPRINTK(0, "ADDR %02x\n", (unsigned)(val & 0xfe));
> > +                }
> > +                I2CSR_SET(MIF, 1);
> > +                I2CSR_SET(RXAK, 0);
> > +
> > +            } else if (I2CCR(MTX)) {
> > +                DPRINTK(0, "WRITE %02x\n", (unsigned)val);
> > +                i2c_send(i2c->bus, val);
> > +                I2CSR_SET(MIF, 1);
> > +                I2CSR_SET(RXAK, 0);
> > +            } else {
> > +                LOG(LOG_GUEST_ERROR, "I2CDR Write during read\n");
> > +            }
> > +            mpc8540_update_irq(i2c);
> > +        } else {
> > +            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy\n");
> > +        }
> > +        break;
> > +    case R_I2CDFSRR: /* FILTER */
> > +        val &= 0x3f;
> > +        i2c->filt = val;
> > +        break;
> > +    }
> > +
> > +    DPRINTK(1, "I2CCR = %02x I2SCR = %02x\n", i2c->ctrl, i2c->sts);
> > +}
> > +
> > +static const MemoryRegionOps i2c_ops = {
> > +    .read = mpc8540_i2c_read,
> > +    .write = mpc8540_i2c_write,
> > +    .endianness = DEVICE_NATIVE_ENDIAN,
> > +    .impl = {
> > +        .min_access_size = 1,
> > +        .max_access_size = 1,
> > +    },
> > +};
> > +
> > +static
> > +void mpc8540_i2c_reset(DeviceState *dev)
> > +{
> > +    I2CState *i2c = MPC8540_I2C(dev);
> > +
> > +    i2c->sts = 0x81; /* transfer complete and ack received */
> > +}
> > +
> > +static int mpc8540_i2c_inst_init(SysBusDevice *dev)
> > +{
> > +    I2CState *i2c = MPC8540_I2C(dev);
> > +
> > +    i2c->bus = i2c_init_bus(&dev->parent_obj, "bus");
> > +
> > +    memory_region_init_io(&i2c->mmio, &dev->parent_obj.parent_obj,
> > +                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
> > +
> > +    sysbus_init_mmio(dev, &i2c->mmio);
> > +    sysbus_init_irq(dev, &i2c->irq);
> > +    return 0;
> > +}
> 
> This should be a realize routine.

Ah.. that's a good point, actually.  On that basis, I'm pulling the
draft patch from ppc-for-2.12

> > +static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> > +
> > +    k->init = &mpc8540_i2c_inst_init;
> > +    dc->reset = &mpc8540_i2c_reset;
> > +}
> > +
> > +static const TypeInfo mpc8540_i2c_type = {
> > +    .name = TYPE_MPC8540_I2C,
> > +    .parent = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(I2CState),
> > +    .class_size = sizeof(SysBusDeviceClass),
> > +    .class_init = mpc8540_i2c_class_init,
> > +};
> > +
> > +static void mpc8540_i2c_register(void)
> > +{
> > +    type_register_static(&mpc8540_i2c_type);
> > +}
> > +
> > +type_init(mpc8540_i2c_register)
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 01/12] e500: add board config options
  2017-11-22 17:55     ` Michael Davidsaver
  2017-11-23 16:07       ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
@ 2017-11-24  0:21       ` David Gibson
  1 sibling, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-11-24  0:21 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2884 bytes --]

On Wed, Nov 22, 2017 at 11:55:04AM -0600, Michael Davidsaver wrote:
> On 11/21/2017 09:28 PM, David Gibson wrote:
> > On Sun, Nov 19, 2017 at 09:24:09PM -0600, Michael Davidsaver wrote:
> >> allow board code to skip common NIC and guest image setup
> >> and configure decrementor frequency.
> >> Existing boards unchanged.
> >>
> >> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> > 
> > So, it's spelled "decrementer".
> > 
> > Other than that, the patch looks correct.  However having a big common
> > function for overall init with a pile of ad-hoc configuration
> > parameters is usually not a great way to go.  I think what we want
> > instead is to eliminate ppce500_init(), instead doing the setup logic
> > separately in each of the e500 machines.   The large common slabs of
> > code can be helpers in e500.c, but the overall logic - including most
> > of the things controlled by the current params - would be under the
> > individual machine's control.
> 
> I agree that ppce500_init() is unwieldy, and am willing to spend some
> time on cleanup.  I'm just not sure what to do.
> 
> I can see moving initialization of at least the serial, i2c, gpio, and
> possibly MPIC and PCI host bridge into the e500-ccsr class.
> 
> I'm not sure what to do with all the device tree construction code in
> e500.c, which has a bunch of hard coded register offsets.  A comment
> here summarizes the problem nicely.

So, those aren't bad ideas for cleanups, but I'm not going to insist
on that before merging this stuff.  What I'm after is something
simpler.  At the moment the structure looks something like this:

	machine_init() {
		common_init(big pile of parameters);
	}

	common_init() {
		chunk1;
		if (param1)
			chunk2;
		chunk3;
		if (param2)
			chunk4;
		...
	}

What I would prefer is:

	machine_init1() {
		chunk1();
		chunk2(param1)
		chunk3(param3);
	}

	machine_init2() {
		chunk1();
		chunk3(param3);
		chunk4(param2);
	}

> 
> > /* TODO: parameterize */
> > #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
> > #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
> 
> It seems desirable to avoid having these offsets appear in two different
> files, which could allow them to get out of sync.
> 
> I had the idea of using an Interface to split up device tree
> construction, and was encouraged to find PnvXScomInterfaceClass which
> seems be a way of combining device tree construction in a device class.
> Is this the way to go?

At some point, quite likely (I've actually had thoughts on making
devicetree construction more convenient qemu wide, but haven't had
time to do much about it).

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr
  2017-11-22  3:36   ` [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr David Gibson
@ 2017-12-06  3:12     ` David Gibson
  2017-12-06  3:18       ` Michael Davidsaver
  0 siblings, 1 reply; 33+ messages in thread
From: David Gibson @ 2017-12-06  3:12 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 925 bytes --]

On Wed, Nov 22, 2017 at 02:36:43PM +1100, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:10PM -0600, Michael Davidsaver wrote:
> > Preparation for adding more MPCxxxx control
> > registers.
> > 
> > Use e500 SVR to enable part specific registers.
> > Only the mpc8544 reset register at present.
> > 
> > Expose CCSR as SysBusDevice region to eliminate
> > e500-ccsr.h.
> > 
> > Track CCSR base address within device, and map on reset,
> > in preparation for CCSRBAR.
> > 
> > Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> Applied to ppc-for-2.12.

Sorry.  I've now pulled this from ppc-for-2.12, because it caused a
breakage of make check (specifically the boot-serial-test with ppc64).

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr
  2017-12-06  3:12     ` David Gibson
@ 2017-12-06  3:18       ` Michael Davidsaver
  2017-12-06  4:23         ` David Gibson
  0 siblings, 1 reply; 33+ messages in thread
From: Michael Davidsaver @ 2017-12-06  3:18 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-ppc, qemu-devel

On 12/05/2017 10:12 PM, David Gibson wrote:
> On Wed, Nov 22, 2017 at 02:36:43PM +1100, David Gibson wrote:
>> On Sun, Nov 19, 2017 at 09:24:10PM -0600, Michael Davidsaver wrote:
>>> Preparation for adding more MPCxxxx control
>>> registers.
>>>
>>> Use e500 SVR to enable part specific registers.
>>> Only the mpc8544 reset register at present.
>>>
>>> Expose CCSR as SysBusDevice region to eliminate
>>> e500-ccsr.h.
>>>
>>> Track CCSR base address within device, and map on reset,
>>> in preparation for CCSRBAR.
>>>
>>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
>>
>> Applied to ppc-for-2.12.
> 
> Sorry.  I've now pulled this from ppc-for-2.12, because it caused a
> breakage of make check (specifically the boot-serial-test with ppc64).

Oops, I'll begin running this test myself.  So far I've only been running
tests for i386, amd64, arm, and ppc.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr
  2017-12-06  3:18       ` Michael Davidsaver
@ 2017-12-06  4:23         ` David Gibson
  0 siblings, 0 replies; 33+ messages in thread
From: David Gibson @ 2017-12-06  4:23 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1421 bytes --]

On Tue, Dec 05, 2017 at 10:18:56PM -0500, Michael Davidsaver wrote:
> On 12/05/2017 10:12 PM, David Gibson wrote:
> > On Wed, Nov 22, 2017 at 02:36:43PM +1100, David Gibson wrote:
> >> On Sun, Nov 19, 2017 at 09:24:10PM -0600, Michael Davidsaver wrote:
> >>> Preparation for adding more MPCxxxx control
> >>> registers.
> >>>
> >>> Use e500 SVR to enable part specific registers.
> >>> Only the mpc8544 reset register at present.
> >>>
> >>> Expose CCSR as SysBusDevice region to eliminate
> >>> e500-ccsr.h.
> >>>
> >>> Track CCSR base address within device, and map on reset,
> >>> in preparation for CCSRBAR.
> >>>
> >>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> >>
> >> Applied to ppc-for-2.12.
> > 
> > Sorry.  I've now pulled this from ppc-for-2.12, because it caused a
> > breakage of make check (specifically the boot-serial-test with ppc64).
> 
> Oops, I'll begin running this test myself.  So far I've only been running
> tests for i386, amd64, arm, and ppc.

I really recommend running a build and make check smoke test for all
targets ("./configure && make && make check SPEED=slow") before
posting patches for submission.  It takes a while, but not stupidly
long.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2017-12-06  4:23 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-20  3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
2017-11-20  3:24 ` [Qemu-devel] [PATCH 01/12] e500: add board config options Michael Davidsaver
2017-11-22  3:28   ` David Gibson
2017-11-22 17:55     ` Michael Davidsaver
2017-11-23 16:07       ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
2017-11-24  0:21       ` [Qemu-devel] " David Gibson
2017-11-20  3:24 ` [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge Michael Davidsaver
2017-11-22  3:46   ` David Gibson
2017-11-22  4:57     ` Michael Davidsaver
2017-11-20  3:24 ` [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers Michael Davidsaver
2017-11-22  3:57   ` David Gibson
2017-11-20  3:24 ` [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge Michael Davidsaver
2017-11-22  3:58   ` David Gibson
2017-11-20  3:24 ` [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller Michael Davidsaver
2017-11-22  4:06   ` David Gibson
2017-11-23 15:39   ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
2017-11-24  0:13     ` David Gibson
2017-11-20  3:24 ` [Qemu-devel] [PATCH 07/12] qtest: add e500_i2c_create() Michael Davidsaver
2017-11-20  3:24 ` [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr Michael Davidsaver
2017-11-22  4:08   ` David Gibson
2017-11-22 16:46     ` Michael Davidsaver
2017-11-20  3:24 ` [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom Michael Davidsaver
2017-11-22  4:10   ` David Gibson
2017-11-20  3:24 ` [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC Michael Davidsaver
2017-11-22  4:11   ` David Gibson
2017-11-20  3:24 ` [Qemu-devel] [PATCH 11/12] ppc: add mvme3100 machine Michael Davidsaver
2017-11-20  3:24 ` [Qemu-devel] [PATCH 12/12] tests: add mvme3100-test Michael Davidsaver
     [not found] ` <20171120032420.9134-3-mdavidsaver@gmail.com>
2017-11-22  3:36   ` [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr David Gibson
2017-12-06  3:12     ` David Gibson
2017-12-06  3:18       ` Michael Davidsaver
2017-12-06  4:23         ` David Gibson
2017-11-22  4:12 ` [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC David Gibson
2017-11-22  4:58   ` Michael Davidsaver

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.