All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2
@ 2017-11-26 21:58 Michael Davidsaver
  2017-11-26 21:58 ` [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report() Michael Davidsaver
                   ` (16 more replies)
  0 siblings, 17 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:58 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Changes since previous iteration.

openpic: debug w/ info_report()

  New

i2c: start trace-events
i2c: add mpc8540 i2c controller

  Debugging cleanup and fix a spurious warning triggered by Linux guests.

qtest: add e500_i2c_create()

  Unchanged

timer: generalize Dallas/Maxim RTC i2c devices
tests: rewrite testing for DS RTC devices

  Combined models of ds1338 and ds1375 RTCs, along with untested support
  for some similar chips.
  Test case for setting time to exercise offset calculation.

e500: fix pci host bridge class/type

  After further investigation, revert the change which caused the host bridge
  to be identified as a pci-pci bridge.

e500: additional CCSR registers

  Also update CPUPPCState::mpic_iack when changing CCSRBAR.

e500: additional CCSR registers
e500: move mpic under CCSR
e500: move uarts CCSR
e500: derive baud from CCB clock
e500: add i2c controller to CCSR
e500: move PCI host bridge into CCSR

  Moved MPIC, UARTS, and PCI host bridge under CCSR device.
  Many of the PPCE500Params members become properties of the CCSR device.

e500: split mpc8544ds specific initialization

  Split ppce500_init() to create mpc85xx_init().
  mpc85xx_init() has all the bits used by the exist mpc8544ds and ppce500 machines,
  but not by the new mvme3100 machine (which doesn't use PPCE500Params).

ppc: add mvme3100 machine

  Minor changes related to ppce500_init() changes

tests: run ds-rtc-i2c-test w/ ppc/mvme3100

  New

tests: add mvme3100-test

  Unchanged

Michael Davidsaver (17):
  openpic: debug w/ info_report()
  i2c: start trace-events
  i2c: add mpc8540 i2c controller
  qtest: add e500_i2c_create()
  timer: generalize Dallas/Maxim RTC i2c devices
  tests: rewrite testing for DS RTC devices
  e500: fix pci host bridge class/type
  e500: additional CCSR registers
  e500: move mpic under CCSR
  e500: move uarts CCSR
  e500: derive baud from CCB clock
  e500: add i2c controller to CCSR
  e500: move PCI host bridge into CCSR
  e500: split mpc8544ds specific initialization
  ppc: add mvme3100 machine
  tests: run ds-rtc-i2c-test w/ ppc/mvme3100
  tests: add mvme3100-test

 Makefile.objs                   |   1 +
 default-configs/arm-softmmu.mak |   2 +-
 default-configs/ppc-softmmu.mak |   1 +
 hw/i2c/Makefile.objs            |   1 +
 hw/i2c/mpc8540_i2c.c            | 307 +++++++++++++++++
 hw/i2c/trace-events             |   7 +
 hw/intc/openpic.c               | 102 +++---
 hw/pci-host/ppce500.c           |   5 -
 hw/ppc/Makefile.objs            |   1 +
 hw/ppc/e500.c                   | 175 +++-------
 hw/ppc/e500.h                   |   3 +-
 hw/ppc/e500_ccsr.c              | 246 ++++++++++++-
 hw/ppc/e500plat.c               |   2 +-
 hw/ppc/mpc8544ds.c              |   2 +-
 hw/ppc/mvme3100.c               | 740 ++++++++++++++++++++++++++++++++++++++++
 hw/ppc/mvme3100_cpld.c          | 192 +++++++++++
 hw/timer/Makefile.objs          |   2 +-
 hw/timer/ds-rtc-i2c.c           | 461 +++++++++++++++++++++++++
 hw/timer/ds1338.c               | 239 -------------
 tests/Makefile.include          |   9 +-
 tests/ds-rtc-i2c-test.c         | 170 +++++++++
 tests/ds1338-test.c             |  77 -----
 tests/libqos/i2c-e500.c         |  66 ++++
 tests/libqos/i2c.h              |   3 +
 tests/mvme3100-test.c           |  79 +++++
 25 files changed, 2376 insertions(+), 517 deletions(-)
 create mode 100644 hw/i2c/mpc8540_i2c.c
 create mode 100644 hw/i2c/trace-events
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c
 create mode 100644 hw/timer/ds-rtc-i2c.c
 delete mode 100644 hw/timer/ds1338.c
 create mode 100644 tests/ds-rtc-i2c-test.c
 delete mode 100644 tests/ds1338-test.c
 create mode 100644 tests/libqos/i2c-e500.c
 create mode 100644 tests/mvme3100-test.c

-- 
2.11.0

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

* [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report()
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
@ 2017-11-26 21:58 ` Michael Davidsaver
  2017-11-27  7:09   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 02/17] i2c: start trace-events Michael Davidsaver
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:58 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Replace *printf() with *_report().
Remove trailing new lines.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/intc/openpic.c | 102 +++++++++++++++++++++++++++---------------------------
 1 file changed, 51 insertions(+), 51 deletions(-)

diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 10d6e871fb..9159a06f07 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -46,6 +46,7 @@
 #include "qapi/qmp/qerror.h"
 #include "qemu/log.h"
 #include "qemu/timer.h"
+#include "qemu/error-report.h"
 
 //#define DEBUG_OPENPIC
 
@@ -58,8 +59,7 @@ static const int debug_openpic = 0;
 static int get_current_cpu(void);
 #define DPRINTF(fmt, ...) do { \
         if (debug_openpic) { \
-            printf("Core%d: ", get_current_cpu()); \
-            printf(fmt , ## __VA_ARGS__); \
+            info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \
         } \
     } while (0)
 
@@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt)
         }
     }
 
-    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
+    error_report("%s: unsupported inttgt %d", __func__, inttgt);
     return OPENPIC_OUTPUT_INT;
 }
 
@@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q)
             break;
         }
 
-        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
+        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d",
                 irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
 
         if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
@@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
     dst = &opp->dst[n_CPU];
     src = &opp->src[n_IRQ];
 
-    DPRINTF("%s: IRQ %d active %d was %d\n",
+    DPRINTF("%s: IRQ %d active %d was %d",
             __func__, n_IRQ, active, was_active);
 
     if (src->output != OPENPIC_OUTPUT_INT) {
-        DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
+        DPRINTF("%s: output %d irq %d active %d was %d count %d",
                 __func__, src->output, n_IRQ, active, was_active,
                 dst->outputs_active[src->output]);
 
@@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
          */
         if (active) {
             if (!was_active && dst->outputs_active[src->output]++ == 0) {
-                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
+                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d",
                         __func__, src->output, n_CPU, n_IRQ);
                 qemu_irq_raise(dst->irqs[src->output]);
             }
         } else {
             if (was_active && --dst->outputs_active[src->output] == 0) {
-                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
+                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d",
                         __func__, src->output, n_CPU, n_IRQ);
                 qemu_irq_lower(dst->irqs[src->output]);
             }
@@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
     IRQ_check(opp, &dst->raised);
 
     if (active && priority <= dst->ctpr) {
-        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
+        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d",
                 __func__, n_IRQ, priority, dst->ctpr, n_CPU);
         active = 0;
     }
@@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
     if (active) {
         if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
                 priority <= dst->servicing.priority) {
-            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d",
                     __func__, n_IRQ, dst->servicing.next, n_CPU);
         } else {
-            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
+            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d",
                     __func__, n_CPU, n_IRQ, dst->raised.next);
             qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
         }
@@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
         IRQ_get_next(opp, &dst->servicing);
         if (dst->raised.priority > dst->ctpr &&
                 dst->raised.priority > dst->servicing.priority) {
-            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
+            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d",
                     __func__, n_IRQ, dst->raised.next, dst->raised.priority,
                     dst->ctpr, dst->servicing.priority, n_CPU);
             /* IRQ line stays asserted */
         } else {
-            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
+            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d",
                     __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
             qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
         }
@@ -489,7 +489,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
 
     if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
         /* Interrupt source is disabled */
-        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
+        DPRINTF("%s: IRQ %d is disabled", __func__, n_IRQ);
         active = false;
     }
 
@@ -500,7 +500,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
      * ctpr may have changed and we need to withdraw the interrupt.
      */
     if (!active && !was_active) {
-        DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
+        DPRINTF("%s: IRQ %d is already inactive", __func__, n_IRQ);
         return;
     }
 
@@ -512,7 +512,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
 
     if (src->destmask == 0) {
         /* No target */
-        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
+        DPRINTF("%s: IRQ %d has no target", __func__, n_IRQ);
         return;
     }
 
@@ -547,12 +547,12 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)
     IRQSource *src;
 
     if (n_IRQ >= OPENPIC_MAX_IRQ) {
-        fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
+        error_report("%s: IRQ %d out of range", __func__, n_IRQ);
         abort();
     }
 
     src = &opp->src[n_IRQ];
-    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
+    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x",
             n_IRQ, level, src->ivpr);
     if (src->level) {
         /* level-sensitive irq */
@@ -612,13 +612,13 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
     }
 
     src->idr = val & mask;
-    DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
+    DPRINTF("Set IDR %d to 0x%08x", n_IRQ, src->idr);
 
     if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
         if (src->idr & crit_mask) {
             if (src->idr & normal_mask) {
                 DPRINTF("%s: IRQ configured for multiple output types, using "
-                        "critical\n", __func__);
+                        "critical", __func__);
             }
 
             src->output = OPENPIC_OUTPUT_CINT;
@@ -648,7 +648,7 @@ static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
         IRQSource *src = &opp->src[n_IRQ];
 
         src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
-        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
+        DPRINTF("Set ILR %d to 0x%08x, output %d", n_IRQ, src->idr,
                 src->output);
 
         /* TODO: on MPIC v4.0 only, set nomask for non-INT */
@@ -688,7 +688,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
     }
 
     openpic_update_irq(opp, n_IRQ);
-    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
+    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x", n_IRQ, val,
             opp->src[n_IRQ].ivpr);
 }
 
@@ -719,7 +719,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
     IRQDest *dst;
     int idx;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
             __func__, addr, val);
     if (addr & 0xF) {
         return;
@@ -747,11 +747,11 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
     case 0x1090: /* PIR */
         for (idx = 0; idx < opp->nb_cpus; idx++) {
             if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
-                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+                DPRINTF("Raise OpenPIC RESET output for CPU %d", idx);
                 dst = &opp->dst[idx];
                 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
             } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
-                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+                DPRINTF("Lower OpenPIC RESET output for CPU %d", idx);
                 dst = &opp->dst[idx];
                 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
             }
@@ -781,7 +781,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
     OpenPICState *opp = opaque;
     uint32_t retval;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
     retval = 0xFFFFFFFF;
     if (addr & 0xF) {
         return retval;
@@ -828,7 +828,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
     default:
         break;
     }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+    DPRINTF("%s: => 0x%08x", __func__, retval);
 
     return retval;
 }
@@ -843,7 +843,7 @@ static void qemu_timer_cb(void *opaque)
     uint32_t val =   tmr->tbcr & ~TBCR_CI;
     uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG);  /* invert toggle. */
 
-    DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ);
+    DPRINTF("%s n_IRQ=%d", __func__, n_IRQ);
     /* Reload current count from base count and setup timer. */
     tmr->tccr = val | tog;
     openpic_tmr_set_tmr(tmr, val, /*enabled=*/true);
@@ -898,7 +898,7 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
     OpenPICState *opp = opaque;
     int idx;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
             __func__, (addr + 0x10f0), val);
     if (addr & 0xF) {
         return;
@@ -943,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
     uint32_t retval = -1;
     int idx;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0);
+    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr + 0x10f0);
     if (addr & 0xF) {
         goto out;
     }
@@ -970,7 +970,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
     }
 
 out:
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+    DPRINTF("%s: => 0x%08x", __func__, retval);
 
     return retval;
 }
@@ -981,7 +981,7 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
     OpenPICState *opp = opaque;
     int idx;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
             __func__, addr, val);
 
     addr = addr & 0xffff;
@@ -1006,7 +1006,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
     uint32_t retval;
     int idx;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
     retval = 0xFFFFFFFF;
 
     addr = addr & 0xffff;
@@ -1024,7 +1024,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
         break;
     }
 
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+    DPRINTF("%s: => 0x%08x", __func__, retval);
     return retval;
 }
 
@@ -1035,7 +1035,7 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
     int idx = opp->irq_msi;
     int srs, ibs;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
             __func__, addr, val);
     if (addr & 0xF) {
         return;
@@ -1061,7 +1061,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
     uint64_t r = 0;
     int i, srs;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
     if (addr & 0xF) {
         return -1;
     }
@@ -1096,7 +1096,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
 {
     uint64_t r = 0;
 
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
 
     /* TODO: EISR/EIMR */
 
@@ -1106,7 +1106,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
 static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
                                   unsigned size)
 {
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
             __func__, addr, val);
 
     /* TODO: EISR/EIMR */
@@ -1120,7 +1120,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
     IRQDest *dst;
     int s_IRQ, n_IRQ;
 
-    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
+    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x", __func__, idx,
             addr, val);
 
     if (idx < 0 || idx >= opp->nb_cpus) {
@@ -1146,16 +1146,16 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
     case 0x80: /* CTPR */
         dst->ctpr = val & 0x0000000F;
 
-        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
+        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d",
                 __func__, idx, dst->ctpr, dst->raised.priority,
                 dst->servicing.priority);
 
         if (dst->raised.priority <= dst->ctpr) {
-            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
+            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr",
                     __func__, idx);
             qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
         } else if (dst->raised.priority > dst->servicing.priority) {
-            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
+            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d",
                     __func__, idx, dst->raised.next);
             qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
         }
@@ -1168,11 +1168,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
         /* Read-only register */
         break;
     case 0xB0: /* EOI */
-        DPRINTF("EOI\n");
+        DPRINTF("EOI");
         s_IRQ = IRQ_get_next(opp, &dst->servicing);
 
         if (s_IRQ < 0) {
-            DPRINTF("%s: EOI with no interrupt in service\n", __func__);
+            DPRINTF("%s: EOI with no interrupt in service", __func__);
             break;
         }
 
@@ -1185,7 +1185,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
         if (n_IRQ != -1 &&
             (s_IRQ == -1 ||
              IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
-            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+            DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
                     idx, n_IRQ);
             qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
         }
@@ -1207,11 +1207,11 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
     IRQSource *src;
     int retval, irq;
 
-    DPRINTF("Lower OpenPIC INT output\n");
+    DPRINTF("Lower OpenPIC INT output");
     qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
 
     irq = IRQ_get_next(opp, &dst->raised);
-    DPRINTF("IACK: irq=%d\n", irq);
+    DPRINTF("IACK: irq=%d", irq);
 
     if (irq == -1) {
         /* No more interrupt pending */
@@ -1221,7 +1221,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
     src = &opp->src[irq];
     if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
             !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
-        fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
+        error_report("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x",
                 __func__, irq, dst->ctpr, src->ivpr);
         openpic_update_irq(opp, irq);
         retval = opp->spve;
@@ -1241,7 +1241,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
     /* Timers and IPIs support multicast. */
     if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) ||
         ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) {
-        DPRINTF("irq is IPI or TMR\n");
+        DPRINTF("irq is IPI or TMR");
         src->destmask &= ~(1 << cpu);
         if (src->destmask && !src->level) {
             /* trigger on CPUs that didn't know about it yet */
@@ -1262,7 +1262,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
     IRQDest *dst;
     uint32_t retval;
 
-    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
+    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr);
     retval = 0xFFFFFFFF;
 
     if (idx < 0 || idx >= opp->nb_cpus) {
@@ -1290,7 +1290,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
     default:
         break;
     }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+    DPRINTF("%s: => 0x%08x", __func__, retval);
 
     return retval;
 }
-- 
2.11.0

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

* [Qemu-devel] [PATCH 02/17] i2c: start trace-events
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
  2017-11-26 21:58 ` [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report() Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller Michael Davidsaver
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

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

diff --git a/Makefile.objs b/Makefile.objs
index 285c6f3c15..984ae8ecba 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -155,6 +155,7 @@ trace-events-subdirs += hw/arm
 trace-events-subdirs += hw/alpha
 trace-events-subdirs += hw/xen
 trace-events-subdirs += hw/ide
+trace-events-subdirs += hw/i2c
 trace-events-subdirs += ui
 trace-events-subdirs += audio
 trace-events-subdirs += net
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
new file mode 100644
index 0000000000..9284b1fbad
--- /dev/null
+++ b/hw/i2c/trace-events
@@ -0,0 +1 @@
+# See docs/devel/tracing.txt for syntax documentation.
-- 
2.11.0

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

* [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
  2017-11-26 21:58 ` [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report() Michael Davidsaver
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 02/17] i2c: start trace-events Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-11-27  7:12   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 04/17] qtest: add e500_i2c_create() Michael Davidsaver
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/i2c/Makefile.objs |   1 +
 hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i2c/trace-events  |   6 +
 3 files changed, 314 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..b9f5773b35
--- /dev/null
+++ b/hw/i2c/mpc8540_i2c.c
@@ -0,0 +1,307 @@
+/*
+ * MPC8540 I2C bus interface
+ * As described in
+ * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
+ * Part 2 chapter 11
+ *
+ * Compatible I2C controllers are found on other Freescale chips
+ * including mpc8544 and P2010.
+ *
+ * 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"
+#include "qemu/error-report.h"
+
+#include "trace.h"
+
+/* #define DEBUG_LVL 0 */
+
+#ifdef DEBUG_LVL
+#define DPRINTK(LVL, FMT, ...) do { \
+    if ((LVL) <= DEBUG_LVL) {\
+        info_report(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 "\n", ## __VA_ARGS__)
+
+#define TYPE_MPC8540_I2C "mpc8540-i2c"
+#define MPC8540_I2C(obj) OBJECT_CHECK(MPC8540I2CState, (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 MPC8540I2CState {
+    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, dbuf_valid;
+
+    qemu_irq irq;
+
+    MemoryRegion mmio;
+} MPC8540I2CState;
+
+#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(MPC8540I2CState *i2c)
+{
+    int ena = i2c->ctrl & 0x40,
+        sts = i2c->sts & 0x02,
+        act = !!(ena && sts);
+
+    DPRINTK(1, "IRQ %c ena %c sts %c",
+            act ? 'X' : '_',
+            ena ? 'X' : '_',
+            sts ? 'X' : '_');
+
+    qemu_set_irq(i2c->irq, act);
+}
+
+static
+uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+    MPC8540I2CState *i2c = opaque;
+    uint32_t val;
+
+    switch (addr) {
+    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)) {
+                if (!i2c->dbuf_valid) {
+                    LOG(LOG_GUEST_ERROR, "Read during addr or tx");
+                }
+                i2c->dbuf = 0xff;
+                i2c->dbuf_valid = false;
+            } else {
+                int ret = i2c_recv(i2c->bus);
+                i2c->dbuf = (uint8_t)ret;
+                i2c->dbuf_valid = true;
+                trace_mpc8540_i2c_read(i2c->dbuf);
+                I2CSR_SET(MIF, 1);
+                I2CSR_SET(RXAK, 0);
+                mpc8540_update_irq(i2c);
+            }
+        } else {
+            i2c->dbuf = 0xff;
+            i2c->dbuf_valid = false;
+            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy");
+        }
+        break;
+    case R_I2CDFSRR: /* FILTER */
+        val = i2c->filt;
+        break;
+    default:
+        val = 0xff;
+    }
+
+    DPRINTK(addr == 0xc ? 2 : 1, " read %08x -> %08x",
+            (unsigned)addr, (unsigned)val);
+    return val;
+}
+
+static
+void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    MPC8540I2CState *i2c = opaque;
+
+    DPRINTK(1, " write %08x <- %08x", (unsigned)addr, (unsigned)val);
+
+    switch (addr) {
+    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");
+
+        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
+            /* MSTA 0 -> 1 is START */
+
+            I2CSR_SET(MBB, 1);
+            if (I2CCR(MTX)) {
+                trace_mpc8540_i2c_event("START Tx");
+            } else {
+                trace_mpc8540_i2c_event("START Rx");
+            }
+            i2c_end_transfer(i2c->bus); /* paranoia */
+
+        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
+            /* MSTA 1 -> 0 is STOP */
+
+            I2CSR_SET(MBB, 0);
+            trace_mpc8540_i2c_event("STOP");
+            i2c_end_transfer(i2c->bus);
+
+        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
+            i2c_end_transfer(i2c->bus);
+            I2CSR_SET(MBB, 1);
+            if (I2CCR(MTX)) {
+                trace_mpc8540_i2c_event("REPEAT START Tx");
+            } else {
+                trace_mpc8540_i2c_event("REPEAT START Rx");
+            }
+
+        }
+        /* 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",
+                        (unsigned)(val & 0xfe));
+                } else {
+                    trace_mpc8540_i2c_address((unsigned)(val & 0xfe),
+                                              (val & 0x1) ? 'R' : 'T');
+                }
+                I2CSR_SET(MIF, 1);
+                I2CSR_SET(RXAK, 0);
+
+            } else if (I2CCR(MTX)) {
+                trace_mpc8540_i2c_write((unsigned)val);
+                i2c_send(i2c->bus, val);
+                I2CSR_SET(MIF, 1);
+                I2CSR_SET(RXAK, 0);
+            } else {
+                LOG(LOG_GUEST_ERROR, "I2CDR Write during read");
+            }
+            mpc8540_update_irq(i2c);
+        } else {
+            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy");
+        }
+        break;
+    case R_I2CDFSRR: /* FILTER */
+        val &= 0x3f;
+        i2c->filt = val;
+        break;
+    }
+
+    DPRINTK(1, "I2CCR = %02x I2SCR = %02x", 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)
+{
+    MPC8540I2CState *i2c = MPC8540_I2C(dev);
+
+    i2c->sts = 0x81; /* transfer complete and ack received */
+    i2c->dbuf_valid = false;
+}
+
+static void mpc8540_i2c_inst_init(DeviceState *dev, Error **errp)
+{
+    MPC8540I2CState *i2c = MPC8540_I2C(dev);
+
+    i2c->bus = i2c_init_bus(dev, "bus");
+
+    memory_region_init_io(&i2c->mmio, OBJECT(dev),
+                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
+
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->mmio);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
+}
+
+static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = &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(MPC8540I2CState),
+    .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)
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 9284b1fbad..ac38d76984 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -1 +1,7 @@
 # See docs/devel/tracing.txt for syntax documentation.
+
+# hw/i2c/mpc8540_i2c.c
+mpc8540_i2c_event(const char *evt) "Bus Event %s"
+mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX"
+mpc8540_i2c_write(uint8_t byte) "Write 0x%02x"
+mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
-- 
2.11.0

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

* [Qemu-devel] [PATCH 04/17] qtest: add e500_i2c_create()
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (2 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices Michael Davidsaver
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, 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] 42+ messages in thread

* [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (3 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 04/17] qtest: add e500_i2c_create() Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-11-30  5:13   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 06/17] tests: rewrite testing for DS RTC devices Michael Davidsaver
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.

Tested with ds1338 and ds1375.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs          |   2 +-
 hw/timer/ds-rtc-i2c.c           | 461 ++++++++++++++++++++++++++++++++++++++++
 hw/timer/ds1338.c               | 239 ---------------------
 4 files changed, 463 insertions(+), 241 deletions(-)
 create mode 100644 hw/timer/ds-rtc-i2c.c
 delete mode 100644 hw/timer/ds1338.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index d37edc4312..b857823681 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -31,7 +31,7 @@ CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
 CONFIG_IMX_FEC=y
 CONFIG_FTGMAC100=y
-CONFIG_DS1338=y
+CONFIG_DSRTCI2C=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8c19eac3b6..290015ebec 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 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_DSRTCI2C) += ds-rtc-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/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c
new file mode 100644
index 0000000000..ad2f8f2a68
--- /dev/null
+++ b/hw/timer/ds-rtc-i2c.c
@@ -0,0 +1,461 @@
+/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors: Michael Davidsaver
+ *          Paul Brook
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * Models real time read/set and NVRAM.
+ * Does not model alarms, or control/status registers.
+ *
+ * Generalized register map is:
+ *   [Current time]
+ *   [Alarm settings] (optional)
+ *   [Control/Status] (optional)
+ *   [Non-volatile memory] (optional)
+ *
+ * The current time registers are almost always the same,
+ * with the exception being that some have a CENTURY bit
+ * in the month register.
+ */
+#include "qemu/osdep.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"
+#include "sysemu/qtest.h"
+#include "qemu/error-report.h"
+
+/* #define DEBUG_DSRTC */
+
+#ifdef DEBUG_DSRTC
+#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \
+                            ## __VA_ARGS__)
+
+#define DSRTC_REGSIZE (0x40)
+
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+typedef struct DSRTCInfo {
+    /* if bit 7 of the Month register is set after Y2K */
+    bool has_century;
+    /* address of first non-volatile memory cell.
+     * nv_start >= reg_end means no NV memory.
+     */
+    uint8_t nv_start;
+    /* total size of register range.  When address counter rolls over. */
+    uint8_t reg_size;
+} DSRTCInfo;
+
+typedef struct DSRTCState {
+    I2CSlave parent_obj;
+
+    const DSRTCInfo *info;
+
+    qemu_irq alarm_irq;
+
+    /* register address counter */
+    uint8_t addr;
+    /* when writing, whether the address has been sent */
+    bool addrd;
+
+    int64_t time_offset;
+    int8_t wday_offset;
+
+    uint8_t regs[DSRTC_REGSIZE];
+} DSRTCState;
+
+typedef struct DSRTCClass {
+    I2CSlaveClass parent_class;
+
+    const DSRTCInfo *info;
+} DSRTCClass;
+
+#define TYPE_DSRTC "ds-rtc-i2c"
+#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
+#define DSRTC_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC)
+#define DSRTC_CLASS(klass) \
+    OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC)
+
+static const VMStateDescription vmstate_dsrtc = {
+    .name = TYPE_DSRTC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
+        VMSTATE_INT64(time_offset, DSRTCState),
+        VMSTATE_INT8_V(wday_offset, DSRTCState, 2),
+        VMSTATE_UINT8_ARRAY(regs, DSRTCState, DSRTC_REGSIZE),
+        VMSTATE_UINT8(addr, DSRTCState),
+        VMSTATE_BOOL(addrd, DSRTCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void dsrtc_reset(DeviceState *device);
+
+/* update current time registers */
+static
+void dsrtc_latch(DSRTCState *ds)
+{
+    struct tm now;
+    bool use12;
+
+    qemu_get_timedate(&now, ds->time_offset);
+
+    DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)",
+            now.tm_year, now.tm_mon, now.tm_mday,
+            now.tm_hour, now.tm_min, now.tm_sec,
+            now.tm_wday);
+
+    use12 = ARRAY_FIELD_EX32(ds->regs, HOUR, SET12);
+
+    /* 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 (!use12) {
+        /* 24 hour (0-23) */
+        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour));
+    } else {
+        /* 12 hour am/pm (1-12) */
+        ARRAY_FIELD_DP32(ds->regs, HOUR, SET12, 1);
+        ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12u);
+        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12,
+                         to_bcd(1u + (now.tm_hour % 12u)));
+    }
+
+    ds->regs[R_WDAY] = (now.tm_wday + ds->wday_offset) % 7u + 1u;
+    ds->regs[R_DATE] = to_bcd(now.tm_mday);
+
+    ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1));
+    if (ds->info->has_century) {
+        ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year >= 100u);
+    }
+
+    ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+    DPRINTK("Latched time");
+}
+
+/* call after guest writes to current time registers
+ * to re-compute our offset from host time.
+ */
+static
+void dsrtc_update(DSRTCState *ds)
+{
+    int user_wday;
+    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)) {
+        /* 12 hour (1-12) */
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR12)) - 1u;
+        if (ARRAY_FIELD_EX32(ds->regs, HOUR, AMPM)) {
+            now.tm_hour += 12;
+        }
+
+    } else {
+        /* 23 hour (0-23) */
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR24));
+    }
+
+    now.tm_wday = from_bcd(ds->regs[R_WDAY]) - 1u;
+    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]);
+    if (ARRAY_FIELD_EX32(ds->regs, MONTH, CENTURY) || !ds->info->has_century) {
+        now.tm_year += 100;
+    }
+
+    DPRINTK("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)",
+            now.tm_year, now.tm_mon, now.tm_mday,
+            now.tm_hour, now.tm_min, now.tm_sec,
+            now.tm_wday);
+
+    /* round trip to get real wday_offset based on time delta */
+    user_wday = now.tm_wday;
+    ds->time_offset = qemu_timedate_diff(&now);
+    /* race possible if we run at midnight
+     * TODO: make qemu_timedate_diff() calculate wday offset as well?
+     */
+    qemu_get_timedate(&now, ds->time_offset);
+    /* calculate wday_offset to achieve guest requested wday */
+    ds->wday_offset = user_wday - now.tm_wday;
+
+    DPRINTK("Update offset = %" PRId64 ", wday_offset = %d",
+            ds->time_offset, ds->wday_offset);
+}
+
+static
+void dsrtc_advance(DSRTCState *ds)
+{
+    ds->addr = (ds->addr + 1) % ds->info->reg_size;
+    if (ds->addr == 0) {
+        /* latch time on roll over */
+        dsrtc_latch(ds);
+    }
+}
+
+static
+int dsrtc_event(I2CSlave *s, enum i2c_event event)
+{
+    DSRTCState *ds = DSRTC(s);
+
+    switch (event) {
+    case I2C_START_SEND:
+        ds->addrd = false;
+        /* fall through */
+    case I2C_START_RECV:
+        dsrtc_latch(ds);
+        /* fall through */
+    case I2C_FINISH:
+        DPRINTK("Event %d", (int)event);
+        /* fall through */
+    case I2C_NACK:
+        break;
+    }
+    return 0;
+}
+
+static
+int dsrtc_recv(I2CSlave *s)
+{
+    DSRTCState *ds = DSRTC(s);
+    int ret = 0;
+
+    ret = ds->regs[ds->addr];
+
+    if (ds->addr > R_YEAR && ds->addr < ds->info->nv_start) {
+        LOG(LOG_UNIMP, "Read from unimplemented (%02x) %02x", ds->addr, ret);
+    }
+
+    DPRINTK("Recv (%02x) %02x", ds->addr, ret);
+
+    dsrtc_advance(ds);
+
+    return ret;
+}
+
+static
+int dsrtc_send(I2CSlave *s, uint8_t data)
+{
+    DSRTCState *ds = DSRTC(s);
+
+    if (!ds->addrd) {
+        if (data == 0xff && qtest_enabled()) {
+            /* allow test runner to zero offsets */
+            DPRINTK("Testing reset");
+            dsrtc_reset(DEVICE(s));
+            return 0;
+        }
+        ds->addr = data % DSRTC_REGSIZE;
+        ds->addrd = true;
+        DPRINTK("Set address pointer %02x", data);
+        return 0;
+    }
+
+    DPRINTK("Send (%02x) %02x", ds->addr, data);
+
+    if (ds->addr <= R_YEAR) {
+        ds->regs[ds->addr] = data;
+        dsrtc_update(ds);
+
+    } else if (ds->addr >= ds->info->nv_start) {
+        ds->regs[ds->addr] = data;
+
+    } else {
+        LOG(LOG_UNIMP, "Register not modeled");
+    }
+
+    dsrtc_advance(ds);
+
+    return 0;
+}
+
+static
+void dsrtc_reset(DeviceState *device)
+{
+    DSRTCState *ds = DSRTC(device);
+
+    memset(ds->regs, 0, sizeof(ds->regs));
+
+    ds->addr = 0;
+    ds->addrd = false;
+    ds->time_offset = 0;
+    ds->wday_offset = 0;
+
+    DPRINTK("Reset");
+}
+
+static
+void dsrtc_realize(DeviceState *device, Error **errp)
+{
+    DSRTCState *ds = DSRTC(device);
+    DSRTCClass *r = DSRTC_GET_CLASS(device);
+
+    ds->info = r->info;
+
+    /* Alarms not yet implemented, but allow
+     * board code to wire up the alarm interrupt
+     * output anyway.
+     */
+    qdev_init_gpio_out(device, &ds->alarm_irq, 1);
+}
+
+static
+void dsrtc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+    DSRTCClass *r = DSRTC_CLASS(klass);
+
+    r->info = data;
+
+    k->event = &dsrtc_event;
+    k->recv = &dsrtc_recv;
+    k->send = &dsrtc_send;
+
+    dc->vmsd = &vmstate_dsrtc;
+    dc->realize = dsrtc_realize;
+    dc->reset = dsrtc_reset;
+    dc->user_creatable = true;
+}
+
+static
+const TypeInfo ds_rtc_base_type = {
+    .abstract = true,
+    .name = TYPE_DSRTC,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(DSRTCState),
+};
+
+#define DSRTC_CONFIG(NAME) \
+static const TypeInfo NAME##_type = { \
+    .name = #NAME, \
+    .parent = TYPE_DSRTC, \
+    .class_size = sizeof(I2CSlaveClass), \
+    .class_init = dsrtc_class_init, \
+    .class_data = (void *)&NAME##_info, \
+};
+
+/* ds3231 - alarms, no eeprom */
+static const DSRTCInfo ds3231_info = {
+    .has_century = true,
+    .nv_start    = 0x13, /* no nv memory */
+    .reg_size    = 0x13,
+};
+DSRTC_CONFIG(ds3231)
+
+/* only model block 0 (RTC), blocks 1,2 (eeprom) not modeled.
+ * blocks have different i2c addresses
+ */
+static const DSRTCInfo ds1388_info = {
+    .has_century = false,
+    .nv_start    = 0x0d,
+    .reg_size    = 0x0d,
+};
+DSRTC_CONFIG(ds1388)
+
+/* alarms, eeprom */
+static const DSRTCInfo ds1375_info = {
+    .has_century = true,
+    .nv_start    = 0x10,
+    .reg_size    = 0x20,
+};
+DSRTC_CONFIG(ds1375)
+
+/* no alarms, no eeprom */
+static const DSRTCInfo ds1340_info = {
+    .has_century = false,
+    .nv_start    = 0x10,
+    .reg_size    = 0x10,
+};
+DSRTC_CONFIG(ds1340)
+
+/* alarms, no eeprom */
+static const DSRTCInfo ds1339_info = {
+    .has_century = false,
+    .nv_start    = 0x11,
+    .reg_size    = 0x11,
+};
+DSRTC_CONFIG(ds1339)
+
+/* no alarms, eeprom */
+static const DSRTCInfo ds1338_info = {
+    .has_century = false,
+    .nv_start    = 0x08,
+    .reg_size    = 0x40,
+};
+DSRTC_CONFIG(ds1338)
+
+/* alarms, no eeprom */
+static const DSRTCInfo ds1337_info = {
+    .has_century = true,
+    .nv_start    = 0x10,
+    .reg_size    = 0x10,
+};
+DSRTC_CONFIG(ds1337)
+
+/* ds1307 registers are identical to ds1338 */
+static
+const TypeInfo ds1307_type = {
+    .name = "ds1307",
+    .parent = "ds1338",
+};
+
+static void ds_rtc_i2c_register(void)
+{
+    type_register_static(&ds_rtc_base_type);
+    type_register_static(&ds3231_type);
+    type_register_static(&ds1388_type);
+    type_register_static(&ds1375_type);
+    type_register_static(&ds1340_type);
+    type_register_static(&ds1339_type);
+    type_register_static(&ds1338_type);
+    type_register_static(&ds1337_type);
+    type_register_static(&ds1307_type);
+}
+
+type_init(ds_rtc_i2c_register)
diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
deleted file mode 100644
index 3849b74a68..0000000000
--- a/hw/timer/ds1338.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * MAXIM DS1338 I2C RTC+NVRAM
- *
- * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/i2c/i2c.h"
-#include "qemu/bcd.h"
-
-/* Size of NVRAM including both the user-accessible area and the
- * secondary register area.
- */
-#define NVRAM_SIZE 64
-
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12   0x40
-#define HOURS_PM   0x20
-#define CTRL_OSF   0x20
-
-#define TYPE_DS1338 "ds1338"
-#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
-
-typedef struct DS1338State {
-    I2CSlave parent_obj;
-
-    int64_t offset;
-    uint8_t wday_offset;
-    uint8_t nvram[NVRAM_SIZE];
-    int32_t ptr;
-    bool addr_byte;
-} DS1338State;
-
-static const VMStateDescription vmstate_ds1338 = {
-    .name = "ds1338",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
-        VMSTATE_INT64(offset, DS1338State),
-        VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
-        VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
-        VMSTATE_INT32(ptr, DS1338State),
-        VMSTATE_BOOL(addr_byte, DS1338State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void capture_current_time(DS1338State *s)
-{
-    /* Capture the current time into the secondary registers
-     * which will be actually read by the data transfer operation.
-     */
-    struct tm now;
-    qemu_get_timedate(&now, s->offset);
-    s->nvram[0] = to_bcd(now.tm_sec);
-    s->nvram[1] = to_bcd(now.tm_min);
-    if (s->nvram[2] & HOURS_12) {
-        int tmp = now.tm_hour;
-        if (tmp % 12 == 0) {
-            tmp += 12;
-        }
-        if (tmp <= 12) {
-            s->nvram[2] = HOURS_12 | to_bcd(tmp);
-        } else {
-            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
-        }
-    } else {
-        s->nvram[2] = to_bcd(now.tm_hour);
-    }
-    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
-    s->nvram[4] = to_bcd(now.tm_mday);
-    s->nvram[5] = to_bcd(now.tm_mon + 1);
-    s->nvram[6] = to_bcd(now.tm_year - 100);
-}
-
-static void inc_regptr(DS1338State *s)
-{
-    /* The register pointer wraps around after 0x3F; wraparound
-     * causes the current time/date to be retransferred into
-     * the secondary registers.
-     */
-    s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
-    if (!s->ptr) {
-        capture_current_time(s);
-    }
-}
-
-static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
-{
-    DS1338State *s = DS1338(i2c);
-
-    switch (event) {
-    case I2C_START_RECV:
-        /* In h/w, capture happens on any START condition, not just a
-         * START_RECV, but there is no need to actually capture on
-         * START_SEND, because the guest can't get at that data
-         * without going through a START_RECV which would overwrite it.
-         */
-        capture_current_time(s);
-        break;
-    case I2C_START_SEND:
-        s->addr_byte = true;
-        break;
-    default:
-        break;
-    }
-
-    return 0;
-}
-
-static int ds1338_recv(I2CSlave *i2c)
-{
-    DS1338State *s = DS1338(i2c);
-    uint8_t res;
-
-    res  = s->nvram[s->ptr];
-    inc_regptr(s);
-    return res;
-}
-
-static int ds1338_send(I2CSlave *i2c, uint8_t data)
-{
-    DS1338State *s = DS1338(i2c);
-
-    if (s->addr_byte) {
-        s->ptr = data & (NVRAM_SIZE - 1);
-        s->addr_byte = false;
-        return 0;
-    }
-    if (s->ptr < 7) {
-        /* Time register. */
-        struct tm now;
-        qemu_get_timedate(&now, s->offset);
-        switch(s->ptr) {
-        case 0:
-            /* TODO: Implement CH (stop) bit.  */
-            now.tm_sec = from_bcd(data & 0x7f);
-            break;
-        case 1:
-            now.tm_min = from_bcd(data & 0x7f);
-            break;
-        case 2:
-            if (data & HOURS_12) {
-                int tmp = from_bcd(data & (HOURS_PM - 1));
-                if (data & HOURS_PM) {
-                    tmp += 12;
-                }
-                if (tmp % 12 == 0) {
-                    tmp -= 12;
-                }
-                now.tm_hour = tmp;
-            } else {
-                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
-            }
-            break;
-        case 3:
-            {
-                /* The day field is supposed to contain a value in
-                   the range 1-7. Otherwise behavior is undefined.
-                 */
-                int user_wday = (data & 7) - 1;
-                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-            }
-            break;
-        case 4:
-            now.tm_mday = from_bcd(data & 0x3f);
-            break;
-        case 5:
-            now.tm_mon = from_bcd(data & 0x1f) - 1;
-            break;
-        case 6:
-            now.tm_year = from_bcd(data) + 100;
-            break;
-        }
-        s->offset = qemu_timedate_diff(&now);
-    } else if (s->ptr == 7) {
-        /* Control register. */
-
-        /* Ensure bits 2, 3 and 6 will read back as zero. */
-        data &= 0xB3;
-
-        /* Attempting to write the OSF flag to logic 1 leaves the
-           value unchanged. */
-        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
-        s->nvram[s->ptr] = data;
-    } else {
-        s->nvram[s->ptr] = data;
-    }
-    inc_regptr(s);
-    return 0;
-}
-
-static void ds1338_reset(DeviceState *dev)
-{
-    DS1338State *s = DS1338(dev);
-
-    /* The clock is running and synchronized with the host */
-    s->offset = 0;
-    s->wday_offset = 0;
-    memset(s->nvram, 0, NVRAM_SIZE);
-    s->ptr = 0;
-    s->addr_byte = false;
-}
-
-static void ds1338_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
-    k->event = ds1338_event;
-    k->recv = ds1338_recv;
-    k->send = ds1338_send;
-    dc->reset = ds1338_reset;
-    dc->vmsd = &vmstate_ds1338;
-}
-
-static const TypeInfo ds1338_info = {
-    .name          = TYPE_DS1338,
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(DS1338State),
-    .class_init    = ds1338_class_init,
-};
-
-static void ds1338_register_types(void)
-{
-    type_register_static(&ds1338_info);
-}
-
-type_init(ds1338_register_types)
-- 
2.11.0

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

* [Qemu-devel] [PATCH 06/17] tests: rewrite testing for DS RTC devices
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (4 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type Michael Davidsaver
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Replace existing ds1338-test with more thorough
test of time read and set.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 tests/Makefile.include  |   4 +-
 tests/ds-rtc-i2c-test.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/ds1338-test.c     |  77 -----------------------
 3 files changed, 164 insertions(+), 79 deletions(-)
 create mode 100644 tests/ds-rtc-i2c-test.c
 delete mode 100644 tests/ds1338-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ad1c219423..56045cdf09 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -348,7 +348,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
 check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
-check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-i2c-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -745,7 +745,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
 	tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
-tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
new file mode 100644
index 0000000000..0586dbd467
--- /dev/null
+++ b/tests/ds-rtc-i2c-test.c
@@ -0,0 +1,162 @@
+/* Testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * 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.
+ */
+#include <stdio.h>
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "qemu/cutils.h"
+#include "qemu/timer.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#define IMX25_I2C_0_BASE 0x43F80000
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+static bool use_century;
+
+static
+time_t rtc_gettime(void)
+{
+    struct tm parts;
+    uint8_t buf[7];
+
+    buf[0] = 0;
+    i2c_send(i2c, addr, buf, 1);
+    i2c_recv(i2c, addr, buf, 7);
+
+    parts.tm_sec = from_bcd(buf[0]);
+    parts.tm_min = from_bcd(buf[1]);
+    if (buf[2] & 0x40) {
+        /* 12 hour */
+        parts.tm_hour = from_bcd(buf[2] & 0x1f) % 12u;
+        if (buf[2] & 0x20) {
+            parts.tm_hour += 12u;
+        }
+    } else {
+        /* 24 hour */
+        parts.tm_hour = from_bcd(buf[2] & 0x3f);
+    }
+    parts.tm_wday = from_bcd(buf[3]);
+    parts.tm_mday = from_bcd(buf[4]);
+    parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
+    parts.tm_year = from_bcd(buf[6]);
+    if (!use_century || (buf[5] & 0x80)) {
+        parts.tm_year += 100u;
+    }
+
+    return mktimegm(&parts);
+}
+
+/* read back and compare with current system time */
+static
+void test_rtc_current(void)
+{
+    uint8_t buf;
+    time_t expected, actual;
+
+    /* magic address to zero RTC time offset
+     * as tests may be run in any order
+     */
+    buf = 0xff;
+    i2c_send(i2c, addr, &buf, 1);
+
+    actual = time(NULL);
+    /* new second may start here */
+    expected = rtc_gettime();
+    g_assert_cmpuint(expected, <=, actual + 1);
+    g_assert_cmpuint(expected, >=, actual);
+}
+
+
+static uint8_t test_time_24[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 18:30:53 +0000 */
+    0x53,
+    0x30,
+    0x18, /* 6 PM in 24 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
+static uint8_t test_time_12[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 18:30:53 +0000 */
+    0x53,
+    0x30,
+    0x67, /* 6 PM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
+/* write in and read back known time */
+static
+void test_rtc_set(const void *raw)
+{
+    const uint8_t *testtime = raw;
+    uint8_t buf[7];
+    unsigned retry = 2;
+
+    for (; retry; retry--) {
+        i2c_send(i2c, addr, testtime, 8);
+        /* new second may start here */
+        i2c_send(i2c, addr, testtime, 1);
+        i2c_recv(i2c, addr, buf, 7);
+
+        if (testtime[1] == buf[0]) {
+            break;
+        }
+        /* we raced start of second, retry */
+    };
+
+    g_assert_cmpuint(testtime[1], ==, buf[0]);
+    g_assert_cmpuint(testtime[2], ==, buf[1]);
+    g_assert_cmpuint(testtime[3], ==, buf[2]);
+    g_assert_cmpuint(testtime[4], ==, buf[3]);
+    g_assert_cmpuint(testtime[5], ==, buf[4]);
+    if (use_century) {
+        g_assert_cmpuint(testtime[6], ==, buf[5]);
+    } else {
+        g_assert_cmpuint(testtime[6] & 0x7f, ==, buf[5]);
+    }
+    g_assert_cmpuint(testtime[7], ==, buf[6]);
+
+    g_assert_cmpuint(retry, >, 0);
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "arm") == 0) {
+        qtest_start("-display none -machine imx25-pdk");
+        i2c = imx_i2c_create(IMX25_I2C_0_BASE);
+        addr = DS1338_ADDR;
+        use_century = false;
+
+    }
+
+    qtest_add_data_func("/ds-rtc-i2c/set24", test_time_24, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12", test_time_12, test_rtc_set);
+    qtest_add_func("/ds-rtc-i2c/current", test_rtc_current);
+
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
deleted file mode 100644
index 26968bc82a..0000000000
--- a/tests/ds1338-test.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * QTest testcase for the DS1338 RTC
- *
- * Copyright (c) 2013 Jean-Christophe Dubois
- *
- *  This program 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.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/i2c.h"
-
-#define IMX25_I2C_0_BASE 0x43F80000
-
-#define DS1338_ADDR 0x68
-
-static I2CAdapter *i2c;
-static uint8_t addr;
-
-static inline uint8_t bcd2bin(uint8_t x)
-{
-    return ((x) & 0x0f) + ((x) >> 4) * 10;
-}
-
-static void send_and_receive(void)
-{
-    uint8_t cmd[1];
-    uint8_t resp[7];
-    time_t now = time(NULL);
-    struct tm *tm_ptr = gmtime(&now);
-
-    /* reset the index in the RTC memory */
-    cmd[0] = 0;
-    i2c_send(i2c, addr, cmd, 1);
-
-    /* retrieve the date */
-    i2c_recv(i2c, addr, resp, 7);
-
-    /* check retrieved time againt local time */
-    g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
-    g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
-    g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
-}
-
-int main(int argc, char **argv)
-{
-    QTestState *s = NULL;
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-
-    s = qtest_start("-display none -machine imx25-pdk");
-    i2c = imx_i2c_create(IMX25_I2C_0_BASE);
-    addr = DS1338_ADDR;
-
-    qtest_add_func("/ds1338/tx-rx", send_and_receive);
-
-    ret = g_test_run();
-
-    if (s) {
-        qtest_quit(s);
-    }
-    g_free(i2c);
-
-    return ret;
-}
-- 
2.11.0

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

* [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (5 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 06/17] tests: rewrite testing for DS RTC devices Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-11-27  7:15   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers Michael Davidsaver
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Correct some confusion wrt. the PCI facing
side of the PCI host bridge (not PCIe root complex).
The ref. manual for the mpc8533 (as well as
mpc8540 and mpc8540) give the class code as
PCI_CLASS_PROCESSOR_POWERPC.
While the PCI_HEADER_TYPE field is oddly omitted,
the tables in the "PCI Configuration Header"
section shows a type 0 layout using all 6 BAR
registers (as 2x 32, and 2x 64 bit regions)

So 997505065dc92e533debf5cb23012ba4e673d387
seems to be in error.  Although there was
perhaps some confusion as the mpc8533
has a separate PCIe root complex.
With PCIe, a root complex has PCI_HEADER_TYPE=1.

Neither the PCI host bridge, nor the PCIe
root complex advertise class PCI_CLASS_BRIDGE_PCI.

This was confusing Linux guests, which try
to interpret the host bridge as a pci-pci
bridge, but get confused and re-enumerate
the bus when the primary/secondary/subordinate
bus registers don't have valid values.

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

diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index f2d108bc8a..8073d396ff 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
                                                       "/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_mr,
                              0, memory_region_size(ccsr_mr));
     pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
-- 
2.11.0

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

* [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (6 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-04  9:30   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR Michael Davidsaver
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Add CCSRBAR to allow CCSR region to be relocated.

Guest memory size introspection via RAM config
registers.

Dummy RAM error controls.

Clock introspection via Power on Reset PLL
Status Register.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

ccsrbase also update iack
---
 hw/ppc/e500.c      |  5 ++-
 hw/ppc/e500_ccsr.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b90f4231a6..e22919f4f1 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -51,7 +51,9 @@
 
 #define RAM_SIZES_ALIGN            (64UL << 20)
 
-/* TODO: parameterize */
+/* TODO: parameterize
+ * Some CCSR offsets duplicated in e500_ccsr.c
+ */
 #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
 #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
 #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
@@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     object_property_add_child(qdev_get_machine(), "e500-ccsr",
                               OBJECT(dev), NULL);
     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_ccsr.c b/hw/ppc/e500_ccsr.c
index 1b586c3f42..9400d7cf13 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -30,13 +30,26 @@
 #include "hw/sysbus.h"
 
 /* E500_ denotes registers common to all */
+/* Some CCSR offsets duplicated in e500.c */
 
+#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)
 
 #define MPC8544_RSTCR       (0xE00B0)
 #define MPC8544_RSTCR_RESET      (0x02)
 
+#define E500_MPIC_OFFSET   (0x40000ULL)
+
 typedef struct {
     /*< private >*/
     SysBusDevice parent_obj;
@@ -44,19 +57,59 @@ typedef struct {
 
     MemoryRegion iomem;
 
-    uint32_t defbase;
+    uint32_t defbase, base;
+    uint32_t ram_size;
+    uint32_t merrd;
+
+    uint32_t porpllsr;
+
+    DeviceState *pic;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
 #define E500_CCSR(obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR)
 
+/* call after changing CCSRState::base */
+static void e500_ccsr_post_move(CCSRState *ccsr)
+{
+    CPUState *cs;
+
+    CPU_FOREACH(cs) {
+        PowerPCCPU *cpu = POWERPC_CPU(cs);
+        CPUPPCState *env = &cpu->env;
+
+        env->mpic_iack = ccsr->base +
+                         E500_MPIC_OFFSET + 0xa0;
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
+}
+
 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 +125,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;
+        e500_ccsr_post_move(ccsr);
+        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 +169,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
     }
 };
 
+static int e500_ccsr_post_load(void *opaque, int version_id)
+{
+    CCSRState *ccsr = opaque;
+
+    e500_ccsr_post_move(ccsr);
+    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_move(ccsr);
 }
 
 static void e500_ccsr_initfn(Object *obj)
@@ -123,15 +197,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;
 }
 
-- 
2.11.0

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

* [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (7 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-05  6:34   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR Michael Davidsaver
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Start moving code out of ppce500_init()

Existing ppce500_init_mpic() suggests that MPIC may not be created w/ KVM.
However, ppce500_init() used mpicdev unconditionally, and would
fail if the MPIC isn't created.  So require creation.

Not tested with KVM for lack of hardware.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c      | 102 +++--------------------------------------------------
 hw/ppc/e500_ccsr.c |  85 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 103 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index e22919f4f1..1872bb8eaa 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -29,7 +29,6 @@
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "sysemu/device_tree.h"
-#include "hw/ppc/openpic.h"
 #include "hw/ppc/ppc.h"
 #include "hw/loader.h"
 #include "elf.h"
@@ -679,92 +678,6 @@ static void ppce500_cpu_reset(void *opaque)
     mmubooke_create_initial_mapping(env);
 }
 
-static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
-                                           qemu_irq **irqs)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    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);
-
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-
-    k = 0;
-    for (i = 0; i < smp_cpus; i++) {
-        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
-            sysbus_connect_irq(s, k++, irqs[i][j]);
-        }
-    }
-
-    return dev;
-}
-
-static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
-                                          qemu_irq **irqs, Error **errp)
-{
-    Error *err = NULL;
-    DeviceState *dev;
-    CPUState *cs;
-
-    dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
-    qdev_prop_set_uint32(dev, "model", params->mpic_version);
-
-    object_property_set_bool(OBJECT(dev), true, "realized", &err);
-    if (err) {
-        error_propagate(errp, err);
-        object_unparent(OBJECT(dev));
-        return NULL;
-    }
-
-    CPU_FOREACH(cs) {
-        if (kvm_openpic_connect_vcpu(dev, cs)) {
-            fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
-                    __func__);
-            abort();
-        }
-    }
-
-    return dev;
-}
-
-static DeviceState *ppce500_init_mpic(MachineState *machine,
-                                      PPCE500Params *params,
-                                      MemoryRegion *ccsr,
-                                      qemu_irq **irqs)
-{
-    DeviceState *dev = NULL;
-    SysBusDevice *s;
-
-    if (kvm_enabled()) {
-        Error *err = NULL;
-
-        if (machine_kernel_irqchip_allowed(machine)) {
-            dev = ppce500_init_mpic_kvm(params, irqs, &err);
-        }
-        if (machine_kernel_irqchip_required(machine) && !dev) {
-            error_reportf_err(err,
-                              "kernel_irqchip requested but unavailable: ");
-            exit(1);
-        }
-    }
-
-    if (!dev) {
-        dev = ppce500_init_mpic_qemu(params, irqs);
-    }
-
-    s = SYS_BUS_DEVICE(dev);
-    memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
-                                s->mmio[0].memory);
-
-    return dev;
-}
-
 static void ppce500_power_off(void *opaque, int line, int on)
 {
     if (on) {
@@ -794,18 +707,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
      * 4 respectively */
     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
-    qemu_irq **irqs;
     DeviceState *dev, *mpicdev;
     CPUPPCState *firstenv = NULL;
     MemoryRegion *ccsr_addr_space;
     SysBusDevice *s;
 
-    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
-    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
     for (i = 0; i < smp_cpus; i++) {
         PowerPCCPU *cpu;
         CPUState *cs;
-        qemu_irq *input;
 
         cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
         env = &cpu->env;
@@ -821,13 +730,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
             firstenv = env;
         }
 
-        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
-        input = (qemu_irq *)env->irq_inputs;
-        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
-        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
-        env->mpic_iack = params->ccsrbar_base +
-                         MPC8544_MPIC_REGS_OFFSET + 0xa0;
 
         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
 
@@ -857,12 +760,15 @@ 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, "mpic-model", params->mpic_version);
     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);
 
-    mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
+    /* created under "e500-ccsr" */
+    mpicdev = DEVICE(object_resolve_path("/machine/pic", 0));
+    assert(mpicdev);
 
     /* Serial */
     if (serial_hds[0]) {
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index 9400d7cf13..68d952794e 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -24,10 +24,14 @@
 #include "qemu-common.h"
 #include "qemu/log.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
 #include "cpu.h"
 #include "hw/hw.h"
+#include "hw/boards.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
 #include "hw/sysbus.h"
+#include "hw/ppc/openpic.h"
 
 /* E500_ denotes registers common to all */
 /* Some CCSR offsets duplicated in e500.c */
@@ -185,20 +189,90 @@ static void e500_ccsr_reset(DeviceState *dev)
     e500_ccsr_post_move(ccsr);
 }
 
-static void e500_ccsr_initfn(Object *obj)
+static void e500_ccsr_init(Object *obj)
 {
-    CCSRState *ccsr = E500_CCSR(obj);
+    DeviceState *dev = DEVICE(obj);
+    CCSRState *ccsr = E500_CCSR(dev);
+
+    assert(current_machine);
+    if (kvm_enabled()) {
+
+        if (!machine_kernel_irqchip_allowed(current_machine)) {
+            error_report("Machine does not allow PIC,"
+                         " but this is not supported");
+            exit(1);
+        }
 
-    memory_region_init_io(&ccsr->iomem, obj, &e500_ccsr_ops,
+        ccsr->pic = qdev_create(NULL, TYPE_KVM_OPENPIC);
+    } else {
+        ccsr->pic = qdev_create(NULL, TYPE_OPENPIC);
+    }
+
+    if (!ccsr->pic) {
+        error_report("Failed to create PIC");
+        exit(1);
+    }
+
+    object_property_add_child(qdev_get_machine(), "pic", OBJECT(ccsr->pic),
+                              &error_fatal);
+
+    qdev_prop_set_uint32(ccsr->pic, "nb_cpus", smp_cpus);
+
+    object_property_add_alias(obj, "mpic-model",
+                              OBJECT(ccsr->pic), "model",
+                              &error_fatal);
+}
+
+static void e500_ccsr_realize(DeviceState *dev, Error **errp)
+{
+    CCSRState *ccsr = E500_CCSR(dev);
+    SysBusDevice *pic;
+
+    /* Base 1MB CCSR Region */
+    memory_region_init_io(&ccsr->iomem, OBJECT(dev), &e500_ccsr_ops,
                           ccsr, "e500-ccsr", 1024 * 1024);
-    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &ccsr->iomem);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &ccsr->iomem);
+
+    qdev_init_nofail(ccsr->pic);
+    pic = SYS_BUS_DEVICE(ccsr->pic);
+
+    /* connect MPIC to CPU(s) */
+    if (kvm_enabled()) {
+        CPUState *cs;
+
+        CPU_FOREACH(cs) {
+            if (kvm_openpic_connect_vcpu(ccsr->pic, cs)) {
+                error_setg(errp, "%s: failed to connect vcpu to irqchip",
+                           __func__);
+                return;
+            }
+        }
+
+    } else {
+        CPUState *cs;
+
+        CPU_FOREACH(cs) {
+            PowerPCCPU *cpu = POWERPC_CPU(cs);
+            CPUPPCState *env = &cpu->env;
+            qemu_irq *inputs = (qemu_irq *)env->irq_inputs;
+            int base = cs->cpu_index * PPCE500_INPUT_NB;
+
+            sysbus_connect_irq(pic, base + OPENPIC_OUTPUT_INT,
+                               inputs[PPCE500_INPUT_INT]);
+            sysbus_connect_irq(pic, base + OPENPIC_OUTPUT_CINT,
+                               inputs[PPCE500_INPUT_CINT]);
+        }
+    }
 
+    memory_region_add_subregion(&ccsr->iomem, E500_MPIC_OFFSET,
+                                sysbus_mmio_get_region(pic, 0));
 }
 
 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),
+    /* "mpic-model" aliased from MPIC */
     DEFINE_PROP_END_OF_LIST()
 };
 
@@ -221,6 +295,7 @@ void e500_ccsr_class_initfn(ObjectClass *klass, void *data)
 
     dc->props = e500_ccsr_props;
     dc->vmsd = &vmstate_e500_ccsr;
+    dc->realize = e500_ccsr_realize;
     dc->reset = e500_ccsr_reset;
 }
 
@@ -228,7 +303,7 @@ static const TypeInfo e500_ccsr_info = {
     .name          = TYPE_E500_CCSR,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(CCSRState),
-    .instance_init = e500_ccsr_initfn,
+    .instance_init = e500_ccsr_init,
     .class_size    = sizeof(SysBusDeviceClass),
     .class_init    = e500_ccsr_class_initfn
 };
-- 
2.11.0

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

* [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (8 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-05  6:37   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock Michael Davidsaver
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c      | 13 -------------
 hw/ppc/e500_ccsr.c | 18 ++++++++++++++++++
 2 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 1872bb8eaa..2d87d91582 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -22,7 +22,6 @@
 #include "net/net.h"
 #include "qemu/config-file.h"
 #include "hw/hw.h"
-#include "hw/char/serial.h"
 #include "hw/pci/pci.h"
 #include "hw/boards.h"
 #include "sysemu/sysemu.h"
@@ -770,18 +769,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     mpicdev = DEVICE(object_resolve_path("/machine/pic", 0));
     assert(mpicdev);
 
-    /* Serial */
-    if (serial_hds[0]) {
-        serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
-                       0, qdev_get_gpio_in(mpicdev, 42), 399193,
-                       serial_hds[0], DEVICE_BIG_ENDIAN);
-    }
-
-    if (serial_hds[1]) {
-        serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
-                       0, qdev_get_gpio_in(mpicdev, 42), 399193,
-                       serial_hds[1], DEVICE_BIG_ENDIAN);
-    }
 
     /* PCI */
     dev = qdev_create(NULL, "e500-pcihost");
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index 68d952794e..f1adba4e54 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -31,6 +31,7 @@
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "hw/sysbus.h"
+#include "hw/char/serial.h"
 #include "hw/ppc/openpic.h"
 
 /* E500_ denotes registers common to all */
@@ -45,6 +46,8 @@
 #define E500_ERR_DETECT  (0x2e40)
 #define E500_ERR_DISABLE (0x2e44)
 
+#define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
+
 #define E500_PORPLLSR    (0xE0000)
 #define E500_PVR         (0xE00A0)
 #define E500_SVR         (0xE00A4)
@@ -266,6 +269,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
 
     memory_region_add_subregion(&ccsr->iomem, E500_MPIC_OFFSET,
                                 sysbus_mmio_get_region(pic, 0));
+    /* Note: MPIC internal interrupts are offset by 16 */
+
+    /* DUARTS */
+    if (serial_hds[0]) {
+        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0),
+                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
+    }
+
+    if (serial_hds[1]) {
+        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(1),
+                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+                       serial_hds[1], DEVICE_BIG_ENDIAN);
+    }
+
 }
 
 static Property e500_ccsr_props[] = {
-- 
2.11.0

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

* [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (9 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-05  6:40   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR Michael Davidsaver
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

The CCB (Complex Core Bus) clock is the reference for the DUARTs
with an extra divide by 16.

>From the mpc8540, mpc8544, and P2010 ref manuals.
CCB=333MHz, with divider=0x87a gives ~9600 baud.
333e6 Hz/(16*0x87a) = 9591 Hz.
This is verified with a real mpc8540.

The existing value for the mpc8544ds boards is replaced.
Previously the uart "clock-frequency" device tree node
was left as zero, and at some point either u-boot or Linux
picks a value inconsistent with the frequency
given to serial_mm_init().
The FIFO timeout calculated from this was incorrect.

Now use an arbitrary (valid) CCB frequency of 333MHz
in the device tree and for the UART.

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c      |  9 ++++++++-
 hw/ppc/e500_ccsr.c | 16 ++++++++++++----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 2d87d91582..cfd5ed0152 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -49,6 +49,12 @@
 
 #define RAM_SIZES_ALIGN            (64UL << 20)
 
+/* Somewhat arbitrarily choosen Complex Core Bus frequency
+ * for our simulation (real freq of mpc8544ds board unknown)
+ * Used in baud rate calculations.
+ */
+#define CCB_FREQ (333333333)
+
 /* TODO: parameterize
  * Some CCSR offsets duplicated in e500_ccsr.c
  */
@@ -113,7 +119,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
-    qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
+    qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", CCB_FREQ);
     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
@@ -759,6 +765,7 @@ 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, "ccb-freq", CCB_FREQ);
     qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
     qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
     qdev_prop_set_uint32(dev, "ram-size", ram_size);
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index f1adba4e54..c479ed91ee 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -69,6 +69,7 @@ typedef struct {
     uint32_t merrd;
 
     uint32_t porpllsr;
+    uint32_t ccb_freq;
 
     DeviceState *pic;
 } CCSRState;
@@ -272,15 +273,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
     /* Note: MPIC internal interrupts are offset by 16 */
 
     /* DUARTS */
+    /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
+     * is the CCB clock divided by 16.
+     * So baud rate is CCB/(16*divider)
+     */
     if (serial_hds[0]) {
-        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0),
-                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0), 0,
+                       qdev_get_gpio_in(ccsr->pic, 16 + 26),
+                       ccsr->ccb_freq / 16u,
                        serial_hds[0], DEVICE_BIG_ENDIAN);
     }
 
     if (serial_hds[1]) {
-        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(1),
-                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(1), 0,
+                       qdev_get_gpio_in(ccsr->pic, 16 + 26),
+                       ccsr->ccb_freq / 16u,
                        serial_hds[1], DEVICE_BIG_ENDIAN);
     }
 
@@ -290,6 +297,7 @@ 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_UINT32("ccb-freq", CCSRState, ccb_freq, 333333333u),
     /* "mpic-model" aliased from MPIC */
     DEFINE_PROP_END_OF_LIST()
 };
-- 
2.11.0

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

* [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (10 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-05  6:49   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR Michael Davidsaver
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Add i2c controller found on mpc8540,
mpc8544, and P2010 (newer ppc, unmodeled).

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

diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index c479ed91ee..cd8216daaf 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -46,6 +46,8 @@
 #define E500_ERR_DETECT  (0x2e40)
 #define E500_ERR_DISABLE (0x2e44)
 
+#define E500_I2C_OFFSET  (0x3000)
+
 #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
 
 #define E500_PORPLLSR    (0xE0000)
@@ -72,6 +74,7 @@ typedef struct {
     uint32_t ccb_freq;
 
     DeviceState *pic;
+    DeviceState *i2c;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
@@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
                                 sysbus_mmio_get_region(pic, 0));
     /* Note: MPIC internal interrupts are offset by 16 */
 
+    /* attach I2C controller */
+    ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
+    object_property_add_child(qdev_get_machine(), "i2c[*]",
+                              OBJECT(ccsr->i2c), NULL);
+    qdev_init_nofail(ccsr->i2c);
+    memory_region_add_subregion(&ccsr->iomem, E500_I2C_OFFSET,
+                                sysbus_mmio_get_region(
+                                    SYS_BUS_DEVICE(ccsr->i2c), 0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(ccsr->i2c), 0,
+                          qdev_get_gpio_in(ccsr->pic, 16 + 27));
+
+
     /* DUARTS */
     /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
      * is the CCB clock divided by 16.
-- 
2.11.0

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

* [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (11 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-05  6:53   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization Michael Davidsaver
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 hw/ppc/e500.c      | 13 ++++---------
 hw/ppc/e500_ccsr.c | 27 +++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index cfd5ed0152..b0c8495aef 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
     qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
     qdev_prop_set_uint32(dev, "ram-size", ram_size);
+    qdev_prop_set_uint32(dev, "pci_first_slot", params->pci_first_slot);
+    qdev_prop_set_uint32(dev, "pci_first_pin_irq", pci_irq_nrs[0]);
     qdev_init_nofail(dev);
     ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
@@ -778,20 +780,13 @@ 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);
+    dev = DEVICE(object_resolve_path("/machine/pci-host", 0));
+    assert(dev);
     s = SYS_BUS_DEVICE(dev);
     for (i = 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
     }
 
-    memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
-                                sysbus_mmio_get_region(s, 0));
-
     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
     if (!pci_bus)
         printf("couldn't create PCI controller!\n");
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index cd8216daaf..4ec8f7524d 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -50,6 +50,8 @@
 
 #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
 
+#define E500_PCI_OFFSET  (0x8000ULL)
+
 #define E500_PORPLLSR    (0xE0000)
 #define E500_PVR         (0xE00A0)
 #define E500_SVR         (0xE00A4)
@@ -75,6 +77,7 @@ typedef struct {
 
     DeviceState *pic;
     DeviceState *i2c;
+    DeviceState *pcihost;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
@@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)
     DeviceState *dev = DEVICE(obj);
     CCSRState *ccsr = E500_CCSR(dev);
 
+    /* prepare MPIC */
     assert(current_machine);
     if (kvm_enabled()) {
 
@@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)
     object_property_add_alias(obj, "mpic-model",
                               OBJECT(ccsr->pic), "model",
                               &error_fatal);
+
+    /* prepare PCI host bridge */
+    ccsr->pcihost = qdev_create(NULL, "e500-pcihost");
+    object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(ccsr->pcihost),
+                              &error_abort);
+
+    object_property_add_alias(obj, "pci_first_slot",
+                              OBJECT(ccsr->pcihost), "first_slot",
+                              &error_fatal);
+    object_property_add_alias(obj, "pci_first_pin_irq",
+                              OBJECT(ccsr->pcihost), "first_pin_irq",
+                              &error_fatal);
 }
 
 static void e500_ccsr_realize(DeviceState *dev, Error **errp)
@@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
                           ccsr, "e500-ccsr", 1024 * 1024);
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &ccsr->iomem);
 
+    /* realize MPIC */
     qdev_init_nofail(ccsr->pic);
     pic = SYS_BUS_DEVICE(ccsr->pic);
 
@@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
                                 sysbus_mmio_get_region(pic, 0));
     /* Note: MPIC internal interrupts are offset by 16 */
 
+    /* realize PCI host bridge*/
+    qdev_init_nofail(ccsr->pcihost);
+
+    memory_region_add_subregion(&ccsr->iomem, E500_PCI_OFFSET,
+                                sysbus_mmio_get_region(
+                                    SYS_BUS_DEVICE(ccsr->pcihost), 0));
+
     /* attach I2C controller */
     ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
     object_property_add_child(qdev_get_machine(), "i2c[*]",
@@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {
     DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
     DEFINE_PROP_UINT32("ccb-freq", CCSRState, ccb_freq, 333333333u),
     /* "mpic-model" aliased from MPIC */
+    /* "pci_first_slot"
+     * "pci_first_pin_irq" aliased from PCI host bridge
+     */
     DEFINE_PROP_END_OF_LIST()
 };
 
-- 
2.11.0

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

* [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (12 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-19  5:05   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine Michael Davidsaver
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

split off the remaining board specific parts
of e500_init() as mpc85xx_init() which
will be used by the existing
mpc8544ds and generic e500 boards.

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

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b0c8495aef..0ac7cdf6a1 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -690,7 +690,32 @@ static void ppce500_power_off(void *opaque, int line, int on)
     }
 }
 
-void ppce500_init(MachineState *machine, PPCE500Params *params)
+
+void ppce500_init(MachineState *machine, uint32_t decrementer_freq)
+{
+    int i;
+    for (i = 0; i < smp_cpus; i++) {
+        PowerPCCPU *cpu;
+        CPUState *cs;
+        CPUPPCState *env;
+
+        cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+        env = &cpu->env;
+        cs = CPU(cpu);
+
+        if (env->mmu_model != POWERPC_MMU_BOOKE206) {
+            error_report("MMU model %i not supported by this machine.",
+                         env->mmu_model);
+            exit(1);
+        }
+
+        env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
+
+        ppc_booke_timers_init(cpu, decrementer_freq, PPC_TIMER_E500);
+    }
+}
+
+void mpc85xx_init(MachineState *machine, PPCE500Params *params)
 {
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -716,31 +741,21 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     CPUPPCState *firstenv = NULL;
     MemoryRegion *ccsr_addr_space;
     SysBusDevice *s;
+    CPUState *cs;
 
-    for (i = 0; i < smp_cpus; i++) {
+    ppce500_init(machine, 400000000);
+
+    CPU_FOREACH(cs) {
         PowerPCCPU *cpu;
-        CPUState *cs;
 
-        cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+        cpu = POWERPC_CPU(cs);
         env = &cpu->env;
-        cs = CPU(cpu);
 
-        if (env->mmu_model != POWERPC_MMU_BOOKE206) {
-            fprintf(stderr, "MMU model %i not supported by this machine.\n",
-                env->mmu_model);
-            exit(1);
-        }
 
+        /* Register reset handler */
         if (!firstenv) {
             firstenv = env;
-        }
 
-        env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
-
-        ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
-
-        /* Register reset handler */
-        if (!i) {
             /* Primary CPU */
             struct boot_info *boot_info;
             boot_info = g_malloc0(sizeof(struct boot_info));
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 70ba1d8f4f..350be17462 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -24,7 +24,8 @@ typedef struct PPCE500Params {
     hwaddr spin_base;
 } PPCE500Params;
 
-void ppce500_init(MachineState *machine, PPCE500Params *params);
+void ppce500_init(MachineState *machine, uint32_t decrementer_freq);
+void mpc85xx_init(MachineState *machine, PPCE500Params *params);
 
 hwaddr booke206_page_size_to_tlb(uint64_t size);
 
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index e59e80fb9e..103efc68c2 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -55,7 +55,7 @@ static void e500plat_init(MachineState *machine)
         params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
     }
 
-    ppce500_init(machine, &params);
+    mpc85xx_init(machine, &params);
 }
 
 static void e500plat_machine_init(MachineClass *mc)
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 1717953ec7..7de4ed8ae2 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -47,7 +47,7 @@ static void mpc8544ds_init(MachineState *machine)
         exit(1);
     }
 
-    ppce500_init(machine, &params);
+    mpc85xx_init(machine, &params);
 }
 
 
-- 
2.11.0

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

* [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (13 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-20  4:05   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100 Michael Davidsaver
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test Michael Davidsaver
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 default-configs/ppc-softmmu.mak |   1 +
 hw/ppc/Makefile.objs            |   1 +
 hw/ppc/mvme3100.c               | 740 ++++++++++++++++++++++++++++++++++++++++
 hw/ppc/mvme3100_cpld.c          | 192 +++++++++++
 4 files changed, 934 insertions(+)
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index bb225c6e46..3777194a4a 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_DSRTCI2C=y
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..8eb6a3a9a4
--- /dev/null
+++ b/hw/ppc/mvme3100.c
@@ -0,0 +1,740 @@
+/*
+ * 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)
+
+#define E500_TSEC_OFFSET(N)     (0x24000 + (N) * 0x1000)
+
+/* Complex Core Bus frequency */
+#define CCB_FREQ (333333333u)
+
+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;
+
+    MemoryRegion ram;
+} 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 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;
+}
+
+static void mvme3100_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    cpu_reset(cs);
+
+    /* HID0 clock control functions not modeled.
+     * Decrementer always enabled with CCB/8 as reference.
+     * HID0[EMCP] and HID0[TBEN] set
+     */
+    env->spr[SPR_HID0] |= 0x80004000;
+
+    remap_tlb_bare(&cpu->env);
+    env->nip = 0xfffffffc;
+}
+
+static
+void mvme3100_pci1_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+/* 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 model one PCI-PCI bridge (0:0x12:0) but with a different vendor/device
+ *
+ * We don't model:
+ * # The SATA controller GD31244 (0x8086-0x3200)
+ * # The USB (OHCI) controller uPD740101 (0x1033-0x0035)
+ * # The second PCI-PCI bridge (0:0x13:0) in front of the USB controllers
+ *
+ * (Note that the SATA controller found on newer boards is different)
+ */
+
+static void mvme3100_init(MachineState *machine)
+{
+    MVME3100State *mvme3100 = MVME3100(machine);
+    const mvme3100_info *info;
+    DeviceState *dev;
+    BusState *i2c;
+    PCIBus *pci0, *pci1;
+    SysBusDevice *cpld, *pic;
+    qemu_irq *pci1_pins = g_malloc_n(4, sizeof(*pci1_pins));
+    FWCfgState *fwinfo;
+    DriveInfo *drvinfo;
+    MemoryRegion *ccsr;
+
+    {
+        MVME3100Class *klass = MVME3100_GET_CLASS(machine);
+        info = klass->info;
+    }
+
+    /* Setup CPU */
+
+    ppce500_init(machine, CCB_FREQ / 8u);
+
+    memory_region_allocate_system_memory(&mvme3100->ram, NULL,
+                                         "mvme3100.ram", ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, &mvme3100->ram);
+
+    qemu_register_reset(mvme3100_cpu_reset, POWERPC_CPU(first_cpu));
+
+    /* Create CCSR and builtin periphrials */
+    dev = qdev_create(NULL, "e500-ccsr");
+    object_property_add_child(qdev_get_machine(), "e500-ccsr",
+                              OBJECT(dev), NULL);
+    qdev_prop_set_uint32(dev, "ccb-freq", CCB_FREQ);
+    qdev_prop_set_uint32(dev, "mpic-model", OPENPIC_MODEL_FSL_MPIC_20);
+    qdev_prop_set_uint32(dev, "porpllsr", info->porpllsr);
+    qdev_prop_set_uint32(dev, "base", 0xff700000ULL);
+    qdev_prop_set_uint32(dev, "ram-size", ram_size);
+    qdev_prop_set_uint32(dev, "pci_first_slot", 0);
+    qdev_prop_set_uint32(dev, "pci_first_pin_irq", 1);
+    qdev_init_nofail(dev);
+
+    ccsr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+
+    pic = SYS_BUS_DEVICE(object_resolve_path("/machine/pic", 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);
+
+    dev = DEVICE(object_resolve_path("/machine/pci-host", NULL));
+    assert(dev);
+    pci0 = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
+    assert(pci0);
+
+    /* Add expansion PCI bus (2x PMC sites)
+     * "pci-bridge" is not a PLX bridge, but shouldn't matter?
+     */
+    dev = qdev_create(BUS(pci0), "pci-bridge");
+
+    qdev_prop_set_uint8(dev, "chassis_nr", 1);
+    qdev_prop_set_int32(dev, "addr", PCI_DEVFN(0x12, 0));
+
+    qdev_init_nofail(dev);
+
+    pci1 = PCI_BUS(qdev_get_child_bus(dev, "pci.1"));
+    assert(pci1);
+
+    pci1_pins[0] = qdev_get_gpio_in(DEVICE(pic), 4);
+    pci1_pins[1] = qdev_get_gpio_in(DEVICE(pic), 5);
+    pci1_pins[2] = qdev_get_gpio_in(DEVICE(pic), 6);
+    pci1_pins[3] = qdev_get_gpio_in(DEVICE(pic), 7);
+
+    pci_bus_irqs(pci1, mvme3100_pci1_set_irq,
+                 pci_swizzle_map_irq_fn, pci1_pins, 4);
+
+    /* the actual PLX bridge doesn't emit interrupts */
+    pci_set_byte(PCI_DEVICE(dev)->config + PCI_INTERRUPT_PIN, 0);
+
+    /* root bus is only home to soldered devices, and has a
+     * an arbitrary IRQ pin mapping.
+     * Don't allow qdev_device_add() to consider it.
+     */
+    {
+        BusState *bpci0 = BUS(pci0);
+        BusClass *bcls  = BUS_GET_CLASS(pci0);
+        assert(bpci0);
+
+        /* bus 0 is thus declared to be full.
+         * as a side-effect, expansion PCI bus limited to 15 devices
+         */
+        bpci0->max_index = bcls->max_dev = 15;
+    }
+
+    /* 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);
+
+    /* NIC (2x TSEC and 1x FEC) */
+    if (nd_table[0].used) {
+        qemu_check_nic_model(&nd_table[0], "eTSEC");
+
+        dev = etsec_create(E500_TSEC_OFFSET(0), ccsr, &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(E500_TSEC_OFFSET(1), ccsr, &nd_table[1],
+                qdev_get_gpio_in(DEVICE(pic), 16 + 19),
+                qdev_get_gpio_in(DEVICE(pic), 16 + 20),
+                qdev_get_gpio_in(DEVICE(pic), 16 + 23));
+
+    } else if (nd_table[2].used) {
+        qemu_log_mask(LOG_UNIMP, "FEC (ethernet #3) not modeled\n");
+    }
+
+    /* 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);
+    qdev_connect_gpio_out(dev, 0, qdev_get_gpio_in(DEVICE(pic), 11));
+
+    /* 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] 42+ messages in thread

* [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (14 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-19  5:06   ` David Gibson
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test Michael Davidsaver
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, Michael Davidsaver

Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
 tests/Makefile.include  | 3 ++-
 tests/ds-rtc-i2c-test.c | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 56045cdf09..062d4e5b7b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -308,6 +308,7 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
 check-qtest-ppc-y += tests/prom-env-test$(EXESUF)
 check-qtest-ppc-y += tests/drive_del-test$(EXESUF)
 check-qtest-ppc-y += tests/boot-serial-test$(EXESUF)
+check-qtest-ppc-y += tests/ds-rtc-i2c-test$(EXESUF)
 
 check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF)
 gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c
@@ -745,7 +746,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
 	tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
-tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) $(libqos-e500-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
index 0586dbd467..f7dab1863e 100644
--- a/tests/ds-rtc-i2c-test.c
+++ b/tests/ds-rtc-i2c-test.c
@@ -18,6 +18,9 @@
 #define IMX25_I2C_0_BASE 0x43F80000
 #define DS1338_ADDR 0x68
 
+#define E500_CCSR_BASE 0xff700000
+#define DS1375_ADDR 0xd0
+
 static I2CAdapter *i2c;
 static uint8_t addr;
 static bool use_century;
@@ -148,6 +151,11 @@ int main(int argc, char *argv[])
         addr = DS1338_ADDR;
         use_century = false;
 
+    } else if (strcmp(arch, "ppc") == 0) {
+        qtest_start("-machine mvme3100-1152");
+        i2c = e500_i2c_create(E500_CCSR_BASE);
+        addr = DS1375_ADDR;
+        use_century = true;
     }
 
     qtest_add_data_func("/ds-rtc-i2c/set24", test_time_24, test_rtc_set);
-- 
2.11.0

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

* [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test
  2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
                   ` (15 preceding siblings ...)
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100 Michael Davidsaver
@ 2017-11-26 21:59 ` Michael Davidsaver
  2017-12-19  5:06   ` David Gibson
  16 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-26 21:59 UTC (permalink / raw)
  To: Alexander Graf, David Gibson; +Cc: qemu-devel, qemu-ppc, 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 062d4e5b7b..97bce77ee4 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -373,6 +373,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)
 
@@ -782,6 +784,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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report()
  2017-11-26 21:58 ` [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report() Michael Davidsaver
@ 2017-11-27  7:09   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-11-27  7:09 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:58:59PM -0600, Michael Davidsaver wrote:
> Replace *printf() with *_report().
> Remove trailing new lines.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Applied to ppc-for-2.12.

> ---
>  hw/intc/openpic.c | 102 +++++++++++++++++++++++++++---------------------------
>  1 file changed, 51 insertions(+), 51 deletions(-)
> 
> diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
> index 10d6e871fb..9159a06f07 100644
> --- a/hw/intc/openpic.c
> +++ b/hw/intc/openpic.c
> @@ -46,6 +46,7 @@
>  #include "qapi/qmp/qerror.h"
>  #include "qemu/log.h"
>  #include "qemu/timer.h"
> +#include "qemu/error-report.h"
>  
>  //#define DEBUG_OPENPIC
>  
> @@ -58,8 +59,7 @@ static const int debug_openpic = 0;
>  static int get_current_cpu(void);
>  #define DPRINTF(fmt, ...) do { \
>          if (debug_openpic) { \
> -            printf("Core%d: ", get_current_cpu()); \
> -            printf(fmt , ## __VA_ARGS__); \
> +            info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \
>          } \
>      } while (0)
>  
> @@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt)
>          }
>      }
>  
> -    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
> +    error_report("%s: unsupported inttgt %d", __func__, inttgt);
>      return OPENPIC_OUTPUT_INT;
>  }
>  
> @@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q)
>              break;
>          }
>  
> -        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
> +        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d",
>                  irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
>  
>          if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
> @@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
>      dst = &opp->dst[n_CPU];
>      src = &opp->src[n_IRQ];
>  
> -    DPRINTF("%s: IRQ %d active %d was %d\n",
> +    DPRINTF("%s: IRQ %d active %d was %d",
>              __func__, n_IRQ, active, was_active);
>  
>      if (src->output != OPENPIC_OUTPUT_INT) {
> -        DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
> +        DPRINTF("%s: output %d irq %d active %d was %d count %d",
>                  __func__, src->output, n_IRQ, active, was_active,
>                  dst->outputs_active[src->output]);
>  
> @@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
>           */
>          if (active) {
>              if (!was_active && dst->outputs_active[src->output]++ == 0) {
> -                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
> +                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d",
>                          __func__, src->output, n_CPU, n_IRQ);
>                  qemu_irq_raise(dst->irqs[src->output]);
>              }
>          } else {
>              if (was_active && --dst->outputs_active[src->output] == 0) {
> -                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
> +                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d",
>                          __func__, src->output, n_CPU, n_IRQ);
>                  qemu_irq_lower(dst->irqs[src->output]);
>              }
> @@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
>      IRQ_check(opp, &dst->raised);
>  
>      if (active && priority <= dst->ctpr) {
> -        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
> +        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d",
>                  __func__, n_IRQ, priority, dst->ctpr, n_CPU);
>          active = 0;
>      }
> @@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
>      if (active) {
>          if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
>                  priority <= dst->servicing.priority) {
> -            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
> +            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d",
>                      __func__, n_IRQ, dst->servicing.next, n_CPU);
>          } else {
> -            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
> +            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d",
>                      __func__, n_CPU, n_IRQ, dst->raised.next);
>              qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
>          }
> @@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
>          IRQ_get_next(opp, &dst->servicing);
>          if (dst->raised.priority > dst->ctpr &&
>                  dst->raised.priority > dst->servicing.priority) {
> -            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
> +            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d",
>                      __func__, n_IRQ, dst->raised.next, dst->raised.priority,
>                      dst->ctpr, dst->servicing.priority, n_CPU);
>              /* IRQ line stays asserted */
>          } else {
> -            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
> +            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d",
>                      __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
>              qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
>          }
> @@ -489,7 +489,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
>  
>      if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
>          /* Interrupt source is disabled */
> -        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
> +        DPRINTF("%s: IRQ %d is disabled", __func__, n_IRQ);
>          active = false;
>      }
>  
> @@ -500,7 +500,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
>       * ctpr may have changed and we need to withdraw the interrupt.
>       */
>      if (!active && !was_active) {
> -        DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
> +        DPRINTF("%s: IRQ %d is already inactive", __func__, n_IRQ);
>          return;
>      }
>  
> @@ -512,7 +512,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
>  
>      if (src->destmask == 0) {
>          /* No target */
> -        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
> +        DPRINTF("%s: IRQ %d has no target", __func__, n_IRQ);
>          return;
>      }
>  
> @@ -547,12 +547,12 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)
>      IRQSource *src;
>  
>      if (n_IRQ >= OPENPIC_MAX_IRQ) {
> -        fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
> +        error_report("%s: IRQ %d out of range", __func__, n_IRQ);
>          abort();
>      }
>  
>      src = &opp->src[n_IRQ];
> -    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
> +    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x",
>              n_IRQ, level, src->ivpr);
>      if (src->level) {
>          /* level-sensitive irq */
> @@ -612,13 +612,13 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
>      }
>  
>      src->idr = val & mask;
> -    DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
> +    DPRINTF("Set IDR %d to 0x%08x", n_IRQ, src->idr);
>  
>      if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
>          if (src->idr & crit_mask) {
>              if (src->idr & normal_mask) {
>                  DPRINTF("%s: IRQ configured for multiple output types, using "
> -                        "critical\n", __func__);
> +                        "critical", __func__);
>              }
>  
>              src->output = OPENPIC_OUTPUT_CINT;
> @@ -648,7 +648,7 @@ static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
>          IRQSource *src = &opp->src[n_IRQ];
>  
>          src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
> -        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
> +        DPRINTF("Set ILR %d to 0x%08x, output %d", n_IRQ, src->idr,
>                  src->output);
>  
>          /* TODO: on MPIC v4.0 only, set nomask for non-INT */
> @@ -688,7 +688,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
>      }
>  
>      openpic_update_irq(opp, n_IRQ);
> -    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
> +    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x", n_IRQ, val,
>              opp->src[n_IRQ].ivpr);
>  }
>  
> @@ -719,7 +719,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
>      IRQDest *dst;
>      int idx;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
> +    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
>              __func__, addr, val);
>      if (addr & 0xF) {
>          return;
> @@ -747,11 +747,11 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
>      case 0x1090: /* PIR */
>          for (idx = 0; idx < opp->nb_cpus; idx++) {
>              if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
> -                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
> +                DPRINTF("Raise OpenPIC RESET output for CPU %d", idx);
>                  dst = &opp->dst[idx];
>                  qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
>              } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
> -                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
> +                DPRINTF("Lower OpenPIC RESET output for CPU %d", idx);
>                  dst = &opp->dst[idx];
>                  qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
>              }
> @@ -781,7 +781,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
>      OpenPICState *opp = opaque;
>      uint32_t retval;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
> +    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
>      retval = 0xFFFFFFFF;
>      if (addr & 0xF) {
>          return retval;
> @@ -828,7 +828,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
>      default:
>          break;
>      }
> -    DPRINTF("%s: => 0x%08x\n", __func__, retval);
> +    DPRINTF("%s: => 0x%08x", __func__, retval);
>  
>      return retval;
>  }
> @@ -843,7 +843,7 @@ static void qemu_timer_cb(void *opaque)
>      uint32_t val =   tmr->tbcr & ~TBCR_CI;
>      uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG);  /* invert toggle. */
>  
> -    DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ);
> +    DPRINTF("%s n_IRQ=%d", __func__, n_IRQ);
>      /* Reload current count from base count and setup timer. */
>      tmr->tccr = val | tog;
>      openpic_tmr_set_tmr(tmr, val, /*enabled=*/true);
> @@ -898,7 +898,7 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
>      OpenPICState *opp = opaque;
>      int idx;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
> +    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
>              __func__, (addr + 0x10f0), val);
>      if (addr & 0xF) {
>          return;
> @@ -943,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
>      uint32_t retval = -1;
>      int idx;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0);
> +    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr + 0x10f0);
>      if (addr & 0xF) {
>          goto out;
>      }
> @@ -970,7 +970,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
>      }
>  
>  out:
> -    DPRINTF("%s: => 0x%08x\n", __func__, retval);
> +    DPRINTF("%s: => 0x%08x", __func__, retval);
>  
>      return retval;
>  }
> @@ -981,7 +981,7 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
>      OpenPICState *opp = opaque;
>      int idx;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
> +    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
>              __func__, addr, val);
>  
>      addr = addr & 0xffff;
> @@ -1006,7 +1006,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
>      uint32_t retval;
>      int idx;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
> +    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
>      retval = 0xFFFFFFFF;
>  
>      addr = addr & 0xffff;
> @@ -1024,7 +1024,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
>          break;
>      }
>  
> -    DPRINTF("%s: => 0x%08x\n", __func__, retval);
> +    DPRINTF("%s: => 0x%08x", __func__, retval);
>      return retval;
>  }
>  
> @@ -1035,7 +1035,7 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
>      int idx = opp->irq_msi;
>      int srs, ibs;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
> +    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
>              __func__, addr, val);
>      if (addr & 0xF) {
>          return;
> @@ -1061,7 +1061,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
>      uint64_t r = 0;
>      int i, srs;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
> +    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
>      if (addr & 0xF) {
>          return -1;
>      }
> @@ -1096,7 +1096,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
>  {
>      uint64_t r = 0;
>  
> -    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
> +    DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
>  
>      /* TODO: EISR/EIMR */
>  
> @@ -1106,7 +1106,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
>  static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
>                                    unsigned size)
>  {
> -    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
> +    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
>              __func__, addr, val);
>  
>      /* TODO: EISR/EIMR */
> @@ -1120,7 +1120,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
>      IRQDest *dst;
>      int s_IRQ, n_IRQ;
>  
> -    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
> +    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x", __func__, idx,
>              addr, val);
>  
>      if (idx < 0 || idx >= opp->nb_cpus) {
> @@ -1146,16 +1146,16 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
>      case 0x80: /* CTPR */
>          dst->ctpr = val & 0x0000000F;
>  
> -        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
> +        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d",
>                  __func__, idx, dst->ctpr, dst->raised.priority,
>                  dst->servicing.priority);
>  
>          if (dst->raised.priority <= dst->ctpr) {
> -            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
> +            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr",
>                      __func__, idx);
>              qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
>          } else if (dst->raised.priority > dst->servicing.priority) {
> -            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
> +            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d",
>                      __func__, idx, dst->raised.next);
>              qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
>          }
> @@ -1168,11 +1168,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
>          /* Read-only register */
>          break;
>      case 0xB0: /* EOI */
> -        DPRINTF("EOI\n");
> +        DPRINTF("EOI");
>          s_IRQ = IRQ_get_next(opp, &dst->servicing);
>  
>          if (s_IRQ < 0) {
> -            DPRINTF("%s: EOI with no interrupt in service\n", __func__);
> +            DPRINTF("%s: EOI with no interrupt in service", __func__);
>              break;
>          }
>  
> @@ -1185,7 +1185,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
>          if (n_IRQ != -1 &&
>              (s_IRQ == -1 ||
>               IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
> -            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
> +            DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
>                      idx, n_IRQ);
>              qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
>          }
> @@ -1207,11 +1207,11 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
>      IRQSource *src;
>      int retval, irq;
>  
> -    DPRINTF("Lower OpenPIC INT output\n");
> +    DPRINTF("Lower OpenPIC INT output");
>      qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
>  
>      irq = IRQ_get_next(opp, &dst->raised);
> -    DPRINTF("IACK: irq=%d\n", irq);
> +    DPRINTF("IACK: irq=%d", irq);
>  
>      if (irq == -1) {
>          /* No more interrupt pending */
> @@ -1221,7 +1221,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
>      src = &opp->src[irq];
>      if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
>              !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
> -        fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
> +        error_report("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x",
>                  __func__, irq, dst->ctpr, src->ivpr);
>          openpic_update_irq(opp, irq);
>          retval = opp->spve;
> @@ -1241,7 +1241,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
>      /* Timers and IPIs support multicast. */
>      if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) ||
>          ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) {
> -        DPRINTF("irq is IPI or TMR\n");
> +        DPRINTF("irq is IPI or TMR");
>          src->destmask &= ~(1 << cpu);
>          if (src->destmask && !src->level) {
>              /* trigger on CPUs that didn't know about it yet */
> @@ -1262,7 +1262,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
>      IRQDest *dst;
>      uint32_t retval;
>  
> -    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
> +    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr);
>      retval = 0xFFFFFFFF;
>  
>      if (idx < 0 || idx >= opp->nb_cpus) {
> @@ -1290,7 +1290,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
>      default:
>          break;
>      }
> -    DPRINTF("%s: => 0x%08x\n", __func__, retval);
> +    DPRINTF("%s: => 0x%08x", __func__, retval);
>  
>      return retval;
>  }

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller Michael Davidsaver
@ 2017-11-27  7:12   ` David Gibson
  2017-11-27 19:05     ` Michael Davidsaver
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-11-27  7:12 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:01PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  hw/i2c/Makefile.objs |   1 +
>  hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/i2c/trace-events  |   6 +
>  3 files changed, 314 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..b9f5773b35
> --- /dev/null
> +++ b/hw/i2c/mpc8540_i2c.c
> @@ -0,0 +1,307 @@
> +/*
> + * MPC8540 I2C bus interface
> + * As described in
> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
> + * Part 2 chapter 11
> + *
> + * Compatible I2C controllers are found on other Freescale chips
> + * including mpc8544 and P2010.
> + *
> + * 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"
> +#include "qemu/error-report.h"
> +
> +#include "trace.h"
> +
> +/* #define DEBUG_LVL 0 */
> +
> +#ifdef DEBUG_LVL
> +#define DPRINTK(LVL, FMT, ...) do { \
> +    if ((LVL) <= DEBUG_LVL) {\
> +        info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \
> +    } } while (0)
> +#else
> +#define DPRINTK(LVL, FMT, ...) do {} while (0)
> +#endif

So, you have both this DPRINTK stuff, and some trace events, which
seems a bit odd?  Why not just one or the other.

> +
> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
> +    " : " FMT "\n", ## __VA_ARGS__)
> +
> +#define TYPE_MPC8540_I2C "mpc8540-i2c"
> +#define MPC8540_I2C(obj) OBJECT_CHECK(MPC8540I2CState, (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 MPC8540I2CState {
> +    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, dbuf_valid;
> +
> +    qemu_irq irq;
> +
> +    MemoryRegion mmio;
> +} MPC8540I2CState;
> +
> +#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(MPC8540I2CState *i2c)
> +{
> +    int ena = i2c->ctrl & 0x40,
> +        sts = i2c->sts & 0x02,
> +        act = !!(ena && sts);
> +
> +    DPRINTK(1, "IRQ %c ena %c sts %c",
> +            act ? 'X' : '_',
> +            ena ? 'X' : '_',
> +            sts ? 'X' : '_');
> +
> +    qemu_set_irq(i2c->irq, act);
> +}
> +
> +static
> +uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    MPC8540I2CState *i2c = opaque;
> +    uint32_t val;
> +
> +    switch (addr) {
> +    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)) {
> +                if (!i2c->dbuf_valid) {
> +                    LOG(LOG_GUEST_ERROR, "Read during addr or tx");
> +                }
> +                i2c->dbuf = 0xff;
> +                i2c->dbuf_valid = false;
> +            } else {
> +                int ret = i2c_recv(i2c->bus);
> +                i2c->dbuf = (uint8_t)ret;
> +                i2c->dbuf_valid = true;
> +                trace_mpc8540_i2c_read(i2c->dbuf);
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +                mpc8540_update_irq(i2c);
> +            }
> +        } else {
> +            i2c->dbuf = 0xff;
> +            i2c->dbuf_valid = false;
> +            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy");
> +        }
> +        break;
> +    case R_I2CDFSRR: /* FILTER */
> +        val = i2c->filt;
> +        break;
> +    default:
> +        val = 0xff;
> +    }
> +
> +    DPRINTK(addr == 0xc ? 2 : 1, " read %08x -> %08x",
> +            (unsigned)addr, (unsigned)val);
> +    return val;
> +}
> +
> +static
> +void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    MPC8540I2CState *i2c = opaque;
> +
> +    DPRINTK(1, " write %08x <- %08x", (unsigned)addr, (unsigned)val);
> +
> +    switch (addr) {
> +    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");
> +
> +        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
> +            /* MSTA 0 -> 1 is START */
> +
> +            I2CSR_SET(MBB, 1);
> +            if (I2CCR(MTX)) {
> +                trace_mpc8540_i2c_event("START Tx");
> +            } else {
> +                trace_mpc8540_i2c_event("START Rx");
> +            }
> +            i2c_end_transfer(i2c->bus); /* paranoia */
> +
> +        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
> +            /* MSTA 1 -> 0 is STOP */
> +
> +            I2CSR_SET(MBB, 0);
> +            trace_mpc8540_i2c_event("STOP");
> +            i2c_end_transfer(i2c->bus);
> +
> +        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
> +            i2c_end_transfer(i2c->bus);
> +            I2CSR_SET(MBB, 1);
> +            if (I2CCR(MTX)) {
> +                trace_mpc8540_i2c_event("REPEAT START Tx");
> +            } else {
> +                trace_mpc8540_i2c_event("REPEAT START Rx");
> +            }
> +
> +        }
> +        /* 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",
> +                        (unsigned)(val & 0xfe));
> +                } else {
> +                    trace_mpc8540_i2c_address((unsigned)(val & 0xfe),
> +                                              (val & 0x1) ? 'R' : 'T');
> +                }
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +
> +            } else if (I2CCR(MTX)) {
> +                trace_mpc8540_i2c_write((unsigned)val);
> +                i2c_send(i2c->bus, val);
> +                I2CSR_SET(MIF, 1);
> +                I2CSR_SET(RXAK, 0);
> +            } else {
> +                LOG(LOG_GUEST_ERROR, "I2CDR Write during read");
> +            }
> +            mpc8540_update_irq(i2c);
> +        } else {
> +            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy");
> +        }
> +        break;
> +    case R_I2CDFSRR: /* FILTER */
> +        val &= 0x3f;
> +        i2c->filt = val;
> +        break;
> +    }
> +
> +    DPRINTK(1, "I2CCR = %02x I2SCR = %02x", 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)
> +{
> +    MPC8540I2CState *i2c = MPC8540_I2C(dev);
> +
> +    i2c->sts = 0x81; /* transfer complete and ack received */
> +    i2c->dbuf_valid = false;
> +}
> +
> +static void mpc8540_i2c_inst_init(DeviceState *dev, Error **errp)
> +{
> +    MPC8540I2CState *i2c = MPC8540_I2C(dev);
> +
> +    i2c->bus = i2c_init_bus(dev, "bus");
> +
> +    memory_region_init_io(&i2c->mmio, OBJECT(dev),
> +                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
> +
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->mmio);
> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
> +}

As someone pointed out on the earlier version, this stuff needs to go
into a realize() function rather than instance_init - instance_init is
called too early to go safely constructing and installing memory
regions.

> +
> +static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = &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(MPC8540I2CState),
> +    .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)
> diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
> index 9284b1fbad..ac38d76984 100644
> --- a/hw/i2c/trace-events
> +++ b/hw/i2c/trace-events
> @@ -1 +1,7 @@
>  # See docs/devel/tracing.txt for syntax documentation.
> +
> +# hw/i2c/mpc8540_i2c.c
> +mpc8540_i2c_event(const char *evt) "Bus Event %s"
> +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX"
> +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x"
> +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type Michael Davidsaver
@ 2017-11-27  7:15   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-11-27  7:15 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:05PM -0600, Michael Davidsaver wrote:
> Correct some confusion wrt. the PCI facing
> side of the PCI host bridge (not PCIe root complex).
> The ref. manual for the mpc8533 (as well as
> mpc8540 and mpc8540) give the class code as
> PCI_CLASS_PROCESSOR_POWERPC.
> While the PCI_HEADER_TYPE field is oddly omitted,
> the tables in the "PCI Configuration Header"
> section shows a type 0 layout using all 6 BAR
> registers (as 2x 32, and 2x 64 bit regions)
> 
> So 997505065dc92e533debf5cb23012ba4e673d387
> seems to be in error.  Although there was
> perhaps some confusion as the mpc8533
> has a separate PCIe root complex.
> With PCIe, a root complex has PCI_HEADER_TYPE=1.
> 
> Neither the PCI host bridge, nor the PCIe
> root complex advertise class PCI_CLASS_BRIDGE_PCI.
> 
> This was confusing Linux guests, which try
> to interpret the host bridge as a pci-pci
> bridge, but get confused and re-enumerate
> the bus when the primary/secondary/subordinate
> bus registers don't have valid values.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Applied to ppc-for-2.12.

> ---
>  hw/pci-host/ppce500.c | 5 -----
>  1 file changed, 5 deletions(-)
> 
> diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
> index f2d108bc8a..8073d396ff 100644
> --- a/hw/pci-host/ppce500.c
> +++ b/hw/pci-host/ppce500.c
> @@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
>                                                        "/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_mr,
>                               0, memory_region_size(ccsr_mr));
>      pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
  2017-11-27  7:12   ` David Gibson
@ 2017-11-27 19:05     ` Michael Davidsaver
  2017-11-29  1:32       ` David Gibson
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-11-27 19:05 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On 11/27/2017 01:12 AM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:01PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
>> ---
>>  hw/i2c/Makefile.objs |   1 +
>>  hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>  hw/i2c/trace-events  |   6 +
>>  3 files changed, 314 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..b9f5773b35
>> --- /dev/null
>> +++ b/hw/i2c/mpc8540_i2c.c
>> @@ -0,0 +1,307 @@
>> +/*
>> + * MPC8540 I2C bus interface
>> + * As described in
>> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
>> + * Part 2 chapter 11
>> + *
>> + * Compatible I2C controllers are found on other Freescale chips
>> + * including mpc8544 and P2010.
>> + *
>> + * 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"
>> +#include "qemu/error-report.h"
>> +
>> +#include "trace.h"
>> +
>> +/* #define DEBUG_LVL 0 */
>> +
>> +#ifdef DEBUG_LVL
>> +#define DPRINTK(LVL, FMT, ...) do { \
>> +    if ((LVL) <= DEBUG_LVL) {\
>> +        info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \
>> +    } } while (0)
>> +#else
>> +#define DPRINTK(LVL, FMT, ...) do {} while (0)
>> +#endif
> 
> So, you have both this DPRINTK stuff, and some trace events, which
> seems a bit odd?  Why not just one or the other.

My thinking is to have trace events for the commonly used points (by me at least)
for troubleshooting devices on the i2c bus, but leave the others for troubleshooting
the i2c controller itself as DPRINTK.

So this is mainly my laziness in not seeing sufficient benefit to defining events for the
remaining 5 DPRINTK s.

>> +
>> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
>> +    " : " FMT "\n", ## __VA_ARGS__)
>> +
>> +#define TYPE_MPC8540_I2C "mpc8540-i2c"
>> +#define MPC8540_I2C(obj) OBJECT_CHECK(MPC8540I2CState, (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 MPC8540I2CState {
>> +    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, dbuf_valid;
>> +
>> +    qemu_irq irq;
>> +
>> +    MemoryRegion mmio;
>> +} MPC8540I2CState;
>> +
>> +#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(MPC8540I2CState *i2c)
>> +{
>> +    int ena = i2c->ctrl & 0x40,
>> +        sts = i2c->sts & 0x02,
>> +        act = !!(ena && sts);
>> +
>> +    DPRINTK(1, "IRQ %c ena %c sts %c",
>> +            act ? 'X' : '_',
>> +            ena ? 'X' : '_',
>> +            sts ? 'X' : '_');
>> +
>> +    qemu_set_irq(i2c->irq, act);
>> +}
>> +
>> +static
>> +uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    MPC8540I2CState *i2c = opaque;
>> +    uint32_t val;
>> +
>> +    switch (addr) {
>> +    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)) {
>> +                if (!i2c->dbuf_valid) {
>> +                    LOG(LOG_GUEST_ERROR, "Read during addr or tx");
>> +                }
>> +                i2c->dbuf = 0xff;
>> +                i2c->dbuf_valid = false;
>> +            } else {
>> +                int ret = i2c_recv(i2c->bus);
>> +                i2c->dbuf = (uint8_t)ret;
>> +                i2c->dbuf_valid = true;
>> +                trace_mpc8540_i2c_read(i2c->dbuf);
>> +                I2CSR_SET(MIF, 1);
>> +                I2CSR_SET(RXAK, 0);
>> +                mpc8540_update_irq(i2c);
>> +            }
>> +        } else {
>> +            i2c->dbuf = 0xff;
>> +            i2c->dbuf_valid = false;
>> +            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy");
>> +        }
>> +        break;
>> +    case R_I2CDFSRR: /* FILTER */
>> +        val = i2c->filt;
>> +        break;
>> +    default:
>> +        val = 0xff;
>> +    }
>> +
>> +    DPRINTK(addr == 0xc ? 2 : 1, " read %08x -> %08x",
>> +            (unsigned)addr, (unsigned)val);
>> +    return val;
>> +}
>> +
>> +static
>> +void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>> +{
>> +    MPC8540I2CState *i2c = opaque;
>> +
>> +    DPRINTK(1, " write %08x <- %08x", (unsigned)addr, (unsigned)val);
>> +
>> +    switch (addr) {
>> +    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");
>> +
>> +        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
>> +            /* MSTA 0 -> 1 is START */
>> +
>> +            I2CSR_SET(MBB, 1);
>> +            if (I2CCR(MTX)) {
>> +                trace_mpc8540_i2c_event("START Tx");
>> +            } else {
>> +                trace_mpc8540_i2c_event("START Rx");
>> +            }
>> +            i2c_end_transfer(i2c->bus); /* paranoia */
>> +
>> +        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
>> +            /* MSTA 1 -> 0 is STOP */
>> +
>> +            I2CSR_SET(MBB, 0);
>> +            trace_mpc8540_i2c_event("STOP");
>> +            i2c_end_transfer(i2c->bus);
>> +
>> +        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
>> +            i2c_end_transfer(i2c->bus);
>> +            I2CSR_SET(MBB, 1);
>> +            if (I2CCR(MTX)) {
>> +                trace_mpc8540_i2c_event("REPEAT START Tx");
>> +            } else {
>> +                trace_mpc8540_i2c_event("REPEAT START Rx");
>> +            }
>> +
>> +        }
>> +        /* 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",
>> +                        (unsigned)(val & 0xfe));
>> +                } else {
>> +                    trace_mpc8540_i2c_address((unsigned)(val & 0xfe),
>> +                                              (val & 0x1) ? 'R' : 'T');
>> +                }
>> +                I2CSR_SET(MIF, 1);
>> +                I2CSR_SET(RXAK, 0);
>> +
>> +            } else if (I2CCR(MTX)) {
>> +                trace_mpc8540_i2c_write((unsigned)val);
>> +                i2c_send(i2c->bus, val);
>> +                I2CSR_SET(MIF, 1);
>> +                I2CSR_SET(RXAK, 0);
>> +            } else {
>> +                LOG(LOG_GUEST_ERROR, "I2CDR Write during read");
>> +            }
>> +            mpc8540_update_irq(i2c);
>> +        } else {
>> +            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy");
>> +        }
>> +        break;
>> +    case R_I2CDFSRR: /* FILTER */
>> +        val &= 0x3f;
>> +        i2c->filt = val;
>> +        break;
>> +    }
>> +
>> +    DPRINTK(1, "I2CCR = %02x I2SCR = %02x", 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)
>> +{
>> +    MPC8540I2CState *i2c = MPC8540_I2C(dev);
>> +
>> +    i2c->sts = 0x81; /* transfer complete and ack received */
>> +    i2c->dbuf_valid = false;
>> +}
>> +
>> +static void mpc8540_i2c_inst_init(DeviceState *dev, Error **errp)
>> +{
>> +    MPC8540I2CState *i2c = MPC8540_I2C(dev);
>> +
>> +    i2c->bus = i2c_init_bus(dev, "bus");
>> +
>> +    memory_region_init_io(&i2c->mmio, OBJECT(dev),
>> +                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
>> +
>> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->mmio);
>> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
>> +}
> 
> As someone pointed out on the earlier version, this stuff needs to go
> into a realize() function rather than instance_init - instance_init is
> called too early to go safely constructing and installing memory
> regions.

In fact I did (see "dc->realize" below), but apparently managed to change the argument list
without thinking to re-name the function.  I will do so now...

>> +
>> +static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->realize = &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(MPC8540I2CState),
>> +    .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)
>> diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
>> index 9284b1fbad..ac38d76984 100644
>> --- a/hw/i2c/trace-events
>> +++ b/hw/i2c/trace-events
>> @@ -1 +1,7 @@
>>  # See docs/devel/tracing.txt for syntax documentation.
>> +
>> +# hw/i2c/mpc8540_i2c.c
>> +mpc8540_i2c_event(const char *evt) "Bus Event %s"
>> +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX"
>> +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x"
>> +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
> 



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

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

* Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
  2017-11-27 19:05     ` Michael Davidsaver
@ 2017-11-29  1:32       ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-11-29  1:32 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Mon, Nov 27, 2017 at 01:05:11PM -0600, Michael Davidsaver wrote:
> On 11/27/2017 01:12 AM, David Gibson wrote:
> > On Sun, Nov 26, 2017 at 03:59:01PM -0600, Michael Davidsaver wrote:
> >> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> >> ---
> >>  hw/i2c/Makefile.objs |   1 +
> >>  hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  hw/i2c/trace-events  |   6 +
> >>  3 files changed, 314 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..b9f5773b35
> >> --- /dev/null
> >> +++ b/hw/i2c/mpc8540_i2c.c
> >> @@ -0,0 +1,307 @@
> >> +/*
> >> + * MPC8540 I2C bus interface
> >> + * As described in
> >> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
> >> + * Part 2 chapter 11
> >> + *
> >> + * Compatible I2C controllers are found on other Freescale chips
> >> + * including mpc8544 and P2010.
> >> + *
> >> + * 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"
> >> +#include "qemu/error-report.h"
> >> +
> >> +#include "trace.h"
> >> +
> >> +/* #define DEBUG_LVL 0 */
> >> +
> >> +#ifdef DEBUG_LVL
> >> +#define DPRINTK(LVL, FMT, ...) do { \
> >> +    if ((LVL) <= DEBUG_LVL) {\
> >> +        info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \
> >> +    } } while (0)
> >> +#else
> >> +#define DPRINTK(LVL, FMT, ...) do {} while (0)
> >> +#endif
> > 
> > So, you have both this DPRINTK stuff, and some trace events, which
> > seems a bit odd?  Why not just one or the other.
> 
> My thinking is to have trace events for the commonly used points (by me at least)
> for troubleshooting devices on the i2c bus, but leave the others for troubleshooting
> the i2c controller itself as DPRINTK.
> 
> So this is mainly my laziness in not seeing sufficient benefit to defining events for the
> remaining 5 DPRINTK s.

I sympathize - I have mixed feelings about tracepoints myself.  But
they remain the preferred debugging approach in qemu.

To address they issue above, I suggest you use a consistent naming
scheme for the "common" vs. "rare" tracepoints, that way the whole of
one set or the other can be enabled/disabled with a single wildcard.


> 
> >> +
> >> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
> >> +    " : " FMT "\n", ## __VA_ARGS__)
> >> +
> >> +#define TYPE_MPC8540_I2C "mpc8540-i2c"
> >> +#define MPC8540_I2C(obj) OBJECT_CHECK(MPC8540I2CState, (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 MPC8540I2CState {
> >> +    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, dbuf_valid;
> >> +
> >> +    qemu_irq irq;
> >> +
> >> +    MemoryRegion mmio;
> >> +} MPC8540I2CState;
> >> +
> >> +#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(MPC8540I2CState *i2c)
> >> +{
> >> +    int ena = i2c->ctrl & 0x40,
> >> +        sts = i2c->sts & 0x02,
> >> +        act = !!(ena && sts);
> >> +
> >> +    DPRINTK(1, "IRQ %c ena %c sts %c",
> >> +            act ? 'X' : '_',
> >> +            ena ? 'X' : '_',
> >> +            sts ? 'X' : '_');
> >> +
> >> +    qemu_set_irq(i2c->irq, act);
> >> +}
> >> +
> >> +static
> >> +uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
> >> +{
> >> +    MPC8540I2CState *i2c = opaque;
> >> +    uint32_t val;
> >> +
> >> +    switch (addr) {
> >> +    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)) {
> >> +                if (!i2c->dbuf_valid) {
> >> +                    LOG(LOG_GUEST_ERROR, "Read during addr or tx");
> >> +                }
> >> +                i2c->dbuf = 0xff;
> >> +                i2c->dbuf_valid = false;
> >> +            } else {
> >> +                int ret = i2c_recv(i2c->bus);
> >> +                i2c->dbuf = (uint8_t)ret;
> >> +                i2c->dbuf_valid = true;
> >> +                trace_mpc8540_i2c_read(i2c->dbuf);
> >> +                I2CSR_SET(MIF, 1);
> >> +                I2CSR_SET(RXAK, 0);
> >> +                mpc8540_update_irq(i2c);
> >> +            }
> >> +        } else {
> >> +            i2c->dbuf = 0xff;
> >> +            i2c->dbuf_valid = false;
> >> +            LOG(LOG_GUEST_ERROR, "Read when not enabled or busy");
> >> +        }
> >> +        break;
> >> +    case R_I2CDFSRR: /* FILTER */
> >> +        val = i2c->filt;
> >> +        break;
> >> +    default:
> >> +        val = 0xff;
> >> +    }
> >> +
> >> +    DPRINTK(addr == 0xc ? 2 : 1, " read %08x -> %08x",
> >> +            (unsigned)addr, (unsigned)val);
> >> +    return val;
> >> +}
> >> +
> >> +static
> >> +void mpc8540_i2c_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> >> +{
> >> +    MPC8540I2CState *i2c = opaque;
> >> +
> >> +    DPRINTK(1, " write %08x <- %08x", (unsigned)addr, (unsigned)val);
> >> +
> >> +    switch (addr) {
> >> +    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");
> >> +
> >> +        } else if (!I2CCR(MSTA) && FIELD_EX32(val, I2CCR, MSTA)) {
> >> +            /* MSTA 0 -> 1 is START */
> >> +
> >> +            I2CSR_SET(MBB, 1);
> >> +            if (I2CCR(MTX)) {
> >> +                trace_mpc8540_i2c_event("START Tx");
> >> +            } else {
> >> +                trace_mpc8540_i2c_event("START Rx");
> >> +            }
> >> +            i2c_end_transfer(i2c->bus); /* paranoia */
> >> +
> >> +        } else if (I2CCR(MSTA) && !FIELD_EX32(val, I2CCR, MSTA)) {
> >> +            /* MSTA 1 -> 0 is STOP */
> >> +
> >> +            I2CSR_SET(MBB, 0);
> >> +            trace_mpc8540_i2c_event("STOP");
> >> +            i2c_end_transfer(i2c->bus);
> >> +
> >> +        } else if (I2CCR(MSTA) && FIELD_EX32(val, I2CCR, RSTA)) {
> >> +            i2c_end_transfer(i2c->bus);
> >> +            I2CSR_SET(MBB, 1);
> >> +            if (I2CCR(MTX)) {
> >> +                trace_mpc8540_i2c_event("REPEAT START Tx");
> >> +            } else {
> >> +                trace_mpc8540_i2c_event("REPEAT START Rx");
> >> +            }
> >> +
> >> +        }
> >> +        /* 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",
> >> +                        (unsigned)(val & 0xfe));
> >> +                } else {
> >> +                    trace_mpc8540_i2c_address((unsigned)(val & 0xfe),
> >> +                                              (val & 0x1) ? 'R' : 'T');
> >> +                }
> >> +                I2CSR_SET(MIF, 1);
> >> +                I2CSR_SET(RXAK, 0);
> >> +
> >> +            } else if (I2CCR(MTX)) {
> >> +                trace_mpc8540_i2c_write((unsigned)val);
> >> +                i2c_send(i2c->bus, val);
> >> +                I2CSR_SET(MIF, 1);
> >> +                I2CSR_SET(RXAK, 0);
> >> +            } else {
> >> +                LOG(LOG_GUEST_ERROR, "I2CDR Write during read");
> >> +            }
> >> +            mpc8540_update_irq(i2c);
> >> +        } else {
> >> +            LOG(LOG_GUEST_ERROR, "I2CDR Write when not enabled or busy");
> >> +        }
> >> +        break;
> >> +    case R_I2CDFSRR: /* FILTER */
> >> +        val &= 0x3f;
> >> +        i2c->filt = val;
> >> +        break;
> >> +    }
> >> +
> >> +    DPRINTK(1, "I2CCR = %02x I2SCR = %02x", 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)
> >> +{
> >> +    MPC8540I2CState *i2c = MPC8540_I2C(dev);
> >> +
> >> +    i2c->sts = 0x81; /* transfer complete and ack received */
> >> +    i2c->dbuf_valid = false;
> >> +}
> >> +
> >> +static void mpc8540_i2c_inst_init(DeviceState *dev, Error **errp)
> >> +{
> >> +    MPC8540I2CState *i2c = MPC8540_I2C(dev);
> >> +
> >> +    i2c->bus = i2c_init_bus(dev, "bus");
> >> +
> >> +    memory_region_init_io(&i2c->mmio, OBJECT(dev),
> >> +                          &i2c_ops, i2c, TYPE_MPC8540_I2C, 0x18);
> >> +
> >> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->mmio);
> >> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
> >> +}
> > 
> > As someone pointed out on the earlier version, this stuff needs to go
> > into a realize() function rather than instance_init - instance_init is
> > called too early to go safely constructing and installing memory
> > regions.
> 
> In fact I did (see "dc->realize" below), but apparently managed to change the argument list
> without thinking to re-name the function.  I will do so now...
> 
> >> +
> >> +static void mpc8540_i2c_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    DeviceClass *dc = DEVICE_CLASS(klass);
> >> +
> >> +    dc->realize = &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(MPC8540I2CState),
> >> +    .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)
> >> diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
> >> index 9284b1fbad..ac38d76984 100644
> >> --- a/hw/i2c/trace-events
> >> +++ b/hw/i2c/trace-events
> >> @@ -1 +1,7 @@
> >>  # See docs/devel/tracing.txt for syntax documentation.
> >> +
> >> +# hw/i2c/mpc8540_i2c.c
> >> +mpc8540_i2c_event(const char *evt) "Bus Event %s"
> >> +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX"
> >> +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x"
> >> +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
> > 
> 
> 




-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices Michael Davidsaver
@ 2017-11-30  5:13   ` David Gibson
  2017-12-03 21:15     ` Michael Davidsaver
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-11-30  5:13 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote:
> Support for: ds1307, ds1337, ds1338, ds1339,
> ds1340, ds1375, ds1388, and ds3231.
> 
> Tested with ds1338 and ds1375.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

I certainly like the idea of consolidating this code, but reviewing to
see that the new code really is a generalization of the old is
something I won't have time for for a while.

Also, hw/timer is not within my purview so it'll probably need to go
another path to merge.

> ---
>  default-configs/arm-softmmu.mak |   2 +-
>  hw/timer/Makefile.objs          |   2 +-
>  hw/timer/ds-rtc-i2c.c           | 461 ++++++++++++++++++++++++++++++++++++++++
>  hw/timer/ds1338.c               | 239 ---------------------
>  4 files changed, 463 insertions(+), 241 deletions(-)
>  create mode 100644 hw/timer/ds-rtc-i2c.c
>  delete mode 100644 hw/timer/ds1338.c
> 
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index d37edc4312..b857823681 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -31,7 +31,7 @@ CONFIG_SMC91C111=y
>  CONFIG_ALLWINNER_EMAC=y
>  CONFIG_IMX_FEC=y
>  CONFIG_FTGMAC100=y
> -CONFIG_DS1338=y
> +CONFIG_DSRTCI2C=y
>  CONFIG_PFLASH_CFI01=y
>  CONFIG_PFLASH_CFI02=y
>  CONFIG_MICRODRIVE=y
> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> index 8c19eac3b6..290015ebec 100644
> --- a/hw/timer/Makefile.objs
> +++ b/hw/timer/Makefile.objs
> @@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
>  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_DSRTCI2C) += ds-rtc-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/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c
> new file mode 100644
> index 0000000000..ad2f8f2a68
> --- /dev/null
> +++ b/hw/timer/ds-rtc-i2c.c
> @@ -0,0 +1,461 @@
> +/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus
> + *
> + * Copyright (c) 2017 Michael Davidsaver
> + * Copyright (c) 2009 CodeSourcery
> + *
> + * Authors: Michael Davidsaver
> + *          Paul Brook
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the LICENSE file in the top-level directory.
> + *
> + * Models real time read/set and NVRAM.
> + * Does not model alarms, or control/status registers.
> + *
> + * Generalized register map is:
> + *   [Current time]
> + *   [Alarm settings] (optional)
> + *   [Control/Status] (optional)
> + *   [Non-volatile memory] (optional)
> + *
> + * The current time registers are almost always the same,
> + * with the exception being that some have a CENTURY bit
> + * in the month register.
> + */
> +#include "qemu/osdep.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"
> +#include "sysemu/qtest.h"
> +#include "qemu/error-report.h"
> +
> +/* #define DEBUG_DSRTC */
> +
> +#ifdef DEBUG_DSRTC
> +#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__)
> +#else
> +#define DPRINTK(FMT, ...) do {} while (0)
> +#endif
> +
> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \
> +                            ## __VA_ARGS__)
> +
> +#define DSRTC_REGSIZE (0x40)
> +
> +/* values stored in BCD */
> +/* 00-59 */
> +#define R_SEC   (0x0)
> +/* 00-59 */
> +#define R_MIN   (0x1)
> +#define R_HOUR  (0x2)
> +/* 1-7 */
> +#define R_WDAY  (0x3)
> +/* 0-31 */
> +#define R_DATE  (0x4)
> +#define R_MONTH (0x5)
> +/* 0-99 */
> +#define R_YEAR  (0x6)
> +
> +/* use 12 hour mode when set */
> +FIELD(HOUR, SET12, 6, 1)
> +/* 00-23 */
> +FIELD(HOUR, HOUR24, 0, 6)
> +FIELD(HOUR, AMPM, 5, 1)
> +/* 1-12 (not 0-11!) */
> +FIELD(HOUR, HOUR12, 0, 5)
> +
> +/* 1-12 */
> +FIELD(MONTH, MONTH, 0, 5)
> +FIELD(MONTH, CENTURY, 7, 1)
> +
> +typedef struct DSRTCInfo {
> +    /* if bit 7 of the Month register is set after Y2K */
> +    bool has_century;
> +    /* address of first non-volatile memory cell.
> +     * nv_start >= reg_end means no NV memory.
> +     */
> +    uint8_t nv_start;
> +    /* total size of register range.  When address counter rolls over. */
> +    uint8_t reg_size;
> +} DSRTCInfo;
> +
> +typedef struct DSRTCState {
> +    I2CSlave parent_obj;
> +
> +    const DSRTCInfo *info;
> +
> +    qemu_irq alarm_irq;
> +
> +    /* register address counter */
> +    uint8_t addr;
> +    /* when writing, whether the address has been sent */
> +    bool addrd;
> +
> +    int64_t time_offset;
> +    int8_t wday_offset;
> +
> +    uint8_t regs[DSRTC_REGSIZE];
> +} DSRTCState;
> +
> +typedef struct DSRTCClass {
> +    I2CSlaveClass parent_class;
> +
> +    const DSRTCInfo *info;
> +} DSRTCClass;
> +
> +#define TYPE_DSRTC "ds-rtc-i2c"
> +#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
> +#define DSRTC_GET_CLASS(obj) \
> +    OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC)
> +#define DSRTC_CLASS(klass) \
> +    OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC)
> +
> +static const VMStateDescription vmstate_dsrtc = {
> +    .name = TYPE_DSRTC,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
> +        VMSTATE_INT64(time_offset, DSRTCState),
> +        VMSTATE_INT8_V(wday_offset, DSRTCState, 2),
> +        VMSTATE_UINT8_ARRAY(regs, DSRTCState, DSRTC_REGSIZE),
> +        VMSTATE_UINT8(addr, DSRTCState),
> +        VMSTATE_BOOL(addrd, DSRTCState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void dsrtc_reset(DeviceState *device);
> +
> +/* update current time registers */
> +static
> +void dsrtc_latch(DSRTCState *ds)
> +{
> +    struct tm now;
> +    bool use12;
> +
> +    qemu_get_timedate(&now, ds->time_offset);
> +
> +    DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)",
> +            now.tm_year, now.tm_mon, now.tm_mday,
> +            now.tm_hour, now.tm_min, now.tm_sec,
> +            now.tm_wday);
> +
> +    use12 = ARRAY_FIELD_EX32(ds->regs, HOUR, SET12);
> +
> +    /* 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 (!use12) {
> +        /* 24 hour (0-23) */
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour));
> +    } else {
> +        /* 12 hour am/pm (1-12) */
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, SET12, 1);
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12u);
> +        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12,
> +                         to_bcd(1u + (now.tm_hour % 12u)));
> +    }
> +
> +    ds->regs[R_WDAY] = (now.tm_wday + ds->wday_offset) % 7u + 1u;
> +    ds->regs[R_DATE] = to_bcd(now.tm_mday);
> +
> +    ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1));
> +    if (ds->info->has_century) {
> +        ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year >= 100u);
> +    }
> +
> +    ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u);
> +
> +    DPRINTK("Latched time");
> +}
> +
> +/* call after guest writes to current time registers
> + * to re-compute our offset from host time.
> + */
> +static
> +void dsrtc_update(DSRTCState *ds)
> +{
> +    int user_wday;
> +    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)) {
> +        /* 12 hour (1-12) */
> +        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR12)) - 1u;
> +        if (ARRAY_FIELD_EX32(ds->regs, HOUR, AMPM)) {
> +            now.tm_hour += 12;
> +        }
> +
> +    } else {
> +        /* 23 hour (0-23) */
> +        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR24));
> +    }
> +
> +    now.tm_wday = from_bcd(ds->regs[R_WDAY]) - 1u;
> +    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]);
> +    if (ARRAY_FIELD_EX32(ds->regs, MONTH, CENTURY) || !ds->info->has_century) {
> +        now.tm_year += 100;
> +    }
> +
> +    DPRINTK("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)",
> +            now.tm_year, now.tm_mon, now.tm_mday,
> +            now.tm_hour, now.tm_min, now.tm_sec,
> +            now.tm_wday);
> +
> +    /* round trip to get real wday_offset based on time delta */
> +    user_wday = now.tm_wday;
> +    ds->time_offset = qemu_timedate_diff(&now);
> +    /* race possible if we run at midnight
> +     * TODO: make qemu_timedate_diff() calculate wday offset as well?
> +     */
> +    qemu_get_timedate(&now, ds->time_offset);
> +    /* calculate wday_offset to achieve guest requested wday */
> +    ds->wday_offset = user_wday - now.tm_wday;
> +
> +    DPRINTK("Update offset = %" PRId64 ", wday_offset = %d",
> +            ds->time_offset, ds->wday_offset);
> +}
> +
> +static
> +void dsrtc_advance(DSRTCState *ds)
> +{
> +    ds->addr = (ds->addr + 1) % ds->info->reg_size;
> +    if (ds->addr == 0) {
> +        /* latch time on roll over */
> +        dsrtc_latch(ds);
> +    }
> +}
> +
> +static
> +int dsrtc_event(I2CSlave *s, enum i2c_event event)
> +{
> +    DSRTCState *ds = DSRTC(s);
> +
> +    switch (event) {
> +    case I2C_START_SEND:
> +        ds->addrd = false;
> +        /* fall through */
> +    case I2C_START_RECV:
> +        dsrtc_latch(ds);
> +        /* fall through */
> +    case I2C_FINISH:
> +        DPRINTK("Event %d", (int)event);
> +        /* fall through */
> +    case I2C_NACK:
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static
> +int dsrtc_recv(I2CSlave *s)
> +{
> +    DSRTCState *ds = DSRTC(s);
> +    int ret = 0;
> +
> +    ret = ds->regs[ds->addr];
> +
> +    if (ds->addr > R_YEAR && ds->addr < ds->info->nv_start) {
> +        LOG(LOG_UNIMP, "Read from unimplemented (%02x) %02x", ds->addr, ret);
> +    }
> +
> +    DPRINTK("Recv (%02x) %02x", ds->addr, ret);
> +
> +    dsrtc_advance(ds);
> +
> +    return ret;
> +}
> +
> +static
> +int dsrtc_send(I2CSlave *s, uint8_t data)
> +{
> +    DSRTCState *ds = DSRTC(s);
> +
> +    if (!ds->addrd) {
> +        if (data == 0xff && qtest_enabled()) {
> +            /* allow test runner to zero offsets */
> +            DPRINTK("Testing reset");
> +            dsrtc_reset(DEVICE(s));
> +            return 0;
> +        }
> +        ds->addr = data % DSRTC_REGSIZE;
> +        ds->addrd = true;
> +        DPRINTK("Set address pointer %02x", data);
> +        return 0;
> +    }
> +
> +    DPRINTK("Send (%02x) %02x", ds->addr, data);
> +
> +    if (ds->addr <= R_YEAR) {
> +        ds->regs[ds->addr] = data;
> +        dsrtc_update(ds);
> +
> +    } else if (ds->addr >= ds->info->nv_start) {
> +        ds->regs[ds->addr] = data;
> +
> +    } else {
> +        LOG(LOG_UNIMP, "Register not modeled");
> +    }
> +
> +    dsrtc_advance(ds);
> +
> +    return 0;
> +}
> +
> +static
> +void dsrtc_reset(DeviceState *device)
> +{
> +    DSRTCState *ds = DSRTC(device);
> +
> +    memset(ds->regs, 0, sizeof(ds->regs));
> +
> +    ds->addr = 0;
> +    ds->addrd = false;
> +    ds->time_offset = 0;
> +    ds->wday_offset = 0;
> +
> +    DPRINTK("Reset");
> +}
> +
> +static
> +void dsrtc_realize(DeviceState *device, Error **errp)
> +{
> +    DSRTCState *ds = DSRTC(device);
> +    DSRTCClass *r = DSRTC_GET_CLASS(device);
> +
> +    ds->info = r->info;
> +
> +    /* Alarms not yet implemented, but allow
> +     * board code to wire up the alarm interrupt
> +     * output anyway.
> +     */
> +    qdev_init_gpio_out(device, &ds->alarm_irq, 1);
> +}
> +
> +static
> +void dsrtc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> +    DSRTCClass *r = DSRTC_CLASS(klass);
> +
> +    r->info = data;
> +
> +    k->event = &dsrtc_event;
> +    k->recv = &dsrtc_recv;
> +    k->send = &dsrtc_send;
> +
> +    dc->vmsd = &vmstate_dsrtc;
> +    dc->realize = dsrtc_realize;
> +    dc->reset = dsrtc_reset;
> +    dc->user_creatable = true;
> +}
> +
> +static
> +const TypeInfo ds_rtc_base_type = {
> +    .abstract = true,
> +    .name = TYPE_DSRTC,
> +    .parent = TYPE_I2C_SLAVE,
> +    .instance_size = sizeof(DSRTCState),
> +};
> +
> +#define DSRTC_CONFIG(NAME) \
> +static const TypeInfo NAME##_type = { \
> +    .name = #NAME, \
> +    .parent = TYPE_DSRTC, \
> +    .class_size = sizeof(I2CSlaveClass), \
> +    .class_init = dsrtc_class_init, \
> +    .class_data = (void *)&NAME##_info, \
> +};
> +
> +/* ds3231 - alarms, no eeprom */
> +static const DSRTCInfo ds3231_info = {
> +    .has_century = true,
> +    .nv_start    = 0x13, /* no nv memory */
> +    .reg_size    = 0x13,
> +};
> +DSRTC_CONFIG(ds3231)
> +
> +/* only model block 0 (RTC), blocks 1,2 (eeprom) not modeled.
> + * blocks have different i2c addresses
> + */
> +static const DSRTCInfo ds1388_info = {
> +    .has_century = false,
> +    .nv_start    = 0x0d,
> +    .reg_size    = 0x0d,
> +};
> +DSRTC_CONFIG(ds1388)
> +
> +/* alarms, eeprom */
> +static const DSRTCInfo ds1375_info = {
> +    .has_century = true,
> +    .nv_start    = 0x10,
> +    .reg_size    = 0x20,
> +};
> +DSRTC_CONFIG(ds1375)
> +
> +/* no alarms, no eeprom */
> +static const DSRTCInfo ds1340_info = {
> +    .has_century = false,
> +    .nv_start    = 0x10,
> +    .reg_size    = 0x10,
> +};
> +DSRTC_CONFIG(ds1340)
> +
> +/* alarms, no eeprom */
> +static const DSRTCInfo ds1339_info = {
> +    .has_century = false,
> +    .nv_start    = 0x11,
> +    .reg_size    = 0x11,
> +};
> +DSRTC_CONFIG(ds1339)
> +
> +/* no alarms, eeprom */
> +static const DSRTCInfo ds1338_info = {
> +    .has_century = false,
> +    .nv_start    = 0x08,
> +    .reg_size    = 0x40,
> +};
> +DSRTC_CONFIG(ds1338)
> +
> +/* alarms, no eeprom */
> +static const DSRTCInfo ds1337_info = {
> +    .has_century = true,
> +    .nv_start    = 0x10,
> +    .reg_size    = 0x10,
> +};
> +DSRTC_CONFIG(ds1337)
> +
> +/* ds1307 registers are identical to ds1338 */
> +static
> +const TypeInfo ds1307_type = {
> +    .name = "ds1307",
> +    .parent = "ds1338",
> +};
> +
> +static void ds_rtc_i2c_register(void)
> +{
> +    type_register_static(&ds_rtc_base_type);
> +    type_register_static(&ds3231_type);
> +    type_register_static(&ds1388_type);
> +    type_register_static(&ds1375_type);
> +    type_register_static(&ds1340_type);
> +    type_register_static(&ds1339_type);
> +    type_register_static(&ds1338_type);
> +    type_register_static(&ds1337_type);
> +    type_register_static(&ds1307_type);
> +}
> +
> +type_init(ds_rtc_i2c_register)
> diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
> deleted file mode 100644
> index 3849b74a68..0000000000
> --- a/hw/timer/ds1338.c
> +++ /dev/null
> @@ -1,239 +0,0 @@
> -/*
> - * MAXIM DS1338 I2C RTC+NVRAM
> - *
> - * Copyright (c) 2009 CodeSourcery.
> - * Written by Paul Brook
> - *
> - * This code is licensed under the GNU GPL v2.
> - *
> - * Contributions after 2012-01-13 are licensed under the terms of the
> - * GNU GPL, version 2 or (at your option) any later version.
> - */
> -
> -#include "qemu/osdep.h"
> -#include "qemu-common.h"
> -#include "hw/i2c/i2c.h"
> -#include "qemu/bcd.h"
> -
> -/* Size of NVRAM including both the user-accessible area and the
> - * secondary register area.
> - */
> -#define NVRAM_SIZE 64
> -
> -/* Flags definitions */
> -#define SECONDS_CH 0x80
> -#define HOURS_12   0x40
> -#define HOURS_PM   0x20
> -#define CTRL_OSF   0x20
> -
> -#define TYPE_DS1338 "ds1338"
> -#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
> -
> -typedef struct DS1338State {
> -    I2CSlave parent_obj;
> -
> -    int64_t offset;
> -    uint8_t wday_offset;
> -    uint8_t nvram[NVRAM_SIZE];
> -    int32_t ptr;
> -    bool addr_byte;
> -} DS1338State;
> -
> -static const VMStateDescription vmstate_ds1338 = {
> -    .name = "ds1338",
> -    .version_id = 2,
> -    .minimum_version_id = 1,
> -    .fields = (VMStateField[]) {
> -        VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
> -        VMSTATE_INT64(offset, DS1338State),
> -        VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
> -        VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
> -        VMSTATE_INT32(ptr, DS1338State),
> -        VMSTATE_BOOL(addr_byte, DS1338State),
> -        VMSTATE_END_OF_LIST()
> -    }
> -};
> -
> -static void capture_current_time(DS1338State *s)
> -{
> -    /* Capture the current time into the secondary registers
> -     * which will be actually read by the data transfer operation.
> -     */
> -    struct tm now;
> -    qemu_get_timedate(&now, s->offset);
> -    s->nvram[0] = to_bcd(now.tm_sec);
> -    s->nvram[1] = to_bcd(now.tm_min);
> -    if (s->nvram[2] & HOURS_12) {
> -        int tmp = now.tm_hour;
> -        if (tmp % 12 == 0) {
> -            tmp += 12;
> -        }
> -        if (tmp <= 12) {
> -            s->nvram[2] = HOURS_12 | to_bcd(tmp);
> -        } else {
> -            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
> -        }
> -    } else {
> -        s->nvram[2] = to_bcd(now.tm_hour);
> -    }
> -    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
> -    s->nvram[4] = to_bcd(now.tm_mday);
> -    s->nvram[5] = to_bcd(now.tm_mon + 1);
> -    s->nvram[6] = to_bcd(now.tm_year - 100);
> -}
> -
> -static void inc_regptr(DS1338State *s)
> -{
> -    /* The register pointer wraps around after 0x3F; wraparound
> -     * causes the current time/date to be retransferred into
> -     * the secondary registers.
> -     */
> -    s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
> -    if (!s->ptr) {
> -        capture_current_time(s);
> -    }
> -}
> -
> -static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
> -{
> -    DS1338State *s = DS1338(i2c);
> -
> -    switch (event) {
> -    case I2C_START_RECV:
> -        /* In h/w, capture happens on any START condition, not just a
> -         * START_RECV, but there is no need to actually capture on
> -         * START_SEND, because the guest can't get at that data
> -         * without going through a START_RECV which would overwrite it.
> -         */
> -        capture_current_time(s);
> -        break;
> -    case I2C_START_SEND:
> -        s->addr_byte = true;
> -        break;
> -    default:
> -        break;
> -    }
> -
> -    return 0;
> -}
> -
> -static int ds1338_recv(I2CSlave *i2c)
> -{
> -    DS1338State *s = DS1338(i2c);
> -    uint8_t res;
> -
> -    res  = s->nvram[s->ptr];
> -    inc_regptr(s);
> -    return res;
> -}
> -
> -static int ds1338_send(I2CSlave *i2c, uint8_t data)
> -{
> -    DS1338State *s = DS1338(i2c);
> -
> -    if (s->addr_byte) {
> -        s->ptr = data & (NVRAM_SIZE - 1);
> -        s->addr_byte = false;
> -        return 0;
> -    }
> -    if (s->ptr < 7) {
> -        /* Time register. */
> -        struct tm now;
> -        qemu_get_timedate(&now, s->offset);
> -        switch(s->ptr) {
> -        case 0:
> -            /* TODO: Implement CH (stop) bit.  */
> -            now.tm_sec = from_bcd(data & 0x7f);
> -            break;
> -        case 1:
> -            now.tm_min = from_bcd(data & 0x7f);
> -            break;
> -        case 2:
> -            if (data & HOURS_12) {
> -                int tmp = from_bcd(data & (HOURS_PM - 1));
> -                if (data & HOURS_PM) {
> -                    tmp += 12;
> -                }
> -                if (tmp % 12 == 0) {
> -                    tmp -= 12;
> -                }
> -                now.tm_hour = tmp;
> -            } else {
> -                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
> -            }
> -            break;
> -        case 3:
> -            {
> -                /* The day field is supposed to contain a value in
> -                   the range 1-7. Otherwise behavior is undefined.
> -                 */
> -                int user_wday = (data & 7) - 1;
> -                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
> -            }
> -            break;
> -        case 4:
> -            now.tm_mday = from_bcd(data & 0x3f);
> -            break;
> -        case 5:
> -            now.tm_mon = from_bcd(data & 0x1f) - 1;
> -            break;
> -        case 6:
> -            now.tm_year = from_bcd(data) + 100;
> -            break;
> -        }
> -        s->offset = qemu_timedate_diff(&now);
> -    } else if (s->ptr == 7) {
> -        /* Control register. */
> -
> -        /* Ensure bits 2, 3 and 6 will read back as zero. */
> -        data &= 0xB3;
> -
> -        /* Attempting to write the OSF flag to logic 1 leaves the
> -           value unchanged. */
> -        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
> -
> -        s->nvram[s->ptr] = data;
> -    } else {
> -        s->nvram[s->ptr] = data;
> -    }
> -    inc_regptr(s);
> -    return 0;
> -}
> -
> -static void ds1338_reset(DeviceState *dev)
> -{
> -    DS1338State *s = DS1338(dev);
> -
> -    /* The clock is running and synchronized with the host */
> -    s->offset = 0;
> -    s->wday_offset = 0;
> -    memset(s->nvram, 0, NVRAM_SIZE);
> -    s->ptr = 0;
> -    s->addr_byte = false;
> -}
> -
> -static void ds1338_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> -
> -    k->event = ds1338_event;
> -    k->recv = ds1338_recv;
> -    k->send = ds1338_send;
> -    dc->reset = ds1338_reset;
> -    dc->vmsd = &vmstate_ds1338;
> -}
> -
> -static const TypeInfo ds1338_info = {
> -    .name          = TYPE_DS1338,
> -    .parent        = TYPE_I2C_SLAVE,
> -    .instance_size = sizeof(DS1338State),
> -    .class_init    = ds1338_class_init,
> -};
> -
> -static void ds1338_register_types(void)
> -{
> -    type_register_static(&ds1338_info);
> -}
> -
> -type_init(ds1338_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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
  2017-11-30  5:13   ` David Gibson
@ 2017-12-03 21:15     ` Michael Davidsaver
  2017-12-06 11:14       ` David Gibson
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-12-03 21:15 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On 11/29/2017 11:13 PM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote:
>> Support for: ds1307, ds1337, ds1338, ds1339,
>> ds1340, ds1375, ds1388, and ds3231.
>>
>> Tested with ds1338 and ds1375.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> I certainly like the idea of consolidating this code, but reviewing to
> see that the new code really is a generalization of the old is
> something I won't have time for for a while.
> 
> Also, hw/timer is not within my purview so it'll probably need to go
> another path to merge.

Could you be a bit more explicit about what, if anything, I need to do
to move this forward?


>> ---
>>  default-configs/arm-softmmu.mak |   2 +-
>>  hw/timer/Makefile.objs          |   2 +-
>>  hw/timer/ds-rtc-i2c.c           | 461 ++++++++++++++++++++++++++++++++++++++++
>>  hw/timer/ds1338.c               | 239 ---------------------
>>  4 files changed, 463 insertions(+), 241 deletions(-)
>>  create mode 100644 hw/timer/ds-rtc-i2c.c
>>  delete mode 100644 hw/timer/ds1338.c
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index d37edc4312..b857823681 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -31,7 +31,7 @@ CONFIG_SMC91C111=y
>>  CONFIG_ALLWINNER_EMAC=y
>>  CONFIG_IMX_FEC=y
>>  CONFIG_FTGMAC100=y
>> -CONFIG_DS1338=y
>> +CONFIG_DSRTCI2C=y
>>  CONFIG_PFLASH_CFI01=y
>>  CONFIG_PFLASH_CFI02=y
>>  CONFIG_MICRODRIVE=y
>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>> index 8c19eac3b6..290015ebec 100644
>> --- a/hw/timer/Makefile.objs
>> +++ b/hw/timer/Makefile.objs
>> @@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
>>  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_DSRTCI2C) += ds-rtc-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/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c
>> new file mode 100644
>> index 0000000000..ad2f8f2a68
>> --- /dev/null
>> +++ b/hw/timer/ds-rtc-i2c.c
>> @@ -0,0 +1,461 @@
>> +/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus
>> + *
>> + * Copyright (c) 2017 Michael Davidsaver
>> + * Copyright (c) 2009 CodeSourcery
>> + *
>> + * Authors: Michael Davidsaver
>> + *          Paul Brook
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the LICENSE file in the top-level directory.
>> + *
>> + * Models real time read/set and NVRAM.
>> + * Does not model alarms, or control/status registers.
>> + *
>> + * Generalized register map is:
>> + *   [Current time]
>> + *   [Alarm settings] (optional)
>> + *   [Control/Status] (optional)
>> + *   [Non-volatile memory] (optional)
>> + *
>> + * The current time registers are almost always the same,
>> + * with the exception being that some have a CENTURY bit
>> + * in the month register.
>> + */
>> +#include "qemu/osdep.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"
>> +#include "sysemu/qtest.h"
>> +#include "qemu/error-report.h"
>> +
>> +/* #define DEBUG_DSRTC */
>> +
>> +#ifdef DEBUG_DSRTC
>> +#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__)
>> +#else
>> +#define DPRINTK(FMT, ...) do {} while (0)
>> +#endif
>> +
>> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \
>> +                            ## __VA_ARGS__)
>> +
>> +#define DSRTC_REGSIZE (0x40)
>> +
>> +/* values stored in BCD */
>> +/* 00-59 */
>> +#define R_SEC   (0x0)
>> +/* 00-59 */
>> +#define R_MIN   (0x1)
>> +#define R_HOUR  (0x2)
>> +/* 1-7 */
>> +#define R_WDAY  (0x3)
>> +/* 0-31 */
>> +#define R_DATE  (0x4)
>> +#define R_MONTH (0x5)
>> +/* 0-99 */
>> +#define R_YEAR  (0x6)
>> +
>> +/* use 12 hour mode when set */
>> +FIELD(HOUR, SET12, 6, 1)
>> +/* 00-23 */
>> +FIELD(HOUR, HOUR24, 0, 6)
>> +FIELD(HOUR, AMPM, 5, 1)
>> +/* 1-12 (not 0-11!) */
>> +FIELD(HOUR, HOUR12, 0, 5)
>> +
>> +/* 1-12 */
>> +FIELD(MONTH, MONTH, 0, 5)
>> +FIELD(MONTH, CENTURY, 7, 1)
>> +
>> +typedef struct DSRTCInfo {
>> +    /* if bit 7 of the Month register is set after Y2K */
>> +    bool has_century;
>> +    /* address of first non-volatile memory cell.
>> +     * nv_start >= reg_end means no NV memory.
>> +     */
>> +    uint8_t nv_start;
>> +    /* total size of register range.  When address counter rolls over. */
>> +    uint8_t reg_size;
>> +} DSRTCInfo;
>> +
>> +typedef struct DSRTCState {
>> +    I2CSlave parent_obj;
>> +
>> +    const DSRTCInfo *info;
>> +
>> +    qemu_irq alarm_irq;
>> +
>> +    /* register address counter */
>> +    uint8_t addr;
>> +    /* when writing, whether the address has been sent */
>> +    bool addrd;
>> +
>> +    int64_t time_offset;
>> +    int8_t wday_offset;
>> +
>> +    uint8_t regs[DSRTC_REGSIZE];
>> +} DSRTCState;
>> +
>> +typedef struct DSRTCClass {
>> +    I2CSlaveClass parent_class;
>> +
>> +    const DSRTCInfo *info;
>> +} DSRTCClass;
>> +
>> +#define TYPE_DSRTC "ds-rtc-i2c"
>> +#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
>> +#define DSRTC_GET_CLASS(obj) \
>> +    OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC)
>> +#define DSRTC_CLASS(klass) \
>> +    OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC)
>> +
>> +static const VMStateDescription vmstate_dsrtc = {
>> +    .name = TYPE_DSRTC,
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
>> +        VMSTATE_INT64(time_offset, DSRTCState),
>> +        VMSTATE_INT8_V(wday_offset, DSRTCState, 2),
>> +        VMSTATE_UINT8_ARRAY(regs, DSRTCState, DSRTC_REGSIZE),
>> +        VMSTATE_UINT8(addr, DSRTCState),
>> +        VMSTATE_BOOL(addrd, DSRTCState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static void dsrtc_reset(DeviceState *device);
>> +
>> +/* update current time registers */
>> +static
>> +void dsrtc_latch(DSRTCState *ds)
>> +{
>> +    struct tm now;
>> +    bool use12;
>> +
>> +    qemu_get_timedate(&now, ds->time_offset);
>> +
>> +    DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)",
>> +            now.tm_year, now.tm_mon, now.tm_mday,
>> +            now.tm_hour, now.tm_min, now.tm_sec,
>> +            now.tm_wday);
>> +
>> +    use12 = ARRAY_FIELD_EX32(ds->regs, HOUR, SET12);
>> +
>> +    /* 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 (!use12) {
>> +        /* 24 hour (0-23) */
>> +        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour));
>> +    } else {
>> +        /* 12 hour am/pm (1-12) */
>> +        ARRAY_FIELD_DP32(ds->regs, HOUR, SET12, 1);
>> +        ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12u);
>> +        ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12,
>> +                         to_bcd(1u + (now.tm_hour % 12u)));
>> +    }
>> +
>> +    ds->regs[R_WDAY] = (now.tm_wday + ds->wday_offset) % 7u + 1u;
>> +    ds->regs[R_DATE] = to_bcd(now.tm_mday);
>> +
>> +    ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1));
>> +    if (ds->info->has_century) {
>> +        ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year >= 100u);
>> +    }
>> +
>> +    ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u);
>> +
>> +    DPRINTK("Latched time");
>> +}
>> +
>> +/* call after guest writes to current time registers
>> + * to re-compute our offset from host time.
>> + */
>> +static
>> +void dsrtc_update(DSRTCState *ds)
>> +{
>> +    int user_wday;
>> +    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)) {
>> +        /* 12 hour (1-12) */
>> +        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR12)) - 1u;
>> +        if (ARRAY_FIELD_EX32(ds->regs, HOUR, AMPM)) {
>> +            now.tm_hour += 12;
>> +        }
>> +
>> +    } else {
>> +        /* 23 hour (0-23) */
>> +        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR24));
>> +    }
>> +
>> +    now.tm_wday = from_bcd(ds->regs[R_WDAY]) - 1u;
>> +    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]);
>> +    if (ARRAY_FIELD_EX32(ds->regs, MONTH, CENTURY) || !ds->info->has_century) {
>> +        now.tm_year += 100;
>> +    }
>> +
>> +    DPRINTK("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)",
>> +            now.tm_year, now.tm_mon, now.tm_mday,
>> +            now.tm_hour, now.tm_min, now.tm_sec,
>> +            now.tm_wday);
>> +
>> +    /* round trip to get real wday_offset based on time delta */
>> +    user_wday = now.tm_wday;
>> +    ds->time_offset = qemu_timedate_diff(&now);
>> +    /* race possible if we run at midnight
>> +     * TODO: make qemu_timedate_diff() calculate wday offset as well?
>> +     */
>> +    qemu_get_timedate(&now, ds->time_offset);
>> +    /* calculate wday_offset to achieve guest requested wday */
>> +    ds->wday_offset = user_wday - now.tm_wday;
>> +
>> +    DPRINTK("Update offset = %" PRId64 ", wday_offset = %d",
>> +            ds->time_offset, ds->wday_offset);
>> +}
>> +
>> +static
>> +void dsrtc_advance(DSRTCState *ds)
>> +{
>> +    ds->addr = (ds->addr + 1) % ds->info->reg_size;
>> +    if (ds->addr == 0) {
>> +        /* latch time on roll over */
>> +        dsrtc_latch(ds);
>> +    }
>> +}
>> +
>> +static
>> +int dsrtc_event(I2CSlave *s, enum i2c_event event)
>> +{
>> +    DSRTCState *ds = DSRTC(s);
>> +
>> +    switch (event) {
>> +    case I2C_START_SEND:
>> +        ds->addrd = false;
>> +        /* fall through */
>> +    case I2C_START_RECV:
>> +        dsrtc_latch(ds);
>> +        /* fall through */
>> +    case I2C_FINISH:
>> +        DPRINTK("Event %d", (int)event);
>> +        /* fall through */
>> +    case I2C_NACK:
>> +        break;
>> +    }
>> +    return 0;
>> +}
>> +
>> +static
>> +int dsrtc_recv(I2CSlave *s)
>> +{
>> +    DSRTCState *ds = DSRTC(s);
>> +    int ret = 0;
>> +
>> +    ret = ds->regs[ds->addr];
>> +
>> +    if (ds->addr > R_YEAR && ds->addr < ds->info->nv_start) {
>> +        LOG(LOG_UNIMP, "Read from unimplemented (%02x) %02x", ds->addr, ret);
>> +    }
>> +
>> +    DPRINTK("Recv (%02x) %02x", ds->addr, ret);
>> +
>> +    dsrtc_advance(ds);
>> +
>> +    return ret;
>> +}
>> +
>> +static
>> +int dsrtc_send(I2CSlave *s, uint8_t data)
>> +{
>> +    DSRTCState *ds = DSRTC(s);
>> +
>> +    if (!ds->addrd) {
>> +        if (data == 0xff && qtest_enabled()) {
>> +            /* allow test runner to zero offsets */
>> +            DPRINTK("Testing reset");
>> +            dsrtc_reset(DEVICE(s));
>> +            return 0;
>> +        }
>> +        ds->addr = data % DSRTC_REGSIZE;
>> +        ds->addrd = true;
>> +        DPRINTK("Set address pointer %02x", data);
>> +        return 0;
>> +    }
>> +
>> +    DPRINTK("Send (%02x) %02x", ds->addr, data);
>> +
>> +    if (ds->addr <= R_YEAR) {
>> +        ds->regs[ds->addr] = data;
>> +        dsrtc_update(ds);
>> +
>> +    } else if (ds->addr >= ds->info->nv_start) {
>> +        ds->regs[ds->addr] = data;
>> +
>> +    } else {
>> +        LOG(LOG_UNIMP, "Register not modeled");
>> +    }
>> +
>> +    dsrtc_advance(ds);
>> +
>> +    return 0;
>> +}
>> +
>> +static
>> +void dsrtc_reset(DeviceState *device)
>> +{
>> +    DSRTCState *ds = DSRTC(device);
>> +
>> +    memset(ds->regs, 0, sizeof(ds->regs));
>> +
>> +    ds->addr = 0;
>> +    ds->addrd = false;
>> +    ds->time_offset = 0;
>> +    ds->wday_offset = 0;
>> +
>> +    DPRINTK("Reset");
>> +}
>> +
>> +static
>> +void dsrtc_realize(DeviceState *device, Error **errp)
>> +{
>> +    DSRTCState *ds = DSRTC(device);
>> +    DSRTCClass *r = DSRTC_GET_CLASS(device);
>> +
>> +    ds->info = r->info;
>> +
>> +    /* Alarms not yet implemented, but allow
>> +     * board code to wire up the alarm interrupt
>> +     * output anyway.
>> +     */
>> +    qdev_init_gpio_out(device, &ds->alarm_irq, 1);
>> +}
>> +
>> +static
>> +void dsrtc_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
>> +    DSRTCClass *r = DSRTC_CLASS(klass);
>> +
>> +    r->info = data;
>> +
>> +    k->event = &dsrtc_event;
>> +    k->recv = &dsrtc_recv;
>> +    k->send = &dsrtc_send;
>> +
>> +    dc->vmsd = &vmstate_dsrtc;
>> +    dc->realize = dsrtc_realize;
>> +    dc->reset = dsrtc_reset;
>> +    dc->user_creatable = true;
>> +}
>> +
>> +static
>> +const TypeInfo ds_rtc_base_type = {
>> +    .abstract = true,
>> +    .name = TYPE_DSRTC,
>> +    .parent = TYPE_I2C_SLAVE,
>> +    .instance_size = sizeof(DSRTCState),
>> +};
>> +
>> +#define DSRTC_CONFIG(NAME) \
>> +static const TypeInfo NAME##_type = { \
>> +    .name = #NAME, \
>> +    .parent = TYPE_DSRTC, \
>> +    .class_size = sizeof(I2CSlaveClass), \
>> +    .class_init = dsrtc_class_init, \
>> +    .class_data = (void *)&NAME##_info, \
>> +};
>> +
>> +/* ds3231 - alarms, no eeprom */
>> +static const DSRTCInfo ds3231_info = {
>> +    .has_century = true,
>> +    .nv_start    = 0x13, /* no nv memory */
>> +    .reg_size    = 0x13,
>> +};
>> +DSRTC_CONFIG(ds3231)
>> +
>> +/* only model block 0 (RTC), blocks 1,2 (eeprom) not modeled.
>> + * blocks have different i2c addresses
>> + */
>> +static const DSRTCInfo ds1388_info = {
>> +    .has_century = false,
>> +    .nv_start    = 0x0d,
>> +    .reg_size    = 0x0d,
>> +};
>> +DSRTC_CONFIG(ds1388)
>> +
>> +/* alarms, eeprom */
>> +static const DSRTCInfo ds1375_info = {
>> +    .has_century = true,
>> +    .nv_start    = 0x10,
>> +    .reg_size    = 0x20,
>> +};
>> +DSRTC_CONFIG(ds1375)
>> +
>> +/* no alarms, no eeprom */
>> +static const DSRTCInfo ds1340_info = {
>> +    .has_century = false,
>> +    .nv_start    = 0x10,
>> +    .reg_size    = 0x10,
>> +};
>> +DSRTC_CONFIG(ds1340)
>> +
>> +/* alarms, no eeprom */
>> +static const DSRTCInfo ds1339_info = {
>> +    .has_century = false,
>> +    .nv_start    = 0x11,
>> +    .reg_size    = 0x11,
>> +};
>> +DSRTC_CONFIG(ds1339)
>> +
>> +/* no alarms, eeprom */
>> +static const DSRTCInfo ds1338_info = {
>> +    .has_century = false,
>> +    .nv_start    = 0x08,
>> +    .reg_size    = 0x40,
>> +};
>> +DSRTC_CONFIG(ds1338)
>> +
>> +/* alarms, no eeprom */
>> +static const DSRTCInfo ds1337_info = {
>> +    .has_century = true,
>> +    .nv_start    = 0x10,
>> +    .reg_size    = 0x10,
>> +};
>> +DSRTC_CONFIG(ds1337)
>> +
>> +/* ds1307 registers are identical to ds1338 */
>> +static
>> +const TypeInfo ds1307_type = {
>> +    .name = "ds1307",
>> +    .parent = "ds1338",
>> +};
>> +
>> +static void ds_rtc_i2c_register(void)
>> +{
>> +    type_register_static(&ds_rtc_base_type);
>> +    type_register_static(&ds3231_type);
>> +    type_register_static(&ds1388_type);
>> +    type_register_static(&ds1375_type);
>> +    type_register_static(&ds1340_type);
>> +    type_register_static(&ds1339_type);
>> +    type_register_static(&ds1338_type);
>> +    type_register_static(&ds1337_type);
>> +    type_register_static(&ds1307_type);
>> +}
>> +
>> +type_init(ds_rtc_i2c_register)
>> diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
>> deleted file mode 100644
>> index 3849b74a68..0000000000
>> --- a/hw/timer/ds1338.c
>> +++ /dev/null
>> @@ -1,239 +0,0 @@
>> -/*
>> - * MAXIM DS1338 I2C RTC+NVRAM
>> - *
>> - * Copyright (c) 2009 CodeSourcery.
>> - * Written by Paul Brook
>> - *
>> - * This code is licensed under the GNU GPL v2.
>> - *
>> - * Contributions after 2012-01-13 are licensed under the terms of the
>> - * GNU GPL, version 2 or (at your option) any later version.
>> - */
>> -
>> -#include "qemu/osdep.h"
>> -#include "qemu-common.h"
>> -#include "hw/i2c/i2c.h"
>> -#include "qemu/bcd.h"
>> -
>> -/* Size of NVRAM including both the user-accessible area and the
>> - * secondary register area.
>> - */
>> -#define NVRAM_SIZE 64
>> -
>> -/* Flags definitions */
>> -#define SECONDS_CH 0x80
>> -#define HOURS_12   0x40
>> -#define HOURS_PM   0x20
>> -#define CTRL_OSF   0x20
>> -
>> -#define TYPE_DS1338 "ds1338"
>> -#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
>> -
>> -typedef struct DS1338State {
>> -    I2CSlave parent_obj;
>> -
>> -    int64_t offset;
>> -    uint8_t wday_offset;
>> -    uint8_t nvram[NVRAM_SIZE];
>> -    int32_t ptr;
>> -    bool addr_byte;
>> -} DS1338State;
>> -
>> -static const VMStateDescription vmstate_ds1338 = {
>> -    .name = "ds1338",
>> -    .version_id = 2,
>> -    .minimum_version_id = 1,
>> -    .fields = (VMStateField[]) {
>> -        VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
>> -        VMSTATE_INT64(offset, DS1338State),
>> -        VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
>> -        VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
>> -        VMSTATE_INT32(ptr, DS1338State),
>> -        VMSTATE_BOOL(addr_byte, DS1338State),
>> -        VMSTATE_END_OF_LIST()
>> -    }
>> -};
>> -
>> -static void capture_current_time(DS1338State *s)
>> -{
>> -    /* Capture the current time into the secondary registers
>> -     * which will be actually read by the data transfer operation.
>> -     */
>> -    struct tm now;
>> -    qemu_get_timedate(&now, s->offset);
>> -    s->nvram[0] = to_bcd(now.tm_sec);
>> -    s->nvram[1] = to_bcd(now.tm_min);
>> -    if (s->nvram[2] & HOURS_12) {
>> -        int tmp = now.tm_hour;
>> -        if (tmp % 12 == 0) {
>> -            tmp += 12;
>> -        }
>> -        if (tmp <= 12) {
>> -            s->nvram[2] = HOURS_12 | to_bcd(tmp);
>> -        } else {
>> -            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
>> -        }
>> -    } else {
>> -        s->nvram[2] = to_bcd(now.tm_hour);
>> -    }
>> -    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
>> -    s->nvram[4] = to_bcd(now.tm_mday);
>> -    s->nvram[5] = to_bcd(now.tm_mon + 1);
>> -    s->nvram[6] = to_bcd(now.tm_year - 100);
>> -}
>> -
>> -static void inc_regptr(DS1338State *s)
>> -{
>> -    /* The register pointer wraps around after 0x3F; wraparound
>> -     * causes the current time/date to be retransferred into
>> -     * the secondary registers.
>> -     */
>> -    s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
>> -    if (!s->ptr) {
>> -        capture_current_time(s);
>> -    }
>> -}
>> -
>> -static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
>> -{
>> -    DS1338State *s = DS1338(i2c);
>> -
>> -    switch (event) {
>> -    case I2C_START_RECV:
>> -        /* In h/w, capture happens on any START condition, not just a
>> -         * START_RECV, but there is no need to actually capture on
>> -         * START_SEND, because the guest can't get at that data
>> -         * without going through a START_RECV which would overwrite it.
>> -         */
>> -        capture_current_time(s);
>> -        break;
>> -    case I2C_START_SEND:
>> -        s->addr_byte = true;
>> -        break;
>> -    default:
>> -        break;
>> -    }
>> -
>> -    return 0;
>> -}
>> -
>> -static int ds1338_recv(I2CSlave *i2c)
>> -{
>> -    DS1338State *s = DS1338(i2c);
>> -    uint8_t res;
>> -
>> -    res  = s->nvram[s->ptr];
>> -    inc_regptr(s);
>> -    return res;
>> -}
>> -
>> -static int ds1338_send(I2CSlave *i2c, uint8_t data)
>> -{
>> -    DS1338State *s = DS1338(i2c);
>> -
>> -    if (s->addr_byte) {
>> -        s->ptr = data & (NVRAM_SIZE - 1);
>> -        s->addr_byte = false;
>> -        return 0;
>> -    }
>> -    if (s->ptr < 7) {
>> -        /* Time register. */
>> -        struct tm now;
>> -        qemu_get_timedate(&now, s->offset);
>> -        switch(s->ptr) {
>> -        case 0:
>> -            /* TODO: Implement CH (stop) bit.  */
>> -            now.tm_sec = from_bcd(data & 0x7f);
>> -            break;
>> -        case 1:
>> -            now.tm_min = from_bcd(data & 0x7f);
>> -            break;
>> -        case 2:
>> -            if (data & HOURS_12) {
>> -                int tmp = from_bcd(data & (HOURS_PM - 1));
>> -                if (data & HOURS_PM) {
>> -                    tmp += 12;
>> -                }
>> -                if (tmp % 12 == 0) {
>> -                    tmp -= 12;
>> -                }
>> -                now.tm_hour = tmp;
>> -            } else {
>> -                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
>> -            }
>> -            break;
>> -        case 3:
>> -            {
>> -                /* The day field is supposed to contain a value in
>> -                   the range 1-7. Otherwise behavior is undefined.
>> -                 */
>> -                int user_wday = (data & 7) - 1;
>> -                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
>> -            }
>> -            break;
>> -        case 4:
>> -            now.tm_mday = from_bcd(data & 0x3f);
>> -            break;
>> -        case 5:
>> -            now.tm_mon = from_bcd(data & 0x1f) - 1;
>> -            break;
>> -        case 6:
>> -            now.tm_year = from_bcd(data) + 100;
>> -            break;
>> -        }
>> -        s->offset = qemu_timedate_diff(&now);
>> -    } else if (s->ptr == 7) {
>> -        /* Control register. */
>> -
>> -        /* Ensure bits 2, 3 and 6 will read back as zero. */
>> -        data &= 0xB3;
>> -
>> -        /* Attempting to write the OSF flag to logic 1 leaves the
>> -           value unchanged. */
>> -        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
>> -
>> -        s->nvram[s->ptr] = data;
>> -    } else {
>> -        s->nvram[s->ptr] = data;
>> -    }
>> -    inc_regptr(s);
>> -    return 0;
>> -}
>> -
>> -static void ds1338_reset(DeviceState *dev)
>> -{
>> -    DS1338State *s = DS1338(dev);
>> -
>> -    /* The clock is running and synchronized with the host */
>> -    s->offset = 0;
>> -    s->wday_offset = 0;
>> -    memset(s->nvram, 0, NVRAM_SIZE);
>> -    s->ptr = 0;
>> -    s->addr_byte = false;
>> -}
>> -
>> -static void ds1338_class_init(ObjectClass *klass, void *data)
>> -{
>> -    DeviceClass *dc = DEVICE_CLASS(klass);
>> -    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
>> -
>> -    k->event = ds1338_event;
>> -    k->recv = ds1338_recv;
>> -    k->send = ds1338_send;
>> -    dc->reset = ds1338_reset;
>> -    dc->vmsd = &vmstate_ds1338;
>> -}
>> -
>> -static const TypeInfo ds1338_info = {
>> -    .name          = TYPE_DS1338,
>> -    .parent        = TYPE_I2C_SLAVE,
>> -    .instance_size = sizeof(DS1338State),
>> -    .class_init    = ds1338_class_init,
>> -};
>> -
>> -static void ds1338_register_types(void)
>> -{
>> -    type_register_static(&ds1338_info);
>> -}
>> -
>> -type_init(ds1338_register_types)
> 



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

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

* Re: [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers Michael Davidsaver
@ 2017-12-04  9:30   ` David Gibson
  2017-12-06  3:13     ` David Gibson
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-12-04  9:30 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:06PM -0600, Michael Davidsaver wrote:
> Add CCSRBAR to allow CCSR region to be relocated.
> 
> Guest memory size introspection via RAM config
> registers.
> 
> Dummy RAM error controls.
> 
> Clock introspection via Power on Reset PLL
> Status Register.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Applied to ppc-for-2.12.

> 
> ccsrbase also update iack
> ---
>  hw/ppc/e500.c      |  5 ++-
>  hw/ppc/e500_ccsr.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 95 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index b90f4231a6..e22919f4f1 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -51,7 +51,9 @@
>  
>  #define RAM_SIZES_ALIGN            (64UL << 20)
>  
> -/* TODO: parameterize */
> +/* TODO: parameterize
> + * Some CCSR offsets duplicated in e500_ccsr.c
> + */
>  #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
>  #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
>  #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
> @@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      object_property_add_child(qdev_get_machine(), "e500-ccsr",
>                                OBJECT(dev), NULL);
>      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_ccsr.c b/hw/ppc/e500_ccsr.c
> index 1b586c3f42..9400d7cf13 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -30,13 +30,26 @@
>  #include "hw/sysbus.h"
>  
>  /* E500_ denotes registers common to all */
> +/* Some CCSR offsets duplicated in e500.c */
>  
> +#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)
>  
>  #define MPC8544_RSTCR       (0xE00B0)
>  #define MPC8544_RSTCR_RESET      (0x02)
>  
> +#define E500_MPIC_OFFSET   (0x40000ULL)
> +
>  typedef struct {
>      /*< private >*/
>      SysBusDevice parent_obj;
> @@ -44,19 +57,59 @@ typedef struct {
>  
>      MemoryRegion iomem;
>  
> -    uint32_t defbase;
> +    uint32_t defbase, base;
> +    uint32_t ram_size;
> +    uint32_t merrd;
> +
> +    uint32_t porpllsr;
> +
> +    DeviceState *pic;
>  } CCSRState;
>  
>  #define TYPE_E500_CCSR "e500-ccsr"
>  #define E500_CCSR(obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR)
>  
> +/* call after changing CCSRState::base */
> +static void e500_ccsr_post_move(CCSRState *ccsr)
> +{
> +    CPUState *cs;
> +
> +    CPU_FOREACH(cs) {
> +        PowerPCCPU *cpu = POWERPC_CPU(cs);
> +        CPUPPCState *env = &cpu->env;
> +
> +        env->mpic_iack = ccsr->base +
> +                         E500_MPIC_OFFSET + 0xa0;
> +    }
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
> +}
> +
>  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 +125,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;
> +        e500_ccsr_post_move(ccsr);
> +        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 +169,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
>      }
>  };
>  
> +static int e500_ccsr_post_load(void *opaque, int version_id)
> +{
> +    CCSRState *ccsr = opaque;
> +
> +    e500_ccsr_post_move(ccsr);
> +    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_move(ccsr);
>  }
>  
>  static void e500_ccsr_initfn(Object *obj)
> @@ -123,15 +197,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;
>  }
>  

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR Michael Davidsaver
@ 2017-12-05  6:34   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-05  6:34 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:07PM -0600, Michael Davidsaver wrote:
> Start moving code out of ppce500_init()
> 
> Existing ppce500_init_mpic() suggests that MPIC may not be created w/ KVM.
> However, ppce500_init() used mpicdev unconditionally, and would
> fail if the MPIC isn't created.  So require creation.
> 
> Not tested with KVM for lack of hardware.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  hw/ppc/e500.c      | 102 +++--------------------------------------------------
>  hw/ppc/e500_ccsr.c |  85 +++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 84 insertions(+), 103 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index e22919f4f1..1872bb8eaa 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -29,7 +29,6 @@
>  #include "sysemu/kvm.h"
>  #include "kvm_ppc.h"
>  #include "sysemu/device_tree.h"
> -#include "hw/ppc/openpic.h"
>  #include "hw/ppc/ppc.h"
>  #include "hw/loader.h"
>  #include "elf.h"
> @@ -679,92 +678,6 @@ static void ppce500_cpu_reset(void *opaque)
>      mmubooke_create_initial_mapping(env);
>  }
>  
> -static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
> -                                           qemu_irq **irqs)
> -{
> -    DeviceState *dev;
> -    SysBusDevice *s;
> -    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);
> -
> -    qdev_init_nofail(dev);
> -    s = SYS_BUS_DEVICE(dev);
> -
> -    k = 0;
> -    for (i = 0; i < smp_cpus; i++) {
> -        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
> -            sysbus_connect_irq(s, k++, irqs[i][j]);
> -        }
> -    }
> -
> -    return dev;
> -}
> -
> -static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
> -                                          qemu_irq **irqs, Error **errp)
> -{
> -    Error *err = NULL;
> -    DeviceState *dev;
> -    CPUState *cs;
> -
> -    dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
> -    qdev_prop_set_uint32(dev, "model", params->mpic_version);
> -
> -    object_property_set_bool(OBJECT(dev), true, "realized", &err);
> -    if (err) {
> -        error_propagate(errp, err);
> -        object_unparent(OBJECT(dev));
> -        return NULL;
> -    }
> -
> -    CPU_FOREACH(cs) {
> -        if (kvm_openpic_connect_vcpu(dev, cs)) {
> -            fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
> -                    __func__);
> -            abort();
> -        }
> -    }
> -
> -    return dev;
> -}
> -
> -static DeviceState *ppce500_init_mpic(MachineState *machine,
> -                                      PPCE500Params *params,
> -                                      MemoryRegion *ccsr,
> -                                      qemu_irq **irqs)
> -{
> -    DeviceState *dev = NULL;
> -    SysBusDevice *s;
> -
> -    if (kvm_enabled()) {
> -        Error *err = NULL;
> -
> -        if (machine_kernel_irqchip_allowed(machine)) {
> -            dev = ppce500_init_mpic_kvm(params, irqs, &err);
> -        }
> -        if (machine_kernel_irqchip_required(machine) && !dev) {
> -            error_reportf_err(err,
> -                              "kernel_irqchip requested but unavailable: ");
> -            exit(1);
> -        }
> -    }
> -
> -    if (!dev) {
> -        dev = ppce500_init_mpic_qemu(params, irqs);
> -    }
> -
> -    s = SYS_BUS_DEVICE(dev);
> -    memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
> -                                s->mmio[0].memory);
> -
> -    return dev;
> -}
> -
>  static void ppce500_power_off(void *opaque, int line, int on)
>  {
>      if (on) {
> @@ -794,18 +707,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
>       * 4 respectively */
>      unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
> -    qemu_irq **irqs;
>      DeviceState *dev, *mpicdev;
>      CPUPPCState *firstenv = NULL;
>      MemoryRegion *ccsr_addr_space;
>      SysBusDevice *s;
>  
> -    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
> -    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
>      for (i = 0; i < smp_cpus; i++) {
>          PowerPCCPU *cpu;
>          CPUState *cs;
> -        qemu_irq *input;
>  
>          cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
>          env = &cpu->env;
> @@ -821,13 +730,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>              firstenv = env;
>          }
>  
> -        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
> -        input = (qemu_irq *)env->irq_inputs;
> -        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
> -        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
>          env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
> -        env->mpic_iack = params->ccsrbar_base +
> -                         MPC8544_MPIC_REGS_OFFSET + 0xa0;
>  
>          ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
>  
> @@ -857,12 +760,15 @@ 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, "mpic-model", params->mpic_version);
>      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);
>  
> -    mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
> +    /* created under "e500-ccsr" */
> +    mpicdev = DEVICE(object_resolve_path("/machine/pic", 0));
> +    assert(mpicdev);
>  
>      /* Serial */
>      if (serial_hds[0]) {
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> index 9400d7cf13..68d952794e 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -24,10 +24,14 @@
>  #include "qemu-common.h"
>  #include "qemu/log.h"
>  #include "qemu/error-report.h"
> +#include "qapi/error.h"
>  #include "cpu.h"
>  #include "hw/hw.h"
> +#include "hw/boards.h"
>  #include "sysemu/sysemu.h"
> +#include "sysemu/kvm.h"
>  #include "hw/sysbus.h"
> +#include "hw/ppc/openpic.h"
>  
>  /* E500_ denotes registers common to all */
>  /* Some CCSR offsets duplicated in e500.c */
> @@ -185,20 +189,90 @@ static void e500_ccsr_reset(DeviceState *dev)
>      e500_ccsr_post_move(ccsr);
>  }
>  
> -static void e500_ccsr_initfn(Object *obj)
> +static void e500_ccsr_init(Object *obj)
>  {
> -    CCSRState *ccsr = E500_CCSR(obj);
> +    DeviceState *dev = DEVICE(obj);
> +    CCSRState *ccsr = E500_CCSR(dev);
> +
> +    assert(current_machine);
> +    if (kvm_enabled()) {
> +
> +        if (!machine_kernel_irqchip_allowed(current_machine)) {
> +            error_report("Machine does not allow PIC,"
> +                         " but this is not supported");
> +            exit(1);

You've changed the logic here from the original; this now always
requires a kernel irqchip with kvm, whereas previously it would allow
fallback to the non kernel irqchip unless
machine_kernel_irqchip_required().

> +        }
>  
> -    memory_region_init_io(&ccsr->iomem, obj, &e500_ccsr_ops,
> +        ccsr->pic = qdev_create(NULL, TYPE_KVM_OPENPIC);
> +    } else {
> +        ccsr->pic = qdev_create(NULL, TYPE_OPENPIC);
> +    }
> +
> +    if (!ccsr->pic) {
> +        error_report("Failed to create PIC");
> +        exit(1);
> +    }
> +
> +    object_property_add_child(qdev_get_machine(), "pic", OBJECT(ccsr->pic),
> +                              &error_fatal);
> +
> +    qdev_prop_set_uint32(ccsr->pic, "nb_cpus", smp_cpus);
> +
> +    object_property_add_alias(obj, "mpic-model",
> +                              OBJECT(ccsr->pic), "model",
> +                              &error_fatal);
> +}
> +
> +static void e500_ccsr_realize(DeviceState *dev, Error **errp)
> +{
> +    CCSRState *ccsr = E500_CCSR(dev);
> +    SysBusDevice *pic;
> +
> +    /* Base 1MB CCSR Region */
> +    memory_region_init_io(&ccsr->iomem, OBJECT(dev), &e500_ccsr_ops,
>                            ccsr, "e500-ccsr", 1024 * 1024);
> -    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &ccsr->iomem);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &ccsr->iomem);
> +
> +    qdev_init_nofail(ccsr->pic);
> +    pic = SYS_BUS_DEVICE(ccsr->pic);
> +
> +    /* connect MPIC to CPU(s) */
> +    if (kvm_enabled()) {
> +        CPUState *cs;
> +
> +        CPU_FOREACH(cs) {
> +            if (kvm_openpic_connect_vcpu(ccsr->pic, cs)) {
> +                error_setg(errp, "%s: failed to connect vcpu to irqchip",
> +                           __func__);
> +                return;
> +            }
> +        }
> +
> +    } else {
> +        CPUState *cs;
> +
> +        CPU_FOREACH(cs) {
> +            PowerPCCPU *cpu = POWERPC_CPU(cs);
> +            CPUPPCState *env = &cpu->env;
> +            qemu_irq *inputs = (qemu_irq *)env->irq_inputs;
> +            int base = cs->cpu_index * PPCE500_INPUT_NB;
> +
> +            sysbus_connect_irq(pic, base + OPENPIC_OUTPUT_INT,
> +                               inputs[PPCE500_INPUT_INT]);
> +            sysbus_connect_irq(pic, base + OPENPIC_OUTPUT_CINT,
> +                               inputs[PPCE500_INPUT_CINT]);
> +        }
> +    }
>  
> +    memory_region_add_subregion(&ccsr->iomem, E500_MPIC_OFFSET,
> +                                sysbus_mmio_get_region(pic, 0));
>  }
>  
>  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),
> +    /* "mpic-model" aliased from MPIC */
>      DEFINE_PROP_END_OF_LIST()
>  };
>  
> @@ -221,6 +295,7 @@ void e500_ccsr_class_initfn(ObjectClass *klass, void *data)
>  
>      dc->props = e500_ccsr_props;
>      dc->vmsd = &vmstate_e500_ccsr;
> +    dc->realize = e500_ccsr_realize;
>      dc->reset = e500_ccsr_reset;
>  }
>  
> @@ -228,7 +303,7 @@ static const TypeInfo e500_ccsr_info = {
>      .name          = TYPE_E500_CCSR,
>      .parent        = TYPE_SYS_BUS_DEVICE,
>      .instance_size = sizeof(CCSRState),
> -    .instance_init = e500_ccsr_initfn,
> +    .instance_init = e500_ccsr_init,
>      .class_size    = sizeof(SysBusDeviceClass),
>      .class_init    = e500_ccsr_class_initfn
>  };

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR Michael Davidsaver
@ 2017-12-05  6:37   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-05  6:37 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:08PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  hw/ppc/e500.c      | 13 -------------
>  hw/ppc/e500_ccsr.c | 18 ++++++++++++++++++
>  2 files changed, 18 insertions(+), 13 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 1872bb8eaa..2d87d91582 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -22,7 +22,6 @@
>  #include "net/net.h"
>  #include "qemu/config-file.h"
>  #include "hw/hw.h"
> -#include "hw/char/serial.h"
>  #include "hw/pci/pci.h"
>  #include "hw/boards.h"
>  #include "sysemu/sysemu.h"
> @@ -770,18 +769,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      mpicdev = DEVICE(object_resolve_path("/machine/pic", 0));
>      assert(mpicdev);
>  
> -    /* Serial */
> -    if (serial_hds[0]) {
> -        serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
> -                       0, qdev_get_gpio_in(mpicdev, 42), 399193,
> -                       serial_hds[0], DEVICE_BIG_ENDIAN);
> -    }
> -
> -    if (serial_hds[1]) {
> -        serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
> -                       0, qdev_get_gpio_in(mpicdev, 42), 399193,
> -                       serial_hds[1], DEVICE_BIG_ENDIAN);
> -    }
>  
>      /* PCI */
>      dev = qdev_create(NULL, "e500-pcihost");
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> index 68d952794e..f1adba4e54 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -31,6 +31,7 @@
>  #include "sysemu/sysemu.h"
>  #include "sysemu/kvm.h"
>  #include "hw/sysbus.h"
> +#include "hw/char/serial.h"
>  #include "hw/ppc/openpic.h"
>  
>  /* E500_ denotes registers common to all */
> @@ -45,6 +46,8 @@
>  #define E500_ERR_DETECT  (0x2e40)
>  #define E500_ERR_DISABLE (0x2e44)
>  
> +#define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
> +
>  #define E500_PORPLLSR    (0xE0000)
>  #define E500_PVR         (0xE00A0)
>  #define E500_SVR         (0xE00A4)
> @@ -266,6 +269,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>  
>      memory_region_add_subregion(&ccsr->iomem, E500_MPIC_OFFSET,
>                                  sysbus_mmio_get_region(pic, 0));
> +    /* Note: MPIC internal interrupts are offset by 16 */
> +
> +    /* DUARTS */
> +    if (serial_hds[0]) {
> +        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0),

By changing the constants in use here for the base address you're now
creating the actual device and creating the device tree entry from
different (but same valued) constants.  That seems risky.

> +                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
> +                       serial_hds[0], DEVICE_BIG_ENDIAN);
> +    }
> +
> +    if (serial_hds[1]) {
> +        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(1),
> +                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
> +                       serial_hds[1], DEVICE_BIG_ENDIAN);
> +    }
> +
>  }
>  
>  static Property e500_ccsr_props[] = {

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock Michael Davidsaver
@ 2017-12-05  6:40   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-05  6:40 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:09PM -0600, Michael Davidsaver wrote:
> The CCB (Complex Core Bus) clock is the reference for the DUARTs
> with an extra divide by 16.
> 
> >From the mpc8540, mpc8544, and P2010 ref manuals.
> CCB=333MHz, with divider=0x87a gives ~9600 baud.
> 333e6 Hz/(16*0x87a) = 9591 Hz.
> This is verified with a real mpc8540.
> 
> The existing value for the mpc8544ds boards is replaced.
> Previously the uart "clock-frequency" device tree node
> was left as zero, and at some point either u-boot or Linux
> picks a value inconsistent with the frequency
> given to serial_mm_init().
> The FIFO timeout calculated from this was incorrect.
> 
> Now use an arbitrary (valid) CCB frequency of 333MHz
> in the device tree and for the UART.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  hw/ppc/e500.c      |  9 ++++++++-
>  hw/ppc/e500_ccsr.c | 16 ++++++++++++----
>  2 files changed, 20 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 2d87d91582..cfd5ed0152 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -49,6 +49,12 @@
>  
>  #define RAM_SIZES_ALIGN            (64UL << 20)
>  
> +/* Somewhat arbitrarily choosen Complex Core Bus frequency
> + * for our simulation (real freq of mpc8544ds board unknown)
> + * Used in baud rate calculations.
> + */
> +#define CCB_FREQ (333333333)
> +
>  /* TODO: parameterize
>   * Some CCSR offsets duplicated in e500_ccsr.c
>   */
> @@ -113,7 +119,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
>      qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
>      qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
>      qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
> -    qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
> +    qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", CCB_FREQ);

Shouldn't this come off the property value, not the constant?

>      qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
>      qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
>      qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
> @@ -759,6 +765,7 @@ 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, "ccb-freq", CCB_FREQ);
>      qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
>      qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
>      qdev_prop_set_uint32(dev, "ram-size", ram_size);
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> index f1adba4e54..c479ed91ee 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -69,6 +69,7 @@ typedef struct {
>      uint32_t merrd;
>  
>      uint32_t porpllsr;
> +    uint32_t ccb_freq;
>  
>      DeviceState *pic;
>  } CCSRState;
> @@ -272,15 +273,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>      /* Note: MPIC internal interrupts are offset by 16 */
>  
>      /* DUARTS */
> +    /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
> +     * is the CCB clock divided by 16.
> +     * So baud rate is CCB/(16*divider)
> +     */
>      if (serial_hds[0]) {
> -        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0),
> -                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
> +        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0), 0,
> +                       qdev_get_gpio_in(ccsr->pic, 16 + 26),
> +                       ccsr->ccb_freq / 16u,
>                         serial_hds[0], DEVICE_BIG_ENDIAN);
>      }
>  
>      if (serial_hds[1]) {
> -        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(1),
> -                       0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
> +        serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(1), 0,
> +                       qdev_get_gpio_in(ccsr->pic, 16 + 26),
> +                       ccsr->ccb_freq / 16u,
>                         serial_hds[1], DEVICE_BIG_ENDIAN);
>      }
>  
> @@ -290,6 +297,7 @@ 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_UINT32("ccb-freq", CCSRState, ccb_freq,
>      333333333u),

And shouldn't this use the #define as the default value?

>      /* "mpic-model" aliased from MPIC */
>      DEFINE_PROP_END_OF_LIST()
>  };

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR Michael Davidsaver
@ 2017-12-05  6:49   ` David Gibson
  2017-12-06  3:26     ` Michael Davidsaver
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-12-05  6:49 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:10PM -0600, Michael Davidsaver wrote:
> Add i2c controller found on mpc8540,
> mpc8544, and P2010 (newer ppc, unmodeled).

This adds it unconditionally.  Are there any E500 models where it
doesn't exist?

> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  hw/ppc/e500_ccsr.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> index c479ed91ee..cd8216daaf 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -46,6 +46,8 @@
>  #define E500_ERR_DETECT  (0x2e40)
>  #define E500_ERR_DISABLE (0x2e44)
>  
> +#define E500_I2C_OFFSET  (0x3000)
> +
>  #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
>  
>  #define E500_PORPLLSR    (0xE0000)
> @@ -72,6 +74,7 @@ typedef struct {
>      uint32_t ccb_freq;
>  
>      DeviceState *pic;
> +    DeviceState *i2c;
>  } CCSRState;
>  
>  #define TYPE_E500_CCSR "e500-ccsr"
> @@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>                                  sysbus_mmio_get_region(pic, 0));
>      /* Note: MPIC internal interrupts are offset by 16 */
>  
> +    /* attach I2C controller */
> +    ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");

Ah.. so I think I missed this on many earlier patches.  I believe
you're not generally supposed to create new subdevices at realize()
time.  Instead the device should be created at CCSR instance_init()
time (but the sub device's "realized" property will need to be set to
1 from CCSR realize()).

> +    object_property_add_child(qdev_get_machine(), "i2c[*]",
> +                              OBJECT(ccsr->i2c), NULL);
> +    qdev_init_nofail(ccsr->i2c);
> +    memory_region_add_subregion(&ccsr->iomem, E500_I2C_OFFSET,
> +                                sysbus_mmio_get_region(
> +                                    SYS_BUS_DEVICE(ccsr->i2c), 0));
> +    sysbus_connect_irq(SYS_BUS_DEVICE(ccsr->i2c), 0,
> +                          qdev_get_gpio_in(ccsr->pic, 16 + 27));
> +
> +
>      /* DUARTS */
>      /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
>       * is the CCB clock divided by 16.

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR Michael Davidsaver
@ 2017-12-05  6:53   ` David Gibson
  2017-12-06  3:42     ` Michael Davidsaver
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-12-05  6:53 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

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

Hmm.  Is there anything you're *not* planning to move under the CCSR.
If not, I'm really wondering if the CCSR ought to be a device in its
own right, rather than just a container memory region used within the
machine.

> ---
>  hw/ppc/e500.c      | 13 ++++---------
>  hw/ppc/e500_ccsr.c | 27 +++++++++++++++++++++++++++
>  2 files changed, 31 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index cfd5ed0152..b0c8495aef 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
>      qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
>      qdev_prop_set_uint32(dev, "ram-size", ram_size);
> +    qdev_prop_set_uint32(dev, "pci_first_slot", params->pci_first_slot);
> +    qdev_prop_set_uint32(dev, "pci_first_pin_irq", pci_irq_nrs[0]);
>      qdev_init_nofail(dev);
>      ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>  
> @@ -778,20 +780,13 @@ 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);
> +    dev = DEVICE(object_resolve_path("/machine/pci-host", 0));
> +    assert(dev);
>      s = SYS_BUS_DEVICE(dev);
>      for (i = 0; i < PCI_NUM_PINS; i++) {
>          sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
>      }
>  
> -    memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
> -                                sysbus_mmio_get_region(s, 0));
> -
>      pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>      if (!pci_bus)
>          printf("couldn't create PCI controller!\n");
> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
> index cd8216daaf..4ec8f7524d 100644
> --- a/hw/ppc/e500_ccsr.c
> +++ b/hw/ppc/e500_ccsr.c
> @@ -50,6 +50,8 @@
>  
>  #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
>  
> +#define E500_PCI_OFFSET  (0x8000ULL)
> +
>  #define E500_PORPLLSR    (0xE0000)
>  #define E500_PVR         (0xE00A0)
>  #define E500_SVR         (0xE00A4)
> @@ -75,6 +77,7 @@ typedef struct {
>  
>      DeviceState *pic;
>      DeviceState *i2c;
> +    DeviceState *pcihost;
>  } CCSRState;
>  
>  #define TYPE_E500_CCSR "e500-ccsr"
> @@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)
>      DeviceState *dev = DEVICE(obj);
>      CCSRState *ccsr = E500_CCSR(dev);
>  
> +    /* prepare MPIC */
>      assert(current_machine);
>      if (kvm_enabled()) {
>  
> @@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)
>      object_property_add_alias(obj, "mpic-model",
>                                OBJECT(ccsr->pic), "model",
>                                &error_fatal);
> +
> +    /* prepare PCI host bridge */
> +    ccsr->pcihost = qdev_create(NULL, "e500-pcihost");
> +    object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(ccsr->pcihost),
> +                              &error_abort);
> +
> +    object_property_add_alias(obj, "pci_first_slot",
> +                              OBJECT(ccsr->pcihost), "first_slot",
> +                              &error_fatal);
> +    object_property_add_alias(obj, "pci_first_pin_irq",
> +                              OBJECT(ccsr->pcihost), "first_pin_irq",
> +                              &error_fatal);
>  }
>  
>  static void e500_ccsr_realize(DeviceState *dev, Error **errp)
> @@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>                            ccsr, "e500-ccsr", 1024 * 1024);
>      sysbus_init_mmio(SYS_BUS_DEVICE(dev), &ccsr->iomem);
>  
> +    /* realize MPIC */
>      qdev_init_nofail(ccsr->pic);
>      pic = SYS_BUS_DEVICE(ccsr->pic);
>  
> @@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>                                  sysbus_mmio_get_region(pic, 0));
>      /* Note: MPIC internal interrupts are offset by 16 */
>  
> +    /* realize PCI host bridge*/
> +    qdev_init_nofail(ccsr->pcihost);
> +
> +    memory_region_add_subregion(&ccsr->iomem, E500_PCI_OFFSET,
> +                                sysbus_mmio_get_region(
> +                                    SYS_BUS_DEVICE(ccsr->pcihost), 0));
> +
>      /* attach I2C controller */
>      ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
>      object_property_add_child(qdev_get_machine(), "i2c[*]",
> @@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {
>      DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
>      DEFINE_PROP_UINT32("ccb-freq", CCSRState, ccb_freq, 333333333u),
>      /* "mpic-model" aliased from MPIC */
> +    /* "pci_first_slot"
> +     * "pci_first_pin_irq" aliased from PCI host bridge
> +     */
>      DEFINE_PROP_END_OF_LIST()
>  };
>  

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers
  2017-12-04  9:30   ` David Gibson
@ 2017-12-06  3:13     ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-06  3:13 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Mon, Dec 04, 2017 at 08:30:13PM +1100, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:06PM -0600, Michael Davidsaver wrote:
> > Add CCSRBAR to allow CCSR region to be relocated.
> > 
> > Guest memory size introspection via RAM config
> > registers.
> > 
> > Dummy RAM error controls.
> > 
> > Clock introspection via Power on Reset PLL
> > Status Register.
> > 
> > Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> Applied to ppc-for-2.12.

Sorry, I've pulled this from ppc-for-2.12 because it depended on the
guts patch which brokem make check.

> 
> > 
> > ccsrbase also update iack
> > ---
> >  hw/ppc/e500.c      |  5 ++-
> >  hw/ppc/e500_ccsr.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
> >  2 files changed, 95 insertions(+), 3 deletions(-)
> > 
> > diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> > index b90f4231a6..e22919f4f1 100644
> > --- a/hw/ppc/e500.c
> > +++ b/hw/ppc/e500.c
> > @@ -51,7 +51,9 @@
> >  
> >  #define RAM_SIZES_ALIGN            (64UL << 20)
> >  
> > -/* TODO: parameterize */
> > +/* TODO: parameterize
> > + * Some CCSR offsets duplicated in e500_ccsr.c
> > + */
> >  #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
> >  #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
> >  #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
> > @@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
> >      object_property_add_child(qdev_get_machine(), "e500-ccsr",
> >                                OBJECT(dev), NULL);
> >      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_ccsr.c b/hw/ppc/e500_ccsr.c
> > index 1b586c3f42..9400d7cf13 100644
> > --- a/hw/ppc/e500_ccsr.c
> > +++ b/hw/ppc/e500_ccsr.c
> > @@ -30,13 +30,26 @@
> >  #include "hw/sysbus.h"
> >  
> >  /* E500_ denotes registers common to all */
> > +/* Some CCSR offsets duplicated in e500.c */
> >  
> > +#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)
> >  
> >  #define MPC8544_RSTCR       (0xE00B0)
> >  #define MPC8544_RSTCR_RESET      (0x02)
> >  
> > +#define E500_MPIC_OFFSET   (0x40000ULL)
> > +
> >  typedef struct {
> >      /*< private >*/
> >      SysBusDevice parent_obj;
> > @@ -44,19 +57,59 @@ typedef struct {
> >  
> >      MemoryRegion iomem;
> >  
> > -    uint32_t defbase;
> > +    uint32_t defbase, base;
> > +    uint32_t ram_size;
> > +    uint32_t merrd;
> > +
> > +    uint32_t porpllsr;
> > +
> > +    DeviceState *pic;
> >  } CCSRState;
> >  
> >  #define TYPE_E500_CCSR "e500-ccsr"
> >  #define E500_CCSR(obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR)
> >  
> > +/* call after changing CCSRState::base */
> > +static void e500_ccsr_post_move(CCSRState *ccsr)
> > +{
> > +    CPUState *cs;
> > +
> > +    CPU_FOREACH(cs) {
> > +        PowerPCCPU *cpu = POWERPC_CPU(cs);
> > +        CPUPPCState *env = &cpu->env;
> > +
> > +        env->mpic_iack = ccsr->base +
> > +                         E500_MPIC_OFFSET + 0xa0;
> > +    }
> > +
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
> > +}
> > +
> >  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 +125,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;
> > +        e500_ccsr_post_move(ccsr);
> > +        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 +169,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
> >      }
> >  };
> >  
> > +static int e500_ccsr_post_load(void *opaque, int version_id)
> > +{
> > +    CCSRState *ccsr = opaque;
> > +
> > +    e500_ccsr_post_move(ccsr);
> > +    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_move(ccsr);
> >  }
> >  
> >  static void e500_ccsr_initfn(Object *obj)
> > @@ -123,15 +197,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;
> >  }
> >  
> 



-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR
  2017-12-05  6:49   ` David Gibson
@ 2017-12-06  3:26     ` Michael Davidsaver
  0 siblings, 0 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-12-06  3:26 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On 12/05/2017 01:49 AM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:10PM -0600, Michael Davidsaver wrote:
>> Add i2c controller found on mpc8540,
>> mpc8544, and P2010 (newer ppc, unmodeled).
> 
> This adds it unconditionally.  Are there any E500 models where it
> doesn't exist?

Not in the devices I've looked at, though I certainly haven't looked
at them all.  In fact the mpc8544 has two i2c controllers.

I keep mentioning the P2010 as it is about a decade
newer than the mpc85xx chips.  My _assumption_ is that the commonalities
between these are a reasonable least common denominator.


>>
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
>> ---
>>  hw/ppc/e500_ccsr.c | 15 +++++++++++++++
>>  1 file changed, 15 insertions(+)
>>
>> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
>> index c479ed91ee..cd8216daaf 100644
>> --- a/hw/ppc/e500_ccsr.c
>> +++ b/hw/ppc/e500_ccsr.c
>> @@ -46,6 +46,8 @@
>>  #define E500_ERR_DETECT  (0x2e40)
>>  #define E500_ERR_DISABLE (0x2e44)
>>  
>> +#define E500_I2C_OFFSET  (0x3000)
>> +
>>  #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
>>  
>>  #define E500_PORPLLSR    (0xE0000)
>> @@ -72,6 +74,7 @@ typedef struct {
>>      uint32_t ccb_freq;
>>  
>>      DeviceState *pic;
>> +    DeviceState *i2c;
>>  } CCSRState;
>>  
>>  #define TYPE_E500_CCSR "e500-ccsr"
>> @@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>>                                  sysbus_mmio_get_region(pic, 0));
>>      /* Note: MPIC internal interrupts are offset by 16 */
>>  
>> +    /* attach I2C controller */
>> +    ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
> 
> Ah.. so I think I missed this on many earlier patches.  I believe
> you're not generally supposed to create new subdevices at realize()
> time.  Instead the device should be created at CCSR instance_init()
> time (but the sub device's "realized" property will need to be set to
> 1 from CCSR realize()).
> 
>> +    object_property_add_child(qdev_get_machine(), "i2c[*]",
>> +                              OBJECT(ccsr->i2c), NULL);
>> +    qdev_init_nofail(ccsr->i2c);
>> +    memory_region_add_subregion(&ccsr->iomem, E500_I2C_OFFSET,
>> +                                sysbus_mmio_get_region(
>> +                                    SYS_BUS_DEVICE(ccsr->i2c), 0));
>> +    sysbus_connect_irq(SYS_BUS_DEVICE(ccsr->i2c), 0,
>> +                          qdev_get_gpio_in(ccsr->pic, 16 + 27));
>> +
>> +
>>      /* DUARTS */
>>      /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
>>       * is the CCB clock divided by 16.
> 



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

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

* Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
  2017-12-05  6:53   ` David Gibson
@ 2017-12-06  3:42     ` Michael Davidsaver
  2017-12-06 11:11       ` David Gibson
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Davidsaver @ 2017-12-06  3:42 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On 12/05/2017 01:53 AM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:11PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> 
> Hmm.  Is there anything you're *not* planning to move under the CCSR.

Well, the decrementer/timebase initialization for one as this has
nothing to do with the CCSR registers.

I haven't added the TSEC/eTSEC instances either.
Partly this is because the existing boards, for reasons I don't understand,
use virtio NICs.

Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544
has instances 1 and 3.  So I decided to leave NIC setup to the Machine
rather then add the extra code to parameterize this under the CCSR device.

> If not, I'm really wondering if the CCSR ought to be a device in its
> own right, rather than just a container memory region used within the
> machine.

I don't think I follow what you mean by "device" in this context?
The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr").
What device-like characteristics could it have?


>> ---
>>  hw/ppc/e500.c      | 13 ++++---------
>>  hw/ppc/e500_ccsr.c | 27 +++++++++++++++++++++++++++
>>  2 files changed, 31 insertions(+), 9 deletions(-)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index cfd5ed0152..b0c8495aef 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>      qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
>>      qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
>>      qdev_prop_set_uint32(dev, "ram-size", ram_size);
>> +    qdev_prop_set_uint32(dev, "pci_first_slot", params->pci_first_slot);
>> +    qdev_prop_set_uint32(dev, "pci_first_pin_irq", pci_irq_nrs[0]);
>>      qdev_init_nofail(dev);
>>      ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>>  
>> @@ -778,20 +780,13 @@ 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);
>> +    dev = DEVICE(object_resolve_path("/machine/pci-host", 0));
>> +    assert(dev);
>>      s = SYS_BUS_DEVICE(dev);
>>      for (i = 0; i < PCI_NUM_PINS; i++) {
>>          sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
>>      }
>>  
>> -    memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
>> -                                sysbus_mmio_get_region(s, 0));
>> -
>>      pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>>      if (!pci_bus)
>>          printf("couldn't create PCI controller!\n");
>> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
>> index cd8216daaf..4ec8f7524d 100644
>> --- a/hw/ppc/e500_ccsr.c
>> +++ b/hw/ppc/e500_ccsr.c
>> @@ -50,6 +50,8 @@
>>  
>>  #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
>>  
>> +#define E500_PCI_OFFSET  (0x8000ULL)
>> +
>>  #define E500_PORPLLSR    (0xE0000)
>>  #define E500_PVR         (0xE00A0)
>>  #define E500_SVR         (0xE00A4)
>> @@ -75,6 +77,7 @@ typedef struct {
>>  
>>      DeviceState *pic;
>>      DeviceState *i2c;
>> +    DeviceState *pcihost;
>>  } CCSRState;
>>  
>>  #define TYPE_E500_CCSR "e500-ccsr"
>> @@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)
>>      DeviceState *dev = DEVICE(obj);
>>      CCSRState *ccsr = E500_CCSR(dev);
>>  
>> +    /* prepare MPIC */
>>      assert(current_machine);
>>      if (kvm_enabled()) {
>>  
>> @@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)
>>      object_property_add_alias(obj, "mpic-model",
>>                                OBJECT(ccsr->pic), "model",
>>                                &error_fatal);
>> +
>> +    /* prepare PCI host bridge */
>> +    ccsr->pcihost = qdev_create(NULL, "e500-pcihost");
>> +    object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(ccsr->pcihost),
>> +                              &error_abort);
>> +
>> +    object_property_add_alias(obj, "pci_first_slot",
>> +                              OBJECT(ccsr->pcihost), "first_slot",
>> +                              &error_fatal);
>> +    object_property_add_alias(obj, "pci_first_pin_irq",
>> +                              OBJECT(ccsr->pcihost), "first_pin_irq",
>> +                              &error_fatal);
>>  }
>>  
>>  static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>> @@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>>                            ccsr, "e500-ccsr", 1024 * 1024);
>>      sysbus_init_mmio(SYS_BUS_DEVICE(dev), &ccsr->iomem);
>>  
>> +    /* realize MPIC */
>>      qdev_init_nofail(ccsr->pic);
>>      pic = SYS_BUS_DEVICE(ccsr->pic);
>>  
>> @@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)
>>                                  sysbus_mmio_get_region(pic, 0));
>>      /* Note: MPIC internal interrupts are offset by 16 */
>>  
>> +    /* realize PCI host bridge*/
>> +    qdev_init_nofail(ccsr->pcihost);
>> +
>> +    memory_region_add_subregion(&ccsr->iomem, E500_PCI_OFFSET,
>> +                                sysbus_mmio_get_region(
>> +                                    SYS_BUS_DEVICE(ccsr->pcihost), 0));
>> +
>>      /* attach I2C controller */
>>      ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
>>      object_property_add_child(qdev_get_machine(), "i2c[*]",
>> @@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {
>>      DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
>>      DEFINE_PROP_UINT32("ccb-freq", CCSRState, ccb_freq, 333333333u),
>>      /* "mpic-model" aliased from MPIC */
>> +    /* "pci_first_slot"
>> +     * "pci_first_pin_irq" aliased from PCI host bridge
>> +     */
>>      DEFINE_PROP_END_OF_LIST()
>>  };
>>  
> 



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

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

* Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
  2017-12-06  3:42     ` Michael Davidsaver
@ 2017-12-06 11:11       ` David Gibson
  2017-12-27  3:53         ` Michael Davidsaver
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-12-06 11:11 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Tue, Dec 05, 2017 at 10:42:25PM -0500, Michael Davidsaver wrote:
> On 12/05/2017 01:53 AM, David Gibson wrote:
> > On Sun, Nov 26, 2017 at 03:59:11PM -0600, Michael Davidsaver wrote:
> >> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> > 
> > Hmm.  Is there anything you're *not* planning to move under the CCSR.
> 
> Well, the decrementer/timebase initialization for one as this has
> nothing to do with the CCSR registers.

Right, but no actual devices, even small ones?

> I haven't added the TSEC/eTSEC instances either.
> Partly this is because the existing boards, for reasons I don't understand,
> use virtio NICs.
> 
> Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544
> has instances 1 and 3.  So I decided to leave NIC setup to the Machine
> rather then add the extra code to parameterize this under the CCSR device.
> 
> > If not, I'm really wondering if the CCSR ought to be a device in its
> > own right, rather than just a container memory region used within the
> > machine.
> 
> I don't think I follow what you mean by "device" in this context?
> The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr").
> What device-like characteristics could it have?

Sorry, I wasn't clear.  the CCSR definitely *is* a device in the
current scheme, but I'm wondering if that was a good idea.


-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
  2017-12-03 21:15     ` Michael Davidsaver
@ 2017-12-06 11:14       ` David Gibson
  2017-12-28  4:11         ` Michael Davidsaver
  0 siblings, 1 reply; 42+ messages in thread
From: David Gibson @ 2017-12-06 11:14 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Dec 03, 2017 at 03:15:10PM -0600, Michael Davidsaver wrote:
> On 11/29/2017 11:13 PM, David Gibson wrote:
> > On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote:
> >> Support for: ds1307, ds1337, ds1338, ds1339,
> >> ds1340, ds1375, ds1388, and ds3231.
> >>
> >> Tested with ds1338 and ds1375.
> >>
> >> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> > 
> > I certainly like the idea of consolidating this code, but reviewing to
> > see that the new code really is a generalization of the old is
> > something I won't have time for for a while.
> > 
> > Also, hw/timer is not within my purview so it'll probably need to go
> > another path to merge.
> 
> Could you be a bit more explicit about what, if anything, I need to do
> to move this forward?

Ugh.. that's pretty tough, since ds1338 doesn't have an activate
maintainer.  You can look at the git history for some possible
candidates of people to ask about it, but it hasn't been touched much
in quite a while.

One approach that could help is to re-order so that your testing
rework goes before the change to ds1338.  If your new generalization
can pass the same set of tests as the original ds1338 code, that's at
least a good start on being convincing that it's a true superset of
the previous functionality.

The other approach is to do the rework in a rather longer series of
patches.  Start by simply moving ds1338.c, then do a mechanical
replacement of the names within it, then start generalizing and
altering.  That's a lot of work for you, but it makes it much easier
to review each step

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization Michael Davidsaver
@ 2017-12-19  5:05   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-19  5:05 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:12PM -0600, Michael Davidsaver wrote:
> split off the remaining board specific parts
> of e500_init() as mpc85xx_init() which
> will be used by the existing
> mpc8544ds and generic e500 boards.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Looks good, but will need a rebase.

> ---
>  hw/ppc/e500.c      | 49 ++++++++++++++++++++++++++++++++-----------------
>  hw/ppc/e500.h      |  3 ++-
>  hw/ppc/e500plat.c  |  2 +-
>  hw/ppc/mpc8544ds.c |  2 +-
>  4 files changed, 36 insertions(+), 20 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index b0c8495aef..0ac7cdf6a1 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -690,7 +690,32 @@ static void ppce500_power_off(void *opaque, int line, int on)
>      }
>  }
>  
> -void ppce500_init(MachineState *machine, PPCE500Params *params)
> +
> +void ppce500_init(MachineState *machine, uint32_t decrementer_freq)
> +{
> +    int i;
> +    for (i = 0; i < smp_cpus; i++) {
> +        PowerPCCPU *cpu;
> +        CPUState *cs;
> +        CPUPPCState *env;
> +
> +        cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
> +        env = &cpu->env;
> +        cs = CPU(cpu);
> +
> +        if (env->mmu_model != POWERPC_MMU_BOOKE206) {
> +            error_report("MMU model %i not supported by this machine.",
> +                         env->mmu_model);
> +            exit(1);
> +        }
> +
> +        env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
> +
> +        ppc_booke_timers_init(cpu, decrementer_freq, PPC_TIMER_E500);
> +    }
> +}
> +
> +void mpc85xx_init(MachineState *machine, PPCE500Params *params)
>  {
>      MemoryRegion *address_space_mem = get_system_memory();
>      MemoryRegion *ram = g_new(MemoryRegion, 1);
> @@ -716,31 +741,21 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      CPUPPCState *firstenv = NULL;
>      MemoryRegion *ccsr_addr_space;
>      SysBusDevice *s;
> +    CPUState *cs;
>  
> -    for (i = 0; i < smp_cpus; i++) {
> +    ppce500_init(machine, 400000000);
> +
> +    CPU_FOREACH(cs) {
>          PowerPCCPU *cpu;
> -        CPUState *cs;
>  
> -        cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
> +        cpu = POWERPC_CPU(cs);
>          env = &cpu->env;
> -        cs = CPU(cpu);
>  
> -        if (env->mmu_model != POWERPC_MMU_BOOKE206) {
> -            fprintf(stderr, "MMU model %i not supported by this machine.\n",
> -                env->mmu_model);
> -            exit(1);
> -        }
>  
> +        /* Register reset handler */
>          if (!firstenv) {
>              firstenv = env;
> -        }
>  
> -        env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
> -
> -        ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
> -
> -        /* Register reset handler */
> -        if (!i) {
>              /* Primary CPU */
>              struct boot_info *boot_info;
>              boot_info = g_malloc0(sizeof(struct boot_info));
> diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
> index 70ba1d8f4f..350be17462 100644
> --- a/hw/ppc/e500.h
> +++ b/hw/ppc/e500.h
> @@ -24,7 +24,8 @@ typedef struct PPCE500Params {
>      hwaddr spin_base;
>  } PPCE500Params;
>  
> -void ppce500_init(MachineState *machine, PPCE500Params *params);
> +void ppce500_init(MachineState *machine, uint32_t decrementer_freq);
> +void mpc85xx_init(MachineState *machine, PPCE500Params *params);
>  
>  hwaddr booke206_page_size_to_tlb(uint64_t size);
>  
> diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
> index e59e80fb9e..103efc68c2 100644
> --- a/hw/ppc/e500plat.c
> +++ b/hw/ppc/e500plat.c
> @@ -55,7 +55,7 @@ static void e500plat_init(MachineState *machine)
>          params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
>      }
>  
> -    ppce500_init(machine, &params);
> +    mpc85xx_init(machine, &params);
>  }
>  
>  static void e500plat_machine_init(MachineClass *mc)
> diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
> index 1717953ec7..7de4ed8ae2 100644
> --- a/hw/ppc/mpc8544ds.c
> +++ b/hw/ppc/mpc8544ds.c
> @@ -47,7 +47,7 @@ static void mpc8544ds_init(MachineState *machine)
>          exit(1);
>      }
>  
> -    ppce500_init(machine, &params);
> +    mpc85xx_init(machine, &params);
>  }
>  
>  

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100 Michael Davidsaver
@ 2017-12-19  5:06   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-19  5:06 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

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

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

But will need to be rebased on the other revised patches.

> ---
>  tests/Makefile.include  | 3 ++-
>  tests/ds-rtc-i2c-test.c | 8 ++++++++
>  2 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 56045cdf09..062d4e5b7b 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -308,6 +308,7 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
>  check-qtest-ppc-y += tests/prom-env-test$(EXESUF)
>  check-qtest-ppc-y += tests/drive_del-test$(EXESUF)
>  check-qtest-ppc-y += tests/boot-serial-test$(EXESUF)
> +check-qtest-ppc-y += tests/ds-rtc-i2c-test$(EXESUF)
>  
>  check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF)
>  gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c
> @@ -745,7 +746,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
>  	tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
>  tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
>  tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
> -tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
> +tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) $(libqos-e500-obj-y)
>  tests/m25p80-test$(EXESUF): tests/m25p80-test.o
>  tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
>  tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
> diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
> index 0586dbd467..f7dab1863e 100644
> --- a/tests/ds-rtc-i2c-test.c
> +++ b/tests/ds-rtc-i2c-test.c
> @@ -18,6 +18,9 @@
>  #define IMX25_I2C_0_BASE 0x43F80000
>  #define DS1338_ADDR 0x68
>  
> +#define E500_CCSR_BASE 0xff700000
> +#define DS1375_ADDR 0xd0
> +
>  static I2CAdapter *i2c;
>  static uint8_t addr;
>  static bool use_century;
> @@ -148,6 +151,11 @@ int main(int argc, char *argv[])
>          addr = DS1338_ADDR;
>          use_century = false;
>  
> +    } else if (strcmp(arch, "ppc") == 0) {
> +        qtest_start("-machine mvme3100-1152");
> +        i2c = e500_i2c_create(E500_CCSR_BASE);
> +        addr = DS1375_ADDR;
> +        use_century = true;
>      }
>  
>      qtest_add_data_func("/ds-rtc-i2c/set24", test_time_24, test_rtc_set);

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test Michael Davidsaver
@ 2017-12-19  5:06   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-19  5:06 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:15PM -0600, Michael Davidsaver wrote:
> Exercise some features of the mvme3100 CPLD logic
> and read from the eeprom w/ VPD.
> 
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>

Looks good, but will need a rebase.

> ---
>  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 062d4e5b7b..97bce77ee4 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -373,6 +373,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)
>  
> @@ -782,6 +784,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;
> +}

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine
  2017-11-26 21:59 ` [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine Michael Davidsaver
@ 2017-12-20  4:05   ` David Gibson
  0 siblings, 0 replies; 42+ messages in thread
From: David Gibson @ 2017-12-20  4:05 UTC (permalink / raw)
  To: Michael Davidsaver; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On Sun, Nov 26, 2017 at 03:59:13PM -0600, Michael Davidsaver wrote:
> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
> ---
>  default-configs/ppc-softmmu.mak |   1 +
>  hw/ppc/Makefile.objs            |   1 +
>  hw/ppc/mvme3100.c               | 740 ++++++++++++++++++++++++++++++++++++++++
>  hw/ppc/mvme3100_cpld.c          | 192 +++++++++++
>  4 files changed, 934 insertions(+)
>  create mode 100644 hw/ppc/mvme3100.c
>  create mode 100644 hw/ppc/mvme3100_cpld.c
> 
> diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
> index bb225c6e46..3777194a4a 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_DSRTCI2C=y
> 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..8eb6a3a9a4
> --- /dev/null
> +++ b/hw/ppc/mvme3100.c
> @@ -0,0 +1,740 @@
> +/*
> + * 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)
> +
> +#define E500_TSEC_OFFSET(N)     (0x24000 + (N) * 0x1000)
> +
> +/* Complex Core Bus frequency */
> +#define CCB_FREQ (333333333u)
> +
> +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;

I'm not seeing a lot of point to having this as a separate structure,
rather then embedding the fields directly in the MVME3100Class.

> +} MVME3100Class;
> +
> +typedef struct MVME3100State {
> +    /*< private >*/
> +    MachineState parent_obj;
> +    /*< public >*/
> +
> +    uint32_t load_address,
> +             entry_address;
> +
> +    MemoryRegion ram;
> +} 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",

Right, it does look like these are things that the user might want to
configure.  I won't insist on that for an initial merge, though.

> +        /* 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);

Just repeat the const size_t for the second declaration, it'll be
easier to read.

> +
> +    if ((len == 0 && remaining < 1)
> +            || (remaining < len + 2))
> +    {

qemu style puts the { on the same line as the if.  Best run your whole
set through checkpatch.pl to catch other style errors.

> +        fprintf(stderr, "VPD GEV overflow\n");

Use error_report() please.  Or even error_setg() and add an Error **
parmaeter to this function (letting the caller decide whether it
should be fatal or not).

> +        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))

Odd bracketing here.  || is associative, so the () around the last two
clauses looks redundant.

> +    {
> +        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");

Giving a fixed serial number seems a bit bogus.  Could you derive this
from the qemu instance UUID, maybe?

> +    /* 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);

IIRC g_strsplit() is non destructive on the input, so you shouldn't
need the E temporary.

> +        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 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;
> +}
> +
> +static void mvme3100_cpu_reset(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    cpu_reset(cs);
> +
> +    /* HID0 clock control functions not modeled.
> +     * Decrementer always enabled with CCB/8 as reference.
> +     * HID0[EMCP] and HID0[TBEN] set
> +     */
> +    env->spr[SPR_HID0] |= 0x80004000;
> +
> +    remap_tlb_bare(&cpu->env);
> +    env->nip = 0xfffffffc;
> +}
> +
> +static
> +void mvme3100_pci1_set_irq(void *opaque, int irq_num, int level)
> +{
> +    qemu_irq *pic = opaque;
> +
> +    qemu_set_irq(pic[irq_num], level);
> +}
> +
> +/* 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 model one PCI-PCI bridge (0:0x12:0) but with a different vendor/device
> + *
> + * We don't model:
> + * # The SATA controller GD31244 (0x8086-0x3200)
> + * # The USB (OHCI) controller uPD740101 (0x1033-0x0035)
> + * # The second PCI-PCI bridge (0:0x13:0) in front of the USB controllers
> + *
> + * (Note that the SATA controller found on newer boards is different)
> + */
> +
> +static void mvme3100_init(MachineState *machine)
> +{
> +    MVME3100State *mvme3100 = MVME3100(machine);
> +    const mvme3100_info *info;
> +    DeviceState *dev;
> +    BusState *i2c;
> +    PCIBus *pci0, *pci1;
> +    SysBusDevice *cpld, *pic;
> +    qemu_irq *pci1_pins = g_malloc_n(4, sizeof(*pci1_pins));
> +    FWCfgState *fwinfo;
> +    DriveInfo *drvinfo;
> +    MemoryRegion *ccsr;
> +
> +    {
> +        MVME3100Class *klass = MVME3100_GET_CLASS(machine);
> +        info = klass->info;
> +    }
> +
> +    /* Setup CPU */
> +
> +    ppce500_init(machine, CCB_FREQ / 8u);
> +
> +    memory_region_allocate_system_memory(&mvme3100->ram, NULL,
> +                                         "mvme3100.ram", ram_size);
> +    memory_region_add_subregion(get_system_memory(), 0, &mvme3100->ram);
> +
> +    qemu_register_reset(mvme3100_cpu_reset, POWERPC_CPU(first_cpu));
> +
> +    /* Create CCSR and builtin periphrials */
> +    dev = qdev_create(NULL, "e500-ccsr");
> +    object_property_add_child(qdev_get_machine(), "e500-ccsr",
> +                              OBJECT(dev), NULL);
> +    qdev_prop_set_uint32(dev, "ccb-freq", CCB_FREQ);
> +    qdev_prop_set_uint32(dev, "mpic-model", OPENPIC_MODEL_FSL_MPIC_20);
> +    qdev_prop_set_uint32(dev, "porpllsr", info->porpllsr);
> +    qdev_prop_set_uint32(dev, "base", 0xff700000ULL);
> +    qdev_prop_set_uint32(dev, "ram-size", ram_size);
> +    qdev_prop_set_uint32(dev, "pci_first_slot", 0);
> +    qdev_prop_set_uint32(dev, "pci_first_pin_irq", 1);
> +    qdev_init_nofail(dev);
> +
> +    ccsr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> +
> +    pic = SYS_BUS_DEVICE(object_resolve_path("/machine/pic", 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);
> +
> +    dev = DEVICE(object_resolve_path("/machine/pci-host", NULL));
> +    assert(dev);
> +    pci0 = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
> +    assert(pci0);
> +
> +    /* Add expansion PCI bus (2x PMC sites)
> +     * "pci-bridge" is not a PLX bridge, but shouldn't matter?
> +     */
> +    dev = qdev_create(BUS(pci0), "pci-bridge");
> +
> +    qdev_prop_set_uint8(dev, "chassis_nr", 1);
> +    qdev_prop_set_int32(dev, "addr", PCI_DEVFN(0x12, 0));
> +
> +    qdev_init_nofail(dev);
> +
> +    pci1 = PCI_BUS(qdev_get_child_bus(dev, "pci.1"));
> +    assert(pci1);
> +
> +    pci1_pins[0] = qdev_get_gpio_in(DEVICE(pic), 4);
> +    pci1_pins[1] = qdev_get_gpio_in(DEVICE(pic), 5);
> +    pci1_pins[2] = qdev_get_gpio_in(DEVICE(pic), 6);
> +    pci1_pins[3] = qdev_get_gpio_in(DEVICE(pic), 7);
> +
> +    pci_bus_irqs(pci1, mvme3100_pci1_set_irq,
> +                 pci_swizzle_map_irq_fn, pci1_pins, 4);
> +
> +    /* the actual PLX bridge doesn't emit interrupts */
> +    pci_set_byte(PCI_DEVICE(dev)->config + PCI_INTERRUPT_PIN, 0);
> +
> +    /* root bus is only home to soldered devices, and has a
> +     * an arbitrary IRQ pin mapping.
> +     * Don't allow qdev_device_add() to consider it.
> +     */
> +    {
> +        BusState *bpci0 = BUS(pci0);
> +        BusClass *bcls  = BUS_GET_CLASS(pci0);
> +        assert(bpci0);

I think the BUS() macro will already abort() if pci0 is NULL or not a
BUS.

> +        /* bus 0 is thus declared to be full.
> +         * as a side-effect, expansion PCI bus limited to 15 devices
> +         */
> +        bpci0->max_index = bcls->max_dev = 15;
> +    }
> +
> +    /* 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);
> +
> +    /* NIC (2x TSEC and 1x FEC) */
> +    if (nd_table[0].used) {
> +        qemu_check_nic_model(&nd_table[0], "eTSEC");
> +
> +        dev = etsec_create(E500_TSEC_OFFSET(0), ccsr, &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(E500_TSEC_OFFSET(1), ccsr, &nd_table[1],
> +                qdev_get_gpio_in(DEVICE(pic), 16 + 19),
> +                qdev_get_gpio_in(DEVICE(pic), 16 + 20),
> +                qdev_get_gpio_in(DEVICE(pic), 16 + 23));
> +
> +    } else if (nd_table[2].used) {
> +        qemu_log_mask(LOG_UNIMP, "FEC (ethernet #3) not modeled\n");
> +    }
> +
> +    /* 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);
> +    qdev_connect_gpio_out(dev, 0, qdev_get_gpio_in(DEVICE(pic), 11));
> +
> +    /* 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)

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
  2017-12-06 11:11       ` David Gibson
@ 2017-12-27  3:53         ` Michael Davidsaver
  0 siblings, 0 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-12-27  3:53 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On 12/06/2017 05:11 AM, David Gibson wrote:
> On Tue, Dec 05, 2017 at 10:42:25PM -0500, Michael Davidsaver wrote:
>> On 12/05/2017 01:53 AM, David Gibson wrote:
>>> On Sun, Nov 26, 2017 at 03:59:11PM -0600, Michael Davidsaver wrote:
>>>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
>>>
>>> Hmm.  Is there anything you're *not* planning to move under the CCSR.
>>
>> Well, the decrementer/timebase initialization for one as this has
>> nothing to do with the CCSR registers.
> 
> Right, but no actual devices, even small ones?

Well, there is the GPIO controller ("mpc8xxx_gpio") as I have frankly
have no idea where it comes from.  Neither MPC8540 nor 8544 define
anything at CCSR offset 0xFF000.  The registers modeled differ
from the GPIO controller which is defined at 0xE0030.

So I'm considering this to be specific to the existing boards.

>> I haven't added the TSEC/eTSEC instances either.
>> Partly this is because the existing boards, for reasons I don't understand,
>> use virtio NICs.
>>
>> Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544
>> has instances 1 and 3.  So I decided to leave NIC setup to the Machine
>> rather then add the extra code to parameterize this under the CCSR device.
>>
>>> If not, I'm really wondering if the CCSR ought to be a device in its
>>> own right, rather than just a container memory region used within the
>>> machine.
>>
>> I don't think I follow what you mean by "device" in this context?
>> The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr").
>> What device-like characteristics could it have?
> 
> Sorry, I wasn't clear.  the CCSR definitely *is* a device in the
> current scheme, but I'm wondering if that was a good idea.

I think I see what you're getting at.  You're right that CCSR
isn't a "device" in the same sense as eg. a UART.  In my mind
it's more like a PCI host bridge, having a few registers itself,
though serving mainly to route to the devices behind it.

I see the CCSR "device" as the bridge onto the system bus.
In some ways it might be considered to be the only device
on the system bus apart from the CPU(s).  This "device"
handles first level routing of physical addresses to
RAM, PCI, or local bus via the LAWBAR* registers (unmodeled).
Or to the I/O devices in the CCSR range via CCSRBAR.

I don't have plans to model that LAWBAR* registers,
as it hasn't proved necessary for RTEMS or Linux guests.
I have considered how this could be done as Linux does
touch these registers, but doesn't readback/check the
values it has written.  I think having a CCSR "device"
would make it simpler to model the local windows
should this become desirable.  eg. if Linux starts
validating LAWBAR* or to run unmodified u-boot.


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

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

* Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
  2017-12-06 11:14       ` David Gibson
@ 2017-12-28  4:11         ` Michael Davidsaver
  0 siblings, 0 replies; 42+ messages in thread
From: Michael Davidsaver @ 2017-12-28  4:11 UTC (permalink / raw)
  To: David Gibson; +Cc: Alexander Graf, qemu-devel, qemu-ppc

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

On 12/06/2017 05:14 AM, David Gibson wrote:
> On Sun, Dec 03, 2017 at 03:15:10PM -0600, Michael Davidsaver wrote:
>> On 11/29/2017 11:13 PM, David Gibson wrote:
>>> On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote:
>>>> Support for: ds1307, ds1337, ds1338, ds1339,
>>>> ds1340, ds1375, ds1388, and ds3231.
>>>>
>>>> Tested with ds1338 and ds1375.
>>>>
>>>> Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
>>>
>>> I certainly like the idea of consolidating this code, but reviewing to
>>> see that the new code really is a generalization of the old is
>>> something I won't have time for for a while.
>>>
>>> Also, hw/timer is not within my purview so it'll probably need to go
>>> another path to merge.
>>
>> Could you be a bit more explicit about what, if anything, I need to do
>> to move this forward?
> 
> Ugh.. that's pretty tough, since ds1338 doesn't have an activate
> maintainer.  You can look at the git history for some possible
> candidates of people to ask about it, but it hasn't been touched much
> in quite a while.
> 
> One approach that could help is to re-order so that your testing
> rework goes before the change to ds1338.  If your new generalization
> can pass the same set of tests as the original ds1338 code, that's at
> least a good start on being convincing that it's a true superset of
> the previous functionality.

A slight wrinkle is that my testing found two bugs with the original
ds1338 model (also one in my new code).  The two don't seem
significant practically.  It actually isn't possible to switch to
12-hour mode.  And there is an obscure off by one situation possible
with wday_offset and timezones.  Of course most guests use 24-hour mode
and ignore the RTC day-of-week.

The upshot of this is that several test cases now fail when run against ds1338.c.

My recommendation would be to start by looking at the test code.
This could be compared against guest code.  When I send the next
iteration I'll include some links.

> The other approach is to do the rework in a rather longer series of
> patches.  Start by simply moving ds1338.c, then do a mechanical
> replacement of the names within it, then start generalizing and
> altering.  That's a lot of work for you, but it makes it much easier
> to review each step

I know from my first foray into QEMU land that this is preferable for review.
Unfortunately, I expanded from my previous ds1375 model instead of the ds1338.


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

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

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

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-26 21:58 [Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2 Michael Davidsaver
2017-11-26 21:58 ` [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report() Michael Davidsaver
2017-11-27  7:09   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 02/17] i2c: start trace-events Michael Davidsaver
2017-11-26 21:59 ` [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller Michael Davidsaver
2017-11-27  7:12   ` David Gibson
2017-11-27 19:05     ` Michael Davidsaver
2017-11-29  1:32       ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 04/17] qtest: add e500_i2c_create() Michael Davidsaver
2017-11-26 21:59 ` [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices Michael Davidsaver
2017-11-30  5:13   ` David Gibson
2017-12-03 21:15     ` Michael Davidsaver
2017-12-06 11:14       ` David Gibson
2017-12-28  4:11         ` Michael Davidsaver
2017-11-26 21:59 ` [Qemu-devel] [PATCH 06/17] tests: rewrite testing for DS RTC devices Michael Davidsaver
2017-11-26 21:59 ` [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type Michael Davidsaver
2017-11-27  7:15   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers Michael Davidsaver
2017-12-04  9:30   ` David Gibson
2017-12-06  3:13     ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR Michael Davidsaver
2017-12-05  6:34   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR Michael Davidsaver
2017-12-05  6:37   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock Michael Davidsaver
2017-12-05  6:40   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR Michael Davidsaver
2017-12-05  6:49   ` David Gibson
2017-12-06  3:26     ` Michael Davidsaver
2017-11-26 21:59 ` [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR Michael Davidsaver
2017-12-05  6:53   ` David Gibson
2017-12-06  3:42     ` Michael Davidsaver
2017-12-06 11:11       ` David Gibson
2017-12-27  3:53         ` Michael Davidsaver
2017-11-26 21:59 ` [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization Michael Davidsaver
2017-12-19  5:05   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine Michael Davidsaver
2017-12-20  4:05   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100 Michael Davidsaver
2017-12-19  5:06   ` David Gibson
2017-11-26 21:59 ` [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test Michael Davidsaver
2017-12-19  5:06   ` David Gibson

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.