From: Joel Stanley <joel@jms.id.au>
To: Alistair Francis <alistair.francis@wdc.com>,
Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Cc: "Weiwei Li" <liwei1518@gmail.com>,
"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>,
"Chao Liu" <chao.liu@processmission.com>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Anirudh Srinivasan" <asrinivasan@oss.tenstorrent.com>,
"Michael Ellerman" <mpe@kernel.org>,
"Portia Stephens" <portias@oss.tenstorrent.com>,
"Cédric Le Goater" <clg@kaod.org>,
qemu-riscv@nongnu.org, qemu-devel@nongnu.org
Subject: [PATCH v3 15/16] hw/riscv/atlantis: Extract an Atlantis SoC device
Date: Thu, 3 Sep 2026 15:21:29 +0930 [thread overview]
Message-ID: <20260903055131.257903-16-joel@jms.id.au> (raw)
In-Reply-To: <20260903055131.257903-1-joel@jms.id.au>
Introduce TYPE_TT_ATLANTIS_SOC and move the hart array, AIA, ACLINT,
boot ROM, UART and I2C controllers into the new TTAtlantisSoCState. The
machine keeps ownership of RAM, device tree generation, firmware
loading, and the board-level I2C slaves.
This makes it easier to compose the SoC into a more complex machine in
the future.
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
include/hw/riscv/tt_atlantis.h | 21 ++++-
hw/riscv/tt_atlantis.c | 144 +++++++++++++++++++++++----------
2 files changed, 119 insertions(+), 46 deletions(-)
diff --git a/include/hw/riscv/tt_atlantis.h b/include/hw/riscv/tt_atlantis.h
index 9ca98bfb8478..5d4e4d133bd9 100644
--- a/include/hw/riscv/tt_atlantis.h
+++ b/include/hw/riscv/tt_atlantis.h
@@ -19,14 +19,16 @@
#define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisState, TT_ATLANTIS_MACHINE)
+#define TYPE_TT_ATLANTIS_SOC "tt-atlantis-soc"
+OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisSoCState, TT_ATLANTIS_SOC)
+
#define TT_ATL_NUM_I2C 5
-struct TTAtlantisState {
+struct TTAtlantisSoCState {
/*< private >*/
- MachineState parent;
+ DeviceState parent;
/*< public >*/
- Notifier machine_done;
const MemMapEntry *memmap;
MemoryRegion *memory;
@@ -39,6 +41,19 @@ struct TTAtlantisState {
DesignWareI2CState i2c[TT_ATL_NUM_I2C];
UnimplementedDeviceState uart1;
MemoryRegion bootrom;
+
+ uint32_t num_harts;
+ char *cpu_type;
+};
+
+struct TTAtlantisState {
+ /*< private >*/
+ MachineState parent;
+
+ /*< public >*/
+ Notifier machine_done;
+
+ TTAtlantisSoCState soc;
};
enum {
diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index d4fe505fe033..6c46121287c7 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -7,6 +7,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/guest-random.h"
@@ -14,6 +15,7 @@
#include "hw/core/boards.h"
#include "hw/core/loader.h"
+#include "hw/core/qdev-properties.h"
#include "hw/core/sysbus.h"
#include "target/riscv/cpu.h"
@@ -67,7 +69,7 @@ static const MemMapEntry tt_atlantis_memmap[] = {
[TT_ATL_DDR_HI] = { 0x100000000, 0x1000000000 },
};
-static I2CBus *i2c_get_bus(TTAtlantisState *s, unsigned busnr)
+static I2CBus *i2c_get_bus(TTAtlantisSoCState *s, unsigned busnr)
{
assert(busnr < TT_ATL_NUM_I2C);
@@ -80,7 +82,7 @@ static uint32_t next_phandle(void)
return fdt_phandle++;
}
-static void create_fdt_memory(void *fdt, TTAtlantisState *s)
+static void create_fdt_memory(void *fdt, TTAtlantisSoCState *s)
{
hwaddr ram_size = memory_region_size(s->dram);
hwaddr size_lo = ram_size;
@@ -105,7 +107,7 @@ static void create_fdt_memory(void *fdt, TTAtlantisState *s)
}
}
-static void create_fdt_aclint(void *fdt, TTAtlantisState *s,
+static void create_fdt_aclint(void *fdt, TTAtlantisSoCState *s,
uint32_t *intc_phandles)
{
g_autofree char *name = NULL;
@@ -207,7 +209,7 @@ static void create_fdt_one_aplic(void *fdt,
qemu_fdt_setprop_cell(fdt, name, "phandle", aplic_phandle);
}
-static void create_fdt_pmu(void *fdt, TTAtlantisState *s)
+static void create_fdt_pmu(void *fdt, TTAtlantisSoCState *s)
{
char pmu_name[] = "/pmu";
RISCVCPU *hart = &s->cpus.harts[0];
@@ -217,7 +219,7 @@ static void create_fdt_pmu(void *fdt, TTAtlantisState *s)
riscv_pmu_generate_fdt_node(fdt, hart->pmu_avail_ctrs, pmu_name);
}
-static void create_fdt_cpu(void *fdt, TTAtlantisState *s,
+static void create_fdt_cpu(void *fdt, TTAtlantisSoCState *s,
uint32_t aplic_s_phandle,
uint32_t imsic_s_phandle)
{
@@ -314,7 +316,7 @@ static void create_fdt_i2c(void *fdt, const MemMapEntry *mem, uint32_t irq,
qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0);
}
-static void create_fdt_i2c_device(void *fdt, TTAtlantisState *s, int bus,
+static void create_fdt_i2c_device(void *fdt, TTAtlantisSoCState *s, int bus,
const char *compat, int addr)
{
hwaddr base = s->memmap[TT_ATL_I2C0 + bus].base;
@@ -326,7 +328,7 @@ static void create_fdt_i2c_device(void *fdt, TTAtlantisState *s, int bus,
qemu_fdt_setprop_cell(fdt, name, "reg", addr);
}
-static void finalize_fdt(void *fdt, TTAtlantisState *s)
+static void finalize_fdt(void *fdt, TTAtlantisSoCState *s)
{
uint32_t aplic_s_phandle = next_phandle();
uint32_t imsic_s_phandle = next_phandle();
@@ -360,9 +362,9 @@ static void finalize_fdt(void *fdt, TTAtlantisState *s)
create_fdt_i2c_device(fdt, s, 4, "ti,tmp105", 0x48);
}
-static void create_fdt(TTAtlantisState *s)
+static void create_fdt(TTAtlantisState *ams)
{
- MachineState *ms = MACHINE(s);
+ MachineState *ms = MACHINE(ams);
int fdt_size = 0;
ms->fdt = riscv_create_board_device_tree("Tenstorrent Atlantis RISC-V Machine",
@@ -374,12 +376,12 @@ static void create_fdt(TTAtlantisState *s)
qemu_fdt_add_subnode(ms->fdt, "/aliases");
- create_fdt_pmu(ms->fdt, s);
+ create_fdt_pmu(ms->fdt, &ams->soc);
}
-static void load_fdt(TTAtlantisState *s)
+static void load_fdt(TTAtlantisState *ams)
{
- MachineState *ms = MACHINE(s);
+ MachineState *ms = MACHINE(ams);
char **node_path;
Error *err = NULL;
int fdt_size = 0;
@@ -405,7 +407,7 @@ static void load_fdt(TTAtlantisState *s)
g_strfreev(node_path);
}
- create_fdt_memory(ms->fdt, s);
+ create_fdt_memory(ms->fdt, &ams->soc);
}
static void mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev,
@@ -419,10 +421,11 @@ static void mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev,
sysbus_mmio_get_region(dev, 0), -1000);
}
-static void tt_atlantis_machine_done(Notifier *notifier, void *data)
+static void tt_atlantis_machine_done(Notifier *n, void *data)
{
- TTAtlantisState *s = container_of(notifier, TTAtlantisState, machine_done);
- MachineState *machine = MACHINE(s);
+ TTAtlantisState *ams = container_of(n, TTAtlantisState, machine_done);
+ TTAtlantisSoCState *s = &ams->soc;
+ MachineState *machine = MACHINE(ams);
hwaddr start_addr = s->memmap[TT_ATL_DDR_LO].base;
hwaddr mem_size;
target_ulong firmware_end_addr, kernel_start_addr;
@@ -480,23 +483,39 @@ static void tt_atlantis_machine_done(Notifier *notifier, void *data)
fdt_load_addr);
}
-static void tt_atlantis_machine_init(MachineState *machine)
+static void tt_atlantis_soc_init(Object *obj)
{
- TTAtlantisState *s = TT_ATLANTIS_MACHINE(machine);
+ TTAtlantisSoCState *s = TT_ATLANTIS_SOC(obj);
+
+ object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
+
+ object_initialize_child(obj, "uart1", &s->uart1,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
+ object_initialize_child(obj, "i2c[*]", &s->i2c[i],
+ TYPE_DESIGNWARE_I2C);
+ }
+}
+
+static void tt_atlantis_soc_realize(DeviceState *dev, Error **errp)
+{
+ TTAtlantisSoCState *s = TT_ATLANTIS_SOC(dev);
ram_addr_t lo_ram_size, ram_size;
- int hart_count = machine->smp.cpus;
+ int hart_count = s->num_harts;
s->memory = get_system_memory();
- s->dram = machine->ram;
+ if (!s->dram) {
+ error_setg(errp, "'dram' link is not set");
+ return;
+ }
ram_size = memory_region_size(s->dram);
s->memmap = tt_atlantis_memmap;
- object_initialize_child(OBJECT(machine), "soc", &s->cpus,
- TYPE_RISCV_HART_ARRAY);
- object_property_set_str(OBJECT(&s->cpus), "cpu-type", machine->cpu_type,
+ /* CPUs */
+ object_property_set_str(OBJECT(&s->cpus), "cpu-type", s->cpu_type,
&error_abort);
object_property_set_int(OBJECT(&s->cpus), "hartid-base", 0,
&error_abort);
@@ -505,7 +524,9 @@ static void tt_atlantis_machine_init(MachineState *machine)
object_property_set_int(OBJECT(&s->cpus), "resetvec",
s->memmap[TT_ATL_BOOTROM].base,
&error_abort);
- sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpus), errp)) {
+ return;
+ }
s->irqchip = riscv_create_aia(s->memory,
true, TT_IMSIC_GUESTS,
@@ -535,26 +556,27 @@ static void tt_atlantis_machine_init(MachineState *machine)
* up to 64GB. The low address is an alias of the first 2GB of that RAM.
*/
if (ram_size > s->memmap[TT_ATL_DDR_HI].size) {
- char *sz = size_to_str(s->memmap[TT_ATL_DDR_HI].size);
- error_report("RAM size is too large, maximum is %s", sz);
- g_free(sz);
- exit(EXIT_FAILURE);
+ g_autofree char *sz = size_to_str(s->memmap[TT_ATL_DDR_HI].size);
+ error_setg(errp, "RAM size is too large, maximum is %s", sz);
+ return;
}
- memory_region_init_alias(&s->ram_hi, OBJECT(machine), "ram.high", s->dram,
+ memory_region_init_alias(&s->ram_hi, OBJECT(s), "ram.high", s->dram,
0, ram_size);
memory_region_add_subregion(s->memory,
s->memmap[TT_ATL_DDR_HI].base, &s->ram_hi);
lo_ram_size = MIN(ram_size, s->memmap[TT_ATL_DDR_LO].size);
- memory_region_init_alias(&s->ram_lo, OBJECT(machine), "ram.low", s->dram,
+ memory_region_init_alias(&s->ram_lo, OBJECT(s), "ram.low", s->dram,
0, lo_ram_size);
memory_region_add_subregion(s->memory,
s->memmap[TT_ATL_DDR_LO].base, &s->ram_lo);
/* Boot ROM */
- memory_region_init_rom(&s->bootrom, NULL, "tt-atlantis.bootrom",
- s->memmap[TT_ATL_BOOTROM].size, &error_fatal);
+ if (!memory_region_init_rom(&s->bootrom, OBJECT(s), "tt-atlantis.bootrom",
+ s->memmap[TT_ATL_BOOTROM].size, errp)) {
+ return;
+ }
memory_region_add_subregion(s->memory, s->memmap[TT_ATL_BOOTROM].base,
&s->bootrom);
@@ -571,26 +593,56 @@ static void tt_atlantis_machine_init(MachineState *machine)
* Create an unimplemented device region so writes don't fault
* and reads return zero, which keeps Linux happy.
*/
- object_initialize_child(OBJECT(s), "uart1", &s->uart1,
- TYPE_UNIMPLEMENTED_DEVICE);
mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->uart1),
"tt-atlantis.uart1", s->memmap[TT_ATL_UART1].base,
s->memmap[TT_ATL_UART1].size);
/* I2C */
for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
- SysBusDevice *sbd;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->i2c[i]);
- object_initialize_child(OBJECT(s), "i2c[*]", &s->i2c[i],
- TYPE_DESIGNWARE_I2C);
- sbd = SYS_BUS_DEVICE(&s->i2c[i]);
- sysbus_realize(sbd, &error_fatal);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
memory_region_add_subregion(s->memory,
s->memmap[TT_ATL_I2C0 + i].base,
sysbus_mmio_get_region(sbd, 0));
sysbus_connect_irq(sbd, 0,
qdev_get_gpio_in(s->irqchip, TT_ATL_I2C0_IRQ + i));
}
+}
+
+static const Property tt_atlantis_soc_props[] = {
+ DEFINE_PROP_STRING("cpu-type", TTAtlantisSoCState, cpu_type),
+ DEFINE_PROP_UINT32("num-harts", TTAtlantisSoCState, num_harts, 8),
+ DEFINE_PROP_LINK("dram", TTAtlantisSoCState, dram,
+ TYPE_MEMORY_REGION, MemoryRegion *),
+};
+
+static void tt_atlantis_soc_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = tt_atlantis_soc_realize;
+ device_class_set_props(dc, tt_atlantis_soc_props);
+ /* The SoC can only be instantiated from the machine */
+ dc->user_creatable = false;
+}
+
+static void tt_atlantis_machine_init(MachineState *machine)
+{
+ TTAtlantisState *ams = TT_ATLANTIS_MACHINE(machine);
+ TTAtlantisSoCState *s = &ams->soc;
+
+ object_initialize_child(OBJECT(machine), "soc", &ams->soc,
+ TYPE_TT_ATLANTIS_SOC);
+ object_property_set_str(OBJECT(&ams->soc), "cpu-type", machine->cpu_type,
+ &error_abort);
+ object_property_set_int(OBJECT(&ams->soc), "num-harts", machine->smp.cpus,
+ &error_abort);
+ object_property_set_link(OBJECT(&ams->soc), "dram", OBJECT(machine->ram),
+ &error_abort);
+ qdev_realize(DEVICE(&ams->soc), NULL, &error_fatal);
/* I2C peripherals: qemu specific */
i2c_slave_create_simple(i2c_get_bus(s, 0), "ds1338", 0x6f);
@@ -598,13 +650,13 @@ static void tt_atlantis_machine_init(MachineState *machine)
/* Load or create device tree */
if (machine->dtb) {
- load_fdt(s);
+ load_fdt(ams);
} else {
- create_fdt(s);
+ create_fdt(ams);
}
- s->machine_done.notify = tt_atlantis_machine_done;
- qemu_add_machine_init_done_notifier(&s->machine_done);
+ ams->machine_done.notify = tt_atlantis_machine_done;
+ qemu_add_machine_init_done_notifier(&ams->machine_done);
}
static void tt_atlantis_machine_class_init(ObjectClass *oc, const void *data)
@@ -624,6 +676,12 @@ static void tt_atlantis_machine_class_init(ObjectClass *oc, const void *data)
static const TypeInfo tt_atlantis_types[] = {
{
+ .name = TYPE_TT_ATLANTIS_SOC,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(TTAtlantisSoCState),
+ .instance_init = tt_atlantis_soc_init,
+ .class_init = tt_atlantis_soc_class_init,
+ }, {
.name = MACHINE_TYPE_NAME("tt-atlantis"),
.parent = TYPE_MACHINE,
.class_init = tt_atlantis_machine_class_init,
--
2.47.3
next prev parent reply other threads:[~2026-09-03 5:54 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-03 5:51 [PATCH v3 00/16] hw/riscv: Socify Atlantis Joel Stanley
2026-09-03 5:51 ` [PATCH v3 01/16] hw/riscv/aia: Take a MemoryRegion for the created devices Joel Stanley
2026-09-03 6:06 ` Chao Liu via
2026-09-03 6:06 ` Chao Liu via qemu development
2026-09-03 5:51 ` [PATCH v3 02/16] hw/intc/riscv_aclint: " Joel Stanley
2026-09-03 5:51 ` [PATCH v3 03/16] hw/intc/riscv_imsic: Take a MemoryRegion for the created device Joel Stanley
2026-09-03 5:51 ` [PATCH v3 04/16] hw/intc/riscv_aplic: " Joel Stanley
2026-09-03 5:51 ` [PATCH v3 05/16] hw/intc/sifive_plic: " Joel Stanley
2026-09-03 6:07 ` Chao Liu via qemu development
2026-09-03 6:07 ` Chao Liu via
2026-09-03 5:51 ` [PATCH v3 06/16] hw/riscv/cps: Map interrupt controllers in SoC container Joel Stanley
2026-09-03 5:51 ` [PATCH v3 07/16] hw/riscv/atlantis: Make UART unimp region a SoC device Joel Stanley
2026-09-03 5:51 ` [PATCH v3 08/16] hw/riscv/atlantis: Remove unused fdt_size Joel Stanley
2026-09-03 5:51 ` [PATCH v3 09/16] hw/riscv/atlantis: Rename hart array 'soc' to 'cpus' Joel Stanley
2026-09-03 5:51 ` [PATCH v3 10/16] hw/riscv/atlantis: Rework device tree creation Joel Stanley
2026-09-03 5:51 ` [PATCH v3 11/16] hw/riscv/atlantis: Use local reference for system memory Joel Stanley
2026-09-03 5:51 ` [PATCH v3 12/16] hw/riscv/atlantis: Decouple RAM size from MachineState Joel Stanley
2026-09-03 5:51 ` [PATCH v3 13/16] hw/riscv/atlantis: Make TTAtlantisState own memory containers Joel Stanley
2026-09-03 5:51 ` [PATCH v3 14/16] hw/riscv: Add property to hart array to allow private memory Joel Stanley
2026-09-04 10:42 ` Philippe Mathieu-Daudé
2026-09-07 7:27 ` Joel Stanley
2026-09-03 5:51 ` Joel Stanley [this message]
2026-09-04 10:47 ` [PATCH v3 15/16] hw/riscv/atlantis: Extract an Atlantis SoC device Philippe Mathieu-Daudé
2026-09-04 10:48 ` Philippe Mathieu-Daudé
2026-09-07 7:16 ` Joel Stanley
2026-09-03 5:51 ` [PATCH v3 16/16] hw/riscv/atlantis: Map the SoC through a memory container Joel Stanley
2026-09-03 23:35 ` [PATCH v3 00/16] hw/riscv: Socify Atlantis Alistair Francis
2026-09-04 10:49 ` Philippe Mathieu-Daudé
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260903055131.257903-16-joel@jms.id.au \
--to=joel@jms.id.au \
--cc=alistair.francis@wdc.com \
--cc=asrinivasan@oss.tenstorrent.com \
--cc=chao.liu@processmission.com \
--cc=clg@kaod.org \
--cc=daniel.barboza@oss.qualcomm.com \
--cc=liwei1518@gmail.com \
--cc=mpe@kernel.org \
--cc=npiggin@gmail.com \
--cc=portias@oss.tenstorrent.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.