On 14/10/2026 12:40 PM, Alistair wrote:
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?


Yes but the documentation needs to be updated as well. I'll send a v4.



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 {

Reply via email to