On Fri, 2026-10-02 at 09:33 +1000, Portia Stephens wrote: > Previously only the Ascalon console UART was enabled, this enables > all 5 > UARTs on the SoC. Only UART1 is added to the serial interface for > now. > The next change will handle adding the rest of the UARTs. > > Signed-off-by: Portia Stephens <[email protected]> > Reviewed-by: Daniel Henrique Barboza > <[email protected]> > --- > hw/riscv/tt_atlantis.c | 54 +++++++++++++++++++++++++------- > -- > include/hw/riscv/tt_atlantis.h | 11 ++++++- > 2 files changed, 50 insertions(+), 15 deletions(-) > > diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c > index 70815e12ef..2342edce93 100644 > --- a/hw/riscv/tt_atlantis.c > +++ b/hw/riscv/tt_atlantis.c > @@ -62,7 +62,11 @@ static const MemMapEntry tt_atlantis_memmap[] = { > [TT_ATL_I2C2] = { 0xd4060000, 0x10000 }, > [TT_ATL_I2C3] = { 0xd4070000, 0x10000 }, > [TT_ATL_I2C4] = { 0xd4080000, 0x10000 }, > + [TT_ATL_UART0] = { 0xd4100000, 0x10000 }, > [TT_ATL_UART1] = { 0xd4110000, 0x10000 }, > + [TT_ATL_UART2] = { 0xd4120000, 0x10000 }, > + [TT_ATL_UART3] = { 0xd4130000, 0x10000 }, > + [TT_ATL_UART4] = { 0xd4140000, 0x10000 }, > [TT_ATL_SAPLIC] = { 0xe8000000, 0x4000000 }, > [TT_ATL_DDR_HI] = { 0x100000000, 0x1000000000 }, > }; > @@ -259,13 +263,14 @@ static void create_fdt_cpu(void *fdt, > TTAtlantisSoCState *s, > } > > static void create_fdt_uart(void *fdt, const MemMapEntry *mem, int > irq, > - int irqchip_phandle) > + int irqchip_phandle, int index) > { > static const char * const compat[2] = { > "snps,dw-apb-uart", "ns16550a" > }; > g_autofree char *name = > g_strdup_printf("/soc/serial@%"HWADDR_PRIX, > mem->base); > + g_autofree char *alias = g_strdup_printf("serial%d", index); > > qemu_fdt_add_subnode(fdt, name); > qemu_fdt_setprop_string_array(fdt, name, "compatible", > @@ -277,8 +282,10 @@ static void create_fdt_uart(void *fdt, const > MemMapEntry *mem, int irq, > qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", > irqchip_phandle); > qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x4); > > - qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name); > - qemu_fdt_setprop_string(fdt, "/aliases", "serial0", name); > + if (index == 0) { > + qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", > name); > + } > + qemu_fdt_setprop_string(fdt, "/aliases", alias, name); > } > > static void create_fdt_rng(void *fdt) > @@ -347,8 +354,11 @@ static void finalize_fdt(void *fdt, > TTAtlantisSoCState *s) > * aplic_s_phandle); > */ > > - create_fdt_uart(fdt, &s->memmap[TT_ATL_UART1], TT_ATL_UART1_IRQ, > - aplic_s_phandle); > + /* Skip UART0 since it is the RCPU console, UART1 is the Ascalon > console */ > + for (int i = 0; i < TT_ATL_NUM_UARTS - 1; i++) {
I feel like `int i = 1` would be a bit cleaner. No need to respin though Reviewed-by: Alistair Francis <[email protected]> Alistair > + create_fdt_uart(fdt, &s->memmap[TT_ATL_UART1 + i], > TT_ATL_UART1_IRQ + i, > + aplic_s_phandle, i); > + } > > create_fdt_clk(fdt, "periph-clk", 100000000, > periph_clk_phandle); > > @@ -474,13 +484,21 @@ static void tt_atlantis_machine_done(Notifier > *n, void *data) > fdt_load_addr); > } > > +static inline int tt_atlantis_uart_index(int uart_dev) > +{ > + return uart_dev - TT_ATL_UART0; > +} > + > static void tt_atlantis_soc_init(Object *obj) > { > 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_DW8250); > + for (int i = 0; i < TT_ATL_NUM_UARTS; i++) { > + object_initialize_child(obj, "uart[*]", &s->uart[i], > + TYPE_DW8250); > + } > > for (int i = 0; i < TT_ATL_NUM_I2C; i++) { > object_initialize_child(obj, "i2c[*]", &s->i2c[i], > @@ -574,14 +592,22 @@ static void tt_atlantis_soc_realize(DeviceState > *dev, Error **errp) > memory_region_add_subregion(s->memory, s- > >memmap[TT_ATL_BOOTROM].base, > &s->bootrom); > > - /* UART1, the soc console (UART0 is for the boot > microcontroller) */ > - qdev_prop_set_chr(DEVICE(&s->uart1), "chardev", serial_hd(0)); > - sysbus_realize(SYS_BUS_DEVICE(&s->uart1), &error_fatal); > - memory_region_add_subregion(s->memory, > - s->memmap[TT_ATL_UART1].base, > - > sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart1), 0)); > - sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart1), 0, > - qdev_get_gpio_in(s->irqchip, > TT_ATL_UART1_IRQ)); > + /* UART1, the soc console (UART0 is for the boot microcontroller > */ > + qdev_prop_set_chr(DEVICE(&s- > >uart[tt_atlantis_uart_index(TT_ATL_UART1)]), > + "chardev", serial_hd(0)); > + > + for (int i = 0; i < TT_ATL_NUM_UARTS; i++) { > + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->uart[i]); > + if (!sysbus_realize(sbd, errp)) { > + return; > + } > + > + memory_region_add_subregion(s->memory, > + s->memmap[TT_ATL_UART0 + > i].base, > + sysbus_mmio_get_region(sbd, 0)); > + sysbus_connect_irq(sbd, 0, > + qdev_get_gpio_in(s->irqchip, > TT_ATL_UART0_IRQ + i)); > + } > > /* I2C */ > for (int i = 0; i < TT_ATL_NUM_I2C; i++) { > diff --git a/include/hw/riscv/tt_atlantis.h > b/include/hw/riscv/tt_atlantis.h > index 000988c037..b81b7c8abd 100644 > --- a/include/hw/riscv/tt_atlantis.h > +++ b/include/hw/riscv/tt_atlantis.h > @@ -23,6 +23,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisState, > TT_ATLANTIS_MACHINE) > OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisSoCState, TT_ATLANTIS_SOC) > > #define TT_ATL_NUM_I2C 5 > +#define TT_ATL_NUM_UARTS 5 > > struct TTAtlantisSoCState { > /*< private >*/ > @@ -39,7 +40,7 @@ struct TTAtlantisSoCState { > RISCVHartArrayState cpus; > DeviceState *irqchip; > DesignWareI2CState i2c[TT_ATL_NUM_I2C]; > - DW8250State uart1; > + DW8250State uart[TT_ATL_NUM_UARTS]; > MemoryRegion bootrom; > > uint32_t num_harts; > @@ -63,7 +64,11 @@ enum { > TT_ATL_I2C2_IRQ = 35, > TT_ATL_I2C3_IRQ = 36, > TT_ATL_I2C4_IRQ = 37, > + TT_ATL_UART0_IRQ = 38, > TT_ATL_UART1_IRQ = 39, > + TT_ATL_UART2_IRQ = 40, > + TT_ATL_UART3_IRQ = 41, > + TT_ATL_UART4_IRQ = 42, > }; > > enum { > @@ -80,7 +85,11 @@ enum { > TT_ATL_MIMSIC, > TT_ATL_SAPLIC, > TT_ATL_SIMSIC, > + TT_ATL_UART0, > TT_ATL_UART1, > + TT_ATL_UART2, > + TT_ATL_UART3, > + TT_ATL_UART4, > }; > > #endif
