On 7/17/2026 6:32 PM, Brian Cain wrote:
> Instantiate the QTimer device in both machine models, map its
> view region, connect its interrupt lines into l2vic,
> and link it to the globalreg device.
> 
> Store the QTimer DeviceState pointer in the shared
> HexagonCommonMachineState.
> 
> 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               | 14 ++++++++++++++
>  hw/hexagon/hexagon_globalreg.c         | 17 +++++++++++++++--
>  hw/hexagon/virt.c                      | 16 ++++++++++++++++
>  hw/hexagon/Kconfig                     |  1 +
>  6 files changed, 51 insertions(+), 2 deletions(-)
> 
> diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
> index 6753ae32cde..3eea1e54ff2 100644
> --- a/include/hw/hexagon/hexagon.h
> +++ b/include/hw/hexagon/hexagon.h
> @@ -157,6 +157,7 @@ struct HexagonCommonMachineState {
>      MemoryRegion ram;
>      MemoryRegion cfgtable_rom;
>      DeviceState *l2vic_dev;
> +    DeviceState *qtimer_dev;
>  };
>  
>  #endif
> 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/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
> index 4cf88627c8f..21bb80ac27a 100644
> --- a/hw/hexagon/hexagon_dsp.c
> +++ b/hw/hexagon/hexagon_dsp.c
> @@ -17,6 +17,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/core/loader.h"
>  #include "qapi/error.h"
>  #include "qemu/error-report.h"
> @@ -141,6 +142,17 @@ static void hexagon_common_init(MachineState *machine, 
> Rev_t rev,
>      sysbus_mmio_map(SYS_BUS_DEVICE(hms->l2vic_dev), 1,
>                      m_cfg->cfgtable.fastl2vic_base << 16);
>  
> +    hms->qtimer_dev = qdev_new(TYPE_QCT_QTIMER);
> +    object_property_add_child(OBJECT(machine), "qtimer",
> +                              OBJECT(hms->qtimer_dev));
> +    qdev_prop_set_uint32(hms->qtimer_dev, "nr_frames", 3);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(hms->qtimer_dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(hms->qtimer_dev), 1, m_cfg->qtmr_region);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(hms->qtimer_dev), 0,
> +                       qdev_get_gpio_in(hms->l2vic_dev, 3));
> +    sysbus_connect_irq(SYS_BUS_DEVICE(hms->qtimer_dev), 1,
> +                       qdev_get_gpio_in(hms->l2vic_dev, 4));
> +
>      glob_regs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG);
>      object_property_add_child(OBJECT(machine), "global-regs",
>                                OBJECT(glob_regs_dev));
> @@ -148,6 +160,8 @@ static void hexagon_common_init(MachineState *machine, 
> Rev_t rev,
>      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);
> +    object_property_set_link(OBJECT(glob_regs_dev), "qtimer",
> +                             OBJECT(hms->qtimer_dev), &error_fatal);
>      sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs_dev), &error_fatal);
>  
>      tlb_dev = qdev_new(TYPE_HEXAGON_TLB);
> diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
> index 3d0d6f9516c..0353d89f87b 100644
> --- a/hw/hexagon/hexagon_globalreg.c
> +++ b/hw/hexagon/hexagon_globalreg.c
> @@ -141,15 +141,26 @@ 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;
> +}
> +
>  /*
> - * 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.
> + * HEX_SREG_VID/VID1 are backed by the L2VIC's VID group registers, and
> + * HEX_SREG_TIMERLO/TIMERHI are backed by the QTimer's live counter,
> + * rather than the plain regs[] array, when those devices are 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);
>      }
> +    if (is_timer_reg(reg) && s->qtimer) {
> +        return reg == HEX_SREG_TIMERLO ?
> +                qct_qtimer_get_timer_lo(s->qtimer) :
> +                qct_qtimer_get_timer_hi(s->qtimer);
> +    }
>      return s->regs[reg];
>  }
>  
> @@ -306,6 +317,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/virt.c b/hw/hexagon/virt.c
> index 2256d3d53a5..7e32765d1cc 100644
> --- a/hw/hexagon/virt.c
> +++ b/hw/hexagon/virt.c
> @@ -16,6 +16,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/core/loader.h"
>  #include "hw/core/qdev-properties.h"
>  #include "hw/core/qdev-clock.h"
> @@ -279,12 +280,27 @@ static void virt_init(MachineState *ms)
>      sysbus_mmio_map(SYS_BUS_DEVICE(vms->parent_obj.l2vic_dev), 1,
>                      m_cfg->cfgtable.fastl2vic_base << 16);
>  
> +    vms->parent_obj.qtimer_dev = qdev_new(TYPE_QCT_QTIMER);
> +    object_property_add_child(OBJECT(ms), "qtimer",
> +                              OBJECT(vms->parent_obj.qtimer_dev));
> +    qdev_prop_set_uint32(vms->parent_obj.qtimer_dev, "nr_frames", 2);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev),
> +                             &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), 1,
> +                    m_cfg->qtmr_region);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), 0,
> +                       qdev_get_gpio_in(vms->parent_obj.l2vic_dev, 3));
> +    sysbus_connect_irq(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), 1,
> +                       qdev_get_gpio_in(vms->parent_obj.l2vic_dev, 4));

We should consider extract an init function for this, as it's mostly
duplicated between virt and hexagon_dsp.
Also, is the difference in nr_frames expected?

> +
>      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);
> +    object_property_set_link(OBJECT(gsregs_dev), "qtimer",
> +                             OBJECT(vms->parent_obj.qtimer_dev), 
> &error_fatal);
>      sysbus_realize_and_unref(SYS_BUS_DEVICE(gsregs_dev), &error_fatal);
>  
>      tlb_dev = qdev_new(TYPE_HEXAGON_TLB);
> diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
> index 191c6c5d65c..56cd5b15c55 100644
> --- a/hw/hexagon/Kconfig
> +++ b/hw/hexagon/Kconfig
> @@ -3,6 +3,7 @@ config HEX_DSP
>      default y
>      depends on HEXAGON
>      select HEX_L2VIC
> +    select HEX_QTIMER
>  
>  config HEX_VIRT
>      bool

Reply via email to