qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/17] arm-devs queue
@ 2013-03-15 16:56 Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 01/17] hw/vexpress: Pass proc_id via VEDBoardInfo Peter Maydell
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Another arm-devs pullreq: xilinx fixes from Peter C, the pl330
model, and my vexpress fixes for the system control regs.
Please pull.

thanks
-- PMM


The following changes since commit dc0b0616f726956001be09e9a65a6e0b0bd939db:

  Merge remote-tracking branch 'stefanha/block' into staging (2013-03-15 10:47:21 -0500)

are available in the git repository at:


  git://git.linaro.org/people/pmaydell/qemu-arm.git arm-devs.next

for you to fetch changes up to f8b9fe249a706bfed61e0bb66c73394553696382:

  xilinx_spips: QOM styling fixes (2013-03-15 16:41:59 +0000)

----------------------------------------------------------------
Nathan Rossi (2):
      xilinx_spips: Fix bus setup conditional check
      xilinx_spips: Add missing dual-bus snoop commands

Peter Crosthwaite (5):
      iov: Factor out hexdumper
      pl330: Initial version
      xilinx_zynq: added pl330 to machine model
      xilinx_spips: Set unused IRQs to NULL
      xilinx_spips: QOM styling fixes

Peter Maydell (10):
      hw/vexpress: Pass proc_id via VEDBoardInfo
      hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way
      hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op
      hw/arm_sysctl: Implement SYS_CFG_DVIMODE as a no-op
      hw/arm_sysctl: Convert from qdev init to instance_init
      qdev: Implement (variable length) array properties
      hw/arm_sysctl: Implement SYS_CFG_VOLT
      hw/vexpress: Pass voltage sensor properties to sysctl device
      hw/arm_sysctl: Implement SYS_CFG_OSC function
      hw/vexpress: Set reset values for daughterboard oscillators

 default-configs/arm-softmmu.mak |    1 +
 hw/Makefile.objs                |    1 +
 hw/arm/vexpress.c               |   81 +-
 hw/arm/xilinx_zynq.c            |   24 +
 hw/arm_sysctl.c                 |  261 +++++-
 hw/pl330.c                      | 1654 +++++++++++++++++++++++++++++++++++++++
 hw/qdev-core.h                  |    3 +
 hw/qdev-properties.c            |  104 +++
 hw/qdev-properties.h            |   39 +
 hw/xilinx_spips.c               |   64 +-
 include/qemu-common.h           |    6 +
 util/Makefile.objs              |    1 +
 util/hexdump.c                  |   37 +
 util/iov.c                      |   36 +-
 14 files changed, 2234 insertions(+), 78 deletions(-)
 create mode 100644 hw/pl330.c
 create mode 100644 util/hexdump.c

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

* [Qemu-devel] [PATCH 01/17] hw/vexpress: Pass proc_id via VEDBoardInfo
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 02/17] hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way Peter Maydell
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Pass the daughterboard-specific proc_id property to the code that
creates the sysctl device via the VEDBoardInfo struct, rather than
by having the daughterboard init function write to a uint32_t*
argument. This is a cleaner way to pass the info around, and
is in line with the way we are going to handle voltage and
oscillator initialization.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/vexpress.c |   19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 02922c3..47a844f 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -147,19 +147,20 @@ typedef struct VEDBoardInfo VEDBoardInfo;
 typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
                           ram_addr_t ram_size,
                           const char *cpu_model,
-                          qemu_irq *pic, uint32_t *proc_id);
+                          qemu_irq *pic);
 
 struct VEDBoardInfo {
     const hwaddr *motherboard_map;
     hwaddr loader_start;
     const hwaddr gic_cpu_if_addr;
+    uint32_t proc_id;
     DBoardInitFn *init;
 };
 
 static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
                                   ram_addr_t ram_size,
                                   const char *cpu_model,
-                                  qemu_irq *pic, uint32_t *proc_id)
+                                  qemu_irq *pic)
 {
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -175,8 +176,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
         cpu_model = "cortex-a9";
     }
 
-    *proc_id = 0x0c000191;
-
     for (n = 0; n < smp_cpus; n++) {
         ARMCPU *cpu = cpu_arm_init(cpu_model);
         if (!cpu) {
@@ -251,13 +250,14 @@ static const VEDBoardInfo a9_daughterboard = {
     .motherboard_map = motherboard_legacy_map,
     .loader_start = 0x60000000,
     .gic_cpu_if_addr = 0x1e000100,
+    .proc_id = 0x0c000191,
     .init = a9_daughterboard_init,
 };
 
 static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
                                    ram_addr_t ram_size,
                                    const char *cpu_model,
-                                   qemu_irq *pic, uint32_t *proc_id)
+                                   qemu_irq *pic)
 {
     int n;
     MemoryRegion *sysmem = get_system_memory();
@@ -271,8 +271,6 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
         cpu_model = "cortex-a15";
     }
 
-    *proc_id = 0x14000237;
-
     for (n = 0; n < smp_cpus; n++) {
         ARMCPU *cpu;
         qemu_irq *irqp;
@@ -344,6 +342,7 @@ static const VEDBoardInfo a15_daughterboard = {
     .motherboard_map = motherboard_aseries_map,
     .loader_start = 0x80000000,
     .gic_cpu_if_addr = 0x2c002000,
+    .proc_id = 0x14000237,
     .init = a15_daughterboard_init,
 };
 
@@ -352,7 +351,6 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
 {
     DeviceState *dev, *sysctl, *pl041;
     qemu_irq pic[64];
-    uint32_t proc_id;
     uint32_t sys_id;
     DriveInfo *dinfo;
     ram_addr_t vram_size, sram_size;
@@ -361,8 +359,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
     MemoryRegion *sram = g_new(MemoryRegion, 1);
     const hwaddr *map = daughterboard->motherboard_map;
 
-    daughterboard->init(daughterboard, args->ram_size, args->cpu_model,
-                        pic, &proc_id);
+    daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic);
 
     /* Motherboard peripherals: the wiring is the same but the
      * addresses vary between the legacy and A-Series memory maps.
@@ -372,7 +369,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
 
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
-    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id);
     qdev_init_nofail(sysctl);
     sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 02/17] hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 01/17] hw/vexpress: Pass proc_id via VEDBoardInfo Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 03/17] hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op Peter Maydell
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

The SYS_CFGCTRL register consists of separate fields
for DCC, function, site, position and device, as well
as a read/write bit. Refactor the code handling SYS_CFGCTRL
writes to make it easier to add support for functions
like SYS_CFG_OSC which support multiple device fields.
We also pull the handling out into its own function for
clarity, as there are potentially a lot of implementable
subfunctions.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_sysctl.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 132 insertions(+), 11 deletions(-)

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index a46f8d4..05a3200 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -9,6 +9,7 @@
 
 #include "hw/hw.h"
 #include "qemu/timer.h"
+#include "qemu/bitops.h"
 #include "hw/sysbus.h"
 #include "hw/primecell.h"
 #include "sysemu/sysemu.h"
@@ -191,6 +192,110 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
     }
 }
 
+/* SYS_CFGCTRL functions */
+#define SYS_CFG_OSC 1
+#define SYS_CFG_VOLT 2
+#define SYS_CFG_AMP 3
+#define SYS_CFG_TEMP 4
+#define SYS_CFG_RESET 5
+#define SYS_CFG_SCC 6
+#define SYS_CFG_MUXFPGA 7
+#define SYS_CFG_SHUTDOWN 8
+#define SYS_CFG_REBOOT 9
+#define SYS_CFG_DVIMODE 11
+#define SYS_CFG_POWER 12
+#define SYS_CFG_ENERGY 13
+
+/* SYS_CFGCTRL site field values */
+#define SYS_CFG_SITE_MB 0
+#define SYS_CFG_SITE_DB1 1
+#define SYS_CFG_SITE_DB2 2
+
+/**
+ * vexpress_cfgctrl_read:
+ * @s: arm_sysctl_state pointer
+ * @dcc, @function, @site, @position, @device: split out values from
+ * SYS_CFGCTRL register
+ * @val: pointer to where to put the read data on success
+ *
+ * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
+ * write the read value to *val. On failure, return false (and val may
+ * or may not be written to).
+ */
+static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
+                                  unsigned int function, unsigned int site,
+                                  unsigned int position, unsigned int device,
+                                  uint32_t *val)
+{
+    /* We don't support anything other than DCC 0, board stack position 0
+     * or sites other than motherboard/daughterboard:
+     */
+    if (dcc != 0 || position != 0 ||
+        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
+        goto cfgctrl_unimp;
+    }
+
+    switch (function) {
+    default:
+        break;
+    }
+
+cfgctrl_unimp:
+    qemu_log_mask(LOG_UNIMP,
+                  "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
+                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
+                  function, dcc, site, position, device);
+    return false;
+}
+
+/**
+ * vexpress_cfgctrl_write:
+ * @s: arm_sysctl_state pointer
+ * @dcc, @function, @site, @position, @device: split out values from
+ * SYS_CFGCTRL register
+ * @val: data to write
+ *
+ * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
+ * On failure, return false.
+ */
+static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
+                                   unsigned int function, unsigned int site,
+                                   unsigned int position, unsigned int device,
+                                   uint32_t val)
+{
+    /* We don't support anything other than DCC 0, board stack position 0
+     * or sites other than motherboard/daughterboard:
+     */
+    if (dcc != 0 || position != 0 ||
+        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
+        goto cfgctrl_unimp;
+    }
+
+    switch (function) {
+    case SYS_CFG_SHUTDOWN:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            qemu_system_shutdown_request();
+            return true;
+        }
+        break;
+    case SYS_CFG_REBOOT:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            qemu_system_reset_request();
+            return true;
+        }
+        break;
+    default:
+        break;
+    }
+
+cfgctrl_unimp:
+    qemu_log_mask(LOG_UNIMP,
+                  "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
+                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
+                  function, dcc, site, position, device);
+    return false;
+}
+
 static void arm_sysctl_write(void *opaque, hwaddr offset,
                              uint64_t val, unsigned size)
 {
@@ -322,17 +427,33 @@ static void arm_sysctl_write(void *opaque, hwaddr offset,
         if (board_id(s) != BOARD_ID_VEXPRESS) {
             goto bad_reg;
         }
-        s->sys_cfgctrl = val & ~(3 << 18);
-        s->sys_cfgstat = 1;            /* complete */
-        switch (s->sys_cfgctrl) {
-        case 0xc0800000:            /* SYS_CFG_SHUTDOWN to motherboard */
-            qemu_system_shutdown_request();
-            break;
-        case 0xc0900000:            /* SYS_CFG_REBOOT to motherboard */
-            qemu_system_reset_request();
-            break;
-        default:
-            s->sys_cfgstat |= 2;        /* error */
+        /* Undefined bits [19:18] are RAZ/WI, and writing to
+         * the start bit just triggers the action; it always reads
+         * as zero.
+         */
+        s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
+        if (val & (1 << 31)) {
+            /* Start bit set -- actually do something */
+            unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
+            unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
+            unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
+            unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
+            unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
+            s->sys_cfgstat = 1;            /* complete */
+            if (s->sys_cfgctrl & (1 << 30)) {
+                if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
+                                            device, s->sys_cfgdata)) {
+                    s->sys_cfgstat |= 2;        /* error */
+                }
+            } else {
+                uint32_t val;
+                if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
+                                           device, &val)) {
+                    s->sys_cfgstat |= 2;        /* error */
+                } else {
+                    s->sys_cfgdata = val;
+                }
+            }
         }
         s->sys_cfgctrl &= ~(1 << 31);
         return;
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 03/17] hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 01/17] hw/vexpress: Pass proc_id via VEDBoardInfo Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 02/17] hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 04/17] hw/arm_sysctl: Implement SYS_CFG_DVIMODE " Peter Maydell
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

SYS_CFG_MUXFPGA allows the guest to select whether the
video output should come from the motherboard's LCD
controller or the daughterboard's one. Since QEMU doesn't
currently support selecting the video output like this,
implement as a no-op, so Linux doesn't complain about
the register not being implemented.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_sysctl.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 05a3200..a6e5ed4 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -272,6 +272,17 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
     }
 
     switch (function) {
+    case SYS_CFG_MUXFPGA:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            /* Select whether video output comes from motherboard
+             * or daughterboard: log and ignore as QEMU doesn't
+             * support this.
+             */
+            qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
+                          "not supported, ignoring\n");
+            return true;
+        }
+        break;
     case SYS_CFG_SHUTDOWN:
         if (site == SYS_CFG_SITE_MB && device == 0) {
             qemu_system_shutdown_request();
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 04/17] hw/arm_sysctl: Implement SYS_CFG_DVIMODE as a no-op
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (2 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 03/17] hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 05/17] hw/arm_sysctl: Convert from qdev init to instance_init Peter Maydell
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

SYS_CFG_DVIMODE allows the guest to select whether the
output DVI signal is VGA, SVGA, XGA, SGA or UXGA. Since
this makes no difference to QEMU, implement writes as a
no-op so Linux doesn't complain.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_sysctl.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index a6e5ed4..840bfad 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -295,6 +295,14 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
             return true;
         }
         break;
+    case SYS_CFG_DVIMODE:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            /* Selecting DVI mode is meaningless for QEMU: we will
+             * always display the output correctly according to the
+             * pixel height/width programmed into the CLCD controller.
+             */
+            return true;
+        }
     default:
         break;
     }
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 05/17] hw/arm_sysctl: Convert from qdev init to instance_init
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (3 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 04/17] hw/arm_sysctl: Implement SYS_CFG_DVIMODE " Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 06/17] qdev: Implement (variable length) array properties Peter Maydell
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Convert this device from old-style qdev init to an instance_init
function. We don't need a realize function yet, though.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_sysctl.c |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 840bfad..7c94b78 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -525,15 +525,16 @@ static void arm_sysctl_gpio_set(void *opaque, int line, int level)
     }
 }
 
-static int arm_sysctl_init(SysBusDevice *dev)
+static void arm_sysctl_init(Object *obj)
 {
-    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
+    DeviceState *dev = DEVICE(obj);
+    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd);
 
     memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
-    qdev_init_gpio_out(&s->busdev.qdev, &s->pl110_mux_ctrl, 1);
-    return 0;
+    sysbus_init_mmio(sd, &s->iomem);
+    qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);
+    qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
 }
 
 static Property arm_sysctl_properties[] = {
@@ -545,9 +546,7 @@ static Property arm_sysctl_properties[] = {
 static void arm_sysctl_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = arm_sysctl_init;
     dc->reset = arm_sysctl_reset;
     dc->vmsd = &vmstate_arm_sysctl;
     dc->props = arm_sysctl_properties;
@@ -557,6 +556,7 @@ static const TypeInfo arm_sysctl_info = {
     .name          = "realview_sysctl",
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(arm_sysctl_state),
+    .instance_init = arm_sysctl_init,
     .class_init    = arm_sysctl_class_init,
 };
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 06/17] qdev: Implement (variable length) array properties
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (4 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 05/17] hw/arm_sysctl: Convert from qdev init to instance_init Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 07/17] hw/arm_sysctl: Implement SYS_CFG_VOLT Peter Maydell
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Add support for declaring array properties for qdev devices.
These work by defining an initial static property 'len-arrayname'
which the user of the device should set to the desired size
of the array. When this property is set, memory is allocated
for the array elements, and dynamic properties "arrayname[0]",
"arrayname[1]"... are created so the user of the device can
then set the values of the individual array elements.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/qdev-core.h       |    3 ++
 hw/qdev-properties.c |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/qdev-properties.h |   39 +++++++++++++++++++
 3 files changed, 146 insertions(+)

diff --git a/hw/qdev-core.h b/hw/qdev-core.h
index 2486f36..547fbc7 100644
--- a/hw/qdev-core.h
+++ b/hw/qdev-core.h
@@ -175,6 +175,9 @@ struct Property {
     uint8_t      bitnr;
     uint8_t      qtype;
     int64_t      defval;
+    int          arrayoffset;
+    PropertyInfo *arrayinfo;
+    int          arrayfieldsize;
 };
 
 struct PropertyInfo {
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 0307a78..247ca6c 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -779,6 +779,110 @@ PropertyInfo qdev_prop_pci_host_devaddr = {
     .set = set_pci_host_devaddr,
 };
 
+/* --- support for array properties --- */
+
+/* Used as an opaque for the object properties we add for each
+ * array element. Note that the struct Property must be first
+ * in the struct so that a pointer to this works as the opaque
+ * for the underlying element's property hooks as well as for
+ * our own release callback.
+ */
+typedef struct {
+    struct Property prop;
+    char *propname;
+    ObjectPropertyRelease *release;
+} ArrayElementProperty;
+
+/* object property release callback for array element properties:
+ * we call the underlying element's property release hook, and
+ * then free the memory we allocated when we added the property.
+ */
+static void array_element_release(Object *obj, const char *name, void *opaque)
+{
+    ArrayElementProperty *p = opaque;
+    if (p->release) {
+        p->release(obj, name, opaque);
+    }
+    g_free(p->propname);
+    g_free(p);
+}
+
+static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
+                              const char *name, Error **errp)
+{
+    /* Setter for the property which defines the length of a
+     * variable-sized property array. As well as actually setting the
+     * array-length field in the device struct, we have to create the
+     * array itself and dynamically add the corresponding properties.
+     */
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
+    void **arrayptr = (void *)dev + prop->arrayoffset;
+    void *eltptr;
+    const char *arrayname;
+    int i;
+
+    if (dev->realized) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+        return;
+    }
+    if (*alenptr) {
+        error_setg(errp, "array size property %s may not be set more than once",
+                   name);
+        return;
+    }
+    visit_type_uint32(v, alenptr, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    if (!*alenptr) {
+        return;
+    }
+
+    /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
+     * strip it off so we can get the name of the array itself.
+     */
+    assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
+                   strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
+    arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);
+
+    /* Note that it is the responsibility of the individual device's deinit
+     * to free the array proper.
+     */
+    *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
+    for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
+        char *propname = g_strdup_printf("%s[%d]", arrayname, i);
+        ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
+        arrayprop->release = prop->arrayinfo->release;
+        arrayprop->propname = propname;
+        arrayprop->prop.info = prop->arrayinfo;
+        arrayprop->prop.name = propname;
+        /* This ugly piece of pointer arithmetic sets up the offset so
+         * that when the underlying get/set hooks call qdev_get_prop_ptr
+         * they get the right answer despite the array element not actually
+         * being inside the device struct.
+         */
+        arrayprop->prop.offset = eltptr - (void *)dev;
+        assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr);
+        object_property_add(obj, propname,
+                            arrayprop->prop.info->name,
+                            arrayprop->prop.info->get,
+                            arrayprop->prop.info->set,
+                            array_element_release,
+                            arrayprop, errp);
+        if (error_is_set(errp)) {
+            return;
+        }
+    }
+}
+
+PropertyInfo qdev_prop_arraylen = {
+    .name = "uint32",
+    .get = get_uint32,
+    .set = set_prop_arraylen,
+};
+
 /* --- public helpers --- */
 
 static Property *qdev_prop_walk(Property *props, const char *name)
diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
index 0b0465c..c9bb246 100644
--- a/hw/qdev-properties.h
+++ b/hw/qdev-properties.h
@@ -26,6 +26,7 @@ extern PropertyInfo qdev_prop_vlan;
 extern PropertyInfo qdev_prop_pci_devfn;
 extern PropertyInfo qdev_prop_blocksize;
 extern PropertyInfo qdev_prop_pci_host_devaddr;
+extern PropertyInfo qdev_prop_arraylen;
 
 #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
         .name      = (_name),                                    \
@@ -51,6 +52,44 @@ extern PropertyInfo qdev_prop_pci_host_devaddr;
         .defval    = (bool)_defval,                              \
         }
 
+#define PROP_ARRAY_LEN_PREFIX "len-"
+
+/**
+ * DEFINE_PROP_ARRAY:
+ * @_name: name of the array
+ * @_state: name of the device state structure type
+ * @_field: uint32_t field in @_state to hold the array length
+ * @_arrayfield: field in @_state (of type '@_arraytype *') which
+ *               will point to the array
+ * @_arrayprop: PropertyInfo defining what property the array elements have
+ * @_arraytype: C type of the array elements
+ *
+ * Define device properties for a variable-length array _name.  A
+ * static property "len-arrayname" is defined. When the device creator
+ * sets this property to the desired length of array, further dynamic
+ * properties "arrayname[0]", "arrayname[1]", ...  are defined so the
+ * device creator can set the array element values. Setting the
+ * "len-arrayname" property more than once is an error.
+ *
+ * When the array length is set, the @_field member of the device
+ * struct is set to the array length, and @_arrayfield is set to point
+ * to (zero-initialised) memory allocated for the array.  For a zero
+ * length array, @_field will be set to 0 and @_arrayfield to NULL.
+ * It is the responsibility of the device deinit code to free the
+ * @_arrayfield memory.
+ */
+#define DEFINE_PROP_ARRAY(_name, _state, _field,                        \
+                          _arrayfield, _arrayprop, _arraytype) {        \
+        .name = (PROP_ARRAY_LEN_PREFIX _name),                          \
+        .info = &(qdev_prop_arraylen),                                  \
+        .offset = offsetof(_state, _field)                              \
+            + type_check(uint32_t, typeof_field(_state, _field)),       \
+        .qtype = QTYPE_QINT,                                            \
+        .arrayinfo = &(_arrayprop),                                     \
+        .arrayfieldsize = sizeof(_arraytype),                           \
+        .arrayoffset = offsetof(_state, _arrayfield),                   \
+        }
+
 #define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
     DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
 #define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 07/17] hw/arm_sysctl: Implement SYS_CFG_VOLT
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (5 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 06/17] qdev: Implement (variable length) array properties Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 08/17] hw/vexpress: Pass voltage sensor properties to sysctl device Peter Maydell
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Implement the SYS_CFG_VOLT registers which return the voltage
of various supplies on motherboard and daughterboard. Since
QEMU implements a perfectly stable power supply these registers
always return a constant value. The number and value of the
daughterboard voltages is dependent on the specific daughterboard,
so we use a property array to allow the board to configure them
appropriately.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_sysctl.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 7c94b78..e2f00d3 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -35,6 +35,8 @@ typedef struct {
     uint32_t sys_cfgctrl;
     uint32_t sys_cfgstat;
     uint32_t sys_clcd;
+    uint32_t db_num_vsensors;
+    uint32_t *db_voltage;
 } arm_sysctl_state;
 
 static const VMStateDescription vmstate_arm_sysctl = {
@@ -236,6 +238,19 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
     }
 
     switch (function) {
+    case SYS_CFG_VOLT:
+        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {
+            *val = s->db_voltage[device];
+            return true;
+        }
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            /* There is only one motherboard voltage sensor:
+             * VIO : 3.3V : bus voltage between mother and daughterboard
+             */
+            *val = 3300000;
+            return true;
+        }
+        break;
     default:
         break;
     }
@@ -537,9 +552,19 @@ static void arm_sysctl_init(Object *obj)
     qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
 }
 
+static void arm_sysctl_finalize(Object *obj)
+{
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
+    g_free(s->db_voltage);
+}
+
 static Property arm_sysctl_properties[] = {
     DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
     DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
+    /* Daughterboard power supply voltages (as reported via SYS_CFG) */
+    DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
+                      db_voltage, qdev_prop_uint32, uint32_t),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -557,6 +582,7 @@ static const TypeInfo arm_sysctl_info = {
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(arm_sysctl_state),
     .instance_init = arm_sysctl_init,
+    .instance_finalize = arm_sysctl_finalize,
     .class_init    = arm_sysctl_class_init,
 };
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 08/17] hw/vexpress: Pass voltage sensor properties to sysctl device
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (6 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 07/17] hw/arm_sysctl: Implement SYS_CFG_VOLT Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 09/17] hw/arm_sysctl: Implement SYS_CFG_OSC function Peter Maydell
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Pass voltage sensor properties to the sysctl device. Since
these are daughterboard specific, we specify them via the
VEDBoardInfo structure.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1359985476-29380-9-git-send-email-peter.maydell@linaro.org
---
 hw/arm/vexpress.c |   30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 47a844f..a2dc759 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -154,6 +154,8 @@ struct VEDBoardInfo {
     hwaddr loader_start;
     const hwaddr gic_cpu_if_addr;
     uint32_t proc_id;
+    uint32_t num_voltage_sensors;
+    const uint32_t *voltages;
     DBoardInitFn *init;
 };
 
@@ -246,11 +248,25 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
     sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
 }
 
+/* Voltage values for SYS_CFG_VOLT daughterboard registers;
+ * values are in microvolts.
+ */
+static const uint32_t a9_voltages[] = {
+    1000000, /* VD10 : 1.0V : SoC internal logic voltage */
+    1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */
+    1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */
+    1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */
+    900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */
+    3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */
+};
+
 static const VEDBoardInfo a9_daughterboard = {
     .motherboard_map = motherboard_legacy_map,
     .loader_start = 0x60000000,
     .gic_cpu_if_addr = 0x1e000100,
     .proc_id = 0x0c000191,
+    .num_voltage_sensors = ARRAY_SIZE(a9_voltages),
+    .voltages = a9_voltages,
     .init = a9_daughterboard_init,
 };
 
@@ -338,11 +354,17 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
     /* 0x7ffd0000: PL354 static memory controller: not modelled */
 }
 
+static const uint32_t a15_voltages[] = {
+    900000, /* Vcore: 0.9V : CPU core voltage */
+};
+
 static const VEDBoardInfo a15_daughterboard = {
     .motherboard_map = motherboard_aseries_map,
     .loader_start = 0x80000000,
     .gic_cpu_if_addr = 0x2c002000,
     .proc_id = 0x14000237,
+    .num_voltage_sensors = ARRAY_SIZE(a15_voltages),
+    .voltages = a15_voltages,
     .init = a15_daughterboard_init,
 };
 
@@ -358,6 +380,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
     MemoryRegion *vram = g_new(MemoryRegion, 1);
     MemoryRegion *sram = g_new(MemoryRegion, 1);
     const hwaddr *map = daughterboard->motherboard_map;
+    int i;
 
     daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic);
 
@@ -370,6 +393,13 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
     qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id);
+    qdev_prop_set_uint32(sysctl, "len-db-voltage",
+                         daughterboard->num_voltage_sensors);
+    for (i = 0; i < daughterboard->num_voltage_sensors; i++) {
+        char *propname = g_strdup_printf("db-voltage[%d]", i);
+        qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]);
+        g_free(propname);
+    }
     qdev_init_nofail(sysctl);
     sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 09/17] hw/arm_sysctl: Implement SYS_CFG_OSC function
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (7 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 08/17] hw/vexpress: Pass voltage sensor properties to sysctl device Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 10/17] hw/vexpress: Set reset values for daughterboard oscillators Peter Maydell
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Implement the SYS_CFG_OSC function. Since the idea of
programmable clock rates doesn't make much sense for QEMU,
we simply allow the clock rate to be read back as written.
The number and value of the daughterboard oscillators varies
between daughterboards, so we provide an array property to
allow their reset values to be configured.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_sysctl.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index e2f00d3..25fc6ea 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -35,13 +35,17 @@ typedef struct {
     uint32_t sys_cfgctrl;
     uint32_t sys_cfgstat;
     uint32_t sys_clcd;
+    uint32_t mb_clock[6];
+    uint32_t *db_clock;
     uint32_t db_num_vsensors;
     uint32_t *db_voltage;
+    uint32_t db_num_clocks;
+    uint32_t *db_clock_reset;
 } arm_sysctl_state;
 
 static const VMStateDescription vmstate_arm_sysctl = {
     .name = "realview_sysctl",
-    .version_id = 3,
+    .version_id = 4,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32(leds, arm_sysctl_state),
@@ -56,6 +60,9 @@ static const VMStateDescription vmstate_arm_sysctl = {
         VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
         VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
         VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
+        VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4),
+        VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks,
+                              4, vmstate_info_uint32, uint32_t),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -79,6 +86,7 @@ static int board_id(arm_sysctl_state *s)
 static void arm_sysctl_reset(DeviceState *d)
 {
     arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
+    int i;
 
     s->leds = 0;
     s->lockval = 0;
@@ -86,6 +94,17 @@ static void arm_sysctl_reset(DeviceState *d)
     s->cfgdata2 = 0;
     s->flags = 0;
     s->resetlevel = 0;
+    /* Motherboard oscillators (in Hz) */
+    s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */
+    s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */
+    s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */
+    s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */
+    s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */
+    s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */
+    /* Daughterboard oscillators: reset from property values */
+    for (i = 0; i < s->db_num_clocks; i++) {
+        s->db_clock[i] = s->db_clock_reset[i];
+    }
     if (board_id(s) == BOARD_ID_VEXPRESS) {
         /* On VExpress this register will RAZ/WI */
         s->sys_clcd = 0;
@@ -251,6 +270,18 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
             return true;
         }
         break;
+    case SYS_CFG_OSC:
+        if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
+            /* motherboard clock */
+            *val = s->mb_clock[device];
+            return true;
+        }
+        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
+            /* daughterboard clock */
+            *val = s->db_clock[device];
+            return true;
+        }
+        break;
     default:
         break;
     }
@@ -287,6 +318,18 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
     }
 
     switch (function) {
+    case SYS_CFG_OSC:
+        if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
+            /* motherboard clock */
+            s->mb_clock[device] = val;
+            return true;
+        }
+        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
+            /* daughterboard clock */
+            s->db_clock[device] = val;
+            return true;
+        }
+        break;
     case SYS_CFG_MUXFPGA:
         if (site == SYS_CFG_SITE_MB && device == 0) {
             /* Select whether video output comes from motherboard
@@ -552,11 +595,19 @@ static void arm_sysctl_init(Object *obj)
     qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
 }
 
+static void arm_sysctl_realize(DeviceState *d, Error **errp)
+{
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
+    s->db_clock = g_new0(uint32_t, s->db_num_clocks);
+}
+
 static void arm_sysctl_finalize(Object *obj)
 {
     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
     arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
     g_free(s->db_voltage);
+    g_free(s->db_clock);
+    g_free(s->db_clock_reset);
 }
 
 static Property arm_sysctl_properties[] = {
@@ -565,6 +616,9 @@ static Property arm_sysctl_properties[] = {
     /* Daughterboard power supply voltages (as reported via SYS_CFG) */
     DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
                       db_voltage, qdev_prop_uint32, uint32_t),
+    /* Daughterboard clock reset values (as reported via SYS_CFG) */
+    DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,
+                      db_clock_reset, qdev_prop_uint32, uint32_t),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -572,6 +626,7 @@ static void arm_sysctl_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
 
+    dc->realize = arm_sysctl_realize;
     dc->reset = arm_sysctl_reset;
     dc->vmsd = &vmstate_arm_sysctl;
     dc->props = arm_sysctl_properties;
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 10/17] hw/vexpress: Set reset values for daughterboard oscillators
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (8 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 09/17] hw/arm_sysctl: Implement SYS_CFG_OSC function Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 11/17] iov: Factor out hexdumper Peter Maydell
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

Set the reset values for the VExpress daughterboard oscillators
via the new sysctl properties.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/vexpress.c |   32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index a2dc759..2e1a5d0 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -156,6 +156,8 @@ struct VEDBoardInfo {
     uint32_t proc_id;
     uint32_t num_voltage_sensors;
     const uint32_t *voltages;
+    uint32_t num_clocks;
+    const uint32_t *clocks;
     DBoardInitFn *init;
 };
 
@@ -260,6 +262,13 @@ static const uint32_t a9_voltages[] = {
     3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */
 };
 
+/* Reset values for daughterboard oscillators (in Hz) */
+static const uint32_t a9_clocks[] = {
+    45000000, /* AMBA AXI ACLK: 45MHz */
+    23750000, /* daughterboard CLCD clock: 23.75MHz */
+    66670000, /* Test chip reference clock: 66.67MHz */
+};
+
 static const VEDBoardInfo a9_daughterboard = {
     .motherboard_map = motherboard_legacy_map,
     .loader_start = 0x60000000,
@@ -267,6 +276,8 @@ static const VEDBoardInfo a9_daughterboard = {
     .proc_id = 0x0c000191,
     .num_voltage_sensors = ARRAY_SIZE(a9_voltages),
     .voltages = a9_voltages,
+    .num_clocks = ARRAY_SIZE(a9_clocks),
+    .clocks = a9_clocks,
     .init = a9_daughterboard_init,
 };
 
@@ -358,6 +369,18 @@ static const uint32_t a15_voltages[] = {
     900000, /* Vcore: 0.9V : CPU core voltage */
 };
 
+static const uint32_t a15_clocks[] = {
+    60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */
+    0, /* OSCCLK1: reserved */
+    0, /* OSCCLK2: reserved */
+    0, /* OSCCLK3: reserved */
+    40000000, /* OSCCLK4: 40MHz : external AXI master clock */
+    23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */
+    50000000, /* OSCCLK6: 50MHz : static memory controller clock */
+    60000000, /* OSCCLK7: 60MHz : SYSCLK reference */
+    40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */
+};
+
 static const VEDBoardInfo a15_daughterboard = {
     .motherboard_map = motherboard_aseries_map,
     .loader_start = 0x80000000,
@@ -365,6 +388,8 @@ static const VEDBoardInfo a15_daughterboard = {
     .proc_id = 0x14000237,
     .num_voltage_sensors = ARRAY_SIZE(a15_voltages),
     .voltages = a15_voltages,
+    .num_clocks = ARRAY_SIZE(a15_clocks),
+    .clocks = a15_clocks,
     .init = a15_daughterboard_init,
 };
 
@@ -400,6 +425,13 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
         qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]);
         g_free(propname);
     }
+    qdev_prop_set_uint32(sysctl, "len-db-clock",
+                         daughterboard->num_clocks);
+    for (i = 0; i < daughterboard->num_clocks; i++) {
+        char *propname = g_strdup_printf("db-clock[%d]", i);
+        qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]);
+        g_free(propname);
+    }
     qdev_init_nofail(sysctl);
     sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 11/17] iov: Factor out hexdumper
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (9 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 10/17] hw/vexpress: Set reset values for daughterboard oscillators Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 12/17] pl330: Initial version Peter Maydell
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Factor out the hexdumper functionality from iov for all to use. Useful for
creating verbose debug printfery that dumps packet data.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: faaac219c55ea586d3f748befaf5a2788fd271b8.1361853677.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/qemu-common.h |    6 ++++++
 util/Makefile.objs    |    1 +
 util/hexdump.c        |   37 +++++++++++++++++++++++++++++++++++++
 util/iov.c            |   36 +++++++++++-------------------------
 4 files changed, 55 insertions(+), 25 deletions(-)
 create mode 100644 util/hexdump.c

diff --git a/include/qemu-common.h b/include/qemu-common.h
index 5e13708..7754ee2 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -442,4 +442,10 @@ int64_t pow2floor(int64_t value);
 int uleb128_encode_small(uint8_t *out, uint32_t n);
 int uleb128_decode_small(const uint8_t *in, uint32_t *n);
 
+/*
+ * Hexdump a buffer to a file. An optional string prefix is added to every line
+ */
+
+void hexdump(const char *buf, FILE *fp, const char *prefix, size_t size);
+
 #endif
diff --git a/util/Makefile.objs b/util/Makefile.objs
index cad5ce8..557bda7 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -9,3 +9,4 @@ util-obj-y += error.o qemu-error.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
 util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
 util-obj-y += qemu-option.o qemu-progress.o
+util-obj-y += hexdump.o
diff --git a/util/hexdump.c b/util/hexdump.c
new file mode 100644
index 0000000..0d0efc8
--- /dev/null
+++ b/util/hexdump.c
@@ -0,0 +1,37 @@
+/*
+ * Helper to hexdump a buffer
+ *
+ * Copyright (c) 2013 Red Hat, Inc.
+ * Copyright (c) 2013 Gerd Hoffmann <kraxel@redhat.com>
+ * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
+ * Copyright (c) 2013 Xilinx, Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * 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-common.h"
+
+void hexdump(const char *buf, FILE *fp, const char *prefix, size_t size)
+{
+    unsigned int b;
+
+    for (b = 0; b < size; b++) {
+        if ((b % 16) == 0) {
+            fprintf(fp, "%s: %04x:", prefix, b);
+        }
+        if ((b % 4) == 0) {
+            fprintf(fp, " ");
+        }
+        fprintf(fp, " %02x", (unsigned char)buf[b]);
+        if ((b % 16) == 15) {
+            fprintf(fp, "\n");
+        }
+    }
+    if ((b % 16) != 0) {
+        fprintf(fp, "\n");
+    }
+}
diff --git a/util/iov.c b/util/iov.c
index fbe675d..9dae318 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -201,32 +201,18 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
 void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
                  FILE *fp, const char *prefix, size_t limit)
 {
-    unsigned int i, v, b;
-    uint8_t *c;
-
-    c = iov[0].iov_base;
-    for (i = 0, v = 0, b = 0; b < limit; i++, b++) {
-        if (i == iov[v].iov_len) {
-            i = 0; v++;
-            if (v == iov_cnt) {
-                break;
-            }
-            c = iov[v].iov_base;
-        }
-        if ((b % 16) == 0) {
-            fprintf(fp, "%s: %04x:", prefix, b);
-        }
-        if ((b % 4) == 0) {
-            fprintf(fp, " ");
-        }
-        fprintf(fp, " %02x", c[i]);
-        if ((b % 16) == 15) {
-            fprintf(fp, "\n");
-        }
-    }
-    if ((b % 16) != 0) {
-        fprintf(fp, "\n");
+    int v;
+    size_t size = 0;
+    char *buf;
+
+    for (v = 0; v < iov_cnt; v++) {
+        size += iov[v].iov_len;
     }
+    size = size > limit ? limit : size;
+    buf = g_malloc(size);
+    iov_to_buf(iov, iov_cnt, 0, buf, size);
+    hexdump(buf, fp, prefix, size);
+    g_free(buf);
 }
 
 unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 12/17] pl330: Initial version
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (10 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 11/17] iov: Factor out hexdumper Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 13/17] xilinx_zynq: added pl330 to machine model Peter Maydell
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Device model for Primecell PL330 DMA controller.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Kirill Batuzov <batuzovk@ispras.ru>
Tested-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
Reviewed-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 098aac26233d7334bed2bca4f06f539638ca6d24.1361853677.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 default-configs/arm-softmmu.mak |    1 +
 hw/Makefile.objs                |    1 +
 hw/pl330.c                      | 1654 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 1656 insertions(+)
 create mode 100644 hw/pl330.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 68b2045..ab87035 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -42,6 +42,7 @@ CONFIG_PL110=y
 CONFIG_PL181=y
 CONFIG_PL190=y
 CONFIG_PL310=y
+CONFIG_PL330=y
 CONFIG_CADENCE=y
 CONFIG_XGMAC=y
 
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index eb7eb31..11812c6 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -98,6 +98,7 @@ common-obj-$(CONFIG_PL110) += pl110.o
 common-obj-$(CONFIG_PL181) += pl181.o
 common-obj-$(CONFIG_PL190) += pl190.o
 common-obj-$(CONFIG_PL310) += arm_l2x0.o
+common-obj-$(CONFIG_PL330) += pl330.o
 common-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
 common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
 common-obj-$(CONFIG_CADENCE) += cadence_uart.o
diff --git a/hw/pl330.c b/hw/pl330.c
new file mode 100644
index 0000000..1a04773
--- /dev/null
+++ b/hw/pl330.c
@@ -0,0 +1,1654 @@
+/*
+ * ARM PrimeCell PL330 DMA Controller
+ *
+ * Copyright (c) 2009 Samsung Electronics.
+ * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ *
+ * 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; version 2 or later.
+ *
+ * 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 "sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/dma.h"
+
+#ifndef PL330_ERR_DEBUG
+#define PL330_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do {\
+    if (PL330_ERR_DEBUG >= lvl) {\
+        fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\
+    } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+#define PL330_PERIPH_NUM            32
+#define PL330_MAX_BURST_LEN         128
+#define PL330_INSN_MAXSIZE          6
+
+#define PL330_FIFO_OK               0
+#define PL330_FIFO_STALL            1
+#define PL330_FIFO_ERR              (-1)
+
+#define PL330_FAULT_UNDEF_INSTR             (1 <<  0)
+#define PL330_FAULT_OPERAND_INVALID         (1 <<  1)
+#define PL330_FAULT_DMAGO_ERR               (1 <<  4)
+#define PL330_FAULT_EVENT_ERR               (1 <<  5)
+#define PL330_FAULT_CH_PERIPH_ERR           (1 <<  6)
+#define PL330_FAULT_CH_RDWR_ERR             (1 <<  7)
+#define PL330_FAULT_ST_DATA_UNAVAILABLE     (1 << 12)
+#define PL330_FAULT_FIFOEMPTY_ERR           (1 << 13)
+#define PL330_FAULT_INSTR_FETCH_ERR         (1 << 16)
+#define PL330_FAULT_DATA_WRITE_ERR          (1 << 17)
+#define PL330_FAULT_DATA_READ_ERR           (1 << 18)
+#define PL330_FAULT_DBG_INSTR               (1 << 30)
+#define PL330_FAULT_LOCKUP_ERR              (1 << 31)
+
+#define PL330_UNTAGGED              0xff
+
+#define PL330_SINGLE                0x0
+#define PL330_BURST                 0x1
+
+#define PL330_WATCHDOG_LIMIT        1024
+
+/* IOMEM mapped registers */
+#define PL330_REG_DSR               0x000
+#define PL330_REG_DPC               0x004
+#define PL330_REG_INTEN             0x020
+#define PL330_REG_INT_EVENT_RIS     0x024
+#define PL330_REG_INTMIS            0x028
+#define PL330_REG_INTCLR            0x02C
+#define PL330_REG_FSRD              0x030
+#define PL330_REG_FSRC              0x034
+#define PL330_REG_FTRD              0x038
+#define PL330_REG_FTR_BASE          0x040
+#define PL330_REG_CSR_BASE          0x100
+#define PL330_REG_CPC_BASE          0x104
+#define PL330_REG_CHANCTRL          0x400
+#define PL330_REG_DBGSTATUS         0xD00
+#define PL330_REG_DBGCMD            0xD04
+#define PL330_REG_DBGINST0          0xD08
+#define PL330_REG_DBGINST1          0xD0C
+#define PL330_REG_CR0_BASE          0xE00
+#define PL330_REG_PERIPH_ID         0xFE0
+
+#define PL330_IOMEM_SIZE    0x1000
+
+#define CFG_BOOT_ADDR 2
+#define CFG_INS 3
+#define CFG_PNS 4
+#define CFG_CRD 5
+
+static const uint32_t pl330_id[] = {
+    0x30, 0x13, 0x24, 0x00, 0x0D, 0xF0, 0x05, 0xB1
+};
+
+/* DMA channel states as they are described in PL330 Technical Reference Manual
+ * Most of them will not be used in emulation.
+ */
+typedef enum  {
+    pl330_chan_stopped = 0,
+    pl330_chan_executing = 1,
+    pl330_chan_cache_miss = 2,
+    pl330_chan_updating_pc = 3,
+    pl330_chan_waiting_event = 4,
+    pl330_chan_at_barrier = 5,
+    pl330_chan_queue_busy = 6,
+    pl330_chan_waiting_periph = 7,
+    pl330_chan_killing = 8,
+    pl330_chan_completing = 9,
+    pl330_chan_fault_completing = 14,
+    pl330_chan_fault = 15,
+} PL330ChanState;
+
+typedef struct PL330State PL330State;
+
+typedef struct PL330Chan {
+    uint32_t src;
+    uint32_t dst;
+    uint32_t pc;
+    uint32_t control;
+    uint32_t status;
+    uint32_t lc[2];
+    uint32_t fault_type;
+    uint32_t watchdog_timer;
+
+    bool ns;
+    uint8_t request_flag;
+    uint8_t wakeup;
+    uint8_t wfp_sbp;
+
+    uint8_t state;
+    uint8_t stall;
+
+    bool is_manager;
+    PL330State *parent;
+    uint8_t tag;
+} PL330Chan;
+
+static const VMStateDescription vmstate_pl330_chan = {
+    .name = "pl330_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(src, PL330Chan),
+        VMSTATE_UINT32(dst, PL330Chan),
+        VMSTATE_UINT32(pc, PL330Chan),
+        VMSTATE_UINT32(control, PL330Chan),
+        VMSTATE_UINT32(status, PL330Chan),
+        VMSTATE_UINT32_ARRAY(lc, PL330Chan, 2),
+        VMSTATE_UINT32(fault_type, PL330Chan),
+        VMSTATE_UINT32(watchdog_timer, PL330Chan),
+        VMSTATE_BOOL(ns, PL330Chan),
+        VMSTATE_UINT8(request_flag, PL330Chan),
+        VMSTATE_UINT8(wakeup, PL330Chan),
+        VMSTATE_UINT8(wfp_sbp, PL330Chan),
+        VMSTATE_UINT8(state, PL330Chan),
+        VMSTATE_UINT8(stall, PL330Chan),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330Fifo {
+    uint8_t *buf;
+    uint8_t *tag;
+    uint32_t head;
+    uint32_t num;
+    uint32_t buf_size;
+} PL330Fifo;
+
+static const VMStateDescription vmstate_pl330_fifo = {
+    .name = "pl330_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size),
+        VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size),
+        VMSTATE_UINT32(head, PL330Fifo),
+        VMSTATE_UINT32(num, PL330Fifo),
+        VMSTATE_UINT32(buf_size, PL330Fifo),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330QueueEntry {
+    uint32_t addr;
+    uint32_t len;
+    uint8_t n;
+    bool inc;
+    bool z;
+    uint8_t tag;
+    uint8_t seqn;
+} PL330QueueEntry;
+
+static const VMStateDescription vmstate_pl330_queue_entry = {
+    .name = "pl330_queue_entry",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(addr, PL330QueueEntry),
+        VMSTATE_UINT32(len, PL330QueueEntry),
+        VMSTATE_UINT8(n, PL330QueueEntry),
+        VMSTATE_BOOL(inc, PL330QueueEntry),
+        VMSTATE_BOOL(z, PL330QueueEntry),
+        VMSTATE_UINT8(tag, PL330QueueEntry),
+        VMSTATE_UINT8(seqn, PL330QueueEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330Queue {
+    PL330State *parent;
+    PL330QueueEntry *queue;
+    uint32_t queue_size;
+} PL330Queue;
+
+static const VMStateDescription vmstate_pl330_queue = {
+    .name = "pl330_queue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1,
+                                 vmstate_pl330_queue_entry, PL330QueueEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+struct PL330State {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq_abort;
+    qemu_irq *irq;
+
+    /* Config registers. cfg[5] = CfgDn. */
+    uint32_t cfg[6];
+#define EVENT_SEC_STATE 3
+#define PERIPH_SEC_STATE 4
+    /* cfg 0 bits and pieces */
+    uint32_t num_chnls;
+    uint8_t num_periph_req;
+    uint8_t num_events;
+    uint8_t mgr_ns_at_rst;
+    /* cfg 1 bits and pieces */
+    uint8_t i_cache_len;
+    uint8_t num_i_cache_lines;
+    /* CRD bits and pieces */
+    uint8_t data_width;
+    uint8_t wr_cap;
+    uint8_t wr_q_dep;
+    uint8_t rd_cap;
+    uint8_t rd_q_dep;
+    uint16_t data_buffer_dep;
+
+    PL330Chan manager;
+    PL330Chan *chan;
+    PL330Fifo fifo;
+    PL330Queue read_queue;
+    PL330Queue write_queue;
+    uint8_t *lo_seqn;
+    uint8_t *hi_seqn;
+    QEMUTimer *timer; /* is used for restore dma. */
+
+    uint32_t inten;
+    uint32_t int_status;
+    uint32_t ev_status;
+    uint32_t dbg[2];
+    uint8_t debug_status;
+    uint8_t num_faulting;
+    uint8_t periph_busy[PL330_PERIPH_NUM];
+
+};
+
+#define TYPE_PL330 "pl330"
+#define PL330(obj) OBJECT_CHECK(PL330State, (obj), TYPE_PL330)
+
+static const VMStateDescription vmstate_pl330 = {
+    .name = "pl330",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
+        VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
+                                     vmstate_pl330_chan, PL330Chan),
+        VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls),
+        VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls),
+        VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo),
+        VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue,
+                       PL330Queue),
+        VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue,
+                       PL330Queue),
+        VMSTATE_TIMER(timer, PL330State),
+        VMSTATE_UINT32(inten, PL330State),
+        VMSTATE_UINT32(int_status, PL330State),
+        VMSTATE_UINT32(ev_status, PL330State),
+        VMSTATE_UINT32_ARRAY(dbg, PL330State, 2),
+        VMSTATE_UINT8(debug_status, PL330State),
+        VMSTATE_UINT8(num_faulting, PL330State),
+        VMSTATE_UINT8_ARRAY(periph_busy, PL330State, PL330_PERIPH_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330InsnDesc {
+    /* OPCODE of the instruction */
+    uint8_t opcode;
+    /* Mask so we can select several sibling instructions, such as
+       DMALD, DMALDS and DMALDB */
+    uint8_t opmask;
+    /* Size of instruction in bytes */
+    uint8_t size;
+    /* Interpreter */
+    void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len);
+} PL330InsnDesc;
+
+
+/* MFIFO Implementation
+ *
+ * MFIFO is implemented as a cyclic buffer of BUF_SIZE size. Tagged bytes are
+ * stored in this buffer. Data is stored in BUF field, tags - in the
+ * corresponding array elements of TAG field.
+ */
+
+/* Initialize queue. */
+
+static void pl330_fifo_init(PL330Fifo *s, uint32_t size)
+{
+    s->buf = g_malloc0(size);
+    s->tag = g_malloc0(size);
+    s->buf_size = size;
+}
+
+/* Cyclic increment */
+
+static inline int pl330_fifo_inc(PL330Fifo *s, int x)
+{
+    return (x + 1) % s->buf_size;
+}
+
+/* Number of empty bytes in MFIFO */
+
+static inline int pl330_fifo_num_free(PL330Fifo *s)
+{
+    return s->buf_size - s->num;
+}
+
+/* Push LEN bytes of data stored in BUF to MFIFO and tag it with TAG.
+ * Zero returned on success, PL330_FIFO_STALL if there is no enough free
+ * space in MFIFO to store requested amount of data. If push was unsuccessful
+ * no data is stored to MFIFO.
+ */
+
+static int pl330_fifo_push(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
+{
+    int i;
+
+    if (s->buf_size - s->num < len) {
+        return PL330_FIFO_STALL;
+    }
+    for (i = 0; i < len; i++) {
+        int push_idx = (s->head + s->num + i) % s->buf_size;
+        s->buf[push_idx] = buf[i];
+        s->tag[push_idx] = tag;
+    }
+    s->num += len;
+    return PL330_FIFO_OK;
+}
+
+/* Get LEN bytes of data from MFIFO and store it to BUF. Tag value of each
+ * byte is verified. Zero returned on success, PL330_FIFO_ERR on tag mismatch
+ * and PL330_FIFO_STALL if there is no enough data in MFIFO. If get was
+ * unsuccessful no data is removed from MFIFO.
+ */
+
+static int pl330_fifo_get(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
+{
+    int i;
+
+    if (s->num < len) {
+        return PL330_FIFO_STALL;
+    }
+    for (i = 0; i < len; i++) {
+        if (s->tag[s->head] == tag) {
+            int get_idx = (s->head + i) % s->buf_size;
+            buf[i] = s->buf[get_idx];
+        } else { /* Tag mismatch - Rollback transaction */
+            return PL330_FIFO_ERR;
+        }
+    }
+    s->head = (s->head + len) % s->buf_size;
+    s->num -= len;
+    return PL330_FIFO_OK;
+}
+
+/* Reset MFIFO. This completely erases all data in it. */
+
+static inline void pl330_fifo_reset(PL330Fifo *s)
+{
+    s->head = 0;
+    s->num = 0;
+}
+
+/* Return tag of the first byte stored in MFIFO. If MFIFO is empty
+ * PL330_UNTAGGED is returned.
+ */
+
+static inline uint8_t pl330_fifo_tag(PL330Fifo *s)
+{
+    return (!s->num) ? PL330_UNTAGGED : s->tag[s->head];
+}
+
+/* Returns non-zero if tag TAG is present in fifo or zero otherwise */
+
+static int pl330_fifo_has_tag(PL330Fifo *s, uint8_t tag)
+{
+    int i, n;
+
+    i = s->head;
+    for (n = 0; n < s->num; n++) {
+        if (s->tag[i] == tag) {
+            return 1;
+        }
+        i = pl330_fifo_inc(s, i);
+    }
+    return 0;
+}
+
+/* Remove all entry tagged with TAG from MFIFO */
+
+static void pl330_fifo_tagged_remove(PL330Fifo *s, uint8_t tag)
+{
+    int i, t, n;
+
+    t = i = s->head;
+    for (n = 0; n < s->num; n++) {
+        if (s->tag[i] != tag) {
+            s->buf[t] = s->buf[i];
+            s->tag[t] = s->tag[i];
+            t = pl330_fifo_inc(s, t);
+        } else {
+            s->num = s->num - 1;
+        }
+        i = pl330_fifo_inc(s, i);
+    }
+}
+
+/* Read-Write Queue implementation
+ *
+ * A Read-Write Queue stores up to QUEUE_SIZE instructions (loads or stores).
+ * Each instruction is described by source (for loads) or destination (for
+ * stores) address ADDR, width of data to be loaded/stored LEN, number of
+ * stores/loads to be performed N, INC bit, Z bit and TAG to identify channel
+ * this instruction belongs to. Queue does not store any information about
+ * nature of the instruction: is it load or store. PL330 has different queues
+ * for loads and stores so this is already known at the top level where it
+ * matters.
+ *
+ * Queue works as FIFO for instructions with equivalent tags, but can issue
+ * instructions with different tags in arbitrary order. SEQN field attached to
+ * each instruction helps to achieve this. For each TAG queue contains
+ * instructions with consecutive SEQN values ranging from LO_SEQN[TAG] to
+ * HI_SEQN[TAG]-1 inclusive. SEQN is 8-bit unsigned integer, so SEQN=255 is
+ * followed by SEQN=0.
+ *
+ * Z bit indicates that zeroes should be stored. No MFIFO fetches are performed
+ * in this case.
+ */
+
+static void pl330_queue_reset(PL330Queue *s)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        s->queue[i].tag = PL330_UNTAGGED;
+    }
+}
+
+/* Initialize queue */
+static void pl330_queue_init(PL330Queue *s, int size, PL330State *parent)
+{
+    s->parent = parent;
+    s->queue = g_new0(PL330QueueEntry, size);
+    s->queue_size = size;
+}
+
+/* Returns pointer to an empty slot or NULL if queue is full */
+static PL330QueueEntry *pl330_queue_find_empty(PL330Queue *s)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        if (s->queue[i].tag == PL330_UNTAGGED) {
+            return &s->queue[i];
+        }
+    }
+    return NULL;
+}
+
+/* Put instruction in queue.
+ * Return value:
+ * - zero - OK
+ * - non-zero - queue is full
+ */
+
+static int pl330_queue_put_insn(PL330Queue *s, uint32_t addr,
+                                int len, int n, bool inc, bool z, uint8_t tag)
+{
+    PL330QueueEntry *entry = pl330_queue_find_empty(s);
+
+    if (!entry) {
+        return 1;
+    }
+    entry->tag = tag;
+    entry->addr = addr;
+    entry->len = len;
+    entry->n = n;
+    entry->z = z;
+    entry->inc = inc;
+    entry->seqn = s->parent->hi_seqn[tag];
+    s->parent->hi_seqn[tag]++;
+    return 0;
+}
+
+/* Returns a pointer to queue slot containing instruction which satisfies
+ *  following conditions:
+ *   - it has valid tag value (not PL330_UNTAGGED)
+ *   - if enforce_seq is set it has to be issuable without violating queue
+ *     logic (see above)
+ *   - if TAG argument is not PL330_UNTAGGED this instruction has tag value
+ *     equivalent to the argument TAG value.
+ *  If such instruction cannot be found NULL is returned.
+ */
+
+static PL330QueueEntry *pl330_queue_find_insn(PL330Queue *s, uint8_t tag,
+                                              bool enforce_seq)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        if (s->queue[i].tag != PL330_UNTAGGED) {
+            if ((!enforce_seq ||
+                    s->queue[i].seqn == s->parent->lo_seqn[s->queue[i].tag]) &&
+                    (s->queue[i].tag == tag || tag == PL330_UNTAGGED ||
+                    s->queue[i].z)) {
+                return &s->queue[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+/* Removes instruction from queue. */
+
+static inline void pl330_queue_remove_insn(PL330Queue *s, PL330QueueEntry *e)
+{
+    s->parent->lo_seqn[e->tag]++;
+    e->tag = PL330_UNTAGGED;
+}
+
+/* Removes all instructions tagged with TAG from queue. */
+
+static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        if (s->queue[i].tag == tag) {
+            s->queue[i].tag = PL330_UNTAGGED;
+        }
+    }
+}
+
+/* DMA instruction execution engine */
+
+/* Moves DMA channel to the FAULT state and updates it's status. */
+
+static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
+{
+    DB_PRINT("ch: %p, flags: %x\n", ch, flags);
+    ch->fault_type |= flags;
+    if (ch->state == pl330_chan_fault) {
+        return;
+    }
+    ch->state = pl330_chan_fault;
+    ch->parent->num_faulting++;
+    if (ch->parent->num_faulting == 1) {
+        DB_PRINT("abort interrupt raised\n");
+        qemu_irq_raise(ch->parent->irq_abort);
+    }
+}
+
+/*
+ * For information about instructions see PL330 Technical Reference Manual.
+ *
+ * Arguments:
+ *   CH - channel executing the instruction
+ *   OPCODE - opcode
+ *   ARGS - array of 8-bit arguments
+ *   LEN - number of elements in ARGS array
+ */
+
+static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]);
+    uint8_t ra = (opcode >> 1) & 1;
+
+    if (ch->is_manager) {
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
+        return;
+    }
+    if (ra) {
+        ch->dst += im;
+    } else {
+        ch->src += im;
+    }
+}
+
+static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    PL330State *s = ch->parent;
+
+    if (ch->state == pl330_chan_executing && !ch->is_manager) {
+        /* Wait for all transfers to complete */
+        if (pl330_fifo_has_tag(&s->fifo, ch->tag) ||
+            pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL ||
+            pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) {
+
+            ch->stall = 1;
+            return;
+        }
+    }
+    DB_PRINT("DMA ending!\n");
+    pl330_fifo_tagged_remove(&s->fifo, ch->tag);
+    pl330_queue_remove_tagged(&s->read_queue, ch->tag);
+    pl330_queue_remove_tagged(&s->write_queue, ch->tag);
+    ch->state = pl330_chan_stopped;
+}
+
+static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode,
+                                            uint8_t *args, int len)
+{
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    /* Do nothing */
+}
+
+static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t chan_id;
+    uint8_t ns;
+    uint32_t pc;
+    PL330Chan *s;
+
+    DB_PRINT("\n");
+
+    if (!ch->is_manager) {
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
+        return;
+    }
+    ns = !!(opcode & 2);
+    chan_id = args[0] & 7;
+    if ((args[0] >> 3)) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (chan_id >= ch->parent->num_chnls) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    pc = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
+         (((uint32_t)args[2]) << 8)  | (((uint32_t)args[1]));
+    if (ch->parent->chan[chan_id].state != pl330_chan_stopped) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !ns) {
+        pl330_fault(ch, PL330_FAULT_DMAGO_ERR);
+        return;
+    }
+    s = &ch->parent->chan[chan_id];
+    s->ns = ns;
+    s->pc = pc;
+    s->state = pl330_chan_executing;
+}
+
+static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t bs = opcode & 3;
+    uint32_t size, num;
+    bool inc;
+
+    if (bs == 2) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
+        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
+        /* Perform NOP */
+        return;
+    }
+    if (bs == 1 && ch->request_flag == PL330_SINGLE) {
+        num = 1;
+    } else {
+        num = ((ch->control >> 4) & 0xf) + 1;
+    }
+    size = (uint32_t)1 << ((ch->control >> 1) & 0x7);
+    inc = !!(ch->control & 1);
+    ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
+                                    size, num, inc, 0, ch->tag);
+    if (!ch->stall) {
+        DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
+                 ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
+        ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
+    }
+}
+
+static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    pl330_dmald(ch, opcode, args, len);
+}
+
+static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t lc = (opcode & 2) >> 1;
+
+    ch->lc[lc] = args[0];
+}
+
+static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    if (ch->state == pl330_chan_fault ||
+        ch->state == pl330_chan_fault_completing) {
+        /* This is the only way for a channel to leave the faulting state */
+        ch->fault_type = 0;
+        ch->parent->num_faulting--;
+        if (ch->parent->num_faulting == 0) {
+            DB_PRINT("abort interrupt lowered\n");
+            qemu_irq_lower(ch->parent->irq_abort);
+        }
+    }
+    ch->state = pl330_chan_killing;
+    pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag);
+    pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag);
+    pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag);
+    ch->state = pl330_chan_stopped;
+}
+
+static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
+                                    uint8_t *args, int len)
+{
+    uint8_t nf = (opcode & 0x10) >> 4;
+    uint8_t bs = opcode & 3;
+    uint8_t lc = (opcode & 4) >> 2;
+
+    if (bs == 2) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
+        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
+        /* Perform NOP */
+        return;
+    }
+    if (!nf || ch->lc[lc]) {
+        if (nf) {
+            ch->lc[lc]--;
+        }
+        DB_PRINT("loop reiteration\n");
+        ch->pc -= args[0];
+        ch->pc -= len + 1;
+        /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */
+    } else {
+        DB_PRINT("loop fallthrough\n");
+    }
+}
+
+
+static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t rd = args[0] & 7;
+    uint32_t im;
+
+    if ((args[0] >> 3)) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    im = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
+         (((uint32_t)args[2]) << 8)  | (((uint32_t)args[1]));
+    switch (rd) {
+    case 0:
+        ch->src = im;
+        break;
+    case 1:
+        ch->control = im;
+        break;
+    case 2:
+        ch->dst = im;
+        break;
+    default:
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+}
+
+static void pl330_dmanop(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    /* NOP is NOP. */
+}
+
+static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+   if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) {
+        ch->state = pl330_chan_at_barrier;
+        ch->stall = 1;
+        return;
+    } else {
+        ch->state = pl330_chan_executing;
+    }
+}
+
+static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t ev_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    ev_id = (args[0] >> 3) & 0x1f;
+    if (ev_id >= ch->parent->num_events) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
+        pl330_fault(ch, PL330_FAULT_EVENT_ERR);
+        return;
+    }
+    if (ch->parent->inten & (1 << ev_id)) {
+        ch->parent->int_status |= (1 << ev_id);
+        DB_PRINT("event interrupt raised %d\n", ev_id);
+        qemu_irq_raise(ch->parent->irq[ev_id]);
+    } else {
+        ch->parent->ev_status |= (1 << ev_id);
+    }
+}
+
+static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t bs = opcode & 3;
+    uint32_t size, num;
+    bool inc;
+
+    if (bs == 2) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
+        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
+        /* Perform NOP */
+        return;
+    }
+    num = ((ch->control >> 18) & 0xf) + 1;
+    size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
+    inc = !!((ch->control >> 14) & 1);
+    ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
+                                    size, num, inc, 0, ch->tag);
+    if (!ch->stall) {
+        DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
+                 ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
+        ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
+    }
+}
+
+static void pl330_dmastp(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    pl330_dmast(ch, opcode, args, len);
+}
+
+static void pl330_dmastz(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint32_t size, num;
+    bool inc;
+
+    num = ((ch->control >> 18) & 0xf) + 1;
+    size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
+    inc = !!((ch->control >> 14) & 1);
+    ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
+                                    size, num, inc, 1, ch->tag);
+    if (inc) {
+        ch->dst += size * num;
+    }
+}
+
+static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint8_t ev_id;
+    int i;
+
+    if (args[0] & 5) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    ev_id = (args[0] >> 3) & 0x1f;
+    if (ev_id >= ch->parent->num_events) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
+        pl330_fault(ch, PL330_FAULT_EVENT_ERR);
+        return;
+    }
+    ch->wakeup = ev_id;
+    ch->state = pl330_chan_waiting_event;
+    if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) {
+        ch->state = pl330_chan_executing;
+        /* If anyone else is currently waiting on the same event, let them
+         * clear the ev_status so they pick up event as well
+         */
+        for (i = 0; i < ch->parent->num_chnls; ++i) {
+            PL330Chan *peer = &ch->parent->chan[i];
+            if (peer->state == pl330_chan_waiting_event &&
+                    peer->wakeup == ev_id) {
+                return;
+            }
+        }
+        ch->parent->ev_status &= ~(1 << ev_id);
+    } else {
+        ch->stall = 1;
+    }
+}
+
+static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint8_t bs = opcode & 3;
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    switch (bs) {
+    case 0: /* S */
+        ch->request_flag = PL330_SINGLE;
+        ch->wfp_sbp = 0;
+        break;
+    case 1: /* P */
+        ch->request_flag = PL330_BURST;
+        ch->wfp_sbp = 2;
+        break;
+    case 2: /* B */
+        ch->request_flag = PL330_BURST;
+        ch->wfp_sbp = 1;
+        break;
+    default:
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+
+    if (ch->parent->periph_busy[periph_id]) {
+        ch->state = pl330_chan_waiting_periph;
+        ch->stall = 1;
+    } else if (ch->state == pl330_chan_waiting_periph) {
+        ch->state = pl330_chan_executing;
+    }
+}
+
+static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) {
+        ch->state = pl330_chan_at_barrier;
+        ch->stall = 1;
+        return;
+    } else {
+        ch->state = pl330_chan_executing;
+    }
+}
+
+/* NULL terminated array of the instruction descriptions. */
+static const PL330InsnDesc insn_desc[] = {
+    { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
+    { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
+    { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
+    { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
+    { .opcode = 0x04, .opmask = 0xFC, .size = 1, .exec = pl330_dmald, },
+    { .opcode = 0x25, .opmask = 0xFD, .size = 2, .exec = pl330_dmaldp, },
+    { .opcode = 0x20, .opmask = 0xFD, .size = 2, .exec = pl330_dmalp, },
+    /* dmastp  must be before dmalpend in this list, because their maps
+     * are overlapping
+     */
+    { .opcode = 0x29, .opmask = 0xFD, .size = 2, .exec = pl330_dmastp, },
+    { .opcode = 0x28, .opmask = 0xE8, .size = 2, .exec = pl330_dmalpend, },
+    { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
+    { .opcode = 0xBC, .opmask = 0xFF, .size = 6, .exec = pl330_dmamov, },
+    { .opcode = 0x18, .opmask = 0xFF, .size = 1, .exec = pl330_dmanop, },
+    { .opcode = 0x12, .opmask = 0xFF, .size = 1, .exec = pl330_dmarmb, },
+    { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
+    { .opcode = 0x08, .opmask = 0xFC, .size = 1, .exec = pl330_dmast, },
+    { .opcode = 0x0C, .opmask = 0xFF, .size = 1, .exec = pl330_dmastz, },
+    { .opcode = 0x36, .opmask = 0xFF, .size = 2, .exec = pl330_dmawfe, },
+    { .opcode = 0x30, .opmask = 0xFC, .size = 2, .exec = pl330_dmawfp, },
+    { .opcode = 0x13, .opmask = 0xFF, .size = 1, .exec = pl330_dmawmb, },
+    { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
+};
+
+/* Instructions which can be issued via debug registers. */
+static const PL330InsnDesc debug_insn_desc[] = {
+    { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
+    { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
+    { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
+    { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
+};
+
+static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch)
+{
+    uint8_t opcode;
+    int i;
+
+    dma_memory_read(&dma_context_memory, ch->pc, &opcode, 1);
+    for (i = 0; insn_desc[i].size; i++) {
+        if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) {
+            return &insn_desc[i];
+        }
+    }
+    return NULL;
+}
+
+static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn)
+{
+    uint8_t buf[PL330_INSN_MAXSIZE];
+
+    assert(insn->size <= PL330_INSN_MAXSIZE);
+    dma_memory_read(&dma_context_memory, ch->pc, buf, insn->size);
+    insn->exec(ch, buf[0], &buf[1], insn->size - 1);
+}
+
+static inline void pl330_update_pc(PL330Chan *ch,
+                                   const PL330InsnDesc *insn)
+{
+    ch->pc += insn->size;
+}
+
+/* Try to execute current instruction in channel CH. Number of executed
+   instructions is returned (0 or 1). */
+static int pl330_chan_exec(PL330Chan *ch)
+{
+    const PL330InsnDesc *insn;
+
+    if (ch->state != pl330_chan_executing &&
+            ch->state != pl330_chan_waiting_periph &&
+            ch->state != pl330_chan_at_barrier &&
+            ch->state != pl330_chan_waiting_event) {
+        DB_PRINT("%d\n", ch->state);
+        return 0;
+    }
+    ch->stall = 0;
+    insn = pl330_fetch_insn(ch);
+    if (!insn) {
+        DB_PRINT("pl330 undefined instruction\n");
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
+        return 0;
+    }
+    pl330_exec_insn(ch, insn);
+    if (!ch->stall) {
+        pl330_update_pc(ch, insn);
+        ch->watchdog_timer = 0;
+        return 1;
+    /* WDT only active in exec state */
+    } else if (ch->state == pl330_chan_executing) {
+        ch->watchdog_timer++;
+        if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) {
+            pl330_fault(ch, PL330_FAULT_LOCKUP_ERR);
+        }
+    }
+    return 0;
+}
+
+/* Try to execute 1 instruction in each channel, one instruction from read
+   queue and one instruction from write queue. Number of successfully executed
+   instructions is returned. */
+static int pl330_exec_cycle(PL330Chan *channel)
+{
+    PL330State *s = channel->parent;
+    PL330QueueEntry *q;
+    int i;
+    int num_exec = 0;
+    int fifo_res = 0;
+    uint8_t buf[PL330_MAX_BURST_LEN];
+
+    /* Execute one instruction in each channel */
+    num_exec += pl330_chan_exec(channel);
+
+    /* Execute one instruction from read queue */
+    q = pl330_queue_find_insn(&s->read_queue, PL330_UNTAGGED, true);
+    if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) {
+        int len = q->len - (q->addr & (q->len - 1));
+
+        dma_memory_read(&dma_context_memory, q->addr, buf, len);
+        if (PL330_ERR_DEBUG > 1) {
+            DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
+                      q->addr, len);
+            hexdump((char *)buf, stderr, "", len);
+        }
+        fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag);
+        if (fifo_res == PL330_FIFO_OK) {
+            if (q->inc) {
+                q->addr += len;
+            }
+            q->n--;
+            if (!q->n) {
+                pl330_queue_remove_insn(&s->read_queue, q);
+            }
+            num_exec++;
+        }
+    }
+
+    /* Execute one instruction from write queue. */
+    q = pl330_queue_find_insn(&s->write_queue, pl330_fifo_tag(&s->fifo), true);
+    if (q != NULL) {
+        int len = q->len - (q->addr & (q->len - 1));
+
+        if (q->z) {
+            for (i = 0; i < len; i++) {
+                buf[i] = 0;
+            }
+        } else {
+            fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag);
+        }
+        if (fifo_res == PL330_FIFO_OK || q->z) {
+            dma_memory_write(&dma_context_memory, q->addr, buf, len);
+            if (PL330_ERR_DEBUG > 1) {
+                DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
+                         q->addr, len);
+                hexdump((char *)buf, stderr, "", len);
+            }
+            if (q->inc) {
+                q->addr += len;
+            }
+            num_exec++;
+        } else if (fifo_res == PL330_FIFO_STALL) {
+            pl330_fault(&channel->parent->chan[q->tag],
+                                PL330_FAULT_FIFOEMPTY_ERR);
+        }
+        q->n--;
+        if (!q->n) {
+            pl330_queue_remove_insn(&s->write_queue, q);
+        }
+    }
+
+    return num_exec;
+}
+
+static int pl330_exec_channel(PL330Chan *channel)
+{
+    int insr_exec = 0;
+
+    /* TODO: Is it all right to execute everything or should we do per-cycle
+       simulation? */
+    while (pl330_exec_cycle(channel)) {
+        insr_exec++;
+    }
+
+    /* Detect deadlock */
+    if (channel->state == pl330_chan_executing) {
+        pl330_fault(channel, PL330_FAULT_LOCKUP_ERR);
+    }
+    /* Situation when one of the queues has deadlocked but all channels
+     * have finished their programs should be impossible.
+     */
+
+    return insr_exec;
+}
+
+static inline void pl330_exec(PL330State *s)
+{
+    DB_PRINT("\n");
+    int i, insr_exec;
+    do {
+        insr_exec = pl330_exec_channel(&s->manager);
+
+        for (i = 0; i < s->num_chnls; i++) {
+            insr_exec += pl330_exec_channel(&s->chan[i]);
+        }
+    } while (insr_exec);
+}
+
+static void pl330_exec_cycle_timer(void *opaque)
+{
+    PL330State *s = (PL330State *)opaque;
+    pl330_exec(s);
+}
+
+/* Stop or restore dma operations */
+
+static void pl330_dma_stop_irq(void *opaque, int irq, int level)
+{
+    PL330State *s = (PL330State *)opaque;
+
+    if (s->periph_busy[irq] != level) {
+        s->periph_busy[irq] = level;
+        qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock));
+    }
+}
+
+static void pl330_debug_exec(PL330State *s)
+{
+    uint8_t args[5];
+    uint8_t opcode;
+    uint8_t chan_id;
+    int i;
+    PL330Chan *ch;
+    const PL330InsnDesc *insn;
+
+    s->debug_status = 1;
+    chan_id = (s->dbg[0] >>  8) & 0x07;
+    opcode  = (s->dbg[0] >> 16) & 0xff;
+    args[0] = (s->dbg[0] >> 24) & 0xff;
+    args[1] = (s->dbg[1] >>  0) & 0xff;
+    args[2] = (s->dbg[1] >>  8) & 0xff;
+    args[3] = (s->dbg[1] >> 16) & 0xff;
+    args[4] = (s->dbg[1] >> 24) & 0xff;
+    DB_PRINT("chan id: %d\n", chan_id);
+    if (s->dbg[0] & 1) {
+        ch = &s->chan[chan_id];
+    } else {
+        ch = &s->manager;
+    }
+    insn = NULL;
+    for (i = 0; debug_insn_desc[i].size; i++) {
+        if ((opcode & debug_insn_desc[i].opmask) == debug_insn_desc[i].opcode) {
+            insn = &debug_insn_desc[i];
+        }
+    }
+    if (!insn) {
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR);
+        return ;
+    }
+    ch->stall = 0;
+    insn->exec(ch, opcode, args, insn->size - 1);
+    if (ch->fault_type) {
+        ch->fault_type |= PL330_FAULT_DBG_INSTR;
+    }
+    if (ch->stall) {
+        qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not "
+                      "implemented\n");
+    }
+    s->debug_status = 0;
+}
+
+/* IOMEM mapped registers */
+
+static void pl330_iomem_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    PL330State *s = (PL330State *) opaque;
+    uint32_t i;
+
+    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
+
+    switch (offset) {
+    case PL330_REG_INTEN:
+        s->inten = value;
+        break;
+    case PL330_REG_INTCLR:
+        for (i = 0; i < s->num_events; i++) {
+            if (s->int_status & s->inten & value & (1 << i)) {
+                DB_PRINT("event interrupt lowered %d\n", i);
+                qemu_irq_lower(s->irq[i]);
+            }
+        }
+        s->ev_status &= ~(value & s->inten);
+        s->int_status &= ~(value & s->inten);
+        break;
+    case PL330_REG_DBGCMD:
+        if ((value & 3) == 0) {
+            pl330_debug_exec(s);
+            pl330_exec(s);
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u "
+                          "for offset " TARGET_FMT_plx "\n", (unsigned)value,
+                          offset);
+        }
+        break;
+    case PL330_REG_DBGINST0:
+        DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value);
+        s->dbg[0] = value;
+        break;
+    case PL330_REG_DBGINST1:
+        DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value);
+        s->dbg[1] = value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx
+                      "\n", offset);
+        break;
+    }
+}
+
+static inline uint32_t pl330_iomem_read_imp(void *opaque,
+        hwaddr offset)
+{
+    PL330State *s = (PL330State *)opaque;
+    int chan_id;
+    int i;
+    uint32_t res;
+
+    if (offset >= PL330_REG_PERIPH_ID && offset < PL330_REG_PERIPH_ID + 32) {
+        return pl330_id[(offset - PL330_REG_PERIPH_ID) >> 2];
+    }
+    if (offset >= PL330_REG_CR0_BASE && offset < PL330_REG_CR0_BASE + 24) {
+        return s->cfg[(offset - PL330_REG_CR0_BASE) >> 2];
+    }
+    if (offset >= PL330_REG_CHANCTRL && offset < PL330_REG_DBGSTATUS) {
+        offset -= PL330_REG_CHANCTRL;
+        chan_id = offset >> 5;
+        if (chan_id >= s->num_chnls) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+        switch (offset & 0x1f) {
+        case 0x00:
+            return s->chan[chan_id].src;
+        case 0x04:
+            return s->chan[chan_id].dst;
+        case 0x08:
+            return s->chan[chan_id].control;
+        case 0x0C:
+            return s->chan[chan_id].lc[0];
+        case 0x10:
+            return s->chan[chan_id].lc[1];
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+    }
+    if (offset >= PL330_REG_CSR_BASE && offset < 0x400) {
+        offset -= PL330_REG_CSR_BASE;
+        chan_id = offset >> 3;
+        if (chan_id >= s->num_chnls) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+        switch ((offset >> 2) & 1) {
+        case 0x0:
+            res = (s->chan[chan_id].ns << 21) |
+                    (s->chan[chan_id].wakeup << 4) |
+                    (s->chan[chan_id].state) |
+                    (s->chan[chan_id].wfp_sbp << 14);
+            return res;
+        case 0x1:
+            return s->chan[chan_id].pc;
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: read error\n");
+            return 0;
+        }
+    }
+    if (offset >= PL330_REG_FTR_BASE && offset < 0x100) {
+        offset -= PL330_REG_FTR_BASE;
+        chan_id = offset >> 2;
+        if (chan_id >= s->num_chnls) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+        return s->chan[chan_id].fault_type;
+    }
+    switch (offset) {
+    case PL330_REG_DSR:
+        return (s->manager.ns << 9) | (s->manager.wakeup << 4) |
+            (s->manager.state & 0xf);
+    case PL330_REG_DPC:
+        return s->manager.pc;
+    case PL330_REG_INTEN:
+        return s->inten;
+    case PL330_REG_INT_EVENT_RIS:
+        return s->ev_status;
+    case PL330_REG_INTMIS:
+        return s->int_status;
+    case PL330_REG_INTCLR:
+        /* Documentation says that we can't read this register
+         * but linux kernel does it
+         */
+        return 0;
+    case PL330_REG_FSRD:
+        return s->manager.state ? 1 : 0;
+    case PL330_REG_FSRC:
+        res = 0;
+        for (i = 0; i < s->num_chnls; i++) {
+            if (s->chan[i].state == pl330_chan_fault ||
+                s->chan[i].state == pl330_chan_fault_completing) {
+                res |= 1 << i;
+            }
+        }
+        return res;
+    case PL330_REG_FTRD:
+        return s->manager.fault_type;
+    case PL330_REG_DBGSTATUS:
+        return s->debug_status;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                      TARGET_FMT_plx "\n", offset);
+    }
+    return 0;
+}
+
+static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    int ret = pl330_iomem_read_imp(opaque, offset);
+    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret);
+    return ret;
+}
+
+static const MemoryRegionOps pl330_ops = {
+    .read = pl330_iomem_read,
+    .write = pl330_iomem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+/* Controller logic and initialization */
+
+static void pl330_chan_reset(PL330Chan *ch)
+{
+    ch->src = 0;
+    ch->dst = 0;
+    ch->pc = 0;
+    ch->state = pl330_chan_stopped;
+    ch->watchdog_timer = 0;
+    ch->stall = 0;
+    ch->control = 0;
+    ch->status = 0;
+    ch->fault_type = 0;
+}
+
+static void pl330_reset(DeviceState *d)
+{
+    int i;
+    PL330State *s = PL330(d);
+
+    s->inten = 0;
+    s->int_status = 0;
+    s->ev_status = 0;
+    s->debug_status = 0;
+    s->num_faulting = 0;
+    s->manager.ns = s->mgr_ns_at_rst;
+    pl330_fifo_reset(&s->fifo);
+    pl330_queue_reset(&s->read_queue);
+    pl330_queue_reset(&s->write_queue);
+
+    for (i = 0; i < s->num_chnls; i++) {
+        pl330_chan_reset(&s->chan[i]);
+    }
+    for (i = 0; i < s->num_periph_req; i++) {
+        s->periph_busy[i] = 0;
+    }
+
+    qemu_del_timer(s->timer);
+}
+
+static void pl330_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    PL330State *s = PL330(dev);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_abort);
+    memory_region_init_io(&s->iomem, &pl330_ops, s, "dma", PL330_IOMEM_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+    s->timer = qemu_new_timer_ns(vm_clock, pl330_exec_cycle_timer, s);
+
+    s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) |
+                (s->num_periph_req > 0 ? 1 : 0) |
+                ((s->num_chnls - 1) & 0x7) << 4 |
+                ((s->num_periph_req - 1) & 0x1f) << 12 |
+                ((s->num_events - 1) & 0x1f) << 17;
+
+    switch (s->i_cache_len) {
+    case (4):
+        s->cfg[1] |= 2;
+        break;
+    case (8):
+        s->cfg[1] |= 3;
+        break;
+    case (16):
+        s->cfg[1] |= 4;
+        break;
+    case (32):
+        s->cfg[1] |= 5;
+        break;
+    default:
+        error_setg(errp, "Bad value for i-cache_len property: %d\n",
+                   s->i_cache_len);
+        return;
+    }
+    s->cfg[1] |= ((s->num_i_cache_lines - 1) & 0xf) << 4;
+
+    s->chan = g_new0(PL330Chan, s->num_chnls);
+    s->hi_seqn = g_new0(uint8_t, s->num_chnls);
+    s->lo_seqn = g_new0(uint8_t, s->num_chnls);
+    for (i = 0; i < s->num_chnls; i++) {
+        s->chan[i].parent = s;
+        s->chan[i].tag = (uint8_t)i;
+    }
+    s->manager.parent = s;
+    s->manager.tag = s->num_chnls;
+    s->manager.is_manager = true;
+
+    s->irq = g_new0(qemu_irq, s->num_events);
+    for (i = 0; i < s->num_events; i++) {
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
+    }
+
+    qdev_init_gpio_in(dev, pl330_dma_stop_irq, PL330_PERIPH_NUM);
+
+    switch (s->data_width) {
+    case (32):
+        s->cfg[CFG_CRD] |= 0x2;
+        break;
+    case (64):
+        s->cfg[CFG_CRD] |= 0x3;
+        break;
+    case (128):
+        s->cfg[CFG_CRD] |= 0x4;
+        break;
+    default:
+        error_setg(errp, "Bad value for data_width property: %d\n",
+                   s->data_width);
+        return;
+    }
+
+    s->cfg[CFG_CRD] |= ((s->wr_cap - 1) & 0x7) << 4 |
+                    ((s->wr_q_dep - 1) & 0xf) << 8 |
+                    ((s->rd_cap - 1) & 0x7) << 12 |
+                    ((s->rd_q_dep - 1) & 0xf) << 16 |
+                    ((s->data_buffer_dep - 1) & 0x1ff) << 20;
+
+    pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
+    pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
+    pl330_fifo_init(&s->fifo, s->data_buffer_dep);
+}
+
+static Property pl330_properties[] = {
+    /* CR0 */
+    DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8),
+    DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4),
+    DEFINE_PROP_UINT8("num_events", PL330State, num_events, 16),
+    DEFINE_PROP_UINT8("mgr_ns_at_rst", PL330State, mgr_ns_at_rst, 0),
+    /* CR1 */
+    DEFINE_PROP_UINT8("i-cache_len", PL330State, i_cache_len, 4),
+    DEFINE_PROP_UINT8("num_i-cache_lines", PL330State, num_i_cache_lines, 8),
+    /* CR2-4 */
+    DEFINE_PROP_UINT32("boot_addr", PL330State, cfg[CFG_BOOT_ADDR], 0),
+    DEFINE_PROP_UINT32("INS", PL330State, cfg[CFG_INS], 0),
+    DEFINE_PROP_UINT32("PNS", PL330State, cfg[CFG_PNS], 0),
+    /* CRD */
+    DEFINE_PROP_UINT8("data_width", PL330State, data_width, 64),
+    DEFINE_PROP_UINT8("wr_cap", PL330State, wr_cap, 8),
+    DEFINE_PROP_UINT8("wr_q_dep", PL330State, wr_q_dep, 16),
+    DEFINE_PROP_UINT8("rd_cap", PL330State, rd_cap, 8),
+    DEFINE_PROP_UINT8("rd_q_dep", PL330State, rd_q_dep, 16),
+    DEFINE_PROP_UINT16("data_buffer_dep", PL330State, data_buffer_dep, 256),
+
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pl330_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = pl330_realize;
+    dc->reset = pl330_reset;
+    dc->props = pl330_properties;
+    dc->vmsd = &vmstate_pl330;
+}
+
+static const TypeInfo pl330_type_info = {
+    .name           = TYPE_PL330,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(PL330State),
+    .class_init      = pl330_class_init,
+};
+
+static void pl330_register_types(void)
+{
+    type_register_static(&pl330_type_info);
+}
+
+type_init(pl330_register_types)
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 13/17] xilinx_zynq: added pl330 to machine model
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (11 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 12/17] pl330: Initial version Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 14/17] xilinx_spips: Set unused IRQs to NULL Peter Maydell
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 5bc295bd2aa50dfe573f428574dbd7d8add7b3f8.1361853677.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/xilinx_zynq.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index f78c47e..6f36286 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -35,6 +35,10 @@
 
 #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
 
+static const int dma_irqs[8] = {
+    46, 47, 48, 49, 72, 73, 74, 75
+};
+
 static struct arm_boot_info zynq_binfo = {};
 
 static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
@@ -196,6 +200,26 @@ static void zynq_init(QEMUMachineInitArgs *args)
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
 
+    dev = qdev_create(NULL, "pl330");
+    qdev_prop_set_uint8(dev, "num_chnls",  8);
+    qdev_prop_set_uint8(dev, "num_periph_req",  4);
+    qdev_prop_set_uint8(dev, "num_events",  16);
+
+    qdev_prop_set_uint8(dev, "data_width",  64);
+    qdev_prop_set_uint8(dev, "wr_cap",  8);
+    qdev_prop_set_uint8(dev, "wr_q_dep",  16);
+    qdev_prop_set_uint8(dev, "rd_cap",  8);
+    qdev_prop_set_uint8(dev, "rd_q_dep",  16);
+    qdev_prop_set_uint16(dev, "data_buffer_dep",  256);
+
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0xF8003000);
+    sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */
+    for (n = 0; n < 8; ++n) { /* event irqs */
+        sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
+    }
+
     zynq_binfo.ram_size = ram_size;
     zynq_binfo.kernel_filename = kernel_filename;
     zynq_binfo.kernel_cmdline = kernel_cmdline;
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 14/17] xilinx_spips: Set unused IRQs to NULL
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (12 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 13/17] xilinx_zynq: added pl330 to machine model Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 15/17] xilinx_spips: Fix bus setup conditional check Peter Maydell
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Unused CS lines should init to 0 to avoid segfaulting when accessing an
unattached QSPI controller.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: c1e45198032106e69e8fe9339fc2e6348d524fcd.1362373359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/xilinx_spips.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
index 6c21b96..853f4e0 100644
--- a/hw/xilinx_spips.c
+++ b/hw/xilinx_spips.c
@@ -497,7 +497,7 @@ static int xilinx_spips_init(SysBusDevice *dev)
         s->spi[i] = ssi_create_bus(&dev->qdev, bus_name);
     }
 
-    s->cs_lines = g_new(qemu_irq, s->num_cs * s->num_busses);
+    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
     sysbus_init_irq(dev, &s->irq);
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 15/17] xilinx_spips: Fix bus setup conditional check
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (13 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 14/17] xilinx_spips: Set unused IRQs to NULL Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 16/17] xilinx_spips: Add missing dual-bus snoop commands Peter Maydell
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Nathan Rossi <nathan.rossi@xilinx.com>

The R_LQPSI_CFG register has the LQSPI_CFG_SEP_BUS and LQSPI_CFG_TWO_MEM bits.

Signed-off-by: Nathan Rossi <nathan.rossi@xilinx.com>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: d76c8e364c80a42352ae4f0661aff2cd17ad32a4.1362373359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/xilinx_spips.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
index 853f4e0..efa1449 100644
--- a/hw/xilinx_spips.c
+++ b/hw/xilinx_spips.c
@@ -143,8 +143,8 @@ typedef struct {
 
 static inline int num_effective_busses(XilinxSPIPS *s)
 {
-    return (s->regs[R_LQSPI_STS] & LQSPI_CFG_SEP_BUS &&
-            s->regs[R_LQSPI_STS] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
+    return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
+            s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
 }
 
 static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 16/17] xilinx_spips: Add missing dual-bus snoop commands
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (14 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 15/17] xilinx_spips: Fix bus setup conditional check Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 17/17] xilinx_spips: QOM styling fixes Peter Maydell
  2013-03-17 20:48 ` [Qemu-devel] [PULL 00/17] arm-devs queue Blue Swirl
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Nathan Rossi <nathan.rossi@xilinx.com>

Added additional commands to the switch to check for when snooping commands in
dual bus mode setups. Cleaned up code to use an enum.

Signed-off-by: Nathan Rossi <nathan.rossi@xilinx.com>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 848c116c711dab0af10729a487968384aadd9faf.1362373359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/xilinx_spips.c |   29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
index efa1449..3183f7a 100644
--- a/hw/xilinx_spips.c
+++ b/hw/xilinx_spips.c
@@ -115,6 +115,19 @@
 #define SNOOP_NONE 0xFE
 #define SNOOP_STRIPING 0
 
+typedef enum {
+    READ = 0x3,
+    FAST_READ = 0xb,
+    DOR = 0x3b,
+    QOR = 0x6b,
+    DIOR = 0xbb,
+    QIOR = 0xeb,
+
+    PP = 0x2,
+    DPP = 0xa2,
+    QPP = 0x32,
+} FlashCMD;
+
 typedef struct {
     SysBusDevice busdev;
     MemoryRegion iomem;
@@ -251,15 +264,19 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
         switch (s->snoop_state) {
         case (SNOOP_CHECKING):
             switch (tx) { /* new instruction code */
-            case 0x0b: /* dual/quad output read DOR/QOR */
-            case 0x6b:
-                s->snoop_state = 4;
+            case READ: /* 3 address bytes, no dummy bytes/cycles */
+            case PP:
+            case DPP:
+            case QPP:
+                s->snoop_state = 3;
                 break;
-            /* FIXME: these vary between vendor - set to spansion */
-            case 0xbb: /* high performance dual read DIOR */
+            case FAST_READ: /* 3 address bytes, 1 dummy byte */
+            case DOR:
+            case QOR:
+            case DIOR: /* FIXME: these vary between vendor - set to spansion */
                 s->snoop_state = 4;
                 break;
-            case 0xeb: /* high performance quad read QIOR */
+            case QIOR: /* 3 address bytes, 2 dummy bytes */
                 s->snoop_state = 6;
                 break;
             default:
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 17/17] xilinx_spips: QOM styling fixes
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (15 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 16/17] xilinx_spips: Add missing dual-bus snoop commands Peter Maydell
@ 2013-03-15 16:56 ` Peter Maydell
  2013-03-17 20:48 ` [Qemu-devel] [PULL 00/17] arm-devs queue Blue Swirl
  17 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2013-03-15 16:56 UTC (permalink / raw)
  To: Anthony Liguori, Blue Swirl; +Cc: qemu-devel, Paul Brook

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Few fixes for the latest QOM styling guides.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: de9daeee6c142e8b57ad042fd680cedcdc94d2fc.1362373359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/xilinx_spips.c |   29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
index 3183f7a..b2397f4 100644
--- a/hw/xilinx_spips.c
+++ b/hw/xilinx_spips.c
@@ -154,6 +154,11 @@ typedef struct {
     hwaddr lqspi_cached_addr;
 } XilinxSPIPS;
 
+#define TYPE_XILINX_SPIPS "xilinx,spips"
+
+#define XILINX_SPIPS(obj) \
+     OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
+
 static inline int num_effective_busses(XilinxSPIPS *s)
 {
     return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
@@ -210,7 +215,7 @@ static void xilinx_spips_update_ixr(XilinxSPIPS *s)
 
 static void xilinx_spips_reset(DeviceState *d)
 {
-    XilinxSPIPS *s = DO_UPCAST(XilinxSPIPS, busdev.qdev, d);
+    XilinxSPIPS *s = XILINX_SPIPS(d);
 
     int i;
     for (i = 0; i < R_MAX; i++) {
@@ -500,9 +505,10 @@ static const MemoryRegionOps lqspi_ops = {
     }
 };
 
-static int xilinx_spips_init(SysBusDevice *dev)
+static void xilinx_spips_realize(DeviceState *dev, Error **errp)
 {
-    XilinxSPIPS *s = FROM_SYSBUS(typeof(*s), dev);
+    XilinxSPIPS *s = XILINX_SPIPS(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     int i;
 
     DB_PRINT("inited device model\n");
@@ -511,31 +517,29 @@ static int xilinx_spips_init(SysBusDevice *dev)
     for (i = 0; i < s->num_busses; ++i) {
         char bus_name[16];
         snprintf(bus_name, 16, "spi%d", i);
-        s->spi[i] = ssi_create_bus(&dev->qdev, bus_name);
+        s->spi[i] = ssi_create_bus(dev, bus_name);
     }
 
     s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
-    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(sbd, &s->irq);
     for (i = 0; i < s->num_cs * s->num_busses; ++i) {
-        sysbus_init_irq(dev, &s->cs_lines[i]);
+        sysbus_init_irq(sbd, &s->cs_lines[i]);
     }
 
     memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
-    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_mmio(sbd, &s->iomem);
 
     memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
                           (1 << LQSPI_ADDRESS_BITS) * 2);
-    sysbus_init_mmio(dev, &s->mmlqspi);
+    sysbus_init_mmio(sbd, &s->mmlqspi);
 
     s->irqline = -1;
     s->lqspi_cached_addr = ~0ULL;
 
     fifo8_create(&s->rx_fifo, RXFF_A);
     fifo8_create(&s->tx_fifo, TXFF_A);
-
-    return 0;
 }
 
 static int xilinx_spips_post_load(void *opaque, int version_id)
@@ -569,16 +573,15 @@ static Property xilinx_spips_properties[] = {
 static void xilinx_spips_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 
-    sdc->init = xilinx_spips_init;
+    dc->realize = xilinx_spips_realize;
     dc->reset = xilinx_spips_reset;
     dc->props = xilinx_spips_properties;
     dc->vmsd = &vmstate_xilinx_spips;
 }
 
 static const TypeInfo xilinx_spips_info = {
-    .name  = "xilinx,spips",
+    .name  = TYPE_XILINX_SPIPS,
     .parent = TYPE_SYS_BUS_DEVICE,
     .instance_size  = sizeof(XilinxSPIPS),
     .class_init = xilinx_spips_class_init,
-- 
1.7.9.5

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

* Re: [Qemu-devel] [PULL 00/17] arm-devs queue
  2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
                   ` (16 preceding siblings ...)
  2013-03-15 16:56 ` [Qemu-devel] [PATCH 17/17] xilinx_spips: QOM styling fixes Peter Maydell
@ 2013-03-17 20:48 ` Blue Swirl
  17 siblings, 0 replies; 19+ messages in thread
From: Blue Swirl @ 2013-03-17 20:48 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Anthony Liguori, qemu-devel, Paul Brook

Thanks, pulled.

On Fri, Mar 15, 2013 at 4:56 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Another arm-devs pullreq: xilinx fixes from Peter C, the pl330
> model, and my vexpress fixes for the system control regs.
> Please pull.
>
> thanks
> -- PMM
>
>
> The following changes since commit dc0b0616f726956001be09e9a65a6e0b0bd939db:
>
>   Merge remote-tracking branch 'stefanha/block' into staging (2013-03-15 10:47:21 -0500)
>
> are available in the git repository at:
>
>
>   git://git.linaro.org/people/pmaydell/qemu-arm.git arm-devs.next
>
> for you to fetch changes up to f8b9fe249a706bfed61e0bb66c73394553696382:
>
>   xilinx_spips: QOM styling fixes (2013-03-15 16:41:59 +0000)
>
> ----------------------------------------------------------------
> Nathan Rossi (2):
>       xilinx_spips: Fix bus setup conditional check
>       xilinx_spips: Add missing dual-bus snoop commands
>
> Peter Crosthwaite (5):
>       iov: Factor out hexdumper
>       pl330: Initial version
>       xilinx_zynq: added pl330 to machine model
>       xilinx_spips: Set unused IRQs to NULL
>       xilinx_spips: QOM styling fixes
>
> Peter Maydell (10):
>       hw/vexpress: Pass proc_id via VEDBoardInfo
>       hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way
>       hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op
>       hw/arm_sysctl: Implement SYS_CFG_DVIMODE as a no-op
>       hw/arm_sysctl: Convert from qdev init to instance_init
>       qdev: Implement (variable length) array properties
>       hw/arm_sysctl: Implement SYS_CFG_VOLT
>       hw/vexpress: Pass voltage sensor properties to sysctl device
>       hw/arm_sysctl: Implement SYS_CFG_OSC function
>       hw/vexpress: Set reset values for daughterboard oscillators
>
>  default-configs/arm-softmmu.mak |    1 +
>  hw/Makefile.objs                |    1 +
>  hw/arm/vexpress.c               |   81 +-
>  hw/arm/xilinx_zynq.c            |   24 +
>  hw/arm_sysctl.c                 |  261 +++++-
>  hw/pl330.c                      | 1654 +++++++++++++++++++++++++++++++++++++++
>  hw/qdev-core.h                  |    3 +
>  hw/qdev-properties.c            |  104 +++
>  hw/qdev-properties.h            |   39 +
>  hw/xilinx_spips.c               |   64 +-
>  include/qemu-common.h           |    6 +
>  util/Makefile.objs              |    1 +
>  util/hexdump.c                  |   37 +
>  util/iov.c                      |   36 +-
>  14 files changed, 2234 insertions(+), 78 deletions(-)
>  create mode 100644 hw/pl330.c
>  create mode 100644 util/hexdump.c

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

end of thread, other threads:[~2013-03-17 20:49 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-15 16:56 [Qemu-devel] [PULL 00/17] arm-devs queue Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 01/17] hw/vexpress: Pass proc_id via VEDBoardInfo Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 02/17] hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 03/17] hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 04/17] hw/arm_sysctl: Implement SYS_CFG_DVIMODE " Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 05/17] hw/arm_sysctl: Convert from qdev init to instance_init Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 06/17] qdev: Implement (variable length) array properties Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 07/17] hw/arm_sysctl: Implement SYS_CFG_VOLT Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 08/17] hw/vexpress: Pass voltage sensor properties to sysctl device Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 09/17] hw/arm_sysctl: Implement SYS_CFG_OSC function Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 10/17] hw/vexpress: Set reset values for daughterboard oscillators Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 11/17] iov: Factor out hexdumper Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 12/17] pl330: Initial version Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 13/17] xilinx_zynq: added pl330 to machine model Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 14/17] xilinx_spips: Set unused IRQs to NULL Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 15/17] xilinx_spips: Fix bus setup conditional check Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 16/17] xilinx_spips: Add missing dual-bus snoop commands Peter Maydell
2013-03-15 16:56 ` [Qemu-devel] [PATCH 17/17] xilinx_spips: QOM styling fixes Peter Maydell
2013-03-17 20:48 ` [Qemu-devel] [PULL 00/17] arm-devs queue Blue Swirl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).