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.


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 {

Reply via email to