cadence_qspi_flash_reset() currently performs the OSPI flash GPIO
reset sequence by directly accessing PLM/PSM-protected registers,
bypassing the firmware interface.

Add zynqmp_pm_ospi_flash_reset() as a firmware abstraction, backed by
zynqmp_pm_ospi_flash_reset_raw() (the same register sequence, added
here as a weak default for Versal, Versal Net and Versal Gen 2) which
the next patch switches cadence_qspi_flash_reset() to use. The
firmware-backed override falls back to the raw sequence at EL3/SPL,
where SMC is unavailable, matching zynqmp_mmio_read()/write().

CONFIG_CADENCE_OSPI_VERSAL covers Versal, Versal Net and Versal Gen 2
alike, so the wrapper needs a Gen 2 weak default too for
amd_versal2_mini_ospi_defconfig to link. Versal Gen 2's actual flash
reset still goes through cadence_device_reset() (see cadence_qspi.c's
dispatcher) and never calls this wrapper at runtime - this addition
resolves the build symbol only, with no functional Gen 2 coverage.

zynqmp_pm_ospi_flash_reset() only calls zynqmp_pm_ospi_flash_reset_raw()
or xilinx_pm_request(), neither needing CONFIG_ZYNQMP_IPI, so it lives
outside that guard, like the other wrapper functions above it.

Signed-off-by: Akshay Belsare <[email protected]>
---
 arch/arm/mach-versal-net/cpu.c                | 51 +++++++++++++++++++
 .../mach-versal-net/include/mach/sys_proto.h  |  6 +++
 arch/arm/mach-versal/cpu.c                    | 51 +++++++++++++++++++
 arch/arm/mach-versal/include/mach/sys_proto.h |  6 +++
 arch/arm/mach-versal2/cpu.c                   | 51 +++++++++++++++++++
 .../arm/mach-versal2/include/mach/sys_proto.h |  6 +++
 drivers/firmware/firmware-zynqmp.c            | 14 +++++
 include/zynqmp_firmware.h                     |  2 +
 8 files changed, 187 insertions(+)

diff --git a/arch/arm/mach-versal-net/cpu.c b/arch/arm/mach-versal-net/cpu.c
index f5c8e684dda..20a41d9ed97 100644
--- a/arch/arm/mach-versal-net/cpu.c
+++ b/arch/arm/mach-versal-net/cpu.c
@@ -20,6 +20,7 @@
 #include <asm/cache.h>
 #include <dm/platdata.h>
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/string.h>
 #include "../../../board/xilinx/common/board.h"
 
@@ -250,6 +251,56 @@ __weak int zynqmp_pm_ospi_enable_linear_mode(bool enable)
        return 0;
 }
 
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+int zynqmp_pm_ospi_flash_reset_raw(void)
+{
+       /* CRP WPROT */
+       writel(0, WPROT_CRP);
+       /* GPIO Reset */
+       writel(0, RST_GPIO);
+
+       /* disable IOU write protection */
+       writel(0, WPROT_LPD_MIO);
+
+       /* set direction as output */
+       writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
+              BOOT_MODE_DIR);
+
+       /* Data output enable */
+       writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
+              BOOT_MODE_OUT);
+
+       /* IOU SLCR write enable */
+       writel(0, WPROT_PMC_MIO);
+
+       /* set MIO as GPIO */
+       writel(0x60, MIO_PIN_12);
+
+       /* Set value 1 to pin */
+       writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(10);
+
+       /* Disable Tri-state */
+       writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
+       udelay(5);
+
+       /* Set value 0 to pin */
+       writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(150);
+
+       /* Set value 1 to pin */
+       writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(1200);
+
+       return 0;
+}
+
+__weak int zynqmp_pm_ospi_flash_reset(void)
+{
+       return zynqmp_pm_ospi_flash_reset_raw();
+}
+#endif
+
 U_BOOT_DRVINFO(soc_xilinx_versal_net) = {
        .name = "soc_xilinx_versal_net",
 };
diff --git a/arch/arm/mach-versal-net/include/mach/sys_proto.h 
b/arch/arm/mach-versal-net/include/mach/sys_proto.h
index 2682b0faeea..aa680baba89 100644
--- a/arch/arm/mach-versal-net/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal-net/include/mach/sys_proto.h
@@ -15,3 +15,9 @@ u8 versal_net_get_bootmode(void);
 u32 versal_net_bootmode_reg(void);
 /* Overridable OSPI AXI-mux select: weak MMIO default, firmware override */
 int zynqmp_pm_ospi_enable_linear_mode(bool enable);
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+/* Overridable OSPI flash GPIO reset sequence: weak MMIO default, firmware 
override */
+int zynqmp_pm_ospi_flash_reset(void);
+/* Direct GPIO reset sequence (EL3 / no-firmware path) */
+int zynqmp_pm_ospi_flash_reset_raw(void);
+#endif
diff --git a/arch/arm/mach-versal/cpu.c b/arch/arm/mach-versal/cpu.c
index 3ec51bf560e..d0f23767662 100644
--- a/arch/arm/mach-versal/cpu.c
+++ b/arch/arm/mach-versal/cpu.c
@@ -17,6 +17,7 @@
 #include <asm/arch/sys_proto.h>
 #include <asm/cache.h>
 #include <dm/platdata.h>
+#include <linux/delay.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -190,6 +191,56 @@ __weak int zynqmp_pm_ospi_enable_linear_mode(bool enable)
        return 0;
 }
 
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+int zynqmp_pm_ospi_flash_reset_raw(void)
+{
+       /* CRP WPROT */
+       writel(0, WPROT_CRP);
+       /* GPIO Reset */
+       writel(0, RST_GPIO);
+
+       /* disable IOU write protection */
+       writel(0, WPROT_LPD_MIO);
+
+       /* set direction as output */
+       writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
+              BOOT_MODE_DIR);
+
+       /* Data output enable */
+       writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
+              BOOT_MODE_OUT);
+
+       /* IOU SLCR write enable */
+       writel(0, WPROT_PMC_MIO);
+
+       /* set MIO as GPIO */
+       writel(0x60, MIO_PIN_12);
+
+       /* Set value 1 to pin */
+       writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(10);
+
+       /* Disable Tri-state */
+       writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
+       udelay(5);
+
+       /* Set value 0 to pin */
+       writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(150);
+
+       /* Set value 1 to pin */
+       writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(1200);
+
+       return 0;
+}
+
+__weak int zynqmp_pm_ospi_flash_reset(void)
+{
+       return zynqmp_pm_ospi_flash_reset_raw();
+}
+#endif
+
 U_BOOT_DRVINFO(soc_xilinx_versal) = {
        .name = "soc_xilinx_versal",
 };
diff --git a/arch/arm/mach-versal/include/mach/sys_proto.h 
b/arch/arm/mach-versal/include/mach/sys_proto.h
index da357abaaee..83fc9b73b03 100644
--- a/arch/arm/mach-versal/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal/include/mach/sys_proto.h
@@ -29,5 +29,11 @@ u32 versal_bootmode_reg(void);
 void versal_timer_setup(void);
 /* Overridable OSPI AXI-mux select: weak MMIO default, firmware override */
 int zynqmp_pm_ospi_enable_linear_mode(bool enable);
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+/* Overridable OSPI flash GPIO reset sequence: weak MMIO default, firmware 
override */
+int zynqmp_pm_ospi_flash_reset(void);
+/* Direct GPIO reset sequence (EL3 / no-firmware path) */
+int zynqmp_pm_ospi_flash_reset_raw(void);
+#endif
 
 #endif /* _ASM_ARCH_SYS_PROTO_H */
diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c
index c2173161fd7..c1cd4aef508 100644
--- a/arch/arm/mach-versal2/cpu.c
+++ b/arch/arm/mach-versal2/cpu.c
@@ -22,6 +22,7 @@
 #include <asm/cache.h>
 #include <dm/platdata.h>
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/string.h>
 #include "../../../board/xilinx/common/board.h"
 
@@ -323,6 +324,56 @@ __weak int zynqmp_pm_ospi_enable_linear_mode(bool enable)
        return 0;
 }
 
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+int zynqmp_pm_ospi_flash_reset_raw(void)
+{
+       /* CRP WPROT */
+       writel(0, WPROT_CRP);
+       /* GPIO Reset */
+       writel(0, RST_GPIO);
+
+       /* disable IOU write protection */
+       writel(0, WPROT_LPD_MIO);
+
+       /* set direction as output */
+       writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
+              BOOT_MODE_DIR);
+
+       /* Data output enable */
+       writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
+              BOOT_MODE_OUT);
+
+       /* IOU SLCR write enable */
+       writel(0, WPROT_PMC_MIO);
+
+       /* set MIO as GPIO */
+       writel(0x60, MIO_PIN_12);
+
+       /* Set value 1 to pin */
+       writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(10);
+
+       /* Disable Tri-state */
+       writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
+       udelay(5);
+
+       /* Set value 0 to pin */
+       writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(150);
+
+       /* Set value 1 to pin */
+       writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+       udelay(1200);
+
+       return 0;
+}
+
+__weak int zynqmp_pm_ospi_flash_reset(void)
+{
+       return zynqmp_pm_ospi_flash_reset_raw();
+}
+#endif
+
 U_BOOT_DRVINFO(soc_amd_versal2) = {
        .name = "soc_amd_versal2",
 };
diff --git a/arch/arm/mach-versal2/include/mach/sys_proto.h 
b/arch/arm/mach-versal2/include/mach/sys_proto.h
index 30db724bc2c..5a903a0881a 100644
--- a/arch/arm/mach-versal2/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal2/include/mach/sys_proto.h
@@ -23,6 +23,12 @@ u8 versal2_get_bootmode(void);
 void versal2_timer_setup(void);
 /* Overridable OSPI AXI-mux select: weak MMIO default, firmware override */
 int zynqmp_pm_ospi_enable_linear_mode(bool enable);
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+/* Overridable OSPI flash GPIO reset sequence: weak MMIO default, firmware 
override */
+int zynqmp_pm_ospi_flash_reset(void);
+/* Direct GPIO reset sequence (EL3 / no-firmware path) */
+int zynqmp_pm_ospi_flash_reset_raw(void);
+#endif
 
 int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us);
 int zynqmp_pm_wait_sram_init_done(u32 timeout_us);
diff --git a/drivers/firmware/firmware-zynqmp.c 
b/drivers/firmware/firmware-zynqmp.c
index d09e92de1b0..6e6724653b7 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -869,6 +869,20 @@ int zynqmp_pm_ospi_enable_linear_mode(bool enable)
 }
 #endif
 
+#if !CONFIG_IS_ENABLED(DM_GPIO) && \
+       (defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL_NET) || \
+        defined(CONFIG_ARCH_VERSAL2))
+int zynqmp_pm_ospi_flash_reset(void)
+{
+       /* At EL3 or in SPL the firmware (SMC) path is unavailable */
+       if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3)
+               return zynqmp_pm_ospi_flash_reset_raw();
+
+       return xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI, IOCTL_OSPI_FLASH_RESET,
+                                0, 0, 0, 0, NULL);
+}
+#endif
+
 static const struct udevice_id zynqmp_firmware_ids[] = {
        { .compatible = "xlnx,zynqmp-firmware", .data = (ulong)smc_call_legacy 
},
        { .compatible = "xlnx,versal-firmware", .data = (ulong)smc_call_legacy},
diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h
index 949ef5ec121..1270e061364 100644
--- a/include/zynqmp_firmware.h
+++ b/include/zynqmp_firmware.h
@@ -412,6 +412,8 @@ enum pm_ioctl_id {
        IOCTL_AIE_OPS = 33,
        /* IOCTL to get default/current QoS */
        IOCTL_GET_QOS = 34,
+       /* IOCTL for OSPI flash GPIO reset sequence */
+       IOCTL_OSPI_FLASH_RESET = 35,
 };
 
 enum pm_sd_config_type {
-- 
2.25.1

Reply via email to