[PATCH v4 16/18] hw/hexagon: connect qtimer device

Brian Cain <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
Add the QTimer to the shared hex-subsys so both machine models pick it
up.  Map its view region, wire its interrupt lines into l2vic, and link
it to the globalreg device backing HEX_SREG_TIMERLO/TIMERHI.

Signed-off-by: Brian Cain <[email protected]>
---
 include/hw/hexagon/hexagon.h           |  1 +
 include/hw/hexagon/hexagon_globalreg.h |  4 ++++
 hw/hexagon/hex-subsys.c                | 29 ++++++++++++++++++++++++++
 hw/hexagon/hexagon_globalreg.c         | 17 +++++++++++++++
 hw/hexagon/Kconfig                     |  1 +
 5 files changed, 52 insertions(+)

diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index ec1578807d8..3d7b3cb12dc 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -159,6 +159,7 @@ struct HexagonCommonMachineState {
     MemoryRegion vtcm;
     DeviceState *cluster;
     DeviceState *l2vic;
+    DeviceState *qtimer;
     DeviceState *glob_regs;
     DeviceState *tlb;
 };
diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h
index 397dc6854c9..07437dfabb1 100644
--- a/include/hw/hexagon/hexagon_globalreg.h
+++ b/include/hw/hexagon/hexagon_globalreg.h
@@ -11,6 +11,7 @@
 #include "hw/core/qdev.h"
 #include "hw/core/sysbus.h"
 #include "hw/intc/hex-l2vic.h"
+#include "hw/timer/qct-qtimer.h"
 #include "qom/object.h"
 #include "target/hexagon/cpu.h"
 
@@ -26,6 +27,9 @@ struct HexagonGlobalRegState {
     /* L2VIC interface used to back the VID/VID1 registers */
     HexL2VicInterface *l2vic;
 
+    /* QTimer interface used to back the TIMERLO/TIMERHI registers */
+    QctQtimerInterface *qtimer;
+
     /* Global performance cycle counter base */
     uint64_t g_pcycle_base;
 
diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c
index 25c028f6579..12d4ec72d38 100644
--- a/hw/hexagon/hex-subsys.c
+++ b/hw/hexagon/hex-subsys.c
@@ -11,6 +11,7 @@
 #include "hw/hexagon/hexagon_globalreg.h"
 #include "hw/hexagon/hexagon_tlb.h"
 #include "hw/intc/hex-l2vic.h"
+#include "hw/timer/qct-qtimer.h"
 #include "hw/cpu/cluster.h"
 #include "hw/core/loader.h"
 #include "hw/core/qdev-properties.h"
@@ -20,6 +21,13 @@
 
 #define HEX_L2VIC_CPU_IRQS 8
 
+/* L2VIC input lines the QTimer's two frames are wired to. */
+#define HEX_QTIMER_L2VIC_IRQ0 3
+#define HEX_QTIMER_L2VIC_IRQ1 4
+
+/* Number of QTimer frames instantiated for every Hexagon machine. */
+#define HEX_QTIMER_NR_FRAMES 3
+
 static DeviceState *l2vic_create(HexagonCommonMachineState *hms,
                                  const struct hexagon_machine_config *m_cfg)
 {
@@ -43,6 +51,24 @@ static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu)
     }
 }
 
+static DeviceState *qtimer_create(HexagonCommonMachineState *hms,
+                                  const struct hexagon_machine_config *m_cfg)
+{
+    DeviceState *qtimer = qdev_new(TYPE_QCT_QTIMER);
+
+    object_property_add_child(OBJECT(hms), "qtimer", OBJECT(qtimer));
+    qdev_prop_set_uint32(qtimer, "nr_frames", HEX_QTIMER_NR_FRAMES);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(qtimer), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 0, m_cfg->csr_base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 1, m_cfg->qtmr_region);
+    sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), 0,
+                       qdev_get_gpio_in(hms->l2vic, HEX_QTIMER_L2VIC_IRQ0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), 1,
+                       qdev_get_gpio_in(hms->l2vic, HEX_QTIMER_L2VIC_IRQ1));
+
+    return qtimer;
+}
+
 static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
                                      const struct hexagon_machine_config *m_cfg,
                                      Rev_t rev)
@@ -54,6 +80,8 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
     qdev_prop_set_uint32(glob_regs, "dsp-rev", rev);
     object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic),
                              &error_fatal);
+    object_property_set_link(OBJECT(glob_regs), "qtimer", OBJECT(hms->qtimer),
+                             &error_fatal);
     sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal);
 
     return glob_regs;
@@ -110,6 +138,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
 
     hms->cluster = cluster_create(hms);
     hms->l2vic = l2vic_create(hms, m_cfg);
+    hms->qtimer = qtimer_create(hms, m_cfg);
     hms->glob_regs = globalreg_create(hms, m_cfg, rev);
     hms->tlb = tlb_create(hms, m_cfg);
 }
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
index 285cb48c44b..61621cf2b8f 100644
--- a/hw/hexagon/hexagon_globalreg.c
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -12,6 +12,7 @@
 #include "hw/core/sysbus.h"
 #include "hw/core/resettable.h"
 #include "hw/intc/hex-l2vic.h"
+#include "hw/timer/qct-qtimer.h"
 #include "migration/vmstate.h"
 #include "qom/object.h"
 #include "target/hexagon/cpu.h"
@@ -141,11 +142,21 @@ static inline bool is_vid_reg(uint32_t reg)
     return reg == HEX_SREG_VID || reg == HEX_SREG_VID1;
 }
 
+static inline bool is_timer_reg(uint32_t reg)
+{
+    return reg == HEX_SREG_TIMERLO || reg == HEX_SREG_TIMERHI;
+}
+
 static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg)
 {
     if (is_vid_reg(reg)) {
         return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1);
     }
+    if (is_timer_reg(reg)) {
+        return reg == HEX_SREG_TIMERLO ?
+                qct_qtimer_get_timer_lo(s->qtimer) :
+                qct_qtimer_get_timer_hi(s->qtimer);
+    }
     return s->regs[reg];
 }
 
@@ -289,6 +300,10 @@ static void hexagon_globalreg_realize(DeviceState *dev, Error **errp)
         error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set");
         return;
     }
+    if (!s->qtimer) {
+        error_setg(errp, "hexagon_globalreg: 'qtimer' link property not set");
+        return;
+    }
 }
 
 static const VMStateDescription vmstate_hexagon_globalreg = {
@@ -312,6 +327,8 @@ static const VMStateDescription vmstate_hexagon_globalreg = {
 static const Property hexagon_globalreg_properties[] = {
     DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic,
                      TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *),
+    DEFINE_PROP_LINK("qtimer", HexagonGlobalRegState, qtimer,
+                     TYPE_QCT_QTIMER_INTERFACE, QctQtimerInterface *),
     DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
     DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
                        config_table_addr, 0xffffffffULL),
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index c75090c44a1..83b2763d1e3 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -4,6 +4,7 @@ config HEX_DSP
     depends on HEXAGON
     select CPU_CLUSTER
     select HEX_L2VIC
+    select HEX_QTIMER
 
 config HEX_VIRT
     bool
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.