Let the hexagon-sim-style machines their QDSP6 subsystem, and with it the
l2vic and QTimer.

The config table's subsystem base is updated to align with the chosen
address.

Reviewed-by: Anton Johansson <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 MAINTAINERS                       |  1 +
 include/hw/hexagon/hexagon.h      |  4 ++
 hw/hexagon/hexagon_dsp.c          | 71 +++++++++++++++++++++++++++-
 tests/qtest/hexagon-config-test.c | 78 +++++++++++++++++++++++++++++++
 tests/qtest/meson.build           |  3 +-
 5 files changed, 155 insertions(+), 2 deletions(-)
 create mode 100644 tests/qtest/hexagon-config-test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0bbd7986658..72082ce854d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1391,6 +1391,7 @@ F: include/hw/misc/qcom-qdsp6ss-clk.h
 F: configs/devices/hexagon-softmmu/default.mak
 F: docs/system/hexagon/
 F: tests/functional/hexagon/
+F: tests/qtest/hexagon-config-test.c
 F: tests/qtest/qcom-dsp-test.c
 F: docs/devel/hexagon-sys.rst
 
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index c4e78216fb8..678e658a6d3 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -47,6 +47,10 @@ typedef enum {
 
 #define HEXAGON_CFGSPACE_ENTRIES (128)
 
+/* Offsets of q6ss cfg peripherals from the subsystem base. */
+#define HEXAGON_L2VIC_OFFSET  0x10000
+#define HEXAGON_QTIMER_OFFSET 0x21000
+
 union hexagon_config_table {
     struct {
         /* Base address of L2TCM space */
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index 3854342014f..05b95f39aa2 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -17,6 +17,7 @@
 #include "hw/hexagon/hex-subsys.h"
 #include "hw/core/loader.h"
 #include "qapi/error.h"
+#include "qapi/visitor.h"
 #include "qemu/error-report.h"
 #include "qemu/log.h"
 #include "elf.h"
@@ -38,6 +39,8 @@
 #include "machine_cfg_v85qa_1.h.inc"
 
 #define TYPE_HEXAGON_DSP_MACHINE "hexagon-dsp-machine"
+#define HEXAGON_DSP_SUBSYSTEM_BASE 0xfc900000
+#define HEXAGON_DSP_SUBSYSTEM_SIZE (HEXAGON_QTIMER_OFFSET + 0x1000)
 OBJECT_DECLARE_SIMPLE_TYPE(HexagonDspMachineState, HEXAGON_DSP_MACHINE)
 
 struct HexagonDspMachineState {
@@ -45,6 +48,8 @@ struct HexagonDspMachineState {
 
     hwaddr isdb_secure_flag;
     hwaddr isdb_trusted_flag;
+    uint32_t subsystem_base;
+    struct hexagon_machine_config config;
 };
 
 static HexagonDspMachineState *current_dms;
@@ -110,6 +115,58 @@ static void do_cpu_reset(void *opaque)
     cpu_reset(cs);
 }
 
+static void hexagon_sim_get_subsystem_base(Object *obj, Visitor *v,
+                                           const char *name, void *opaque,
+                                           Error **errp)
+{
+    HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(obj);
+    uint32_t value = dms->subsystem_base;
+
+    visit_type_uint32(v, name, &value, errp);
+}
+
+static void hexagon_sim_set_subsystem_base(Object *obj, Visitor *v,
+                                           const char *name, void *opaque,
+                                           Error **errp)
+{
+    HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(obj);
+    uint64_t subsystem_end;
+    uint32_t value;
+
+    if (!visit_type_uint32(v, name, &value, errp)) {
+        return;
+    }
+    if (!value || !QEMU_IS_ALIGNED(value, 64 * KiB)) {
+        error_setg(errp, "subsystem-base must be nonzero and 64 KiB aligned");
+        return;
+    }
+    subsystem_end = (uint64_t)value + HEXAGON_DSP_SUBSYSTEM_SIZE;
+    if (subsystem_end > (uint64_t)UINT32_MAX + 1) {
+        error_setg(errp, "subsystem-base 0x%x requires 0x%x bytes for the "
+                   "subsystem, beyond the end of the address space",
+                   value, HEXAGON_DSP_SUBSYSTEM_SIZE);
+        return;
+    }
+
+    dms->subsystem_base = value;
+}
+
+static void add_dsp_properties(ObjectClass *oc)
+{
+    object_class_property_add(oc, "subsystem-base", "uint32",
+                              hexagon_sim_get_subsystem_base,
+                              hexagon_sim_set_subsystem_base, NULL, NULL);
+    object_class_property_set_description(oc, "subsystem-base",
+                                          "Simulator subsystem base address");
+}
+
+static void hexagon_dsp_init(Object *obj)
+{
+    HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(obj);
+
+    dms->subsystem_base = HEXAGON_DSP_SUBSYSTEM_BASE;
+}
+
 static void hexagon_common_init(MachineState *machine, Rev_t rev,
                                 const struct hexagon_machine_config *m_cfg)
 {
@@ -124,7 +181,13 @@ static void hexagon_common_init(MachineState *machine, 
Rev_t rev,
 
     machine->enable_graphics = 0;
 
-    hex_subsys_create(hms, m_cfg, rev);
+    dms->config = *m_cfg;
+    dms->config.csr_base = dms->subsystem_base;
+    dms->config.l2vic_base = dms->subsystem_base + HEXAGON_L2VIC_OFFSET;
+    dms->config.qtmr_region = dms->subsystem_base + HEXAGON_QTIMER_OFFSET;
+    dms->config.cfgtable.subsystem_base = dms->subsystem_base >> 16;
+
+    hex_subsys_create(hms, &dms->config, rev);
 
     g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, machine->smp.cpus);
 
@@ -186,6 +249,7 @@ static void v66g_1024_init(ObjectClass *oc, const void 
*data)
     mc->is_default = true;
     mc->default_cpu_type = TYPE_HEXAGON_CPU_V66;
     mc->default_cpus = 4;
+    add_dsp_properties(oc);
 }
 
 static void v68n_1024_config_init(MachineState *machine)
@@ -202,6 +266,7 @@ static void v68n_1024_init(ObjectClass *oc, const void 
*data)
     init_mc(mc);
     mc->default_cpu_type = TYPE_HEXAGON_CPU_V68;
     mc->default_cpus = 6;
+    add_dsp_properties(oc);
 }
 
 static void v73nc_1_config_init(MachineState *machine)
@@ -239,6 +304,7 @@ static void v79na_1_init(ObjectClass *oc, const void *data)
     init_mc(mc);
     mc->default_cpu_type = TYPE_HEXAGON_CPU_V79;
     mc->default_cpus = 8;
+    add_dsp_properties(oc);
 }
 
 static void v81dgb_1_init(ObjectClass *oc, const void *data)
@@ -251,6 +317,7 @@ static void v81dgb_1_init(ObjectClass *oc, const void *data)
     mc->default_cpu_type = TYPE_HEXAGON_CPU_V81;
     mc->max_cpus = 12;
     mc->default_cpus = 12;
+    add_dsp_properties(oc);
 }
 
 static void v81qa_1_config_init(MachineState *machine)
@@ -268,6 +335,7 @@ static void v81qa_1_init(ObjectClass *oc, const void *data)
     mc->default_cpu_type = TYPE_HEXAGON_CPU_V81;
     mc->max_cpus = 12;
     mc->default_cpus = 12;
+    add_dsp_properties(oc);
 }
 
 static void v85qa_1_config_init(MachineState *machine)
@@ -316,6 +384,7 @@ static const TypeInfo hexagon_machine_types[] = {
         .name = TYPE_HEXAGON_DSP_MACHINE,
         .parent = TYPE_HEXAGON_COMMON_MACHINE,
         .instance_size = sizeof(HexagonDspMachineState),
+        .instance_init = hexagon_dsp_init,
         .abstract = true,
     },
     {
diff --git a/tests/qtest/hexagon-config-test.c 
b/tests/qtest/hexagon-config-test.c
new file mode 100644
index 00000000000..9554fce57ca
--- /dev/null
+++ b/tests/qtest/hexagon-config-test.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "hw/hexagon/hexagon.h"
+
+#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
+#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
+#include "hw/hexagon/machine_cfg_v79na_1.h.inc"
+#include "hw/hexagon/machine_cfg_v81dgb_1.h.inc"
+#include "hw/hexagon/machine_cfg_v81qa_1.h.inc"
+
+typedef struct {
+    const char *machine;
+    const struct hexagon_machine_config *cfg;
+    uint32_t subsystem_base;
+} HexagonMachineCfg;
+
+static const HexagonMachineCfg hexagon_machines[] = {
+    { "V66G_1024", &v66g_1024, 0 },
+    { "V68N_1024", &v68n_1024, 0 },
+    { "V79NA_1", &v79na_1, 0 },
+    { "V81DGB_1", &v81dgb_1, 0 },
+    { "V81QA_1", &v81qa_1, 0 },
+    { "V81QA_1", &v81qa_1, 0xfca00000 },
+};
+
+static void test_config_table(gconstpointer data)
+{
+    const HexagonMachineCfg *mc = data;
+    uint64_t subsystem_base;
+    uint32_t subsystem_base_entry;
+    g_autofree char *args;
+
+    if (mc->subsystem_base) {
+        args = g_strdup_printf("-machine %s,subsystem-base=0x%x", mc->machine,
+                               mc->subsystem_base);
+    } else {
+        args = g_strdup_printf("-machine %s", mc->machine);
+    }
+
+    qtest_start(args);
+
+    subsystem_base_entry = readl(mc->cfg->cfgbase +
+                                 offsetof(union hexagon_config_table,
+                                          subsystem_base));
+    subsystem_base = (uint64_t)subsystem_base_entry << 16;
+    g_assert_cmphex(subsystem_base, ==,
+                    mc->subsystem_base ?: mc->cfg->csr_base);
+    writel(subsystem_base + HEXAGON_L2VIC_OFFSET + 0x200, 1);
+    g_assert_cmphex(readl(subsystem_base + HEXAGON_L2VIC_OFFSET + 0x100),
+                    ==, 1);
+    g_assert_cmphex(readl(subsystem_base + HEXAGON_QTIMER_OFFSET + 0x10),
+                    ==, 19200000);
+
+    qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+    size_t i;
+
+    g_test_init(&argc, &argv, NULL);
+
+    for (i = 0; i < ARRAY_SIZE(hexagon_machines); i++) {
+        const HexagonMachineCfg *mc = &hexagon_machines[i];
+        g_autofree char *path = g_strdup_printf("/config/%s/%x", mc->machine,
+                                                mc->subsystem_base);
+
+        qtest_add_data_func(path, mc, test_config_table);
+    }
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 7ab472a8100..46d4fc1d2b0 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -321,7 +321,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
    ['k230-ddr-test', 'k230-wdt-test', 'k230-gsdma-test', 
'k230-decomp-gzip-test'] : []) + \
    ['milkv-duo-test']
 
-qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qcom-dsp-test',
+qtests_hexagon = ['boot-serial-test', 'hexagon-config-test', 'l2vic-test',
+                  'qcom-dsp-test',
                   'qct-qtimer-test']
 
 qos_test_ss = ss.source_set()
-- 
2.34.1

Reply via email to