All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer
@ 2018-07-30 16:24 Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters Peter Maydell
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Peter Maydell @ 2018-07-30 16:24 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

This patchset adds some missing timer and counter devices
to the MPS2 boards:

 * the MPS2 "fpgaio" register bank includes some registers
   which provide various kinds of free-running counter
 * the boards have an instance fo the CMSDK "dual timer module"

Together these are sufficient for QEMU's mps2-an505
emulation to pass the "timer test" subsection of the
self-test program which can be found (behind a clickthrough
EULA) in the Cortex-M33_IoT_kit_2_0.zip at:
 https://developer.arm.com/products/system-design/development-boards/fpga-prototyping-boards/download-fpga-images

The dual-timer patch ended up a bit big; I can try to split
that up if people would prefer that for review.

thanks
-- PMM

Peter Maydell (5):
  hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters
  hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
  hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module
  hw/arm/iotkit: Wire up the dualtimer
  hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511

 hw/timer/Makefile.objs                 |   1 +
 include/hw/arm/iotkit.h                |   3 +-
 include/hw/misc/mps2-fpgaio.h          |  10 +
 include/hw/timer/cmsdk-apb-dualtimer.h |  72 ++++
 hw/arm/iotkit.c                        |   8 +-
 hw/arm/mps2.c                          |  11 +
 hw/misc/mps2-fpgaio.c                  | 146 ++++++-
 hw/timer/cmsdk-apb-dualtimer.c         | 515 +++++++++++++++++++++++++
 MAINTAINERS                            |   2 +
 default-configs/arm-softmmu.mak        |   1 +
 hw/timer/trace-events                  |   5 +
 11 files changed, 767 insertions(+), 7 deletions(-)
 create mode 100644 include/hw/timer/cmsdk-apb-dualtimer.h
 create mode 100644 hw/timer/cmsdk-apb-dualtimer.c

-- 
2.17.1

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

* [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
@ 2018-07-30 16:24 ` Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER Peter Maydell
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2018-07-30 16:24 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The MPS2 FPGAIO block includes some simple free-running counters.
Implement these.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/misc/mps2-fpgaio.h |  4 +++
 hw/misc/mps2-fpgaio.c         | 53 ++++++++++++++++++++++++++++++++++-
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
index eedf17ebc6d..ec057d38c76 100644
--- a/include/hw/misc/mps2-fpgaio.h
+++ b/include/hw/misc/mps2-fpgaio.h
@@ -38,6 +38,10 @@ typedef struct {
     uint32_t misc;
 
     uint32_t prescale_clk;
+
+    /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
+    int64_t clk1hz_tick_offset;
+    int64_t clk100hz_tick_offset;
 } MPS2FPGAIO;
 
 #endif
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index 7394a057d82..bbc28f641f0 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -22,6 +22,7 @@
 #include "hw/sysbus.h"
 #include "hw/registerfields.h"
 #include "hw/misc/mps2-fpgaio.h"
+#include "qemu/timer.h"
 
 REG32(LED0, 0)
 REG32(BUTTON, 8)
@@ -32,10 +33,21 @@ REG32(PRESCALE, 0x1c)
 REG32(PSCNTR, 0x20)
 REG32(MISC, 0x4c)
 
+static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
+{
+    return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND);
+}
+
+static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
+{
+    return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
+}
+
 static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
 {
     MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
     uint64_t r;
+    int64_t now;
 
     switch (offset) {
     case A_LED0:
@@ -54,10 +66,15 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
         r = s->misc;
         break;
     case A_CLK1HZ:
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1);
+        break;
     case A_CLK100HZ:
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
+        break;
     case A_COUNTER:
     case A_PSCNTR:
-        /* These are all upcounters of various frequencies. */
         qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
         r = 0;
         break;
@@ -76,6 +93,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
                               unsigned size)
 {
     MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
+    int64_t now;
 
     trace_mps2_fpgaio_write(offset, value, size);
 
@@ -100,6 +118,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
                       "MPS2 FPGAIO: MISC control bits unimplemented\n");
         s->misc = value;
         break;
+    case A_CLK1HZ:
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1);
+        break;
+    case A_CLK100HZ:
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
@@ -116,11 +142,14 @@ static const MemoryRegionOps mps2_fpgaio_ops = {
 static void mps2_fpgaio_reset(DeviceState *dev)
 {
     MPS2FPGAIO *s = MPS2_FPGAIO(dev);
+    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 
     trace_mps2_fpgaio_reset();
     s->led0 = 0;
     s->prescale = 0;
     s->misc = 0;
+    s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
+    s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
 }
 
 static void mps2_fpgaio_init(Object *obj)
@@ -133,6 +162,24 @@ static void mps2_fpgaio_init(Object *obj)
     sysbus_init_mmio(sbd, &s->iomem);
 }
 
+static bool mps2_fpgaio_counters_needed(void *opaque)
+{
+    /* Currently vmstate.c insists all subsections have a 'needed' function */
+    return true;
+}
+
+static const VMStateDescription mps2_fpgaio_counters_vmstate = {
+    .name = "mps2-fpgaio/counters",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = mps2_fpgaio_counters_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
+        VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription mps2_fpgaio_vmstate = {
     .name = "mps2-fpgaio",
     .version_id = 1,
@@ -142,6 +189,10 @@ static const VMStateDescription mps2_fpgaio_vmstate = {
         VMSTATE_UINT32(prescale, MPS2FPGAIO),
         VMSTATE_UINT32(misc, MPS2FPGAIO),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &mps2_fpgaio_counters_vmstate,
+        NULL
     }
 };
 
-- 
2.17.1

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

* [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters Peter Maydell
@ 2018-07-30 16:24 ` Peter Maydell
  2018-07-30 22:09   ` Alistair Francis
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 3/5] hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module Peter Maydell
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: Peter Maydell @ 2018-07-30 16:24 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

In the MPS2 FPGAIO, PSCNTR is a free-running downcounter with
a reload value configured via the PRESCALE register, and
COUNTER counts up by 1 every time PSCNTR reaches zero.
Implement these counters.

We can just increment the counters migration subsection's
version ID because we only added it in the previous commit,
so no released QEMU versions will be using it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/misc/mps2-fpgaio.h |  6 +++
 hw/misc/mps2-fpgaio.c         | 97 +++++++++++++++++++++++++++++++++--
 2 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
index ec057d38c76..69e265cd4b2 100644
--- a/include/hw/misc/mps2-fpgaio.h
+++ b/include/hw/misc/mps2-fpgaio.h
@@ -37,6 +37,12 @@ typedef struct {
     uint32_t prescale;
     uint32_t misc;
 
+    /* QEMU_CLOCK_VIRTUAL time at which counter and pscntr were last synced */
+    int64_t pscntr_sync_ticks;
+    /* Values of COUNTER and PSCNTR at time pscntr_sync_ticks */
+    uint32_t counter;
+    uint32_t pscntr;
+
     uint32_t prescale_clk;
 
     /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index bbc28f641f0..5cf10ebd66a 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -43,6 +43,77 @@ static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
     return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
 }
 
+static void resync_counter(MPS2FPGAIO *s)
+{
+    /*
+     * Update s->counter and s->pscntr to their true current values
+     * by calculating how many times PSCNTR has ticked since the
+     * last time we did a resync.
+     */
+    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    int64_t elapsed = now - s->pscntr_sync_ticks;
+
+    /*
+     * Round elapsed down to a whole number of PSCNTR ticks, so we don't
+     * lose time if we do multiple resyncs in a single tick.
+     */
+    uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND);
+
+    /*
+     * Work out what PSCNTR and COUNTER have moved to. We assume that
+     * PSCNTR reloads from PRESCALE one tick-period after it hits zero,
+     * and that COUNTER increments at the same moment.
+     */
+    if (ticks == 0) {
+        /* We haven't ticked since the last time we were asked */
+        return;
+    } else if (ticks < s->pscntr) {
+        /* We haven't yet reached zero, just reduce the PSCNTR */
+        s->pscntr -= ticks;
+    } else {
+        if (s->prescale == 0) {
+            /*
+             * If the reload value is zero then the PSCNTR will stick
+             * at zero once it reaches it, and so we will increment
+             * COUNTER every tick after that.
+             */
+            s->counter += ticks - s->pscntr;
+            s->pscntr = 0;
+        } else {
+            /*
+             * This is the complicated bit. This ASCII art diagram gives an
+             * example with PRESCALE==5 PSCNTR==7:
+             *
+             * ticks  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
+             * PSCNTR 7  6  5  4  3  2  1  0  5  4  3  2  1  0  5
+             * cinc                           1                 2
+             * y            0  1  2  3  4  5  6  7  8  9 10 11 12
+             * x            0  1  2  3  4  5  0  1  2  3  4  5  0
+             *
+             * where x = y % (s->prescale + 1)
+             * and so PSCNTR = s->prescale - x
+             * and COUNTER is incremented by y / (s->prescale + 1)
+             *
+             * The case where PSCNTR < PRESCALE works out the same,
+             * though we must be careful to calculate y as 64-bit unsigned
+             * for all parts of the expression.
+             * y < 0 is not possible because that implies ticks < s->pscntr.
+             */
+            uint64_t y = ticks - s->pscntr + s->prescale;
+            s->pscntr = s->prescale - (y % (s->prescale + 1));
+            s->counter += y / (s->prescale + 1);
+        }
+    }
+
+    /*
+     * Only advance the sync time to the timestamp of the last PSCNTR tick,
+     * not all the way to 'now', so we don't lose time if we do multiple
+     * resyncs in a single tick.
+     */
+    s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND,
+                                     s->prescale_clk);
+}
+
 static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
 {
     MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
@@ -74,9 +145,12 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
         r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
         break;
     case A_COUNTER:
+        resync_counter(s);
+        r = s->counter;
+        break;
     case A_PSCNTR:
-        qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
-        r = 0;
+        resync_counter(s);
+        r = s->pscntr;
         break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
@@ -107,6 +181,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
         s->led0 = value & 0x3;
         break;
     case A_PRESCALE:
+        resync_counter(s);
         s->prescale = value;
         break;
     case A_MISC:
@@ -126,6 +201,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
         s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
         break;
+    case A_COUNTER:
+        resync_counter(s);
+        s->counter = value;
+        break;
+    case A_PSCNTR:
+        resync_counter(s);
+        s->pscntr = value;
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
@@ -150,6 +233,9 @@ static void mps2_fpgaio_reset(DeviceState *dev)
     s->misc = 0;
     s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
     s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
+    s->counter = 0;
+    s->pscntr = 0;
+    s->pscntr_sync_ticks = now;
 }
 
 static void mps2_fpgaio_init(Object *obj)
@@ -170,12 +256,15 @@ static bool mps2_fpgaio_counters_needed(void *opaque)
 
 static const VMStateDescription mps2_fpgaio_counters_vmstate = {
     .name = "mps2-fpgaio/counters",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .needed = mps2_fpgaio_counters_needed,
     .fields = (VMStateField[]) {
         VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
         VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
+        VMSTATE_UINT32(counter, MPS2FPGAIO),
+        VMSTATE_UINT32(pscntr, MPS2FPGAIO),
+        VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
2.17.1

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

* [Qemu-devel] [PATCH 3/5] hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER Peter Maydell
@ 2018-07-30 16:24 ` Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 4/5] hw/arm/iotkit: Wire up the dualtimer Peter Maydell
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2018-07-30 16:24 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The Arm Cortex-M System Design Kit includes a "dual-input timer module"
which combines two programmable down-counters. Implement a model
of this device.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/Makefile.objs                 |   1 +
 include/hw/timer/cmsdk-apb-dualtimer.h |  72 ++++
 hw/timer/cmsdk-apb-dualtimer.c         | 515 +++++++++++++++++++++++++
 MAINTAINERS                            |   2 +
 default-configs/arm-softmmu.mak        |   1 +
 hw/timer/trace-events                  |   5 +
 6 files changed, 596 insertions(+)
 create mode 100644 include/hw/timer/cmsdk-apb-dualtimer.h
 create mode 100644 hw/timer/cmsdk-apb-dualtimer.c

diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index e16b2b913ce..b32194d153d 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -44,4 +44,5 @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
 
 common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
 common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
+common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o
 common-obj-$(CONFIG_MSF2) += mss-timer.o
diff --git a/include/hw/timer/cmsdk-apb-dualtimer.h b/include/hw/timer/cmsdk-apb-dualtimer.h
new file mode 100644
index 00000000000..9843a9dbb1d
--- /dev/null
+++ b/include/hw/timer/cmsdk-apb-dualtimer.h
@@ -0,0 +1,72 @@
+/*
+ * ARM CMSDK APB dual-timer emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 or
+ *  (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "APB dual-input timer" which is part of the Cortex-M
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ *
+ * QEMU interface:
+ *  + QOM property "pclk-frq": frequency at which the timer is clocked
+ *  + sysbus MMIO region 0: the register bank
+ *  + sysbus IRQ 0: combined timer interrupt TIMINTC
+ *  + sysbus IRO 1: timer block 1 interrupt TIMINT1
+ *  + sysbus IRQ 2: timer block 2 interrupt TIMINT2
+ */
+
+#ifndef CMSDK_APB_DUALTIMER_H
+#define CMSDK_APB_DUALTIMER_H
+
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+
+#define TYPE_CMSDK_APB_DUALTIMER "cmsdk-apb-dualtimer"
+#define CMSDK_APB_DUALTIMER(obj) OBJECT_CHECK(CMSDKAPBDualTimer, (obj), \
+                                              TYPE_CMSDK_APB_DUALTIMER)
+
+typedef struct CMSDKAPBDualTimer CMSDKAPBDualTimer;
+
+/* One of the two identical timer modules in the dual-timer module */
+typedef struct CMSDKAPBDualTimerModule {
+    CMSDKAPBDualTimer *parent;
+    struct ptimer_state *timer;
+    qemu_irq timerint;
+    /*
+     * We must track the guest LOAD and VALUE register state by hand
+     * rather than leaving this state only in the ptimer limit/count,
+     * because if CONTROL.SIZE is 0 then only the low 16 bits of the
+     * counter actually counts, but the high half is still guest
+     * accessible.
+     */
+    uint32_t load;
+    uint32_t value;
+    uint32_t control;
+    uint32_t intstatus;
+} CMSDKAPBDualTimerModule;
+
+#define CMSDK_APB_DUALTIMER_NUM_MODULES 2
+
+struct CMSDKAPBDualTimer {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion iomem;
+    qemu_irq timerintc;
+    uint32_t pclk_frq;
+
+    CMSDKAPBDualTimerModule timermod[CMSDK_APB_DUALTIMER_NUM_MODULES];
+    uint32_t timeritcr;
+    uint32_t timeritop;
+};
+
+#endif
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
new file mode 100644
index 00000000000..4b005e28136
--- /dev/null
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -0,0 +1,515 @@
+/*
+ * ARM CMSDK APB dual-timer emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 or
+ *  (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "APB dual-input timer" which is part of the Cortex-M
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "qemu/main-loop.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/timer/cmsdk-apb-dualtimer.h"
+
+REG32(TIMER1LOAD, 0x0)
+REG32(TIMER1VALUE, 0x4)
+REG32(TIMER1CONTROL, 0x8)
+    FIELD(CONTROL, ONESHOT, 0, 1)
+    FIELD(CONTROL, SIZE, 1, 1)
+    FIELD(CONTROL, PRESCALE, 2, 2)
+    FIELD(CONTROL, INTEN, 5, 1)
+    FIELD(CONTROL, MODE, 6, 1)
+    FIELD(CONTROL, ENABLE, 7, 1)
+#define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
+                              R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
+                              R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
+REG32(TIMER1INTCLR, 0xc)
+REG32(TIMER1RIS, 0x10)
+REG32(TIMER1MIS, 0x14)
+REG32(TIMER1BGLOAD, 0x18)
+REG32(TIMER2LOAD, 0x20)
+REG32(TIMER2VALUE, 0x24)
+REG32(TIMER2CONTROL, 0x28)
+REG32(TIMER2INTCLR, 0x2c)
+REG32(TIMER2RIS, 0x30)
+REG32(TIMER2MIS, 0x34)
+REG32(TIMER2BGLOAD, 0x38)
+REG32(TIMERITCR, 0xf00)
+    FIELD(TIMERITCR, ENABLE, 0, 1)
+#define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
+REG32(TIMERITOP, 0xf04)
+    FIELD(TIMERITOP, TIMINT1, 0, 1)
+    FIELD(TIMERITOP, TIMINT2, 1, 1)
+#define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
+                                R_TIMERITOP_TIMINT2_MASK)
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* PID/CID values */
+static const int timer_id[] = {
+    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+    0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
+    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
+{
+    /* Return masked interrupt status for the timer module */
+    return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
+}
+
+static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
+{
+    bool timint1, timint2, timintc;
+
+    if (s->timeritcr) {
+        /* Integration test mode: outputs driven directly from TIMERITOP bits */
+        timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
+        timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
+    } else {
+        timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
+        timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
+    }
+
+    timintc = timint1 || timint2;
+
+    qemu_set_irq(s->timermod[0].timerint, timint1);
+    qemu_set_irq(s->timermod[1].timerint, timint2);
+    qemu_set_irq(s->timerintc, timintc);
+}
+
+static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
+                                             uint32_t newctrl)
+{
+    /* Handle a write to the CONTROL register */
+    uint32_t changed;
+
+    newctrl &= R_CONTROL_VALID_MASK;
+
+    changed = m->control ^ newctrl;
+
+    if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
+        /* ENABLE cleared, stop timer before any further changes */
+        ptimer_stop(m->timer);
+    }
+
+    if (changed & R_CONTROL_PRESCALE_MASK) {
+        int divisor;
+
+        switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
+        case 0:
+            divisor = 1;
+            break;
+        case 1:
+            divisor = 16;
+            break;
+        case 2:
+            divisor = 256;
+            break;
+        case 3:
+            /* UNDEFINED; complain, and arbitrarily treat like 2 */
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
+                          " is undefined behaviour\n");
+            divisor = 256;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor);
+    }
+
+    if (changed & R_CONTROL_MODE_MASK) {
+        uint32_t load;
+        if (newctrl & R_CONTROL_MODE_MASK) {
+            /* Periodic: the limit is the LOAD register value */
+            load = m->load;
+        } else {
+            /* Free-running: counter wraps around */
+            load = ptimer_get_limit(m->timer);
+            if (!(m->control & R_CONTROL_SIZE_MASK)) {
+                load = deposit32(load, 16, 16, extract32(m->load, 16, 16));
+            }
+            m->load = load;
+            load = 0xffffffff;
+        }
+        if (!(m->control & R_CONTROL_SIZE_MASK)) {
+            load &= 0xffff;
+        }
+        ptimer_set_limit(m->timer, load, 0);
+    }
+
+    if (changed & R_CONTROL_SIZE_MASK) {
+        /* Timer switched between 16 and 32 bit count */
+        uint32_t value, load;
+
+        value = ptimer_get_count(m->timer);
+        load = ptimer_get_limit(m->timer);
+        if (newctrl & R_CONTROL_SIZE_MASK) {
+            /* 16 -> 32, top half of VALUE is in struct field */
+            value = deposit32(value, 16, 16, extract32(m->value, 16, 16));
+        } else {
+            /* 32 -> 16: save top half to struct field and truncate */
+            m->value = value;
+            value &= 0xffff;
+        }
+
+        if (newctrl & R_CONTROL_MODE_MASK) {
+            /* Periodic, timer limit has LOAD value */
+            if (newctrl & R_CONTROL_SIZE_MASK) {
+                load = deposit32(load, 16, 16, extract32(m->load, 16, 16));
+            } else {
+                m->load = load;
+                load &= 0xffff;
+            }
+        } else {
+            /* Free-running, timer limit is set to give wraparound */
+            if (newctrl & R_CONTROL_SIZE_MASK) {
+                load = 0xffffffff;
+            } else {
+                load = 0xffff;
+            }
+        }
+        ptimer_set_count(m->timer, value);
+        ptimer_set_limit(m->timer, load, 0);
+    }
+
+    if (newctrl & R_CONTROL_ENABLE_MASK) {
+        /*
+         * ENABLE is set; start the timer after all other changes.
+         * We start it even if the ENABLE bit didn't actually change,
+         * in case the timer was an expired one-shot timer that has
+         * now been changed into a free-running or periodic timer.
+         */
+        ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
+    }
+
+    m->control = newctrl;
+}
+
+static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
+                                          unsigned size)
+{
+    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
+    uint64_t r;
+
+    if (offset >= A_TIMERITCR) {
+        switch (offset) {
+        case A_TIMERITCR:
+            r = s->timeritcr;
+            break;
+        case A_PID4 ... A_CID3:
+            r = timer_id[(offset - A_PID4) / 4];
+            break;
+        default:
+        bad_offset:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "CMSDK APB dual-timer read: bad offset %x\n",
+                          (int) offset);
+            r = 0;
+            break;
+        }
+    } else {
+        int timer = offset >> 5;
+        CMSDKAPBDualTimerModule *m;
+
+        if (timer >= ARRAY_SIZE(s->timermod)) {
+            goto bad_offset;
+        }
+
+        m = &s->timermod[timer];
+
+        switch (offset & 0x1F) {
+        case A_TIMER1LOAD:
+        case A_TIMER1BGLOAD:
+            if (m->control & R_CONTROL_MODE_MASK) {
+                /*
+                 * Periodic: the ptimer limit is the LOAD register value, (or
+                 * just the low 16 bits of it if the timer is in 16-bit mode)
+                 */
+                r = ptimer_get_limit(m->timer);
+                if (!(m->control & R_CONTROL_SIZE_MASK)) {
+                    r = deposit32(r, 16, 16, extract32(m->load, 16, 16));
+                }
+            } else {
+                /* Free-running: LOAD register value is just in m->load */
+                r = m->load;
+            }
+            break;
+        case A_TIMER1VALUE:
+            r = ptimer_get_count(m->timer);
+            if (!(m->control & R_CONTROL_SIZE_MASK)) {
+                r = deposit32(r, 16, 16, extract32(m->value, 16, 16));
+            }
+            break;
+        case A_TIMER1CONTROL:
+            r = m->control;
+            break;
+        case A_TIMER1RIS:
+            r = m->intstatus;
+            break;
+        case A_TIMER1MIS:
+            r = cmsdk_dualtimermod_intstatus(m);
+            break;
+        default:
+            goto bad_offset;
+        }
+    }
+
+    trace_cmsdk_apb_dualtimer_read(offset, r, size);
+    return r;
+}
+
+static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
+                                       uint64_t value, unsigned size)
+{
+    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
+
+    trace_cmsdk_apb_dualtimer_write(offset, value, size);
+
+    if (offset >= A_TIMERITCR) {
+        switch (offset) {
+        case A_TIMERITCR:
+            s->timeritcr = value & R_TIMERITCR_VALID_MASK;
+            cmsdk_apb_dualtimer_update(s);
+        case A_TIMERITOP:
+            s->timeritop = value & R_TIMERITOP_VALID_MASK;
+            cmsdk_apb_dualtimer_update(s);
+        default:
+        bad_offset:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "CMSDK APB dual-timer write: bad offset %x\n",
+                          (int) offset);
+            break;
+        }
+    } else {
+        int timer = offset >> 5;
+        CMSDKAPBDualTimerModule *m;
+
+        if (timer >= ARRAY_SIZE(s->timermod)) {
+            goto bad_offset;
+        }
+
+        m = &s->timermod[timer];
+
+        switch (offset & 0x1F) {
+        case A_TIMER1LOAD:
+            /* Set the limit, and immediately reload the count from it */
+            m->load = value;
+            m->value = value;
+            if (!(m->control & R_CONTROL_SIZE_MASK)) {
+                value &= 0xffff;
+            }
+            if (!(m->control & R_CONTROL_MODE_MASK)) {
+                /*
+                 * In free-running mode this won't set the limit but will
+                 * still change the current count value.
+                 */
+                ptimer_set_count(m->timer, value);
+            } else {
+                if (!value) {
+                    ptimer_stop(m->timer);
+                }
+                ptimer_set_limit(m->timer, value, 1);
+                if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
+                    /* Force possibly-expired oneshot timer to restart */
+                    ptimer_run(m->timer, 1);
+                }
+            }
+            break;
+        case A_TIMER1BGLOAD:
+            /* Set the limit, but not the current count */
+            m->load = value;
+            if (!(m->control & R_CONTROL_MODE_MASK)) {
+                /* In free-running mode there is no limit */
+                break;
+            }
+            if (!(m->control & R_CONTROL_SIZE_MASK)) {
+                value &= 0xffff;
+            }
+            ptimer_set_limit(m->timer, value, 0);
+            break;
+        case A_TIMER1CONTROL:
+            cmsdk_dualtimermod_write_control(m, value);
+            cmsdk_apb_dualtimer_update(s);
+            break;
+        case A_TIMER1INTCLR:
+            m->intstatus = 0;
+            cmsdk_apb_dualtimer_update(s);
+            break;
+        default:
+            goto bad_offset;
+        }
+    }
+}
+
+static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
+    .read = cmsdk_apb_dualtimer_read,
+    .write = cmsdk_apb_dualtimer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    /* byte/halfword accesses are just zero-padded on reads and writes */
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+};
+
+static void cmsdk_dualtimermod_tick(void *opaque)
+{
+    CMSDKAPBDualTimerModule *m = opaque;
+
+    m->intstatus = 1;
+    cmsdk_apb_dualtimer_update(m->parent);
+}
+
+static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
+{
+    m->control = R_CONTROL_INTEN_MASK;
+    m->intstatus = 0;
+    m->load = 0;
+    m->value = 0xffffffff;
+    ptimer_stop(m->timer);
+    /*
+     * We start in free-running mode, with VALUE at 0xffffffff, and
+     * in 16-bit counter mode. This means that the ptimer count and
+     * limit must both be set to 0xffff, so we wrap at 16 bits.
+     */
+    ptimer_set_limit(m->timer, 0xffff, 1);
+    ptimer_set_freq(m->timer, m->parent->pclk_frq);
+}
+
+static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
+{
+    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
+    int i;
+
+    trace_cmsdk_apb_dualtimer_reset();
+
+    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
+        cmsdk_dualtimermod_reset(&s->timermod[i]);
+    }
+    s->timeritcr = 0;
+    s->timeritop = 0;
+}
+
+static void cmsdk_apb_dualtimer_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
+    int i;
+
+    memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
+                          s, "cmsdk-apb-dualtimer", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->timerintc);
+
+    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
+        sysbus_init_irq(sbd, &s->timermod[i].timerint);
+    }
+}
+
+static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
+{
+    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
+    int i;
+
+    if (s->pclk_frq == 0) {
+        error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
+        CMSDKAPBDualTimerModule *m = &s->timermod[i];
+        QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m);
+
+        m->parent = s;
+        m->timer = ptimer_init(bh,
+                               PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
+                               PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
+                               PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+                               PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+    }
+}
+
+static const VMStateDescription cmsdk_dualtimermod_vmstate = {
+    .name = "cmsdk-apb-dualtimer-module",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
+        VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
+        VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
+        VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
+        VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
+    .name = "cmsdk-apb-dualtimer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
+                             CMSDK_APB_DUALTIMER_NUM_MODULES,
+                             1, cmsdk_dualtimermod_vmstate,
+                             CMSDKAPBDualTimerModule),
+        VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
+        VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property cmsdk_apb_dualtimer_properties[] = {
+    DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = cmsdk_apb_dualtimer_realize;
+    dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
+    dc->reset = cmsdk_apb_dualtimer_reset;
+    dc->props = cmsdk_apb_dualtimer_properties;
+}
+
+static const TypeInfo cmsdk_apb_dualtimer_info = {
+    .name = TYPE_CMSDK_APB_DUALTIMER,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(CMSDKAPBDualTimer),
+    .instance_init = cmsdk_apb_dualtimer_init,
+    .class_init = cmsdk_apb_dualtimer_class_init,
+};
+
+static void cmsdk_apb_dualtimer_register_types(void)
+{
+    type_register_static(&cmsdk_apb_dualtimer_info);
+}
+
+type_init(cmsdk_apb_dualtimer_register_types);
diff --git a/MAINTAINERS b/MAINTAINERS
index 666e9368126..2c1a55ca207 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -453,6 +453,8 @@ F: hw/timer/pl031.c
 F: include/hw/arm/primecell.h
 F: hw/timer/cmsdk-apb-timer.c
 F: include/hw/timer/cmsdk-apb-timer.h
+F: hw/timer/cmsdk-apb-dualtimer.c
+F: include/hw/timer/cmsdk-apb-dualtimer.h
 F: hw/char/cmsdk-apb-uart.c
 F: include/hw/char/cmsdk-apb-uart.h
 F: hw/misc/tz-ppc.c
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 834d45cfaf9..046e8903839 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -103,6 +103,7 @@ CONFIG_STM32F2XX_SPI=y
 CONFIG_STM32F205_SOC=y
 
 CONFIG_CMSDK_APB_TIMER=y
+CONFIG_CMSDK_APB_DUALTIMER=y
 CONFIG_CMSDK_APB_UART=y
 
 CONFIG_MPS2_FPGAIO=y
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index e6e042fddb7..fa4213df5be 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -61,5 +61,10 @@ cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB t
 cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
 cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset"
 
+# hw/timer/cmsdk_apb_dualtimer.c
+cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
+
 # hw/timer/xlnx-zynqmp-rtc.c
 xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
-- 
2.17.1

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

* [Qemu-devel] [PATCH 4/5] hw/arm/iotkit: Wire up the dualtimer
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
                   ` (2 preceding siblings ...)
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 3/5] hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module Peter Maydell
@ 2018-07-30 16:24 ` Peter Maydell
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 5/5] hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511 Peter Maydell
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2018-07-30 16:24 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

Now we have a model of the CMSDK dual timer, we can wire it
up in the IoTKit.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h | 3 ++-
 hw/arm/iotkit.c         | 8 +++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index 2cddde55dd1..3e6d806e352 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -56,6 +56,7 @@
 #include "hw/misc/tz-ppc.h"
 #include "hw/misc/tz-mpc.h"
 #include "hw/timer/cmsdk-apb-timer.h"
+#include "hw/timer/cmsdk-apb-dualtimer.h"
 #include "hw/misc/unimp.h"
 #include "hw/or-irq.h"
 #include "hw/core/split-irq.h"
@@ -87,7 +88,7 @@ typedef struct IoTKit {
     SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
     qemu_or_irq mpc_irq_orgate;
 
-    UnimplementedDeviceState dualtimer;
+    CMSDKAPBDualTimer dualtimer;
     UnimplementedDeviceState s32ktimer;
 
     MemoryRegion container;
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 8cadc8b1608..130d013909e 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -139,7 +139,7 @@ static void iotkit_init(Object *obj)
     sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
                           TYPE_CMSDK_APB_TIMER);
     sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
-                          TYPE_UNIMPLEMENTED_DEVICE);
+                          TYPE_CMSDK_APB_DUALTIMER);
     object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
                             sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
                             &error_abort, NULL);
@@ -390,13 +390,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer");
-    qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000);
+
+    qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
     object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err);
     if (err) {
         error_propagate(errp, err);
         return;
     }
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
+                       qdev_get_gpio_in(DEVICE(&s->armv7m), 5));
     mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
     object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
     if (err) {
-- 
2.17.1

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

* [Qemu-devel] [PATCH 5/5] hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
                   ` (3 preceding siblings ...)
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 4/5] hw/arm/iotkit: Wire up the dualtimer Peter Maydell
@ 2018-07-30 16:24 ` Peter Maydell
  2018-07-30 21:00 ` [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer no-reply
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2018-07-30 16:24 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The MPS2 FPGA images for the Cortex-M3 (mps2-an385 and mps2-511)
both include a CMSDK dual-timer module. Wire this up.

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

diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index c3946da3173..b0125ca0ebf 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -34,6 +34,7 @@
 #include "hw/misc/unimp.h"
 #include "hw/char/cmsdk-apb-uart.h"
 #include "hw/timer/cmsdk-apb-timer.h"
+#include "hw/timer/cmsdk-apb-dualtimer.h"
 #include "hw/misc/mps2-scc.h"
 #include "hw/devices.h"
 #include "net/net.h"
@@ -64,6 +65,7 @@ typedef struct {
     MemoryRegion blockram_m3;
     MemoryRegion sram;
     MPS2SCC scc;
+    CMSDKAPBDualTimer dualtimer;
 } MPS2MachineState;
 
 #define TYPE_MPS2_MACHINE "mps2"
@@ -296,6 +298,15 @@ static void mps2_common_init(MachineState *machine)
     cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
     cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ);
 
+    sysbus_init_child_obj(OBJECT(mms), "dualtimer", &mms->dualtimer,
+                          sizeof(mms->dualtimer), TYPE_CMSDK_APB_DUALTIMER);
+    qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ);
+    object_property_set_bool(OBJECT(&mms->dualtimer), true, "realized",
+                             &error_fatal);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
+                       qdev_get_gpio_in(armv7m, 10));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
+
     object_initialize(&mms->scc, sizeof(mms->scc), TYPE_MPS2_SCC);
     sccdev = DEVICE(&mms->scc);
     qdev_set_parent_bus(sccdev, sysbus_get_default());
-- 
2.17.1

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

* Re: [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
                   ` (4 preceding siblings ...)
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 5/5] hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511 Peter Maydell
@ 2018-07-30 21:00 ` no-reply
  2018-07-31  5:26 ` no-reply
  2018-08-16 12:20 ` Peter Maydell
  7 siblings, 0 replies; 10+ messages in thread
From: no-reply @ 2018-07-30 21:00 UTC (permalink / raw)
  To: peter.maydell; +Cc: famz, qemu-arm, qemu-devel, patches

Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20180730162458.23186-1-peter.maydell@linaro.org
Subject: [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
72316845d2 hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511
1e40b97496 hw/arm/iotkit: Wire up the dualtimer
b4970bc615 hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module
222de88154 hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
201fa0eef0 hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters

=== OUTPUT BEGIN ===
Checking PATCH 1/5: hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters...
ERROR: spaces required around that '*' (ctx:VxV)
#131: FILE: hw/misc/mps2-fpgaio.c:193:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 1 errors, 0 warnings, 123 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 2/5: hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER...
Checking PATCH 3/5: hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#50: 
new file mode 100644

total: 0 errors, 1 warnings, 617 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 4/5: hw/arm/iotkit: Wire up the dualtimer...
Checking PATCH 5/5: hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
  2018-07-30 16:24 ` [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER Peter Maydell
@ 2018-07-30 22:09   ` Alistair Francis
  0 siblings, 0 replies; 10+ messages in thread
From: Alistair Francis @ 2018-07-30 22:09 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, qemu-devel@nongnu.org Developers, Patch Tracking

On Mon, Jul 30, 2018 at 9:24 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> In the MPS2 FPGAIO, PSCNTR is a free-running downcounter with
> a reload value configured via the PRESCALE register, and
> COUNTER counts up by 1 every time PSCNTR reaches zero.
> Implement these counters.
>
> We can just increment the counters migration subsection's
> version ID because we only added it in the previous commit,
> so no released QEMU versions will be using it.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  include/hw/misc/mps2-fpgaio.h |  6 +++
>  hw/misc/mps2-fpgaio.c         | 97 +++++++++++++++++++++++++++++++++--
>  2 files changed, 99 insertions(+), 4 deletions(-)
>
> diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
> index ec057d38c76..69e265cd4b2 100644
> --- a/include/hw/misc/mps2-fpgaio.h
> +++ b/include/hw/misc/mps2-fpgaio.h
> @@ -37,6 +37,12 @@ typedef struct {
>      uint32_t prescale;
>      uint32_t misc;
>
> +    /* QEMU_CLOCK_VIRTUAL time at which counter and pscntr were last synced */
> +    int64_t pscntr_sync_ticks;
> +    /* Values of COUNTER and PSCNTR at time pscntr_sync_ticks */
> +    uint32_t counter;
> +    uint32_t pscntr;
> +
>      uint32_t prescale_clk;
>
>      /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
> diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
> index bbc28f641f0..5cf10ebd66a 100644
> --- a/hw/misc/mps2-fpgaio.c
> +++ b/hw/misc/mps2-fpgaio.c
> @@ -43,6 +43,77 @@ static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
>      return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
>  }
>
> +static void resync_counter(MPS2FPGAIO *s)
> +{
> +    /*
> +     * Update s->counter and s->pscntr to their true current values
> +     * by calculating how many times PSCNTR has ticked since the
> +     * last time we did a resync.
> +     */
> +    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    int64_t elapsed = now - s->pscntr_sync_ticks;
> +
> +    /*
> +     * Round elapsed down to a whole number of PSCNTR ticks, so we don't
> +     * lose time if we do multiple resyncs in a single tick.
> +     */
> +    uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND);
> +
> +    /*
> +     * Work out what PSCNTR and COUNTER have moved to. We assume that
> +     * PSCNTR reloads from PRESCALE one tick-period after it hits zero,
> +     * and that COUNTER increments at the same moment.
> +     */
> +    if (ticks == 0) {
> +        /* We haven't ticked since the last time we were asked */
> +        return;
> +    } else if (ticks < s->pscntr) {
> +        /* We haven't yet reached zero, just reduce the PSCNTR */
> +        s->pscntr -= ticks;
> +    } else {
> +        if (s->prescale == 0) {
> +            /*
> +             * If the reload value is zero then the PSCNTR will stick
> +             * at zero once it reaches it, and so we will increment
> +             * COUNTER every tick after that.
> +             */
> +            s->counter += ticks - s->pscntr;
> +            s->pscntr = 0;
> +        } else {
> +            /*
> +             * This is the complicated bit. This ASCII art diagram gives an
> +             * example with PRESCALE==5 PSCNTR==7:
> +             *
> +             * ticks  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
> +             * PSCNTR 7  6  5  4  3  2  1  0  5  4  3  2  1  0  5
> +             * cinc                           1                 2
> +             * y            0  1  2  3  4  5  6  7  8  9 10 11 12
> +             * x            0  1  2  3  4  5  0  1  2  3  4  5  0
> +             *
> +             * where x = y % (s->prescale + 1)
> +             * and so PSCNTR = s->prescale - x
> +             * and COUNTER is incremented by y / (s->prescale + 1)
> +             *
> +             * The case where PSCNTR < PRESCALE works out the same,
> +             * though we must be careful to calculate y as 64-bit unsigned
> +             * for all parts of the expression.
> +             * y < 0 is not possible because that implies ticks < s->pscntr.
> +             */
> +            uint64_t y = ticks - s->pscntr + s->prescale;
> +            s->pscntr = s->prescale - (y % (s->prescale + 1));
> +            s->counter += y / (s->prescale + 1);
> +        }
> +    }
> +
> +    /*
> +     * Only advance the sync time to the timestamp of the last PSCNTR tick,
> +     * not all the way to 'now', so we don't lose time if we do multiple
> +     * resyncs in a single tick.
> +     */
> +    s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND,
> +                                     s->prescale_clk);
> +}
> +
>  static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
>  {
>      MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
> @@ -74,9 +145,12 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
>          r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
>          break;
>      case A_COUNTER:
> +        resync_counter(s);
> +        r = s->counter;
> +        break;
>      case A_PSCNTR:
> -        qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
> -        r = 0;
> +        resync_counter(s);
> +        r = s->pscntr;
>          break;
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR,
> @@ -107,6 +181,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
>          s->led0 = value & 0x3;
>          break;
>      case A_PRESCALE:
> +        resync_counter(s);
>          s->prescale = value;
>          break;
>      case A_MISC:
> @@ -126,6 +201,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
>          now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>          s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
>          break;
> +    case A_COUNTER:
> +        resync_counter(s);
> +        s->counter = value;
> +        break;
> +    case A_PSCNTR:
> +        resync_counter(s);
> +        s->pscntr = value;
> +        break;
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
> @@ -150,6 +233,9 @@ static void mps2_fpgaio_reset(DeviceState *dev)
>      s->misc = 0;
>      s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
>      s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
> +    s->counter = 0;
> +    s->pscntr = 0;
> +    s->pscntr_sync_ticks = now;
>  }
>
>  static void mps2_fpgaio_init(Object *obj)
> @@ -170,12 +256,15 @@ static bool mps2_fpgaio_counters_needed(void *opaque)
>
>  static const VMStateDescription mps2_fpgaio_counters_vmstate = {
>      .name = "mps2-fpgaio/counters",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .needed = mps2_fpgaio_counters_needed,
>      .fields = (VMStateField[]) {
>          VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
>          VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
> +        VMSTATE_UINT32(counter, MPS2FPGAIO),
> +        VMSTATE_UINT32(pscntr, MPS2FPGAIO),
> +        VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO),
>          VMSTATE_END_OF_LIST()
>      }
>  };
> --
> 2.17.1
>
>

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

* Re: [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
                   ` (5 preceding siblings ...)
  2018-07-30 21:00 ` [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer no-reply
@ 2018-07-31  5:26 ` no-reply
  2018-08-16 12:20 ` Peter Maydell
  7 siblings, 0 replies; 10+ messages in thread
From: no-reply @ 2018-07-31  5:26 UTC (permalink / raw)
  To: peter.maydell; +Cc: famz, qemu-arm, qemu-devel, patches

Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20180730162458.23186-1-peter.maydell@linaro.org
Subject: [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
ddb70544a8 hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511
bdb50460f4 hw/arm/iotkit: Wire up the dualtimer
008a768e12 hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module
5a008a3545 hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
752c65591e hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters

=== OUTPUT BEGIN ===
Checking PATCH 1/5: hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters...
ERROR: spaces required around that '*' (ctx:VxV)
#131: FILE: hw/misc/mps2-fpgaio.c:193:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 1 errors, 0 warnings, 123 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 2/5: hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER...
Checking PATCH 3/5: hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#50: 
new file mode 100644

total: 0 errors, 1 warnings, 617 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 4/5: hw/arm/iotkit: Wire up the dualtimer...
Checking PATCH 5/5: hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer
  2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
                   ` (6 preceding siblings ...)
  2018-07-31  5:26 ` no-reply
@ 2018-08-16 12:20 ` Peter Maydell
  7 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2018-08-16 12:20 UTC (permalink / raw)
  To: qemu-arm, QEMU Developers; +Cc: patches

Ping? Patch 2 has been reviewed but the rest are still waiting.

thanks
-- PMM

On 30 July 2018 at 17:24, Peter Maydell <peter.maydell@linaro.org> wrote:
> This patchset adds some missing timer and counter devices
> to the MPS2 boards:
>
>  * the MPS2 "fpgaio" register bank includes some registers
>    which provide various kinds of free-running counter
>  * the boards have an instance fo the CMSDK "dual timer module"
>
> Together these are sufficient for QEMU's mps2-an505
> emulation to pass the "timer test" subsection of the
> self-test program which can be found (behind a clickthrough
> EULA) in the Cortex-M33_IoT_kit_2_0.zip at:
>  https://developer.arm.com/products/system-design/development-boards/fpga-prototyping-boards/download-fpga-images
>
> The dual-timer patch ended up a bit big; I can try to split
> that up if people would prefer that for review.
>
> thanks
> -- PMM
>
> Peter Maydell (5):
>   hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters
>   hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
>   hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module
>   hw/arm/iotkit: Wire up the dualtimer
>   hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511
>
>  hw/timer/Makefile.objs                 |   1 +
>  include/hw/arm/iotkit.h                |   3 +-
>  include/hw/misc/mps2-fpgaio.h          |  10 +
>  include/hw/timer/cmsdk-apb-dualtimer.h |  72 ++++
>  hw/arm/iotkit.c                        |   8 +-
>  hw/arm/mps2.c                          |  11 +
>  hw/misc/mps2-fpgaio.c                  | 146 ++++++-
>  hw/timer/cmsdk-apb-dualtimer.c         | 515 +++++++++++++++++++++++++
>  MAINTAINERS                            |   2 +
>  default-configs/arm-softmmu.mak        |   1 +
>  hw/timer/trace-events                  |   5 +
>  11 files changed, 767 insertions(+), 7 deletions(-)
>  create mode 100644 include/hw/timer/cmsdk-apb-dualtimer.h
>  create mode 100644 hw/timer/cmsdk-apb-dualtimer.c

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

end of thread, other threads:[~2018-08-16 12:20 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER Peter Maydell
2018-07-30 22:09   ` Alistair Francis
2018-07-30 16:24 ` [Qemu-devel] [PATCH 3/5] hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 4/5] hw/arm/iotkit: Wire up the dualtimer Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 5/5] hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511 Peter Maydell
2018-07-30 21:00 ` [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer no-reply
2018-07-31  5:26 ` no-reply
2018-08-16 12:20 ` Peter Maydell

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