hw/hexagon: connect qtimer device
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. Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-17-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Aug 5, 2026 at 21:27 UTC
57eaab1e8c8d7c1624591b1aeb668f14c3a8131d
5 files changed
+51
hw/hexagon/Kconfig
+1
@@ -4,6 +4,7 @@ config HEX_DSP
4
depends on HEXAGON
5
select CPU_CLUSTER
6
select HEX_L2VIC
7
+ select HEX_QTIMER
8
9
config HEX_VIRT
10
bool
hw/hexagon/hex-subsys.c
+28
@@ -11,6 +11,7 @@
11
#include "hw/hexagon/hexagon_globalreg.h"
12
#include "hw/hexagon/hexagon_tlb.h"
13
#include "hw/intc/hex-l2vic.h"
14
+#include "hw/timer/qct-qtimer.h"
15
#include "hw/cpu/cluster.h"
16
#include "hw/core/loader.h"
17
#include "hw/core/qdev-properties.h"
@@ -20,6 +21,11 @@
21
22
#define HEX_L2VIC_CPU_IRQS 8
23
24
+/* Number of QTimer frames instantiated for every Hexagon machine. */
25
+#define HEX_QTIMER_NR_FRAMES 3
26
+
27
+#define HEX_QTIMER_L2VIC_IRQ_BASE 2
28
+
29
static DeviceState *l2vic_create(HexagonCommonMachineState *hms,
30
const struct hexagon_machine_config *m_cfg)
31
{
@@ -43,6 +49,25 @@ static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu)
49
}
50
}
51
52
+static DeviceState *qtimer_create(HexagonCommonMachineState *hms,
53
+ const struct hexagon_machine_config *m_cfg)
54
+{
55
+ DeviceState *qtimer = qdev_new(TYPE_QCT_QTIMER);
56
+
57
+ object_property_add_child(OBJECT(hms), "qtimer", OBJECT(qtimer));
58
+ qdev_prop_set_uint32(qtimer, "nr_frames", HEX_QTIMER_NR_FRAMES);
59
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(qtimer), &error_fatal);
60
+ sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 0, m_cfg->csr_base);
61
+ sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 1, m_cfg->qtmr_region);
62
+ for (unsigned int i = 0; i < HEX_QTIMER_NR_FRAMES; i++) {
63
+ sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), i,
64
+ qdev_get_gpio_in(hms->l2vic,
65
+ HEX_QTIMER_L2VIC_IRQ_BASE + i));
66
+ }
67
+
68
+ return qtimer;
69
+}
70
+
71
static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
72
const struct hexagon_machine_config *m_cfg,
73
Rev_t rev)
@@ -54,6 +79,8 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
79
qdev_prop_set_uint32(glob_regs, "dsp-rev", rev);
80
object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic),
81
&error_fatal);
82
+ object_property_set_link(OBJECT(glob_regs), "qtimer", OBJECT(hms->qtimer),
83
+ &error_fatal);
84
sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal);
85
86
return glob_regs;
@@ -110,6 +137,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
137
138
hms->cluster = cluster_create(hms);
139
hms->l2vic = l2vic_create(hms, m_cfg);
140
+ hms->qtimer = qtimer_create(hms, m_cfg);
141
hms->glob_regs = globalreg_create(hms, m_cfg, rev);
142
hms->tlb = tlb_create(hms, m_cfg);
143
}
hw/hexagon/hexagon_globalreg.c
+17
@@ -12,6 +12,7 @@
12
#include "hw/core/sysbus.h"
13
#include "hw/core/resettable.h"
14
#include "hw/intc/hex-l2vic.h"
15
+#include "hw/timer/qct-qtimer.h"
16
#include "migration/vmstate.h"
17
#include "qom/object.h"
18
#include "target/hexagon/cpu.h"
@@ -141,11 +142,21 @@ static inline bool is_vid_reg(uint32_t reg)
142
return reg == HEX_SREG_VID || reg == HEX_SREG_VID1;
143
}
144
145
+static inline bool is_timer_reg(uint32_t reg)
146
+{
147
+ return reg == HEX_SREG_TIMERLO || reg == HEX_SREG_TIMERHI;
148
+}
149
+
150
static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg)
151
{
152
if (is_vid_reg(reg)) {
153
return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1);
154
}
155
+ if (is_timer_reg(reg)) {
156
+ return reg == HEX_SREG_TIMERLO ?
157
+ qct_qtimer_get_timer_lo(s->qtimer) :
158
+ qct_qtimer_get_timer_hi(s->qtimer);
159
+ }
160
return s->regs[reg];
161
}
162
@@ -289,6 +300,10 @@ static void hexagon_globalreg_realize(DeviceState *dev, Error **errp)
300
error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set");
301
return;
302
}
303
+ if (!s->qtimer) {
304
+ error_setg(errp, "hexagon_globalreg: 'qtimer' link property not set");
305
+ return;
306
+ }
307
}
308
309
static const VMStateDescription vmstate_hexagon_globalreg = {
@@ -312,6 +327,8 @@ static const VMStateDescription vmstate_hexagon_globalreg = {
327
static const Property hexagon_globalreg_properties[] = {
328
DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic,
329
TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *),
330
+ DEFINE_PROP_LINK("qtimer", HexagonGlobalRegState, qtimer,
331
+ TYPE_QCT_QTIMER_INTERFACE, QctQtimerInterface *),
332
DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
333
DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
334
config_table_addr, 0xffffffffULL),
include/hw/hexagon/hexagon.h
+1
@@ -159,6 +159,7 @@ struct HexagonCommonMachineState {
159
MemoryRegion vtcm;
160
DeviceState *cluster;
161
DeviceState *l2vic;
162
+ DeviceState *qtimer;
163
DeviceState *glob_regs;
164
DeviceState *tlb;
165
};
include/hw/hexagon/hexagon_globalreg.h
+4
@@ -11,6 +11,7 @@
11
#include "hw/core/qdev.h"
12
#include "hw/core/sysbus.h"
13
#include "hw/intc/hex-l2vic.h"
14
+#include "hw/timer/qct-qtimer.h"
15
#include "qom/object.h"
16
#include "target/hexagon/cpu.h"
17
@@ -26,6 +27,9 @@ struct HexagonGlobalRegState {
27
/* L2VIC interface used to back the VID/VID1 registers */
28
HexL2VicInterface *l2vic;
29
30
+ /* QTimer interface used to back the TIMERLO/TIMERHI registers */
31
+ QctQtimerInterface *qtimer;
32
+
33
/* Global performance cycle counter base */
34
uint64_t g_pcycle_base;
35