scsi: ufs-qcom: add number of lanes per direction
authorYaniv Gardi <ygardi@codeaurora.org>
Thu, 10 Mar 2016 15:37:05 +0000 (17:37 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 15 Mar 2016 01:04:45 +0000 (21:04 -0400)
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.

Reviewed-by: Hannes Reinecke <hare@suse.de>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
drivers/scsi/ufs/ufs-qcom.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index 03c0e989e020a98ec28195896c8f8612686a580e..66f6adf8d44da55c87cb1fdd5ef501e40c3ea273 100644 (file)
@@ -38,6 +38,9 @@ Optional properties:
                          defined or a value in the array is "0" then it is assumed
                          that the frequency is set by the parent clock or a
                          fixed rate clock source.
+-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.
index 4f38d008bfb401d9eeeb359472e643bdf3e85c9b..ed5772902f4b00da6b46c2d709ccf8b87f410eb7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -132,21 +132,24 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
        if (err)
                goto disable_rx_l0;
 
-       err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
-               host->rx_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;
+               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_rx_l1:
-       clk_disable_unprepare(host->rx_l1_sync_clk);
+       if (host->hba->lanes_per_direction > 1)
+               clk_disable_unprepare(host->rx_l1_sync_clk);
 disable_tx_l0:
        clk_disable_unprepare(host->tx_l0_sync_clk);
 disable_rx_l0:
@@ -170,14 +173,16 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
        if (err)
                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_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;
 }
index d2a7b127b05c19e259c5dca4a4771bdfdb97b5f5..718f12e0988535fa14b517c1288626fa5d5da99f 100644 (file)
@@ -40,6 +40,8 @@
 #include "ufshcd.h"
 #include "ufshcd-pltfrm.h"
 
+#define UFSHCD_DEFAULT_LANES_PER_DIRECTION             2
+
 static int ufshcd_parse_clock_info(struct ufs_hba *hba)
 {
        int ret = 0;
@@ -277,6 +279,21 @@ void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown);
 
+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_pltfrm_init - probe routine of the driver
  * @pdev: pointer to Platform device handle
@@ -331,6 +348,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
+       ufshcd_init_lanes_per_dir(hba);
+
        err = ufshcd_init(hba, mmio_base, irq);
        if (err) {
                dev_err(dev, "Initialization failed\n");
index 9c1b94bef8f344ce722406d179c8b0f172001bd6..a8e42dfc32ecd9d493522f4e7d8fe8ce1ccae671 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/async.h>
 #include <linux/devfreq.h>
 
+#include <linux/of.h>
 #include "ufshcd.h"
 #include "unipro.h"
 
index e3931d0c94eb9e63c3c5fbe5158e631e7133ac3c..9ae7f85b2a3346de0a69990cb0bd58df0556a09e 100644 (file)
@@ -509,6 +509,8 @@ struct ufs_hba {
 
        bool wlun_dev_clr_ua;
 
+       /* 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;