hw/hexagon: connect l2vic device
Add the l2vic to the shared hex-subsys so both machine models pick it up. Map its register banks, wire the interrupt lines to CPU[0] and link each vCPU, globalregs. Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-10-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
03f38eecc93b66520bd22b07d25c88e03db0ff41
7 files changed
+72
-5
hw/hexagon/hex-subsys.c
+37
-1
@@ -10,6 +10,7 @@
10
#include "hw/hexagon/hex-subsys.h"
11
#include "hw/hexagon/hexagon_globalreg.h"
12
#include "hw/hexagon/hexagon_tlb.h"
13
+#include "hw/intc/hex-l2vic.h"
14
#include "hw/cpu/cluster.h"
15
#include "hw/core/loader.h"
16
#include "hw/core/qdev-properties.h"
@@ -17,6 +18,31 @@
18
#include "hw/core/sysbus.h"
19
#include "system/address-spaces.h"
20
21
+#define HEX_L2VIC_CPU_IRQS 8
22
+
23
+static DeviceState *l2vic_create(HexagonCommonMachineState *hms,
24
+ const struct hexagon_machine_config *m_cfg)
25
+{
26
+ DeviceState *l2vic = qdev_new(TYPE_HEX_L2VIC);
27
+
28
+ object_property_add_child(OBJECT(hms), "l2vic", OBJECT(l2vic));
29
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(l2vic), &error_fatal);
30
+ sysbus_mmio_map(SYS_BUS_DEVICE(l2vic), 0, m_cfg->l2vic_base);
31
+ sysbus_mmio_map(SYS_BUS_DEVICE(l2vic), 1,
32
+ m_cfg->cfgtable.fastl2vic_base << 16);
33
+
34
+ return l2vic;
35
+}
36
+
37
+static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu)
38
+{
39
+ int i;
40
+
41
+ for (i = 0; i < HEX_L2VIC_CPU_IRQS; i++) {
42
+ sysbus_connect_irq(SYS_BUS_DEVICE(l2vic), i, qdev_get_gpio_in(cpu, i));
43
+ }
44
+}
45
+
46
static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
47
const struct hexagon_machine_config *m_cfg,
48
Rev_t rev)
@@ -26,6 +52,8 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
52
object_property_add_child(OBJECT(hms), "global-regs", OBJECT(glob_regs));
53
qdev_prop_set_uint64(glob_regs, "config-table-addr", m_cfg->cfgbase);
54
qdev_prop_set_uint32(glob_regs, "dsp-rev", rev);
55
+ object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic),
56
+ &error_fatal);
57
sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal);
58
59
return glob_regs;
@@ -81,6 +109,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
109
}
110
111
hms->cluster = cluster_create(hms);
112
+ hms->l2vic = l2vic_create(hms, m_cfg);
113
hms->glob_regs = globalreg_create(hms, m_cfg, rev);
114
hms->tlb = tlb_create(hms, m_cfg);
115
}
@@ -92,6 +121,8 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
121
OBJECT(hms->glob_regs), &error_fatal);
122
object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb),
123
&error_fatal);
124
+ object_property_set_link(OBJECT(cpu), "l2vic", OBJECT(hms->l2vic),
125
+ &error_fatal);
126
}
127
128
void hex_subsys_realize_cluster(HexagonCommonMachineState *hms)
@@ -105,7 +136,12 @@ void hex_subsys_realize_cluster(HexagonCommonMachineState *hms)
136
qdev_realize_and_unref(hms->cluster, NULL, &error_fatal);
137
}
138
108
-void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
139
+void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu,
140
+ bool boot_cpu)
141
{
142
qdev_realize_and_unref(cpu, NULL, &error_fatal);
143
+
144
+ if (boot_cpu) {
145
+ l2vic_connect_cpu(hms->l2vic, cpu);
146
+ }
147
}
hw/hexagon/hexagon_dsp.c
+1
-1
@@ -139,7 +139,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
139
hex_subsys_realize_cluster(hms);
140
141
for (int i = 0; i < machine->smp.cpus; i++) {
142
- hex_subsys_realize_cpu(hms, DEVICE(cpus[i]));
142
+ hex_subsys_realize_cpu(hms, DEVICE(cpus[i]), (i == 0));
143
}
144
}
145
hw/hexagon/hexagon_globalreg.c
+25
@@ -11,6 +11,7 @@
11
#include "hw/core/qdev-properties.h"
12
#include "hw/core/sysbus.h"
13
#include "hw/core/resettable.h"
14
+#include "hw/intc/hex-l2vic.h"
15
#include "migration/vmstate.h"
16
#include "qom/object.h"
17
#include "target/hexagon/cpu.h"
@@ -135,8 +136,16 @@ static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val,
136
return new_val;
137
}
138
139
+static inline bool is_vid_reg(uint32_t reg)
140
+{
141
+ return reg == HEX_SREG_VID || reg == HEX_SREG_VID1;
142
+}
143
+
144
static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg)
145
{
146
+ if (is_vid_reg(reg)) {
147
+ return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1);
148
+ }
149
return s->regs[reg];
150
}
151
@@ -144,6 +153,9 @@ static void set_reg_value(HexagonGlobalRegState *s, uint32_t reg,
153
uint32_t value)
154
{
155
s->regs[reg] = value;
156
+ if (is_vid_reg(reg)) {
157
+ l2vic_update_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1, value);
158
+ }
159
}
160
161
uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
@@ -269,6 +281,16 @@ static void hexagon_globalreg_reset_hold(Object *obj, ResetType type)
281
do_hexagon_globalreg_reset(s);
282
}
283
284
+static void hexagon_globalreg_realize(DeviceState *dev, Error **errp)
285
+{
286
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(dev);
287
+
288
+ if (!s->l2vic) {
289
+ error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set");
290
+ return;
291
+ }
292
+}
293
+
294
static const VMStateDescription vmstate_hexagon_globalreg = {
295
.name = "hexagon_globalreg",
296
.version_id = 1,
@@ -288,6 +310,8 @@ static const VMStateDescription vmstate_hexagon_globalreg = {
310
};
311
312
static const Property hexagon_globalreg_properties[] = {
313
+ DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic,
314
+ TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *),
315
DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
316
DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
317
config_table_addr, 0xffffffffULL),
@@ -308,6 +332,7 @@ static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
332
ResettableClass *rc = RESETTABLE_CLASS(klass);
333
334
rc->phases.hold = hexagon_globalreg_reset_hold;
335
+ dc->realize = hexagon_globalreg_realize;
336
dc->vmsd = &vmstate_hexagon_globalreg;
337
dc->user_creatable = false;
338
device_class_set_props(dc, hexagon_globalreg_properties);
hw/hexagon/virt.c
+1
-1
@@ -270,7 +270,7 @@ static void virt_init(MachineState *ms)
270
hex_subsys_realize_cluster(&vms->parent_obj);
271
272
for (int i = 0; i < ms->smp.cpus; i++) {
273
- hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i]));
273
+ hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i]), (i == 0));
274
}
275
276
fdt_add_cpu_nodes(vms);
include/hw/hexagon/hex-subsys.h
+3
-2
@@ -18,7 +18,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
18
/*
19
* Parent a CPU into the subsystem's cluster and wire its links. Call for
20
* every CPU before hex_subsys_realize_cluster(), then realize each CPU with
21
- * hex_subsys_realize_cpu().
21
+ * hex_subsys_realize_cpu(). CPU[0] receives the L2VIC outputs.
22
*/
23
void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu);
24
@@ -26,6 +26,7 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu);
26
void hex_subsys_realize_cluster(HexagonCommonMachineState *hms);
27
28
/* Realize a CPU previously parented via hex_subsys_add_cpu(). */
29
-void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu);
29
+void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu,
30
+ bool boot_cpu);
31
32
#endif /* HW_HEXAGON_HEX_SUBSYS_H */
include/hw/hexagon/hexagon.h
+1
@@ -158,6 +158,7 @@ struct HexagonCommonMachineState {
158
MemoryRegion cfgtable_rom;
159
MemoryRegion vtcm;
160
DeviceState *cluster;
161
+ DeviceState *l2vic;
162
DeviceState *glob_regs;
163
DeviceState *tlb;
164
};
include/hw/hexagon/hexagon_globalreg.h
+4
@@ -10,6 +10,7 @@
10
11
#include "hw/core/qdev.h"
12
#include "hw/core/sysbus.h"
13
+#include "hw/intc/hex-l2vic.h"
14
#include "qom/object.h"
15
#include "target/hexagon/cpu.h"
16
@@ -22,6 +23,9 @@ struct HexagonGlobalRegState {
23
/* Array of system registers */
24
uint32_t regs[NUM_SREGS];
25
26
+ /* L2VIC interface used to back the VID/VID1 registers */
27
+ HexL2VicInterface *l2vic;
28
+
29
/* Global performance cycle counter base */
30
uint64_t g_pcycle_base;
31