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