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(®); - 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(®); - 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
