Skip to contentSkip to conversation

scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms

PATCH Superseded Can Guo 3 participants 5 messages Oct 12, 2018 – Oct 13, 2018

Subsystems (2)

v3 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Can Guo

author
#0 lore raw

PATCH v3 1/1 scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms

From: Venkat Gopalakrishnan <[email protected]>

Per Qcom's UFS host controller HW design, the UFS Tx lane1 clock could be muxed with Tx lane0 clock, hence keep Tx lane1 clock optional by ignoring it if it is not provided in device tree. This change also performs some cleanup to lanes per direction checks when enable/disable lane clocks just for symmetry.

---
Changes since v2:
- Incorporated review comments from Doug.

Changes since v1:
- Incorporated review comments from Doug.
- Update the commit title and commit message.

 drivers/scsi/ufs/ufs-qcom.c | 55 ++++++++++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 26 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +29 -26
index 2b38db2..dbc84cb 100644
@@ -79,20 +79,28 @@ static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
 }
 
 static int ufs_qcom_host_clk_get(struct device *dev,
-		const char *name, struct clk **clk_out)
+		const char *name, struct clk **clk_out, bool optional)
 {
 	struct clk *clk;
 	int err = 0;
 
 	clk = devm_clk_get(dev, name);
-	if (IS_ERR(clk)) {
-		err = PTR_ERR(clk);
-		dev_err(dev, "%s: failed to get %s err %d",
-				__func__, name, err);
-	} else {
+	if (!IS_ERR(clk)) {
 		*clk_out = clk;
+		return 0;
 	}
 
+	err = PTR_ERR(clk);
+
+	if (optional && err == -ENOENT) {
+		*clk_out = NULL;
+		return 0;
+	}
+
+	if (err != -EPROBE_DEFER)
+		dev_err(dev, "failed to get %s err %d",
+				name, err);
+
 	return err;
 }
 
@@ -113,11 +121,9 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
 	if (!host->is_lane_clks_enabled)
 		return;
 
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->tx_l1_sync_clk);
+	clk_disable_unprepare(host->tx_l1_sync_clk);
 	clk_disable_unprepare(host->tx_l0_sync_clk);
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
 	clk_disable_unprepare(host->rx_l0_sync_clk);
 
 	host->is_lane_clks_enabled = false;
@@ -141,24 +147,21 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
 	if (err)
 		goto disable_rx_l0;
 
-	if (host->hba->lanes_per_direction > 1) {
-		err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+	err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
 			host->rx_l1_sync_clk);
-		if (err)
-			goto disable_tx_l0;
+	if (err)
+		goto disable_tx_l0;
 
-		err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+	err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
 			host->tx_l1_sync_clk);
-		if (err)
-			goto disable_rx_l1;
-	}
+	if (err)
+		goto disable_rx_l1;
 
 	host->is_lane_clks_enabled = true;
 	goto out;
 
 disable_rx_l1:
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
 disable_tx_l0:
 	clk_disable_unprepare(host->tx_l0_sync_clk);
 disable_rx_l0:
@@ -172,25 +175,25 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
 	int err = 0;
 	struct device *dev = host->hba->dev;
 
-	err = ufs_qcom_host_clk_get(dev,
-			"rx_lane0_sync_clk", &host->rx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
+					&host->rx_l0_sync_clk, false);
 	if (err)
 		goto out;
 
-	err = ufs_qcom_host_clk_get(dev,
-			"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk",
+					&host->tx_l0_sync_clk, false);
 	if (err)
 		goto out;
 
 	/* In case of single lane per direction, don't read lane1 clocks */
 	if (host->hba->lanes_per_direction > 1) {
 		err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
-			&host->rx_l1_sync_clk);
+			&host->rx_l1_sync_clk, false);
 		if (err)
 			goto out;
 
 		err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
-			&host->tx_l1_sync_clk);
+			&host->tx_l1_sync_clk, true);
 	}
 out:
 	return err;
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
Reviewed-by on v3 1/1
#1 lore raw
Quoted 129 lines · Can Guo

From: Venkat Gopalakrishnan <[email protected]>

Per Qcom's UFS host controller HW design, the UFS Tx lane1 clock could be muxed with Tx lane0 clock, hence keep Tx lane1 clock optional by ignoring it if it is not provided in device tree. This change also performs some cleanup to lanes per direction checks when enable/disable lane clocks just for symmetry.

---
Changes since v2:
- Incorporated review comments from Doug.

Changes since v1:
- Incorporated review comments from Doug.
- Update the commit title and commit message.

  drivers/scsi/ufs/ufs-qcom.c | 55 ++++++++++++++++++++++++---------------------
  1 file changed, 29 insertions(+), 26 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +27 -25
index 2b38db2..dbc84cb 100644
@@ -79,20 +79,28 @@ static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
  }
 
  static int ufs_qcom_host_clk_get(struct device *dev,
-		const char *name, struct clk **clk_out)
+		const char *name, struct clk **clk_out, bool optional)
  {
  	struct clk *clk;
  	int err = 0;
 
  	clk = devm_clk_get(dev, name);
-	if (IS_ERR(clk)) {
-		err = PTR_ERR(clk);
-		dev_err(dev, "%s: failed to get %s err %d",
-				__func__, name, err);
-	} else {
+	if (!IS_ERR(clk)) {
  		*clk_out = clk;
+		return 0;
  	}
 
+	err = PTR_ERR(clk);
+
+	if (optional && err == -ENOENT) {
+		*clk_out = NULL;
+		return 0;
+	}
+
+	if (err != -EPROBE_DEFER)
+		dev_err(dev, "failed to get %s err %d",
+				name, err);
+
  	return err;
  }
 
@@ -113,11 +121,9 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
  	if (!host->is_lane_clks_enabled)
  		return;
 
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->tx_l1_sync_clk);
+	clk_disable_unprepare(host->tx_l1_sync_clk);
  	clk_disable_unprepare(host->tx_l0_sync_clk);
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
  	clk_disable_unprepare(host->rx_l0_sync_clk);
 
  	host->is_lane_clks_enabled = false;
@@ -141,24 +147,21 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
  	if (err)
  		goto disable_rx_l0;
 
-	if (host->hba->lanes_per_direction > 1) {
-		err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+	err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
  			host->rx_l1_sync_clk);
-		if (err)
-			goto disable_tx_l0;
+	if (err)
+		goto disable_tx_l0;
 
-		err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+	err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
  			host->tx_l1_sync_clk);
-		if (err)
-			goto disable_rx_l1;
-	}
+	if (err)
+		goto disable_rx_l1;
 
  	host->is_lane_clks_enabled = true;
  	goto out;
 
  disable_rx_l1:
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
  disable_tx_l0:
  	clk_disable_unprepare(host->tx_l0_sync_clk);
  disable_rx_l0:
@@ -172,25 +175,25 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
  	int err = 0;
  	struct device *dev = host->hba->dev;
 
-	err = ufs_qcom_host_clk_get(dev,
-			"rx_lane0_sync_clk", &host->rx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
+					&host->rx_l0_sync_clk, false);
  	if (err)
  		goto out;
 
-	err = ufs_qcom_host_clk_get(dev,
-			"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk",
+					&host->tx_l0_sync_clk, false);
  	if (err)
  		goto out;
 
  	/* In case of single lane per direction, don't read lane1 clocks */
  	if (host->hba->lanes_per_direction > 1) {
  		err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
-			&host->rx_l1_sync_clk);

drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) · line 199

Quoted 10 lines
drivers/scsi/ufs/ufs-qcom.c +2 -1
+			&host->rx_l1_sync_clk, false);
  		if (err)
  			goto out;
 
  		err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
-			&host->tx_l1_sync_clk);
+			&host->tx_l1_sync_clk, true);
  	}
  out:
  	return err;

Best regards
Vivek

#2 lore raw

Hi,

Quoted 135 lines · Vivek Gautam
Quoted 121 lines · Can Guo

From: Venkat Gopalakrishnan <[email protected]>

Per Qcom's UFS host controller HW design, the UFS Tx lane1 clock could be muxed with Tx lane0 clock, hence keep Tx lane1 clock optional by ignoring it if it is not provided in device tree. This change also performs some cleanup to lanes per direction checks when enable/disable lane clocks just for symmetry.

---
Changes since v2:
- Incorporated review comments from Doug.

Changes since v1:
- Incorporated review comments from Doug.
- Update the commit title and commit message.

  drivers/scsi/ufs/ufs-qcom.c | 55 
++++++++++++++++++++++++---------------------
  1 file changed, 29 insertions(+), 26 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +26 -19
index 2b38db2..dbc84cb 100644
@@ -79,20 +79,28 @@ static int ufs_qcom_get_connected_tx_lanes(struct 
 ufs_hba *hba, u32 *tx_lanes)
  }
    static int ufs_qcom_host_clk_get(struct device *dev,
-		const char *name, struct clk **clk_out)
+		const char *name, struct clk **clk_out, bool optional)
  {
  	struct clk *clk;
  	int err = 0;
    	clk = devm_clk_get(dev, name);
-	if (IS_ERR(clk)) {
-		err = PTR_ERR(clk);
-		dev_err(dev, "%s: failed to get %s err %d",
-				__func__, name, err);
-	} else {
+	if (!IS_ERR(clk)) {
  		*clk_out = clk;
+		return 0;
  	}
  +	err = PTR_ERR(clk);
+
+	if (optional && err == -ENOENT) {
+		*clk_out = NULL;
+		return 0;
+	}
+
+	if (err != -EPROBE_DEFER)
+		dev_err(dev, "failed to get %s err %d",
+				name, err);
+
  	return err;
  }
  @@ -113,11 +121,9 @@ static void ufs_qcom_disable_lane_clks(struct 
 ufs_qcom_host *host)
  	if (!host->is_lane_clks_enabled)
  		return;
  -	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->tx_l1_sync_clk);
+	clk_disable_unprepare(host->tx_l1_sync_clk);
  	clk_disable_unprepare(host->tx_l0_sync_clk);
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
  	clk_disable_unprepare(host->rx_l0_sync_clk);
    	host->is_lane_clks_enabled = false;
@@ -141,24 +147,21 @@ static int ufs_qcom_enable_lane_clks(struct 
 ufs_qcom_host *host)
  	if (err)
  		goto disable_rx_l0;
  -	if (host->hba->lanes_per_direction > 1) {
-		err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+	err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
  			host->rx_l1_sync_clk);
-		if (err)
-			goto disable_tx_l0;
+	if (err)
+		goto disable_tx_l0;
  -		err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+	err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
  			host->tx_l1_sync_clk);
-		if (err)
-			goto disable_rx_l1;
-	}
+	if (err)
+		goto disable_rx_l1;
    	host->is_lane_clks_enabled = true;
  	goto out;
    disable_rx_l1:
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
  disable_tx_l0:
  	clk_disable_unprepare(host->tx_l0_sync_clk);
  disable_rx_l0:
@@ -172,25 +175,25 @@ static int ufs_qcom_init_lane_clks(struct 
 ufs_qcom_host *host)
  	int err = 0;
  	struct device *dev = host->hba->dev;
  -	err = ufs_qcom_host_clk_get(dev,
-			"rx_lane0_sync_clk", &host->rx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
+					&host->rx_l0_sync_clk, false);
  	if (err)
  		goto out;
  -	err = ufs_qcom_host_clk_get(dev,
-			"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk",
+					&host->tx_l0_sync_clk, false);
  	if (err)
  		goto out;
    	/* In case of single lane per direction, don't read lane1 clocks 
 */
  	if (host->hba->lanes_per_direction > 1) {
  		err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",

drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_init_lane_clks(struct · line 199

Quoted 10 lines
drivers/scsi/ufs/ufs-qcom.c +2 -2
-			&host->rx_l1_sync_clk);
+			&host->rx_l1_sync_clk, false);
  		if (err)
  			goto out;
    		err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
-			&host->tx_l1_sync_clk);
+			&host->tx_l1_sync_clk, true);
  	}
  out:
  	return err;
Quoted 2 lines

Best regards
Vivek

Thank you Vivek.

-Can Guo

Reviewed-by Tested-by on v3 1/1
#3 lore raw
In reply to Can Guo

Hi,

drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) · line 102

Quoted 3 lines · Can Guo
drivers/scsi/ufs/ufs-qcom.c +3 -0
+       if (err != -EPROBE_DEFER)
+               dev_err(dev, "failed to get %s err %d",
+                               name, err);

I wouldn't spin just for this, but if you spin for some other reason you could move the above "dev_err" onto one line now. Sorry: I should have noticed that / done that on my patch...

Review static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)

Quoted 1 line
(quoted diff) +0 -0
@@ -141,24 +147,21 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)

Idea for a future patch: now that I look at what's left of this function you're basically re-implementing clk_bulk_prepare_enable() and clk_bulk_disable_unprepare() now. I bet your code would be cleaner / nicer by switching to that.

...possibly you might need to improve the clk_bulk_get() API to allow for some clock to be optional, but that would be a pretty easy patch to post up.

In any case I think it's better to do the clk_bulk switch in a future / separate patch, so:

-Doug

#4 lore raw
Quoted 12 lines · Doug Anderson

Hi,

drivers/scsi/ufs/ufs-qcom.c static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) · line 102

Quoted 3 lines · Can Guo
drivers/scsi/ufs/ufs-qcom.c +3 -0
+       if (err != -EPROBE_DEFER)
+               dev_err(dev, "failed to get %s err %d",
+                               name, err);

I wouldn't spin just for this, but if you spin for some other reason you could move the above "dev_err" onto one line now. Sorry: I should have noticed that / done that on my patch...

Yeah... I didn't notice it too. Shall push a new one to address it.

Quoted 12 lines

Review static int ufs_qcom_enable_lane_clks(struct · line 147

Quoted 2 lines
(quoted diff) +0 -0
@@ -141,24 +147,21 @@ static int ufs_qcom_enable_lane_clks(struct 
 ufs_qcom_host *host)

Idea for a future patch: now that I look at what's left of this function you're basically re-implementing clk_bulk_prepare_enable() and clk_bulk_disable_unprepare() now. I bet your code would be cleaner / nicer by switching to that.

...possibly you might need to improve the clk_bulk_get() API to allow for some clock to be optional, but that would be a pretty easy patch to post up.

Quoted 8 lines

In any case I think it's better to do the clk_bulk switch in a future / separate patch, so:

-Doug

That is a good idea, I shall follow up after this one is merged.

Thank you.
-Can Guo