Currently, phy_set_mode_ext() on the QMP UFS PHY makes no change to the hardware state, instead it is mandatory that phy_power_on() followed by phy_calibrate() be run afterwards, for the new mode to be picked up. By absorbing the phy_power_off() -> ... -> phy_power_on() -> phy_calibrate() surrounding sequence into phy_set_mode_ext(), the UFS HCD consumer driver can be greatly simplified, and we also have a proper self-standing phy_set_mode_ext() implementation which does not rely on other calls to do its job. So simplify ufs_qcom_power_up_sequence() to only call phy_set_mode_ext() and let PHY power management be handled just by ufs_qcom_setup_clocks(). Actually, after this change, ufs_qcom_power_up_sequence() becomes an inadequate name, since from the consumer perspective the powering up is invisible. So change it to ufs_qcom_phy_change_mode(). The consumer and the provider are modified at once because ufs-qcom.c already calls phy_set_mode_ext() while the QMP PHY is powered on, so introducing the extra logic in qmp_ufs_set_mode() would cause a potentially breaking second QMP PHY power sequence until the consumer is patched to remove its own calls. Signed-off-by: Vladimir Oltean --- Cc: Can Guo Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Dmitry Baryshkov Cc: Nitin Rawat Cc: Manivannan Sadhasivam v7->v8: patch is new Commit was previously posted here but did not get any testing. https://lore.kernel.org/linux-phy/20260327112858.r5lpqygtvsane2vf@skbuf/ Signed-off-by: Vladimir Oltean --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 6 ++++++ drivers/ufs/host/ufs-qcom.c | 25 +++++-------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 771bc7c2ab50..e4e7966eb39a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -2012,6 +2012,12 @@ static int qmp_ufs_set_mode(struct phy *phy, enum phy_mode mode, int submode) qmp->mode = mode; qmp->submode = submode; + if (phy->power_count) { + qmp_ufs_power_off(phy); + qmp_ufs_power_on(phy); + return qmp_ufs_phy_calibrate(phy); + } + return 0; } diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 9039b087bf21..e28edcfd13a1 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -485,7 +485,7 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) return UFS_HS_G3; } -static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) +static int ufs_qcom_phy_change_mode(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_host_params *host_params = &host->host_params; @@ -508,26 +508,11 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) if (ret) return ret; - if (phy->power_count) - phy_power_off(phy); - - - /* phy initialization - calibrate the phy */ ret = phy_set_mode_ext(phy, mode, host->phy_gear); - if (ret) - goto out_disable_phy; - - /* power on phy - start serdes and phy's power and clocks */ - ret = phy_power_on(phy); - if (ret) { - dev_err(hba->dev, "%s: phy power on failed, ret = %d\n", - __func__, ret); - return ret; - } - - ret = phy_calibrate(phy); if (ret) { - dev_err(hba->dev, "Failed to calibrate PHY: %d\n", ret); + dev_err(hba->dev, + "Failed to change PHY mode %d submode %d: %pe\n", + mode, host->phy_gear, ERR_PTR(ret)); return ret; } @@ -582,7 +567,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - err = ufs_qcom_power_up_sequence(hba); + err = ufs_qcom_phy_change_mode(hba); if (err) return err; -- 2.34.1