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                | 28 ++++++++++++++++++++++++++
 hw/hexagon/hexagon_globalreg.c         | 17 ++++++++++++++++
 hw/hexagon/Kconfig                     |  1 +
 5 files changed, 51 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 5f238006bae..b231b749eb9 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,23 @@ 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), 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 +79,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 +137,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

Reply via email to