From 4b62fc1b7e9e6ead90bbc5a5c9e82b8ee03fbfef Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 23 Jun 2026 14:53:38 +0200 Subject: arm64: zynqmp: Decouple MMIO accessors from firmware 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 Link: https://patch.msgid.link/d532df144d2c8e34be835bad6d0de3b26befdf01.1782219202.git.michal.simek@amd.com --- arch/arm/mach-zynqmp/cpu.c | 49 ++++++++------------------- arch/arm/mach-zynqmp/include/mach/sys_proto.h | 3 ++ drivers/firmware/firmware-zynqmp.c | 31 +++++++++++++++++ 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/arch/arm/mach-zynqmp/cpu.c b/arch/arm/mach-zynqmp/cpu.c index e6f2e0b3ee0..088cc962189 100644 --- a/arch/arm/mach-zynqmp/cpu.c +++ b/arch/arm/mach-zynqmp/cpu.c @@ -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) diff --git a/arch/arm/mach-zynqmp/include/mach/sys_proto.h b/arch/arm/mach-zynqmp/include/mach/sys_proto.h index 723e7593cf7..d2bb10ffcbb 100644 --- a/arch/arm/mach-zynqmp/include/mach/sys_proto.h +++ b/arch/arm/mach-zynqmp/include/mach/sys_proto.h @@ -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 */ diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 4c4f4c19ae4..6052a31b5b4 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -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) { -- cgit v1.3.1