qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 0/8] arm-devs queue
@ 2011-12-12 10:47 Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer Peter Maydell
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

The following changes since commit f18318eef8b4b263f4e82a5338c9b2875a6c73c8:

  Merge branch 'master' of git://git.qemu.org/qemu (2011-12-12 04:12:31 +0400)

are available in the git repository at:

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

Peter Chubb (1):
      Fix sp804 dual-timer

Peter Maydell (7):
      hw/arm_mptimer.c: Turn ARM MPcore private timers into qdev devices
      hw/arm_gic: Expose GIC CPU interfaces as sysbus memory regions
      hw/mpcore.c: Use the GIC memory regions for the CPU interface
      hw/realview_gic: Use GIC memory region for the CPU interface
      hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only
      hw/a9mpcore.c: Implement A9MP peripherals rather than 11MPcore ones
      hw/mpcore.c: Merge with hw/arm11mpcore.c

 Makefile.target   |    1 +
 hw/a9mpcore.c     |  189 ++++++++++++++++++++++++++++--
 hw/arm11mpcore.c  |  130 +++++++++++++++++++++-
 hw/arm_gic.c      |   75 ++++++++++++-
 hw/arm_mptimer.c  |  332 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/arm_timer.c    |   41 ++++++-
 hw/mpcore.c       |  283 ---------------------------------------------
 hw/realview_gic.c |   25 +----
 8 files changed, 751 insertions(+), 325 deletions(-)
 create mode 100644 hw/arm_mptimer.c
 delete mode 100644 hw/mpcore.c

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

* [Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 2/8] hw/arm_mptimer.c: Turn ARM MPcore private timers into qdev devices Peter Maydell
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

From: Peter Chubb <peter.chubb@nicta.com.au>

Properly implement dual-timer read/write for the sp804 dual timer module.
Based on ARM specs at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html

Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: David Mirabito <david.mirabito@nicta.com.au>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_timer.c |   41 +++++++++++++++++++++++++++++++++++------
 1 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 518bad2..0a5b9d2 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -170,9 +170,9 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
 }
 
 /* ARM PrimeCell SP804 dual timer module.
-   Docs for this device don't seem to be publicly available.  This
-   implementation is based on guesswork, the linux kernel sources and the
-   Integrator/CP timer modules.  */
+ * Docs at
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
+*/
 
 typedef struct {
     SysBusDevice busdev;
@@ -182,6 +182,13 @@ typedef struct {
     qemu_irq irq;
 } sp804_state;
 
+static const uint8_t sp804_ids[] = {
+    /* Timer ID */
+    0x04, 0x18, 0x14, 0,
+    /* PrimeCell ID */
+    0xd, 0xf0, 0x05, 0xb1
+};
+
 /* Merge the IRQs from the two component devices.  */
 static void sp804_set_irq(void *opaque, int irq, int level)
 {
@@ -196,12 +203,27 @@ static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
 {
     sp804_state *s = (sp804_state *)opaque;
 
-    /* ??? Don't know the PrimeCell ID for this device.  */
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
-    } else {
+    }
+    if (offset < 0x40) {
         return arm_timer_read(s->timer[1], offset - 0x20);
     }
+
+    /* TimerPeriphID */
+    if (offset >= 0xfe0 && offset <= 0xffc) {
+        return sp804_ids[(offset - 0xfe0) >> 2];
+    }
+
+    switch (offset) {
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        return 0;
+    }
+
+    hw_error("%s: Bad offset %x\n", __func__, (int)offset);
+    return 0;
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
@@ -211,9 +233,16 @@ static void sp804_write(void *opaque, target_phys_addr_t offset,
 
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
-    } else {
+        return;
+    }
+
+    if (offset < 0x40) {
         arm_timer_write(s->timer[1], offset - 0x20, value);
+        return;
     }
+
+    /* Technically we could be writing to the Test Registers, but not likely */
+    hw_error("%s: Bad offset %x\n", __func__, (int)offset);
 }
 
 static const MemoryRegionOps sp804_ops = {
-- 
1.7.1

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

* [Qemu-devel] [PATCH 2/8] hw/arm_mptimer.c: Turn ARM MPcore private timers into qdev devices
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 3/8] hw/arm_gic: Expose GIC CPU interfaces as sysbus memory regions Peter Maydell
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Turn the ARM MPcore private timer/watchdog blocks into separate
qdev devices. This will allow us to share them neatly between
11MPCore and A9MPcore.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 Makefile.target  |    1 +
 hw/arm_mptimer.c |  332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/mpcore.c      |  184 +++++-------------------------
 3 files changed, 365 insertions(+), 152 deletions(-)
 create mode 100644 hw/arm_mptimer.c

diff --git a/Makefile.target b/Makefile.target
index a111521..39b2e5a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -344,6 +344,7 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 obj-arm-y += pl061.o
 obj-arm-y += arm-semi.o
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
new file mode 100644
index 0000000..455a0aa
--- /dev/null
+++ b/hw/arm_mptimer.c
@@ -0,0 +1,332 @@
+/*
+ * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Paul Brook, Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* This device implements the per-cpu private timer and watchdog block
+ * which is used in both the ARM11MPCore and Cortex-A9MP.
+ */
+
+#define MAX_CPUS 4
+
+/* State of a single timer or watchdog block */
+typedef struct {
+    uint32_t count;
+    uint32_t load;
+    uint32_t control;
+    uint32_t status;
+    int64_t tick;
+    QEMUTimer *timer;
+    qemu_irq irq;
+    MemoryRegion iomem;
+} timerblock;
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t num_cpu;
+    timerblock timerblock[MAX_CPUS * 2];
+    MemoryRegion iomem[2];
+} arm_mptimer_state;
+
+static inline int get_current_cpu(arm_mptimer_state *s)
+{
+    if (cpu_single_env->cpu_index >= s->num_cpu) {
+        hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
+                 s->num_cpu, cpu_single_env->cpu_index);
+    }
+    return cpu_single_env->cpu_index;
+}
+
+static inline void timerblock_update_irq(timerblock *tb)
+{
+    qemu_set_irq(tb->irq, tb->status);
+}
+
+/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
+static inline uint32_t timerblock_scale(timerblock *tb)
+{
+    return (((tb->control >> 8) & 0xff) + 1) * 10;
+}
+
+static void timerblock_reload(timerblock *tb, int restart)
+{
+    if (tb->count == 0) {
+        return;
+    }
+    if (restart) {
+        tb->tick = qemu_get_clock_ns(vm_clock);
+    }
+    tb->tick += (int64_t)tb->count * timerblock_scale(tb);
+    qemu_mod_timer(tb->timer, tb->tick);
+}
+
+static void timerblock_tick(void *opaque)
+{
+    timerblock *tb = (timerblock *)opaque;
+    tb->status = 1;
+    if (tb->control & 2) {
+        tb->count = tb->load;
+        timerblock_reload(tb, 0);
+    } else {
+        tb->count = 0;
+    }
+    timerblock_update_irq(tb);
+}
+
+static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
+{
+    timerblock *tb = (timerblock *)opaque;
+    int64_t val;
+    addr &= 0x1f;
+    switch (addr) {
+    case 0: /* Load */
+        return tb->load;
+    case 4: /* Counter.  */
+        if (((tb->control & 1) == 0) || (tb->count == 0)) {
+            return 0;
+        }
+        /* Slow and ugly, but hopefully won't happen too often.  */
+        val = tb->tick - qemu_get_clock_ns(vm_clock);
+        val /= timerblock_scale(tb);
+        if (val < 0) {
+            val = 0;
+        }
+        return val;
+    case 8: /* Control.  */
+        return tb->control;
+    case 12: /* Interrupt status.  */
+        return tb->status;
+    default:
+        return 0;
+    }
+}
+
+static void timerblock_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t value, unsigned size)
+{
+    timerblock *tb = (timerblock *)opaque;
+    int64_t old;
+    addr &= 0x1f;
+    switch (addr) {
+    case 0: /* Load */
+        tb->load = value;
+        /* Fall through.  */
+    case 4: /* Counter.  */
+        if ((tb->control & 1) && tb->count) {
+            /* Cancel the previous timer.  */
+            qemu_del_timer(tb->timer);
+        }
+        tb->count = value;
+        if (tb->control & 1) {
+            timerblock_reload(tb, 1);
+        }
+        break;
+    case 8: /* Control.  */
+        old = tb->control;
+        tb->control = value;
+        if (((old & 1) == 0) && (value & 1)) {
+            if (tb->count == 0 && (tb->control & 2)) {
+                tb->count = tb->load;
+            }
+            timerblock_reload(tb, 1);
+        }
+        break;
+    case 12: /* Interrupt status.  */
+        tb->status &= ~value;
+        timerblock_update_irq(tb);
+        break;
+    }
+}
+
+/* Wrapper functions to implement the "read timer/watchdog for
+ * the current CPU" memory regions.
+ */
+static uint64_t arm_thistimer_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+    int id = get_current_cpu(s);
+    return timerblock_read(&s->timerblock[id * 2], addr, size);
+}
+
+static void arm_thistimer_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t value, unsigned size)
+{
+    arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+    int id = get_current_cpu(s);
+    timerblock_write(&s->timerblock[id * 2], addr, value, size);
+}
+
+static uint64_t arm_thiswdog_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
+{
+    arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+    int id = get_current_cpu(s);
+    return timerblock_read(&s->timerblock[id * 2 + 1], addr, size);
+}
+
+static void arm_thiswdog_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t value, unsigned size)
+{
+    arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+    int id = get_current_cpu(s);
+    timerblock_write(&s->timerblock[id * 2 + 1], addr, value, size);
+}
+
+static const MemoryRegionOps arm_thistimer_ops = {
+    .read = arm_thistimer_read,
+    .write = arm_thistimer_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps arm_thiswdog_ops = {
+    .read = arm_thiswdog_read,
+    .write = arm_thiswdog_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps timerblock_ops = {
+    .read = timerblock_read,
+    .write = timerblock_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timerblock_reset(timerblock *tb)
+{
+    tb->count = 0;
+    tb->load = 0;
+    tb->control = 0;
+    tb->status = 0;
+    tb->tick = 0;
+}
+
+static void arm_mptimer_reset(DeviceState *dev)
+{
+    arm_mptimer_state *s =
+        FROM_SYSBUS(arm_mptimer_state, sysbus_from_qdev(dev));
+    int i;
+    /* We reset every timer in the array, not just the ones we're using,
+     * because vmsave will look at every array element.
+     */
+    for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
+        timerblock_reset(&s->timerblock[i]);
+    }
+}
+
+static int arm_mptimer_init(SysBusDevice *dev)
+{
+    arm_mptimer_state *s = FROM_SYSBUS(arm_mptimer_state, dev);
+    int i;
+    if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
+        hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
+    }
+    /* We implement one timer and one watchdog block per CPU, and
+     * expose multiple MMIO regions:
+     *  * region 0 is "timer for this core"
+     *  * region 1 is "watchdog for this core"
+     *  * region 2 is "timer for core 0"
+     *  * region 3 is "watchdog for core 0"
+     *  * region 4 is "timer for core 1"
+     *  * region 5 is "watchdog for core 1"
+     * and so on.
+     * The outgoing interrupt lines are
+     *  * timer for core 0
+     *  * watchdog for core 0
+     *  * timer for core 1
+     *  * watchdog for core 1
+     * and so on.
+     */
+    memory_region_init_io(&s->iomem[0], &arm_thistimer_ops, s,
+                          "arm_mptimer_timer", 0x20);
+    sysbus_init_mmio(dev, &s->iomem[0]);
+    memory_region_init_io(&s->iomem[1], &arm_thiswdog_ops, s,
+                          "arm_mptimer_wdog", 0x20);
+    sysbus_init_mmio(dev, &s->iomem[1]);
+    for (i = 0; i < (s->num_cpu * 2); i++) {
+        timerblock *tb = &s->timerblock[i];
+        tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
+        sysbus_init_irq(dev, &tb->irq);
+        memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
+                              "arm_mptimer_timerblock", 0x20);
+        sysbus_init_mmio(dev, &tb->iomem);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_timerblock = {
+    .name = "arm_mptimer_timerblock",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(count, timerblock),
+        VMSTATE_UINT32(load, timerblock),
+        VMSTATE_UINT32(control, timerblock),
+        VMSTATE_UINT32(status, timerblock),
+        VMSTATE_INT64(tick, timerblock),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_arm_mptimer = {
+    .name = "arm_mptimer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(timerblock, arm_mptimer_state, (MAX_CPUS * 2),
+                             1, vmstate_timerblock, timerblock),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo arm_mptimer_info = {
+    .init = arm_mptimer_init,
+    .qdev.name = "arm_mptimer",
+    .qdev.size = sizeof(arm_mptimer_state),
+    .qdev.vmsd = &vmstate_arm_mptimer,
+    .qdev.reset = arm_mptimer_reset,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void arm_mptimer_register_devices(void)
+{
+    sysbus_register_withprop(&arm_mptimer_info);
+}
+
+device_init(arm_mptimer_register_devices)
diff --git a/hw/mpcore.c b/hw/mpcore.c
index 4357d12..3d64609 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -22,135 +22,18 @@ gic_get_current_cpu(void)
 
 /* MPCore private memory region.  */
 
-typedef struct {
-    uint32_t count;
-    uint32_t load;
-    uint32_t control;
-    uint32_t status;
-    uint32_t old_status;
-    int64_t tick;
-    QEMUTimer *timer;
-    struct mpcore_priv_state *mpcore;
-    int id; /* Encodes both timer/watchdog and CPU.  */
-} mpcore_timer_state;
-
 typedef struct mpcore_priv_state {
     gic_state gic;
     uint32_t scu_control;
     int iomemtype;
-    mpcore_timer_state timer[8];
+    uint32_t old_timer_status[8];
     uint32_t num_cpu;
+    qemu_irq *timer_irq;
     MemoryRegion iomem;
     MemoryRegion container;
+    DeviceState *mptimer;
 } mpcore_priv_state;
 
-/* Per-CPU Timers.  */
-
-static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
-{
-    if (s->status & ~s->old_status) {
-        gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
-    }
-    s->old_status = s->status;
-}
-
-/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
-static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s)
-{
-    return (((s->control >> 8) & 0xff) + 1) * 10;
-}
-
-static void mpcore_timer_reload(mpcore_timer_state *s, int restart)
-{
-    if (s->count == 0)
-        return;
-    if (restart)
-        s->tick = qemu_get_clock_ns(vm_clock);
-    s->tick += (int64_t)s->count * mpcore_timer_scale(s);
-    qemu_mod_timer(s->timer, s->tick);
-}
-
-static void mpcore_timer_tick(void *opaque)
-{
-    mpcore_timer_state *s = (mpcore_timer_state *)opaque;
-    s->status = 1;
-    if (s->control & 2) {
-        s->count = s->load;
-        mpcore_timer_reload(s, 0);
-    } else {
-        s->count = 0;
-    }
-    mpcore_timer_update_irq(s);
-}
-
-static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset)
-{
-    int64_t val;
-    switch (offset) {
-    case 0: /* Load */
-        return s->load;
-        /* Fall through.  */
-    case 4: /* Counter.  */
-        if (((s->control & 1) == 0) || (s->count == 0))
-            return 0;
-        /* Slow and ugly, but hopefully won't happen too often.  */
-        val = s->tick - qemu_get_clock_ns(vm_clock);
-        val /= mpcore_timer_scale(s);
-        if (val < 0)
-            val = 0;
-        return val;
-    case 8: /* Control.  */
-        return s->control;
-    case 12: /* Interrupt status.  */
-        return s->status;
-    default:
-        return 0;
-    }
-}
-
-static void mpcore_timer_write(mpcore_timer_state *s, int offset,
-                               uint32_t value)
-{
-    int64_t old;
-    switch (offset) {
-    case 0: /* Load */
-        s->load = value;
-        /* Fall through.  */
-    case 4: /* Counter.  */
-        if ((s->control & 1) && s->count) {
-            /* Cancel the previous timer.  */
-            qemu_del_timer(s->timer);
-        }
-        s->count = value;
-        if (s->control & 1) {
-            mpcore_timer_reload(s, 1);
-        }
-        break;
-    case 8: /* Control.  */
-        old = s->control;
-        s->control = value;
-        if (((old & 1) == 0) && (value & 1)) {
-            if (s->count == 0 && (s->control & 2))
-                s->count = s->load;
-            mpcore_timer_reload(s, 1);
-        }
-        break;
-    case 12: /* Interrupt status.  */
-        s->status &= ~value;
-        mpcore_timer_update_irq(s);
-        break;
-    }
-}
-
-static void mpcore_timer_init(mpcore_priv_state *mpcore,
-                              mpcore_timer_state *s, int id)
-{
-    s->id = id;
-    s->mpcore = mpcore;
-    s->timer = qemu_new_timer_ns(vm_clock, mpcore_timer_tick, s);
-}
-
-
 /* Per-CPU private memory mapped IO.  */
 
 static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
@@ -185,20 +68,6 @@ static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
             }
         }
         return gic_cpu_read(&s->gic, id, offset & 0xff);
-    } else if (offset < 0xb00) {
-        /* Timers.  */
-        if (offset < 0x700) {
-            id = gic_get_current_cpu();
-        } else {
-            id = (offset - 0x700) >> 8;
-            if (id >= s->num_cpu) {
-                return 0;
-            }
-        }
-        id <<= 1;
-        if (offset & 0x20)
-          id++;
-        return mpcore_timer_read(&s->timer[id], offset & 0xf);
     }
 bad_reg:
     hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
@@ -233,20 +102,6 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
         if (id < s->num_cpu) {
             gic_cpu_write(&s->gic, id, offset & 0xff, value);
         }
-    } else if (offset < 0xb00) {
-        /* Timers.  */
-        if (offset < 0x700) {
-            id = gic_get_current_cpu();
-        } else {
-            id = (offset - 0x700) >> 8;
-        }
-        if (id < s->num_cpu) {
-            id <<= 1;
-            if (offset & 0x20)
-              id++;
-            mpcore_timer_write(&s->timer[id], offset & 0xf, value);
-        }
-        return;
     }
     return;
 bad_reg:
@@ -259,25 +114,50 @@ static const MemoryRegionOps mpcore_priv_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
+static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
+{
+    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+    if (level && !s->old_timer_status[irq]) {
+        gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
+    }
+    s->old_timer_status[irq] = level;
+}
+
 static void mpcore_priv_map_setup(mpcore_priv_state *s)
 {
+    int i;
+    SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
     memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
     memory_region_init_io(&s->iomem, &mpcore_priv_ops, s, "mpcode-priv",
                           0x1000);
     memory_region_add_subregion(&s->container, 0, &s->iomem);
+    /* Add the regions for timer and watchdog for "current CPU" and
+     * for each specific CPU.
+     */
+    s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
+                                      s, (s->num_cpu + 1) * 2);
+    for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
+        /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
+        target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
+        memory_region_add_subregion(&s->container, offset,
+                                    sysbus_mmio_get_region(busdev, i));
+    }
     memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+    /* Wire up the interrupt from each watchdog and timer. */
+    for (i = 0; i < s->num_cpu * 2; i++) {
+        sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+    }
 }
 
 static int mpcore_priv_init(SysBusDevice *dev)
 {
     mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
-    int i;
 
     gic_init(&s->gic, s->num_cpu);
+    s->mptimer = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->mptimer);
     mpcore_priv_map_setup(s);
     sysbus_init_mmio(dev, &s->container);
-    for (i = 0; i < s->num_cpu * 2; i++) {
-        mpcore_timer_init(s, &s->timer[i], i);
-    }
     return 0;
 }
-- 
1.7.1

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

* [Qemu-devel] [PATCH 3/8] hw/arm_gic: Expose GIC CPU interfaces as sysbus memory regions
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 2/8] hw/arm_mptimer.c: Turn ARM MPcore private timers into qdev devices Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 4/8] hw/mpcore.c: Use the GIC memory regions for the CPU interface Peter Maydell
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Expose the ARM GIC CPU interfaces as memory regions, rather than
just providing read and write functions for them.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_gic.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 74 insertions(+), 1 deletions(-)

diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 527c9ce..66c48fd 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -103,7 +103,14 @@ typedef struct gic_state
     int num_cpu;
 #endif
 
-    MemoryRegion iomem;
+    MemoryRegion iomem; /* Distributor */
+#ifndef NVIC
+    /* This is just so we can have an opaque pointer which identifies
+     * both this GIC and which CPU interface we should be accessing.
+     */
+    struct gic_state *backref[NCPU];
+    MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
+#endif
 } gic_state;
 
 /* TODO: Many places that call this routine could be optimized.  */
@@ -633,6 +640,54 @@ static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
     }
     gic_update(s);
 }
+
+/* Wrappers to read/write the GIC CPU interface for the current CPU */
+static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
+{
+    gic_state *s = (gic_state *)opaque;
+    return gic_cpu_read(s, gic_get_current_cpu(), addr & 0xff);
+}
+
+static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t value, unsigned size)
+{
+    gic_state *s = (gic_state *)opaque;
+    gic_cpu_write(s, gic_get_current_cpu(), addr & 0xff, value);
+}
+
+/* Wrappers to read/write the GIC CPU interface for a specific CPU.
+ * These just decode the opaque pointer into gic_state* + cpu id.
+ */
+static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
+{
+    gic_state **backref = (gic_state **)opaque;
+    gic_state *s = *backref;
+    int id = (backref - s->backref);
+    return gic_cpu_read(s, id, addr & 0xff);
+}
+
+static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t value, unsigned size)
+{
+    gic_state **backref = (gic_state **)opaque;
+    gic_state *s = *backref;
+    int id = (backref - s->backref);
+    gic_cpu_write(s, id, addr & 0xff, value);
+}
+
+static const MemoryRegionOps gic_thiscpu_ops = {
+    .read = gic_thiscpu_read,
+    .write = gic_thiscpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps gic_cpu_ops = {
+    .read = gic_do_cpu_read,
+    .write = gic_do_cpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
 #endif
 
 static void gic_reset(gic_state *s)
@@ -752,6 +807,24 @@ static void gic_init(gic_state *s)
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
     memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
+#ifndef NVIC
+    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
+     * a region for "CPU interface for this core", then a region for
+     * "CPU interface for core 0", "for core 1", ...
+     * NB that the memory region size of 0x100 applies for the 11MPCore
+     * and also cores following the GIC v1 spec (ie A9).
+     * GIC v2 defines a larger memory region (0x1000) so this will need
+     * to be extended when we implement A15.
+     */
+    memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
+                          "gic_cpu", 0x100);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        s->backref[i] = s;
+        memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
+                              "gic_cpu", 0x100);
+    }
+#endif
+
     gic_reset(s);
     register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
 }
-- 
1.7.1

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

* [Qemu-devel] [PATCH 4/8] hw/mpcore.c: Use the GIC memory regions for the CPU interface
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
                   ` (2 preceding siblings ...)
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 3/8] hw/arm_gic: Expose GIC CPU interfaces as sysbus memory regions Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 5/8] hw/realview_gic: Use GIC memory region " Peter Maydell
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Switch to using the GIC memory regions for the CPU interface
rather than hand implementing them as a subcase of mpcore_priv_read()
and mpcore_priv_write().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/mpcore.c |   35 ++++++++++-------------------------
 1 files changed, 10 insertions(+), 25 deletions(-)

diff --git a/hw/mpcore.c b/hw/mpcore.c
index 3d64609..a0af1ad 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -41,7 +41,7 @@ static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
     int id;
-    offset &= 0xfff;
+    offset &= 0xff;
     if (offset < 0x100) {
         /* SCU */
         switch (offset) {
@@ -57,17 +57,6 @@ static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
         default:
             goto bad_reg;
         }
-    } else if (offset < 0x600) {
-        /* Interrupt controller.  */
-        if (offset < 0x200) {
-            id = gic_get_current_cpu();
-        } else {
-            id = (offset - 0x200) >> 8;
-            if (id >= s->num_cpu) {
-                return 0;
-            }
-        }
-        return gic_cpu_read(&s->gic, id, offset & 0xff);
     }
 bad_reg:
     hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
@@ -78,8 +67,7 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
                               uint64_t value, unsigned size)
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
-    int id;
-    offset &= 0xfff;
+    offset &= 0xff;
     if (offset < 0x100) {
         /* SCU */
         switch (offset) {
@@ -92,16 +80,6 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
         default:
             goto bad_reg;
         }
-    } else if (offset < 0x600) {
-        /* Interrupt controller.  */
-        if (offset < 0x200) {
-            id = gic_get_current_cpu();
-        } else {
-            id = (offset - 0x200) >> 8;
-        }
-        if (id < s->num_cpu) {
-            gic_cpu_write(&s->gic, id, offset & 0xff, value);
-        }
     }
     return;
 bad_reg:
@@ -129,8 +107,15 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s)
     SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
     memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
     memory_region_init_io(&s->iomem, &mpcore_priv_ops, s, "mpcode-priv",
-                          0x1000);
+                          0x100);
     memory_region_add_subregion(&s->container, 0, &s->iomem);
+    /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
+     * at 0x200, 0x300...
+     */
+    for (i = 0; i < (s->num_cpu + 1); i++) {
+        target_phys_addr_t offset = 0x100 + (i * 0x100);
+        memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
+    }
     /* Add the regions for timer and watchdog for "current CPU" and
      * for each specific CPU.
      */
-- 
1.7.1

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

* [Qemu-devel] [PATCH 5/8] hw/realview_gic: Use GIC memory region for the CPU interface
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
                   ` (3 preceding siblings ...)
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 4/8] hw/mpcore.c: Use the GIC memory regions for the CPU interface Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 6/8] hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only Peter Maydell
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Use the GIC provided memory region for the CPU interface rather
than implementing our own.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/realview_gic.c |   25 +------------------------
 1 files changed, 1 insertions(+), 24 deletions(-)

diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 479f939..8c4d509 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -23,36 +23,13 @@ gic_get_current_cpu(void)
 
 typedef struct {
     gic_state gic;
-    MemoryRegion iomem;
     MemoryRegion container;
 } RealViewGICState;
 
-static uint64_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset,
-                                      unsigned size)
-{
-    gic_state *s = (gic_state *)opaque;
-    return gic_cpu_read(s, gic_get_current_cpu(), offset);
-}
-
-static void realview_gic_cpu_write(void *opaque, target_phys_addr_t offset,
-                                   uint64_t value, unsigned size)
-{
-    gic_state *s = (gic_state *)opaque;
-    gic_cpu_write(s, gic_get_current_cpu(), offset, value);
-}
-
-static const MemoryRegionOps realview_gic_cpu_ops = {
-    .read = realview_gic_cpu_read,
-    .write = realview_gic_cpu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
 static void realview_gic_map_setup(RealViewGICState *s)
 {
     memory_region_init(&s->container, "realview-gic-container", 0x2000);
-    memory_region_init_io(&s->iomem, &realview_gic_cpu_ops, &s->gic,
-                          "realview-gic", 0x1000);
-    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    memory_region_add_subregion(&s->container, 0, &s->gic.cpuiomem[0]);
     memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
 }
 
-- 
1.7.1

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

* [Qemu-devel] [PATCH 6/8] hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
                   ` (4 preceding siblings ...)
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 5/8] hw/realview_gic: Use GIC memory region " Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 7/8] hw/a9mpcore.c: Implement A9MP peripherals rather than 11MPcore ones Peter Maydell
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

The only code left in mpcore_priv_read and mpcore_priv_write is now
the implementation of the SCU registers. Clean up by renaming functions
and removing some unnecessary conditionals to make this clearer.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/mpcore.c |   73 +++++++++++++++++++++++++----------------------------------
 1 files changed, 31 insertions(+), 42 deletions(-)

diff --git a/hw/mpcore.c b/hw/mpcore.c
index a0af1ad..670d7e5 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -36,59 +36,49 @@ typedef struct mpcore_priv_state {
 
 /* Per-CPU private memory mapped IO.  */
 
-static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
-                                 unsigned size)
+static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
     int id;
     offset &= 0xff;
-    if (offset < 0x100) {
-        /* SCU */
-        switch (offset) {
-        case 0x00: /* Control.  */
-            return s->scu_control;
-        case 0x04: /* Configuration.  */
-            id = ((1 << s->num_cpu) - 1) << 4;
-            return id | (s->num_cpu - 1);
-        case 0x08: /* CPU status.  */
-            return 0;
-        case 0x0c: /* Invalidate all.  */
-            return 0;
-        default:
-            goto bad_reg;
-        }
+    /* SCU */
+    switch (offset) {
+    case 0x00: /* Control.  */
+        return s->scu_control;
+    case 0x04: /* Configuration.  */
+        id = ((1 << s->num_cpu) - 1) << 4;
+        return id | (s->num_cpu - 1);
+    case 0x08: /* CPU status.  */
+        return 0;
+    case 0x0c: /* Invalidate all.  */
+        return 0;
+    default:
+        hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
     }
-bad_reg:
-    hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
-    return 0;
 }
 
-static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
-                              uint64_t value, unsigned size)
+static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
+                             uint64_t value, unsigned size)
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
     offset &= 0xff;
-    if (offset < 0x100) {
-        /* SCU */
-        switch (offset) {
-        case 0: /* Control register.  */
-            s->scu_control = value & 1;
-            break;
-        case 0x0c: /* Invalidate all.  */
-            /* This is a no-op as cache is not emulated.  */
-            break;
-        default:
-            goto bad_reg;
-        }
+    /* SCU */
+    switch (offset) {
+    case 0: /* Control register.  */
+        s->scu_control = value & 1;
+        break;
+    case 0x0c: /* Invalidate all.  */
+        /* This is a no-op as cache is not emulated.  */
+        break;
+    default:
+        hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
     }
-    return;
-bad_reg:
-    hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
 }
 
-static const MemoryRegionOps mpcore_priv_ops = {
-    .read = mpcore_priv_read,
-    .write = mpcore_priv_write,
+static const MemoryRegionOps mpcore_scu_ops = {
+    .read = mpcore_scu_read,
+    .write = mpcore_scu_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
@@ -106,8 +96,7 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s)
     int i;
     SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
     memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
-    memory_region_init_io(&s->iomem, &mpcore_priv_ops, s, "mpcode-priv",
-                          0x100);
+    memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
     memory_region_add_subregion(&s->container, 0, &s->iomem);
     /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
      * at 0x200, 0x300...
-- 
1.7.1

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

* [Qemu-devel] [PATCH 7/8] hw/a9mpcore.c: Implement A9MP peripherals rather than 11MPcore ones
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
                   ` (5 preceding siblings ...)
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 6/8] hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 8/8] hw/mpcore.c: Merge with hw/arm11mpcore.c Peter Maydell
  2011-12-12 16:34 ` [Qemu-devel] [PULL 0/8] arm-devs queue Anthony Liguori
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Implement the A9MP private peripheral region correctly, rather
than piggybacking on the 11MPCore code; the two CPUs are not the
same in this area.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/a9mpcore.c |  189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 179 insertions(+), 10 deletions(-)

diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 6f108f4..cd2985f 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -2,28 +2,197 @@
  * Cortex-A9MPCore internal peripheral emulation.
  *
  * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
+ * Copyright (c) 2011 Linaro Limited.
+ * Written by Paul Brook, Peter Maydell.
  *
  * This code is licensed under the GPL.
  */
 
-/* 64 external IRQ lines.  */
+#include "sysbus.h"
+
+/* Configuration for arm_gic.c:
+ * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ */
 #define GIC_NIRQ 96
-#include "mpcore.c"
+#define NCPU 4
+
+static inline int
+gic_get_current_cpu(void)
+{
+  return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+/* A9MP private memory region.  */
+
+typedef struct a9mp_priv_state {
+    gic_state gic;
+    uint32_t scu_control;
+    uint32_t old_timer_status[8];
+    uint32_t num_cpu;
+    qemu_irq *timer_irq;
+    MemoryRegion scu_iomem;
+    MemoryRegion ptimer_iomem;
+    MemoryRegion container;
+    DeviceState *mptimer;
+} a9mp_priv_state;
+
+static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
+                            unsigned size)
+{
+    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+    switch (offset) {
+    case 0x00: /* Control */
+        return s->scu_control;
+    case 0x04: /* Configuration */
+        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
+    case 0x08: /* CPU Power Status */
+        return 0;
+    case 0x0c: /* Invalidate All Registers In Secure State */
+        return 0;
+    case 0x40: /* Filtering Start Address Register */
+    case 0x44: /* Filtering End Address Register */
+        /* RAZ/WI, like an implementation with only one AXI master */
+        return 0;
+    case 0x50: /* SCU Access Control Register */
+    case 0x54: /* SCU Non-secure Access Control Register */
+        /* unimplemented, fall through */
+    default:
+        return 0;
+    }
+}
+
+static void a9_scu_write(void *opaque, target_phys_addr_t offset,
+                         uint64_t value, unsigned size)
+{
+    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+    switch (offset) {
+    case 0x00: /* Control */
+        s->scu_control = value & 1;
+        break;
+    case 0x4: /* Configuration: RO */
+        break;
+    case 0x0c: /* Invalidate All Registers In Secure State */
+        /* no-op as we do not implement caches */
+        break;
+    case 0x40: /* Filtering Start Address Register */
+    case 0x44: /* Filtering End Address Register */
+        /* RAZ/WI, like an implementation with only one AXI master */
+        break;
+    case 0x8: /* CPU Power Status */
+    case 0x50: /* SCU Access Control Register */
+    case 0x54: /* SCU Non-secure Access Control Register */
+        /* unimplemented, fall through */
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps a9_scu_ops = {
+    .read = a9_scu_read,
+    .write = a9_scu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level)
+{
+    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+    if (level && !s->old_timer_status[irq]) {
+        gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
+    }
+    s->old_timer_status[irq] = level;
+}
+
+static void a9mp_priv_reset(DeviceState *dev)
+{
+    a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev));
+    int i;
+    s->scu_control = 0;
+    for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
+        s->old_timer_status[i] = 0;
+    }
+}
+
+static int a9mp_priv_init(SysBusDevice *dev)
+{
+    a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev);
+    SysBusDevice *busdev;
+    int i;
+
+    if (s->num_cpu > NCPU) {
+        hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
+    }
+
+    gic_init(&s->gic, s->num_cpu);
+
+    s->mptimer = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->mptimer);
+    busdev = sysbus_from_qdev(s->mptimer);
+
+    /* Memory map (addresses are offsets from PERIPHBASE):
+     *  0x0000-0x00ff -- Snoop Control Unit
+     *  0x0100-0x01ff -- GIC CPU interface
+     *  0x0200-0x02ff -- Global Timer
+     *  0x0300-0x05ff -- nothing
+     *  0x0600-0x06ff -- private timers and watchdogs
+     *  0x0700-0x0fff -- nothing
+     *  0x1000-0x1fff -- GIC Distributor
+     *
+     * We should implement the global timer but don't currently do so.
+     */
+    memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
+    memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
+    memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
+    /* GIC CPU interface */
+    memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]);
+    /* Note that the A9 exposes only the "timer/watchdog for this core"
+     * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
+     */
+    memory_region_add_subregion(&s->container, 0x600,
+                                sysbus_mmio_get_region(busdev, 0));
+    memory_region_add_subregion(&s->container, 0x620,
+                                sysbus_mmio_get_region(busdev, 1));
+    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+
+    sysbus_init_mmio(dev, &s->container);
+
+    /* Wire up the interrupt from each watchdog and timer. */
+    s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler,
+                                      s, (s->num_cpu + 1) * 2);
+    for (i = 0; i < s->num_cpu * 2; i++) {
+        sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_a9mp_priv = {
+    .name = "a9mpcore_priv",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(scu_control, a9mp_priv_state),
+        VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-static SysBusDeviceInfo mpcore_priv_info = {
-    .init = mpcore_priv_init,
+static SysBusDeviceInfo a9mp_priv_info = {
+    .init = a9mp_priv_init,
     .qdev.name  = "a9mpcore_priv",
-    .qdev.size  = sizeof(mpcore_priv_state),
+    .qdev.size  = sizeof(a9mp_priv_state),
+    .qdev.vmsd = &vmstate_a9mp_priv,
+    .qdev.reset = a9mp_priv_reset,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+        DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
 
-static void a9mpcore_register_devices(void)
+static void a9mp_register_devices(void)
 {
-    sysbus_register_withprop(&mpcore_priv_info);
+    sysbus_register_withprop(&a9mp_priv_info);
 }
 
-device_init(a9mpcore_register_devices)
+device_init(a9mp_register_devices)
-- 
1.7.1

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

* [Qemu-devel] [PATCH 8/8] hw/mpcore.c: Merge with hw/arm11mpcore.c
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
                   ` (6 preceding siblings ...)
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 7/8] hw/a9mpcore.c: Implement A9MP peripherals rather than 11MPcore ones Peter Maydell
@ 2011-12-12 10:47 ` Peter Maydell
  2011-12-12 16:34 ` [Qemu-devel] [PULL 0/8] arm-devs queue Anthony Liguori
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2011-12-12 10:47 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

hw/mpcore.c is now implementing only ARM11MPCore specific peripherals,
and is #included only from hw/arm11mpcore.c, so just merge it into that
file.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm11mpcore.c |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/mpcore.c      |  137 ------------------------------------------------------
 2 files changed, 129 insertions(+), 138 deletions(-)
 delete mode 100644 hw/mpcore.c

diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index 32ecf98..bc0457e 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -7,11 +7,139 @@
  * This code is licensed under the GPL.
  */
 
+#include "sysbus.h"
+#include "qemu-timer.h"
+
 /* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
    (+ 32 internal).  However my test chip only exposes/reports 32.
    More importantly Linux falls over if more than 32 are present!  */
 #define GIC_NIRQ 64
-#include "mpcore.c"
+
+#define NCPU 4
+
+static inline int
+gic_get_current_cpu(void)
+{
+  return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+/* MPCore private memory region.  */
+
+typedef struct mpcore_priv_state {
+    gic_state gic;
+    uint32_t scu_control;
+    int iomemtype;
+    uint32_t old_timer_status[8];
+    uint32_t num_cpu;
+    qemu_irq *timer_irq;
+    MemoryRegion iomem;
+    MemoryRegion container;
+    DeviceState *mptimer;
+} mpcore_priv_state;
+
+/* Per-CPU private memory mapped IO.  */
+
+static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
+{
+    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+    int id;
+    offset &= 0xff;
+    /* SCU */
+    switch (offset) {
+    case 0x00: /* Control.  */
+        return s->scu_control;
+    case 0x04: /* Configuration.  */
+        id = ((1 << s->num_cpu) - 1) << 4;
+        return id | (s->num_cpu - 1);
+    case 0x08: /* CPU status.  */
+        return 0;
+    case 0x0c: /* Invalidate all.  */
+        return 0;
+    default:
+        hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
+    }
+}
+
+static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
+                             uint64_t value, unsigned size)
+{
+    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+    offset &= 0xff;
+    /* SCU */
+    switch (offset) {
+    case 0: /* Control register.  */
+        s->scu_control = value & 1;
+        break;
+    case 0x0c: /* Invalidate all.  */
+        /* This is a no-op as cache is not emulated.  */
+        break;
+    default:
+        hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps mpcore_scu_ops = {
+    .read = mpcore_scu_read,
+    .write = mpcore_scu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
+{
+    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+    if (level && !s->old_timer_status[irq]) {
+        gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
+    }
+    s->old_timer_status[irq] = level;
+}
+
+static void mpcore_priv_map_setup(mpcore_priv_state *s)
+{
+    int i;
+    SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
+    memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
+    memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
+    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
+     * at 0x200, 0x300...
+     */
+    for (i = 0; i < (s->num_cpu + 1); i++) {
+        target_phys_addr_t offset = 0x100 + (i * 0x100);
+        memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
+    }
+    /* Add the regions for timer and watchdog for "current CPU" and
+     * for each specific CPU.
+     */
+    s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
+                                      s, (s->num_cpu + 1) * 2);
+    for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
+        /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
+        target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
+        memory_region_add_subregion(&s->container, offset,
+                                    sysbus_mmio_get_region(busdev, i));
+    }
+    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+    /* Wire up the interrupt from each watchdog and timer. */
+    for (i = 0; i < s->num_cpu * 2; i++) {
+        sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+    }
+}
+
+static int mpcore_priv_init(SysBusDevice *dev)
+{
+    mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+
+    gic_init(&s->gic, s->num_cpu);
+    s->mptimer = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->mptimer);
+    mpcore_priv_map_setup(s);
+    sysbus_init_mmio(dev, &s->container);
+    return 0;
+}
 
 /* Dummy PIC to route IRQ lines.  The baseboard has 4 independent IRQ
    controllers.  The output of these, plus some of the raw input lines
diff --git a/hw/mpcore.c b/hw/mpcore.c
deleted file mode 100644
index 670d7e5..0000000
--- a/hw/mpcore.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * ARM MPCore internal peripheral emulation (common code).
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysbus.h"
-#include "qemu-timer.h"
-
-#define NCPU 4
-
-static inline int
-gic_get_current_cpu(void)
-{
-  return cpu_single_env->cpu_index;
-}
-
-#include "arm_gic.c"
-
-/* MPCore private memory region.  */
-
-typedef struct mpcore_priv_state {
-    gic_state gic;
-    uint32_t scu_control;
-    int iomemtype;
-    uint32_t old_timer_status[8];
-    uint32_t num_cpu;
-    qemu_irq *timer_irq;
-    MemoryRegion iomem;
-    MemoryRegion container;
-    DeviceState *mptimer;
-} mpcore_priv_state;
-
-/* Per-CPU private memory mapped IO.  */
-
-static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
-                                unsigned size)
-{
-    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
-    int id;
-    offset &= 0xff;
-    /* SCU */
-    switch (offset) {
-    case 0x00: /* Control.  */
-        return s->scu_control;
-    case 0x04: /* Configuration.  */
-        id = ((1 << s->num_cpu) - 1) << 4;
-        return id | (s->num_cpu - 1);
-    case 0x08: /* CPU status.  */
-        return 0;
-    case 0x0c: /* Invalidate all.  */
-        return 0;
-    default:
-        hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
-    }
-}
-
-static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
-                             uint64_t value, unsigned size)
-{
-    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
-    offset &= 0xff;
-    /* SCU */
-    switch (offset) {
-    case 0: /* Control register.  */
-        s->scu_control = value & 1;
-        break;
-    case 0x0c: /* Invalidate all.  */
-        /* This is a no-op as cache is not emulated.  */
-        break;
-    default:
-        hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps mpcore_scu_ops = {
-    .read = mpcore_scu_read,
-    .write = mpcore_scu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
-{
-    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
-    if (level && !s->old_timer_status[irq]) {
-        gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
-    }
-    s->old_timer_status[irq] = level;
-}
-
-static void mpcore_priv_map_setup(mpcore_priv_state *s)
-{
-    int i;
-    SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
-    memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
-    memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
-    memory_region_add_subregion(&s->container, 0, &s->iomem);
-    /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
-     * at 0x200, 0x300...
-     */
-    for (i = 0; i < (s->num_cpu + 1); i++) {
-        target_phys_addr_t offset = 0x100 + (i * 0x100);
-        memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
-    }
-    /* Add the regions for timer and watchdog for "current CPU" and
-     * for each specific CPU.
-     */
-    s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
-                                      s, (s->num_cpu + 1) * 2);
-    for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
-        /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
-        target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
-        memory_region_add_subregion(&s->container, offset,
-                                    sysbus_mmio_get_region(busdev, i));
-    }
-    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
-    /* Wire up the interrupt from each watchdog and timer. */
-    for (i = 0; i < s->num_cpu * 2; i++) {
-        sysbus_connect_irq(busdev, i, s->timer_irq[i]);
-    }
-}
-
-static int mpcore_priv_init(SysBusDevice *dev)
-{
-    mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
-
-    gic_init(&s->gic, s->num_cpu);
-    s->mptimer = qdev_create(NULL, "arm_mptimer");
-    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
-    qdev_init_nofail(s->mptimer);
-    mpcore_priv_map_setup(s);
-    sysbus_init_mmio(dev, &s->container);
-    return 0;
-}
-- 
1.7.1

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

* Re: [Qemu-devel] [PULL 0/8] arm-devs queue
  2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
                   ` (7 preceding siblings ...)
  2011-12-12 10:47 ` [Qemu-devel] [PATCH 8/8] hw/mpcore.c: Merge with hw/arm11mpcore.c Peter Maydell
@ 2011-12-12 16:34 ` Anthony Liguori
  8 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2011-12-12 16:34 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel

On 12/12/2011 04:47 AM, Peter Maydell wrote:
> The following changes since commit f18318eef8b4b263f4e82a5338c9b2875a6c73c8:
>
>    Merge branch 'master' of git://git.qemu.org/qemu (2011-12-12 04:12:31 +0400)
>
> are available in the git repository at:
>
>    git://git.linaro.org/people/pmaydell/qemu-arm.git arm-devs.for-upstream

Pulled.  Thanks.

Regards,

Anthony Liguori

>
> Peter Chubb (1):
>        Fix sp804 dual-timer
>
> Peter Maydell (7):
>        hw/arm_mptimer.c: Turn ARM MPcore private timers into qdev devices
>        hw/arm_gic: Expose GIC CPU interfaces as sysbus memory regions
>        hw/mpcore.c: Use the GIC memory regions for the CPU interface
>        hw/realview_gic: Use GIC memory region for the CPU interface
>        hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only
>        hw/a9mpcore.c: Implement A9MP peripherals rather than 11MPcore ones
>        hw/mpcore.c: Merge with hw/arm11mpcore.c
>
>   Makefile.target   |    1 +
>   hw/a9mpcore.c     |  189 ++++++++++++++++++++++++++++--
>   hw/arm11mpcore.c  |  130 +++++++++++++++++++++-
>   hw/arm_gic.c      |   75 ++++++++++++-
>   hw/arm_mptimer.c  |  332 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/arm_timer.c    |   41 ++++++-
>   hw/mpcore.c       |  283 ---------------------------------------------
>   hw/realview_gic.c |   25 +----
>   8 files changed, 751 insertions(+), 325 deletions(-)
>   create mode 100644 hw/arm_mptimer.c
>   delete mode 100644 hw/mpcore.c
>
>

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

end of thread, other threads:[~2011-12-12 16:35 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-12 10:47 [Qemu-devel] [PULL 0/8] arm-devs queue Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 2/8] hw/arm_mptimer.c: Turn ARM MPcore private timers into qdev devices Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 3/8] hw/arm_gic: Expose GIC CPU interfaces as sysbus memory regions Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 4/8] hw/mpcore.c: Use the GIC memory regions for the CPU interface Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 5/8] hw/realview_gic: Use GIC memory region " Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 6/8] hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 7/8] hw/a9mpcore.c: Implement A9MP peripherals rather than 11MPcore ones Peter Maydell
2011-12-12 10:47 ` [Qemu-devel] [PATCH 8/8] hw/mpcore.c: Merge with hw/arm11mpcore.c Peter Maydell
2011-12-12 16:34 ` [Qemu-devel] [PULL 0/8] arm-devs queue Anthony Liguori

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