* [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* 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
* [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* 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
* [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* 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
* [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* 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
* [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* 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
* [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* 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 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
* [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* 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
* [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* 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
* [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* 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
* [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* 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
* [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* 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
* [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* 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 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
* [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 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 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