@samitouri / QOSamiQemu / commits / 30b505c451

hw/riscv/atlantis: Integrate i2c controllers

Add DesignWare I2C controllers to the tt-atlantis machine. Provide a fixed clock in the device tree so that the Linux driver probes without WARNing. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Acked-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20260630024952.1520546-12-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Joel Stanley committed Jun 30, 2026 at 12:19 UTC 30b505c4512287488f320e8f66eb17a10681aef1
3 files changed +74
hw/riscv/Kconfig
+1
@@ -129,6 +129,7 @@ config TENSTORRENT
129 select RISCV_IMSIC
130 select SERIAL_MM
131 select DEVICE_TREE
132 + select DESIGNWARE_I2C
133
134 config XIANGSHAN_KUNMINGHU
135 bool
hw/riscv/tt_atlantis.c
+59
@@ -54,6 +54,11 @@ static const MemMapEntry tt_atlantis_memmap[] = {
54 [TT_ATL_ACLINT] = { 0xa2180000, 0x10000 },
55 [TT_ATL_SIMSIC] = { 0xa4000000, 0x200000 },
56 [TT_ATL_MAPLIC] = { 0xcc000000, 0x4000000 },
57 + [TT_ATL_I2C0] = { 0xd4040000, 0x10000 },
58 + [TT_ATL_I2C1] = { 0xd4050000, 0x10000 },
59 + [TT_ATL_I2C2] = { 0xd4060000, 0x10000 },
60 + [TT_ATL_I2C3] = { 0xd4070000, 0x10000 },
61 + [TT_ATL_I2C4] = { 0xd4080000, 0x10000 },
62 [TT_ATL_UART1] = { 0xd4110000, 0x10000 },
63 [TT_ATL_SAPLIC] = { 0xe8000000, 0x4000000 },
64 [TT_ATL_DDR_HI] = { 0x100000000, 0x1000000000 },
@@ -275,10 +280,40 @@ static void create_fdt_rng(void *fdt)
280 qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
281 }
282
283 +static void create_fdt_clk(void *fdt, const char *clock_name,
284 + uint32_t freq, uint32_t phandle)
285 +{
286 + g_autofree char *name = g_strdup_printf("/clocks/%s", clock_name);
287 +
288 + qemu_fdt_add_path(fdt, name);
289 + qemu_fdt_setprop_string(fdt, name, "compatible", "fixed-clock");
290 + qemu_fdt_setprop_string(fdt, name, "clock-output-names", clock_name);
291 + qemu_fdt_setprop_cell(fdt, name, "#clock-cells", 0);
292 + qemu_fdt_setprop_cell(fdt, name, "clock-frequency", freq);
293 + qemu_fdt_setprop_cell(fdt, name, "phandle", phandle);
294 +}
295 +
296 +static void create_fdt_i2c(void *fdt, const MemMapEntry *mem, uint32_t irq,
297 + uint32_t irqchip_phandle, uint32_t clk_phandle)
298 +{
299 + g_autofree char *name = g_strdup_printf("/soc/i2c@%"HWADDR_PRIX, mem->base);
300 +
301 + qemu_fdt_add_subnode(fdt, name);
302 + qemu_fdt_setprop_string(fdt, name, "compatible", "snps,designware-i2c");
303 + qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
304 + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irqchip_phandle);
305 + qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x4);
306 + qemu_fdt_setprop_cell(fdt, name, "clocks", clk_phandle);
307 + qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 100000);
308 + qemu_fdt_setprop_cell(fdt, name, "#address-cells", 1);
309 + qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0);
310 +}
311 +
312 static void finalize_fdt(TTAtlantisState *s)
313 {
314 uint32_t aplic_s_phandle = next_phandle();
315 uint32_t imsic_s_phandle = next_phandle();
316 + uint32_t periph_clk_phandle = next_phandle();
317 void *fdt = MACHINE(s)->fdt;
318
319 create_fdt_cpu(s, s->memmap, aplic_s_phandle, imsic_s_phandle);
@@ -292,6 +327,15 @@ static void finalize_fdt(TTAtlantisState *s)
327
328 create_fdt_uart(fdt, &s->memmap[TT_ATL_UART1], TT_ATL_UART1_IRQ,
329 aplic_s_phandle);
330 +
331 + create_fdt_clk(fdt, "periph-clk", 100000000, periph_clk_phandle);
332 +
333 + for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
334 + create_fdt_i2c(fdt,
335 + &s->memmap[TT_ATL_I2C0 + i],
336 + TT_ATL_I2C0_IRQ + i,
337 + aplic_s_phandle, periph_clk_phandle);
338 + }
339 }
340
341 static void create_fdt(TTAtlantisState *s)
@@ -492,6 +536,21 @@ static void tt_atlantis_machine_init(MachineState *machine)
536 s->memmap[TT_ATL_UART1].base,
537 s->memmap[TT_ATL_UART1].size);
538
539 + /* I2C */
540 + for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
541 + SysBusDevice *sbd;
542 +
543 + object_initialize_child(OBJECT(s), "i2c[*]", &s->i2c[i],
544 + TYPE_DESIGNWARE_I2C);
545 + sbd = SYS_BUS_DEVICE(&s->i2c[i]);
546 + sysbus_realize(sbd, &error_fatal);
547 + memory_region_add_subregion(system_memory,
548 + s->memmap[TT_ATL_I2C0 + i].base,
549 + sysbus_mmio_get_region(sbd, 0));
550 + sysbus_connect_irq(sbd, 0,
551 + qdev_get_gpio_in(s->irqchip, TT_ATL_I2C0_IRQ + i));
552 + }
553 +
554 /* Load or create device tree */
555 if (machine->dtb) {
556 load_fdt(s);
include/hw/riscv/tt_atlantis.h
+14
@@ -11,12 +11,15 @@
11
12 #include "hw/core/boards.h"
13 #include "hw/core/sysbus.h"
14 +#include "hw/i2c/designware_i2c.h"
15 #include "hw/intc/riscv_imsic.h"
16 #include "hw/riscv/riscv_hart.h"
17
18 #define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
19 OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisState, TT_ATLANTIS_MACHINE)
20
21 +#define TT_ATL_NUM_I2C 5
22 +
23 struct TTAtlantisState {
24 /*< private >*/
25 MachineState parent;
@@ -27,11 +30,17 @@ struct TTAtlantisState {
30
31 RISCVHartArrayState soc;
32 DeviceState *irqchip;
33 + DesignWareI2CState i2c[TT_ATL_NUM_I2C];
34
35 int fdt_size;
36 };
37
38 enum {
39 + TT_ATL_I2C0_IRQ = 33,
40 + TT_ATL_I2C1_IRQ = 34,
41 + TT_ATL_I2C2_IRQ = 35,
42 + TT_ATL_I2C3_IRQ = 36,
43 + TT_ATL_I2C4_IRQ = 37,
44 TT_ATL_UART1_IRQ = 39,
45 };
46
@@ -40,6 +49,11 @@ enum {
49 TT_ATL_BOOTROM,
50 TT_ATL_DDR_LO,
51 TT_ATL_DDR_HI,
52 + TT_ATL_I2C0,
53 + TT_ATL_I2C1,
54 + TT_ATL_I2C2,
55 + TT_ATL_I2C3,
56 + TT_ATL_I2C4,
57 TT_ATL_MAPLIC,
58 TT_ATL_MIMSIC,
59 TT_ATL_SAPLIC,