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

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 {

Reply via email to