Instantiate the L2VIC device in both machine models, map its slow and
MMIO regions, and link it to each CPU via the "l2vic" property.

Reviewed-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 include/hw/hexagon/hexagon.h           |  1 +
 include/hw/hexagon/hexagon_globalreg.h |  4 +++
 hw/hexagon/hexagon_dsp.c               | 20 +++++++++++++
 hw/hexagon/hexagon_globalreg.c         | 41 ++++++++++++++++++++++----
 hw/hexagon/virt.c                      | 22 ++++++++++++++
 5 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 1034b09c2ac..6753ae32cde 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -156,6 +156,7 @@ struct HexagonCommonMachineState {
 
     MemoryRegion ram;
     MemoryRegion cfgtable_rom;
+    DeviceState *l2vic_dev;
 };
 
 #endif
diff --git a/include/hw/hexagon/hexagon_globalreg.h 
b/include/hw/hexagon/hexagon_globalreg.h
index 950099808fd..397dc6854c9 100644
--- a/include/hw/hexagon/hexagon_globalreg.h
+++ b/include/hw/hexagon/hexagon_globalreg.h
@@ -10,6 +10,7 @@
 
 #include "hw/core/qdev.h"
 #include "hw/core/sysbus.h"
+#include "hw/intc/hex-l2vic.h"
 #include "qom/object.h"
 #include "target/hexagon/cpu.h"
 
@@ -22,6 +23,9 @@ struct HexagonGlobalRegState {
     /* Array of system registers */
     uint32_t regs[NUM_SREGS];
 
+    /* L2VIC interface used to back the VID/VID1 registers */
+    HexL2VicInterface *l2vic;
+
     /* Global performance cycle counter base */
     uint64_t g_pcycle_base;
 
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index aa493993229..4cf88627c8f 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -16,6 +16,7 @@
 #include "hw/hexagon/hexagon.h"
 #include "hw/hexagon/hexagon_globalreg.h"
 #include "hw/hexagon/hexagon_tlb.h"
+#include "hw/intc/hex-l2vic.h"
 #include "hw/core/loader.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
@@ -111,6 +112,7 @@ static void hexagon_common_init(MachineState *machine, 
Rev_t rev,
     MemoryRegion *address_space;
     DeviceState *glob_regs_dev;
     DeviceState *tlb_dev;
+    DeviceState *cpu0 = NULL;
 
     memset(&hexagon_binfo, 0, sizeof(hexagon_binfo));
     if (machine->kernel_filename) {
@@ -131,11 +133,21 @@ static void hexagon_common_init(MachineState *machine, 
Rev_t rev,
                            machine->ram_size, &error_fatal);
     memory_region_add_subregion(address_space, 0x0, &hms->ram);
 
+    hms->l2vic_dev = qdev_new(TYPE_HEX_L2VIC);
+    object_property_add_child(OBJECT(machine), "l2vic",
+                              OBJECT(hms->l2vic_dev));
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(hms->l2vic_dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(hms->l2vic_dev), 0, m_cfg->l2vic_base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(hms->l2vic_dev), 1,
+                    m_cfg->cfgtable.fastl2vic_base << 16);
+
     glob_regs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG);
     object_property_add_child(OBJECT(machine), "global-regs",
                               OBJECT(glob_regs_dev));
     qdev_prop_set_uint64(glob_regs_dev, "config-table-addr", m_cfg->cfgbase);
     qdev_prop_set_uint32(glob_regs_dev, "dsp-rev", rev);
+    object_property_set_link(OBJECT(glob_regs_dev), "l2vic",
+                             OBJECT(hms->l2vic_dev), &error_fatal);
     sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs_dev), &error_fatal);
 
     tlb_dev = qdev_new(TYPE_HEXAGON_TLB);
@@ -154,15 +166,23 @@ static void hexagon_common_init(MachineState *machine, 
Rev_t rev,
          */
         qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
         if (i == 0) {
+            cpu0 = DEVICE(cpu);
             hexagon_init_bootstrap(dms, cpu);
         }
         object_property_set_link(OBJECT(cpu), "global-regs",
                                  OBJECT(glob_regs_dev), &error_fatal);
         object_property_set_link(OBJECT(cpu), "tlb",
                                  OBJECT(tlb_dev), &error_fatal);
+        object_property_set_link(OBJECT(cpu), "l2vic",
+                                 OBJECT(hms->l2vic_dev), &error_fatal);
         qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
     }
 
+    for (int i = 0; i < 8; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(hms->l2vic_dev), i,
+                           qdev_get_gpio_in(cpu0, i));
+    }
+
     rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable,
                           sizeof(m_cfg->cfgtable), m_cfg->cfgbase,
                           &address_space_memory);
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
index b5e5913507e..3d0d6f9516c 100644
--- a/hw/hexagon/hexagon_globalreg.c
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -11,6 +11,7 @@
 #include "hw/core/qdev-properties.h"
 #include "hw/core/sysbus.h"
 #include "hw/core/resettable.h"
+#include "hw/intc/hex-l2vic.h"
 #include "migration/vmstate.h"
 #include "qom/object.h"
 #include "target/hexagon/cpu.h"
@@ -135,6 +136,32 @@ static inline uint32_t apply_write_mask(uint32_t new_val, 
uint32_t cur_val,
     return new_val;
 }
 
+static inline bool is_vid_reg(uint32_t reg)
+{
+    return reg == HEX_SREG_VID || reg == HEX_SREG_VID1;
+}
+
+/*
+ * HEX_SREG_VID/VID1 are backed by the L2VIC's VID group registers
+ * rather than the plain regs[] array, when an L2VIC is wired up.
+ */
+static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg)
+{
+    if (is_vid_reg(reg) && s->l2vic) {
+        return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1);
+    }
+    return s->regs[reg];
+}
+
+static void set_reg_value(HexagonGlobalRegState *s, uint32_t reg,
+                          uint32_t value)
+{
+    s->regs[reg] = value;
+    if (is_vid_reg(reg) && s->l2vic) {
+        l2vic_update_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1, value);
+    }
+}
+
 uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
                                 uint32_t htid)
 {
@@ -146,7 +173,7 @@ uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, 
uint32_t reg,
     g_assert(reg < NUM_SREGS);
     g_assert(reg >= HEX_SREG_GLB_START);
 
-    value = s->regs[reg];
+    value = get_reg_value(s, reg);
 
     trace_hexagon_globalreg_read(htid, get_sreg_name(reg), value);
     return value;
@@ -160,7 +187,7 @@ void hexagon_globalreg_write(HexagonGlobalRegState *s, 
uint32_t reg,
     }
     g_assert(reg < NUM_SREGS);
     g_assert(reg >= HEX_SREG_GLB_START);
-    s->regs[reg] = value;
+    set_reg_value(s, reg, value);
     trace_hexagon_globalreg_write(htid, get_sreg_name(reg), value);
 }
 
@@ -168,6 +195,7 @@ uint32_t 
hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
                                         uint32_t value)
 {
     uint32_t reg_mask;
+    uint32_t cur_val;
 
     if (!s) {
         return value;
@@ -175,9 +203,10 @@ uint32_t 
hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
     g_assert(reg < NUM_SREGS);
     g_assert(reg >= HEX_SREG_GLB_START);
     reg_mask = global_sreg_immut_masks[reg];
+    cur_val = get_reg_value(s, reg);
     return reg_mask == IMMUTABLE ?
-            s->regs[reg] :
-            apply_write_mask(value, s->regs[reg], reg_mask);
+            cur_val :
+            apply_write_mask(value, cur_val, reg_mask);
 }
 
 void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
@@ -186,7 +215,7 @@ void hexagon_globalreg_write_masked(HexagonGlobalRegState 
*s, uint32_t reg,
     if (!s) {
         return;
     }
-    s->regs[reg] = hexagon_globalreg_masked_value(s, reg, value);
+    set_reg_value(s, reg, hexagon_globalreg_masked_value(s, reg, value));
 }
 
 uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s)
@@ -275,6 +304,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_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
     DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
                        config_table_addr, 0xffffffffULL),
diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c
index a3638998b87..2256d3d53a5 100644
--- a/hw/hexagon/virt.c
+++ b/hw/hexagon/virt.c
@@ -15,6 +15,7 @@
 #include "hw/hexagon/hexagon.h"
 #include "hw/hexagon/hexagon_globalreg.h"
 #include "hw/hexagon/hexagon_tlb.h"
+#include "hw/intc/hex-l2vic.h"
 #include "hw/core/loader.h"
 #include "hw/core/qdev-properties.h"
 #include "hw/core/qdev-clock.h"
@@ -268,10 +269,22 @@ static void virt_init(MachineState *ms)
                                 &vms->parent_obj.cfgtable_rom);
     fdt_add_hvx(vms, m_cfg);
 
+    vms->parent_obj.l2vic_dev = qdev_new(TYPE_HEX_L2VIC);
+    object_property_add_child(OBJECT(ms), "l2vic",
+                              OBJECT(vms->parent_obj.l2vic_dev));
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(vms->parent_obj.l2vic_dev),
+                             &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(vms->parent_obj.l2vic_dev), 0,
+                    m_cfg->l2vic_base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(vms->parent_obj.l2vic_dev), 1,
+                    m_cfg->cfgtable.fastl2vic_base << 16);
+
     gsregs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG);
     object_property_add_child(OBJECT(ms), "global-regs", OBJECT(gsregs_dev));
     qdev_prop_set_uint64(gsregs_dev, "config-table-addr", m_cfg->cfgbase);
     qdev_prop_set_uint32(gsregs_dev, "dsp-rev", v68_rev);
+    object_property_set_link(OBJECT(gsregs_dev), "l2vic",
+                             OBJECT(vms->parent_obj.l2vic_dev), &error_fatal);
     sysbus_realize_and_unref(SYS_BUS_DEVICE(gsregs_dev), &error_fatal);
 
     tlb_dev = qdev_new(TYPE_HEXAGON_TLB);
@@ -301,9 +314,18 @@ static void virt_init(MachineState *ms)
                                  OBJECT(gsregs_dev), &error_fatal);
         object_property_set_link(OBJECT(cpu), "tlb",
                                  OBJECT(tlb_dev), &error_fatal);
+        object_property_set_link(OBJECT(cpu), "l2vic",
+                                 OBJECT(vms->parent_obj.l2vic_dev),
+                                 &error_fatal);
 
         qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
     }
+
+    for (int i = 0; i < 8; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(vms->parent_obj.l2vic_dev), i,
+                           qdev_get_gpio_in(cpu0, i));
+    }
+
     fdt_add_cpu_nodes(vms);
     clk_phandle = fdt_add_clocks(vms);
     fdt_add_uart(vms, VIRT_UART0, clk_phandle);
-- 
2.34.1

Reply via email to