From: Portia Stephens <[email protected]> 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]> --- 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 e889951677..d567ec1155 100644 --- a/hw/riscv/tt_atlantis.c +++ b/hw/riscv/tt_atlantis.c @@ -63,7 +63,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 }, }; @@ -260,11 +264,12 @@ 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 compat[] = "snps,dw-apb-uart\0ns16550a"; 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(fdt, name, "compatible", compat, sizeof(compat)); @@ -275,8 +280,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) @@ -345,8 +352,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++) { + 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); @@ -472,13 +482,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(OBJECT(s), "uart[*]", &s->uart[i], + TYPE_DW8250); + } for (int i = 0; i < TT_ATL_NUM_I2C; i++) { object_initialize_child(obj, "i2c[*]", &s->i2c[i], @@ -572,14 +590,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 -- 2.43.0
