The M-PHY and SRAM readiness poll loops move out of the UFS controller
driver and into the firmware backend, exposed as blocking waits with
a caller-owned timeout budget. This keeps the UFS driver backend-agnostic
and lets an other backends offload the wait to the platform in a single
call instead of round-tripping every poll.

set_sram_bypass() now performs the SRAM_CSR read-modify-write in the
firmware layer.

Hook up functions are also update to reflect their usage.

Signed-off-by: Michal Simek <[email protected]>
---

 arch/arm/mach-versal2/cpu.c                   | 34 ++++++---
 arch/arm/mach-versal2/include/mach/hardware.h |  5 ++
 .../arm/mach-versal2/include/mach/sys_proto.h |  8 +-
 drivers/firmware/firmware-zynqmp.c            | 72 +++++++++++-------
 drivers/ufs/ufs-amd-versal2.c                 | 73 +++++--------------
 5 files changed, 95 insertions(+), 97 deletions(-)

diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c
index 01efa7b79282..d72f66f4fbac 100644
--- a/arch/arm/mach-versal2/cpu.c
+++ b/arch/arm/mach-versal2/cpu.c
@@ -11,6 +11,7 @@
 #include <malloc.h>
 #include <time.h>
 #include <vsprintf.h>
+#include <wait_bit.h>
 #include <asm/armv8/mmu.h>
 #include <asm/cache.h>
 #include <asm/global_data.h>
@@ -160,25 +161,40 @@ u8 __weak versal2_get_bootmode(void)
        return bootmode;
 }
 
-int __weak zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value)
+/*
+ * Wait for the M-PHY TX/RX config-ready status to settle (all bits cleared) or
+ * @timeout_us to elapse. The direct-MMIO fallback owns the poll loop, 
mirroring
+ * the EEMI backend; the timeout budget is owned by the caller.
+ */
+int __weak zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us)
 {
-       *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_TX_RX_CFG_RDY);
-       return 0;
+       return wait_for_bit_le32((void *)(uintptr_t)(PMXC_SLCR_BASE_ADDRESS +
+                                                    PMXC_TX_RX_CFG_RDY),
+                                TX_RX_CFG_RDY_MASK, false, timeout_us / 1000,
+                                false);
 }
 
-int __weak zynqmp_pm_ufs_sram_csr_read(u32 *value)
+int __weak zynqmp_pm_wait_sram_init_done(u32 timeout_us)
 {
-       *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR);
-       return 0;
+       return wait_for_bit_le32((void *)(uintptr_t)(PMXC_SLCR_BASE_ADDRESS +
+                                                    PMXC_SRAM_CSR),
+                                SRAM_CSR_INIT_DONE_MASK, true, timeout_us / 
1000,
+                                false);
 }
 
-int __weak zynqmp_pm_ufs_sram_csr_write(u32 *value)
+int __weak zynqmp_pm_set_sram_bypass(void)
 {
-       writel(*value, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR);
+       u32 sram_csr;
+
+       sram_csr = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR);
+       sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK;
+       sram_csr |= SRAM_CSR_BYPASS_MASK;
+       writel(sram_csr, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR);
+
        return 0;
 }
 
-int __weak zynqmp_pm_ufs_cal_reg(u32 *value)
+int __weak zynqmp_pm_get_ufs_calibration_values(u32 *value)
 {
        *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET);
        return 0;
diff --git a/arch/arm/mach-versal2/include/mach/hardware.h 
b/arch/arm/mach-versal2/include/mach/hardware.h
index 7977529fd6c1..4ff732d660fd 100644
--- a/arch/arm/mach-versal2/include/mach/hardware.h
+++ b/arch/arm/mach-versal2/include/mach/hardware.h
@@ -65,6 +65,11 @@
 #define PMXC_SRAM_CSR                  0x4C
 #define PMXC_TX_RX_CFG_RDY             0x54
 
+#define SRAM_CSR_INIT_DONE_MASK                BIT(0)
+#define SRAM_CSR_EXT_LD_DONE_MASK      BIT(1)
+#define SRAM_CSR_BYPASS_MASK           BIT(2)
+#define TX_RX_CFG_RDY_MASK             GENMASK(3, 0)
+
 #define PMC_GLOBAL_PGGS3_REG   0xF111005C
 #define PMC_GLOBAL_PGGS4_REG   0xF1110060
 
diff --git a/arch/arm/mach-versal2/include/mach/sys_proto.h 
b/arch/arm/mach-versal2/include/mach/sys_proto.h
index c1dfd184d865..d678adf9c267 100644
--- a/arch/arm/mach-versal2/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal2/include/mach/sys_proto.h
@@ -22,9 +22,9 @@ u8 versal2_get_bootmode(void);
 /* EL3 clock/timer register setup, called from board_early_init_r() */
 void versal2_timer_setup(void);
 
-int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value);
-int zynqmp_pm_ufs_sram_csr_read(u32 *value);
-int zynqmp_pm_ufs_sram_csr_write(u32 *value);
-int zynqmp_pm_ufs_cal_reg(u32 *value);
+int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us);
+int zynqmp_pm_wait_sram_init_done(u32 timeout_us);
+int zynqmp_pm_set_sram_bypass(void);
+int zynqmp_pm_get_ufs_calibration_values(u32 *value);
 
 #endif /* _ASM_ARCH_SYS_PROTO_H */
diff --git a/drivers/firmware/firmware-zynqmp.c 
b/drivers/firmware/firmware-zynqmp.c
index 2bdb1c4d9f89..fae66ccb3d83 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -19,6 +19,7 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 
 #if defined(CONFIG_ZYNQMP_IPI)
 #include <mailbox.h>
@@ -175,51 +176,60 @@ unsigned int zynqmp_firmware_version(void)
 };
 
 #if defined(CONFIG_ARCH_VERSAL2)
-int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value)
+/*
+ * Poll the M-PHY TX/RX config-ready status until it settles or @timeout_us
+ * elapses. Legacy EEMI firmware only offers the per-read status primitive, so
+ * the poll loop lives here rather than in the UFS driver; the timeout budget 
is
+ * owned by the caller.
+ */
+int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us)
 {
        u32 ret_payload[PAYLOAD_ARG_CNT];
        int ret;
 
-       if (!value)
-               return -EINVAL;
+       while (timeout_us--) {
+               ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR,
+                                       IOCTL_READ_REG, TXRX_CFGRDY_OFFSET, 0, 
0,
+                                       0, ret_payload);
+               if (ret)
+                       return ret;
 
-       ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR,
-                               IOCTL_READ_REG, TXRX_CFGRDY_OFFSET, 0, 0,
-                               0, ret_payload);
-       if (ret)
-               return ret;
+               if (!(ret_payload[1] & TX_RX_CFG_RDY_MASK))
+                       return 0;
 
-       *value = ret_payload[1];
+               udelay(1);
+       }
 
-       return ret;
+       return -ETIMEDOUT;
 }
 
-int zynqmp_pm_ufs_sram_csr_read(u32 *value)
+int zynqmp_pm_wait_sram_init_done(u32 timeout_us)
 {
        u32 ret_payload[PAYLOAD_ARG_CNT];
        int ret;
 
-       if (!value)
-               return -EINVAL;
+       while (timeout_us--) {
+               ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR,
+                                       IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0,
+                                       0, ret_payload);
+               if (ret)
+                       return ret;
 
-       ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR,
-                               IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0,
-                               0, ret_payload);
-       if (ret)
-               return ret;
+               if (ret_payload[1] & SRAM_CSR_INIT_DONE_MASK)
+                       return 0;
 
-       *value = ret_payload[1];
+               udelay(1);
+       }
 
-       return ret;
+       return -ETIMEDOUT;
 }
 
-int zynqmp_pm_ufs_sram_csr_write(u32 *value)
+int zynqmp_pm_set_sram_bypass(void)
 {
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       u32 sram_csr;
        int ret;
 
-       if (!value)
-               return -EINVAL;
-
        ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_MASK_WRITE_REG);
        if (ret) {
                printf("%s: IOCTL_MASK_WRITE_REG is not supported : %d\n"
@@ -228,15 +238,21 @@ int zynqmp_pm_ufs_sram_csr_write(u32 *value)
        }
 
        ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR,
-                               IOCTL_MASK_WRITE_REG, SRAM_CSR_OFFSET,
-                               GENMASK(2, 1), *value, 0, NULL);
+                               IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0,
+                               0, ret_payload);
        if (ret)
                return ret;
 
-       return ret;
+       sram_csr = ret_payload[1];
+       sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK;
+       sram_csr |= SRAM_CSR_BYPASS_MASK;
+
+       return xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR,
+                                IOCTL_MASK_WRITE_REG, SRAM_CSR_OFFSET,
+                                GENMASK(2, 1), sram_csr, 0, NULL);
 }
 
-int zynqmp_pm_ufs_cal_reg(u32 *value)
+int zynqmp_pm_get_ufs_calibration_values(u32 *value)
 {
        u32 ret_payload[PAYLOAD_ARG_CNT];
        int ret;
diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c
index 986147848bda..48854792cbf3 100644
--- a/drivers/ufs/ufs-amd-versal2.c
+++ b/drivers/ufs/ufs-amd-versal2.c
@@ -20,10 +20,6 @@
 #include "ufshcd-dwc.h"
 #include "ufshci-dwc.h"
 
-#define SRAM_CSR_INIT_DONE_MASK                BIT(0)
-#define SRAM_CSR_EXT_LD_DONE_MASK      BIT(1)
-#define SRAM_CSR_BYPASS_MASK           BIT(2)
-
 #define MPHY_FAST_RX_AFE_CAL           BIT(2)
 #define MPHY_FW_CALIB_CFG_VAL          BIT(8)
 
@@ -31,8 +27,6 @@
 #define MPHY_RX_OVRD_VAL               BIT(2)
 #define MPHY_RX_ACK_MASK               BIT(0)
 
-#define TX_RX_CFG_RDY_MASK             GENMASK(3, 0)
-
 #define TIMEOUT_MICROSEC               1000000L
 
 struct ufs_versal2_priv {
@@ -229,7 +223,6 @@ static int ufs_versal2_setup_phy(struct ufs_hba *hba)
 static int ufs_versal2_phy_init(struct ufs_hba *hba)
 {
        struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
-       u32 reg, time_left;
        int ret;
        static const struct ufshcd_dme_attr_val rmmi_attrs[] = {
                { UIC_ARG_MIB(CBREFCLKCTRL2), CBREFREFCLK_GATE_OVR_EN, 
DME_LOCAL },
@@ -238,24 +231,15 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba)
                { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL }
        };
 
-       /* Wait for Tx/Rx config_rdy */
-       time_left = TIMEOUT_MICROSEC;
-       do {
-               time_left--;
-               ret = zynqmp_pm_ufs_get_txrx_cfgrdy(&reg);
-               if (ret)
-                       return ret;
-
-               reg &= TX_RX_CFG_RDY_MASK;
-               if (!reg)
-                       break;
-
-               mdelay(5);
-       } while (time_left);
-
-       if (!time_left) {
+       /*
+        * Wait for Tx/Rx config_rdy. The poll loop lives in the firmware
+        * backend (IO, EEMI or SCMI) so this driver stays backend-agnostic;
+        * the timeout budget stays here with the consumer.
+        */
+       ret = zynqmp_pm_wait_mphy_tx_rx_config_ready(TIMEOUT_MICROSEC);
+       if (ret) {
                dev_err(hba->dev, "Tx/Rx configuration signal busy.\n");
-               return -ETIMEDOUT;
+               return ret;
        }
 
        ret = ufshcd_dwc_dme_set_attrs(hba, rmmi_attrs, ARRAY_SIZE(rmmi_attrs));
@@ -269,24 +253,11 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba)
                return ret;
        }
 
-       /* Wait for SRAM init done */
-       time_left = TIMEOUT_MICROSEC;
-       do {
-               time_left--;
-               ret = zynqmp_pm_ufs_sram_csr_read(&reg);
-               if (ret)
-                       return ret;
-
-               reg &= SRAM_CSR_INIT_DONE_MASK;
-               if (reg)
-                       break;
-
-               mdelay(5);
-       } while (time_left);
-
-       if (!time_left) {
+       /* Wait for SRAM init done (poll handled by the firmware backend). */
+       ret = zynqmp_pm_wait_sram_init_done(TIMEOUT_MICROSEC);
+       if (ret) {
                dev_err(hba->dev, "SRAM initialization failed.\n");
-               return -ETIMEDOUT;
+               return ret;
        }
 
        ret = ufs_versal2_setup_phy(hba);
@@ -301,7 +272,7 @@ static int ufs_versal2_init(struct ufs_hba *hba)
        struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
        struct clk clk;
        unsigned long core_clk_rate = 0;
-       u32 cal, sram_csr;
+       u32 cal;
        int ret = 0;
 
        priv->phy_mode = UFSHCD_DWC_PHY_MODE_ROM;
@@ -345,28 +316,18 @@ static int ufs_versal2_init(struct ufs_hba *hba)
                return ret;
        }
 
-       ret = zynqmp_pm_ufs_sram_csr_read(&sram_csr);
-       if (ret)
+       ret = zynqmp_pm_set_sram_bypass();
+       if (ret) {
+               dev_err(hba->dev, "Bypass SRAM interface failed, err = %d\n", 
ret);
                return ret;
-
-       if (!priv->phy_mode) {
-               sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK;
-               sram_csr |= SRAM_CSR_BYPASS_MASK;
-       } else {
-               dev_err(hba->dev, "Invalid phy-mode %d.\n", priv->phy_mode);
-               return -EINVAL;
        }
 
-       ret = zynqmp_pm_ufs_sram_csr_write(&sram_csr);
-       if (ret)
-               return ret;
-
        /* De Assert RST_UFS Reset for UFS block in PMX_IOU */
        ret = reset_deassert(priv->rstc);
        if (ret)
                dev_err(hba->dev, "host reset deassert failed, err = %d\n", 
ret);
 
-       ret = zynqmp_pm_ufs_cal_reg(&cal);
+       ret = zynqmp_pm_get_ufs_calibration_values(&cal);
        if (ret)
                return ret;
 
-- 
2.43.0

Reply via email to