Commit 2019f4e0dd for qemu.org

commit 2019f4e0ddb3f7c0d3246042ee7535b7348792ce
Author: Kuan-Jui Chiu <kchiu@axiado.com>
Date:   Tue Aug 11 20:14:11 2026 +0100

    hw/arm: ax3000-soc: Enable Axiado SD host controller

    Enable SD host controller into Axiado AX3000 SoC to load kernel and rootfs
    from eMMC.

    Signed-off-by: Kuan-Jui Chiu <kchiu@axiado.com>
    Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
    Message-id: 20260713073033.3883619-6-kchiu@axiado.com
    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 69161a439c..32e7d83339 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -731,4 +731,5 @@ config AXIADO_SOC
     select ARM_GIC
     select CADENCE # UART
     select AXIADO_CLK
+    select AXIADO_SDHCI
     select UNIMP
diff --git a/hw/arm/ax3000-soc.c b/hw/arm/ax3000-soc.c
index aaeae11074..23903b081b 100644
--- a/hw/arm/ax3000-soc.c
+++ b/hw/arm/ax3000-soc.c
@@ -35,6 +35,7 @@ static void ax3000_init(Object *obj)
     }

     object_initialize_child(obj, "clk", &s->ax3000_clk, TYPE_AX3000_CLK);
+    object_initialize_child(obj, "sdhci0", &s->sdhci0, TYPE_AXIADO_SDHCI);
 }

 static void ax3000_realize(DeviceState *dev, Error **errp)
@@ -46,6 +47,7 @@ static void ax3000_realize(DeviceState *dev, Error **errp)
     QList *redist_region_count;
     SysBusDevice *sdhci0_sbd;
     DeviceState *card;
+    DriveInfo *dinfo;

     /* CPUs */
     for (int i = 0; i < sc->num_cpus; i++) {
@@ -165,6 +167,26 @@ static void ax3000_realize(DeviceState *dev, Error **errp)
         return;
     }
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->ax3000_clk), 0, AX3000_PLL_BASE);
+
+    /* SDHCI */
+    sdhci0_sbd = SYS_BUS_DEVICE(&s->sdhci0);
+    if (!sysbus_realize(sdhci0_sbd, errp)) {
+        return;
+    }
+
+    sysbus_mmio_map(sdhci0_sbd, 0, AX3000_SDHCI0_BASE);
+    sysbus_mmio_map(sdhci0_sbd, 1, AX3000_EMMC_PHY_BASE);
+    sysbus_connect_irq(sdhci0_sbd, 0,
+                       qdev_get_gpio_in(gic_dev, AX3000_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);
+    }
 }

 static void ax3000_class_init(ObjectClass *oc, const void *data)
diff --git a/include/hw/arm/ax3000-soc.h b/include/hw/arm/ax3000-soc.h
index 329aa4e769..52b47aa829 100644
--- a/include/hw/arm/ax3000-soc.h
+++ b/include/hw/arm/ax3000-soc.h
@@ -13,6 +13,7 @@
 #include "hw/intc/arm_gicv3_common.h"
 #include "hw/char/cadence_uart.h"
 #include "hw/misc/axiado_clk.h"
+#include "hw/sd/axiado_sdhci.h"
 #include "hw/core/sysbus.h"
 #include "qemu/units.h"

@@ -34,6 +35,9 @@ OBJECT_DECLARE_TYPE(Ax3000SoCState, Ax3000SoCClass, AX3000_SOC)
 #define AX3000_UART2_BASE       0x80620000
 #define AX3000_UART3_BASE       0x80520800

+#define AX3000_SDHCI0_BASE      0x86000000
+#define AX3000_EMMC_PHY_BASE    0x80801C00
+
 #define AX3000_TIMER_CTRL       0x8A020000
 #define AX3000_PLL_BASE         0x80000000

@@ -52,6 +56,7 @@ typedef struct Ax3000SoCState {
     MemoryRegion        dram[AX3000_NUM_BANKS];
     Ax3000ClkState      ax3000_clk;
     CadenceUARTState    uart[AX3000_NUM_UARTS];
+    AxiadoSDHCIState    sdhci0;
 } Ax3000SoCState;

 typedef struct Ax3000SoCClass {
@@ -65,6 +70,8 @@ enum Ax3000Irqs {
     AX3000_UART1_IRQ    = 113,
     AX3000_UART2_IRQ    = 114,
     AX3000_UART3_IRQ    = 170,
+
+    AX3000_SDHCI0_IRQ   = 123,
 };

 #endif /* AXIADO_AX3000_H */