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.
Signed-off-by: Brian Cain <[email protected]> --- include/hw/hexagon/hexagon.h | 1 + include/hw/hexagon/hexagon_globalreg.h | 4 ++++ hw/hexagon/hex-subsys.c | 28 ++++++++++++++++++++++++++ hw/hexagon/hexagon_globalreg.c | 17 ++++++++++++++++ hw/hexagon/Kconfig | 1 + 5 files changed, 51 insertions(+) diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index ec1578807d8..3d7b3cb12dc 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -159,6 +159,7 @@ struct HexagonCommonMachineState { MemoryRegion vtcm; DeviceState *cluster; DeviceState *l2vic; + DeviceState *qtimer; DeviceState *glob_regs; DeviceState *tlb; }; diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h index 397dc6854c9..07437dfabb1 100644 --- a/include/hw/hexagon/hexagon_globalreg.h +++ b/include/hw/hexagon/hexagon_globalreg.h @@ -11,6 +11,7 @@ #include "hw/core/qdev.h" #include "hw/core/sysbus.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "qom/object.h" #include "target/hexagon/cpu.h" @@ -26,6 +27,9 @@ struct HexagonGlobalRegState { /* L2VIC interface used to back the VID/VID1 registers */ HexL2VicInterface *l2vic; + /* QTimer interface used to back the TIMERLO/TIMERHI registers */ + QctQtimerInterface *qtimer; + /* Global performance cycle counter base */ uint64_t g_pcycle_base; diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index 5f238006bae..b231b749eb9 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -11,6 +11,7 @@ #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "hw/cpu/cluster.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" @@ -20,6 +21,13 @@ #define HEX_L2VIC_CPU_IRQS 8 +/* L2VIC input lines the QTimer's two frames are wired to. */ +#define HEX_QTIMER_L2VIC_IRQ0 3 +#define HEX_QTIMER_L2VIC_IRQ1 4 + +/* Number of QTimer frames instantiated for every Hexagon machine. */ +#define HEX_QTIMER_NR_FRAMES 3 + static DeviceState *l2vic_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg) { @@ -43,6 +51,23 @@ static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu) } } +static DeviceState *qtimer_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg) +{ + DeviceState *qtimer = qdev_new(TYPE_QCT_QTIMER); + + object_property_add_child(OBJECT(hms), "qtimer", OBJECT(qtimer)); + qdev_prop_set_uint32(qtimer, "nr_frames", HEX_QTIMER_NR_FRAMES); + sysbus_realize_and_unref(SYS_BUS_DEVICE(qtimer), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 1, m_cfg->qtmr_region); + sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), 0, + qdev_get_gpio_in(hms->l2vic, HEX_QTIMER_L2VIC_IRQ0)); + sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), 1, + qdev_get_gpio_in(hms->l2vic, HEX_QTIMER_L2VIC_IRQ1)); + + return qtimer; +} + static DeviceState *globalreg_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg, Rev_t rev) @@ -54,6 +79,8 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms, qdev_prop_set_uint32(glob_regs, "dsp-rev", rev); object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic), &error_fatal); + object_property_set_link(OBJECT(glob_regs), "qtimer", OBJECT(hms->qtimer), + &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal); return glob_regs; @@ -110,6 +137,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms, hms->cluster = cluster_create(hms); hms->l2vic = l2vic_create(hms, m_cfg); + hms->qtimer = qtimer_create(hms, m_cfg); hms->glob_regs = globalreg_create(hms, m_cfg, rev); hms->tlb = tlb_create(hms, m_cfg); } diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c index 285cb48c44b..61621cf2b8f 100644 --- a/hw/hexagon/hexagon_globalreg.c +++ b/hw/hexagon/hexagon_globalreg.c @@ -12,6 +12,7 @@ #include "hw/core/sysbus.h" #include "hw/core/resettable.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "migration/vmstate.h" #include "qom/object.h" #include "target/hexagon/cpu.h" @@ -141,11 +142,21 @@ static inline bool is_vid_reg(uint32_t reg) return reg == HEX_SREG_VID || reg == HEX_SREG_VID1; } +static inline bool is_timer_reg(uint32_t reg) +{ + return reg == HEX_SREG_TIMERLO || reg == HEX_SREG_TIMERHI; +} + static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg) { if (is_vid_reg(reg)) { return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1); } + if (is_timer_reg(reg)) { + return reg == HEX_SREG_TIMERLO ? + qct_qtimer_get_timer_lo(s->qtimer) : + qct_qtimer_get_timer_hi(s->qtimer); + } return s->regs[reg]; } @@ -289,6 +300,10 @@ static void hexagon_globalreg_realize(DeviceState *dev, Error **errp) error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set"); return; } + if (!s->qtimer) { + error_setg(errp, "hexagon_globalreg: 'qtimer' link property not set"); + return; + } } static const VMStateDescription vmstate_hexagon_globalreg = { @@ -312,6 +327,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_LINK("qtimer", HexagonGlobalRegState, qtimer, + TYPE_QCT_QTIMER_INTERFACE, QctQtimerInterface *), 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/Kconfig b/hw/hexagon/Kconfig index c75090c44a1..83b2763d1e3 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -4,6 +4,7 @@ config HEX_DSP depends on HEXAGON select CPU_CLUSTER select HEX_L2VIC + select HEX_QTIMER config HEX_VIRT bool -- 2.34.1
