On 9/29/2026 12:16 AM, [email protected] wrote:
From: Portia Stephens <[email protected]>

Replace the ns16550 UART with a Designware UART now that a model is
available. The hack which sets the rest of the UART register space as
unimplemented can be removed.

Signed-off-by: Portia Stephens <[email protected]>
---
  hw/riscv/Kconfig               |  2 +-
  hw/riscv/tt_atlantis.c         | 41 +++++++++-------------------------
  include/hw/riscv/tt_atlantis.h |  4 ++--
  3 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index d06ac26648..5d2abdbb67 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -127,7 +127,7 @@ config TENSTORRENT
      select RISCV_ACLINT
      select RISCV_APLIC
      select RISCV_IMSIC
-    select SERIAL_MM
+    select DW8250
      select DEVICE_TREE
      select DESIGNWARE_I2C
      select DS1338
diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index 8a219afef7..e889951677 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -24,7 +24,7 @@
  #include "hw/riscv/fdt-common.h"
  #include "hw/riscv/riscv_hart.h"
-#include "hw/char/serial-mm.h"
+#include "hw/char/dw8250.h"
  #include "hw/intc/riscv_aclint.h"
  #include "hw/misc/unimp.h"
@@ -262,11 +262,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)
  {
+    static const char compat[] = "snps,dw-apb-uart\0ns16550a";
      g_autofree char *name = g_strdup_printf("/soc/serial@%"HWADDR_PRIX,
                                              mem->base);
qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
+    qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));

We have some instances of a string array being declared with 
qemu_fdt_setprop(), and this
works as long as the compat string has NULL chars between the strings.

However I suggest using qemu_fdt_setprop_string_array() instead like we're 
doing in newer
FDT code.  It's a bit easier to read and debug than dealing with \0 in the 
middle of the
char array.

Here's an example from fdt-common.c:


        static const char * const compat[3] = {
            "sifive,test1", "sifive,test0", "syscon"
        };

        qemu_fdt_setprop_string_array(fdt, name, "compatible",
                                      (char **)&compat, ARRAY_SIZE(compat));

In your case this would be:


        static const char * const compat[2] = {
            "snps,dw-apb-uart", "ns16550a"
        };
        (...)
        qemu_fdt_setprop_string_array(fdt, name, "compatible",
                                      (char **)&compat, ARRAY_SIZE(compat));


Thanks,
Daniel

      qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, 
mem->size);
      qemu_fdt_setprop_cell(fdt, name, "reg-shift", 2);
      qemu_fdt_setprop_cell(fdt, name, "reg-io-width", 4);
@@ -409,17 +410,6 @@ static void load_fdt(TTAtlantisState *ams)
      create_fdt_memory(ms->fdt, &ams->soc);
  }
-static void mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev,
-                                   const char *name, hwaddr addr, uint64_t 
size)
-{
-    qdev_prop_set_string(DEVICE(dev), "name", name);
-    qdev_prop_set_uint64(DEVICE(dev), "size", size);
-    sysbus_realize(dev, &error_abort);
-
-    memory_region_add_subregion_overlap(memory, addr,
-                                        sysbus_mmio_get_region(dev, 0), -1000);
-}
-
  static void tt_atlantis_machine_done(Notifier *n, void *data)
  {
      TTAtlantisState *ams = container_of(n, TTAtlantisState, machine_done);
@@ -488,8 +478,7 @@ static void tt_atlantis_soc_init(Object *obj)
object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); - object_initialize_child(obj, "uart1", &s->uart1,
-                            TYPE_UNIMPLEMENTED_DEVICE);
+    object_initialize_child(obj, "uart1", &s->uart1, TYPE_DW8250);
for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
          object_initialize_child(obj, "i2c[*]", &s->i2c[i],
@@ -584,21 +573,13 @@ static void tt_atlantis_soc_realize(DeviceState *dev, 
Error **errp)
                                  &s->bootrom);
/* UART1, the soc console (UART0 is for the boot microcontroller) */
-    serial_mm_init(s->memory, s->memmap[TT_ATL_UART1].base, 2,
-                   qdev_get_gpio_in(s->irqchip, TT_ATL_UART1_IRQ),
-                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
-    /*
-     * Atlantis contains a DesignWare uart while the QEMU machine
-     * uses the serial_mm model with the base ns16550 register set.
-     * Linux's dw driver writes outside of serial_mm's 0x20 sized
-     * mapping and faults.
-     *
-     * Create an unimplemented device region so writes don't fault
-     * and reads return zero, which keeps Linux happy.
-     */
-    mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->uart1),
-                           "tt-atlantis.uart1", s->memmap[TT_ATL_UART1].base,
-                           s->memmap[TT_ATL_UART1].size);
+    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));
/* 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 3923308b7c..000988c037 100644
--- a/include/hw/riscv/tt_atlantis.h
+++ b/include/hw/riscv/tt_atlantis.h
@@ -13,7 +13,7 @@
  #include "hw/core/sysbus.h"
  #include "hw/i2c/designware_i2c.h"
  #include "hw/intc/riscv_imsic.h"
-#include "hw/misc/unimp.h"
+#include "hw/char/dw8250.h"
  #include "hw/riscv/riscv_hart.h"
#define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
@@ -39,7 +39,7 @@ struct TTAtlantisSoCState {
      RISCVHartArrayState cpus;
      DeviceState *irqchip;
      DesignWareI2CState i2c[TT_ATL_NUM_I2C];
-    UnimplementedDeviceState uart1;
+    DW8250State uart1;
      MemoryRegion bootrom;
uint32_t num_harts;


Reply via email to