@samitouri / QOSamiQemu / commits / 03f38eecc9

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