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
