scsi: ufs: Fix ufs power down/on specs violation
Subsystems (2)
PATCH 1/1 scsi: ufs: Fix ufs power down/on specs violation
As per specs, e.g, JESD220E chapter 7.2, while powering off/on the ufs device, RST_N signal and REF_CLK signal should be between VSS(Ground) and VCCQ/VCCQ2.
Power down:
1. Assert RST_N low
2. Turn-off REF_CLK
3. Turn-off VCC
4. Turn-off VCCQ/VCCQ2.
power on:
1. Turn-on VCC
2. Turn-on VCCQ/VCCQ2
3. Turn-On REF_CLK
4. Deassert RST_N high.
--- drivers/scsi/ufs/ufs-qcom.c | 14 ++++++++++---- drivers/scsi/ufs/ufshcd.c | 19 +++++++++---------- drivers/scsi/ufs/ufshcd.h | 4 ++-- 3 files changed, 21 insertions(+), 16 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +10 -4
@@ -582,6 +582,9 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)ufs_qcom_disable_lane_clks (host);phy_power_off (phy); +if (hba->vops && hba->vops->device_reset) + hba->vops->device_reset (hba, false); + }else if (!ufs_qcom_is_link_active (hba)) {ufs_qcom_disable_lane_clks (host); }
@@ -1400,10 +1403,11 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)/** * ufs_qcom_device_reset() - toggle the (optional) device reset line * @hba: per-adapter instance +* @toggle: need pulling up or not * * Toggles the (optional) reset line to reset the attached device. */ -static int ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba,bool toggle) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);
@@ -1416,10 +1420,12 @@ static int ufs_qcom_device_reset(struct ufs_hba *hba)* be on the safe side. */ gpiod_set_value_cansleep (host->device_reset,1 ); -usleep_range (10 ,15 ); -gpiod_set_value_cansleep (host->device_reset,0 ); -usleep_range (10 ,15 ); +if (toggle) { +usleep_range (10 ,15 ); +gpiod_set_value_cansleep (host->device_reset,0 ); +usleep_range (10 ,15 ); + }return 0 ; }
drivers/scsi/ufs/ufshcd.c +9 -10
@@ -8633,8 +8633,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_dev_active; -ufshcd_vreg_set_lpm (hba); - disable_clks:/* * Call vendor specific suspend callback. As these callbacks may access
@@ -8664,6 +8662,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm (hba); +ufshcd_vreg_set_lpm (hba); goto out; set_link_active:
@@ -8729,18 +8728,18 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) old_link_state = hba->uic_link_state;ufshcd_hba_vreg_set_hpm (hba); + ret =ufshcd_vreg_set_hpm (hba); +if (ret) + goto out; +/* Make sure clocks are enabled before accessing controller */ ret =ufshcd_setup_clocks (hba, true);if (ret) - goto out; + goto disable_vreg;/* enable the host irq as host controller would be active soon */ ufshcd_enable_irq (hba); - ret =ufshcd_vreg_set_hpm (hba); -if (ret) - goto disable_irq_and_vops_clks; -/* * Call vendor specific resume callback. As these callbacks may access * vendor specific host controller register space call them when the
@@ -8748,7 +8747,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)*/ ret =ufshcd_vops_resume (hba, pm_op);if (ret) - goto disable_vreg; + goto disable_irq_and_vops_clks;/* For DeepSleep, the only supported option is to have the link off */ WARN_ON (ufshcd_is_ufs_dev_deepsleep (hba) && !ufshcd_is_link_off (hba));
@@ -8815,8 +8814,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)ufshcd_link_state_transition (hba, old_link_state,0 ); vendor_suspend:ufshcd_vops_suspend (hba, pm_op); -disable_vreg: -ufshcd_vreg_set_lpm (hba); disable_irq_and_vops_clks:ufshcd_disable_irq (hba);if (hba->clk_scaling.is_allowed)
@@ -8827,6 +8824,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)trace_ufshcd_clk_gating (dev_name (hba->dev), hba->clk_gating.state); } +disable_vreg: +ufshcd_vreg_set_lpm (hba); out: hba->pm_op_in_progress =0 ;if (ret)
drivers/scsi/ufs/ufshcd.h +2 -2
@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -int (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba,bool );void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);
@@ -1211,7 +1211,7 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)static inline void ufshcd_vops_device_reset (struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { -int err = hba->vops->device_reset (hba); +int err = hba->vops->device_reset (hba, true);if (!err)ufshcd_set_ufs_dev_active (hba);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Quoted 27 lines · Ziqi Chen
As per specs, e.g, JESD220E chapter 7.2, while powering off/on the ufs device,
RST_Nsignal andREF_CLKsignal should be between VSS(Ground) and VCCQ/VCCQ2.Power down:
1. AssertRST_Nlow
2. Turn-offREF_CLK
3. Turn-off VCC
4. Turn-off VCCQ/VCCQ2.
power on:
1. Turn-on VCC
2. Turn-on VCCQ/VCCQ2
3. Turn-OnREF_CLK
4. DeassertRST_Nhigh.Signed-off-by Ziqi Chen <[email protected]>--- drivers/scsi/ufs/ufs-qcom.c | 14 ++++++++++---- drivers/scsi/ufs/ufshcd.c | 19 +++++++++---------- drivers/scsi/ufs/ufshcd.h | 4 ++-- 3 files changed, 21 insertions(+), 16 deletions(-)drivers/scsi/ufs/ufs-qcom.c +0
-0
drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_suspend(struct ufs_hba *hba, · line 588
Quoted 7 lines
drivers/scsi/ufs/ufs-qcom.c +3
-0@@ -582,6 +582,9 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)ufs_qcom_disable_lane_clks (host );phy_power_off (phy); +if (hba->vops && hba->vops->device_reset) + hba->vops->device_reset (hba, false); +
Can you make a new wrapper func to do this? ufs-qcom.c is the vendor driver, why call hba->vops->func() in vendor driver?
Quoted 139 lines
drivers/scsi/ufs/ufs-qcom.c +0
-0}else if (!ufs_qcom_is_link_active (hba)) {ufs_qcom_disable_lane_clks (host);drivers/scsi/ufs/ufs-qcom.c +7
-4}@@ -1400,10 +1403,11 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)/** * ufs_qcom_device_reset() - toggle the (optional) device reset line * @hba: per-adapter instance +* @toggle: need pulling up or not * * Toggles the (optional) reset line to reset the attached device. */ -static int ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba,bool toggle) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);@@ -1416,10 +1420,12 @@ static int ufs_qcom_device_reset(struct ufs_hba*hba) * be on the safe side. */ gpiod_set_value_cansleep (host->device_reset,1 ); -usleep_range (10 ,15 ); -gpiod_set_value_cansleep (host->device_reset,0 ); -usleep_range (10 ,15 ); +if (toggle) { +usleep_range (10 ,15 ); +gpiod_set_value_cansleep (host->device_reset,0 ); +usleep_range (10 ,15 ); + }return 0 ;}
drivers/scsi/ufs/ufshcd.c +0
-2@@ -8633,8 +8633,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_dev_active; - ufshcd_vreg_set_lpm(hba); - disable_clks:/* * Call vendor specific suspend callback. As these callbacks may
accessdrivers/scsi/ufs/ufshcd.c +1
-0@@ -8664,6 +8662,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm (hba ); +ufshcd_vreg_set_lpm (hba); goto out;
set_link_active:drivers/scsi/ufs/ufshcd.c +5
-5@@ -8729,18 +8728,18 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) old_link_state = hba->uic_link_state;ufshcd_hba_vreg_set_hpm (hba); + ret =ufshcd_vreg_set_hpm (hba); +if (ret) + goto out; +/* Make sure clocks are enabled before accessing controller */ ret =ufshcd_setup_clocks (hba, true);if (ret) - goto out; + goto disable_vreg;/* enable the host irq as host controller would be active soon */ ufshcd_enable_irq (hba); - ret =ufshcd_vreg_set_hpm (hba); -if (ret) - goto disable_irq_and_vops_clks; -/* * Call vendor specific resume callback. As these callbacks may access
drivers/scsi/ufs/ufshcd.c +1
-1* vendor specific host controller register space call them when the @@ -8748,7 +8747,7 @@ static int ufshcd_resume(struct ufs_hba *hba,enum ufs_pm_op pm_op) */ ret =ufshcd_vops_resume (hba, pm_op);if (ret) - goto disable_vreg; + goto disable_irq_and_vops_clks;/* For DeepSleep, the only supported option is to have the link off */
WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) &&
!ufshcd_is_link_off(hba));drivers/scsi/ufs/ufshcd.c +0
-2@@ -8815,8 +8814,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_link_state_transition(hba, old_link_state, 0); vendor_suspend: ufshcd_vops_suspend(hba, pm_op); -disable_vreg: -ufshcd_vreg_set_lpm (hba); disable_irq_and_vops_clks:ufshcd_disable_irq (hba);drivers/scsi/ufs/ufshcd.c +2
-0if (hba->clk_scaling.is_allowed)@@ -8827,6 +8824,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); } +disable_vreg: +ufshcd_vreg_set_lpm (hba); out: hba->pm_op_in_progress =0 ;drivers/scsi/ufs/ufshcd.c +0
-0if (ret)drivers/scsi/ufs/ufshcd.h +2
-2@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -int (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba,bool );void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1211,7 +1211,7 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { -int err = hba->vops->device_reset (hba); +int err = hba->vops->device_reset (hba, true);if (!err)
ufshcd_set_ufs_dev_active(hba);
Quoted 27 lines · Ziqi Chen
As per specs, e.g, JESD220E chapter 7.2, while powering off/on the ufs device,
RST_Nsignal andREF_CLKsignal should be between VSS(Ground) and VCCQ/VCCQ2.Power down:
1. AssertRST_Nlow
2. Turn-offREF_CLK
3. Turn-off VCC
4. Turn-off VCCQ/VCCQ2.
power on:
1. Turn-on VCC
2. Turn-on VCCQ/VCCQ2
3. Turn-OnREF_CLK
4. DeassertRST_Nhigh.Signed-off-by Ziqi Chen <[email protected]>--- drivers/scsi/ufs/ufs-qcom.c | 14 ++++++++++---- drivers/scsi/ufs/ufshcd.c | 19 +++++++++---------- drivers/scsi/ufs/ufshcd.h | 4 ++-- 3 files changed, 21 insertions(+), 16 deletions(-)drivers/scsi/ufs/ufs-qcom.c +0
-0
drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_suspend(struct ufs_hba *hba, · line 588
Quoted 7 lines
drivers/scsi/ufs/ufs-qcom.c +3
-0@@ -582,6 +582,9 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)ufs_qcom_disable_lane_clks (host );phy_power_off (phy); +if (hba->vops && hba->vops->device_reset) + hba->vops->device_reset (hba, false); +
Instead of doing the pull-down in ufshcd_vops_suspend(), can we do it in ufshcd_suspend()? Since it is a common problem for all soc vendors.
Quoted 50 lines
drivers/scsi/ufs/ufs-qcom.c +0
-0}else if (!ufs_qcom_is_link_active (hba)) {ufs_qcom_disable_lane_clks (host);drivers/scsi/ufs/ufs-qcom.c +7
-4}@@ -1400,10 +1403,11 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)/** * ufs_qcom_device_reset() - toggle the (optional) device reset line * @hba: per-adapter instance +* @toggle: need pulling up or not * * Toggles the (optional) reset line to reset the attached device. */ -static int ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba,bool toggle) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);@@ -1416,10 +1420,12 @@ static int ufs_qcom_device_reset(struct ufs_hba*hba) * be on the safe side. */ gpiod_set_value_cansleep (host->device_reset,1 ); -usleep_range (10 ,15 ); -gpiod_set_value_cansleep (host->device_reset,0 ); -usleep_range (10 ,15 ); +if (toggle) { +usleep_range (10 ,15 ); +gpiod_set_value_cansleep (host->device_reset,0 ); +usleep_range (10 ,15 ); + }return 0 ;}
drivers/scsi/ufs/ufshcd.c +0
-2@@ -8633,8 +8633,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_dev_active; - ufshcd_vreg_set_lpm(hba); - disable_clks:/* * Call vendor specific suspend callback. As these callbacks may
access
drivers/scsi/ufs/ufshcd.c static int ufshcd_suspend(struct ufs_hba *hba, · line 8666
Quoted 5 lines
drivers/scsi/ufs/ufshcd.c +1
-0@@ -8664,6 +8662,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm (hba ); +ufshcd_vreg_set_lpm (hba);
Can you put ufshcd_vreg_set_lpm() before ufshcd_hba_vreg_set_lpm()?
Quoted 84 lines
drivers/scsi/ufs/ufshcd.c +0
-0goto out;
set_link_active:drivers/scsi/ufs/ufshcd.c +5
-5@@ -8729,18 +8728,18 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) old_link_state = hba->uic_link_state;ufshcd_hba_vreg_set_hpm (hba); + ret =ufshcd_vreg_set_hpm (hba); +if (ret) + goto out; +/* Make sure clocks are enabled before accessing controller */ ret =ufshcd_setup_clocks (hba, true);if (ret) - goto out; + goto disable_vreg;/* enable the host irq as host controller would be active soon */ ufshcd_enable_irq (hba); - ret =ufshcd_vreg_set_hpm (hba); -if (ret) - goto disable_irq_and_vops_clks; -/* * Call vendor specific resume callback. As these callbacks may access
drivers/scsi/ufs/ufshcd.c +1
-1* vendor specific host controller register space call them when the @@ -8748,7 +8747,7 @@ static int ufshcd_resume(struct ufs_hba *hba,enum ufs_pm_op pm_op) */ ret =ufshcd_vops_resume (hba, pm_op);if (ret) - goto disable_vreg; + goto disable_irq_and_vops_clks;/* For DeepSleep, the only supported option is to have the link off */
WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) &&
!ufshcd_is_link_off(hba));drivers/scsi/ufs/ufshcd.c +0
-2@@ -8815,8 +8814,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_link_state_transition(hba, old_link_state, 0); vendor_suspend: ufshcd_vops_suspend(hba, pm_op); -disable_vreg: -ufshcd_vreg_set_lpm (hba); disable_irq_and_vops_clks:ufshcd_disable_irq (hba);drivers/scsi/ufs/ufshcd.c +2
-0if (hba->clk_scaling.is_allowed)@@ -8827,6 +8824,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); } +disable_vreg: +ufshcd_vreg_set_lpm (hba); out: hba->pm_op_in_progress =0 ;drivers/scsi/ufs/ufshcd.c +0
-0if (ret)drivers/scsi/ufs/ufshcd.h +2
-2@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -int (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba,bool );void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1211,7 +1211,7 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { -int err = hba->vops->device_reset (hba); +int err = hba->vops->device_reset (hba, true);if (!err)
ufshcd_set_ufs_dev_active(hba);
Hi Can,
Quoted 32 lines · Can Guo
Quoted 31 lines · Ziqi Chen
As per specs, e.g, JESD220E chapter 7.2, while powering off/on the ufs device,
RST_Nsignal andREF_CLKsignal should be between VSS(Ground) and VCCQ/VCCQ2.Power down:
1. AssertRST_Nlow
2. Turn-offREF_CLK
3. Turn-off VCC
4. Turn-off VCCQ/VCCQ2.
power on:
1. Turn-on VCC
2. Turn-on VCCQ/VCCQ2
3. Turn-OnREF_CLK
4. DeassertRST_Nhigh.Signed-off-by Ziqi Chen <[email protected]>--- drivers/scsi/ufs/ufs-qcom.c | 14 ++++++++++---- drivers/scsi/ufs/ufshcd.c | 19 +++++++++---------- drivers/scsi/ufs/ufshcd.h | 4 ++-- 3 files changed, 21 insertions(+), 16 deletions(-)drivers/scsi/ufs/ufs-qcom.c +0
-0@@ -582,6 +582,9 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)ufs_qcom_disable_lane_clks (host );phy_power_off (phy);
Quoted 7 lines
drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) · line 587
Quoted 3 lines
drivers/scsi/ufs/ufs-qcom.c +3
-0+if (hba->vops && hba->vops->device_reset) + hba->vops->device_reset (hba, false); +Instead of doing the pull-down in
ufshcd_vops_suspend(), can we do it inufshcd_suspend()? Since it is a common problem for all soc vendors.
Sure, agree, Thanks.
Quoted 53 lines
Quoted 53 lines
drivers/scsi/ufs/ufs-qcom.c +0
-0}else if (!ufs_qcom_is_link_active (hba)) {ufs_qcom_disable_lane_clks (host);drivers/scsi/ufs/ufs-qcom.c +7
-4}@@ -1400,10 +1403,11 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)/** * ufs_qcom_device_reset() - toggle the (optional) device reset line * @hba: per-adapter instance +* @toggle: need pulling up or not * * Toggles the (optional) reset line to reset the attached device. */ -static int ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba,bool toggle) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);@@ -1416,10 +1420,12 @@ static int ufs_qcom_device_reset(structufs_hba *hba) * be on the safe side. */ gpiod_set_value_cansleep (host->device_reset,1 ); -usleep_range (10 ,15 ); -gpiod_set_value_cansleep (host->device_reset,0 ); -usleep_range (10 ,15 ); +if (toggle) { +usleep_range (10 ,15 ); +gpiod_set_value_cansleep (host->device_reset,0 ); +usleep_range (10 ,15 ); + }return 0 ;}
drivers/scsi/ufs/ufshcd.c +0
-2@@ -8633,8 +8633,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_dev_active; - ufshcd_vreg_set_lpm(hba); - disable_clks:/* * Call vendor specific suspend callback. As these callbacks may
accessdrivers/scsi/ufs/ufshcd.c +0
-0@@ -8664,6 +8662,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
Quoted 5 lines
drivers/scsi/ufs/ufshcd.c static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) · line 8665
Quoted 3 lines
drivers/scsi/ufs/ufshcd.c +1
-0/* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm (hba); +ufshcd_vreg_set_lpm (hba);Can you put
ufshcd_vreg_set_lpm()beforeufshcd_hba_vreg_set_lpm()?
Sure, thanks.
Quoted 85 lines
Quoted 85 lines
drivers/scsi/ufs/ufshcd.c +0
-0goto out;
set_link_active:drivers/scsi/ufs/ufshcd.c +5
-5@@ -8729,18 +8728,18 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) old_link_state = hba->uic_link_state;ufshcd_hba_vreg_set_hpm (hba); + ret =ufshcd_vreg_set_hpm (hba); +if (ret) + goto out; +/* Make sure clocks are enabled before accessing controller */ ret =ufshcd_setup_clocks (hba, true);if (ret) - goto out; + goto disable_vreg;/* enable the host irq as host controller would be active soon */ ufshcd_enable_irq (hba); - ret =ufshcd_vreg_set_hpm (hba); -if (ret) - goto disable_irq_and_vops_clks; -/* * Call vendor specific resume callback. As these callbacks may access
drivers/scsi/ufs/ufshcd.c +1
-1* vendor specific host controller register space call them when the @@ -8748,7 +8747,7 @@ static int ufshcd_resume(struct ufs_hba *hba,enum ufs_pm_op pm_op) */ ret =ufshcd_vops_resume (hba, pm_op);if (ret) - goto disable_vreg; + goto disable_irq_and_vops_clks;/* For DeepSleep, the only supported option is to have the link off */
WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) &&
!ufshcd_is_link_off(hba));drivers/scsi/ufs/ufshcd.c +0
-2@@ -8815,8 +8814,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_link_state_transition(hba, old_link_state, 0); vendor_suspend: ufshcd_vops_suspend(hba, pm_op); -disable_vreg: -ufshcd_vreg_set_lpm (hba); disable_irq_and_vops_clks:ufshcd_disable_irq (hba);drivers/scsi/ufs/ufshcd.c +2
-0if (hba->clk_scaling.is_allowed)@@ -8827,6 +8824,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); } +disable_vreg: +ufshcd_vreg_set_lpm (hba); out: hba->pm_op_in_progress =0 ;drivers/scsi/ufs/ufshcd.c +0
-0if (ret)drivers/scsi/ufs/ufshcd.h +2
-2@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -int (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba,bool );void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1211,7 +1211,7 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { -int err = hba->vops->device_reset (hba); +int err = hba->vops->device_reset (hba, true);if (!err)
ufshcd_set_ufs_dev_active(hba);
Quoted 172 lines · Ziqi Chen
As per specs, e.g, JESD220E chapter 7.2, while powering off/on the ufs device,
RST_Nsignal andREF_CLKsignal should be between VSS(Ground) and VCCQ/VCCQ2.Power down:
1. AssertRST_Nlow
2. Turn-offREF_CLK
3. Turn-off VCC
4. Turn-off VCCQ/VCCQ2.
power on:
1. Turn-on VCC
2. Turn-on VCCQ/VCCQ2
3. Turn-OnREF_CLK
4. DeassertRST_Nhigh.Signed-off-by Ziqi Chen <[email protected]>--- drivers/scsi/ufs/ufs-qcom.c | 14 ++++++++++---- drivers/scsi/ufs/ufshcd.c | 19 +++++++++---------- drivers/scsi/ufs/ufshcd.h | 4 ++-- 3 files changed, 21 insertions(+), 16 deletions(-)drivers/scsi/ufs/ufs-qcom.c +3
-0@@ -582,6 +582,9 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)ufs_qcom_disable_lane_clks (host );phy_power_off (phy); +if (hba->vops && hba->vops->device_reset) + hba->vops->device_reset (hba, false); + }else if (!ufs_qcom_is_link_active (hba)) {ufs_qcom_disable_lane_clks (host);drivers/scsi/ufs/ufs-qcom.c +7
-4}@@ -1400,10 +1403,11 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)/** * ufs_qcom_device_reset() - toggle the (optional) device reset line * @hba: per-adapter instance +* @toggle: need pulling up or not * * Toggles the (optional) reset line to reset the attached device. */ -static int ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba,bool toggle) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);@@ -1416,10 +1420,12 @@ static int ufs_qcom_device_reset(struct ufs_hba*hba) * be on the safe side. */ gpiod_set_value_cansleep (host->device_reset,1 ); -usleep_range (10 ,15 ); -gpiod_set_value_cansleep (host->device_reset,0 ); -usleep_range (10 ,15 ); +if (toggle) { +usleep_range (10 ,15 ); +gpiod_set_value_cansleep (host->device_reset,0 ); +usleep_range (10 ,15 ); + }return 0 ;}
drivers/scsi/ufs/ufshcd.c +0
-2@@ -8633,8 +8633,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_dev_active; - ufshcd_vreg_set_lpm(hba); - disable_clks:/* * Call vendor specific suspend callback. As these callbacks may
accessdrivers/scsi/ufs/ufshcd.c +1
-0@@ -8664,6 +8662,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm (hba ); +ufshcd_vreg_set_lpm (hba); goto out;
set_link_active:drivers/scsi/ufs/ufshcd.c +5
-5@@ -8729,18 +8728,18 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) old_link_state = hba->uic_link_state;ufshcd_hba_vreg_set_hpm (hba); + ret =ufshcd_vreg_set_hpm (hba); +if (ret) + goto out; +/* Make sure clocks are enabled before accessing controller */ ret =ufshcd_setup_clocks (hba, true);if (ret) - goto out; + goto disable_vreg;/* enable the host irq as host controller would be active soon */ ufshcd_enable_irq (hba); - ret =ufshcd_vreg_set_hpm (hba); -if (ret) - goto disable_irq_and_vops_clks; -/* * Call vendor specific resume callback. As these callbacks may access
drivers/scsi/ufs/ufshcd.c +1
-1* vendor specific host controller register space call them when the @@ -8748,7 +8747,7 @@ static int ufshcd_resume(struct ufs_hba *hba,enum ufs_pm_op pm_op) */ ret =ufshcd_vops_resume (hba, pm_op);if (ret) - goto disable_vreg; + goto disable_irq_and_vops_clks;/* For DeepSleep, the only supported option is to have the link off */
WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) &&
!ufshcd_is_link_off(hba));drivers/scsi/ufs/ufshcd.c +0
-2@@ -8815,8 +8814,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_link_state_transition(hba, old_link_state, 0); vendor_suspend: ufshcd_vops_suspend(hba, pm_op); -disable_vreg: -ufshcd_vreg_set_lpm (hba); disable_irq_and_vops_clks:ufshcd_disable_irq (hba);drivers/scsi/ufs/ufshcd.c +2
-0if (hba->clk_scaling.is_allowed)@@ -8827,6 +8824,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); } +disable_vreg: +ufshcd_vreg_set_lpm (hba); out: hba->pm_op_in_progress =0 ;drivers/scsi/ufs/ufshcd.c +0
-0if (ret)drivers/scsi/ufs/ufshcd.h +2
-2@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -int (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba,bool );void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1211,7 +1211,7 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { -int err = hba->vops->device_reset (hba); +int err = hba->vops->device_reset (hba, true);if (!err)
Quoted 1 line
ufshcd_set_ufs_dev_active(hba);
Please check Stanley's new change https://lore.kernel.org/patchwork/patch/1350843/.
You may want to re-name the func ufschd_vops_device_reset() to ufshcd_vops_toggle_device_reset(sturct ufs_hba *hba, bool up) and similarly re-name device_reset() to toggle_device_reset(hba, up). Then in the new func ufshcd_device_reset(), call ufshcd_vops_toggle_device_reset() twice, once to toggle up, once to toggle down. In this way, you will be able to use ufshcd_vops_toggle_device_reset() in ufshcd_suspend().
This is just a rough idea.
Thanks,
Can Guo.