From: Joel Stanley <joel@jms.id.au>
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>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
hw/riscv/Kconfig | 1 +
hw/riscv/tt_atlantis.c | 53 ++++++++++++++++++++++++++++++++++
include/hw/riscv/tt_atlantis.h | 14 +++++++++
3 files changed, 68 insertions(+)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index aaf029c9ed..38180a903f 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -129,6 +129,7 @@ config TENSTORRENT
select RISCV_IMSIC
select SERIAL_MM
select DEVICE_TREE
+ select DESIGNWARE_I2C
config XIANGSHAN_KUNMINGHU
bool
diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index 789a66870a..38be593b18 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -58,6 +58,11 @@ static const MemMapEntry tt_atlantis_memmap[] = {
[TT_ATL_SIMSIC] = { 0xa4000000, 0x200000 },
[TT_ATL_TIMER] = { 0xa8020000, 0x10000 },
[TT_ATL_UART0] = { 0xb0100000, 0x10000 },
+ [TT_ATL_I2C0] = { 0xb0400000, 0x10000 },
+ [TT_ATL_I2C1] = { 0xb0500000, 0x10000 },
+ [TT_ATL_I2C2] = { 0xb0600000, 0x10000 },
+ [TT_ATL_I2C3] = { 0xb0700000, 0x10000 },
+ [TT_ATL_I2C4] = { 0xb0800000, 0x10000 },
[TT_ATL_MAPLIC] = { 0xcc000000, 0x4000000 },
[TT_ATL_SAPLIC] = { 0xe8000000, 0x4000000 },
[TT_ATL_DDR_HI] = { 0x100000000, 0x1000000000 },
@@ -328,10 +333,36 @@ static void create_fdt_uart(void *fdt, const MemMapEntry *mem, int irq,
qemu_fdt_setprop_string(fdt, "/aliases", "serial0", name);
}
+static void create_fdt_clk(void *fdt, const char *name, uint32_t clk_phandle)
+{
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "fixed-clock");
+ qemu_fdt_setprop_cell(fdt, name, "#clock-cells", 0);
+ qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 100000000);
+ qemu_fdt_setprop_cell(fdt, name, "phandle", clk_phandle);
+}
+
+static void create_fdt_i2c(void *fdt, const MemMapEntry *mem, uint32_t irq,
+ uint32_t irqchip_phandle, uint32_t clk_phandle)
+{
+ g_autofree char *name = g_strdup_printf("/soc/i2c@%"HWADDR_PRIX, mem->base);
+
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "snps,designware-i2c");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
+ qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irqchip_phandle);
+ qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x4);
+ qemu_fdt_setprop_cell(fdt, name, "clocks", clk_phandle);
+ qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 100000);
+ qemu_fdt_setprop_cell(fdt, name, "#address-cells", 1);
+ qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0);
+}
+
static void finalize_fdt(TTAtlantisState *s)
{
uint32_t aplic_s_phandle = next_phandle();
uint32_t imsic_s_phandle = next_phandle();
+ uint32_t periph_clk_phandle = next_phandle();
void *fdt = MACHINE(s)->fdt;
create_fdt_cpu(s, s->memmap, aplic_s_phandle, imsic_s_phandle);
@@ -345,6 +376,15 @@ static void finalize_fdt(TTAtlantisState *s)
create_fdt_uart(fdt, &s->memmap[TT_ATL_UART0], TT_ATL_UART0_IRQ,
aplic_s_phandle);
+
+ create_fdt_clk(fdt, "/periph-clk", periph_clk_phandle);
+
+ for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
+ create_fdt_i2c(fdt,
+ &s->memmap[TT_ATL_I2C0 + i],
+ TT_ATL_I2C0_IRQ + i,
+ aplic_s_phandle, periph_clk_phandle);
+ }
}
static void create_fdt(TTAtlantisState *s)
@@ -541,6 +581,19 @@ static void tt_atlantis_machine_init(MachineState *machine)
qdev_get_gpio_in(s->irqchip, TT_ATL_UART0_IRQ),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+ /* I2C */
+ for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
+ object_initialize_child(OBJECT(s), "i2c[*]", &s->i2c[i],
+ TYPE_DESIGNWARE_I2C);
+ sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &error_fatal);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->i2c[i]);
+ memory_region_add_subregion(system_memory,
+ s->memmap[TT_ATL_I2C0 + i].base,
+ sysbus_mmio_get_region(sbd, 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
+ qdev_get_gpio_in(s->irqchip, TT_ATL_I2C0_IRQ + i));
+ }
+
/* Load or create device tree */
if (machine->dtb) {
machine->fdt = load_device_tree(machine->dtb, &s->fdt_size);
diff --git a/include/hw/riscv/tt_atlantis.h b/include/hw/riscv/tt_atlantis.h
index 960dc07841..ddea317409 100644
--- a/include/hw/riscv/tt_atlantis.h
+++ b/include/hw/riscv/tt_atlantis.h
@@ -11,12 +11,15 @@
#include "hw/core/boards.h"
#include "hw/core/sysbus.h"
+#include "hw/i2c/designware_i2c.h"
#include "hw/intc/riscv_imsic.h"
#include "hw/riscv/riscv_hart.h"
#define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisState, TT_ATLANTIS_MACHINE)
+#define TT_ATL_NUM_I2C 5
+
struct TTAtlantisState {
/*< private >*/
MachineState parent;
@@ -27,11 +30,17 @@ struct TTAtlantisState {
RISCVHartArrayState soc;
DeviceState *irqchip;
+ DesignWareI2CState i2c[TT_ATL_NUM_I2C];
int fdt_size;
};
enum {
+ TT_ATL_I2C0_IRQ = 33,
+ TT_ATL_I2C1_IRQ = 34,
+ TT_ATL_I2C2_IRQ = 35,
+ TT_ATL_I2C3_IRQ = 36,
+ TT_ATL_I2C4_IRQ = 37,
TT_ATL_UART0_IRQ = 38,
};
@@ -40,6 +49,11 @@ enum {
TT_ATL_BOOTROM,
TT_ATL_DDR_LO,
TT_ATL_DDR_HI,
+ TT_ATL_I2C0,
+ TT_ATL_I2C1,
+ TT_ATL_I2C2,
+ TT_ATL_I2C3,
+ TT_ATL_I2C4,
TT_ATL_MAPLIC,
TT_ATL_MIMSIC,
TT_ATL_SAPLIC,
--
2.53.0