summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilad Broner <gbroner@codeaurora.org>2014-12-14 11:45:15 +0200
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:58:16 -0700
commitb030bfae539a04ba08c58b6e664bd370215d51c5 (patch)
tree069b7c75d32d7d57e0917f3d28b38edfa7a20755
parent57a5a68620eea1f5834643752ab3d7b39930808a (diff)
scsi: ufs-qcom: add number of lanes per direction
Different platform may have different number of lanes for the UFS link. Add parameter to device tree specifying how many lanes should be configured for the UFS link. Change-Id: Ida8b13b916f76b3cc7afd3da3d04219e95627678 Signed-off-by: Gilad Broner <gbroner@codeaurora.org> [subhashj@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt3
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c48
-rw-r--r--drivers/scsi/ufs/ufshcd.c20
-rw-r--r--include/linux/scsi/ufs/ufshcd.h3
4 files changed, 51 insertions, 23 deletions
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 54fa2a555a64..b43cb9883db6 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -47,6 +47,9 @@ Optional properties:
5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption)
- spm-level : UFS System power management level. Allowed PM levels are same as rpm-level.
- ufs-qcom-crypto : phandle to UFS-QCOM ICE (Inline Cryptographic Engine) node
+- lanes-per-direction: number of lanes available per direction - either 1 or 2.
+ Note that it is assume same number of lanes is used both directions at once.
+ If not specified, default is 2 lanes per direction.
Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on.
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 55ee0c4b9018..07955d70a76f 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -115,33 +115,34 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
if (host->is_lane_clks_enabled)
return 0;
- err = ufs_qcom_host_clk_enable(dev,
- "rx_lane0_sync_clk", host->rx_l0_sync_clk);
+ err = ufs_qcom_host_clk_enable(dev, "rx_lane0_sync_clk",
+ host->rx_l0_sync_clk);
if (err)
goto out;
- err = ufs_qcom_host_clk_enable(dev,
- "rx_lane1_sync_clk", host->rx_l1_sync_clk);
+ err = ufs_qcom_host_clk_enable(dev, "tx_lane0_sync_clk",
+ host->tx_l0_sync_clk);
if (err)
goto disable_rx_l0;
- err = ufs_qcom_host_clk_enable(dev,
- "tx_lane0_sync_clk", host->tx_l0_sync_clk);
- if (err)
- goto disable_rx_l1;
-
- err = ufs_qcom_host_clk_enable(dev,
- "tx_lane1_sync_clk", host->tx_l1_sync_clk);
- if (err)
- goto disable_tx_l0;
+ if (host->hba->lanes_per_direction > 1) {
+ err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+ host->rx_l1_sync_clk);
+ if (err)
+ goto disable_tx_l0;
+ err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+ host->tx_l1_sync_clk);
+ if (err)
+ goto disable_rx_l1;
+ }
host->is_lane_clks_enabled = true;
goto out;
-disable_tx_l0:
- clk_disable_unprepare(host->tx_l0_sync_clk);
disable_rx_l1:
clk_disable_unprepare(host->rx_l1_sync_clk);
+disable_tx_l0:
+ clk_disable_unprepare(host->tx_l0_sync_clk);
disable_rx_l0:
clk_disable_unprepare(host->rx_l0_sync_clk);
out:
@@ -159,17 +160,20 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
goto out;
err = ufs_qcom_host_clk_get(dev,
- "rx_lane1_sync_clk", &host->rx_l1_sync_clk);
- if (err)
- goto out;
-
- err = ufs_qcom_host_clk_get(dev,
"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
if (err)
goto out;
- err = ufs_qcom_host_clk_get(dev,
- "tx_lane1_sync_clk", &host->tx_l1_sync_clk);
+ /* 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);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
+ &host->tx_l1_sync_clk);
+ }
out:
return err;
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4fe8246a52fd..50ab12a7170e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -41,7 +41,7 @@
#include <scsi/ufs/ioctl.h>
#include <linux/devfreq.h>
#include <linux/nls.h>
-
+#include <linux/of.h>
#include <linux/scsi/ufs/ufshcd.h>
#include <linux/scsi/ufs/unipro.h>
#include "ufshci.h"
@@ -162,6 +162,8 @@
#define UFSHCD_PM_QOS_UNVOTE_TIMEOUT_US (10000) /* microseconds */
+#define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2
+
#define ufshcd_toggle_vreg(_dev, _vreg, _on) \
({ \
int _ret; \
@@ -8143,6 +8145,20 @@ static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba)
dev_err(hba->dev, "Failed to create sysfs for clkscale_enable\n");
}
+static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
+{
+ struct device *dev = hba->dev;
+ int ret;
+
+ ret = of_property_read_u32(dev->of_node, "lanes-per-direction",
+ &hba->lanes_per_direction);
+ if (ret) {
+ dev_dbg(hba->dev,
+ "%s: failed to read lanes-per-direction, ret=%d\n",
+ __func__, ret);
+ hba->lanes_per_direction = UFSHCD_DEFAULT_LANES_PER_DIRECTION;
+ }
+}
/**
* ufshcd_init - Driver initialization routine
* @hba: per-adapter instance
@@ -8166,6 +8182,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
hba->mmio_base = mmio_base;
hba->irq = irq;
+ ufshcd_init_lanes_per_dir(hba);
+
err = ufshcd_hba_init(hba);
if (err)
goto out_error;
diff --git a/include/linux/scsi/ufs/ufshcd.h b/include/linux/scsi/ufs/ufshcd.h
index c29027ea9ee7..b731b54abc9c 100644
--- a/include/linux/scsi/ufs/ufshcd.h
+++ b/include/linux/scsi/ufs/ufshcd.h
@@ -731,6 +731,9 @@ struct ufs_hba {
/* Number of requests aborts */
int req_abort_count;
+ /* Number of lanes available (1 or 2) for Rx/Tx */
+ u32 lanes_per_direction;
+
struct ufs_pa_layer_attr pwr_info;
struct ufs_pwr_mode_info max_pwr_info;