include/hw/hexagon/hexagon_globalreg.h | 55 ++++++ hw/hexagon/hexagon_globalreg.c | 243 +++++++++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 include/hw/hexagon/hexagon_globalreg.h create mode 100644 hw/hexagon/hexagon_globalreg.c
Some of the system registers are shared among all threads
in the core. This object contains the representation and
interface to the system registers.
Reviewed-by: Sid Manning <sid.manning@oss.qualcomm.com>
Acked-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon_globalreg.h | 55 ++++++
hw/hexagon/hexagon_globalreg.c | 243 +++++++++++++++++++++++++
2 files changed, 298 insertions(+)
create mode 100644 include/hw/hexagon/hexagon_globalreg.h
create mode 100644 hw/hexagon/hexagon_globalreg.c
diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h
new file mode 100644
index 00000000000..950099808fd
--- /dev/null
+++ b/include/hw/hexagon/hexagon_globalreg.h
@@ -0,0 +1,55 @@
+/*
+ * Hexagon Global Registers QOM Object
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_GLOBALREG_H
+#define HEXAGON_GLOBALREG_H
+
+#include "hw/core/qdev.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+
+#define TYPE_HEXAGON_GLOBALREG "hexagon-globalreg"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonGlobalRegState, HEXAGON_GLOBALREG)
+
+struct HexagonGlobalRegState {
+ SysBusDevice parent_obj;
+
+ /* Array of system registers */
+ uint32_t regs[NUM_SREGS];
+
+ /* Global performance cycle counter base */
+ uint64_t g_pcycle_base;
+
+ /* Properties for global register reset values */
+ uint32_t boot_evb; /* Boot Exception Vector Base (HEX_SREG_EVB) */
+ uint64_t config_table_addr; /* Configuration table base */
+ uint32_t dsp_rev; /* DSP revision register (HEX_SREG_REV) */
+
+ /* ISDB properties */
+ bool isdben_etm_enable; /* ISDB ETM enable bit */
+ bool isdben_dfd_enable; /* ISDB DFD enable bit */
+ bool isdben_trusted; /* ISDB trusted mode bit */
+ bool isdben_secure; /* ISDB secure mode bit */
+};
+
+/* Public interface functions */
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t htid);
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value, uint32_t htid);
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value);
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value);
+
+/* Global performance cycle counter access */
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s);
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
+ uint64_t value);
+
+#endif /* HEXAGON_GLOBALREG_H */
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
new file mode 100644
index 00000000000..28cb5a4158d
--- /dev/null
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -0,0 +1,243 @@
+/*
+ * Hexagon Global Registers
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/sysbus.h"
+#include "hw/core/resettable.h"
+#include "migration/vmstate.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+#include "target/hexagon/hex_regs.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+
+#define IMMUTABLE (~0)
+#define INVALID_REG_VAL 0xdeadbeef
+
+/* Global system register mutability masks */
+static const uint32_t global_sreg_immut_masks[NUM_SREGS] = {
+ [HEX_SREG_EVB] = 0x000000ff,
+ [HEX_SREG_MODECTL] = IMMUTABLE,
+ [HEX_SREG_SYSCFG] = 0x80001c00,
+ [HEX_SREG_IPENDAD] = IMMUTABLE,
+ [HEX_SREG_VID] = 0xfc00fc00,
+ [HEX_SREG_VID1] = 0xfc00fc00,
+ [HEX_SREG_BESTWAIT] = 0xfffffe00,
+ [HEX_SREG_IAHL] = 0x00000000,
+ [HEX_SREG_SCHEDCFG] = 0xfffffee0,
+ [HEX_SREG_CFGBASE] = IMMUTABLE,
+ [HEX_SREG_DIAG] = 0x00000000,
+ [HEX_SREG_REV] = IMMUTABLE,
+ [HEX_SREG_ISDBST] = IMMUTABLE,
+ [HEX_SREG_ISDBCFG0] = 0xe0000000,
+ [HEX_SREG_BRKPTPC0] = 0x00000003,
+ [HEX_SREG_BRKPTCFG0] = 0xfc007000,
+ [HEX_SREG_BRKPTPC1] = 0x00000003,
+ [HEX_SREG_BRKPTCFG1] = 0xfc007000,
+ [HEX_SREG_ISDBMBXIN] = IMMUTABLE,
+ [HEX_SREG_ISDBMBXOUT] = 0x00000000,
+ [HEX_SREG_ISDBEN] = 0xfffffffe,
+ [HEX_SREG_TIMERLO] = IMMUTABLE,
+ [HEX_SREG_TIMERHI] = IMMUTABLE,
+};
+
+static void hexagon_globalreg_init(Object *obj)
+{
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
+
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val,
+ uint32_t reg_mask)
+{
+ if (reg_mask) {
+ return (new_val & ~reg_mask) | (cur_val & reg_mask);
+ }
+ return new_val;
+}
+
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t htid)
+{
+ uint32_t value;
+
+ if (!s) {
+ return 0;
+ }
+ g_assert(reg < NUM_SREGS);
+ g_assert(reg >= HEX_SREG_GLB_START);
+
+ value = s->regs[reg];
+
+ return value;
+}
+
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value, uint32_t htid)
+{
+ if (!s) {
+ return;
+ }
+ g_assert(reg < NUM_SREGS);
+ g_assert(reg >= HEX_SREG_GLB_START);
+ s->regs[reg] = value;
+}
+
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value)
+{
+ uint32_t reg_mask;
+
+ if (!s) {
+ return value;
+ }
+ g_assert(reg < NUM_SREGS);
+ g_assert(reg >= HEX_SREG_GLB_START);
+ reg_mask = global_sreg_immut_masks[reg];
+ return reg_mask == IMMUTABLE ?
+ s->regs[reg] :
+ apply_write_mask(value, s->regs[reg], reg_mask);
+}
+
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value)
+{
+ if (!s) {
+ return;
+ }
+ s->regs[reg] = hexagon_globalreg_masked_value(s, reg, value);
+}
+
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s)
+{
+ g_assert(s);
+ return s->g_pcycle_base;
+}
+
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
+ uint64_t value)
+{
+ g_assert(s);
+ s->g_pcycle_base = value;
+}
+
+static void do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
+{
+ uint32_t isdben_val = 0;
+
+ g_assert(s);
+ memset(s->regs, 0, sizeof(s->regs));
+
+ s->g_pcycle_base = 0;
+
+ s->regs[HEX_SREG_EVB] = s->boot_evb;
+ s->regs[HEX_SREG_CFGBASE] = HEXAGON_CFG_ADDR_BASE(s->config_table_addr);
+ s->regs[HEX_SREG_REV] = s->dsp_rev;
+
+ if (s->isdben_etm_enable) {
+ isdben_val |= (1 << 0); /* ETM enable bit */
+ }
+ if (s->isdben_dfd_enable) {
+ isdben_val |= (1 << 1); /* DFD enable bit */
+ }
+ if (s->isdben_trusted) {
+ isdben_val |= (1 << 2); /* Trusted bit */
+ }
+ if (s->isdben_secure) {
+ isdben_val |= (1 << 3); /* Secure bit */
+ }
+ s->regs[HEX_SREG_ISDBEN] = isdben_val;
+ s->regs[HEX_SREG_MODECTL] = 0x1;
+
+ /*
+ * These register indices are placeholders in these arrays
+ * and their actual values are synthesized from state elsewhere.
+ * We can initialize these with invalid values so that if we
+ * mistakenly generate reads, they will look obviously wrong.
+ */
+ s->regs[HEX_SREG_PCYCLELO] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PCYCLEHI] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_TIMERLO] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_TIMERHI] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT0] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT1] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT2] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT3] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT4] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT5] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT6] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT7] = INVALID_REG_VAL;
+}
+
+static void hexagon_globalreg_reset_hold(Object *obj, ResetType type)
+{
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
+ do_hexagon_globalreg_reset(s);
+}
+
+static const VMStateDescription vmstate_hexagon_globalreg = {
+ .name = "hexagon_globalreg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]){
+ VMSTATE_UINT32_ARRAY(regs, HexagonGlobalRegState, NUM_SREGS),
+ VMSTATE_UINT64(g_pcycle_base, HexagonGlobalRegState),
+ VMSTATE_UINT32(boot_evb, HexagonGlobalRegState),
+ VMSTATE_UINT64(config_table_addr, HexagonGlobalRegState),
+ VMSTATE_UINT32(dsp_rev, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_etm_enable, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_dfd_enable, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_trusted, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_secure, HexagonGlobalRegState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property hexagon_globalreg_properties[] = {
+ DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
+ DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
+ config_table_addr, 0xffffffffULL),
+ DEFINE_PROP_UINT32("dsp-rev", HexagonGlobalRegState, dsp_rev, 0),
+ DEFINE_PROP_BOOL("isdben-etm-enable", HexagonGlobalRegState,
+ isdben_etm_enable, false),
+ DEFINE_PROP_BOOL("isdben-dfd-enable", HexagonGlobalRegState,
+ isdben_dfd_enable, false),
+ DEFINE_PROP_BOOL("isdben-trusted", HexagonGlobalRegState,
+ isdben_trusted, false),
+ DEFINE_PROP_BOOL("isdben-secure", HexagonGlobalRegState,
+ isdben_secure, false),
+};
+
+static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = hexagon_globalreg_reset_hold;
+ dc->vmsd = &vmstate_hexagon_globalreg;
+ dc->user_creatable = false;
+ device_class_set_props(dc, hexagon_globalreg_properties);
+}
+
+static const TypeInfo hexagon_globalreg_info = {
+ .name = TYPE_HEXAGON_GLOBALREG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HexagonGlobalRegState),
+ .instance_init = hexagon_globalreg_init,
+ .class_init = hexagon_globalreg_class_init,
+};
+
+static void hexagon_globalreg_register_types(void)
+{
+ type_register_static(&hexagon_globalreg_info);
+}
+
+type_init(hexagon_globalreg_register_types)
--
2.34.1
© 2016 - 2026 Red Hat, Inc.