From: Kuan-Jui Chiu <kchiu@axiado.com>
To: qemu-devel@nongnu.org, peter.maydell@linaro.org
Cc: Kuan-Jui Chiu <kchiu@axiado.com>
Subject: [PATCH v1 4/5] hw/arm: Add Axiado SoC AX3005
Date: Thu, 20 Aug 2026 03:21:31 -0700 [thread overview]
Message-ID: <20260820102132.361642-5-kchiu@axiado.com> (raw)
In-Reply-To: <20260820102132.361642-1-kchiu@axiado.com>
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 <kchiu@axiado.com>
---
MAINTAINERS | 2 +
hw/arm/ax3005-soc.c | 224 ++++++++++++++++++++++++++++++++++++
hw/arm/meson.build | 3 +-
include/hw/arm/ax3005-soc.h | 102 ++++++++++++++++
4 files changed, 330 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 <kchiu@axiado.com>
L: qemu-arm@nongnu.org
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..e8a91bceb6
--- /dev/null
+++ b/hw/arm/ax3005-soc.c
@@ -0,0 +1,224 @@
+/*
+ * Axiado SoC AX3005
+ *
+ * Author: Kuan-Jui Chiu <kchiu@axiado.com>
+ *
+ * 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_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 <kchiu@axiado.com>
+ *
+ * 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
next prev parent reply other threads:[~2026-08-20 10:27 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-20 10:21 [PATCH v1 0/5] Add Axiado SoC AX3005 and EVB Kuan-Jui Chiu
2026-08-20 10:21 ` [PATCH v1 1/5] hw/sd/axiado_sdhci: Add header guard Kuan-Jui Chiu
2026-08-20 10:21 ` [PATCH v1 2/5] hw/arm: Rename ax3000-boards as axiado-boards Kuan-Jui Chiu
2026-08-20 10:21 ` [PATCH v1 3/5] hw/arm/ax3000: Specify SoC name in header and variable Kuan-Jui Chiu
2026-08-20 10:21 ` Kuan-Jui Chiu [this message]
2026-08-23 10:33 ` [PATCH v1 4/5] hw/arm: Add Axiado SoC AX3005 Jack Wang
2026-08-24 1:50 ` Kuan-Jui Chiu
2026-08-24 12:07 ` Jack Wang
2026-08-20 10:21 ` [PATCH v1 5/5] hw/arm: Add Axiado Ax3005 EVB Kuan-Jui Chiu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260820102132.361642-5-kchiu@axiado.com \
--to=kchiu@axiado.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.