Message ID | 20240112153348.2778-2-quic_nitirawa@quicinc.com |
---|---|
State | Changes Requested |
Headers | show |
Series | Refactor phy powerup sequence | expand |
On 12.01.2024 16:33, Nitin Rawat wrote: > Commit 3f6d1767b1a0 ("phy: ufs-qcom: Refactor all init steps into > phy_poweron") removes the phy_power_on/off from ufs_qcom_setup_clocks > to suspend/resume func. > > To have a better power saving, remove the phy_power_on/off calls from > resume/suspend path and put them back to ufs_qcom_setup_clocks, so that > PHY's regulators & clks can be turned on/off along with UFS's clocks. > > Since phy phy_power_on is separated out from phy calibrate, make > separate calls to phy_power_on and phy_calibrate calls from ufs qcom > driver. > > Also add a mutex lock to protect the usage of is_phy_pwr_on against > possible racing. > > Co-developed-by: Can Guo <quic_cang@quicinc.com> > Signed-off-by: Can Guo <quic_cang@quicinc.com> > Co-developed-by: Naveen Kumar Goud Arepalli <quic_narepall@quicinc.com> > Signed-off-by: Naveen Kumar Goud Arepalli <quic_narepall@quicinc.com> > Signed-off-by: Nitin Rawat <quic_nitirawa@quicinc.com> > --- > drivers/ufs/host/ufs-qcom.c | 104 +++++++++++++++++++++++------------- > drivers/ufs/host/ufs-qcom.h | 4 ++ > 2 files changed, 72 insertions(+), 36 deletions(-) > > diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c > index 39eef470f8fa..2721a30f0db8 100644 > --- a/drivers/ufs/host/ufs-qcom.c > +++ b/drivers/ufs/host/ufs-qcom.c > @@ -338,6 +338,46 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) > return UFS_HS_G3; > } > > +static int ufs_qcom_phy_power_on(struct ufs_hba *hba) > +{ > + struct ufs_qcom_host *host = ufshcd_get_variant(hba); > + struct phy *phy = host->generic_phy; > + int ret = 0; > + > + mutex_lock(&host->phy_mutex); guard(mutex)(&host->phy_mutex); and you can drop the _unlock calls > + if (!host->is_phy_pwr_on) { > + ret = phy_power_on(phy); > + if (ret) { > + mutex_unlock(&host->phy_mutex); > + return ret; And with the _unlock now being unnecessary, you can rewrite this as: if (!host->is_phy_pwr_on) { ret = phy_power_on(phy); if (!ret) host->is_phy_pwr_on = true; } return ret > + } > + host->is_phy_pwr_on = true; > + } > + mutex_unlock(&host->phy_mutex); > + > + return ret; > +} [...] > static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) > { > struct ufs_qcom_host *host = ufshcd_get_variant(hba); > @@ -378,13 +418,18 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) > goto out_disable_phy; > > /* power on phy - start serdes and phy's power and clocks */ > - ret = phy_power_on(phy); > + ret = ufs_qcom_phy_power_on(hba); > if (ret) { > dev_err(hba->dev, "%s: phy power on failed, ret = %d\n", > __func__, ret); > goto out_disable_phy; > } > > + ret = phy_calibrate(phy); > + if (ret) { > + dev_err(hba->dev, "%s: Failed to calibrate PHY %d\n", > + __func__, ret); > + } You can drop the overly verbose __func__, unwrap the line and remove the curly braces, similar for dev_err-s below Actually, shouldn't this error out if calibrate fails?? Konrad
On Fri, Jan 12, 2024 at 09:03:47PM +0530, Nitin Rawat wrote: > Commit 3f6d1767b1a0 ("phy: ufs-qcom: Refactor all init steps into > phy_poweron") removes the phy_power_on/off from ufs_qcom_setup_clocks s/removes/moved > to suspend/resume func. > > To have a better power saving, remove the phy_power_on/off calls from > resume/suspend path and put them back to ufs_qcom_setup_clocks, so that > PHY's regulators & clks can be turned on/off along with UFS's clocks. > > Since phy phy_power_on is separated out from phy calibrate, make > separate calls to phy_power_on and phy_calibrate calls from ufs qcom > driver. > Above change should be in a separate patch. > Also add a mutex lock to protect the usage of is_phy_pwr_on against > possible racing. > > Co-developed-by: Can Guo <quic_cang@quicinc.com> > Signed-off-by: Can Guo <quic_cang@quicinc.com> > Co-developed-by: Naveen Kumar Goud Arepalli <quic_narepall@quicinc.com> > Signed-off-by: Naveen Kumar Goud Arepalli <quic_narepall@quicinc.com> > Signed-off-by: Nitin Rawat <quic_nitirawa@quicinc.com> > --- > drivers/ufs/host/ufs-qcom.c | 104 +++++++++++++++++++++++------------- > drivers/ufs/host/ufs-qcom.h | 4 ++ > 2 files changed, 72 insertions(+), 36 deletions(-) > > diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c > index 39eef470f8fa..2721a30f0db8 100644 > --- a/drivers/ufs/host/ufs-qcom.c > +++ b/drivers/ufs/host/ufs-qcom.c > @@ -338,6 +338,46 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) > return UFS_HS_G3; > } > > +static int ufs_qcom_phy_power_on(struct ufs_hba *hba) > +{ > + struct ufs_qcom_host *host = ufshcd_get_variant(hba); > + struct phy *phy = host->generic_phy; > + int ret = 0; > + > + mutex_lock(&host->phy_mutex); You do not need mutex to protect a variable. If you want to ensure that the access to the flag is atomic, you can use test_and_{set/clear}_bit helpers. > + if (!host->is_phy_pwr_on) { > + ret = phy_power_on(phy); > + if (ret) { > + mutex_unlock(&host->phy_mutex); > + return ret; > + } > + host->is_phy_pwr_on = true; > + } > + mutex_unlock(&host->phy_mutex); > + > + return ret; > +} > + > +static int ufs_qcom_phy_power_off(struct ufs_hba *hba) > +{ > + struct ufs_qcom_host *host = ufshcd_get_variant(hba); > + struct phy *phy = host->generic_phy; > + int ret = 0; > + > + mutex_lock(&host->phy_mutex); > + if (host->is_phy_pwr_on) { > + ret = phy_power_off(phy); > + if (ret) { > + mutex_unlock(&host->phy_mutex); > + return ret; > + } > + host->is_phy_pwr_on = false; > + } > + mutex_unlock(&host->phy_mutex); > + > + return ret; > +} > + > static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) > { > struct ufs_qcom_host *host = ufshcd_get_variant(hba); > @@ -378,13 +418,18 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) > goto out_disable_phy; > > /* power on phy - start serdes and phy's power and clocks */ > - ret = phy_power_on(phy); > + ret = ufs_qcom_phy_power_on(hba); > if (ret) { > dev_err(hba->dev, "%s: phy power on failed, ret = %d\n", > __func__, ret); > goto out_disable_phy; > } > > + ret = phy_calibrate(phy); > + if (ret) { > + dev_err(hba->dev, "%s: Failed to calibrate PHY %d\n", > + __func__, ret); Even though the driver already has a lot of "__func__" to print the function names in error log, please do not add more. I will get rid of the existing ones at some point. - Mani
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 39eef470f8fa..2721a30f0db8 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -338,6 +338,46 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) return UFS_HS_G3; } +static int ufs_qcom_phy_power_on(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct phy *phy = host->generic_phy; + int ret = 0; + + mutex_lock(&host->phy_mutex); + if (!host->is_phy_pwr_on) { + ret = phy_power_on(phy); + if (ret) { + mutex_unlock(&host->phy_mutex); + return ret; + } + host->is_phy_pwr_on = true; + } + mutex_unlock(&host->phy_mutex); + + return ret; +} + +static int ufs_qcom_phy_power_off(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct phy *phy = host->generic_phy; + int ret = 0; + + mutex_lock(&host->phy_mutex); + if (host->is_phy_pwr_on) { + ret = phy_power_off(phy); + if (ret) { + mutex_unlock(&host->phy_mutex); + return ret; + } + host->is_phy_pwr_on = false; + } + mutex_unlock(&host->phy_mutex); + + return ret; +} + static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -378,13 +418,18 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) goto out_disable_phy; /* power on phy - start serdes and phy's power and clocks */ - ret = phy_power_on(phy); + ret = ufs_qcom_phy_power_on(hba); if (ret) { dev_err(hba->dev, "%s: phy power on failed, ret = %d\n", __func__, ret); goto out_disable_phy; } + ret = phy_calibrate(phy); + if (ret) { + dev_err(hba->dev, "%s: Failed to calibrate PHY %d\n", + __func__, ret); + } ufs_qcom_select_unipro_mode(host); return 0; @@ -557,26 +602,17 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct phy *phy = host->generic_phy; if (status == PRE_CHANGE) return 0; - if (ufs_qcom_is_link_off(hba)) { - /* - * Disable the tx/rx lane symbol clocks before PHY is - * powered down as the PLL source should be disabled - * after downstream clocks are disabled. - */ + if (!ufs_qcom_is_link_active(hba)) ufs_qcom_disable_lane_clks(host); - phy_power_off(phy); - /* reset the connected UFS device during power down */ - ufs_qcom_device_reset_ctrl(hba, true); - } else if (!ufs_qcom_is_link_active(hba)) { - ufs_qcom_disable_lane_clks(host); - } + /* reset the connected UFS device during power down */ + if (ufs_qcom_is_link_off(hba) && host->device_reset) + ufs_qcom_device_reset_ctrl(hba, true); return ufs_qcom_ice_suspend(host); } @@ -584,26 +620,11 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct phy *phy = host->generic_phy; int err; - if (ufs_qcom_is_link_off(hba)) { - err = phy_power_on(phy); - if (err) { - dev_err(hba->dev, "%s: failed PHY power on: %d\n", - __func__, err); - return err; - } - - err = ufs_qcom_enable_lane_clks(host); - if (err) - return err; - - } else if (!ufs_qcom_is_link_active(hba)) { - err = ufs_qcom_enable_lane_clks(host); - if (err) - return err; - } + err = ufs_qcom_enable_lane_clks(host); + if (err) + return err; return ufs_qcom_ice_resume(host); } @@ -908,6 +929,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -926,10 +948,22 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, /* disable device ref_clk */ ufs_qcom_dev_ref_clk_ctrl(host, false); } + err = ufs_qcom_phy_power_off(hba); + if (err) { + dev_err(hba->dev, "%s: phy power off failed, ret=%d\n", + __func__, err); + return err; + } } break; case POST_CHANGE: if (on) { + err = ufs_qcom_phy_power_on(hba); + if (err) { + dev_err(hba->dev, "%s: phy power on failed, ret = %d\n", + __func__, err); + return err; + } /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) ufs_qcom_dev_ref_clk_ctrl(host, true); @@ -1110,7 +1144,7 @@ static void ufs_qcom_exit(struct ufs_hba *hba) struct ufs_qcom_host *host = ufshcd_get_variant(hba); ufs_qcom_disable_lane_clks(host); - phy_power_off(host->generic_phy); + ufs_qcom_phy_power_off(hba); phy_exit(host->generic_phy); } @@ -1536,9 +1570,7 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, static void ufs_qcom_reinit_notify(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - - phy_power_off(host->generic_phy); + ufs_qcom_phy_power_off(hba); } /* Resources */ diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 9dd9a391ebb7..241dba01672e 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -215,6 +215,10 @@ struct ufs_qcom_host { u32 phy_gear; bool esi_enabled; + /* flag to check if phy is powered on */ + bool is_phy_pwr_on; + /* Protect the usage of is_phy_pwr_on against racing */ + struct mutex phy_mutex; }; static inline u32