* [PATCH 00/14] Hexagon: Add real SoC-style machines
@ 2026-10-19 5:52 Brian Cain
2026-10-19 5:52 ` [PATCH 01/14] Hexagon: add v85 CPU model Brian Cain
` (13 more replies)
0 siblings, 14 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Previously we added synthetic machines intended for compatibility with
programs created by the Hexagon SDK. These simple configurations have a
memory/irq map that doesn't match any real chips, and they are limited
to an interrupt controller and a timer device.
Here we add DSP machines that reflect real-world devices and run some of
the commercial firmware to test it. Note that for now the boot will not
progress much beyond the initial kernel boot. Dependencies on other
yet-to-be-modeled devices are preventing the firmware from coming up fully
to a steady/idle state.
Brian Cain (14):
Hexagon: add v85 CPU model
hw/hexagon: let a machine place its DDR
hw/hexagon: introduce hex-board abstraction
hw/hexagon: convert virt board to hex-board
hw/misc: add the QDSP6SS PLL, RCG
hw/hexagon: add the QCS6490 CDSP machine
hw/hexagon: add the SA8775P CDSP machine
hw/hexagon: add the SC8480XP NSP0 machine
hw/hexagon: add the SA8797P NSP0 machine
hw/hexagon: add the SM8975 NSP machine
hw/hexagon: add v79NA1 machine
hw/hexagon: add subsystem-base property
target/hexagon: fix the allocframe framekey
tests/functional/hexagon: boot DSP firmware
MAINTAINERS | 6 +
docs/system/hexagon/emulation.rst | 2 +-
include/hw/hexagon/hex-board.h | 65 +++
include/hw/hexagon/hexagon.h | 10 +
include/hw/hexagon/qcom_dsp.h | 81 ++++
include/hw/hexagon/virt.h | 6 -
include/hw/misc/qcom-qdsp6ss-clk.h | 15 +
target/hexagon/cpu-qom.h | 4 +
hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc | 65 +++
hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc | 6 +-
hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc | 56 +++
hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc | 52 +++
hw/hexagon/machine_cfg_sm8975_nsp.h.inc | 55 +++
hw/hexagon/machine_cfg_v79na_1.h.inc | 34 ++
hw/hexagon/hex-board.c | 265 ++++++++++++
hw/hexagon/hex-subsys.c | 4 +-
hw/hexagon/hexagon_dsp.c | 84 +++-
hw/hexagon/qcom_dsp.c | 399 ++++++++++++++++++
hw/hexagon/qcs6490_cdsp.c | 64 +++
hw/hexagon/sa8775p_cdsp.c | 59 +++
hw/hexagon/sa8797p_nsp0.c | 68 +++
hw/hexagon/sc8480xp_nsp0.c | 90 ++++
hw/hexagon/sm8975_nsp.c | 102 +++++
hw/hexagon/virt.c | 309 ++------------
hw/misc/qcom-qdsp6ss-clk.c | 208 +++++++++
linux-user/hexagon/elfload.c | 4 +
target/hexagon/cpu.c | 2 +
target/hexagon/idef-parser/parser-helpers.c | 2 +-
tests/qtest/hexagon-config-test.c | 78 ++++
tests/qtest/l2vic-test.c | 10 +
tests/qtest/qcom-dsp-test.c | 113 +++++
tests/qtest/qct-qtimer-test.c | 10 +
tests/tcg/hexagon/framekey.c | 67 +++
hw/hexagon/Kconfig | 48 ++-
hw/hexagon/meson.build | 7 +
hw/misc/Kconfig | 3 +
hw/misc/meson.build | 3 +
tests/functional/hexagon/meson.build | 2 +
.../hexagon/test_qcom_dsp_firmware.py | 89 ++++
tests/qtest/meson.build | 4 +-
tests/tcg/hexagon/meson.build | 1 +
41 files changed, 2254 insertions(+), 298 deletions(-)
create mode 100644 include/hw/hexagon/hex-board.h
create mode 100644 include/hw/hexagon/qcom_dsp.h
create mode 100644 include/hw/misc/qcom-qdsp6ss-clk.h
create mode 100644 hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
create mode 100644 hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc
create mode 100644 hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc
create mode 100644 hw/hexagon/machine_cfg_sm8975_nsp.h.inc
create mode 100644 hw/hexagon/machine_cfg_v79na_1.h.inc
create mode 100644 hw/hexagon/hex-board.c
create mode 100644 hw/hexagon/qcom_dsp.c
create mode 100644 hw/hexagon/qcs6490_cdsp.c
create mode 100644 hw/hexagon/sa8775p_cdsp.c
create mode 100644 hw/hexagon/sa8797p_nsp0.c
create mode 100644 hw/hexagon/sc8480xp_nsp0.c
create mode 100644 hw/hexagon/sm8975_nsp.c
create mode 100644 hw/misc/qcom-qdsp6ss-clk.c
create mode 100644 tests/qtest/hexagon-config-test.c
create mode 100644 tests/qtest/qcom-dsp-test.c
create mode 100644 tests/tcg/hexagon/framekey.c
create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
--
2.34.1
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH 01/14] Hexagon: add v85 CPU model
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:32 ` Anton Johansson via qemu development
2026-10-19 5:52 ` [PATCH 02/14] hw/hexagon: let a machine place its DDR Brian Cain
` (12 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
docs/system/hexagon/emulation.rst | 2 +-
target/hexagon/cpu-qom.h | 4 ++++
linux-user/hexagon/elfload.c | 4 ++++
target/hexagon/cpu.c | 2 ++
4 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/docs/system/hexagon/emulation.rst b/docs/system/hexagon/emulation.rst
index 12385311aa4..fb57c77ae90 100644
--- a/docs/system/hexagon/emulation.rst
+++ b/docs/system/hexagon/emulation.rst
@@ -6,7 +6,7 @@ Hexagon CPU architecture support
================================
QEMU's TCG emulation includes support for v65, v66, v67, v68, v69, v71, v73,
-v75, v77, v79, v81.
+v75, v77, v79, v81, v83, v85.
It also has support for the following architecture extensions:
- HVX (Hexagon Vector eXtensions)
diff --git a/target/hexagon/cpu-qom.h b/target/hexagon/cpu-qom.h
index 2bfa4d5d0fc..d4c8413ded3 100644
--- a/target/hexagon/cpu-qom.h
+++ b/target/hexagon/cpu-qom.h
@@ -28,6 +28,8 @@ typedef enum {
HEX_VER_V75 = 0x75,
HEX_VER_V79 = 0x79,
HEX_VER_V81 = 0x81,
+ HEX_VER_V83 = 0x83,
+ HEX_VER_V85 = 0x85,
HEX_VER_ANY = 0xff,
} HexagonVersion;
@@ -55,6 +57,8 @@ typedef struct {
#define TYPE_HEXAGON_CPU_V75 HEXAGON_CPU_TYPE_NAME("v75")
#define TYPE_HEXAGON_CPU_V79 HEXAGON_CPU_TYPE_NAME("v79")
#define TYPE_HEXAGON_CPU_V81 HEXAGON_CPU_TYPE_NAME("v81")
+#define TYPE_HEXAGON_CPU_V83 HEXAGON_CPU_TYPE_NAME("v83")
+#define TYPE_HEXAGON_CPU_V85 HEXAGON_CPU_TYPE_NAME("v85")
OBJECT_DECLARE_CPU_TYPE(HexagonCPU, HexagonCPUClass, HEXAGON_CPU)
diff --git a/linux-user/hexagon/elfload.c b/linux-user/hexagon/elfload.c
index 3a6ba4e1304..9f98ad8fb86 100644
--- a/linux-user/hexagon/elfload.c
+++ b/linux-user/hexagon/elfload.c
@@ -113,6 +113,10 @@ const char *get_elf_cpu_model(uint32_t eflags)
return "v79";
case 0x81:
return "v81";
+ case 0x83:
+ return "v83";
+ case 0x85:
+ return "v85";
}
err = snprintf(buf, sizeof(buf), "unknown (0x%x)", eflags);
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index f20d6de6f63..1e3df5d0d03 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -934,6 +934,8 @@ static const TypeInfo hexagon_cpu_type_infos[] = {
DEFINE_CPU(TYPE_HEXAGON_CPU_V75, HEX_VER_V75),
DEFINE_CPU(TYPE_HEXAGON_CPU_V79, HEX_VER_V79),
DEFINE_CPU(TYPE_HEXAGON_CPU_V81, HEX_VER_V81),
+ DEFINE_CPU(TYPE_HEXAGON_CPU_V83, HEX_VER_V83),
+ DEFINE_CPU(TYPE_HEXAGON_CPU_V85, HEX_VER_V85),
};
DEFINE_TYPES(hexagon_cpu_type_infos)
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 02/14] hw/hexagon: let a machine place its DDR
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
2026-10-19 5:52 ` [PATCH 01/14] Hexagon: add v85 CPU model Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 21:40 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 03/14] hw/hexagon: introduce hex-board abstraction Brian Cain
` (11 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
hex_subsys_create() always maps the main DDR at address 0. This is appropriate
for hexagon-sim-style machines, but real SoCs map it elsewhere.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon.h | 2 ++
hw/hexagon/hex-subsys.c | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 9b5d33ffc3b..6955e600aee 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -145,6 +145,8 @@ union hexagon_config_table {
};
struct hexagon_machine_config {
+ /* Base address of the main DDR region */
+ hwaddr ddr_base;
/* Base address of config table */
uint32_t cfgbase;
/* Size of L2 TCM */
diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c
index 9818cf58878..382f45bd09f 100644
--- a/hw/hexagon/hex-subsys.c
+++ b/hw/hexagon/hex-subsys.c
@@ -136,10 +136,10 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
MachineState *machine = MACHINE(hms);
MemoryRegion *sysmem = get_system_memory();
- /* Main DDR at the reset vector. */
+ /* Main DDR. */
memory_region_init_ram(&hms->ram, NULL, "ddr.ram", machine->ram_size,
&error_fatal);
- memory_region_add_subregion(sysmem, 0x0, &hms->ram);
+ memory_region_add_subregion(sysmem, m_cfg->ddr_base, &hms->ram);
/* Config-table ROM and the blob that backs it. */
memory_region_init_rom(&hms->cfgtable_rom, NULL, "config_table.rom",
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 03/14] hw/hexagon: introduce hex-board abstraction
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
2026-10-19 5:52 ` [PATCH 01/14] Hexagon: add v85 CPU model Brian Cain
2026-10-19 5:52 ` [PATCH 02/14] hw/hexagon: let a machine place its DDR Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 21:42 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 04/14] hw/hexagon: convert virt board to hex-board Brian Cain
` (10 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Move what virt.c does to build a board out of it into helpers in a new
hex-board.c, so that other Hexagon machines that describe themselves
with a generated device tree can reuse it.
This will be used by future commits.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
MAINTAINERS | 2 +
include/hw/hexagon/hex-board.h | 65 ++++++++
hw/hexagon/hex-board.c | 265 +++++++++++++++++++++++++++++++++
hw/hexagon/Kconfig | 9 +-
hw/hexagon/meson.build | 1 +
5 files changed, 340 insertions(+), 2 deletions(-)
create mode 100644 include/hw/hexagon/hex-board.h
create mode 100644 hw/hexagon/hex-board.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 22caaee9671..4c9eb1892c1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -256,6 +256,8 @@ F: tests/qtest/l2vic-test.c
F: hw/timer/qct-qtimer.c
F: include/hw/timer/qct-qtimer.h
F: tests/qtest/qct-qtimer-test.c
+F: hw/hexagon/hex-board.c
+F: include/hw/hexagon/hex-board.h
X: target/hexagon/idef-parser/
X: target/hexagon/gen_idef_parser_funcs.py
F: linux-user/hexagon/
diff --git a/include/hw/hexagon/hex-board.h b/include/hw/hexagon/hex-board.h
new file mode 100644
index 00000000000..93a31cb2ecc
--- /dev/null
+++ b/include/hw/hexagon/hex-board.h
@@ -0,0 +1,65 @@
+/*
+ * Board-construction helpers shared by the Hexagon machines.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_HEXAGON_HEX_BOARD_H
+#define HW_HEXAGON_HEX_BOARD_H
+
+#include "hw/hexagon/hexagon.h"
+
+/* The L2VIC interrupt specifiers of the 32 per-cpu lines precede its lines. */
+#define HEX_BOARD_L2VIC_SPI_BASE 32
+
+/*
+ * Create the device tree with its root, /soc and /chosen (including an
+ * rng-seed) nodes. Returns its size in @fdt_size.
+ */
+void hex_board_create_fdt(MachineState *ms, const char *model,
+ const char *compatible, int *fdt_size);
+
+/* Add the L2VIC node and make it the interrupt parent of /soc. */
+int32_t hex_board_fdt_add_l2vic(MachineState *ms,
+ const struct hexagon_machine_config *cfg);
+
+/* Add the /soc/vtcm and /soc/hvx nodes, for what the config provides. */
+void hex_board_fdt_add_hvx(MachineState *ms,
+ const struct hexagon_machine_config *cfg);
+
+/* Add one /cpus/cpu@N node per CPU of the machine. */
+void hex_board_fdt_add_cpus(MachineState *ms);
+
+/* Create the L2 TCM RAM, if the config has any. */
+void hex_board_create_tcm(const struct hexagon_machine_config *cfg,
+ MemoryRegion *tcm);
+
+/* Create the PL011 console and its fixed clock, and describe them. */
+void hex_board_create_uart(MachineState *ms, hwaddr base, hwaddr size,
+ int irq, int32_t l2vic_phandle);
+
+/* Create @count virtio-mmio transports on consecutive lines and slots. */
+void hex_board_create_virtio(MachineState *ms, hwaddr base, hwaddr size,
+ int irq_base, int count,
+ int32_t l2vic_phandle);
+
+/*
+ * Load an ELF for the guest and return its entry point. If @translate is
+ * given it maps the ELF's addresses. The highest address used is returned
+ * in @high, if non-NULL. Exits on failure.
+ */
+uint64_t hex_board_load_elf(const char *filename,
+ uint64_t (*translate)(void *opaque, uint64_t addr),
+ void *opaque, uint64_t *high);
+
+/* Copy the device tree to @addr and refresh its rng-seed on reset. */
+void hex_board_load_fdt(MachineState *ms, int fdt_size, hwaddr addr);
+
+/*
+ * Create the machine's CPUs, with CPU 0 starting at @start if @have_start,
+ * and realize the cluster.
+ */
+void hex_board_create_cpus(MachineState *ms, bool have_start, uint64_t start);
+
+#endif /* HW_HEXAGON_HEX_BOARD_H */
diff --git a/hw/hexagon/hex-board.c b/hw/hexagon/hex-board.c
new file mode 100644
index 00000000000..3bf09e4e7c7
--- /dev/null
+++ b/hw/hexagon/hex-board.c
@@ -0,0 +1,265 @@
+/*
+ * Board-construction helpers shared by the Hexagon machines that describe
+ * themselves to the guest with a generated device tree.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "elf.h"
+#include "hw/char/pl011.h"
+#include "hw/core/boards.h"
+#include "hw/core/clock.h"
+#include "hw/core/loader.h"
+#include "hw/core/qdev-clock.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/sysbus.h"
+#include "hw/hexagon/hex-board.h"
+#include "hw/hexagon/hex-subsys.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "system/address-spaces.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
+#include "system/system.h"
+#include "target/hexagon/cpu.h"
+
+#define APB_CLK_HZ 24000000
+
+void hex_board_create_fdt(MachineState *ms, const char *model,
+ const char *compatible, int *fdt_size)
+{
+ void *fdt = create_device_tree(fdt_size);
+ uint8_t rng_seed[32];
+
+ if (!fdt) {
+ error_report("create_device_tree() failed");
+ exit(1);
+ }
+
+ ms->fdt = fdt;
+
+ qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+ qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1);
+ qemu_fdt_setprop_string(fdt, "/", "model", model);
+ qemu_fdt_setprop_string(fdt, "/", "compatible", compatible);
+
+ qemu_fdt_add_subnode(fdt, "/soc");
+ qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+ qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1);
+ qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
+
+ qemu_fdt_add_subnode(fdt, "/chosen");
+ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+ qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
+}
+
+static void fdt_set_irq(MachineState *ms, const char *nodename, int irq)
+{
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+ HEX_BOARD_L2VIC_SPI_BASE + irq, 0);
+}
+
+int32_t hex_board_fdt_add_l2vic(MachineState *ms,
+ const struct hexagon_machine_config *cfg)
+{
+ int32_t l2vic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ g_autofree char *nodename = g_strdup_printf("/soc/interrupt-controller@%x",
+ cfg->l2vic_base);
+ static const char compat[] = "qcom,h2-pic\0hvm-pic";
+
+ qemu_fdt_setprop_cell(ms->fdt, "/soc", "interrupt-parent", l2vic_phandle);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+ qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, cfg->l2vic_base,
+ cfg->l2vic_size);
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", l2vic_phandle);
+
+ return l2vic_phandle;
+}
+
+void hex_board_fdt_add_hvx(MachineState *ms,
+ const struct hexagon_machine_config *cfg)
+{
+ const union hexagon_config_table *t = &cfg->cfgtable;
+
+ if (t->vtcm_size_kb > 0) {
+ qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm");
+ qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible",
+ "qcom,hexagon_vtcm");
+ qemu_fdt_setprop_cells(ms->fdt, "/soc/vtcm", "reg", 0,
+ t->vtcm_base << 16, t->vtcm_size_kb * 1024);
+ }
+
+ if (t->ext_contexts > 0) {
+ qemu_fdt_add_subnode(ms->fdt, "/soc/hvx");
+ qemu_fdt_setprop_string(ms->fdt, "/soc/hvx", "compatible",
+ "qcom,hexagon-hvx");
+ qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-max-ctxts",
+ t->ext_contexts);
+ qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-vlength",
+ t->hvx_vec_log_length);
+ }
+}
+
+void hex_board_fdt_add_cpus(MachineState *ms)
+{
+ qemu_fdt_add_subnode(ms->fdt, "/cpus");
+ qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
+ qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
+
+ for (int num = ms->smp.cpus - 1; num >= 0; num--) {
+ g_autofree char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
+ qemu_fdt_alloc_phandle(ms->fdt));
+ }
+}
+
+void hex_board_create_tcm(const struct hexagon_machine_config *cfg,
+ MemoryRegion *tcm)
+{
+ if (cfg->l2tcm_size) {
+ memory_region_init_ram(tcm, NULL, "tcm.ram", cfg->l2tcm_size,
+ &error_fatal);
+ memory_region_add_subregion(get_system_memory(),
+ (hwaddr)cfg->cfgtable.l2tcm_base << 16,
+ tcm);
+ }
+}
+
+void hex_board_create_uart(MachineState *ms, hwaddr base, hwaddr size,
+ int irq, int32_t l2vic_phandle)
+{
+ static const char compat[] = "arm,pl011\0arm,primecell";
+ static const char clocknames[] = "uartclk\0apb_pclk";
+ HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
+ int32_t clk_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ g_autofree char *nodename = g_strdup_printf("/pl011@%" PRIx64, base);
+ Clock *apb_clk = clock_new(OBJECT(ms), "apb-pclk");
+ DeviceState *dev = qdev_new(TYPE_PL011);
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
+
+ clock_set_hz(apb_clk, APB_CLK_HZ);
+
+ qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+ qdev_connect_clock_in(dev, "clk", apb_clk);
+ sysbus_realize_and_unref(s, &error_fatal);
+ sysbus_mmio_map(s, 0, base);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(hms->l2vic, irq));
+
+ qemu_fdt_add_subnode(ms->fdt, "/apb-pclk");
+ qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "compatible", "fixed-clock");
+ qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "#clock-cells", 0x0);
+ qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "clock-frequency", APB_CLK_HZ);
+ qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "clock-output-names",
+ "clk24mhz");
+ qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "phandle", clk_phandle);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ /* Can't use setprop_string because of the embedded NUL */
+ qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
+ fdt_set_irq(ms, nodename, irq);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ l2vic_phandle);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clk_phandle,
+ clk_phandle);
+ qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames,
+ sizeof(clocknames));
+
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+ qemu_fdt_add_subnode(ms->fdt, "/aliases");
+ qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", nodename);
+}
+
+void hex_board_create_virtio(MachineState *ms, hwaddr base, hwaddr size,
+ int irq_base, int count,
+ int32_t l2vic_phandle)
+{
+ HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
+
+ for (int i = 0; i < count; i++) {
+ int irq = irq_base + i;
+ hwaddr slot = base + i * size;
+ g_autofree char *nodename = g_strdup_printf("/soc/virtio_mmio@%" PRIx64,
+ slot);
+ DeviceState *dev = qdev_new("virtio-mmio");
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
+
+ object_property_add_child(OBJECT(ms), "virtio-mmio[*]", OBJECT(dev));
+ sysbus_realize_and_unref(s, &error_fatal);
+ sysbus_mmio_map(s, 0, slot);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(hms->l2vic, irq));
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ "virtio,mmio");
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, slot, size);
+ fdt_set_irq(ms, nodename, irq);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ l2vic_phandle);
+ }
+}
+
+uint64_t hex_board_load_elf(const char *filename,
+ uint64_t (*translate)(void *opaque, uint64_t addr),
+ void *opaque, uint64_t *high)
+{
+ uint64_t entry = 0;
+
+ if (load_elf_ram_sym(filename, NULL, translate, opaque, &entry, NULL,
+ high, NULL, 0, EM_HEXAGON, 0, 0,
+ &address_space_memory, false, NULL) <= 0) {
+ error_report("error loading '%s'", filename);
+ exit(1);
+ }
+ return entry;
+}
+
+void hex_board_load_fdt(MachineState *ms, int fdt_size, hwaddr addr)
+{
+ rom_add_blob_fixed_as("fdt", ms->fdt, fdt_size, addr,
+ &address_space_memory);
+ qemu_register_reset_nosnapshotload(
+ qemu_fdt_randomize_seeds,
+ rom_ptr_for_as(&address_space_memory, addr, fdt_size));
+}
+
+static void hex_board_cpu_reset(void *opaque)
+{
+ cpu_reset(CPU(opaque));
+}
+
+void hex_board_create_cpus(MachineState *ms, bool have_start, uint64_t start)
+{
+ HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
+ g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus);
+
+ for (int i = 0; i < ms->smp.cpus; i++) {
+ HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
+
+ qemu_register_reset(hex_board_cpu_reset, cpu);
+ if (i == 0 && have_start) {
+ qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", start);
+ }
+ qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
+ qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", i != 0);
+ hex_subsys_add_cpu(hms, DEVICE(cpu));
+ cpus[i] = cpu;
+ }
+
+ hex_subsys_realize_cluster(hms);
+ for (int i = 0; i < ms->smp.cpus; i++) {
+ hex_subsys_realize_cpu(hms, DEVICE(cpus[i]), i == 0);
+ }
+}
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index bb8a254fd26..63ee8836aca 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -7,12 +7,17 @@ config HEX_DSP
select HEX_QTIMER
select ARM_COMPATIBLE_SEMIHOSTING
-config HEX_VIRT
+config HEX_BOARD
bool
- default y
depends on HEX_DSP && FDT
select DEVICE_TREE
select VIRTIO_MMIO
select PL011
+
+config HEX_VIRT
+ bool
+ default y
+ depends on HEX_DSP && FDT
+ select HEX_BOARD
select VIRTIO_BLK
select VIRTIO_SCSI
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index c4b257dfa28..57bff31ad00 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -4,6 +4,7 @@ hexagon_ss.add(files('hexagon_globalreg.c'))
hexagon_ss.add(files('hexagon_hvx_context.c'))
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hex-subsys.c'))
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_BOARD', if_true: files('hex-board.c'))
hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
hw_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 04/14] hw/hexagon: convert virt board to hex-board
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (2 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 03/14] hw/hexagon: introduce hex-board abstraction Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 21:40 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 05/14] hw/misc: add the QDSP6SS PLL, RCG Brian Cain
` (9 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Build the virt machine with the hex-board helpers instead of its own
copies, and drop the machine state that nothing used. The machine, its
device tree and its devices are unchanged; virt writes interrupts as the
bare line number.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/virt.h | 6 -
hw/hexagon/virt.c | 309 ++++----------------------------------
2 files changed, 26 insertions(+), 289 deletions(-)
diff --git a/include/hw/hexagon/virt.h b/include/hw/hexagon/virt.h
index 4ca2f1ef859..dc9f22a83c4 100644
--- a/include/hw/hexagon/virt.h
+++ b/include/hw/hexagon/virt.h
@@ -17,15 +17,9 @@ struct HexagonVirtMachineState {
HexagonCommonMachineState parent_obj;
int fdt_size;
- MemoryRegion *sys;
MemoryRegion tcm;
- MemoryRegion bios;
- Clock *apb_clk;
- DeviceState *virtio_mmio[VIRTIO_DEV_COUNT];
};
-void hexagon_load_fdt(const struct HexagonVirtMachineState *vms);
-
#define TYPE_HEXAGON_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
OBJECT_DECLARE_SIMPLE_TYPE(HexagonVirtMachineState, HEXAGON_VIRT_MACHINE)
diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c
index b601cd77a92..d8e91770595 100644
--- a/hw/hexagon/virt.c
+++ b/hw/hexagon/virt.c
@@ -8,26 +8,15 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/hexagon/virt.h"
-#include "elf.h"
-#include "hw/char/pl011.h"
-#include "hw/core/clock.h"
-#include "hw/core/sysbus-fdt.h"
#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hex-board.h"
#include "hw/hexagon/hex-subsys.h"
#include "hw/core/loader.h"
-#include "hw/core/qdev-properties.h"
-#include "hw/core/qdev-clock.h"
-#include "hw/core/register.h"
#include "qemu/error-report.h"
-#include "qemu/guest-random.h"
#include "qemu/target-info.h"
#include "qemu/units.h"
#include "machine_cfg_v68n_1024.h.inc"
-#include "system/address-spaces.h"
#include "system/device_tree.h"
-#include "system/reset.h"
-#include "system/system.h"
-#include <libfdt.h>
enum {
VIRT_UART0,
@@ -49,222 +38,9 @@ static const MemMapEntry base_memmap[] = {
};
-static void create_fdt(HexagonVirtMachineState *vms)
-{
- MachineState *ms = MACHINE(vms);
- void *fdt = create_device_tree(&vms->fdt_size);
- uint8_t rng_seed[32];
-
- if (!fdt) {
- error_report("create_device_tree() failed");
- exit(1);
- }
-
- ms->fdt = fdt;
-
- qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
- qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1);
- qemu_fdt_setprop_string(fdt, "/", "model", "hexagon-virt,qemu");
- qemu_fdt_setprop_string(fdt, "/", "compatible", "qcom,sm8150");
-
- qemu_fdt_add_subnode(fdt, "/soc");
- qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
- qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1);
- qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
-
- qemu_fdt_add_subnode(fdt, "/chosen");
- qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
- qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
-}
-
-static int32_t fdt_add_l2vic(HexagonVirtMachineState *vms,
- const struct hexagon_machine_config *m_cfg)
-{
- MachineState *ms = MACHINE(vms);
- int32_t l2vic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
- char *nodename = g_strdup_printf("/soc/interrupt-controller@%x",
- m_cfg->l2vic_base);
- const char compat[] = "qcom,h2-pic\0hvm-pic";
-
- qemu_fdt_setprop_cell(ms->fdt, "/soc", "interrupt-parent", l2vic_phandle);
-
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x0);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 0x1);
- qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
- m_cfg->l2vic_base, m_cfg->l2vic_size);
- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", l2vic_phandle);
-
- g_free(nodename);
- return l2vic_phandle;
-}
-
-static void fdt_add_hvx(HexagonVirtMachineState *vms,
- const struct hexagon_machine_config *m_cfg)
-{
- const MachineState *ms = MACHINE(vms);
- uint32_t vtcm_size_bytes = m_cfg->cfgtable.vtcm_size_kb * 1024;
- if (vtcm_size_bytes > 0) {
- qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm");
- qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible",
- "qcom,hexagon_vtcm");
-
- assert(sizeof(m_cfg->cfgtable.vtcm_base) == sizeof(uint32_t));
- qemu_fdt_setprop_cells(ms->fdt, "/soc/vtcm", "reg", 0,
- m_cfg->cfgtable.vtcm_base << 16,
- vtcm_size_bytes);
- }
-
- if (m_cfg->cfgtable.ext_contexts > 0) {
- qemu_fdt_add_subnode(ms->fdt, "/soc/hvx");
- qemu_fdt_setprop_string(ms->fdt, "/soc/hvx", "compatible",
- "qcom,hexagon-hvx");
- qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-max-ctxts",
- m_cfg->cfgtable.ext_contexts);
- qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-vlength",
- m_cfg->cfgtable.hvx_vec_log_length);
- }
-}
-
-static int32_t fdt_add_clocks(const HexagonVirtMachineState *vms)
-{
- MachineState *ms = MACHINE(vms);
- int32_t clk_phandle = qemu_fdt_alloc_phandle(ms->fdt);
-
- qemu_fdt_add_subnode(ms->fdt, "/apb-pclk");
- qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "compatible", "fixed-clock");
- qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "#clock-cells", 0x0);
- qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "clock-frequency", 24000000);
- qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "clock-output-names",
- "clk24mhz");
- qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "phandle", clk_phandle);
-
- return clk_phandle;
-}
-
-static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart,
- int32_t clk_phandle, int32_t l2vic_phandle)
-{
- char *nodename;
- hwaddr base = base_memmap[uart].base;
- hwaddr size = base_memmap[uart].size;
- assert(uart == 0);
- const char compat[] = "arm,pl011\0arm,primecell";
- const char clocknames[] = "uartclk\0apb_pclk";
- MachineState *ms = MACHINE(vms);
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_new(TYPE_PL011);
- s = SYS_BUS_DEVICE(dev);
- qdev_prop_set_chr(dev, "chardev", serial_hd(0));
- qdev_connect_clock_in(dev, "clk", vms->apb_clk);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, base);
- sysbus_connect_irq(s, 0,
- qdev_get_gpio_in(vms->parent_obj.l2vic, VIRT_UART0_IRQ));
-
- nodename = g_strdup_printf("/pl011@%" PRIx64, base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
-
- /* Note that we can't use setprop_string because of the embedded NUL */
- qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", VIRT_UART0_IRQ);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- l2vic_phandle);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clk_phandle,
- clk_phandle);
- qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames,
- sizeof(clocknames));
-
- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
- qemu_fdt_add_subnode(ms->fdt, "/aliases");
- qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", nodename);
-
- g_free(nodename);
-}
-
-static void fdt_add_cpu_nodes(const HexagonVirtMachineState *vms)
-{
- MachineState *ms = MACHINE(vms);
- qemu_fdt_add_subnode(ms->fdt, "/cpus");
- qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
- qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
-
- /* cpu nodes */
- for (int num = ms->smp.cpus - 1; num >= 0; num--) {
- char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
- qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
- qemu_fdt_alloc_phandle(ms->fdt));
- g_free(nodename);
- }
-}
-
-static void create_virtio_devices(HexagonVirtMachineState *vms,
- int32_t l2vic_phandle)
-{
- MachineState *ms = MACHINE(vms);
- hwaddr size = base_memmap[VIRT_MMIO].size;
-
- for (int i = 0; i < VIRTIO_DEV_COUNT; i++) {
- int irq = VIRTIO_IRQ_BASE + i;
- hwaddr base = base_memmap[VIRT_MMIO].base + i * size;
- char *nodename = g_strdup_printf("/soc/virtio_mmio@%" PRIx64, base);
- DeviceState *dev = qdev_new("virtio-mmio");
- SysBusDevice *s = SYS_BUS_DEVICE(dev);
-
- object_property_add_child(OBJECT(MACHINE(vms)), "virtio-mmio[*]",
- OBJECT(dev));
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, base);
- sysbus_connect_irq(s, 0,
- qdev_get_gpio_in(vms->parent_obj.l2vic, irq));
- vms->virtio_mmio[i] = dev;
-
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- "virtio,mmio");
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", irq);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- l2vic_phandle);
-
- g_free(nodename);
- }
-}
-
-void hexagon_load_fdt(const HexagonVirtMachineState *vms)
-{
- MachineState *ms = MACHINE(vms);
- hwaddr fdt_addr = base_memmap[VIRT_FDT].base;
- uint32_t fdtsize = vms->fdt_size;
-
- g_assert(fdtsize <= base_memmap[VIRT_FDT].size);
- /* copy in the device tree */
- rom_add_blob_fixed_as("fdt", ms->fdt, fdtsize, fdt_addr,
- &address_space_memory);
- qemu_register_reset_nosnapshotload(
- qemu_fdt_randomize_seeds,
- rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize));
-}
-
static uint64_t load_kernel(const HexagonVirtMachineState *vms)
{
- MachineState *ms = MACHINE(vms);
- uint64_t entry = 0;
- if (load_elf_ram_sym(ms->kernel_filename, NULL, NULL, NULL, &entry, NULL,
- NULL, NULL, 0, EM_HEXAGON, 0, 0, &address_space_memory,
- false, NULL) > 0) {
- return entry;
- }
- error_report("error loading '%s'", ms->kernel_filename);
- exit(1);
+ return hex_board_load_elf(MACHINE(vms)->kernel_filename, NULL, NULL, NULL);
}
static uint64_t load_bios(HexagonVirtMachineState *vms)
@@ -283,75 +59,42 @@ static uint64_t load_bios(HexagonVirtMachineState *vms)
return bios_addr; /* Return entry point at address 0x0 */
}
-static void do_cpu_reset(void *opaque)
-{
- HexagonCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- cpu_reset(cs);
-}
-
static void virt_init(MachineState *ms)
{
HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms);
const struct hexagon_machine_config *m_cfg = &v68n_1024;
- int32_t clk_phandle;
int32_t l2vic_phandle;
+ uint64_t start = 0;
+ bool have_start = false;
- create_fdt(vms);
+ hex_board_create_fdt(ms, "hexagon-virt,qemu", "qcom,sm8150",
+ &vms->fdt_size);
qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline);
- vms->sys = get_system_memory();
-
- /* Create APB clock for peripherals */
- vms->apb_clk = clock_new(OBJECT(ms), "apb-pclk");
- clock_set_hz(vms->apb_clk, 24000000);
-
hex_subsys_create(&vms->parent_obj, m_cfg, v68_rev);
-
- if (m_cfg->l2tcm_size) {
- memory_region_init_ram(&vms->tcm, NULL, "tcm.ram", m_cfg->l2tcm_size,
- &error_fatal);
- memory_region_add_subregion(vms->sys, m_cfg->cfgtable.l2tcm_base << 16,
- &vms->tcm);
- }
-
- fdt_add_hvx(vms, m_cfg);
-
- l2vic_phandle = fdt_add_l2vic(vms, m_cfg);
- create_virtio_devices(vms, l2vic_phandle);
-
- g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus);
-
- for (int i = 0; i < ms->smp.cpus; i++) {
- HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
- qemu_register_reset(do_cpu_reset, cpu);
-
- if (i == 0) {
- if (ms->kernel_filename) {
- uint64_t entry = load_kernel(vms);
- qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", entry);
- } else if (ms->firmware) {
- uint64_t entry = load_bios(vms);
- qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", entry);
- }
- }
- qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
- qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
- hex_subsys_add_cpu(&vms->parent_obj, DEVICE(cpu));
- cpus[i] = cpu;
- }
-
- hex_subsys_realize_cluster(&vms->parent_obj);
-
- for (int i = 0; i < ms->smp.cpus; i++) {
- hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i]), (i == 0));
+ hex_board_create_tcm(m_cfg, &vms->tcm);
+ hex_board_fdt_add_hvx(ms, m_cfg);
+
+ l2vic_phandle = hex_board_fdt_add_l2vic(ms, m_cfg);
+ hex_board_create_virtio(ms, base_memmap[VIRT_MMIO].base,
+ base_memmap[VIRT_MMIO].size, VIRTIO_IRQ_BASE,
+ VIRTIO_DEV_COUNT, l2vic_phandle);
+
+ if (ms->kernel_filename) {
+ start = load_kernel(vms);
+ have_start = true;
+ } else if (ms->firmware) {
+ start = load_bios(vms);
+ have_start = true;
}
+ hex_board_create_cpus(ms, have_start, start);
- fdt_add_cpu_nodes(vms);
- clk_phandle = fdt_add_clocks(vms);
- fdt_add_uart(vms, VIRT_UART0, clk_phandle, l2vic_phandle);
+ hex_board_fdt_add_cpus(ms);
+ hex_board_create_uart(ms, base_memmap[VIRT_UART0].base,
+ base_memmap[VIRT_UART0].size, VIRT_UART0_IRQ,
+ l2vic_phandle);
- hexagon_load_fdt(vms);
+ hex_board_load_fdt(ms, vms->fdt_size, base_memmap[VIRT_FDT].base);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 05/14] hw/misc: add the QDSP6SS PLL, RCG
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (3 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 04/14] hw/hexagon: convert virt board to hex-board Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 21:51 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine Brian Cain
` (8 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Firmware brings a Hexagon DSP's clocks up by programming a PLL and polling
its lock-detect. Then it asks the RCG to switch to the new clock.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
MAINTAINERS | 2 +
include/hw/misc/qcom-qdsp6ss-clk.h | 15 +++
hw/misc/qcom-qdsp6ss-clk.c | 208 +++++++++++++++++++++++++++++
hw/misc/Kconfig | 3 +
hw/misc/meson.build | 3 +
5 files changed, 231 insertions(+)
create mode 100644 include/hw/misc/qcom-qdsp6ss-clk.h
create mode 100644 hw/misc/qcom-qdsp6ss-clk.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 4c9eb1892c1..ef619991b4b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1380,7 +1380,9 @@ M: Brian Cain <brian.cain@oss.qualcomm.com>
R: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
S: Supported
F: hw/hexagon/
+F: hw/misc/qcom-qdsp6ss-clk.c
F: include/hw/hexagon/
+F: include/hw/misc/qcom-qdsp6ss-clk.h
F: configs/devices/hexagon-softmmu/default.mak
F: docs/system/hexagon/
F: tests/functional/hexagon/
diff --git a/include/hw/misc/qcom-qdsp6ss-clk.h b/include/hw/misc/qcom-qdsp6ss-clk.h
new file mode 100644
index 00000000000..9e3c58b5726
--- /dev/null
+++ b/include/hw/misc/qcom-qdsp6ss-clk.h
@@ -0,0 +1,15 @@
+/*
+ * Qualcomm QDSP6SS clock blocks: the Lucid alpha PLL and the root clock
+ * generator that firmware programs while bringing a Hexagon DSP up.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_QCOM_QDSP6SS_CLK_H
+#define HW_MISC_QCOM_QDSP6SS_CLK_H
+
+#define TYPE_QCOM_LUCID_PLL "qcom-lucid-pll"
+#define TYPE_QCOM_RCG "qcom-rcg"
+
+#endif /* HW_MISC_QCOM_QDSP6SS_CLK_H */
diff --git a/hw/misc/qcom-qdsp6ss-clk.c b/hw/misc/qcom-qdsp6ss-clk.c
new file mode 100644
index 00000000000..5c9b55e0568
--- /dev/null
+++ b/hw/misc/qcom-qdsp6ss-clk.c
@@ -0,0 +1,208 @@
+/*
+ * Qualcomm QDSP6SS clock blocks
+ *
+ * Firmware brings the DSP's PLLs up by programming them, releasing reset,
+ * selecting the RUN mode and then polling for lock; it then asks the root
+ * clock generator to switch over to the new clock by setting UPDATE and
+ * waiting for the hardware to clear it. Neither the frequencies nor the
+ * clock tree matter to the model: these devices only complete those
+ * handshakes, and otherwise hold whatever is written to them.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/resettable.h"
+#include "hw/core/sysbus.h"
+#include "hw/misc/qcom-qdsp6ss-clk.h"
+#include "migration/vmstate.h"
+#include "qom/object.h"
+
+#define QCOM_CLK_REGS_SIZE 0x1000
+#define QCOM_CLK_NUM_REGS (QCOM_CLK_REGS_SIZE / 4)
+
+/* Lucid PLL registers */
+#define PLL_MODE 0x00
+#define PLL_OPMODE 0x38
+
+#define PLL_MODE_OUTCTRL BIT(0)
+#define PLL_MODE_BYPASSNL BIT(1)
+#define PLL_MODE_RESET_N BIT(2)
+#define PLL_MODE_ACTIVE BIT(30)
+#define PLL_MODE_LOCK_DET BIT(31)
+
+#define PLL_OPMODE_MASK 0x7
+#define PLL_OPMODE_RUN 0x1
+
+/* RCG registers */
+#define RCG_CMD 0x20
+
+#define RCG_CMD_UPDATE BIT(0)
+#define RCG_CMD_ROOT_EN BIT(1)
+#define RCG_CMD_ROOT_OFF BIT(31)
+
+typedef struct QcomClkRegsState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ uint32_t regs[QCOM_CLK_NUM_REGS];
+} QcomClkRegsState;
+
+#define TYPE_QCOM_CLK_REGS "qcom-clk-regs"
+OBJECT_DECLARE_SIMPLE_TYPE(QcomClkRegsState, QCOM_CLK_REGS)
+
+static uint64_t qcom_clk_read(void *opaque, hwaddr offset, unsigned size)
+{
+ QcomClkRegsState *s = opaque;
+
+ return s->regs[offset / 4];
+}
+
+static void qcom_lucid_pll_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ QcomClkRegsState *s = opaque;
+
+ s->regs[offset / 4] = value;
+ if (offset == PLL_MODE || offset == PLL_OPMODE) {
+ uint32_t mode = s->regs[PLL_MODE / 4];
+ uint32_t opmode = s->regs[PLL_OPMODE / 4];
+
+ /* The PLL locks once it is out of reset and running */
+ if ((mode & PLL_MODE_RESET_N) &&
+ (opmode & PLL_OPMODE_MASK) == PLL_OPMODE_RUN) {
+ mode |= PLL_MODE_LOCK_DET | PLL_MODE_ACTIVE;
+ } else {
+ mode &= ~(PLL_MODE_LOCK_DET | PLL_MODE_ACTIVE);
+ }
+ s->regs[PLL_MODE / 4] = mode;
+ }
+}
+
+static void qcom_rcg_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ QcomClkRegsState *s = opaque;
+
+ s->regs[offset / 4] = value;
+ if (offset == RCG_CMD) {
+ /* The update completes at once; the root is on if it was enabled */
+ value &= ~(RCG_CMD_UPDATE | RCG_CMD_ROOT_OFF);
+ if (!(value & RCG_CMD_ROOT_EN)) {
+ value |= RCG_CMD_ROOT_OFF;
+ }
+ s->regs[RCG_CMD / 4] = value;
+ }
+}
+
+static const MemoryRegionOps qcom_lucid_pll_ops = {
+ .read = qcom_clk_read,
+ .write = qcom_lucid_pll_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static const MemoryRegionOps qcom_rcg_ops = {
+ .read = qcom_clk_read,
+ .write = qcom_rcg_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void qcom_clk_realize(DeviceState *dev, const MemoryRegionOps *ops,
+ const char *name)
+{
+ QcomClkRegsState *s = QCOM_CLK_REGS(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), ops, s, name,
+ QCOM_CLK_REGS_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+}
+
+static void qcom_lucid_pll_realize(DeviceState *dev, Error **errp)
+{
+ qcom_clk_realize(dev, &qcom_lucid_pll_ops, TYPE_QCOM_LUCID_PLL);
+}
+
+static void qcom_rcg_realize(DeviceState *dev, Error **errp)
+{
+ qcom_clk_realize(dev, &qcom_rcg_ops, TYPE_QCOM_RCG);
+}
+
+static void qcom_clk_reset_hold(Object *obj, ResetType type)
+{
+ QcomClkRegsState *s = QCOM_CLK_REGS(obj);
+
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static const VMStateDescription vmstate_qcom_clk = {
+ .name = "qcom-qdsp6ss-clk",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, QcomClkRegsState, QCOM_CLK_NUM_REGS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void qcom_clk_regs_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->vmsd = &vmstate_qcom_clk;
+ RESETTABLE_CLASS(oc)->phases.hold = qcom_clk_reset_hold;
+}
+
+static void qcom_lucid_pll_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = qcom_lucid_pll_realize;
+ dc->desc = "Qualcomm Lucid alpha PLL";
+}
+
+static void qcom_rcg_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = qcom_rcg_realize;
+ dc->desc = "Qualcomm root clock generator";
+}
+
+static const TypeInfo qcom_qdsp6ss_clk_types[] = {
+ {
+ .name = TYPE_QCOM_CLK_REGS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(QcomClkRegsState),
+ .class_init = qcom_clk_regs_class_init,
+ .abstract = true,
+ },
+ {
+ .name = TYPE_QCOM_LUCID_PLL,
+ .parent = TYPE_QCOM_CLK_REGS,
+ .class_init = qcom_lucid_pll_class_init,
+ },
+ {
+ .name = TYPE_QCOM_RCG,
+ .parent = TYPE_QCOM_CLK_REGS,
+ .class_init = qcom_rcg_class_init,
+ },
+};
+
+DEFINE_TYPES(qcom_qdsp6ss_clk_types)
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 7abd22869a4..363930230b4 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -267,3 +267,6 @@ config SOPHGO_CV1800B_CLK
bool
source macio/Kconfig
+
+config QCOM_QDSP6SS_CLK
+ bool
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 8a94aba751d..2b437f53d6a 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -179,3 +179,6 @@ system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c'))
system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c'))
system_ss.add(when: 'CONFIG_AXIADO_CLK', if_true: files('axiado_clk.c'))
+
+# Qualcomm Hexagon DSP subsystems
+system_ss.add(when: 'CONFIG_QCOM_QDSP6SS_CLK', if_true: files('qcom-qdsp6ss-clk.c'))
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (4 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 05/14] hw/misc: add the QDSP6SS PLL, RCG Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-20 11:28 ` Anton Johansson via qemu development
2026-10-19 5:52 ` [PATCH 07/14] hw/hexagon: add the SA8775P " Brian Cain
` (7 subsequent siblings)
13 siblings, 2 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
MAINTAINERS | 1 +
include/hw/hexagon/hexagon.h | 1 +
include/hw/hexagon/qcom_dsp.h | 81 +++++
hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc | 65 ++++
hw/hexagon/qcom_dsp.c | 399 ++++++++++++++++++++++
hw/hexagon/qcs6490_cdsp.c | 64 ++++
tests/qtest/l2vic-test.c | 2 +
tests/qtest/qcom-dsp-test.c | 93 +++++
tests/qtest/qct-qtimer-test.c | 2 +
hw/hexagon/Kconfig | 15 +
hw/hexagon/meson.build | 2 +
tests/qtest/meson.build | 3 +-
12 files changed, 727 insertions(+), 1 deletion(-)
create mode 100644 include/hw/hexagon/qcom_dsp.h
create mode 100644 hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
create mode 100644 hw/hexagon/qcom_dsp.c
create mode 100644 hw/hexagon/qcs6490_cdsp.c
create mode 100644 tests/qtest/qcom-dsp-test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ef619991b4b..04df9db77dc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1386,6 +1386,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/qcom-dsp-test.c
F: docs/devel/hexagon-sys.rst
LoongArch Machines
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 6955e600aee..1d0d55ea938 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -23,6 +23,7 @@ typedef enum {
v66_rev = 0xa666,
v67_rev = 0x2667,
v68_rev = 0x8d68,
+ v68_qcs6490_rev = 0x8a68,
v69_rev = 0x8c69,
v71_rev = 0x8c71,
v73_rev = 0x8c73,
diff --git a/include/hw/hexagon/qcom_dsp.h b/include/hw/hexagon/qcom_dsp.h
new file mode 100644
index 00000000000..d127b0b0b10
--- /dev/null
+++ b/include/hw/hexagon/qcom_dsp.h
@@ -0,0 +1,81 @@
+/*
+ * Qualcomm DSP subsystem machines: the board layer shared by the SoC models.
+ *
+ * Each SoC provides a QcomDspMachineInfo describing its subsystem, and the
+ * layer supplies what every one of them has in common: the CPUs, a QEMU-only
+ * PL011 console, virtio-mmio slots, a generated device tree, and the
+ * -bios/-kernel/-initrd boot flow.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_HEXAGON_QCOM_DSP_H
+#define HW_HEXAGON_QCOM_DSP_H
+
+#include "hw/hexagon/hexagon.h"
+#include "qom/object.h"
+
+#define TYPE_QCOM_DSP_MACHINE MACHINE_TYPE_NAME("qcom-dsp")
+OBJECT_DECLARE_TYPE(QcomDspMachineState, QcomDspMachineClass, QCOM_DSP_MACHINE)
+
+/* Number of virtio-mmio transports every machine provides. */
+#define QCOM_DSP_VIRTIO_COUNT 8
+
+typedef struct QcomDspMachineInfo {
+ const char *desc;
+ const char *cpu_type;
+ unsigned int cpus;
+ Rev_t rev;
+ const struct hexagon_machine_config *cfg;
+ /* Where the H2 loadlinux of this SoC expects to find the Linux kernel. */
+ hwaddr kernel_addr;
+ /* Add the devices that are specific to this SoC; may be NULL. */
+ void (*init_devices)(MachineState *ms);
+} QcomDspMachineInfo;
+
+struct QcomDspMachineState {
+ HexagonCommonMachineState parent_obj;
+
+ MemoryRegion tcm;
+ MemoryRegion l2_ecc;
+ int fdt_size;
+ hwaddr fdt_addr;
+ char *firmware_path;
+};
+
+struct QcomDspMachineClass {
+ MachineClass parent_class;
+
+ const QcomDspMachineInfo *info;
+};
+
+/* Describes a register window the machine stubs out as unimplemented. */
+typedef struct QcomDspRegion {
+ const char *name;
+ hwaddr base;
+ /* Zero means one 4 KiB page. */
+ hwaddr size;
+} QcomDspRegion;
+
+/*
+ * Stub out register windows the guest may probe, named
+ * "<machine>.<name>@<base>".
+ */
+void qcom_dsp_add_regions(MachineState *ms, const QcomDspRegion *regions,
+ unsigned int count);
+
+/* Create the sysbus device @type and map it at @base. */
+void qcom_dsp_add_device(const char *type, hwaddr base);
+
+/*
+ * Stub out @ports consecutive QUP GENI serial engines of @size bytes. They
+ * belong to the SoC @soc rather than to the DSP.
+ */
+void qcom_soc_add_qup_geni_ports(const char *soc, hwaddr base,
+ unsigned int ports, hwaddr size);
+
+/* Class init for a machine type whose class_data is a QcomDspMachineInfo. */
+void qcom_dsp_class_init(ObjectClass *oc, const void *data);
+
+#endif /* HW_HEXAGON_QCOM_DSP_H */
diff --git a/hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc b/hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
new file mode 100644
index 00000000000..11302da2238
--- /dev/null
+++ b/hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+static const struct hexagon_machine_config qcs6490_cdsp = {
+ .ddr_base = 0x80000000,
+ .cfgbase = 0x09980000,
+ .l2tcm_size = 0x00000000,
+ .l2vic_base = 0x0a390000,
+ .l2vic_size = 0x00001000,
+ .csr_base = 0x0a3a0000,
+ .qtmr_region = 0x0a3a1000,
+ .cfgtable = {
+ .l2tcm_base = 0x00000980,
+ .reserved0 = 0x00000000,
+ .subsystem_base = 0x00000a38,
+ .etm_base = 0x00000999,
+ .l2cfg_base = 0x0000099a,
+ .reserved1 = 0x0000099b,
+ .l1s0_base = 0x000009c0,
+ .axi2_lowaddr = 0x00000000,
+ .streamer_base = 0x0000099c,
+ .reserved2 = 0x0000099d,
+ .fastl2vic_base = 0x0000099e,
+ .jtlb_size_entries = 0x00000080,
+ .coproc_present = 0x00000001,
+ .ext_contexts = 0x00000002,
+ .vtcm_base = 0x000009c0,
+ .vtcm_size_kb = 0x00000800,
+ .l2tag_size = 0x00000400,
+ .l2ecomem_size = 0x00000400,
+ .thread_enable_mask = 0x0000003f,
+ .eccreg_base = 0x0000099f,
+ .l2line_size = 0x00000080,
+ .tiny_core = 0x00000000,
+ .l2itcm_size = 0x00000000,
+ .l2itcm_base = 0x00000980,
+ .reserved3 = 0x00000000,
+ .dtm_present = 0x00000000,
+ .dma_version = 0x00000001,
+ .hvx_vec_log_length = 0x00000007,
+ .core_id = 0x00000000,
+ .core_count = 0x00000000,
+ .coproc2_reg0 = 0x00000040,
+ .coproc2_reg1 = 0x00000020,
+ .v2x_mode = 0x00000001,
+ .coproc2_reg2 = 0x00000002,
+ .coproc2_reg3 = 0x00000000,
+ .coproc2_reg4 = 0x00000000,
+ .coproc2_reg5 = 0x00000000,
+ .coproc2_reg6 = 0x00000000,
+ .coproc2_reg7 = 0x00000000,
+ .acd_preset = 0x00000001,
+ .mnd_preset = 0x00000001,
+ .l1d_size_kb = 0x00000010,
+ .l1i_size_kb = 0x00000020,
+ .l1d_write_policy = 0x00000002,
+ .vtcm_bank_width = 0x00000040,
+ .reserved4 = 0x00000001,
+ .reserved5 = 0x00000000,
+ .reserved6 = 0x00000000,
+ .coproc2_cvt_mpy_size = 0x0000000a,
+ .consistency_domain = 0x00000000,
+ .capacity_domain = 0x00000000,
+ .axi3_lowaddr = 0x00000000,
+ },
+};
diff --git a/hw/hexagon/qcom_dsp.c b/hw/hexagon/qcom_dsp.c
new file mode 100644
index 00000000000..5520366bb28
--- /dev/null
+++ b/hw/hexagon/qcom_dsp.c
@@ -0,0 +1,399 @@
+/*
+ * DSP subsystem machines: the board layer shared by the SoC models.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/core/boards.h"
+#include "hw/core/loader.h"
+#include "hw/core/sysbus.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hex-board.h"
+#include "hw/hexagon/hex-subsys.h"
+#include "hw/hexagon/qcom_dsp.h"
+#include "hw/misc/unimp.h"
+#include "qemu/datadir.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "system/address-spaces.h"
+#include "system/device_tree.h"
+
+enum {
+ QCOM_DSP_UART0,
+ QCOM_DSP_VIRTIO,
+ QCOM_DSP_GPT,
+ QCOM_DSP_BOOT,
+};
+
+static const MemMapEntry qcom_dsp_memmap[] = {
+ [QCOM_DSP_UART0] = { 0x37000000, 0x00001000 },
+ [QCOM_DSP_VIRTIO] = { 0x37010000, 0x00001000 },
+ /* Not a device: the window the kernel's H2 timer driver binds to. */
+ [QCOM_DSP_GPT] = { 0xab000000, 0x00001000 },
+ [QCOM_DSP_BOOT] = { 0x99c00000, 0x00000200 },
+};
+
+static const int QCOM_DSP_UART0_IRQ = 15;
+/* Virtio IRQs run from QCOM_DSP_VIRTIO_IRQ to QCOM_DSP_VIRTIO_IRQ + 7 */
+static const int QCOM_DSP_VIRTIO_IRQ = 96;
+static const int QCOM_DSP_GPT_IRQ = 12;
+
+#define QCOM_DSP_L2_ECC_SIZE 0x1000
+
+#define QCOM_DSP_MAX_KERNEL_RAM (896 * MiB)
+
+static const uint32_t bootloader[] = {
+ /* Load fdt_base_low value into r0: */
+ 0x099c4000, /* { immext(#0x99c00000) */
+ 0x7800c606, /* r6 = ##-0x662fffd0 } */
+ 0x9186c000, /* { r0 = memw(r6+#0x0) } */
+
+ /* Load fdt_base_high value into r1: */
+ 0x099c4000, /* { immext(#0x99c00000) */
+ 0x7800c586, /* r6 = ##-0x662fffd4 } */
+ 0x9186c001, /* { r1 = memw(r6+#0x0) } */
+
+ /* Load next_stage_entry value into r7: */
+ 0x099c4000, /* { immext(#0x99c00000) */
+ 0x7800c687, /* r7 = ##-0x662fffcc } */
+ 0x9187c007, /* { r7 = memw(r7+#0x0) } */
+
+ /* Jump to next_stage_entry, r1:0 now contains fdt_base: */
+ 0x5287c000, /* { jumpr r7 } */
+ 0x0, /* Invalid packet */
+ 0x0, /* Pad for fdt_base_high */
+ 0x0, /* Pad for fdt_base_low */
+ 0x0, /* Pad for next_stage_entry */
+};
+
+enum {
+ FDT_HI = 11,
+ FDT_LO,
+ ENTRY_ADDR,
+};
+
+static const QcomDspMachineInfo *qcom_dsp_info(MachineState *ms)
+{
+ return QCOM_DSP_MACHINE_GET_CLASS(ms)->info;
+}
+
+void qcom_dsp_add_regions(MachineState *ms, const QcomDspRegion *regions,
+ unsigned int count)
+{
+ const char *machine = MACHINE_GET_CLASS(ms)->name;
+
+ for (unsigned int i = 0; i < count; i++) {
+ g_autofree char *name = g_strdup_printf("%s.%s@%" HWADDR_PRIx, machine,
+ regions[i].name,
+ regions[i].base);
+
+ create_unimplemented_device(name, regions[i].base,
+ regions[i].size ? regions[i].size : 0x1000);
+ }
+}
+
+void qcom_dsp_add_device(const char *type, hwaddr base)
+{
+ DeviceState *dev = qdev_new(type);
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+}
+
+void qcom_soc_add_qup_geni_ports(const char *soc, hwaddr base,
+ unsigned int ports, hwaddr size)
+{
+ for (unsigned int i = 0; i < ports; i++) {
+ g_autofree char *name = g_strdup_printf("%s.qup-geni@%" HWADDR_PRIx,
+ soc, base + i * size);
+
+ create_unimplemented_device(name, base + i * size, size);
+ }
+}
+
+/*
+ * The firmware programs the L2 ECC registers and polls them until what it
+ * wrote reads back, so they need to hold state.
+ */
+static void qcom_dsp_add_l2_ecc_regs(QcomDspMachineState *qms,
+ const QcomDspMachineInfo *info)
+{
+ hwaddr base = (hwaddr)info->cfg->cfgtable.eccreg_base << 16;
+
+ if (!base) {
+ return;
+ }
+ memory_region_init_ram(&qms->l2_ecc, NULL, "l2-ecc-regs",
+ QCOM_DSP_L2_ECC_SIZE, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), base, &qms->l2_ecc);
+}
+
+static void qcom_dsp_create_fdt(QcomDspMachineState *qms)
+{
+ MachineState *ms = MACHINE(qms);
+ g_autofree char *compatible = g_strdup_printf("qcom,%s",
+ MACHINE_GET_CLASS(ms)->name);
+
+ hex_board_create_fdt(ms, MACHINE_GET_CLASS(ms)->desc, compatible,
+ &qms->fdt_size);
+ qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus");
+}
+
+/*
+ * The H2 hypervisor provides the guest timer through hypercalls, so this
+ * node only tells the kernel's timer driver which interrupt to expect.
+ */
+static void qcom_dsp_fdt_add_gpt(MachineState *ms)
+{
+ static const char compat[] = "qcom,h2-timer\0hvm-timer";
+ g_autofree char *name = g_strdup_printf("/soc/gpt@%" PRIx64,
+ qcom_dsp_memmap[QCOM_DSP_GPT].base);
+
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop(ms->fdt, name, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", QCOM_DSP_GPT_IRQ, 0);
+ qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0,
+ qcom_dsp_memmap[QCOM_DSP_GPT].base,
+ qcom_dsp_memmap[QCOM_DSP_GPT].size);
+}
+
+static void qcom_dsp_fdt_add_memory(MachineState *ms)
+{
+ hwaddr kernel_addr = qcom_dsp_info(ms)->kernel_addr;
+ hwaddr ram_end = qcom_dsp_info(ms)->cfg->ddr_base + ms->ram_size;
+ hwaddr size = MIN(ram_end - kernel_addr, QCOM_DSP_MAX_KERNEL_RAM);
+ g_autofree char *nodename = g_strdup_printf("/memory@%" HWADDR_PRIx,
+ kernel_addr);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, kernel_addr,
+ size);
+}
+
+static uint64_t qcom_dsp_kernel_translate(void *opaque, uint64_t addr)
+{
+ return addr + qcom_dsp_info(MACHINE(opaque))->kernel_addr;
+}
+
+static uint64_t qcom_dsp_load_kernel(MachineState *ms, bool through_firmware,
+ hwaddr *image_high)
+{
+ return hex_board_load_elf(ms->kernel_filename,
+ through_firmware ? qcom_dsp_kernel_translate
+ : NULL,
+ ms, image_high);
+}
+
+static uint64_t qcom_dsp_load_firmware(QcomDspMachineState *qms)
+{
+ return hex_board_load_elf(qms->firmware_path, NULL, NULL, NULL);
+}
+
+/*
+ * Place the FDT after the kernel image, inside the RAM window the kernel
+ * maps, and the initrd after that.
+ */
+static void qcom_dsp_load_initrd(QcomDspMachineState *qms)
+{
+ MachineState *ms = MACHINE(qms);
+ hwaddr start = qms->fdt_addr + 4 * MiB;
+ hwaddr ram_end = qcom_dsp_info(ms)->cfg->ddr_base + ms->ram_size;
+ ssize_t size;
+
+ if (!ms->initrd_filename) {
+ return;
+ }
+
+ if (start >= ram_end) {
+ error_report("no room for the initrd: RAM ends at 0x%" HWADDR_PRIx
+ " but the initrd would start at 0x%" HWADDR_PRIx,
+ ram_end, start);
+ exit(1);
+ }
+
+ size = load_image_targphys_as(ms->initrd_filename, start, ram_end - start,
+ &address_space_memory, &error_fatal);
+
+ qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,initrd-start", start);
+ qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,initrd-end", start + size);
+}
+
+/*
+ * A boot stub that passes the FDT address to the firmware in r1:r0, then
+ * jumps to the firmware's entry point.
+ */
+static uint64_t qcom_dsp_setup_boot_stub(QcomDspMachineState *qms,
+ uint64_t firmware_entry)
+{
+ hwaddr bootl_base = qcom_dsp_memmap[QCOM_DSP_BOOT].base;
+ uint32_t stub[ARRAY_SIZE(bootloader)];
+
+ memcpy(stub, bootloader, sizeof(stub));
+ stub[FDT_LO] = cpu_to_le32(extract64(qms->fdt_addr, 0, 32));
+ stub[FDT_HI] = cpu_to_le32(extract64(qms->fdt_addr, 32, 32));
+ stub[ENTRY_ADDR] = cpu_to_le32(extract64(firmware_entry, 0, 32));
+
+ g_assert(sizeof(stub) <= qcom_dsp_memmap[QCOM_DSP_BOOT].size);
+ rom_add_blob_fixed_as("bootloader", stub, sizeof(stub), bootl_base,
+ &address_space_memory);
+
+ return bootl_base;
+}
+
+/* Reject boot options that do not make sense together, and find -bios. */
+static void qcom_dsp_check_boot_options(QcomDspMachineState *qms)
+{
+ MachineState *ms = MACHINE(qms);
+ hwaddr ddr_base = qcom_dsp_info(ms)->cfg->ddr_base;
+ hwaddr kernel_addr = qcom_dsp_info(ms)->kernel_addr;
+
+ if (ms->firmware) {
+ qms->firmware_path = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->firmware);
+ if (!qms->firmware_path) {
+ error_report("Could not find firmware '%s'", ms->firmware);
+ exit(1);
+ }
+ }
+
+ if (ms->initrd_filename && !(ms->kernel_filename && qms->firmware_path)) {
+ error_report("-initrd needs both -kernel and the H2 loadlinux "
+ "firmware given with -bios");
+ exit(1);
+ }
+
+ if (ms->kernel_filename && qms->firmware_path &&
+ (ddr_base > qcom_dsp_memmap[QCOM_DSP_BOOT].base ||
+ ddr_base + ms->ram_size <= kernel_addr)) {
+ error_report("RAM (%" PRIu64 " MiB at 0x%" HWADDR_PRIx ") is too "
+ "small: the kernel is loaded at 0x%" HWADDR_PRIx,
+ ms->ram_size / MiB, ddr_base, kernel_addr);
+ exit(1);
+ }
+}
+
+/* Load what -bios and -kernel name and return where CPU 0 starts, if known. */
+static bool qcom_dsp_load_images(QcomDspMachineState *qms, uint64_t *start)
+{
+ MachineState *ms = MACHINE(qms);
+ hwaddr image_high = 0;
+
+ if (ms->kernel_filename && qms->firmware_path) {
+ uint64_t firmware_entry = qcom_dsp_load_firmware(qms);
+
+ qcom_dsp_load_kernel(ms, true, &image_high);
+ qms->fdt_addr = QEMU_ALIGN_UP(image_high + 16 * MiB, 4 * MiB);
+ qcom_dsp_load_initrd(qms);
+ *start = qcom_dsp_setup_boot_stub(qms, firmware_entry);
+ return true;
+ }
+ if (ms->kernel_filename) {
+ *start = qcom_dsp_load_kernel(ms, false, &image_high);
+ return true;
+ }
+ if (qms->firmware_path) {
+ *start = qcom_dsp_load_firmware(qms);
+ return true;
+ }
+ return false;
+}
+
+static void qcom_dsp_init(MachineState *ms)
+{
+ QcomDspMachineState *qms = QCOM_DSP_MACHINE(ms);
+ HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
+ const QcomDspMachineInfo *info = qcom_dsp_info(ms);
+ int32_t l2vic_phandle;
+ uint64_t start = 0;
+ bool have_start;
+
+ qcom_dsp_check_boot_options(qms);
+ qcom_dsp_create_fdt(qms);
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline);
+
+ hex_subsys_create(hms, info->cfg, info->rev);
+ hex_board_create_tcm(info->cfg, &qms->tcm);
+
+ hex_board_fdt_add_hvx(ms, info->cfg);
+ l2vic_phandle = hex_board_fdt_add_l2vic(ms, info->cfg);
+ qcom_dsp_fdt_add_gpt(ms);
+ /* loadlinux gives the kernel a virtual CPU for every thread that runs. */
+ hex_board_fdt_add_cpus(ms);
+ if (ms->kernel_filename && qms->firmware_path) {
+ qcom_dsp_fdt_add_memory(ms);
+ }
+ hex_board_create_uart(ms, qcom_dsp_memmap[QCOM_DSP_UART0].base,
+ qcom_dsp_memmap[QCOM_DSP_UART0].size,
+ QCOM_DSP_UART0_IRQ, l2vic_phandle);
+ hex_board_create_virtio(ms, qcom_dsp_memmap[QCOM_DSP_VIRTIO].base,
+ qcom_dsp_memmap[QCOM_DSP_VIRTIO].size,
+ QCOM_DSP_VIRTIO_IRQ, QCOM_DSP_VIRTIO_COUNT,
+ l2vic_phandle);
+ qcom_dsp_add_l2_ecc_regs(qms, info);
+ if (info->init_devices) {
+ info->init_devices(ms);
+ }
+
+ if (ms->dtb) {
+ g_free(ms->fdt);
+ ms->fdt = load_device_tree(ms->dtb, &qms->fdt_size);
+ if (!ms->fdt) {
+ error_report("could not load device tree '%s'", ms->dtb);
+ exit(1);
+ }
+ if (ms->kernel_cmdline && *ms->kernel_cmdline) {
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs",
+ ms->kernel_cmdline);
+ }
+ }
+
+ have_start = qcom_dsp_load_images(qms, &start);
+ hex_board_create_cpus(ms, have_start, start);
+
+ if (ms->kernel_filename && qms->firmware_path) {
+ hex_board_load_fdt(ms, qms->fdt_size, qms->fdt_addr);
+ }
+}
+
+static void qcom_dsp_base_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = qcom_dsp_init;
+ mc->default_ram_size = 1 * GiB;
+ mc->is_default = false;
+ mc->block_default_type = IF_VIRTIO;
+ mc->no_cdrom = true;
+ mc->no_floppy = true;
+ mc->no_parallel = true;
+ mc->numa_mem_supported = false;
+}
+
+void qcom_dsp_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ QcomDspMachineClass *qc = QCOM_DSP_MACHINE_CLASS(oc);
+ const QcomDspMachineInfo *info = data;
+
+ qc->info = info;
+ mc->desc = info->desc;
+ mc->default_cpu_type = info->cpu_type;
+ mc->default_cpus = info->cpus;
+ mc->max_cpus = info->cpus;
+}
+
+static const TypeInfo qcom_dsp_types[] = {
+ {
+ .name = TYPE_QCOM_DSP_MACHINE,
+ .parent = TYPE_HEXAGON_COMMON_MACHINE,
+ .instance_size = sizeof(QcomDspMachineState),
+ .class_size = sizeof(QcomDspMachineClass),
+ .class_init = qcom_dsp_base_class_init,
+ .abstract = true,
+ },
+};
+
+DEFINE_TYPES(qcom_dsp_types)
diff --git a/hw/hexagon/qcs6490_cdsp.c b/hw/hexagon/qcs6490_cdsp.c
new file mode 100644
index 00000000000..fe255640c49
--- /dev/null
+++ b/hw/hexagon/qcs6490_cdsp.c
@@ -0,0 +1,64 @@
+/*
+ * QCS6490 CDSP machine.
+ *
+ * Models the Hexagon v68 CDSP subsystem of the QCS6490/SM7325.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/boards.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/qcom_dsp.h"
+#include "hw/misc/qcom-qdsp6ss-clk.h"
+#include "hw/misc/unimp.h"
+#include "qapi/error.h"
+#include "system/address-spaces.h"
+#include "target/hexagon/cpu.h"
+
+#include "machine_cfg_qcs6490_cdsp.h.inc"
+
+#define TYPE_QCS6490_CDSP_MACHINE MACHINE_TYPE_NAME("qcs6490-cdsp")
+
+#define QCS6490_CFGSPACE_BASE 0x09990000
+#define QCS6490_CFGSPACE_SIZE 0x00070000
+
+static const QcomDspRegion qcs6490_regions[] = {
+ { "ss-csr", 0x0a380000, 0x10000 },
+};
+
+static void qcs6490_cdsp_init_devices(MachineState *ms)
+{
+ MemoryRegion *cfgspace = g_new(MemoryRegion, 1);
+
+ memory_region_init_ram(cfgspace, NULL, "cfgspace.ram",
+ QCS6490_CFGSPACE_SIZE, &error_fatal);
+ memory_region_add_subregion_overlap(get_system_memory(),
+ QCS6490_CFGSPACE_BASE, cfgspace, -1);
+ qcom_dsp_add_regions(ms, qcs6490_regions, ARRAY_SIZE(qcs6490_regions));
+ qcom_dsp_add_device(TYPE_QCOM_LUCID_PLL, 0x0a001000);
+ qcom_dsp_add_device(TYPE_QCOM_LUCID_PLL, 0x0a340000);
+ qcom_dsp_add_device(TYPE_QCOM_RCG, 0x0a341000);
+}
+
+static const QcomDspMachineInfo qcs6490_cdsp_info = {
+ .desc = "QCS6490 CDSP",
+ .cpu_type = HEXAGON_CPU_TYPE_NAME("v68"),
+ .cpus = 6,
+ .rev = v68_qcs6490_rev,
+ .cfg = &qcs6490_cdsp,
+ .kernel_addr = 0xa1000000,
+ .init_devices = qcs6490_cdsp_init_devices,
+};
+
+static const TypeInfo qcs6490_cdsp_types[] = {
+ {
+ .name = TYPE_QCS6490_CDSP_MACHINE,
+ .parent = TYPE_QCOM_DSP_MACHINE,
+ .class_init = qcom_dsp_class_init,
+ .class_data = &qcs6490_cdsp_info,
+ },
+};
+
+DEFINE_TYPES(qcs6490_cdsp_types)
diff --git a/tests/qtest/l2vic-test.c b/tests/qtest/l2vic-test.c
index adb4dc7281e..2e0d7dcb0f1 100644
--- a/tests/qtest/l2vic-test.c
+++ b/tests/qtest/l2vic-test.c
@@ -11,6 +11,7 @@
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
+#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
/* L2VIC register offsets exercised by this test */
#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */
@@ -45,6 +46,7 @@ typedef struct {
static const L2VICMachineCfg l2vic_machines[] = {
{ "virt", &v68n_1024 },
{ "V66G_1024", &v66g_1024 },
+ { "qcs6490-cdsp", &qcs6490_cdsp },
};
static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
diff --git a/tests/qtest/qcom-dsp-test.c b/tests/qtest/qcom-dsp-test.c
new file mode 100644
index 00000000000..39d6e53bc4e
--- /dev/null
+++ b/tests/qtest/qcom-dsp-test.c
@@ -0,0 +1,93 @@
+/*
+ * QTest for what the Qualcomm DSP machines have in common: the console and
+ * the virtio-mmio transports.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqtest-single.h"
+
+#define QCOM_DSP_UART_BASE 0x37000000
+#define QCOM_DSP_VIRTIO_BASE 0x37010000
+#define QCOM_DSP_VIRTIO_STRIDE 0x1000
+#define QCOM_DSP_VIRTIO_COUNT 8
+
+#define PL011_UARTPERIPHID0 0xfe0
+#define PL011_PERIPHID0 0x11
+
+#define VIRTIO_MMIO_MAGIC_VALUE 0x000
+#define VIRTIO_MMIO_DEVICE_ID 0x008
+#define VIRTIO_MAGIC 0x74726976 /* "virt" */
+
+static const char *const qcom_dsp_machines[] = {
+ "qcs6490-cdsp",
+};
+
+static void test_console(const void *machine)
+{
+ g_autofree char *args = g_strdup_printf("-machine %s",
+ (const char *)machine);
+
+ qtest_start(args);
+ g_assert_cmphex(readl(QCOM_DSP_UART_BASE + PL011_UARTPERIPHID0), ==,
+ PL011_PERIPHID0);
+ qtest_end();
+}
+
+static void test_virtio_slots(const void *machine)
+{
+ g_autofree char *args = g_strdup_printf("-machine %s",
+ (const char *)machine);
+
+ qtest_start(args);
+ for (int i = 0; i < QCOM_DSP_VIRTIO_COUNT; i++) {
+ uint64_t base = QCOM_DSP_VIRTIO_BASE + i * QCOM_DSP_VIRTIO_STRIDE;
+
+ g_assert_cmphex(readl(base + VIRTIO_MMIO_MAGIC_VALUE), ==,
+ VIRTIO_MAGIC);
+ /* No backend is attached, so the transport is empty. */
+ g_assert_cmpuint(readl(base + VIRTIO_MMIO_DEVICE_ID), ==, 0);
+ }
+ qtest_end();
+}
+
+/* A drive is attached to a virtio transport without any -device. */
+static void test_default_drive(const void *machine)
+{
+ g_autofree char *args = g_strdup_printf(
+ "-machine %s -drive if=virtio,file=null-co://,format=raw",
+ (const char *)machine);
+ int found = 0;
+
+ qtest_start(args);
+ for (int i = 0; i < QCOM_DSP_VIRTIO_COUNT; i++) {
+ uint64_t base = QCOM_DSP_VIRTIO_BASE + i * QCOM_DSP_VIRTIO_STRIDE;
+
+ /* virtio-blk is device ID 2 */
+ found += readl(base + VIRTIO_MMIO_DEVICE_ID) == 2;
+ }
+ g_assert_cmpint(found, ==, 1);
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(qcom_dsp_machines); i++) {
+ const char *name = qcom_dsp_machines[i];
+ g_autofree char *path = NULL;
+
+ path = g_strdup_printf("/qcom-dsp/%s/console", name);
+ qtest_add_data_func(path, name, test_console);
+ path = g_strdup_printf("/qcom-dsp/%s/virtio-slots", name);
+ qtest_add_data_func(path, name, test_virtio_slots);
+ path = g_strdup_printf("/qcom-dsp/%s/default-drive", name);
+ qtest_add_data_func(path, name, test_default_drive);
+ }
+
+ return g_test_run();
+}
diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c
index fd8bb0af776..263751b55bf 100644
--- a/tests/qtest/qct-qtimer-test.c
+++ b/tests/qtest/qct-qtimer-test.c
@@ -12,6 +12,7 @@
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
+#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL
@@ -342,6 +343,7 @@ typedef struct {
static const QtimerMachineCfg qtimer_machines[] = {
{ "virt", &v68n_1024 },
{ "V66G_1024", &v66g_1024 },
+ { "qcs6490-cdsp", &qcs6490_cdsp },
};
static void test_qtimer_on_machine(gconstpointer data)
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index 63ee8836aca..ffc8623691c 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -21,3 +21,18 @@ config HEX_VIRT
select HEX_BOARD
select VIRTIO_BLK
select VIRTIO_SCSI
+
+config HEX_QCOM_DSP
+ bool
+ depends on HEX_DSP && FDT
+ select HEX_BOARD
+ select UNIMP
+ select QCOM_QDSP6SS_CLK
+ select VIRTIO_BLK
+ select VIRTIO_SCSI
+
+config HEX_QCS6490_CDSP
+ bool
+ default y
+ depends on HEX_DSP && FDT
+ select HEX_QCOM_DSP
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index 57bff31ad00..7145e8a65df 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -6,5 +6,7 @@ hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hex-subsys.c'))
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_BOARD', if_true: files('hex-board.c'))
hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_QCOM_DSP', if_true: files('qcom_dsp.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_QCS6490_CDSP', if_true: files('qcs6490_cdsp.c'))
hw_arch += {'hexagon': hexagon_ss}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 019c63ca60b..0bbca236659 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -320,7 +320,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', 'qct-qtimer-test']
+qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qcom-dsp-test',
+ 'qct-qtimer-test']
qos_test_ss = ss.source_set()
qos_test_ss.add(
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 07/14] hw/hexagon: add the SA8775P CDSP machine
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (5 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 08/14] hw/hexagon: add the SC8480XP NSP0 machine Brian Cain
` (6 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc | 6 ++-
hw/hexagon/sa8775p_cdsp.c | 59 +++++++++++++++++++++++
tests/qtest/l2vic-test.c | 2 +
tests/qtest/qcom-dsp-test.c | 1 +
tests/qtest/qct-qtimer-test.c | 2 +
hw/hexagon/Kconfig | 6 +++
hw/hexagon/meson.build | 1 +
7 files changed, 76 insertions(+), 1 deletion(-)
create mode 100644 hw/hexagon/sa8775p_cdsp.c
diff --git a/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc b/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
index 442cbe3be31..7e2ef42b9e2 100644
--- a/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
+++ b/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
static const struct hexagon_machine_config SA8775P_cdsp0 = {
+ .ddr_base = 0x80000000,
.cfgbase = 0x24000000 + 0x180000,
.l2tcm_size = 0x00000000,
.l2vic_base = 0x26300000 + 0x90000,
@@ -25,7 +26,7 @@ static const struct hexagon_machine_config SA8775P_cdsp0 = {
.vtcm_base = 0x00002500,
.vtcm_size_kb = 0x00002000,
.l2tag_size = 0x00000400,
- .l2ecomem_size = 0x00000000,
+ .l2ecomem_size = 0x00000400,
.thread_enable_mask = 0x0000003f,
.eccreg_base = 0x0000241f,
.l2line_size = 0x00000080,
@@ -60,5 +61,8 @@ static const struct hexagon_machine_config SA8775P_cdsp0 = {
.consistency_domain = 0x000000e0,
.capacity_domain = 0x00000080,
.axi3_lowaddr = 0x00000000,
+ .coproc2_int8_subcolumns = 0x00000002,
+ .corecfg_present = 0x00000005,
+ .coproc2_fp16_acc_exp = 0x00000007,
},
};
diff --git a/hw/hexagon/sa8775p_cdsp.c b/hw/hexagon/sa8775p_cdsp.c
new file mode 100644
index 00000000000..de44f8f65cc
--- /dev/null
+++ b/hw/hexagon/sa8775p_cdsp.c
@@ -0,0 +1,59 @@
+/*
+ * Models the v73 CDSP0 of the SA8775P.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/boards.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/qcom_dsp.h"
+#include "target/hexagon/cpu.h"
+
+#include "machine_cfg_sa8775_cdsp0.h.inc"
+
+#define TYPE_SA8775P_CDSP_MACHINE MACHINE_TYPE_NAME("sa8775p-cdsp")
+
+static const QcomDspRegion sa8775p_cdsp_regions[] = {
+ { "tcsr", 0x01fc0000 },
+ { "hwkm-prng", 0x010da000 },
+ { "gdscr", 0x00151000 },
+ { "pll0", 0x26340000 },
+ { "pll1", 0x26000000 },
+ { "clkctl", 0x26348000 },
+ { "ccswi", 0x26008000 },
+ { "rsc", 0x260a4000 },
+};
+
+static void sa8775p_cdsp_init_devices(MachineState *ms)
+{
+ qcom_dsp_add_regions(ms, sa8775p_cdsp_regions,
+ ARRAY_SIZE(sa8775p_cdsp_regions));
+
+ qcom_soc_add_qup_geni_ports("sa8775p", 0x00b80000, 1, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8775p", 0x00880000, 7, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8775p", 0x00980000, 7, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8775p", 0x00a80000, 7, 0x4000);
+}
+
+static const QcomDspMachineInfo sa8775p_cdsp_info = {
+ .desc = "SA8775P CDSP0",
+ .cpu_type = HEXAGON_CPU_TYPE_NAME("v73"),
+ .cpus = 6,
+ .rev = v73_rev,
+ .cfg = &SA8775P_cdsp0,
+ .kernel_addr = 0xa0000000,
+ .init_devices = sa8775p_cdsp_init_devices,
+};
+
+static const TypeInfo sa8775p_cdsp_types[] = {
+ {
+ .name = TYPE_SA8775P_CDSP_MACHINE,
+ .parent = TYPE_QCOM_DSP_MACHINE,
+ .class_init = qcom_dsp_class_init,
+ .class_data = &sa8775p_cdsp_info,
+ },
+};
+
+DEFINE_TYPES(sa8775p_cdsp_types)
diff --git a/tests/qtest/l2vic-test.c b/tests/qtest/l2vic-test.c
index 2e0d7dcb0f1..5d30d18a9fd 100644
--- a/tests/qtest/l2vic-test.c
+++ b/tests/qtest/l2vic-test.c
@@ -12,6 +12,7 @@
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
/* L2VIC register offsets exercised by this test */
#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */
@@ -47,6 +48,7 @@ static const L2VICMachineCfg l2vic_machines[] = {
{ "virt", &v68n_1024 },
{ "V66G_1024", &v66g_1024 },
{ "qcs6490-cdsp", &qcs6490_cdsp },
+ { "sa8775p-cdsp", &SA8775P_cdsp0 },
};
static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
diff --git a/tests/qtest/qcom-dsp-test.c b/tests/qtest/qcom-dsp-test.c
index 39d6e53bc4e..586e113c181 100644
--- a/tests/qtest/qcom-dsp-test.c
+++ b/tests/qtest/qcom-dsp-test.c
@@ -24,6 +24,7 @@
static const char *const qcom_dsp_machines[] = {
"qcs6490-cdsp",
+ "sa8775p-cdsp",
};
static void test_console(const void *machine)
diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c
index 263751b55bf..b20d4a2bced 100644
--- a/tests/qtest/qct-qtimer-test.c
+++ b/tests/qtest/qct-qtimer-test.c
@@ -13,6 +13,7 @@
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL
@@ -344,6 +345,7 @@ static const QtimerMachineCfg qtimer_machines[] = {
{ "virt", &v68n_1024 },
{ "V66G_1024", &v66g_1024 },
{ "qcs6490-cdsp", &qcs6490_cdsp },
+ { "sa8775p-cdsp", &SA8775P_cdsp0 },
};
static void test_qtimer_on_machine(gconstpointer data)
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index ffc8623691c..bdda7872878 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -36,3 +36,9 @@ config HEX_QCS6490_CDSP
default y
depends on HEX_DSP && FDT
select HEX_QCOM_DSP
+
+config HEX_SA8775P_CDSP
+ bool
+ default y
+ depends on HEX_DSP && FDT
+ select HEX_QCOM_DSP
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index 7145e8a65df..b7496426c9a 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -8,5 +8,6 @@ hexagon_ss.add(when: 'CONFIG_HEX_BOARD', if_true: files('hex-board.c'))
hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
hexagon_ss.add(when: 'CONFIG_HEX_QCOM_DSP', if_true: files('qcom_dsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_QCS6490_CDSP', if_true: files('qcs6490_cdsp.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_SA8775P_CDSP', if_true: files('sa8775p_cdsp.c'))
hw_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 08/14] hw/hexagon: add the SC8480XP NSP0 machine
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (6 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 07/14] hw/hexagon: add the SA8775P " Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 09/14] hw/hexagon: add the SA8797P " Brian Cain
` (5 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon.h | 1 +
hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc | 52 +++++++++++++
hw/hexagon/sc8480xp_nsp0.c | 90 ++++++++++++++++++++++
tests/qtest/l2vic-test.c | 2 +
tests/qtest/qcom-dsp-test.c | 1 +
tests/qtest/qct-qtimer-test.c | 2 +
hw/hexagon/Kconfig | 6 ++
hw/hexagon/meson.build | 1 +
8 files changed, 155 insertions(+)
create mode 100644 hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc
create mode 100644 hw/hexagon/sc8480xp_nsp0.c
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 1d0d55ea938..5f993214784 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -29,6 +29,7 @@ typedef enum {
v73_rev = 0x8c73,
v73m_rev = 0xcc73,
v81_rev = 0x8781,
+ v81_sc8480xp_rev = 0x8081,
v81dgb_1_rev = 0xcc81,
} Rev_t;
#define HEXAGON_LATEST_REV v73
diff --git a/hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc b/hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc
new file mode 100644
index 00000000000..5a39e53d834
--- /dev/null
+++ b/hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/* Config table of the SC8480XP NSP0. */
+static const struct hexagon_machine_config sc8480xp_nsp0 = {
+ .ddr_base = 0x80000000,
+ .cfgbase = 0x30180000,
+ .l2vic_base = 0x32390000,
+ .l2vic_size = 0x1000,
+ .csr_base = 0x323a0000,
+ .qtmr_region = 0x323a1000,
+ .cfgtable = {
+ .l2tcm_base = 0x3000,
+ .subsystem_base = 0x3238,
+ .etm_base = 0x3019,
+ .l2cfg_base = 0x301a,
+ .l1s0_base = 0x3100,
+ .fastl2vic_base = 0x301e,
+ .jtlb_size_entries = 0x80,
+ .coproc_present = 0xd,
+ .ext_contexts = 8,
+ .vtcm_base = 0x3100,
+ .vtcm_size_kb = 0x2000,
+ .l2tag_size = 0x400,
+ .l2ecomem_size = 0x400,
+ .thread_enable_mask = 0xfff,
+ .l2line_size = 0x80,
+ .l2itcm_base = 0xd800,
+ .dma_version = 8,
+ .hvx_vec_log_length = 7,
+ .coproc2_reg0 = 0x10,
+ .coproc2_reg1 = 8,
+ .acd_preset = 1,
+ .mnd_preset = 1,
+ .l1d_size_kb = 0x40,
+ .l1i_size_kb = 0x40,
+ .l1d_write_policy = 2,
+ .vtcm_bank_width = 0x80,
+ .reserved4 = 1,
+ .axi3_lowaddr = 0x4000,
+ .corecfg_present = 0xd,
+ .coproc2_fp16_acc_exp = 1,
+ .AXIM_data_width = 0x100,
+ .l1d_ways = 8,
+ .l1i_ways = 4,
+ .l2way_num = 8,
+ .dma_jtlb_entries = 0x40,
+ },
+};
diff --git a/hw/hexagon/sc8480xp_nsp0.c b/hw/hexagon/sc8480xp_nsp0.c
new file mode 100644
index 00000000000..68003f88161
--- /dev/null
+++ b/hw/hexagon/sc8480xp_nsp0.c
@@ -0,0 +1,90 @@
+/*
+ * Models the Hexagon v81 NSP of the SC8480XP.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/boards.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/qcom_dsp.h"
+#include "target/hexagon/cpu.h"
+
+#include "machine_cfg_sc8480xp_nsp0.h.inc"
+
+#define TYPE_SC8480XP_NSP0_MACHINE MACHINE_TYPE_NAME("sc8480xp-nsp0")
+
+static const QcomDspRegion sc8480xp_nsp0_regions[] = {
+ { "tcsr", 0x01f40000, 0xc0000 },
+ { "hwkm-prng", 0x010ca000 },
+ { "pll", 0x32340000 },
+ { "clkctl", 0x32344000, 0x4000 },
+ { "turing-cc", 0x32008000, 0x14000 },
+ { "rsc", 0x320a4000 },
+ { "dsp-rsc", 0x323c0000 },
+ { "ipcc", 0x03e00000 },
+ { "ipcc-legacy", 0x32380000 },
+ { "pinctrl", 0x0f100000, 0x0f00000 },
+ { "gcc", 0x00100000, 0x200000 },
+ { "turing-cc-pll", 0x32000000, 0x8000 },
+ { "q6-acd", 0x32350000, 0x800 },
+ { "hmx-pll", 0x32348000 },
+ { "hmx-cc", 0x3234c000, 0x4000 },
+ { "hmx-acd", 0x32350800, 0x800 },
+ { "stmtrace", 0x16000000, 0x1000000 },
+ { "stmcfg", 0x10002000 },
+ { "etb", 0x11c05000 },
+ { "tpdm", 0x11181000, 0x6000 },
+ { "tpda", 0x11188000 },
+ { "funnel", 0x10041000 },
+ { "funnel", 0x11c04000 },
+ { "llcc", 0x20400000, 0x100000 },
+ { "llcc", 0x20600000, 0x100000 },
+ { "llcc", 0x21800000, 0x100000 },
+ { "llcc", 0x21a00000, 0x100000 },
+ { "llcc", 0x21c00000, 0x100000 },
+ { "llcc", 0x21e00000, 0x100000 },
+ { "llcc", 0x22800000, 0x100000 },
+ { "llcc", 0x22a00000, 0x100000 },
+ { "llcc", 0x22c00000, 0x100000 },
+ { "llcc", 0x22e00000, 0x100000 },
+ { "llcc", 0x23800000, 0x100000 },
+ { "llcc", 0x23a00000, 0x100000 },
+ { "llcc", 0x23c00000, 0x100000 },
+ { "llcc", 0x23e00000, 0x100000 },
+ { "ddrss", 0x20280000, 0x400 },
+};
+
+static void sc8480xp_nsp0_init_devices(MachineState *ms)
+{
+ qcom_dsp_add_regions(ms, sc8480xp_nsp0_regions,
+ ARRAY_SIZE(sc8480xp_nsp0_regions));
+
+ qcom_soc_add_qup_geni_ports("sc8480xp", 0x07980000, 15, 0x4000);
+ qcom_soc_add_qup_geni_ports("sc8480xp", 0x00b80000, 8, 0x4000);
+ qcom_soc_add_qup_geni_ports("sc8480xp", 0x00a80000, 8, 0x4000);
+ qcom_soc_add_qup_geni_ports("sc8480xp", 0x00980000, 2, 0x4000);
+ qcom_soc_add_qup_geni_ports("sc8480xp", 0x00880000, 8, 0x4000);
+}
+
+static const QcomDspMachineInfo sc8480xp_nsp0_info = {
+ .desc = "SC8480XP NSP",
+ .cpu_type = HEXAGON_CPU_TYPE_NAME("v81"),
+ .cpus = 12,
+ .rev = v81_sc8480xp_rev,
+ .cfg = &sc8480xp_nsp0,
+ .kernel_addr = 0xa0000000,
+ .init_devices = sc8480xp_nsp0_init_devices,
+};
+
+static const TypeInfo sc8480xp_nsp0_types[] = {
+ {
+ .name = TYPE_SC8480XP_NSP0_MACHINE,
+ .parent = TYPE_QCOM_DSP_MACHINE,
+ .class_init = qcom_dsp_class_init,
+ .class_data = &sc8480xp_nsp0_info,
+ },
+};
+
+DEFINE_TYPES(sc8480xp_nsp0_types)
diff --git a/tests/qtest/l2vic-test.c b/tests/qtest/l2vic-test.c
index 5d30d18a9fd..7afeabdbed8 100644
--- a/tests/qtest/l2vic-test.c
+++ b/tests/qtest/l2vic-test.c
@@ -12,6 +12,7 @@
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
/* L2VIC register offsets exercised by this test */
@@ -49,6 +50,7 @@ static const L2VICMachineCfg l2vic_machines[] = {
{ "V66G_1024", &v66g_1024 },
{ "qcs6490-cdsp", &qcs6490_cdsp },
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
+ { "sc8480xp-nsp0", &sc8480xp_nsp0 },
};
static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
diff --git a/tests/qtest/qcom-dsp-test.c b/tests/qtest/qcom-dsp-test.c
index 586e113c181..46bbae47881 100644
--- a/tests/qtest/qcom-dsp-test.c
+++ b/tests/qtest/qcom-dsp-test.c
@@ -25,6 +25,7 @@
static const char *const qcom_dsp_machines[] = {
"qcs6490-cdsp",
"sa8775p-cdsp",
+ "sc8480xp-nsp0",
};
static void test_console(const void *machine)
diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c
index b20d4a2bced..629a11802ef 100644
--- a/tests/qtest/qct-qtimer-test.c
+++ b/tests/qtest/qct-qtimer-test.c
@@ -13,6 +13,7 @@
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL
@@ -346,6 +347,7 @@ static const QtimerMachineCfg qtimer_machines[] = {
{ "V66G_1024", &v66g_1024 },
{ "qcs6490-cdsp", &qcs6490_cdsp },
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
+ { "sc8480xp-nsp0", &sc8480xp_nsp0 },
};
static void test_qtimer_on_machine(gconstpointer data)
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index bdda7872878..8785129da0e 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -42,3 +42,9 @@ config HEX_SA8775P_CDSP
default y
depends on HEX_DSP && FDT
select HEX_QCOM_DSP
+
+config HEX_SC8480XP_NSP0
+ bool
+ default y
+ depends on HEX_DSP && FDT
+ select HEX_QCOM_DSP
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index b7496426c9a..b42a37b14de 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -9,5 +9,6 @@ hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
hexagon_ss.add(when: 'CONFIG_HEX_QCOM_DSP', if_true: files('qcom_dsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_QCS6490_CDSP', if_true: files('qcs6490_cdsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_SA8775P_CDSP', if_true: files('sa8775p_cdsp.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_SC8480XP_NSP0', if_true: files('sc8480xp_nsp0.c'))
hw_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 09/14] hw/hexagon: add the SA8797P NSP0 machine
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (7 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 08/14] hw/hexagon: add the SC8480XP NSP0 machine Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 10/14] hw/hexagon: add the SM8975 NSP machine Brian Cain
` (4 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc | 56 +++++++++++++++++++
hw/hexagon/sa8797p_nsp0.c | 68 +++++++++++++++++++++++
tests/qtest/l2vic-test.c | 2 +
tests/qtest/qcom-dsp-test.c | 1 +
tests/qtest/qct-qtimer-test.c | 2 +
hw/hexagon/Kconfig | 6 ++
hw/hexagon/meson.build | 1 +
7 files changed, 136 insertions(+)
create mode 100644 hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc
create mode 100644 hw/hexagon/sa8797p_nsp0.c
diff --git a/hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc b/hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc
new file mode 100644
index 00000000000..abc02a3e9ce
--- /dev/null
+++ b/hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+static const struct hexagon_machine_config sa8797p_nsp0 = {
+ .ddr_base = 0x80000000,
+ .cfgbase = 0x30180000,
+ .l2vic_base = 0x32390000,
+ .l2vic_size = 0x1000,
+ .l2tcm_size = 0x100000,
+ .csr_base = 0x323a0000,
+ .qtmr_region = 0x323a1000,
+ .cfgtable = {
+ .l2tcm_base = 0x3000,
+ .subsystem_base = 0x3238,
+ .etm_base = 0x3019,
+ .l2cfg_base = 0x301a,
+ .l1s0_base = 0x3100,
+ .fastl2vic_base = 0x301e,
+ .jtlb_size_entries = 0x80,
+ .coproc_present = 0xd,
+ .ext_contexts = 8,
+ .vtcm_base = 0x3100,
+ .vtcm_size_kb = 0x4000,
+ .l2tag_size = 0x400,
+ .l2ecomem_size = 0x400,
+ .thread_enable_mask = 0xfff,
+ .eccreg_base = 0x301f,
+ .l2line_size = 0x80,
+ .l2itcm_base = 0x3000,
+ .dma_version = 8,
+ .hvx_vec_log_length = 7,
+ .coproc2_reg0 = 0x10,
+ .coproc2_reg1 = 8,
+ .v2x_mode = 1,
+ .acd_preset = 1,
+ .mnd_preset = 1,
+ .l1d_size_kb = 0x40,
+ .l1i_size_kb = 0x40,
+ .l1d_write_policy = 2,
+ .vtcm_bank_width = 0x80,
+ .reserved4 = 1,
+ .reserved6 = 3,
+ .consistency_domain = 0xe0,
+ .capacity_domain = 0x80,
+ .corecfg_present = 0xd,
+ .coproc2_fp16_acc_exp = 1,
+ .AXIM_data_width = 0x100,
+ .l1d_ways = 8,
+ .l1i_ways = 4,
+ .l2way_num = 8,
+ .dma_jtlb_entries = 0x40,
+ },
+};
diff --git a/hw/hexagon/sa8797p_nsp0.c b/hw/hexagon/sa8797p_nsp0.c
new file mode 100644
index 00000000000..20eebd5389f
--- /dev/null
+++ b/hw/hexagon/sa8797p_nsp0.c
@@ -0,0 +1,68 @@
+/*
+ * Models the v81 NSP0 of the SA8797P.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/boards.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/qcom_dsp.h"
+#include "target/hexagon/cpu.h"
+
+#include "machine_cfg_sa8797p_nsp0.h.inc"
+
+#define TYPE_SA8797P_NSP0_MACHINE MACHINE_TYPE_NAME("sa8797p-nsp0")
+
+static const QcomDspRegion sa8797p_nsp0_regions[] = {
+ { "gcc", 0x00100000, 0x200000 },
+ { "ne-gcc", 0x08900000, 0x100000 },
+ { "se-gcc", 0x08a00000, 0x100000 },
+ { "nw-gcc", 0x08b00000, 0x100000 },
+ { "nsp-cc", 0x320c0000, 0x10000 },
+ { "qfprom", 0x360c8000, 0x8000 },
+ { "q6-cc", 0x32340000, 0x11000 },
+ { "pinctrl", 0x0f100000, 0x0f00000 },
+ { "ipcc", 0x09000000 },
+ { "ipcc-legacy", 0x32380000 },
+ { "stmtrace", 0x16000000, 0x1000000 },
+ { "tpdm", 0x117c0000, 0x2000 },
+ { "tpdm", 0x117c5000, 0x2000 },
+ { "tpda", 0x117c8000 },
+};
+
+static void sa8797p_nsp0_init_devices(MachineState *ms)
+{
+ qcom_dsp_add_regions(ms, sa8797p_nsp0_regions,
+ ARRAY_SIZE(sa8797p_nsp0_regions));
+
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x09b86000, 5, 0x2000);
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x09c06000, 5, 0x2000);
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x00c80000, 1, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x00a80000, 7, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x00980000, 7, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x00880000, 7, 0x4000);
+ qcom_soc_add_qup_geni_ports("sa8797p", 0x198880000, 6, 0x4000);
+}
+
+static const QcomDspMachineInfo sa8797p_nsp0_info = {
+ .desc = "SA8797P NSP",
+ .cpu_type = HEXAGON_CPU_TYPE_NAME("v81"),
+ .cpus = 12,
+ .rev = v81_rev,
+ .cfg = &sa8797p_nsp0,
+ .kernel_addr = 0xa0000000,
+ .init_devices = sa8797p_nsp0_init_devices,
+};
+
+static const TypeInfo sa8797p_nsp0_types[] = {
+ {
+ .name = TYPE_SA8797P_NSP0_MACHINE,
+ .parent = TYPE_QCOM_DSP_MACHINE,
+ .class_init = qcom_dsp_class_init,
+ .class_data = &sa8797p_nsp0_info,
+ },
+};
+
+DEFINE_TYPES(sa8797p_nsp0_types)
diff --git a/tests/qtest/l2vic-test.c b/tests/qtest/l2vic-test.c
index 7afeabdbed8..4cd0319e8b5 100644
--- a/tests/qtest/l2vic-test.c
+++ b/tests/qtest/l2vic-test.c
@@ -12,6 +12,7 @@
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
@@ -51,6 +52,7 @@ static const L2VICMachineCfg l2vic_machines[] = {
{ "qcs6490-cdsp", &qcs6490_cdsp },
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
{ "sc8480xp-nsp0", &sc8480xp_nsp0 },
+ { "sa8797p-nsp0", &sa8797p_nsp0 },
};
static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
diff --git a/tests/qtest/qcom-dsp-test.c b/tests/qtest/qcom-dsp-test.c
index 46bbae47881..def389a0e9e 100644
--- a/tests/qtest/qcom-dsp-test.c
+++ b/tests/qtest/qcom-dsp-test.c
@@ -26,6 +26,7 @@ static const char *const qcom_dsp_machines[] = {
"qcs6490-cdsp",
"sa8775p-cdsp",
"sc8480xp-nsp0",
+ "sa8797p-nsp0",
};
static void test_console(const void *machine)
diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c
index 629a11802ef..21870de5649 100644
--- a/tests/qtest/qct-qtimer-test.c
+++ b/tests/qtest/qct-qtimer-test.c
@@ -13,6 +13,7 @@
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
@@ -348,6 +349,7 @@ static const QtimerMachineCfg qtimer_machines[] = {
{ "qcs6490-cdsp", &qcs6490_cdsp },
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
{ "sc8480xp-nsp0", &sc8480xp_nsp0 },
+ { "sa8797p-nsp0", &sa8797p_nsp0 },
};
static void test_qtimer_on_machine(gconstpointer data)
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index 8785129da0e..bcf368cb8b7 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -48,3 +48,9 @@ config HEX_SC8480XP_NSP0
default y
depends on HEX_DSP && FDT
select HEX_QCOM_DSP
+
+config HEX_SA8797P_NSP0
+ bool
+ default y
+ depends on HEX_DSP && FDT
+ select HEX_QCOM_DSP
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index b42a37b14de..5a10ae694fe 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -10,5 +10,6 @@ hexagon_ss.add(when: 'CONFIG_HEX_QCOM_DSP', if_true: files('qcom_dsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_QCS6490_CDSP', if_true: files('qcs6490_cdsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_SA8775P_CDSP', if_true: files('sa8775p_cdsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_SC8480XP_NSP0', if_true: files('sc8480xp_nsp0.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_SA8797P_NSP0', if_true: files('sa8797p_nsp0.c'))
hw_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 10/14] hw/hexagon: add the SM8975 NSP machine
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (8 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 09/14] hw/hexagon: add the SA8797P " Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 11/14] hw/hexagon: add v79NA1 machine Brian Cain
` (3 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon.h | 1 +
hw/hexagon/machine_cfg_sm8975_nsp.h.inc | 55 +++++++++++++
hw/hexagon/sm8975_nsp.c | 102 ++++++++++++++++++++++++
tests/qtest/l2vic-test.c | 2 +
tests/qtest/qcom-dsp-test.c | 17 ++++
tests/qtest/qct-qtimer-test.c | 2 +
hw/hexagon/Kconfig | 6 ++
hw/hexagon/meson.build | 1 +
8 files changed, 186 insertions(+)
create mode 100644 hw/hexagon/machine_cfg_sm8975_nsp.h.inc
create mode 100644 hw/hexagon/sm8975_nsp.c
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 5f993214784..26b0a1b3757 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -31,6 +31,7 @@ typedef enum {
v81_rev = 0x8781,
v81_sc8480xp_rev = 0x8081,
v81dgb_1_rev = 0xcc81,
+ v85_sm8975_rev = 0x8085,
} Rev_t;
#define HEXAGON_LATEST_REV v73
#define HEXAGON_LATEST_REV_UPPER V73
diff --git a/hw/hexagon/machine_cfg_sm8975_nsp.h.inc b/hw/hexagon/machine_cfg_sm8975_nsp.h.inc
new file mode 100644
index 00000000000..b97e7880938
--- /dev/null
+++ b/hw/hexagon/machine_cfg_sm8975_nsp.h.inc
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/* Config table of the SM8975 NSP. */
+static const struct hexagon_machine_config sm8975_nsp = {
+ .ddr_base = 0x80000000,
+ .cfgbase = 0x24180000,
+ .l2tcm_size = 0x100000,
+ .l2vic_base = 0x26390000,
+ .l2vic_size = 0x1000,
+ .csr_base = 0x263a0000,
+ .qtmr_region = 0x263a1000,
+ .cfgtable = {
+ .l2tcm_base = 0x2400,
+ .subsystem_base = 0x2638,
+ .etm_base = 0x2419,
+ .l2cfg_base = 0x241a,
+ .l1s0_base = 0x2500,
+ .fastl2vic_base = 0x241e,
+ .jtlb_size_entries = 0x80,
+ .coproc_present = 0x1d,
+ .ext_contexts = 8,
+ .vtcm_base = 0x2500,
+ .vtcm_size_kb = 0x3000,
+ .l2tag_size = 0x400,
+ .l2ecomem_size = 0x400,
+ .thread_enable_mask = 0xfff,
+ .l2line_size = 0x80,
+ .l2itcm_base = 0x2400,
+ .dma_version = 0xc,
+ .hvx_vec_log_length = 7,
+ .coproc2_reg0 = 0x10,
+ .coproc2_reg1 = 8,
+ .coproc2_reg2 = 3,
+ .acd_preset = 1,
+ .mnd_preset = 1,
+ .l1d_size_kb = 0x40,
+ .l1i_size_kb = 0x40,
+ .l1d_write_policy = 2,
+ .vtcm_bank_width = 0x80,
+ .consistency_domain = 0xe0,
+ .capacity_domain = 0x80,
+ .axi3_lowaddr = 0x4000,
+ .corecfg_present = 0xd,
+ .coproc2_fp16_acc_exp = 3,
+ .AXIM_data_width = 0x100,
+ .l1d_ways = 8,
+ .l1i_ways = 4,
+ .l2way_num = 8,
+ .dma_jtlb_entries = 0x40,
+ },
+};
diff --git a/hw/hexagon/sm8975_nsp.c b/hw/hexagon/sm8975_nsp.c
new file mode 100644
index 00000000000..91790c84230
--- /dev/null
+++ b/hw/hexagon/sm8975_nsp.c
@@ -0,0 +1,102 @@
+/*
+ * sm8975-nsp machine.
+ *
+ * Models the Hexagon v85 NSP of the SM8975.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/boards.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/qcom_dsp.h"
+#include "target/hexagon/cpu.h"
+
+#include "machine_cfg_sm8975_nsp.h.inc"
+
+#define TYPE_SM8975_NSP_MACHINE MACHINE_TYPE_NAME("sm8975-nsp")
+
+static const QcomDspRegion sm8975_nsp_regions[] = {
+ { "dspss-pub", 0x26300000, 0x10000 },
+ { "wdog", 0x26384000 },
+ { "turing-cc", 0x26008000, 0x14000 },
+ { "pll", 0x26340000 },
+ { "clkctl", 0x26344000, 0x4000 },
+ { "compute-rsc", 0x260a4000 },
+ { "qdsp6-rsc", 0x263c0000 },
+ { "ipcc", 0x01100000 },
+ { "tcsr", 0x26080000, 0x1f000 },
+ { "turing-cc-pll", 0x26000000 },
+ { "turing-cc-pll", 0x26001000 },
+ { "turing-cc-pll", 0x26002000 },
+ { "turing-cc-pll", 0x26003000 },
+ { "turing-cc-pll", 0x26004000 },
+ { "ahb2phy", 0x26006000, 0x2000 },
+ { "ahbe-time", 0x260b7000 },
+ { "nsp-noc", 0x260c0000, 0x21280 },
+ { "ceng", 0x26260000, 0xc000 },
+ { "ceng-irq", 0x2626c000 },
+ { "ubwcd", 0x26280000, 0x10000 },
+ { "vapss", 0x262c0000, 0x40000 },
+ { "llm-isense", 0x26310000, 0x10000 },
+ { "lpm-stats", 0x26320000, 0x10000 },
+ { "mxu-pll", 0x26348000 },
+ { "acd-mnd-dcc", 0x26350000, 0x800 },
+ { "hmx-acd-mnd-dcc", 0x26350800, 0x800 },
+ { "gcc", 0x00100000, 0x200000 },
+ { "fuse", 0x221c8000 },
+ { "hmx-swman", 0x2634a000, 0x400 },
+ { "hmx-broadcast", 0x2634b000, 0x400 },
+ { "hmx-cc", 0x2634c000, 0x4000 },
+ { "ipcc-legacy", 0x26380000 },
+ { "pinctrl", 0x0f100000, 0x0f00000 },
+ { "llcc", 0x31800000, 0x200000 },
+ { "llcc", 0x31c00000, 0x200000 },
+ { "llcc", 0x32800000, 0x200000 },
+ { "llcc", 0x32c00000, 0x200000 },
+ { "llcc", 0x34800000, 0x200000 },
+ { "llcc", 0x34c00000, 0x200000 },
+ { "stmtrace", 0x16000000, 0x1000000 },
+ { "stmcfg", 0x10002000 },
+ { "etb", 0x11305000 },
+ { "tpdm", 0x11181000, 0x2000 },
+ { "tpdm", 0x11185000, 0x2000 },
+ { "funnel", 0x10041000 },
+ { "funnel", 0x11304000 },
+ { "tpda", 0x11188000 },
+};
+
+static void sm8975_nsp_init_devices(MachineState *ms)
+{
+ qcom_dsp_add_regions(ms, sm8975_nsp_regions,
+ ARRAY_SIZE(sm8975_nsp_regions));
+
+ qcom_soc_add_qup_geni_ports("sm8975", 0x08180000, 8, 0x4000);
+ qcom_soc_add_qup_geni_ports("sm8975", 0x08280000, 8, 0x4000);
+ qcom_soc_add_qup_geni_ports("sm8975", 0x01980000, 6, 0x4000);
+ qcom_soc_add_qup_geni_ports("sm8975", 0x01a80000, 5, 0x4000);
+ qcom_soc_add_qup_geni_ports("sm8975", 0x00a80000, 8, 0x4000);
+ qcom_soc_add_qup_geni_ports("sm8975", 0x00880000, 5, 0x4000);
+}
+
+static const QcomDspMachineInfo sm8975_nsp_info = {
+ .desc = "SM8975 NSP",
+ .cpu_type = HEXAGON_CPU_TYPE_NAME("v85"),
+ .cpus = 12,
+ .rev = v85_sm8975_rev,
+ .cfg = &sm8975_nsp,
+ .kernel_addr = 0xa0000000,
+ .init_devices = sm8975_nsp_init_devices,
+};
+
+static const TypeInfo sm8975_nsp_types[] = {
+ {
+ .name = TYPE_SM8975_NSP_MACHINE,
+ .parent = TYPE_QCOM_DSP_MACHINE,
+ .class_init = qcom_dsp_class_init,
+ .class_data = &sm8975_nsp_info,
+ },
+};
+
+DEFINE_TYPES(sm8975_nsp_types)
diff --git a/tests/qtest/l2vic-test.c b/tests/qtest/l2vic-test.c
index 4cd0319e8b5..82f93fd58f9 100644
--- a/tests/qtest/l2vic-test.c
+++ b/tests/qtest/l2vic-test.c
@@ -12,6 +12,7 @@
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sm8975_nsp.h.inc"
#include "hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
@@ -53,6 +54,7 @@ static const L2VICMachineCfg l2vic_machines[] = {
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
{ "sc8480xp-nsp0", &sc8480xp_nsp0 },
{ "sa8797p-nsp0", &sa8797p_nsp0 },
+ { "sm8975-nsp", &sm8975_nsp },
};
static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
diff --git a/tests/qtest/qcom-dsp-test.c b/tests/qtest/qcom-dsp-test.c
index def389a0e9e..9cca6a835d0 100644
--- a/tests/qtest/qcom-dsp-test.c
+++ b/tests/qtest/qcom-dsp-test.c
@@ -9,6 +9,8 @@
#include "qemu/osdep.h"
#include "libqtest.h"
#include "libqtest-single.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/machine_cfg_sm8975_nsp.h.inc"
#define QCOM_DSP_UART_BASE 0x37000000
#define QCOM_DSP_VIRTIO_BASE 0x37010000
@@ -27,6 +29,7 @@ static const char *const qcom_dsp_machines[] = {
"sa8775p-cdsp",
"sc8480xp-nsp0",
"sa8797p-nsp0",
+ "sm8975-nsp",
};
static void test_console(const void *machine)
@@ -76,6 +79,18 @@ static void test_default_drive(const void *machine)
qtest_end();
}
+static void test_tcm(const void *unused)
+{
+ uint64_t base = (uint64_t)sm8975_nsp.cfgtable.l2tcm_base << 16;
+
+ qtest_start("-machine sm8975-nsp");
+ writel(base, 0xdeadbeef);
+ writel(base + sm8975_nsp.l2tcm_size - 4, 0xcafef00d);
+ g_assert_cmphex(readl(base), ==, 0xdeadbeef);
+ g_assert_cmphex(readl(base + sm8975_nsp.l2tcm_size - 4), ==, 0xcafef00d);
+ qtest_end();
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -92,5 +107,7 @@ int main(int argc, char **argv)
qtest_add_data_func(path, name, test_default_drive);
}
+ qtest_add_data_func("/qcom-dsp/sm8975-nsp/tcm", NULL, test_tcm);
+
return g_test_run();
}
diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c
index 21870de5649..b4c1b9e37f4 100644
--- a/tests/qtest/qct-qtimer-test.c
+++ b/tests/qtest/qct-qtimer-test.c
@@ -13,6 +13,7 @@
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
+#include "hw/hexagon/machine_cfg_sm8975_nsp.h.inc"
#include "hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
@@ -350,6 +351,7 @@ static const QtimerMachineCfg qtimer_machines[] = {
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
{ "sc8480xp-nsp0", &sc8480xp_nsp0 },
{ "sa8797p-nsp0", &sa8797p_nsp0 },
+ { "sm8975-nsp", &sm8975_nsp },
};
static void test_qtimer_on_machine(gconstpointer data)
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index bcf368cb8b7..177d87f7f94 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -54,3 +54,9 @@ config HEX_SA8797P_NSP0
default y
depends on HEX_DSP && FDT
select HEX_QCOM_DSP
+
+config HEX_SM8975_NSP
+ bool
+ default y
+ depends on HEX_DSP && FDT
+ select HEX_QCOM_DSP
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index 5a10ae694fe..fa5bc5eb9f1 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -11,5 +11,6 @@ hexagon_ss.add(when: 'CONFIG_HEX_QCS6490_CDSP', if_true: files('qcs6490_cdsp.c')
hexagon_ss.add(when: 'CONFIG_HEX_SA8775P_CDSP', if_true: files('sa8775p_cdsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_SC8480XP_NSP0', if_true: files('sc8480xp_nsp0.c'))
hexagon_ss.add(when: 'CONFIG_HEX_SA8797P_NSP0', if_true: files('sa8797p_nsp0.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_SM8975_NSP', if_true: files('sm8975_nsp.c'))
hw_arch += {'hexagon': hexagon_ss}
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 11/14] hw/hexagon: add v79NA1 machine
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (9 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 10/14] hw/hexagon: add the SM8975 NSP machine Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:16 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 12/14] hw/hexagon: add subsystem-base property Brian Cain
` (2 subsequent siblings)
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Add the Hexagon V79NA_1 simulator machine, with the config table of the
v79 core and eight CPUs by default.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon.h | 1 +
hw/hexagon/machine_cfg_v79na_1.h.inc | 34 ++++++++++++++++++++++++++++
hw/hexagon/hexagon_dsp.c | 22 ++++++++++++++++++
3 files changed, 57 insertions(+)
create mode 100644 hw/hexagon/machine_cfg_v79na_1.h.inc
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 26b0a1b3757..7d15a9e1eb0 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -28,6 +28,7 @@ typedef enum {
v71_rev = 0x8c71,
v73_rev = 0x8c73,
v73m_rev = 0xcc73,
+ v79_rev = 0x8c79,
v81_rev = 0x8781,
v81_sc8480xp_rev = 0x8081,
v81dgb_1_rev = 0xcc81,
diff --git a/hw/hexagon/machine_cfg_v79na_1.h.inc b/hw/hexagon/machine_cfg_v79na_1.h.inc
new file mode 100644
index 00000000000..70a7ae58bc5
--- /dev/null
+++ b/hw/hexagon/machine_cfg_v79na_1.h.inc
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+static const struct hexagon_machine_config v79na_1 = {
+ .cfgbase = 0xd8180000,
+ .l2tcm_size = 0x00000000,
+ .l2vic_base = 0xfc910000,
+ .l2vic_size = 0x00001000,
+ .csr_base = 0xfc900000,
+ .qtmr_region = 0xfc921000,
+ .cfgtable = {
+ .l2tcm_base = 0x0000d800, .subsystem_base = 0x00002000,
+ .etm_base = 0x0000d819, .l2cfg_base = 0x0000d81a,
+ .l1s0_base = 0x0000d900, .axi2_lowaddr = 0x00003000,
+ .fastl2vic_base = 0x0000d81e, .jtlb_size_entries = 0x00000080,
+ .coproc_present = 0x0000000d, .ext_contexts = 0x00000006,
+ .vtcm_base = 0x0000d900, .vtcm_size_kb = 0x00002000,
+ .l2tag_size = 0x00000400, .l2ecomem_size = 0x00000400,
+ .thread_enable_mask = 0x000000ff, .l2line_size = 0x00000080,
+ .l2itcm_base = 0x0000d800, .dma_version = 0x00000006,
+ .hvx_vec_log_length = 0x00000007, .coproc2_reg0 = 0x00000040,
+ .coproc2_reg1 = 0x00000020, .v2x_mode = 0x00000001,
+ .coproc2_reg2 = 0x00000010, .coproc2_reg3 = 0x00000020,
+ .coproc2_reg4 = 0x00000020, .coproc2_reg5 = 0x00000008,
+ .coproc2_reg6 = 0x00000016, .coproc2_reg7 = 0x00000008,
+ .acd_preset = 0x00000001, .mnd_preset = 0x00000001,
+ .l1d_size_kb = 0x00000020, .l1i_size_kb = 0x00000020,
+ .l1d_write_policy = 0x00000002, .vtcm_bank_width = 0x00000080,
+ .reserved4 = 0x00000001, .coproc2_cvt_mpy_size = 0x0000000a,
+ .consistency_domain = 0x000000e0, .capacity_domain = 0x00000080,
+ .axi3_lowaddr = 0x00004000, .coproc2_int8_subcolumns = 0x00000002,
+ .corecfg_present = 0x0000000d, .coproc2_fp16_acc_exp = 0x00000007,
+ .AXIM2_secondary_base = 0x00004000, .AXIM_data_width = 0x00000100,
+ },
+};
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index 8824fe10a59..9f6f34ef9be 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -30,6 +30,7 @@
#include "machine_cfg_v66g_1024.h.inc"
#include "machine_cfg_v68n_1024.h.inc"
+#include "machine_cfg_v79na_1.h.inc"
#include "machine_cfg_v81dgb_1.h.inc"
#include "machine_cfg_v81qa_1.h.inc"
@@ -205,6 +206,22 @@ static void v81dgb_1_config_init(MachineState *machine)
hexagon_common_init(machine, v81dgb_1_rev, &v81dgb_1);
}
+static void v79na_1_config_init(MachineState *machine)
+{
+ hexagon_common_init(machine, v79_rev, &v79na_1);
+}
+
+static void v79na_1_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Hexagon V79NA_1";
+ mc->init = v79na_1_config_init;
+ init_mc(mc);
+ mc->default_cpu_type = TYPE_HEXAGON_CPU_V79;
+ mc->default_cpus = 8;
+}
+
static void v81dgb_1_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -258,6 +275,11 @@ static const TypeInfo hexagon_machine_types[] = {
.parent = TYPE_HEXAGON_DSP_MACHINE,
.class_init = v68n_1024_init,
},
+ {
+ .name = MACHINE_TYPE_NAME("V79NA_1"),
+ .parent = TYPE_HEXAGON_DSP_MACHINE,
+ .class_init = v79na_1_init,
+ },
{
.name = MACHINE_TYPE_NAME("V81DGB_1"),
.parent = TYPE_HEXAGON_DSP_MACHINE,
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 12/14] hw/hexagon: add subsystem-base property
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (10 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 11/14] hw/hexagon: add v79NA1 machine Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 22:16 ` Pierrick Bouvier
2026-10-20 14:53 ` Anton Johansson via qemu development
2026-10-19 5:52 ` [PATCH 13/14] target/hexagon: fix the allocframe framekey Brian Cain
2026-10-19 5:52 ` [PATCH 14/14] tests/functional/hexagon: boot DSP firmware Brian Cain
13 siblings, 2 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
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.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
MAINTAINERS | 1 +
include/hw/hexagon/hexagon.h | 4 ++
hw/hexagon/hexagon_dsp.c | 62 +++++++++++++++++++++++-
tests/qtest/hexagon-config-test.c | 78 +++++++++++++++++++++++++++++++
tests/qtest/meson.build | 3 +-
5 files changed, 146 insertions(+), 2 deletions(-)
create mode 100644 tests/qtest/hexagon-config-test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 04df9db77dc..f1fbc971fed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1386,6 +1386,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 7d15a9e1eb0..32acc2aa26b 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -44,6 +44,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 9f6f34ef9be..1f92a8adccf 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"
@@ -35,6 +36,7 @@
#include "machine_cfg_v81qa_1.h.inc"
#define TYPE_HEXAGON_DSP_MACHINE "hexagon-dsp-machine"
+#define HEXAGON_DSP_SUBSYSTEM_BASE 0xfc900000
OBJECT_DECLARE_SIMPLE_TYPE(HexagonDspMachineState, HEXAGON_DSP_MACHINE)
struct HexagonDspMachineState {
@@ -42,6 +44,8 @@ struct HexagonDspMachineState {
hwaddr isdb_secure_flag;
hwaddr isdb_trusted_flag;
+ uint32_t subsystem_base;
+ struct hexagon_machine_config config;
};
static HexagonDspMachineState *current_dms;
@@ -107,6 +111,50 @@ 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);
+ 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;
+ }
+
+ 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)
{
@@ -121,7 +169,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);
@@ -183,6 +237,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)
@@ -199,6 +254,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 v81dgb_1_config_init(MachineState *machine)
@@ -220,6 +276,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)
@@ -232,6 +289,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)
@@ -250,6 +308,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 const TypeInfo hexagon_machine_types[] = {
@@ -263,6 +322,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 0bbca236659..1cbf8cd391a 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -320,7 +320,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
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 13/14] target/hexagon: fix the allocframe framekey
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (11 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 12/14] hw/hexagon: add subsystem-base property Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 5:52 ` [PATCH 14/14] tests/functional/hexagon: boot DSP firmware Brian Cain
13 siblings, 0 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
The frame that allocframe pushes is {LR, FP}, and what is scrambled is
the LR word: FRAMEKEY is XOR'd into the upper 32 bits. The generated
code for fFRAME_SCRAMBLE built the key from FRAMEKEY in both halves of
a 64-bit value, so it scrambled FP as well. deallocframe and
dealloc_return only undo the upper word, so a FP restored from a frame
pushed with a non-zero FRAMEKEY was corrupt.
Uncovered by testing some boot images using QuRT.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/idef-parser/parser-helpers.c | 2 +-
tests/tcg/hexagon/framekey.c | 67 +++++++++++++++++++++
tests/tcg/hexagon/meson.build | 1 +
3 files changed, 69 insertions(+), 1 deletion(-)
create mode 100644 tests/tcg/hexagon/framekey.c
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
index 49cc11fddd8..14840d98737 100644
--- a/target/hexagon/idef-parser/parser-helpers.c
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -1989,7 +1989,7 @@ HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value)
*value = gen_rvalue_extend(c, locp, value);
OUT(c, locp, "gen_read_reg(", &frame_key, ", HEX_REG_FRAMEKEY);\n");
OUT(c, locp, "tcg_gen_concat_i32_i64(",
- &key, ", ", &frame_key, ", ", &frame_key, ");\n");
+ &key, ", tcg_constant_tl(0), ", &frame_key, ");\n");
OUT(c, locp, "tcg_gen_xor_i64(", &res, ", ", value, ", ", &key, ");\n");
return res;
}
diff --git a/tests/tcg/hexagon/framekey.c b/tests/tcg/hexagon/framekey.c
new file mode 100644
index 00000000000..5d579293477
--- /dev/null
+++ b/tests/tcg/hexagon/framekey.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright(c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+int err;
+
+#include "hex_test.h"
+
+/*
+ * allocframe pushes {LR, FP}, scrambling LR with FRAMEKEY, and deallocframe
+ * restores them. Push a frame and return the words that were stored, FP
+ * through the return value and LR through @lr_stored, and the FP and LR
+ * that deallocframe restores.
+ */
+static inline uint32_t frame_roundtrip(uint32_t key, uint32_t fp,
+ uint32_t lr, uint32_t *lr_stored,
+ uint32_t *fp_back, uint32_t *lr_back)
+{
+ uint32_t fp_stored, saved_fp, saved_lr;
+
+ asm volatile("%[saved_fp] = r30\n\t"
+ "%[saved_lr] = r31\n\t"
+ "framekey = %[key]\n\t"
+ "r30 = %[fp]\n\t"
+ "r31 = %[lr]\n\t"
+ "allocframe(#0)\n\t"
+ "%[fp_stored] = memw(r30)\n\t"
+ "%[lr_stored] = memw(r30 + #4)\n\t"
+ "r31 = #0\n\t"
+ "deallocframe\n\t"
+ "%[fp_back] = r30\n\t"
+ "%[lr_back] = r31\n\t"
+ "framekey = %[zero]\n\t"
+ "r30 = %[saved_fp]\n\t"
+ "r31 = %[saved_lr]\n"
+ : [fp_stored] "=&r"(fp_stored), [lr_stored] "=&r"(*lr_stored),
+ [fp_back] "=&r"(*fp_back), [lr_back] "=&r"(*lr_back),
+ [saved_fp] "=&r"(saved_fp), [saved_lr] "=&r"(saved_lr)
+ : [key] "r"(key), [fp] "r"(fp), [lr] "r"(lr), [zero] "r"(0)
+ : "memory", "framekey");
+ return fp_stored;
+}
+
+static void check_frame(uint32_t key, uint32_t fp, uint32_t lr)
+{
+ uint32_t lr_stored, fp_back, lr_back;
+
+ /* Only LR is scrambled, FP is stored as is */
+ check32(frame_roundtrip(key, fp, lr, &lr_stored, &fp_back, &lr_back), fp);
+ check32(lr_stored, lr ^ key);
+ check32(fp_back, fp);
+ check32(lr_back, lr);
+}
+
+int main()
+{
+ check_frame(0, 0x1234fff0, 0x5678abcc);
+ check_frame(0xf21f20a0, 0x1234fff0, 0x5678abcc);
+
+ puts(err ? "FAIL" : "PASS");
+ return err;
+}
diff --git a/tests/tcg/hexagon/meson.build b/tests/tcg/hexagon/meson.build
index a6ace4c77c2..0fd62ce7e4c 100644
--- a/tests/tcg/hexagon/meson.build
+++ b/tests/tcg/hexagon/meson.build
@@ -68,6 +68,7 @@ tests += {
'overflow.c': {'cflags': cflags, 'exe_name': 'hex-overflow'},
'preg_alias.c': {'cflags': cflags},
'dual_stores.c': {'cflags': cflags},
+ 'framekey.c': {'cflags': cflags},
'multi_result.c': {'cflags': cflags},
'mem_noshuf.c': {'cflags': cflags},
'mem_noshuf_exception.c': {'cflags': cflags},
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 14/14] tests/functional/hexagon: boot DSP firmware
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
` (12 preceding siblings ...)
2026-10-19 5:52 ` [PATCH 13/14] target/hexagon: fix the allocframe framekey Brian Cain
@ 2026-10-19 5:52 ` Brian Cain
2026-10-19 13:47 ` Philippe Mathieu-Daudé
13 siblings, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 5:52 UTC (permalink / raw)
To: qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Philippe Mathieu-Daudé,
Alessandro Di Federico, Brian Cain, Paolo Bonzini, Laurent Vivier
Download the firmware and run it on the corresponding DSP machine.
The images are third-party binaries, so the tests run only when untrusted
code is allowed.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
tests/functional/hexagon/meson.build | 2 +
.../hexagon/test_qcom_dsp_firmware.py | 89 +++++++++++++++++++
2 files changed, 91 insertions(+)
create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
index e182bc98a06..0fd90e491a2 100644
--- a/tests/functional/hexagon/meson.build
+++ b/tests/functional/hexagon/meson.build
@@ -2,10 +2,12 @@
tests_hexagon_system_thorough = [
'arch_tests',
+ 'qcom_dsp_firmware',
'systests',
'minivm',
]
test_hexagon_timeouts = {
+ 'qcom_dsp_firmware': 240,
'systests': 180,
}
diff --git a/tests/functional/hexagon/test_qcom_dsp_firmware.py b/tests/functional/hexagon/test_qcom_dsp_firmware.py
new file mode 100755
index 00000000000..86a0628d9f3
--- /dev/null
+++ b/tests/functional/hexagon/test_qcom_dsp_firmware.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+#
+# Boot the production DSP firmware on the Qualcomm DSP machines
+#
+# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
+from qemu_test import wait_for_console_pattern
+
+
+class QcomDspFirmwareTest(QemuSystemTest):
+ """Base class: the firmware is the ELF that -kernel starts running."""
+
+ REPO = 'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/' \
+ 'd947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom'
+ MACHINE = None
+ ASSET = None
+ MILESTONE = 'Entering main() ...'
+
+ def boot_firmware(self):
+ self.set_machine(self.MACHINE)
+ firmware = self.ASSET.fetch()
+
+ self.vm.set_console(semihosting=True)
+ self.vm.add_args('-kernel', firmware)
+ self.vm.launch()
+ wait_for_console_pattern(self, 'QURT kernel started',
+ failure_message='Fatal Error')
+ wait_for_console_pattern(self, self.MILESTONE,
+ failure_message='Fatal Error')
+ self.vm.kill()
+
+
+@skipUntrustedTest()
+class Qcs6490CdspFirmwareTest(QcomDspFirmwareTest):
+ MACHINE = 'qcs6490-cdsp'
+
+ ASSET = Asset(f'{QcomDspFirmwareTest.REPO}/qcm6490/cdsp.mbn',
+ '43e9c89e15ee82daf83214cae34006a8515fddf9db7f645f5eff4b8e3c4ebb64')
+
+ def test_qcs6490_cdsp_firmware(self):
+ self.boot_firmware()
+
+
+@skipUntrustedTest()
+class Sa8775pCdspFirmwareTest(QcomDspFirmwareTest):
+ MACHINE = 'sa8775p-cdsp'
+ ASSET = Asset(f'{QcomDspFirmwareTest.REPO}/sa8775p/cdsp0.mbn',
+ '1d9d8cd1e913b0d3b49a77b4e962564ab481193e6a5697c8f06406b3fd85a8fc')
+
+ def test_sa8775p_cdsp_firmware(self):
+ self.boot_firmware()
+
+
+@skipUntrustedTest()
+class Sc8480xpNsp0FirmwareTest(QcomDspFirmwareTest):
+ MACHINE = 'sc8480xp-nsp0'
+ ASSET = Asset(f'{QcomDspFirmwareTest.REPO}/glymur/cdsp.mbn',
+ '7b22f33ae273d3dfc5f741a967831e7d4fd79ad141e6a1ecee17509eac207109')
+
+ def test_sc8480xp_nsp0_firmware(self):
+ self.boot_firmware()
+
+
+@skipUntrustedTest()
+class Sa8797pNsp0FirmwareTest(QcomDspFirmwareTest):
+ MACHINE = 'sa8797p-nsp0'
+ ASSET = Asset(f'{QcomDspFirmwareTest.REPO}/nord/cdsp.mbn',
+ '410e7ca3b340e80835e464545a218d9376310a09f24bc87de40bc25f7f5e3240')
+
+ def test_sa8797p_nsp0_firmware(self):
+ self.boot_firmware()
+
+
+@skipUntrustedTest()
+class Sm8975NspFirmwareTest(QcomDspFirmwareTest):
+ MACHINE = 'sm8975-nsp'
+ MILESTONE = 'QURT root task started'
+ ASSET = Asset(f'{QcomDspFirmwareTest.REPO}/hawi/cdsp.mbn',
+ '7373952413c141fc636aa933ab0c71e7be1d10f5f7dd36be5374827b253c3db5')
+
+ def test_sm8975_nsp_firmware(self):
+ self.boot_firmware()
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
--
2.34.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH 14/14] tests/functional/hexagon: boot DSP firmware
2026-10-19 5:52 ` [PATCH 14/14] tests/functional/hexagon: boot DSP firmware Brian Cain
@ 2026-10-19 13:47 ` Philippe Mathieu-Daudé
2026-10-19 13:51 ` Brian Cain
2026-10-19 21:50 ` Pierrick Bouvier
0 siblings, 2 replies; 35+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-19 13:47 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Alessandro Di Federico, Paolo Bonzini,
Laurent Vivier
On 19/10/26 07:52, Brian Cain wrote:
> Download the firmware and run it on the corresponding DSP machine.
>
> The images are third-party binaries, so the tests run only when untrusted
> code is allowed.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> tests/functional/hexagon/meson.build | 2 +
> .../hexagon/test_qcom_dsp_firmware.py | 89 +++++++++++++++++++
> 2 files changed, 91 insertions(+)
> create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
> diff --git a/tests/functional/hexagon/test_qcom_dsp_firmware.py b/tests/functional/hexagon/test_qcom_dsp_firmware.py
> new file mode 100755
> index 00000000000..86a0628d9f3
> --- /dev/null
> +++ b/tests/functional/hexagon/test_qcom_dsp_firmware.py
> @@ -0,0 +1,89 @@
> +#!/usr/bin/env python3
> +#
> +# Boot the production DSP firmware on the Qualcomm DSP machines
> +#
> +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> +#
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
> +from qemu_test import wait_for_console_pattern
> +
> +
> +class QcomDspFirmwareTest(QemuSystemTest):
> + """Base class: the firmware is the ELF that -kernel starts running."""
> +
> + REPO = 'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/' \
> + 'd947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom'
404: Page not found
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 14/14] tests/functional/hexagon: boot DSP firmware
2026-10-19 13:47 ` Philippe Mathieu-Daudé
@ 2026-10-19 13:51 ` Brian Cain
2026-10-19 15:22 ` Brian Cain
2026-10-19 21:50 ` Pierrick Bouvier
1 sibling, 1 reply; 35+ messages in thread
From: Brian Cain @ 2026-10-19 13:51 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Alessandro Di Federico, Paolo Bonzini,
Laurent Vivier
On 10/19/2026 8:47 AM, Philippe Mathieu-Daudé wrote:
> On 19/10/26 07:52, Brian Cain wrote:
>> Download the firmware and run it on the corresponding DSP machine.
>>
>> The images are third-party binaries, so the tests run only when
>> untrusted
>> code is allowed.
>>
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>> tests/functional/hexagon/meson.build | 2 +
>> .../hexagon/test_qcom_dsp_firmware.py | 89 +++++++++++++++++++
>> 2 files changed, 91 insertions(+)
>> create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
>
>
>> diff --git a/tests/functional/hexagon/test_qcom_dsp_firmware.py
>> b/tests/functional/hexagon/test_qcom_dsp_firmware.py
>> new file mode 100755
>> index 00000000000..86a0628d9f3
>> --- /dev/null
>> +++ b/tests/functional/hexagon/test_qcom_dsp_firmware.py
>> @@ -0,0 +1,89 @@
>> +#!/usr/bin/env python3
>> +#
>> +# Boot the production DSP firmware on the Qualcomm DSP machines
>> +#
>> +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> +#
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
>> +from qemu_test import wait_for_console_pattern
>> +
>> +
>> +class QcomDspFirmwareTest(QemuSystemTest):
>> + """Base class: the firmware is the ELF that -kernel starts
>> running."""
>> +
>> + REPO = 'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/' \
>> + 'd947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom'
>
> 404: Page not found
Huh. Maybe I picked a funny commit and somehow the asset cache fooled
me? Will take a closer look.
-Brian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 14/14] tests/functional/hexagon: boot DSP firmware
2026-10-19 13:51 ` Brian Cain
@ 2026-10-19 15:22 ` Brian Cain
0 siblings, 0 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 15:22 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Laurent Vivier, Helge Deller, Pierrick Bouvier, Fabiano Rosas,
Anton Johansson, Alessandro Di Federico, Paolo Bonzini,
Laurent Vivier
On 10/19/2026 8:51 AM, Brian Cain wrote:
>
> On 10/19/2026 8:47 AM, Philippe Mathieu-Daudé wrote:
>> On 19/10/26 07:52, Brian Cain wrote:
>>> Download the firmware and run it on the corresponding DSP machine.
>>>
>>> The images are third-party binaries, so the tests run only when
>>> untrusted
>>> code is allowed.
>>>
>>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>>> ---
>>> tests/functional/hexagon/meson.build | 2 +
>>> .../hexagon/test_qcom_dsp_firmware.py | 89
>>> +++++++++++++++++++
>>> 2 files changed, 91 insertions(+)
>>> create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
>>
>>
>>> diff --git a/tests/functional/hexagon/test_qcom_dsp_firmware.py
>>> b/tests/functional/hexagon/test_qcom_dsp_firmware.py
>>> new file mode 100755
>>> index 00000000000..86a0628d9f3
>>> --- /dev/null
>>> +++ b/tests/functional/hexagon/test_qcom_dsp_firmware.py
>>> @@ -0,0 +1,89 @@
>>> +#!/usr/bin/env python3
>>> +#
>>> +# Boot the production DSP firmware on the Qualcomm DSP machines
>>> +#
>>> +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>>> +#
>>> +# SPDX-License-Identifier: GPL-2.0-or-later
>>> +
>>> +from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
>>> +from qemu_test import wait_for_console_pattern
>>> +
>>> +
>>> +class QcomDspFirmwareTest(QemuSystemTest):
>>> + """Base class: the firmware is the ELF that -kernel starts
>>> running."""
>>> +
>>> + REPO =
>>> 'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/' \
>>> + 'd947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom'
>>
>> 404: Page not found
>
>
> Huh. Maybe I picked a funny commit and somehow the asset cache fooled
> me? Will take a closer look.
Disregard: all is well. A "wget" of one of these assets works for me.
If I paste the URL into chrome, it downloads the asset.
But if I browse
to https://gitlab.com/kernel-firmware/linux-firmware/-/raw/d947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom
I do get a 404. I think this is the expected behavior, though. That
"raw" mode for the URL expects a path to a file object that git could
serve up.
If you browse
to https://gitlab.com/kernel-firmware/linux-firmware/-/tree/d947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom
you can see the directory listing that you might have expected. If you
apply these changes to master I would expect `check-functional` will
download and run them (w/the untrusted code bit set).
The sha in the URL is inconvenient and unclear so in v2 I will switch to
a recent tag instead.
>
>
> -Brian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 02/14] hw/hexagon: let a machine place its DDR
2026-10-19 5:52 ` [PATCH 02/14] hw/hexagon: let a machine place its DDR Brian Cain
@ 2026-10-19 21:40 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 21:40 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> hex_subsys_create() always maps the main DDR at address 0. This is appropriate
> for hexagon-sim-style machines, but real SoCs map it elsewhere.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/hw/hexagon/hexagon.h | 2 ++
> hw/hexagon/hex-subsys.c | 4 ++--
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 04/14] hw/hexagon: convert virt board to hex-board
2026-10-19 5:52 ` [PATCH 04/14] hw/hexagon: convert virt board to hex-board Brian Cain
@ 2026-10-19 21:40 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 21:40 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Build the virt machine with the hex-board helpers instead of its own
> copies, and drop the machine state that nothing used. The machine, its
> device tree and its devices are unchanged; virt writes interrupts as the
> bare line number.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/hw/hexagon/virt.h | 6 -
> hw/hexagon/virt.c | 309 ++++----------------------------------
> 2 files changed, 26 insertions(+), 289 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 03/14] hw/hexagon: introduce hex-board abstraction
2026-10-19 5:52 ` [PATCH 03/14] hw/hexagon: introduce hex-board abstraction Brian Cain
@ 2026-10-19 21:42 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 21:42 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Move what virt.c does to build a board out of it into helpers in a new
> hex-board.c, so that other Hexagon machines that describe themselves
> with a generated device tree can reuse it.
>
> This will be used by future commits.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> MAINTAINERS | 2 +
> include/hw/hexagon/hex-board.h | 65 ++++++++
> hw/hexagon/hex-board.c | 265 +++++++++++++++++++++++++++++++++
> hw/hexagon/Kconfig | 9 +-
> hw/hexagon/meson.build | 1 +
> 5 files changed, 340 insertions(+), 2 deletions(-)
> create mode 100644 include/hw/hexagon/hex-board.h
> create mode 100644 hw/hexagon/hex-board.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 14/14] tests/functional/hexagon: boot DSP firmware
2026-10-19 13:47 ` Philippe Mathieu-Daudé
2026-10-19 13:51 ` Brian Cain
@ 2026-10-19 21:50 ` Pierrick Bouvier
2026-10-19 22:03 ` Brian Cain
1 sibling, 1 reply; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 21:50 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Alessandro Di Federico, Paolo Bonzini, Laurent Vivier
On 10/19/2026 6:47 AM, Philippe Mathieu-Daudé wrote:
> On 19/10/26 07:52, Brian Cain wrote:
>> Download the firmware and run it on the corresponding DSP machine.
>>
>> The images are third-party binaries, so the tests run only when untrusted
>> code is allowed.
>>
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>> tests/functional/hexagon/meson.build | 2 +
>> .../hexagon/test_qcom_dsp_firmware.py | 89 +++++++++++++++++++
>> 2 files changed, 91 insertions(+)
>> create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
>
>
>> diff --git a/tests/functional/hexagon/test_qcom_dsp_firmware.py b/
>> tests/functional/hexagon/test_qcom_dsp_firmware.py
>> new file mode 100755
>> index 00000000000..86a0628d9f3
>> --- /dev/null
>> +++ b/tests/functional/hexagon/test_qcom_dsp_firmware.py
>> @@ -0,0 +1,89 @@
>> +#!/usr/bin/env python3
>> +#
>> +# Boot the production DSP firmware on the Qualcomm DSP machines
>> +#
>> +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> +#
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
>> +from qemu_test import wait_for_console_pattern
>> +
>> +
>> +class QcomDspFirmwareTest(QemuSystemTest):
>> + """Base class: the firmware is the ELF that -kernel starts
>> running."""
>> +
>> + REPO = 'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/' \
>> + 'd947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom'
>
> 404: Page not found
This URL is incomplete at this point, it's just a folder and not the
final file. When concatenating sub paths, like "qcm6490/cdsp.mbn" it
works fine.
It's confusing to our (qemu functional tests) mind since we are blindly
used to see the assets full URL here, instead of it being set in each
subtest.
@Brian: To follow the existing convention, I would recommend to
duplicate full URL between assets following something what is done in:
tests/functional/aarch64/test_aspeed_ast2700a2.py
It's a bit "Do repeat yourself", but at least it's not surprising.
It has also the advantage to be easier to replace url if files are moved
at any point.
Regards,
Pierrick
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 05/14] hw/misc: add the QDSP6SS PLL, RCG
2026-10-19 5:52 ` [PATCH 05/14] hw/misc: add the QDSP6SS PLL, RCG Brian Cain
@ 2026-10-19 21:51 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 21:51 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Firmware brings a Hexagon DSP's clocks up by programming a PLL and polling
> its lock-detect. Then it asks the RCG to switch to the new clock.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> MAINTAINERS | 2 +
> include/hw/misc/qcom-qdsp6ss-clk.h | 15 +++
> hw/misc/qcom-qdsp6ss-clk.c | 208 +++++++++++++++++++++++++++++
> hw/misc/Kconfig | 3 +
> hw/misc/meson.build | 3 +
> 5 files changed, 231 insertions(+)
> create mode 100644 include/hw/misc/qcom-qdsp6ss-clk.h
> create mode 100644 hw/misc/qcom-qdsp6ss-clk.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 14/14] tests/functional/hexagon: boot DSP firmware
2026-10-19 21:50 ` Pierrick Bouvier
@ 2026-10-19 22:03 ` Brian Cain
0 siblings, 0 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 22:03 UTC (permalink / raw)
To: Pierrick Bouvier, Philippe Mathieu-Daudé, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Alessandro Di Federico, Paolo Bonzini, Laurent Vivier
On 10/19/2026 4:50 PM, Pierrick Bouvier wrote:
> On 10/19/2026 6:47 AM, Philippe Mathieu-Daudé wrote:
>> On 19/10/26 07:52, Brian Cain wrote:
>>> Download the firmware and run it on the corresponding DSP machine.
>>>
>>> The images are third-party binaries, so the tests run only when untrusted
>>> code is allowed.
>>>
>>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>>> ---
>>> tests/functional/hexagon/meson.build | 2 +
>>> .../hexagon/test_qcom_dsp_firmware.py | 89 +++++++++++++++++++
>>> 2 files changed, 91 insertions(+)
>>> create mode 100755 tests/functional/hexagon/test_qcom_dsp_firmware.py
>>
>>> diff --git a/tests/functional/hexagon/test_qcom_dsp_firmware.py b/
>>> tests/functional/hexagon/test_qcom_dsp_firmware.py
>>> new file mode 100755
>>> index 00000000000..86a0628d9f3
>>> --- /dev/null
>>> +++ b/tests/functional/hexagon/test_qcom_dsp_firmware.py
>>> @@ -0,0 +1,89 @@
>>> +#!/usr/bin/env python3
>>> +#
>>> +# Boot the production DSP firmware on the Qualcomm DSP machines
>>> +#
>>> +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>>> +#
>>> +# SPDX-License-Identifier: GPL-2.0-or-later
>>> +
>>> +from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
>>> +from qemu_test import wait_for_console_pattern
>>> +
>>> +
>>> +class QcomDspFirmwareTest(QemuSystemTest):
>>> + """Base class: the firmware is the ELF that -kernel starts
>>> running."""
>>> +
>>> + REPO = 'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/' \
>>> + 'd947e4e8e314e9254a1242dc1a5d9cede2cce33d/qcom'
>> 404: Page not found
> This URL is incomplete at this point, it's just a folder and not the
> final file. When concatenating sub paths, like "qcm6490/cdsp.mbn" it
> works fine.
>
> It's confusing to our (qemu functional tests) mind since we are blindly
> used to see the assets full URL here, instead of it being set in each
> subtest.
>
> @Brian: To follow the existing convention, I would recommend to
> duplicate full URL between assets following something what is done in:
> tests/functional/aarch64/test_aspeed_ast2700a2.py
Ok, will do.
> It's a bit "Do repeat yourself", but at least it's not surprising.
> It has also the advantage to be easier to replace url if files are moved
> at any point.
>
> Regards,
> Pierrick
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine
2026-10-19 5:52 ` [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine Brian Cain
@ 2026-10-19 22:15 ` Pierrick Bouvier
2026-10-20 11:28 ` Anton Johansson via qemu development
1 sibling, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:15 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> MAINTAINERS | 1 +
> include/hw/hexagon/hexagon.h | 1 +
> include/hw/hexagon/qcom_dsp.h | 81 +++++
> hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc | 65 ++++
> hw/hexagon/qcom_dsp.c | 399 ++++++++++++++++++++++
> hw/hexagon/qcs6490_cdsp.c | 64 ++++
> tests/qtest/l2vic-test.c | 2 +
> tests/qtest/qcom-dsp-test.c | 93 +++++
> tests/qtest/qct-qtimer-test.c | 2 +
> hw/hexagon/Kconfig | 15 +
> hw/hexagon/meson.build | 2 +
> tests/qtest/meson.build | 3 +-
> 12 files changed, 727 insertions(+), 1 deletion(-)
> create mode 100644 include/hw/hexagon/qcom_dsp.h
> create mode 100644 hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
> create mode 100644 hw/hexagon/qcom_dsp.c
> create mode 100644 hw/hexagon/qcs6490_cdsp.c
> create mode 100644 tests/qtest/qcom-dsp-test.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 07/14] hw/hexagon: add the SA8775P CDSP machine
2026-10-19 5:52 ` [PATCH 07/14] hw/hexagon: add the SA8775P " Brian Cain
@ 2026-10-19 22:15 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:15 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc | 6 ++-
> hw/hexagon/sa8775p_cdsp.c | 59 +++++++++++++++++++++++
> tests/qtest/l2vic-test.c | 2 +
> tests/qtest/qcom-dsp-test.c | 1 +
> tests/qtest/qct-qtimer-test.c | 2 +
> hw/hexagon/Kconfig | 6 +++
> hw/hexagon/meson.build | 1 +
> 7 files changed, 76 insertions(+), 1 deletion(-)
> create mode 100644 hw/hexagon/sa8775p_cdsp.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/14] hw/hexagon: add the SC8480XP NSP0 machine
2026-10-19 5:52 ` [PATCH 08/14] hw/hexagon: add the SC8480XP NSP0 machine Brian Cain
@ 2026-10-19 22:15 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:15 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/hw/hexagon/hexagon.h | 1 +
> hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc | 52 +++++++++++++
> hw/hexagon/sc8480xp_nsp0.c | 90 ++++++++++++++++++++++
> tests/qtest/l2vic-test.c | 2 +
> tests/qtest/qcom-dsp-test.c | 1 +
> tests/qtest/qct-qtimer-test.c | 2 +
> hw/hexagon/Kconfig | 6 ++
> hw/hexagon/meson.build | 1 +
> 8 files changed, 155 insertions(+)
> create mode 100644 hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc
> create mode 100644 hw/hexagon/sc8480xp_nsp0.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 09/14] hw/hexagon: add the SA8797P NSP0 machine
2026-10-19 5:52 ` [PATCH 09/14] hw/hexagon: add the SA8797P " Brian Cain
@ 2026-10-19 22:15 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:15 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc | 56 +++++++++++++++++++
> hw/hexagon/sa8797p_nsp0.c | 68 +++++++++++++++++++++++
> tests/qtest/l2vic-test.c | 2 +
> tests/qtest/qcom-dsp-test.c | 1 +
> tests/qtest/qct-qtimer-test.c | 2 +
> hw/hexagon/Kconfig | 6 ++
> hw/hexagon/meson.build | 1 +
> 7 files changed, 136 insertions(+)
> create mode 100644 hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc
> create mode 100644 hw/hexagon/sa8797p_nsp0.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 10/14] hw/hexagon: add the SM8975 NSP machine
2026-10-19 5:52 ` [PATCH 10/14] hw/hexagon: add the SM8975 NSP machine Brian Cain
@ 2026-10-19 22:15 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:15 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/hw/hexagon/hexagon.h | 1 +
> hw/hexagon/machine_cfg_sm8975_nsp.h.inc | 55 +++++++++++++
> hw/hexagon/sm8975_nsp.c | 102 ++++++++++++++++++++++++
> tests/qtest/l2vic-test.c | 2 +
> tests/qtest/qcom-dsp-test.c | 17 ++++
> tests/qtest/qct-qtimer-test.c | 2 +
> hw/hexagon/Kconfig | 6 ++
> hw/hexagon/meson.build | 1 +
> 8 files changed, 186 insertions(+)
> create mode 100644 hw/hexagon/machine_cfg_sm8975_nsp.h.inc
> create mode 100644 hw/hexagon/sm8975_nsp.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 11/14] hw/hexagon: add v79NA1 machine
2026-10-19 5:52 ` [PATCH 11/14] hw/hexagon: add v79NA1 machine Brian Cain
@ 2026-10-19 22:16 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:16 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> Add the Hexagon V79NA_1 simulator machine, with the config table of the
> v79 core and eight CPUs by default.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/hw/hexagon/hexagon.h | 1 +
> hw/hexagon/machine_cfg_v79na_1.h.inc | 34 ++++++++++++++++++++++++++++
> hw/hexagon/hexagon_dsp.c | 22 ++++++++++++++++++
> 3 files changed, 57 insertions(+)
> create mode 100644 hw/hexagon/machine_cfg_v79na_1.h.inc
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 12/14] hw/hexagon: add subsystem-base property
2026-10-19 5:52 ` [PATCH 12/14] hw/hexagon: add subsystem-base property Brian Cain
@ 2026-10-19 22:16 ` Pierrick Bouvier
2026-10-20 14:53 ` Anton Johansson via qemu development
1 sibling, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2026-10-19 22:16 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: Laurent Vivier, Helge Deller, Fabiano Rosas, Anton Johansson,
Philippe Mathieu-Daudé, Alessandro Di Federico,
Paolo Bonzini, Laurent Vivier
On 10/18/2026 10:52 PM, Brian Cain wrote:
> 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.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> MAINTAINERS | 1 +
> include/hw/hexagon/hexagon.h | 4 ++
> hw/hexagon/hexagon_dsp.c | 62 +++++++++++++++++++++++-
> tests/qtest/hexagon-config-test.c | 78 +++++++++++++++++++++++++++++++
> tests/qtest/meson.build | 3 +-
> 5 files changed, 146 insertions(+), 2 deletions(-)
> create mode 100644 tests/qtest/hexagon-config-test.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 01/14] Hexagon: add v85 CPU model
2026-10-19 5:52 ` [PATCH 01/14] Hexagon: add v85 CPU model Brian Cain
@ 2026-10-19 22:32 ` Anton Johansson via qemu development
2026-10-19 23:58 ` Brian Cain
0 siblings, 1 reply; 35+ messages in thread
From: Anton Johansson via qemu development @ 2026-10-19 22:32 UTC (permalink / raw)
To: Brian Cain
Cc: qemu-devel, Laurent Vivier, Helge Deller, Pierrick Bouvier,
Fabiano Rosas, Philippe Mathieu-Daudé,
Alessandro Di Federico, Paolo Bonzini, Laurent Vivier
On 19/10/26, Brian Cain wrote:
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> docs/system/hexagon/emulation.rst | 2 +-
> target/hexagon/cpu-qom.h | 4 ++++
> linux-user/hexagon/elfload.c | 4 ++++
> target/hexagon/cpu.c | 2 ++
> 4 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/docs/system/hexagon/emulation.rst b/docs/system/hexagon/emulation.rst
> index 12385311aa4..fb57c77ae90 100644
> --- a/docs/system/hexagon/emulation.rst
> +++ b/docs/system/hexagon/emulation.rst
> @@ -6,7 +6,7 @@ Hexagon CPU architecture support
> ================================
>
> QEMU's TCG emulation includes support for v65, v66, v67, v68, v69, v71, v73,
> -v75, v77, v79, v81.
> +v75, v77, v79, v81, v83, v85.
> It also has support for the following architecture extensions:
>
> - HVX (Hexagon Vector eXtensions)
> diff --git a/target/hexagon/cpu-qom.h b/target/hexagon/cpu-qom.h
> index 2bfa4d5d0fc..d4c8413ded3 100644
> --- a/target/hexagon/cpu-qom.h
> +++ b/target/hexagon/cpu-qom.h
> @@ -28,6 +28,8 @@ typedef enum {
> HEX_VER_V75 = 0x75,
> HEX_VER_V79 = 0x79,
> HEX_VER_V81 = 0x81,
> + HEX_VER_V83 = 0x83,
> + HEX_VER_V85 = 0x85,
> HEX_VER_ANY = 0xff,
> } HexagonVersion;
I think you missed adding HEX_VER_V85 to get_elf_hwcap(), currently it
would take the default case and return 0.
Otherwise,
Reviewed-by: Anton Johansson <anjo@rev.ng>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 01/14] Hexagon: add v85 CPU model
2026-10-19 22:32 ` Anton Johansson via qemu development
@ 2026-10-19 23:58 ` Brian Cain
0 siblings, 0 replies; 35+ messages in thread
From: Brian Cain @ 2026-10-19 23:58 UTC (permalink / raw)
To: Anton Johansson
Cc: qemu-devel, Laurent Vivier, Helge Deller, Pierrick Bouvier,
Fabiano Rosas, Philippe Mathieu-Daudé,
Alessandro Di Federico, Paolo Bonzini, Laurent Vivier
On 10/19/2026 5:32 PM, Anton Johansson wrote:
> On 19/10/26, Brian Cain wrote:
>> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>> docs/system/hexagon/emulation.rst | 2 +-
>> target/hexagon/cpu-qom.h | 4 ++++
>> linux-user/hexagon/elfload.c | 4 ++++
>> target/hexagon/cpu.c | 2 ++
>> 4 files changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/docs/system/hexagon/emulation.rst b/docs/system/hexagon/emulation.rst
>> index 12385311aa4..fb57c77ae90 100644
>> --- a/docs/system/hexagon/emulation.rst
>> +++ b/docs/system/hexagon/emulation.rst
>> @@ -6,7 +6,7 @@ Hexagon CPU architecture support
>> ================================
>>
>> QEMU's TCG emulation includes support for v65, v66, v67, v68, v69, v71, v73,
>> -v75, v77, v79, v81.
>> +v75, v77, v79, v81, v83, v85.
>> It also has support for the following architecture extensions:
>>
>> - HVX (Hexagon Vector eXtensions)
>> diff --git a/target/hexagon/cpu-qom.h b/target/hexagon/cpu-qom.h
>> index 2bfa4d5d0fc..d4c8413ded3 100644
>> --- a/target/hexagon/cpu-qom.h
>> +++ b/target/hexagon/cpu-qom.h
>> @@ -28,6 +28,8 @@ typedef enum {
>> HEX_VER_V75 = 0x75,
>> HEX_VER_V79 = 0x79,
>> HEX_VER_V81 = 0x81,
>> + HEX_VER_V83 = 0x83,
>> + HEX_VER_V85 = 0x85,
>> HEX_VER_ANY = 0xff,
>> } HexagonVersion;
> I think you missed adding HEX_VER_V85 to get_elf_hwcap(), currently it
> would take the default case and return 0.
Thanks! I borrowed this patch from another series so that these two
mostly-independent ones could be reviewed separately. In that one, I
did include the get_elf_hwcap() update.
See https://lore.kernel.org/qemu-devel/20261019172603.2625677-5-brian.cain@oss.qualcomm.com/
> Otherwise,
>
> Reviewed-by: Anton Johansson <anjo@rev.ng>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine
2026-10-19 5:52 ` [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
@ 2026-10-20 11:28 ` Anton Johansson via qemu development
1 sibling, 0 replies; 35+ messages in thread
From: Anton Johansson via qemu development @ 2026-10-20 11:28 UTC (permalink / raw)
To: Brian Cain
Cc: qemu-devel, Laurent Vivier, Helge Deller, Pierrick Bouvier,
Fabiano Rosas, Philippe Mathieu-Daudé,
Alessandro Di Federico, Paolo Bonzini, Laurent Vivier
On 19/10/26, Brian Cain wrote:
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> MAINTAINERS | 1 +
> include/hw/hexagon/hexagon.h | 1 +
> include/hw/hexagon/qcom_dsp.h | 81 +++++
> hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc | 65 ++++
> hw/hexagon/qcom_dsp.c | 399 ++++++++++++++++++++++
> hw/hexagon/qcs6490_cdsp.c | 64 ++++
> tests/qtest/l2vic-test.c | 2 +
> tests/qtest/qcom-dsp-test.c | 93 +++++
> tests/qtest/qct-qtimer-test.c | 2 +
> hw/hexagon/Kconfig | 15 +
> hw/hexagon/meson.build | 2 +
> tests/qtest/meson.build | 3 +-
> 12 files changed, 727 insertions(+), 1 deletion(-)
> create mode 100644 include/hw/hexagon/qcom_dsp.h
> create mode 100644 hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
> create mode 100644 hw/hexagon/qcom_dsp.c
> create mode 100644 hw/hexagon/qcs6490_cdsp.c
> create mode 100644 tests/qtest/qcom-dsp-test.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ef619991b4b..04df9db77dc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1386,6 +1386,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/qcom-dsp-test.c
> F: docs/devel/hexagon-sys.rst
>
> LoongArch Machines
> diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
> index 6955e600aee..1d0d55ea938 100644
> --- a/include/hw/hexagon/hexagon.h
> +++ b/include/hw/hexagon/hexagon.h
> @@ -23,6 +23,7 @@ typedef enum {
> v66_rev = 0xa666,
> v67_rev = 0x2667,
> v68_rev = 0x8d68,
> + v68_qcs6490_rev = 0x8a68,
> v69_rev = 0x8c69,
> v71_rev = 0x8c71,
> v73_rev = 0x8c73,
> diff --git a/include/hw/hexagon/qcom_dsp.h b/include/hw/hexagon/qcom_dsp.h
> new file mode 100644
> index 00000000000..d127b0b0b10
> --- /dev/null
> +++ b/include/hw/hexagon/qcom_dsp.h
> @@ -0,0 +1,81 @@
> +/*
> + * Qualcomm DSP subsystem machines: the board layer shared by the SoC models.
> + *
> + * Each SoC provides a QcomDspMachineInfo describing its subsystem, and the
> + * layer supplies what every one of them has in common: the CPUs, a QEMU-only
> + * PL011 console, virtio-mmio slots, a generated device tree, and the
> + * -bios/-kernel/-initrd boot flow.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HW_HEXAGON_QCOM_DSP_H
> +#define HW_HEXAGON_QCOM_DSP_H
> +
> +#include "hw/hexagon/hexagon.h"
> +#include "qom/object.h"
> +
> +#define TYPE_QCOM_DSP_MACHINE MACHINE_TYPE_NAME("qcom-dsp")
> +OBJECT_DECLARE_TYPE(QcomDspMachineState, QcomDspMachineClass, QCOM_DSP_MACHINE)
> +
> +/* Number of virtio-mmio transports every machine provides. */
> +#define QCOM_DSP_VIRTIO_COUNT 8
> +
> +typedef struct QcomDspMachineInfo {
> + const char *desc;
> + const char *cpu_type;
> + unsigned int cpus;
> + Rev_t rev;
> + const struct hexagon_machine_config *cfg;
> + /* Where the H2 loadlinux of this SoC expects to find the Linux kernel. */
> + hwaddr kernel_addr;
> + /* Add the devices that are specific to this SoC; may be NULL. */
> + void (*init_devices)(MachineState *ms);
> +} QcomDspMachineInfo;
> +
> +struct QcomDspMachineState {
> + HexagonCommonMachineState parent_obj;
> +
> + MemoryRegion tcm;
> + MemoryRegion l2_ecc;
> + int fdt_size;
> + hwaddr fdt_addr;
> + char *firmware_path;
> +};
> +
> +struct QcomDspMachineClass {
> + MachineClass parent_class;
> +
> + const QcomDspMachineInfo *info;
> +};
> +
> +/* Describes a register window the machine stubs out as unimplemented. */
> +typedef struct QcomDspRegion {
> + const char *name;
> + hwaddr base;
> + /* Zero means one 4 KiB page. */
> + hwaddr size;
> +} QcomDspRegion;
> +
> +/*
> + * Stub out register windows the guest may probe, named
> + * "<machine>.<name>@<base>".
> + */
> +void qcom_dsp_add_regions(MachineState *ms, const QcomDspRegion *regions,
> + unsigned int count);
> +
> +/* Create the sysbus device @type and map it at @base. */
> +void qcom_dsp_add_device(const char *type, hwaddr base);
> +
> +/*
> + * Stub out @ports consecutive QUP GENI serial engines of @size bytes. They
> + * belong to the SoC @soc rather than to the DSP.
> + */
> +void qcom_soc_add_qup_geni_ports(const char *soc, hwaddr base,
> + unsigned int ports, hwaddr size);
> +
> +/* Class init for a machine type whose class_data is a QcomDspMachineInfo. */
> +void qcom_dsp_class_init(ObjectClass *oc, const void *data);
> +
> +#endif /* HW_HEXAGON_QCOM_DSP_H */
> diff --git a/hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc b/hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
> new file mode 100644
> index 00000000000..11302da2238
> --- /dev/null
> +++ b/hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +static const struct hexagon_machine_config qcs6490_cdsp = {
> + .ddr_base = 0x80000000,
> + .cfgbase = 0x09980000,
> + .l2tcm_size = 0x00000000,
> + .l2vic_base = 0x0a390000,
> + .l2vic_size = 0x00001000,
> + .csr_base = 0x0a3a0000,
> + .qtmr_region = 0x0a3a1000,
> + .cfgtable = {
> + .l2tcm_base = 0x00000980,
> + .reserved0 = 0x00000000,
> + .subsystem_base = 0x00000a38,
> + .etm_base = 0x00000999,
> + .l2cfg_base = 0x0000099a,
> + .reserved1 = 0x0000099b,
> + .l1s0_base = 0x000009c0,
> + .axi2_lowaddr = 0x00000000,
> + .streamer_base = 0x0000099c,
> + .reserved2 = 0x0000099d,
> + .fastl2vic_base = 0x0000099e,
> + .jtlb_size_entries = 0x00000080,
> + .coproc_present = 0x00000001,
> + .ext_contexts = 0x00000002,
> + .vtcm_base = 0x000009c0,
> + .vtcm_size_kb = 0x00000800,
> + .l2tag_size = 0x00000400,
> + .l2ecomem_size = 0x00000400,
> + .thread_enable_mask = 0x0000003f,
> + .eccreg_base = 0x0000099f,
> + .l2line_size = 0x00000080,
> + .tiny_core = 0x00000000,
> + .l2itcm_size = 0x00000000,
> + .l2itcm_base = 0x00000980,
> + .reserved3 = 0x00000000,
> + .dtm_present = 0x00000000,
> + .dma_version = 0x00000001,
> + .hvx_vec_log_length = 0x00000007,
> + .core_id = 0x00000000,
> + .core_count = 0x00000000,
> + .coproc2_reg0 = 0x00000040,
> + .coproc2_reg1 = 0x00000020,
> + .v2x_mode = 0x00000001,
> + .coproc2_reg2 = 0x00000002,
> + .coproc2_reg3 = 0x00000000,
> + .coproc2_reg4 = 0x00000000,
> + .coproc2_reg5 = 0x00000000,
> + .coproc2_reg6 = 0x00000000,
> + .coproc2_reg7 = 0x00000000,
> + .acd_preset = 0x00000001,
> + .mnd_preset = 0x00000001,
> + .l1d_size_kb = 0x00000010,
> + .l1i_size_kb = 0x00000020,
> + .l1d_write_policy = 0x00000002,
> + .vtcm_bank_width = 0x00000040,
> + .reserved4 = 0x00000001,
> + .reserved5 = 0x00000000,
> + .reserved6 = 0x00000000,
> + .coproc2_cvt_mpy_size = 0x0000000a,
> + .consistency_domain = 0x00000000,
> + .capacity_domain = 0x00000000,
> + .axi3_lowaddr = 0x00000000,
> + },
> +};
> diff --git a/hw/hexagon/qcom_dsp.c b/hw/hexagon/qcom_dsp.c
> new file mode 100644
> index 00000000000..5520366bb28
> --- /dev/null
> +++ b/hw/hexagon/qcom_dsp.c
> @@ -0,0 +1,399 @@
> +/*
> + * DSP subsystem machines: the board layer shared by the SoC models.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/core/boards.h"
> +#include "hw/core/loader.h"
> +#include "hw/core/sysbus.h"
> +#include "hw/hexagon/hexagon.h"
> +#include "hw/hexagon/hex-board.h"
> +#include "hw/hexagon/hex-subsys.h"
> +#include "hw/hexagon/qcom_dsp.h"
> +#include "hw/misc/unimp.h"
> +#include "qemu/datadir.h"
> +#include "qemu/error-report.h"
> +#include "qemu/units.h"
> +#include "system/address-spaces.h"
> +#include "system/device_tree.h"
> +
> +enum {
> + QCOM_DSP_UART0,
> + QCOM_DSP_VIRTIO,
> + QCOM_DSP_GPT,
> + QCOM_DSP_BOOT,
> +};
> +
> +static const MemMapEntry qcom_dsp_memmap[] = {
> + [QCOM_DSP_UART0] = { 0x37000000, 0x00001000 },
> + [QCOM_DSP_VIRTIO] = { 0x37010000, 0x00001000 },
> + /* Not a device: the window the kernel's H2 timer driver binds to. */
> + [QCOM_DSP_GPT] = { 0xab000000, 0x00001000 },
> + [QCOM_DSP_BOOT] = { 0x99c00000, 0x00000200 },
> +};
> +
> +static const int QCOM_DSP_UART0_IRQ = 15;
> +/* Virtio IRQs run from QCOM_DSP_VIRTIO_IRQ to QCOM_DSP_VIRTIO_IRQ + 7 */
> +static const int QCOM_DSP_VIRTIO_IRQ = 96;
> +static const int QCOM_DSP_GPT_IRQ = 12;
> +
> +#define QCOM_DSP_L2_ECC_SIZE 0x1000
> +
> +#define QCOM_DSP_MAX_KERNEL_RAM (896 * MiB)
> +
> +static const uint32_t bootloader[] = {
> + /* Load fdt_base_low value into r0: */
> + 0x099c4000, /* { immext(#0x99c00000) */
> + 0x7800c606, /* r6 = ##-0x662fffd0 } */
> + 0x9186c000, /* { r0 = memw(r6+#0x0) } */
> +
> + /* Load fdt_base_high value into r1: */
> + 0x099c4000, /* { immext(#0x99c00000) */
> + 0x7800c586, /* r6 = ##-0x662fffd4 } */
> + 0x9186c001, /* { r1 = memw(r6+#0x0) } */
> +
> + /* Load next_stage_entry value into r7: */
> + 0x099c4000, /* { immext(#0x99c00000) */
> + 0x7800c687, /* r7 = ##-0x662fffcc } */
> + 0x9187c007, /* { r7 = memw(r7+#0x0) } */
> +
> + /* Jump to next_stage_entry, r1:0 now contains fdt_base: */
> + 0x5287c000, /* { jumpr r7 } */
> + 0x0, /* Invalid packet */
> + 0x0, /* Pad for fdt_base_high */
> + 0x0, /* Pad for fdt_base_low */
> + 0x0, /* Pad for next_stage_entry */
> +};
> +
> +enum {
> + FDT_HI = 11,
> + FDT_LO,
> + ENTRY_ADDR,
> +};
> +
> +static const QcomDspMachineInfo *qcom_dsp_info(MachineState *ms)
> +{
> + return QCOM_DSP_MACHINE_GET_CLASS(ms)->info;
> +}
> +
> +void qcom_dsp_add_regions(MachineState *ms, const QcomDspRegion *regions,
> + unsigned int count)
> +{
> + const char *machine = MACHINE_GET_CLASS(ms)->name;
> +
> + for (unsigned int i = 0; i < count; i++) {
> + g_autofree char *name = g_strdup_printf("%s.%s@%" HWADDR_PRIx, machine,
> + regions[i].name,
> + regions[i].base);
> +
> + create_unimplemented_device(name, regions[i].base,
> + regions[i].size ? regions[i].size : 0x1000);
> + }
> +}
> +
> +void qcom_dsp_add_device(const char *type, hwaddr base)
> +{
> + DeviceState *dev = qdev_new(type);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
> +}
> +
> +void qcom_soc_add_qup_geni_ports(const char *soc, hwaddr base,
> + unsigned int ports, hwaddr size)
> +{
> + for (unsigned int i = 0; i < ports; i++) {
> + g_autofree char *name = g_strdup_printf("%s.qup-geni@%" HWADDR_PRIx,
> + soc, base + i * size);
> +
> + create_unimplemented_device(name, base + i * size, size);
> + }
> +}
> +
> +/*
> + * The firmware programs the L2 ECC registers and polls them until what it
> + * wrote reads back, so they need to hold state.
> + */
> +static void qcom_dsp_add_l2_ecc_regs(QcomDspMachineState *qms,
> + const QcomDspMachineInfo *info)
> +{
> + hwaddr base = (hwaddr)info->cfg->cfgtable.eccreg_base << 16;
> +
> + if (!base) {
> + return;
> + }
> + memory_region_init_ram(&qms->l2_ecc, NULL, "l2-ecc-regs",
> + QCOM_DSP_L2_ECC_SIZE, &error_fatal);
> + memory_region_add_subregion(get_system_memory(), base, &qms->l2_ecc);
> +}
> +
> +static void qcom_dsp_create_fdt(QcomDspMachineState *qms)
> +{
> + MachineState *ms = MACHINE(qms);
> + g_autofree char *compatible = g_strdup_printf("qcom,%s",
> + MACHINE_GET_CLASS(ms)->name);
> +
> + hex_board_create_fdt(ms, MACHINE_GET_CLASS(ms)->desc, compatible,
> + &qms->fdt_size);
> + qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus");
> +}
> +
> +/*
> + * The H2 hypervisor provides the guest timer through hypercalls, so this
> + * node only tells the kernel's timer driver which interrupt to expect.
> + */
> +static void qcom_dsp_fdt_add_gpt(MachineState *ms)
> +{
> + static const char compat[] = "qcom,h2-timer\0hvm-timer";
> + g_autofree char *name = g_strdup_printf("/soc/gpt@%" PRIx64,
> + qcom_dsp_memmap[QCOM_DSP_GPT].base);
> +
> + qemu_fdt_add_subnode(ms->fdt, name);
> + qemu_fdt_setprop(ms->fdt, name, "compatible", compat, sizeof(compat));
> + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", QCOM_DSP_GPT_IRQ, 0);
> + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0,
> + qcom_dsp_memmap[QCOM_DSP_GPT].base,
> + qcom_dsp_memmap[QCOM_DSP_GPT].size);
> +}
> +
> +static void qcom_dsp_fdt_add_memory(MachineState *ms)
> +{
> + hwaddr kernel_addr = qcom_dsp_info(ms)->kernel_addr;
> + hwaddr ram_end = qcom_dsp_info(ms)->cfg->ddr_base + ms->ram_size;
> + hwaddr size = MIN(ram_end - kernel_addr, QCOM_DSP_MAX_KERNEL_RAM);
> + g_autofree char *nodename = g_strdup_printf("/memory@%" HWADDR_PRIx,
> + kernel_addr);
> +
> + qemu_fdt_add_subnode(ms->fdt, nodename);
> + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
> + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, kernel_addr,
> + size);
> +}
> +
> +static uint64_t qcom_dsp_kernel_translate(void *opaque, uint64_t addr)
> +{
> + return addr + qcom_dsp_info(MACHINE(opaque))->kernel_addr;
> +}
> +
> +static uint64_t qcom_dsp_load_kernel(MachineState *ms, bool through_firmware,
> + hwaddr *image_high)
> +{
> + return hex_board_load_elf(ms->kernel_filename,
> + through_firmware ? qcom_dsp_kernel_translate
> + : NULL,
> + ms, image_high);
> +}
> +
> +static uint64_t qcom_dsp_load_firmware(QcomDspMachineState *qms)
> +{
> + return hex_board_load_elf(qms->firmware_path, NULL, NULL, NULL);
> +}
> +
> +/*
> + * Place the FDT after the kernel image, inside the RAM window the kernel
> + * maps, and the initrd after that.
> + */
> +static void qcom_dsp_load_initrd(QcomDspMachineState *qms)
> +{
> + MachineState *ms = MACHINE(qms);
> + hwaddr start = qms->fdt_addr + 4 * MiB;
> + hwaddr ram_end = qcom_dsp_info(ms)->cfg->ddr_base + ms->ram_size;
> + ssize_t size;
> +
> + if (!ms->initrd_filename) {
> + return;
> + }
> +
> + if (start >= ram_end) {
> + error_report("no room for the initrd: RAM ends at 0x%" HWADDR_PRIx
> + " but the initrd would start at 0x%" HWADDR_PRIx,
> + ram_end, start);
> + exit(1);
> + }
> +
> + size = load_image_targphys_as(ms->initrd_filename, start, ram_end - start,
> + &address_space_memory, &error_fatal);
> +
> + qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,initrd-start", start);
> + qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,initrd-end", start + size);
> +}
> +
> +/*
> + * A boot stub that passes the FDT address to the firmware in r1:r0, then
> + * jumps to the firmware's entry point.
> + */
> +static uint64_t qcom_dsp_setup_boot_stub(QcomDspMachineState *qms,
> + uint64_t firmware_entry)
> +{
> + hwaddr bootl_base = qcom_dsp_memmap[QCOM_DSP_BOOT].base;
> + uint32_t stub[ARRAY_SIZE(bootloader)];
> +
> + memcpy(stub, bootloader, sizeof(stub));
Maybe I'm missing something, but wouldn't we need to endian swap the
instruction words in `bootloader` on big-endian hosts?
> + stub[FDT_LO] = cpu_to_le32(extract64(qms->fdt_addr, 0, 32));
> + stub[FDT_HI] = cpu_to_le32(extract64(qms->fdt_addr, 32, 32));
> + stub[ENTRY_ADDR] = cpu_to_le32(extract64(firmware_entry, 0, 32));
> +
> + g_assert(sizeof(stub) <= qcom_dsp_memmap[QCOM_DSP_BOOT].size);
> + rom_add_blob_fixed_as("bootloader", stub, sizeof(stub), bootl_base,
> + &address_space_memory);
> +
> + return bootl_base;
> +}
> +
> +/* Reject boot options that do not make sense together, and find -bios. */
> +static void qcom_dsp_check_boot_options(QcomDspMachineState *qms)
> +{
> + MachineState *ms = MACHINE(qms);
> + hwaddr ddr_base = qcom_dsp_info(ms)->cfg->ddr_base;
> + hwaddr kernel_addr = qcom_dsp_info(ms)->kernel_addr;
> +
> + if (ms->firmware) {
> + qms->firmware_path = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->firmware);
> + if (!qms->firmware_path) {
> + error_report("Could not find firmware '%s'", ms->firmware);
> + exit(1);
> + }
> + }
> +
> + if (ms->initrd_filename && !(ms->kernel_filename && qms->firmware_path)) {
> + error_report("-initrd needs both -kernel and the H2 loadlinux "
> + "firmware given with -bios");
> + exit(1);
> + }
> +
> + if (ms->kernel_filename && qms->firmware_path &&
> + (ddr_base > qcom_dsp_memmap[QCOM_DSP_BOOT].base ||
> + ddr_base + ms->ram_size <= kernel_addr)) {
> + error_report("RAM (%" PRIu64 " MiB at 0x%" HWADDR_PRIx ") is too "
> + "small: the kernel is loaded at 0x%" HWADDR_PRIx,
> + ms->ram_size / MiB, ddr_base, kernel_addr);
> + exit(1);
> + }
> +}
> +
> +/* Load what -bios and -kernel name and return where CPU 0 starts, if known. */
> +static bool qcom_dsp_load_images(QcomDspMachineState *qms, uint64_t *start)
> +{
> + MachineState *ms = MACHINE(qms);
> + hwaddr image_high = 0;
> +
> + if (ms->kernel_filename && qms->firmware_path) {
> + uint64_t firmware_entry = qcom_dsp_load_firmware(qms);
> +
> + qcom_dsp_load_kernel(ms, true, &image_high);
> + qms->fdt_addr = QEMU_ALIGN_UP(image_high + 16 * MiB, 4 * MiB);
checks against ram_end only occur when -initrd is specified in
qcom_dsp_load_initrd(), so without -initrd you could get a fdt_addr
that's outside the range of ram.
> + qcom_dsp_load_initrd(qms);
> + *start = qcom_dsp_setup_boot_stub(qms, firmware_entry);
> + return true;
> + }
> + if (ms->kernel_filename) {
> + *start = qcom_dsp_load_kernel(ms, false, &image_high);
> + return true;
> + }
> + if (qms->firmware_path) {
> + *start = qcom_dsp_load_firmware(qms);
> + return true;
> + }
> + return false;
> +}
> +
--
Anton Johansson
rev.ng Labs Srl.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 12/14] hw/hexagon: add subsystem-base property
2026-10-19 5:52 ` [PATCH 12/14] hw/hexagon: add subsystem-base property Brian Cain
2026-10-19 22:16 ` Pierrick Bouvier
@ 2026-10-20 14:53 ` Anton Johansson via qemu development
1 sibling, 0 replies; 35+ messages in thread
From: Anton Johansson via qemu development @ 2026-10-20 14:53 UTC (permalink / raw)
To: Brian Cain
Cc: qemu-devel, Laurent Vivier, Helge Deller, Pierrick Bouvier,
Fabiano Rosas, Philippe Mathieu-Daudé,
Alessandro Di Federico, Paolo Bonzini, Laurent Vivier
On 19/10/26, Brian Cain wrote:
> 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.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> MAINTAINERS | 1 +
> include/hw/hexagon/hexagon.h | 4 ++
> hw/hexagon/hexagon_dsp.c | 62 +++++++++++++++++++++++-
> tests/qtest/hexagon-config-test.c | 78 +++++++++++++++++++++++++++++++
> tests/qtest/meson.build | 3 +-
> 5 files changed, 146 insertions(+), 2 deletions(-)
> create mode 100644 tests/qtest/hexagon-config-test.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 04df9db77dc..f1fbc971fed 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1386,6 +1386,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 7d15a9e1eb0..32acc2aa26b 100644
> --- a/include/hw/hexagon/hexagon.h
> +++ b/include/hw/hexagon/hexagon.h
> @@ -44,6 +44,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 9f6f34ef9be..1f92a8adccf 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"
> @@ -35,6 +36,7 @@
> #include "machine_cfg_v81qa_1.h.inc"
>
> #define TYPE_HEXAGON_DSP_MACHINE "hexagon-dsp-machine"
> +#define HEXAGON_DSP_SUBSYSTEM_BASE 0xfc900000
> OBJECT_DECLARE_SIMPLE_TYPE(HexagonDspMachineState, HEXAGON_DSP_MACHINE)
>
> struct HexagonDspMachineState {
> @@ -42,6 +44,8 @@ struct HexagonDspMachineState {
>
> hwaddr isdb_secure_flag;
> hwaddr isdb_trusted_flag;
> + uint32_t subsystem_base;
> + struct hexagon_machine_config config;
> };
>
> static HexagonDspMachineState *current_dms;
> @@ -107,6 +111,50 @@ 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);
> + 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;
> + }
> +
> + 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)
> {
> @@ -121,7 +169,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;
Since the only requirement on `subsystem_base` is that it's non-zero and
64 KiB aligned, this addition can overflow with e.g.
`subsystem-base=0xffff0000`, adding an upper-bounds check to the set
function could be nice to avoid any footguns in the future.
> + 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);
>
> @@ -183,6 +237,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);
> }
--
Anton Johansson
rev.ng Labs Srl.
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2026-10-20 14:48 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 5:52 [PATCH 00/14] Hexagon: Add real SoC-style machines Brian Cain
2026-10-19 5:52 ` [PATCH 01/14] Hexagon: add v85 CPU model Brian Cain
2026-10-19 22:32 ` Anton Johansson via qemu development
2026-10-19 23:58 ` Brian Cain
2026-10-19 5:52 ` [PATCH 02/14] hw/hexagon: let a machine place its DDR Brian Cain
2026-10-19 21:40 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 03/14] hw/hexagon: introduce hex-board abstraction Brian Cain
2026-10-19 21:42 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 04/14] hw/hexagon: convert virt board to hex-board Brian Cain
2026-10-19 21:40 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 05/14] hw/misc: add the QDSP6SS PLL, RCG Brian Cain
2026-10-19 21:51 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 06/14] hw/hexagon: add the QCS6490 CDSP machine Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-20 11:28 ` Anton Johansson via qemu development
2026-10-19 5:52 ` [PATCH 07/14] hw/hexagon: add the SA8775P " Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 08/14] hw/hexagon: add the SC8480XP NSP0 machine Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 09/14] hw/hexagon: add the SA8797P " Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 10/14] hw/hexagon: add the SM8975 NSP machine Brian Cain
2026-10-19 22:15 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 11/14] hw/hexagon: add v79NA1 machine Brian Cain
2026-10-19 22:16 ` Pierrick Bouvier
2026-10-19 5:52 ` [PATCH 12/14] hw/hexagon: add subsystem-base property Brian Cain
2026-10-19 22:16 ` Pierrick Bouvier
2026-10-20 14:53 ` Anton Johansson via qemu development
2026-10-19 5:52 ` [PATCH 13/14] target/hexagon: fix the allocframe framekey Brian Cain
2026-10-19 5:52 ` [PATCH 14/14] tests/functional/hexagon: boot DSP firmware Brian Cain
2026-10-19 13:47 ` Philippe Mathieu-Daudé
2026-10-19 13:51 ` Brian Cain
2026-10-19 15:22 ` Brian Cain
2026-10-19 21:50 ` Pierrick Bouvier
2026-10-19 22:03 ` Brian Cain
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.