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 <michal.simek@amd.com> Link: https://patch.msgid.link/d532df144d2c8e34be835bad6d0de3b26befdf01.1782219202.git.michal.simek@amd.com
This commit is contained in:
+14
-35
@@ -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;
|
||||
return -EINVAL;
|
||||
|
||||
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];
|
||||
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];
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void zynqmp_timer_setup(void)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user