]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
arm64: zynqmp: Decouple MMIO accessors from firmware
authorMichal Simek <michal.simek@amd.com>
Tue, 23 Jun 2026 12:53:38 +0000 (14:53 +0200)
committerMichal Simek <michal.simek@amd.com>
Wed, 8 Jul 2026 06:55:51 +0000 (08:55 +0200)
zynqmp_mmio_read() and zynqmp_mmio_write() selected between direct MMIO
and the firmware (PM_MMIO_READ/WRITE) interface with an in-function
IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE) / current_el() check. Generic arch
code should not carry firmware-specific ifdefs, and with SCMI the access
method changes again.

Split the accessors like the multiboot and bootmode hooks: the weak
default in arch/arm/mach-zynqmp does the direct MMIO access (used in SPL,
at EL3 and when no firmware is present), while firmware-zynqmp.c provides
a strong definition that issues the firmware call and falls back to the
direct access in SPL/EL3 where the SMC path is unavailable. The raw MMIO
primitives zynqmp_mmio_rawread() and zynqmp_mmio_rawwrite() are exported
for the shared fallback, and the read-modify-write helper now uses the
raw read instead of routing through the firmware-aware accessor.

The firmware-vs-MMIO decision is selected at link time, so adding SCMI
later only requires a third strong definition with no changes to generic
code.

Signed-off-by: Michal Simek <michal.simek@amd.com>
Link: https://patch.msgid.link/d532df144d2c8e34be835bad6d0de3b26befdf01.1782219202.git.michal.simek@amd.com
arch/arm/mach-zynqmp/cpu.c
arch/arm/mach-zynqmp/include/mach/sys_proto.h
drivers/firmware/firmware-zynqmp.c

index e6f2e0b3ee09b172f15c29e61115ce2c645ced7f..088cc96218984dcf8d081345d7c6b320b0f8232c 100644 (file)
@@ -172,15 +172,19 @@ unsigned int zynqmp_get_silicon_version(void)
        return ZYNQMP_CSU_VERSION_SILICON;
 }
 
-static int zynqmp_mmio_rawwrite(const u32 address,
-                     const u32 mask,
-                     const u32 value)
+int zynqmp_mmio_rawread(const u32 address, u32 *value)
+{
+       *value = readl((ulong)address);
+       return 0;
+}
+
+int zynqmp_mmio_rawwrite(const u32 address, const u32 mask, const u32 value)
 {
        u32 data;
        u32 value_local = value;
        int ret;
 
-       ret = zynqmp_mmio_read(address, &data);
+       ret = zynqmp_mmio_rawread(address, &data);
        if (ret)
                return ret;
 
@@ -191,48 +195,23 @@ static int zynqmp_mmio_rawwrite(const u32 address,
        return 0;
 }
 
-static int zynqmp_mmio_rawread(const u32 address, u32 *value)
-{
-       *value = readl((ulong)address);
-       return 0;
-}
-
-int zynqmp_mmio_write(const u32 address,
-                     const u32 mask,
-                     const u32 value)
+int __weak zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value)
 {
        if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3)
                return zynqmp_mmio_rawwrite(address, mask, value);
-#if defined(CONFIG_ZYNQMP_FIRMWARE)
-       else
-               return xilinx_pm_request(PM_MMIO_WRITE, address, mask,
-                                        value, 0, 0, 0, NULL);
-#endif
 
        return -EINVAL;
 }
 
-int zynqmp_mmio_read(const u32 address, u32 *value)
+int __weak zynqmp_mmio_read(const u32 address, u32 *value)
 {
-       u32 ret = -EINVAL;
-
        if (!value)
-               return ret;
-
-       if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) {
-               ret = zynqmp_mmio_rawread(address, value);
-       }
-#if defined(CONFIG_ZYNQMP_FIRMWARE)
-       else {
-               u32 ret_payload[PAYLOAD_ARG_CNT];
+               return -EINVAL;
 
-               ret = xilinx_pm_request(PM_MMIO_READ, address, 0, 0,
-                                       0, 0, 0, ret_payload);
-               *value = ret_payload[1];
-       }
-#endif
+       if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3)
+               return zynqmp_mmio_rawread(address, value);
 
-       return ret;
+       return -EINVAL;
 }
 
 void zynqmp_timer_setup(void)
index 723e7593cf7bc378bf7a335e6f8dbd353ac3dbc8..d2bb10ffcbbbbbf86886a971d03f774c558964d3 100644 (file)
@@ -56,5 +56,8 @@ void tcm_init(enum tcm_mode mode);
 #endif
 /* EL3 clock/timer register setup, called from board_early_init_r() */
 void zynqmp_timer_setup(void);
+/* Direct MMIO accessors (EL3/SPL or no-firmware path) */
+int zynqmp_mmio_rawread(const u32 address, u32 *value);
+int zynqmp_mmio_rawwrite(const u32 address, const u32 mask, const u32 value);
 
 #endif /* _ASM_ARCH_SYS_PROTO_H */
index 4c4f4c19ae4b109374ba432720447640c1fd8d9e..6052a31b5b400421a4d292a8fbf660cf6600872d 100644 (file)
@@ -373,6 +373,37 @@ u8 versal_net_get_bootmode(void)
 }
 #endif
 
+#if defined(CONFIG_ARCH_ZYNQMP)
+int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value)
+{
+       /* At EL3 or in SPL the firmware (SMC) path is unavailable */
+       if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3)
+               return zynqmp_mmio_rawwrite(address, mask, value);
+
+       return xilinx_pm_request(PM_MMIO_WRITE, address, mask, value,
+                                0, 0, 0, NULL);
+}
+
+int zynqmp_mmio_read(const u32 address, u32 *value)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       if (!value)
+               return -EINVAL;
+
+       /* At EL3 or in SPL the firmware (SMC) path is unavailable */
+       if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3)
+               return zynqmp_mmio_rawread(address, value);
+
+       ret = xilinx_pm_request(PM_MMIO_READ, address, 0, 0, 0, 0, 0,
+                               ret_payload);
+       *value = ret_payload[1];
+
+       return ret;
+}
+#endif
+
 #if defined(CONFIG_ARCH_VERSAL2)
 u32 versal2_pmc_multi_boot(void)
 {