[PATCH v2 5/6] hw/arm: Add Axiado SoC AX3005
Kuan-Jui Chiu <[email protected]>
| Newsgroups | org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
This patch adds new model for Axiado SoC AX3005 which supports
4 Cortex-A53 ARM64 CPUs
Arm Generic Interrupt Controller v3
9 Cadence UARTs
1 SDHCI controller with PHY
8 Cadence GPIOs
Signed-off-by: Kuan-Jui Chiu <[email protected]>
---
MAINTAINERS | 2 +
hw/arm/ax3005-soc.c | 225 ++++++++++++++++++++++++++++++++++++
hw/arm/meson.build | 3 +-
include/hw/arm/ax3005-soc.h | 102 ++++++++++++++++
4 files changed, 331 insertions(+), 1 deletion(-)
create mode 100644 hw/arm/ax3005-soc.c
create mode 100644 include/hw/arm/ax3005-soc.h
diff --git a/MAINTAINERS b/MAINTAINERS
index b51f5c3e60..cb542ad591 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1312,8 +1312,10 @@ M: Kuan-Jui Chiu <[email protected]>
L: [email protected]
S: Maintained
F: hw/arm/ax3000*.c
+F: hw/arm/ax3005*.c
F: hw/*/axiado*.c
F: include/hw/arm/ax3000*.h
+F: include/hw/arm/ax3005*.h
F: include/hw/*/axiado*.h
AVR Machines
diff --git a/hw/arm/ax3005-soc.c b/hw/arm/ax3005-soc.c
new file mode 100644
index 0000000000..c4abac17d0
--- /dev/null
+++ b/hw/arm/ax3005-soc.c
@@ -0,0 +1,225 @@
+/*
+ * Axiado SoC AX3005
+ *
+ * Author: Kuan-Jui Chiu <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/address-spaces.h"
+#include "hw/arm/bsa.h"
+#include "hw/arm/ax3005-soc.h"
+#include "hw/misc/unimp.h"
+#include "system/system.h"
+#include "qobject/qlist.h"
+#include "qom/object.h"
+#include "hw/core/boards.h"
+
+static void ax3005_init(Object *obj)
+{
+ Ax3005SoCState *s = AX3005_SOC(obj);
+ Ax3005SoCClass *sc = AX3005_SOC_GET_CLASS(s);
+
+ for (int i = 0; i < sc->num_cpus; i++) {
+ g_autofree char *name = g_strdup_printf("cpu%d", i);
+ object_initialize_child(obj, name, &s->cpu[i],
+ ARM_CPU_TYPE_NAME("cortex-a53"));
+ }
+
+ object_initialize_child(obj, "gic", &s->gic, gicv3_class_name());
+
+ for (int i = 0; i < AX3005_NUM_UARTS; i++) {
+ g_autofree char *name = g_strdup_printf("uart%d", i);
+ object_initialize_child(obj, name, &s->uart[i], TYPE_CADENCE_UART);
+ }
+
+ object_initialize_child(obj, "sdhci0", &s->sdhci0, TYPE_AXIADO_SDHCI);
+
+ for (int i = 0; i < AX3005_NUM_GPIOS; i++) {
+ g_autofree char *name = g_strdup_printf("gpio%d", i);
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_CADENCE_GPIO);
+ }
+}
+
+static void ax3005_realize(DeviceState *dev, Error **errp)
+{
+ Ax3005SoCState *s = AX3005_SOC(dev);
+ Ax3005SoCClass *sc = AX3005_SOC_GET_CLASS(s);
+ SysBusDevice *gic_sbd = SYS_BUS_DEVICE(&s->gic);
+ DeviceState *gic_dev = DEVICE(&s->gic);
+ QList *redist_region_count;
+ SysBusDevice *sdhci0_sbd;
+ DeviceState *card;
+ DriveInfo *dinfo;
+
+ /* CPUs */
+ for (int i = 0; i < sc->num_cpus; i++) {
+ object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 1000000000,
+ &error_abort);
+
+ if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
+ return;
+ }
+ }
+
+ /* GIC */
+ qdev_prop_set_uint32(gic_dev, "num-cpu", sc->num_cpus);
+ qdev_prop_set_uint32(gic_dev, "num-irq",
+ AX3005_NUM_IRQS + GIC_INTERNAL);
+
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, sc->num_cpus);
+ qdev_prop_set_array(gic_dev, "redist-region-count", redist_region_count);
+
+ if (!sysbus_realize(gic_sbd, errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(gic_sbd, 0, AX3005_GIC_DIST_BASE);
+ sysbus_mmio_map(gic_sbd, 1, AX3005_GIC_REDIST_BASE);
+
+ /*
+ * Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs.
+ */
+ const int timer_irqs[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ
+ };
+
+ /*
+ * Wire the outputs from each CPU's generic timer and the GICv3
+ * maintenance interrupt signal to the appropriate GIC PPI inputs, and
+ * the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs.
+ */
+ for (int i = 0; i < sc->num_cpus; i++) {
+ DeviceState *cpu_dev = DEVICE(&s->cpu[i]);
+ int intidbase = AX3005_NUM_IRQS + i * GIC_INTERNAL;
+ qemu_irq irq;
+
+ for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) {
+ irq = qdev_get_gpio_in(gic_dev, intidbase + timer_irqs[j]);
+ qdev_connect_gpio_out(cpu_dev, j, irq);
+ }
+
+ irq = qdev_get_gpio_in(gic_dev, intidbase + ARCH_GIC_MAINT_IRQ);
+ qdev_connect_gpio_out_named(cpu_dev, "gicv3-maintenance-interrupt",
+ 0, irq);
+
+ sysbus_connect_irq(gic_sbd, i,
+ qdev_get_gpio_in(cpu_dev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gic_sbd, i + sc->num_cpus,
+ qdev_get_gpio_in(cpu_dev, ARM_CPU_FIQ));
+ sysbus_connect_irq(gic_sbd, i + 2 * sc->num_cpus,
+ qdev_get_gpio_in(cpu_dev, ARM_CPU_VIRQ));
+ sysbus_connect_irq(gic_sbd, i + 3 * sc->num_cpus,
+ qdev_get_gpio_in(cpu_dev, ARM_CPU_VFIQ));
+ }
+
+ /* DRAM */
+ memory_region_init_ram(&s->dram, OBJECT(s), "dram", AX3005_DRAM_SIZE,
+ &error_fatal);
+ memory_region_add_subregion(get_system_memory(), AX3005_DRAM_BASE,
+ &s->dram);
+
+ /* UARTs */
+ const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[] = {
+ { AX3005_UART0_BASE, AX3005_UART0_IRQ },
+ { AX3005_UART1_BASE, AX3005_UART1_IRQ },
+ { AX3005_UART2_BASE, AX3005_UART2_IRQ },
+ { AX3005_UART3_BASE, AX3005_UART3_IRQ },
+ { AX3005_UART4_BASE, AX3005_UART4_IRQ },
+ { AX3005_UART5_BASE, AX3005_UART5_IRQ },
+ { AX3005_UART6_BASE, AX3005_UART6_IRQ },
+ { AX3005_UART7_BASE, AX3005_UART7_IRQ },
+ { AX3005_UART8_BASE, AX3005_UART8_IRQ }
+ };
+
+ for (int i = 0; i < AX3005_NUM_UARTS; i++) {
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+ qdev_get_gpio_in(gic_dev, serial_table[i].irq));
+ }
+
+ /* Timer control */
+ create_unimplemented_device("ax3005.timerctrl", AX3005_TIMER_CTRL, 32);
+
+ /* SDHCI */
+ sdhci0_sbd = SYS_BUS_DEVICE(&s->sdhci0);
+ if (!sysbus_realize(sdhci0_sbd, errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(sdhci0_sbd, 0, AX3005_SDHCI0_BASE);
+ sysbus_mmio_map(sdhci0_sbd, 1, AX3005_EMMC_PHY_BASE);
+ sysbus_connect_irq(sdhci0_sbd, 0,
+ qdev_get_gpio_in(gic_dev, AX3005_SDHCI0_IRQ));
+
+ dinfo = drive_get(IF_SD, 0, 0);
+ if (dinfo) {
+ card = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(card, "drive",
+ blk_by_legacy_dinfo(dinfo),
+ &error_fatal);
+ qdev_realize_and_unref(card, s->sdhci0.sd_bus, &error_fatal);
+ }
+
+ /* GPIOs */
+ const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } gpio_table[] = {
+ { AX3005_GPIO0_BASE, AX3005_GPIO0_IRQ },
+ { AX3005_GPIO1_BASE, AX3005_GPIO1_IRQ },
+ { AX3005_GPIO2_BASE, AX3005_GPIO2_IRQ },
+ { AX3005_GPIO3_BASE, AX3005_GPIO3_IRQ },
+ { AX3005_GPIO4_BASE, AX3005_GPIO4_IRQ },
+ { AX3005_GPIO5_BASE, AX3005_GPIO5_IRQ },
+ { AX3005_GPIO6_BASE, AX3005_GPIO6_IRQ },
+ { AX3005_GPIO7_BASE, AX3005_GPIO7_IRQ }
+ };
+
+ for (int i = 0; i < AX3005_NUM_GPIOS; i++) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(gic_dev, gpio_table[i].irq));
+ }
+}
+
+static void ax3005_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ Ax3005SoCClass *sc = AX3005_SOC_CLASS(oc);
+
+ dc->desc = "Axiado SoC AX3005";
+ dc->realize = ax3005_realize;
+ sc->num_cpus = AX3005_NUM_CPUS;
+}
+
+static const TypeInfo ax3005_soc_types[] = {
+ {
+ .name = TYPE_AX3005_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Ax3005SoCState),
+ .instance_init = ax3005_init,
+ .class_size = sizeof(Ax3005SoCClass),
+ .class_init = ax3005_class_init,
+ }
+};
+
+DEFINE_TYPES(ax3005_soc_types)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index 8ee5307a91..9fceb8d2e7 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -111,7 +111,8 @@ arm_common_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
arm_common_ss.add(when: ['CONFIG_AXIADO_SOC', 'TARGET_AARCH64'], if_true: files(
- 'ax3000-soc.c'))
+ 'ax3000-soc.c',
+ 'ax3005-soc.c'))
arm_common_ss.add(when: ['CONFIG_AXIADO_EVK', 'TARGET_AARCH64'], if_true: files(
'ax3000-boards.c',
'ax3000-evk.c'))
diff --git a/include/hw/arm/ax3005-soc.h b/include/hw/arm/ax3005-soc.h
new file mode 100644
index 0000000000..2a383a8084
--- /dev/null
+++ b/include/hw/arm/ax3005-soc.h
@@ -0,0 +1,102 @@
+/*
+ * Axiado SoC AX3005
+ *
+ * Author: Kuan-Jui Chiu <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef AXIADO_AX3005_H
+#define AXIADO_AX3005_H
+
+#include "cpu.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "hw/char/cadence_uart.h"
+#include "hw/gpio/cadence_gpio.h"
+#include "hw/sd/axiado_sdhci.h"
+#include "hw/core/sysbus.h"
+#include "qemu/units.h"
+
+#define TYPE_AX3005_SOC "ax3005"
+OBJECT_DECLARE_TYPE(Ax3005SoCState, Ax3005SoCClass, AX3005_SOC)
+
+#define AX3005_DRAM_BASE 0x80000000
+#define AX3005_DRAM_SIZE (2 * GiB)
+
+#define AX3005_GIC_DIST_BASE 0x40400000
+#define AX3005_GIC_DIST_SIZE (64 * KiB)
+#define AX3005_GIC_REDIST_BASE 0x40500000
+#define AX3005_GIC_REDIST_SIZE (768 * KiB)
+
+#define AX3005_UART0_BASE 0x33020000
+#define AX3005_UART1_BASE 0x330A0000
+#define AX3005_UART2_BASE 0x33120000
+#define AX3005_UART3_BASE 0x33020800
+#define AX3005_UART4_BASE 0x331A0400
+#define AX3005_UART5_BASE 0x33381D00
+#define AX3005_UART6_BASE 0x33381E00
+#define AX3005_UART7_BASE 0x33381F00
+#define AX3005_UART8_BASE 0x330C0000
+
+#define AX3005_SDHCI0_BASE 0x46000000
+#define AX3005_EMMC_PHY_BASE 0x33301C00
+
+#define AX3005_GPIO0_BASE 0x33000000
+#define AX3005_GPIO1_BASE 0x33080000
+#define AX3005_GPIO2_BASE 0x33100000
+#define AX3005_GPIO3_BASE 0x33180000
+#define AX3005_GPIO4_BASE 0x33200000
+#define AX3005_GPIO5_BASE 0x33280000
+#define AX3005_GPIO6_BASE 0x33300000
+#define AX3005_GPIO7_BASE 0x33380000
+
+#define AX3005_TIMER_CTRL 0x48016000
+
+enum Ax3005Configuration {
+ AX3005_NUM_CPUS = 4,
+ AX3005_NUM_IRQS = 224,
+ AX3005_NUM_UARTS = 9,
+ AX3005_NUM_GPIOS = 8,
+};
+
+typedef struct Ax3005SoCState {
+ SysBusDevice parent;
+
+ ARMCPU cpu[AX3005_NUM_CPUS];
+ GICv3State gic;
+ MemoryRegion dram;
+ CadenceUARTState uart[AX3005_NUM_UARTS];
+ CadenceGPIOState gpio[AX3005_NUM_GPIOS];
+ AxiadoSDHCIState sdhci0;
+} Ax3005SoCState;
+
+typedef struct Ax3005SoCClass {
+ SysBusDeviceClass parent;
+
+ uint32_t num_cpus;
+} Ax3005SoCClass;
+
+enum Ax3005Irqs {
+ AX3005_UART0_IRQ = 112,
+ AX3005_UART1_IRQ = 113,
+ AX3005_UART2_IRQ = 114,
+ AX3005_UART3_IRQ = 170,
+ AX3005_UART4_IRQ = 208,
+ AX3005_UART5_IRQ = 209,
+ AX3005_UART6_IRQ = 210,
+ AX3005_UART7_IRQ = 211,
+ AX3005_UART8_IRQ = 212,
+
+ AX3005_SDHCI0_IRQ = 123,
+
+ AX3005_GPIO0_IRQ = 183,
+ AX3005_GPIO1_IRQ = 184,
+ AX3005_GPIO2_IRQ = 185,
+ AX3005_GPIO3_IRQ = 186,
+ AX3005_GPIO4_IRQ = 187,
+ AX3005_GPIO5_IRQ = 188,
+ AX3005_GPIO6_IRQ = 189,
+ AX3005_GPIO7_IRQ = 190,
+};
+
+#endif /* AXIADO_AX3005_H */
--
2.34.1