Skip to contentSkip to conversation

scsi: ufs: Fix ufs power down/on specs violation

RFC PATCH Superseded Ziqi Chen 3 participants 7 messages Dec 21, 2020 – Dec 22, 2020

Subsystems (3)

v3 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Ziqi Chen

author
#0 lore raw

RFC PATCH v3 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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43 ++++++++++++++++++++++++++++++-----------
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs-mediatek.c +9 -18
index 80618af..bff2c42 100644
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
 	return 0;
 }
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
 
drivers/scsi/ufs/ufs-qcom.c +10 -12
index 2206b1e..c2ccaa5 100644
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
 }
 
 /**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device reset line
  * @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
  *
  * Toggles the (optional) reset line to reset the attached device.
  */
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
 
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct ufs_hba *hba)
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us to
-	 * 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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
 };
drivers/scsi/ufs/ufshcd.c +32 -11

105 lines not on this page · raw message

drivers/scsi/ufs/ufshcd.h +5 -5
index 9bb5f0e..dccc3eb 100644
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio on the UFS device
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
  */
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
 
 	return -EOPNOTSUPP;
 }
Signature · 8 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek
#1 lore raw
Quoted 97 lines · Ziqi Chen

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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43 ++++++++++++++++++++++++++++++-----------
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs-mediatek.c +9 -18
index 80618af..bff2c42 100644
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
 	return 0;
 }
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
 
drivers/scsi/ufs/ufs-qcom.c +3 -6
index 2206b1e..c2ccaa5 100644
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
 }
 
 /**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device reset line
  * @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
  *
  * Toggles the (optional) reset line to reset the attached device.
  */
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
 
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct ufs_hba *hba)
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us to
-	 * be on the safe side.
-	 */

drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_device_reset(struct ufs_hba *hba) · line 1425

Quoted 10 lines
drivers/scsi/ufs/ufs-qcom.c +5 -5
-	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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);

The comment above describes that the reset pulse should be 10uS, so the only reason I can see for the sleep here would be for devices to come back up after the reset pulse - i.e. what Mediatek believes needs 10-15mS.

As such, I would like you to move this sleep out to the caller and then turns this snippet into just:

	gpiod_set_value_cansleep(host->device_reset, down);

I don't see a problem using Mediatek's reasoning and sleep values in the common case.

Quoted 18 lines
drivers/scsi/ufs/ufs-qcom.c +2 -1
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
 };
drivers/scsi/ufs/ufshcd.c +0 -0
index e221add..2ee905f 100644

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba *hba) · line 590

Quoted 7 lines
drivers/scsi/ufs/ufshcd.c +3 -1
@@ -585,7 +585,20 @@ static void ufshcd_device_reset(struct ufs_hba *hba)
 {
 	int err;
 
-	err = ufshcd_vops_device_reset(hba);
+	err = ufshcd_vops_toggle_device_reset(hba, true);
+	if (err) {
+		dev_err(hba->dev, "device reset pulling down failure: %d\n", err);

"asserting device reset failed"

Quoted 15 lines
drivers/scsi/ufs/ufshcd.c +11 -0
+		return;
+	}
+
+	/*
+	 * The reset signal is active low. The UFS device
+	 * shall detect reset pulses of 1us, sleep for at
+	 * least 10us to be on the safe side.
+	 */
+	usleep_range(10, 15);
+
+	err = ufshcd_vops_toggle_device_reset(hba, false);
 
 	if (!err) {
 		ufshcd_set_ufs_dev_active(hba);

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba *hba) · line 609

Quoted 4 lines
drivers/scsi/ufs/ufshcd.c +1 -0
@@ -593,7 +606,11 @@ static void ufshcd_device_reset(struct ufs_hba *hba)
 			hba->wb_enabled = false;
 			hba->wb_buf_flush_enabled = false;
 		}
+		dev_info(hba->dev, "device reset done\n");

Please use dev_dbg(), as this is only interesting to us when we're actually debugging UFS related issues.

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba *hba) · line 611

Quoted 2 lines
drivers/scsi/ufs/ufshcd.c +2 -0
+	} else {
+		dev_err(hba->dev, "device reset pulling up failure: %d\n", err);

"deasserting device reset failed"

Quoted 99 lines
drivers/scsi/ufs/ufshcd.c +15 -10
 	}
+
 	if (err != -EOPNOTSUPP)
 		ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);
 }
@@ -8686,8 +8703,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
@@ -8703,6 +8718,9 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 	 */
 	ufshcd_disable_irq(hba);
 
+	if (ufshcd_is_link_off(hba))
+		ufshcd_vops_toggle_device_reset(hba, true);
+
 	ufshcd_setup_clocks(hba, false);
 
 	if (ufshcd_is_clkgating_allowed(hba)) {
@@ -8711,6 +8729,8 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 					hba->clk_gating.state);
 	}
 
+	ufshcd_vreg_set_lpm(hba);
+
 	/* Put the host controller in low power mode if possible */
 	ufshcd_hba_vreg_set_lpm(hba);
 	goto out;
@@ -8778,18 +8798,19 @@ 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
@@ -8797,7 +8818,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));
@@ -8864,8 +8885,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)
@@ -8876,6 +8895,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 +1 -1
index 9bb5f0e..dccc3eb 100644
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio on the UFS device
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
  */

drivers/scsi/ufs/ufshcd.h struct ufs_hba_variant_ops { · line 353

Quoted 5 lines
drivers/scsi/ufs/ufshcd.h +1 -1
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);

I don't think "toggle" adds any value to the understanding of what this function is expected to do, so I would prefer that you just keep it "device_reset".

I also would prefer that you replace "down" with "asserted" - as this avoids questions about active high/low etc from the API.

Thanks,
Bjorn

Quoted 21 lines
drivers/scsi/ufs/ufshcd.h +3 -3
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
 
 	return -EOPNOTSUPP;
 }
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek

#2 lore raw
Quoted 124 lines · Bjorn Andersson
Quoted 106 lines · Ziqi Chen

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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43 
++++++++++++++++++++++++++++++-----------
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs-mediatek.c +8 -17
index 80618af..bff2c42 100644
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct 
 ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool 
 down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
drivers/scsi/ufs/ufs-mediatek.c +1 -1
 	return 0;
 }
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops 
 ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
drivers/scsi/ufs/ufs-qcom.c +1 -1
index 2206b1e..c2ccaa5 100644
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct 
 ufs_hba *hba)
 }
 
 /**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device 

reset line
* @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
*
* Toggles the (optional) reset line to reset the attached device. */

drivers/scsi/ufs/ufs-qcom.c +1 -1
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool 

down)
{

drivers/scsi/ufs/ufs-qcom.c +0 -2
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct 
 ufs_hba *hba)
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us 

to

drivers/scsi/ufs/ufs-qcom.c +0 -2
-	 * be on the safe side.
-	 */

drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_device_reset(struct ufs_hba *hba) · line 1425

Quoted 10 lines
drivers/scsi/ufs/ufs-qcom.c +5 -5
-	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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);

The comment above describes that the reset pulse should be 10uS, so the only reason I can see for the sleep here would be for devices to come back up after the reset pulse - i.e. what Mediatek believes needs 10-15mS.

Quoted 7 lines

As such, I would like you to move this sleep out to the caller and then turns this snippet into just:

	gpiod_set_value_cansleep(host->device_reset, down);

I don't see a problem using Mediatek's reasoning and sleep values in the common case.

Understood. It would better to move this sleep (10-15ms)out to the caller and simplify this function.

Quoted 24 lines
Quoted 24 lines
drivers/scsi/ufs/ufs-qcom.c +2 -1
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops 
 ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,

};

drivers/scsi/ufs/ufshcd.c +0 -0
index e221add..2ee905f 100644
@@ -585,7 +585,20 @@ static void ufshcd_device_reset(struct ufs_hba 
 *hba)
 {
 	int err;
 
Quoted 6 lines

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba *hba) · line 590

Quoted 4 lines
drivers/scsi/ufs/ufshcd.c +3 -1
-	err = ufshcd_vops_device_reset(hba);
+	err = ufshcd_vops_toggle_device_reset(hba, true);
+	if (err) {
+		dev_err(hba->dev, "device reset pulling down failure: %d\n", err);

"asserting device reset failed"

Agree, thanks.

Quoted 13 lines
Quoted 13 lines
drivers/scsi/ufs/ufshcd.c +11 -0
+		return;
+	}
+
+	/*
+	 * The reset signal is active low. The UFS device
+	 * shall detect reset pulses of 1us, sleep for at
+	 * least 10us to be on the safe side.
+	 */
+	usleep_range(10, 15);
+
+	err = ufshcd_vops_toggle_device_reset(hba, false);
 
Quoted 11 lines

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba · line 610

Quoted 8 lines
drivers/scsi/ufs/ufshcd.c +0 -0
 	if (!err) {
drivers/scsi/ufs/ufshcd.c +1 -0
 		ufshcd_set_ufs_dev_active(hba);
@@ -593,7 +606,11 @@ static void ufshcd_device_reset(struct ufs_hba 
 *hba)
 			hba->wb_enabled = false;
 			hba->wb_buf_flush_enabled = false;
 		}
+		dev_info(hba->dev, "device reset done\n");

Please use dev_dbg(), as this is only interesting to us when we're actually debugging UFS related issues.

Agree, thanks.

Quoted 5 lines

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba *hba) · line 611

Quoted 3 lines
drivers/scsi/ufs/ufshcd.c +2 -0
+	} else {
+		dev_err(hba->dev, "device reset pulling up failure: %d\n", err);

"deasserting device reset failed"

Agree, thanks.

Quoted 122 lines
Quoted 112 lines
drivers/scsi/ufs/ufshcd.c +1 -0
 	}
+
 	if (err != -EOPNOTSUPP)
 		ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);

}

drivers/scsi/ufs/ufshcd.c +0 -2
@@ -8686,8 +8703,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 +3 -0
@@ -8703,6 +8718,9 @@ static int ufshcd_suspend(struct ufs_hba *hba, 
 enum ufs_pm_op pm_op)
 	 */
 	ufshcd_disable_irq(hba);
 
+	if (ufshcd_is_link_off(hba))
+		ufshcd_vops_toggle_device_reset(hba, true);
+
 	ufshcd_setup_clocks(hba, false);
 
drivers/scsi/ufs/ufshcd.c +2 -0
 	if (ufshcd_is_clkgating_allowed(hba)) {
@@ -8711,6 +8729,8 @@ static int ufshcd_suspend(struct ufs_hba *hba, 
 enum ufs_pm_op pm_op)
 					hba->clk_gating.state);
 	}
 
+	ufshcd_vreg_set_lpm(hba);
+
 	/* Put the host controller in low power mode if possible */
 	ufshcd_hba_vreg_set_lpm(hba);
drivers/scsi/ufs/ufshcd.c +6 -5
 	goto out;
@@ -8778,18 +8798,19 @@ 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
@@ -8797,7 +8818,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
@@ -8864,8 +8885,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 -0
 	if (hba->clk_scaling.is_allowed)
@@ -8876,6 +8895,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 -0
 	if (ret)
drivers/scsi/ufs/ufshcd.h +1 -1
index 9bb5f0e..dccc3eb 100644
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio 

on the UFS device
* @program_key: program or evict an inline encryption key
* @event_notify: called to notify important events */

drivers/scsi/ufs/ufshcd.h struct ufs_hba_variant_ops { · line 353

Quoted 5 lines
drivers/scsi/ufs/ufshcd.h +1 -1
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);

I don't think "toggle" adds any value to the understanding of what this function is expected to do, so I would prefer that you just keep it "device_reset".

Quoted 5 lines

I also would prefer that you replace "down" with "asserted" - as this avoids questions about active high/low etc from the API.

Thanks,
Bjorn

Agree, thanks.

Best Regards,
Ziqi

Quoted 18 lines
Quoted 18 lines
drivers/scsi/ufs/ufshcd.h +3 -3
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void 
 ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba 
 *hba, bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
 
Quoted 6 lines
Quoted 6 lines

return -EOPNOTSUPP;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek

#3 lore raw
In reply to Ziqi Chen
Quoted 10 lines

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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Quoted 7 lines
Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43 ++++++++++++++++++++++++++++++------

--

Quoted 122 lines
---
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs- renamed from drivers/scsi/ufs/ufs-mediatek.c +0 -0

mediatek.c index 80618af..bff2c42 100644

drivers/scsi/ufs/ufs-mediatek.c +8 -17
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct
 ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
 	return 0;

}

drivers/scsi/ufs/ufs-mediatek.c +1 -1
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
drivers/scsi/ufs/ufs-qcom.c +4 -4
index 2206b1e..c2ccaa5 100644
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba
 *hba)  }
 
 /**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device reset
+ line
  * @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
  *
  * Toggles the (optional) reset line to reset the attached device.
  */
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool down)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct ufs_hba
 *hba)
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us

to

drivers/scsi/ufs/ufs-qcom.c +7 -8
-	 * 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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,

};

drivers/scsi/ufs/ufshcd.c index renamed from drivers/scsi/ufs/ufshcd.c +0 -0

e221add..2ee905f 100644

drivers/scsi/ufs/ufshcd.c +3 -1
@@ -585,7 +585,20 @@ static void ufshcd_device_reset(struct ufs_hba *hba)
 {
 	int err;
 
-	err = ufshcd_vops_device_reset(hba);
+	err = ufshcd_vops_toggle_device_reset(hba, true);
+	if (err) {
+		dev_err(hba->dev, "device reset pulling down failure: %d\n",

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba *hba) · line 600

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +9 -0
 err);
+		return;
+	}
+
+	/*
+	 * The reset signal is active low. The UFS device
+	 * shall detect reset pulses of 1us, sleep for at
+	 * least 10us to be on the safe side.
+	 */
+	usleep_range(10, 15);

Is there any point where UFS specification tells this explicitly? I think this should be moved only if the number, i.e. 10 and 15 just relies on hardware conditions.

Thanks.
Kiwoong Kim

Quoted 26 lines
drivers/scsi/ufs/ufshcd.c +5 -0
+	err = ufshcd_vops_toggle_device_reset(hba, false);
 
 	if (!err) {
 		ufshcd_set_ufs_dev_active(hba);
@@ -593,7 +606,11 @@ static void ufshcd_device_reset(struct ufs_hba *hba)
 			hba->wb_enabled = false;
 			hba->wb_buf_flush_enabled = false;
 		}
+		dev_info(hba->dev, "device reset done\n");
+	} else {
+		dev_err(hba->dev, "device reset pulling up failure: %d\n",
 err);
 	}
+
 	if (err != -EOPNOTSUPP)
 		ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);  } @@ -

8686,8 +8703,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +0 -2
 	if (ret)
 		goto set_dev_active;
 
-	ufshcd_vreg_set_lpm(hba);
-
 disable_clks:
 	/*
 	 * Call vendor specific suspend callback. As these callbacks may
Quoted 1 line

access @@ -8703,6 +8718,9 @@ static int ufshcd_suspend(struct ufs_hba

*hba,

Quoted 117 lines

enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +3 -0
 	 */
 	ufshcd_disable_irq(hba);
 
+	if (ufshcd_is_link_off(hba))
+		ufshcd_vops_toggle_device_reset(hba, true);
+
 	ufshcd_setup_clocks(hba, false);
 
 	if (ufshcd_is_clkgating_allowed(hba)) { @@ -8711,6 +8729,8 @@

static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +8 -5
 					hba->clk_gating.state);
 	}
 
+	ufshcd_vreg_set_lpm(hba);
+
 	/* Put the host controller in low power mode if possible */
 	ufshcd_hba_vreg_set_lpm(hba);
 	goto out;
@@ -8778,18 +8798,19 @@ 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 @@ -8797,7 +8818,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +1 -1
 	 */
 	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)); @@ -8864,8 +8885,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +2 -2
 	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)
@@ -8876,6 +8895,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 -0
 	if (ret)
drivers/scsi/ufs/ufshcd.h index renamed from drivers/scsi/ufs/ufshcd.h +0 -0

9bb5f0e..dccc3eb 100644

drivers/scsi/ufs/ufshcd.h +7 -6
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio on
+ the UFS device
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
  */
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void
 ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba *hba,
+bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
 
 	return -EOPNOTSUPP;
 }
--
Quoted 2 lines

The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek

#4 lore raw
Quoted 163 lines · Kiwoong Kim
Quoted 10 lines

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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Quoted 8 lines
Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43 

++++++++++++++++++++++++++++++------

--

Quoted 128 lines
---
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs- renamed from drivers/scsi/ufs/ufs-mediatek.c +0 -0

mediatek.c index 80618af..bff2c42 100644

drivers/scsi/ufs/ufs-mediatek.c +8 -17
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct
 ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool 
 down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
drivers/scsi/ufs/ufs-mediatek.c +1 -1
 	return 0;
 }
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
drivers/scsi/ufs/ufs-qcom.c +0 -0
index 2206b1e..c2ccaa5 100644
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct 

ufs_hba
*hba) }

/**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device reset
+ line
* @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
*
* Toggles the (optional) reset line to reset the attached device. */

drivers/scsi/ufs/ufs-qcom.c +1 -1
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool 

down)
{

drivers/scsi/ufs/ufs-qcom.c +0 -0
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct 

ufs_hba
*hba)

drivers/scsi/ufs/ufs-qcom.c +0 -2
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us

to

drivers/scsi/ufs/ufs-qcom.c +7 -8
-	 * 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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,

};

drivers/scsi/ufs/ufshcd.c index renamed from drivers/scsi/ufs/ufshcd.c +0 -0

e221add..2ee905f 100644

drivers/scsi/ufs/ufshcd.c +3 -1
@@ -585,7 +585,20 @@ static void ufshcd_device_reset(struct ufs_hba 
 *hba)
 {
 	int err;
 
-	err = ufshcd_vops_device_reset(hba);
+	err = ufshcd_vops_toggle_device_reset(hba, true);
+	if (err) {
+		dev_err(hba->dev, "device reset pulling down failure: %d\n",

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba · line 601

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +9 -0
 err);
+		return;
+	}
+
+	/*
+	 * The reset signal is active low. The UFS device
+	 * shall detect reset pulses of 1us, sleep for at
+	 * least 10us to be on the safe side.
+	 */
+	usleep_range(10, 15);

Is there any point where UFS specification tells this explicitly? I think this should be moved only if the number, i.e. 10 and 15 just relies on hardware conditions.

Quoted 2 lines

Thanks.
Kiwoong Kim

Hi Kiwoong,

Thanks for your comment. JESD220E Line 610~611 "The UFS device shall detect more than or equal to 1us of positive or negative RST_n pulse". Both QCOM and Mediatek use 10~15us. What
number do you think more appropriate?

Best Regards,
Ziqi

Quoted 148 lines
Quoted 148 lines
drivers/scsi/ufs/ufshcd.c +5 -0
+	err = ufshcd_vops_toggle_device_reset(hba, false);
 
 	if (!err) {
 		ufshcd_set_ufs_dev_active(hba);
@@ -593,7 +606,11 @@ static void ufshcd_device_reset(struct ufs_hba 
 *hba)
 			hba->wb_enabled = false;
 			hba->wb_buf_flush_enabled = false;
 		}
+		dev_info(hba->dev, "device reset done\n");
+	} else {
+		dev_err(hba->dev, "device reset pulling up failure: %d\n",
 err);
 	}
+
 	if (err != -EOPNOTSUPP)

ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err); } @@ -
8686,8 +8703,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +0 -2
 	if (ret)
 		goto set_dev_active;
 
-	ufshcd_vreg_set_lpm(hba);
-
 disable_clks:
 	/*
 	 * Call vendor specific suspend callback. As these callbacks may

access @@ -8703,6 +8718,9 @@ static int ufshcd_suspend(struct ufs_hba *hba,
enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +3 -0
 	 */
 	ufshcd_disable_irq(hba);
 
+	if (ufshcd_is_link_off(hba))
+		ufshcd_vops_toggle_device_reset(hba, true);
+
 	ufshcd_setup_clocks(hba, false);
 
 	if (ufshcd_is_clkgating_allowed(hba)) { @@ -8711,6 +8729,8 @@

static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +2 -0
 					hba->clk_gating.state);
 	}
 
+	ufshcd_vreg_set_lpm(hba);
+
 	/* Put the host controller in low power mode if possible */
 	ufshcd_hba_vreg_set_lpm(hba);
 	goto out;
@@ -8778,18 +8798,19 @@ static int ufshcd_resume(struct ufs_hba *hba, 

enum
ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +6 -5
 	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 @@ -8797,7 +8818,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +1 -1
 	 */
 	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)); @@ -8864,8 +8885,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +0 -2
 	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)
@@ -8876,6 +8895,8 @@ static int ufshcd_resume(struct ufs_hba *hba, 

enum
ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +2 -0
 		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 index renamed from drivers/scsi/ufs/ufshcd.h +0 -0

9bb5f0e..dccc3eb 100644

drivers/scsi/ufs/ufshcd.h +1 -1
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio 

on
+ the UFS device
* @program_key: program or evict an inline encryption key
* @event_notify: called to notify important events */

drivers/scsi/ufs/ufshcd.h +5 -4
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void
 ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba 
 *hba,
+bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
Quoted 5 lines
Quoted 5 lines

return -EOPNOTSUPP;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek

#5 lore raw
Quoted 169 lines · Kiwoong Kim
Quoted 163 lines
Quoted 10 lines

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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Quoted 8 lines
Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43

++++++++++++++++++++++++++++++------

--

Quoted 128 lines
---
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs- renamed from drivers/scsi/ufs/ufs-mediatek.c +0 -0

mediatek.c index 80618af..bff2c42 100644

drivers/scsi/ufs/ufs-mediatek.c +8 -17
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct
 ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool
 down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
drivers/scsi/ufs/ufs-mediatek.c +1 -1
 	return 0;
 }
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
(quoted diff) +0 -0

b/drivers/scsi/ufs/ufs-qcom.c index 2206b1e..c2ccaa5 100644

drivers/scsi/ufs/ufs-qcom.c +0 -0
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct

ufs_hba
*hba) }

/**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device reset
+ line
* @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
*
* Toggles the (optional) reset line to reset the attached device. */

drivers/scsi/ufs/ufs-qcom.c +1 -1
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool

down)
{

drivers/scsi/ufs/ufs-qcom.c +0 -0
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct

ufs_hba
*hba)

drivers/scsi/ufs/ufs-qcom.c +0 -2
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us

to

drivers/scsi/ufs/ufs-qcom.c +7 -8
-	 * 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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,

};

drivers/scsi/ufs/ufshcd.c +3 -1
index e221add..2ee905f 100644
@@ -585,7 +585,20 @@ static void ufshcd_device_reset(struct ufs_hba
 *hba)
 {
 	int err;
 
-	err = ufshcd_vops_device_reset(hba);
+	err = ufshcd_vops_toggle_device_reset(hba, true);
+	if (err) {
+		dev_err(hba->dev, "device reset pulling down failure: %d\n",

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba · line 601

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +9 -0
 err);
+		return;
+	}
+
+	/*
+	 * The reset signal is active low. The UFS device
+	 * shall detect reset pulses of 1us, sleep for at
+	 * least 10us to be on the safe side.
+	 */
+	usleep_range(10, 15);

Is there any point where UFS specification tells this explicitly? I think this should be moved only if the number, i.e. 10 and 15 just relies on hardware conditions.

Quoted 2 lines

Thanks.
Kiwoong Kim

Hi Kiwoong,

Quoted 7 lines

Thanks for your comment. JESD220E Line 610~611 "The UFS device shall detect more than or equal to 1us of positive or negative RST_n pulse". Both QCOM and Mediatek use 10~15us. What number do you think more appropriate?

Best Regards,
Ziqi

With yours, all the SoC vendors should wait for around 10us unconditionally even if there will be a possibility that some can use shorter period. I see this as a sort of optimization point.

Thanks.
Kiwoong Kim

Quoted 146 lines
Quoted 146 lines
Quoted 146 lines
drivers/scsi/ufs/ufshcd.c +5 -0
+	err = ufshcd_vops_toggle_device_reset(hba, false);
 
 	if (!err) {
 		ufshcd_set_ufs_dev_active(hba);
@@ -593,7 +606,11 @@ static void ufshcd_device_reset(struct ufs_hba
 *hba)
 			hba->wb_enabled = false;
 			hba->wb_buf_flush_enabled = false;
 		}
+		dev_info(hba->dev, "device reset done\n");
+	} else {
+		dev_err(hba->dev, "device reset pulling up failure: %d\n",
 err);
 	}
+
 	if (err != -EOPNOTSUPP)

ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err); } @@ -
8686,8 +8703,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +0 -2
 	if (ret)
 		goto set_dev_active;
 
-	ufshcd_vreg_set_lpm(hba);
-
 disable_clks:
 	/*
 	 * Call vendor specific suspend callback. As these callbacks may

access @@ -8703,6 +8718,9 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +3 -0
 	 */
 	ufshcd_disable_irq(hba);
 
+	if (ufshcd_is_link_off(hba))
+		ufshcd_vops_toggle_device_reset(hba, true);
+
 	ufshcd_setup_clocks(hba, false);
 
 	if (ufshcd_is_clkgating_allowed(hba)) { @@ -8711,6 +8729,8 @@

static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +8 -5
 					hba->clk_gating.state);
 	}
 
+	ufshcd_vreg_set_lpm(hba);
+
 	/* Put the host controller in low power mode if possible */
 	ufshcd_hba_vreg_set_lpm(hba);
 	goto out;
@@ -8778,18 +8798,19 @@ 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 @@ -8797,7 +8818,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +1 -1
 	 */
 	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)); @@ -8864,8 +8885,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +2 -2
 	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)
@@ -8876,6 +8895,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 -0
 	if (ret)
drivers/scsi/ufs/ufshcd.h +1 -1
index 9bb5f0e..dccc3eb 100644
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio

on
+ the UFS device
* @program_key: program or evict an inline encryption key
* @event_notify: called to notify important events */

drivers/scsi/ufs/ufshcd.h +5 -4
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void
 ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba
 *hba,
+bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

return -EOPNOTSUPP;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek

#6 lore raw
Quoted 177 lines · Kiwoong Kim
Quoted 169 lines · Kiwoong Kim
Quoted 163 lines
Quoted 10 lines

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.

To flexibly control device reset line, re-name the function ufschd_vops_device_reset(sturct ufs_hba *hba) to ufshcd_ vops_toggle_device_reset(sturct ufs_hba *hba, bool down). The new parameter "bool down" is used to separate device reset line pulling down from pulling up.

Quoted 8 lines
Cc Kiwoong Kim <[email protected]>
Cc Stanley Chu <[email protected]>
---
 drivers/scsi/ufs/ufs-mediatek.c | 27 +++++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c     | 22 ++++++++++-----------
 drivers/scsi/ufs/ufshcd.c       | 43

++++++++++++++++++++++++++++++------

--

Quoted 128 lines
---
 drivers/scsi/ufs/ufshcd.h       | 10 +++++-----
 4 files changed, 56 insertions(+), 46 deletions(-)
drivers/scsi/ufs/ufs- renamed from drivers/scsi/ufs/ufs-mediatek.c +0 -0

mediatek.c index 80618af..bff2c42 100644

drivers/scsi/ufs/ufs-mediatek.c +8 -17
@@ -841,27 +841,18 @@ static int ufs_mtk_link_startup_notify(struct
 ufs_hba *hba,
 	return ret;
 }
 
-static int ufs_mtk_device_reset(struct ufs_hba *hba)
+static int ufs_mtk_toggle_device_reset(struct ufs_hba *hba, bool
 down)
 {
 	struct arm_smccc_res res;
 
-	ufs_mtk_device_reset_ctrl(0, res);
-
-	/*
-	 * The reset signal is active low. UFS devices shall detect
-	 * more than or equal to 1us of positive or negative RST_n
-	 * pulse width.
-	 *
-	 * To be on safe side, keep the reset low for at least 10us.
-	 */
-	usleep_range(10, 15);
-
-	ufs_mtk_device_reset_ctrl(1, res);
-
-	/* Some devices may need time to respond to rst_n */
-	usleep_range(10000, 15000);
+	if (down) {
+		ufs_mtk_device_reset_ctrl(0, res);
+	} else {
+		ufs_mtk_device_reset_ctrl(1, res);
 
-	dev_info(hba->dev, "device reset done\n");
+		/* Some devices may need time to respond to rst_n */
+		usleep_range(10000, 15000);
+	}
 
drivers/scsi/ufs/ufs-mediatek.c +1 -1
 	return 0;
 }
@@ -1052,7 +1043,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_mtk_vops = {
 	.suspend             = ufs_mtk_suspend,
 	.resume              = ufs_mtk_resume,
 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
-	.device_reset        = ufs_mtk_device_reset,
+	.toggle_device_reset        = ufs_mtk_toggle_device_reset,
 	.event_notify        = ufs_mtk_event_notify,
 };
(quoted diff) +0 -0

b/drivers/scsi/ufs/ufs-qcom.c index 2206b1e..c2ccaa5 100644

drivers/scsi/ufs/ufs-qcom.c +0 -0
@@ -1404,12 +1404,13 @@ static void ufs_qcom_dump_dbg_regs(struct

ufs_hba
*hba) }

/**
- * ufs_qcom_device_reset() - toggle the (optional) device reset line
+ * ufs_qcom_toggle_device_reset() - toggle the (optional) device reset
+ line
* @hba: per-adapter instance
+ * @down: pull down or pull up device reset line
*
* Toggles the (optional) reset line to reset the attached device. */

drivers/scsi/ufs/ufs-qcom.c +1 -1
-static int ufs_qcom_device_reset(struct ufs_hba *hba)
+static int ufs_qcom_toggle_device_reset(struct ufs_hba *hba, bool

down)
{

drivers/scsi/ufs/ufs-qcom.c +0 -0
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1417,15 +1418,12 @@ static int ufs_qcom_device_reset(struct

ufs_hba
*hba)

drivers/scsi/ufs/ufs-qcom.c +0 -2
 	if (!host->device_reset)
 		return -EOPNOTSUPP;
 
-	/*
-	 * The UFS device shall detect reset pulses of 1us, sleep for 10us

to

drivers/scsi/ufs/ufs-qcom.c +7 -8
-	 * 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 (down) {
+		gpiod_set_value_cansleep(host->device_reset, 1);
+	} else {
+		gpiod_set_value_cansleep(host->device_reset, 0);
+		usleep_range(10, 15);
+	}
 
 	return 0;
 }
@@ -1473,7 +1471,7 @@ static const struct ufs_hba_variant_ops
 ufs_hba_qcom_vops = {
 	.suspend		= ufs_qcom_suspend,
 	.resume			= ufs_qcom_resume,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
-	.device_reset		= ufs_qcom_device_reset,
+	.toggle_device_reset		= ufs_qcom_toggle_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,

};

drivers/scsi/ufs/ufshcd.c +3 -1
index e221add..2ee905f 100644
@@ -585,7 +585,20 @@ static void ufshcd_device_reset(struct ufs_hba
 *hba)
 {
 	int err;
 
-	err = ufshcd_vops_device_reset(hba);
+	err = ufshcd_vops_toggle_device_reset(hba, true);
+	if (err) {
+		dev_err(hba->dev, "device reset pulling down failure: %d\n",

drivers/scsi/ufs/ufshcd.c static void ufshcd_device_reset(struct ufs_hba · line 601

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +9 -0
 err);
+		return;
+	}
+
+	/*
+	 * The reset signal is active low. The UFS device
+	 * shall detect reset pulses of 1us, sleep for at
+	 * least 10us to be on the safe side.
+	 */
+	usleep_range(10, 15);

Is there any point where UFS specification tells this explicitly? I think this should be moved only if the number, i.e. 10 and 15 just relies on hardware conditions.

Quoted 2 lines

Thanks.
Kiwoong Kim

Hi Kiwoong,

Quoted 7 lines

Thanks for your comment. JESD220E Line 610~611 "The UFS device shall detect more than or equal to 1us of positive or negative RST_n pulse". Both QCOM and Mediatek use 10~15us. What number do you think more appropriate?

Best Regards,
Ziqi

Quoted 7 lines

With yours, all the SoC vendors should wait for around 10us unconditionally even if there will be a possibility that some can use shorter period. I see this as a sort of optimization point.

Thanks.
Kiwoong Kim

Got your point. As it is a controversial delay among different SoC vendor, I'll move it back to vops and handle it by vendor's driver.

Best Regards,
Ziqi

Quoted 151 lines
Quoted 151 lines
Quoted 151 lines
Quoted 151 lines
drivers/scsi/ufs/ufshcd.c +5 -0
+	err = ufshcd_vops_toggle_device_reset(hba, false);
 
 	if (!err) {
 		ufshcd_set_ufs_dev_active(hba);
@@ -593,7 +606,11 @@ static void ufshcd_device_reset(struct ufs_hba
 *hba)
 			hba->wb_enabled = false;
 			hba->wb_buf_flush_enabled = false;
 		}
+		dev_info(hba->dev, "device reset done\n");
+	} else {
+		dev_err(hba->dev, "device reset pulling up failure: %d\n",
 err);
 	}
+
 	if (err != -EOPNOTSUPP)

ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err); } @@ -
8686,8 +8703,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +0 -2
 	if (ret)
 		goto set_dev_active;
 
-	ufshcd_vreg_set_lpm(hba);
-
 disable_clks:
 	/*
 	 * Call vendor specific suspend callback. As these callbacks may

access @@ -8703,6 +8718,9 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +3 -0
 	 */
 	ufshcd_disable_irq(hba);
 
+	if (ufshcd_is_link_off(hba))
+		ufshcd_vops_toggle_device_reset(hba, true);
+
 	ufshcd_setup_clocks(hba, false);
 
 	if (ufshcd_is_clkgating_allowed(hba)) { @@ -8711,6 +8729,8 @@

static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +8 -5
 					hba->clk_gating.state);
 	}
 
+	ufshcd_vreg_set_lpm(hba);
+
 	/* Put the host controller in low power mode if possible */
 	ufshcd_hba_vreg_set_lpm(hba);
 	goto out;
@@ -8778,18 +8798,19 @@ 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 @@ -8797,7 +8818,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +1 -1
 	 */
 	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)); @@ -8864,8 +8885,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)

drivers/scsi/ufs/ufshcd.c +2 -2
 	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)
@@ -8876,6 +8895,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 -0
 	if (ret)
drivers/scsi/ufs/ufshcd.h +1 -1
index 9bb5f0e..dccc3eb 100644
@@ -319,7 +319,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
- * @device_reset: called to issue a reset pulse on the UFS device
+ * @toggle_device_reset: called to change logic level of reset gpio

on
+ the UFS device
* @program_key: program or evict an inline encryption key
* @event_notify: called to notify important events */

drivers/scsi/ufs/ufshcd.h +5 -5
@@ -350,7 +350,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	(*toggle_device_reset)(struct ufs_hba *hba, bool down);
 	void	(*config_scaling_param)(struct ufs_hba *hba,
 					struct devfreq_dev_profile *profile,
 					void *data);
@@ -1216,10 +1216,10 @@ static inline void
 ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+static inline int ufshcd_vops_toggle_device_reset(struct ufs_hba
 *hba,
+bool down)
 {
-	if (hba->vops && hba->vops->device_reset)
-		return hba->vops->device_reset(hba);
+	if (hba->vops && hba->vops->toggle_device_reset)
+		return hba->vops->toggle_device_reset(hba, down);
 
 	return -EOPNOTSUPP;
 }
--

The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project