On Thu, 2026-10-08 at 09:02 +1000, Portia Stephens wrote:
>
> On 6/10/2026 11:35 PM, Alistair wrote:
> > On Fri, 2026-10-02 at 09:33 +1000, Portia Stephens wrote:
> > > The Atlantis SoC has 5 UARTs. This adds a machine property to set
> > > which uart is on the first serial interface. This is the same
> > > pattern
> > > that is used by aspeed. The rest of the uart's will be added in
> > > sequential order starting at serial interface 1.
> > >
> > > The default value is uart1 which means the Ascalon console will
> > > be on
> > > serial interface 0 by default.
> > >
> > > Signed-off-by: Portia Stephens <[email protected]>
> > > Reviewed-by: Daniel Henrique Barboza
> > > <[email protected]>
> > > ---
> > > hw/riscv/tt_atlantis.c | 77
> > > ++++++++++++++++++++++++++++++--
> > > --
> > > include/hw/riscv/tt_atlantis.h | 1 +
> > > 2 files changed, 69 insertions(+), 9 deletions(-)
> > >
> > > diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
> > > index 2342edce93..7a5e1ddcd1 100644
> > > --- a/hw/riscv/tt_atlantis.c
> > > +++ b/hw/riscv/tt_atlantis.c
> > > @@ -12,6 +12,7 @@
> > > #include "qemu/error-report.h"
> > > #include "qemu/guest-random.h"
> > > #include "qemu/units.h"
> > > +#include "qapi/visitor.h"
> > >
> > > #include "hw/core/boards.h"
> > > #include "hw/core/loader.h"
> > > @@ -422,6 +423,26 @@ static void load_fdt(TTAtlantisState *ams)
> > > create_fdt_memory(ms->fdt, &ams->soc);
> > > }
> > >
> > > +static inline int tt_atlantis_uart_index(int uart_dev)
> > > +{
> > > + return uart_dev - TT_ATL_UART0;
> > > +}
> > > +
> > > +static void
> > > tt_atlantis_connect_serial_hds_to_uarts(TTAtlantisState
> > > *ams)
> > > +{
> > > + TTAtlantisSoCState *s = &ams->soc;
> > > + int uart_index = tt_atlantis_uart_index(ams->uart_chosen);
> > > +
> > > + qdev_prop_set_chr(DEVICE(&s->uart[uart_index]), "chardev",
> > > serial_hd(0));
> > > +
> > > + for (int i = 1, uart = 0; i < TT_ATL_NUM_UARTS; uart++) {
> > > + if (uart == uart_index) {
> > > + continue;
> > > + }
> > > + qdev_prop_set_chr(DEVICE(&s->uart[uart]), "chardev",
> > > serial_hd(i++));
> > > + }
> > I don't like this. We shouldn't dynamically change the command line
> > API
> > based on a property
>
>
> Fair enough, can we just take the first 3 patches in the series and
> drop
> this one? That will add modeling for all the uarts but only expose
> uart1
> on command line.
This is path 3 though. Do you mean take the first 2 patches?
I can do that if you want
Alistair
>
>
> We will expose the remaining uarts as features as added to the model
> that produce output that anyone would care to look at. For example,
> uart0 is the system controller's console, when the system controller
> is
> added to the model then we will expose uart0 on the command line.
> This
> will prevent us from locking into a command line API before we need
> to.
>
>
>
> >
> > Alistair
> >
> > > +}
> > > +
> > > static void tt_atlantis_machine_done(Notifier *n, void *data)
> > > {
> > > TTAtlantisState *ams = container_of(n, TTAtlantisState,
> > > machine_done);
> > > @@ -484,11 +505,6 @@ 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);
> > > @@ -592,10 +608,6 @@ 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-
> > > > 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)) {
> > > @@ -663,6 +675,10 @@ static void
> > > tt_atlantis_machine_init(MachineState *machine)
> > > OBJECT(&ams->soc_memory),
> > > &error_abort);
> > > object_property_set_link(OBJECT(&ams->soc), "dram",
> > > OBJECT(machine->ram),
> > > &error_abort);
> > > +
> > > + /* Map serial interfaces to uart */
> > > + tt_atlantis_connect_serial_hds_to_uarts(ams);
> > > +
> > > qdev_realize(DEVICE(&ams->soc), NULL, &error_fatal);
> > >
> > > /* I2C peripherals: qemu specific */
> > > @@ -680,6 +696,47 @@ static void
> > > tt_atlantis_machine_init(MachineState *machine)
> > > qemu_add_machine_init_done_notifier(&ams->machine_done);
> > > }
> > >
> > > +static void tt_atlantis_get_console(Object *obj, Visitor *v,
> > > const
> > > char *name,
> > > + void *opaque, Error **errp)
> > > +{
> > > + TTAtlantisState *ams = TT_ATLANTIS_MACHINE(obj);
> > > + uint32_t uart_index = tt_atlantis_uart_index(ams-
> > > >uart_chosen);
> > > +
> > > + visit_type_uint32(v, name, &uart_index, errp);
> > > +}
> > > +
> > > +static void tt_atlantis_set_console(Object *obj, Visitor *v,
> > > const
> > > char *name,
> > > + void *opaque, Error **errp)
> > > +{
> > > + TTAtlantisState *ams = TT_ATLANTIS_MACHINE(obj);
> > > + uint32_t value;
> > > +
> > > + if (!visit_type_uint32(v, name, &value, errp)) {
> > > + return;
> > > + }
> > > +
> > > + if (value >= TT_ATL_NUM_UARTS) {
> > > + error_setg(errp, "\"console\" should be in range [%d -
> > > %d]",
> > > + 0, TT_ATL_NUM_UARTS - 1);
> > > + return;
> > > + }
> > > + ams->uart_chosen = value + TT_ATL_UART0;
> > > +}
> > > +
> > > +static void tt_atlantis_machine_class_props_init(ObjectClass
> > > *oc)
> > > +{
> > > + ObjectProperty *console;
> > > +
> > > + console = object_class_property_add(oc, "console",
> > > "uint32_t",
> > > + tt_atlantis_get_console,
> > > + tt_atlantis_set_console,
> > > NULL, NULL);
> > > + object_class_property_set_description(oc, "console",
> > > + "Change the default UART index on -serial. Valid
> > > values
> > > are 0 " \
> > > + "through 4");
> > > + /* Default to UART1, the Ascalon console */
> > > + object_property_set_default_uint(console, 1);
> > > +}
> > > +
> > > static void tt_atlantis_machine_class_init(ObjectClass *oc,
> > > const
> > > void *data)
> > > {
> > > MachineClass *mc = MACHINE_CLASS(oc);
> > > @@ -693,6 +750,8 @@ static void
> > > tt_atlantis_machine_class_init(ObjectClass *oc, const void *data)
> > > mc->block_default_type = IF_VIRTIO;
> > > mc->no_cdrom = 1;
> > > mc->default_ram_id = "tt_atlantis.ram";
> > > +
> > > + tt_atlantis_machine_class_props_init(oc);
> > > }
> > >
> > > static const TypeInfo tt_atlantis_types[] = {
> > > diff --git a/include/hw/riscv/tt_atlantis.h
> > > b/include/hw/riscv/tt_atlantis.h
> > > index b81b7c8abd..7bd46e9c9b 100644
> > > --- a/include/hw/riscv/tt_atlantis.h
> > > +++ b/include/hw/riscv/tt_atlantis.h
> > > @@ -56,6 +56,7 @@ struct TTAtlantisState {
> > >
> > > MemoryRegion soc_memory;
> > > TTAtlantisSoCState soc;
> > > + uint32_t uart_chosen;
> > > };
> > >
> > > enum {