Adapt to the new ICB framework for bus bandwidth voting.

This requires the source/destination port ids.
Also this requires a tuple of values.

The tuple is for two different paths - from UFS master
to BIMC slave. The other is from CPU master to UFS slave.
This tuple consists of the average and peak bandwidth.

Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      |  12 ++
 drivers/scsi/ufs/ufs-qcom.c                        | 234 ++++++++++++++++-----
 drivers/scsi/ufs/ufs-qcom.h                        |  20 ++
 3 files changed, 218 insertions(+), 48 deletions(-)

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index a99ed55..94249ef 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -45,6 +45,18 @@ Optional properties:
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
 
+* Following bus parameters are required:
+interconnects
+interconnect-names
+- Please refer to Documentation/devicetree/bindings/interconnect/
+  for more details on the above.
+qcom,msm-bus,name - string describing the bus path
+qcom,msm-bus,num-cases - number of configurations in which ufs can operate in
+qcom,msm-bus,num-paths - number of paths to vote for
+qcom,msm-bus,vectors-KBps - Takes a tuple <ib ab>, <ib ab> (2 tuples for 2 
num-paths)
+                           The number of these entries *must* be same as
+                           num-cases.
+
 Example:
        ufshc@0xfc598000 {
                compatible = "jedec,ufs-1.1";
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2b38db2..213e975 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
+#include <linux/interconnect.h>
 #include <linux/phy/phy-qcom-ufs.h>
 
 #include "ufshcd.h"
@@ -27,6 +28,10 @@
 #define UFS_QCOM_DEFAULT_DBG_PRINT_EN  \
        (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
+#define UFS_DDR "ufs-ddr"
+#define CPU_UFS "cpu-ufs"
+
+
 enum {
        TSTBUS_UAWM,
        TSTBUS_UARM,
@@ -714,7 +719,6 @@ static int ufs_qcom_get_pwr_dev_param(struct 
ufs_qcom_dev_params *qcom_param,
        return 0;
 }
 
-#ifdef CONFIG_MSM_BUS_SCALING
 static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
                const char *speed_mode)
 {
@@ -768,24 +772,83 @@ static void ufs_qcom_get_speed_mode(struct 
ufs_pa_layer_attr *p, char *result)
        }
 }
 
+static int ufs_qcom_get_ib_ab(struct ufs_qcom_host *host, int index,
+                             struct qcom_bus_vectors *ufs_ddr_vec,
+                             struct qcom_bus_vectors *cpu_ufs_vec)
+{
+       struct qcom_bus_path *usecase;
+
+       if (!host->qbsd)
+               return -EINVAL;
+
+       if (index > host->qbsd->num_usecase)
+               return -EINVAL;
+
+       usecase = host->qbsd->usecase;
+
+       /*
+        *
+        * usecase:0  usecase:0
+        * ufs->ddr   cpu->ufs
+        * |vec[0&1] | vec[2&3]|
+        * +----+----+----+----+
+        * | ab | ib | ab | ib |
+        * |----+----+----+----+
+        * .
+        * .
+        * .
+        * usecase:n  usecase:n
+        * ufs->ddr   cpu->ufs
+        * |vec[0&1] | vec[2&3]|
+        * +----+----+----+----+
+        * | ab | ib | ab | ib |
+        * |----+----+----+----+
+        */
+
+       /* index refers to offset in usecase */
+       ufs_ddr_vec->ab = usecase[index].vec[0].ab;
+       ufs_ddr_vec->ib = usecase[index].vec[0].ib;
+
+       cpu_ufs_vec->ab = usecase[index].vec[1].ab;
+       cpu_ufs_vec->ib = usecase[index].vec[1].ib;
+
+       return 0;
+}
+
 static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
 {
        int err = 0;
+       struct qcom_bus_scale_data *d = host->qbsd;
+       struct qcom_bus_vectors path0, path1;
+       struct device *dev = host->hba->dev;
 
-       if (vote != host->bus_vote.curr_vote) {
-               err = msm_bus_scale_client_update_request(
-                               host->bus_vote.client_handle, vote);
-               if (err) {
-                       dev_err(host->hba->dev,
-                               "%s: msm_bus_scale_client_update_request() 
failed: bus_client_handle=0x%x, vote=%d, err=%d\n",
-                               __func__, host->bus_vote.client_handle,
-                               vote, err);
-                       goto out;
-               }
+       err = ufs_qcom_get_ib_ab(host, vote, &path0, &path1);
+       if (err) {
+               dev_err(dev, "Error: failed (%d) to get ib/ab\n",
+                       err);
+               return err;
+       }
 
-               host->bus_vote.curr_vote = vote;
+       dev_dbg(dev, "Setting vote: %d: ufs-ddr: ab: %llu ib: %llu\n", vote,
+               path0.ab, path0.ib);
+       err = icc_set_bw(d->ufs_ddr, path0.ab, path0.ib);
+       if (err) {
+               dev_err(dev, "Error: (%d) failed setting (%s) bus vote\n", err,
+                       UFS_DDR);
+               return err;
        }
-out:
+
+       dev_dbg(dev, "Setting: cpu-ufs: ab: %llu ib: %llu\n", path1.ab,
+               path1.ib);
+       err = icc_set(d->cpu_ufs, path1.ab, path1.ib);
+       if (err) {
+               dev_err(dev, "Error: (%d) failed setting (%s) bus vote\n", err,
+                       CPU_UFS);
+               return err;
+       }
+
+       host->bus_vote.curr_vote = vote;
+
        return err;
 }
 
@@ -807,6 +870,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host 
*host)
                dev_err(host->hba->dev, "%s: failed %d\n", __func__, err);
        else
                host->bus_vote.saved_vote = vote;
+
        return err;
 }
 
@@ -837,34 +901,114 @@ static int ufs_qcom_update_bus_bw_vote(struct 
ufs_qcom_host *host)
        return count;
 }
 
+static struct qcom_bus_scale_data *ufs_qcom_get_bus_scale_data(struct device
+                                                              *dev)
+
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct device_node *of_node = dev->of_node;
+       struct qcom_bus_scale_data *qsd;
+       struct qcom_bus_path *usecase = NULL;
+       int ret = 0, i = 0, j, num_paths, len;
+       const uint32_t *vec_arr = NULL;
+       bool mem_err = false;
+
+       if (!pdev) {
+               dev_err(dev, "Null platform device!\n");
+               return NULL;
+       }
+
+       qsd = devm_kzalloc(dev, sizeof(struct qcom_bus_scale_data), GFP_KERNEL);
+       if (!qsd)
+               return NULL;
+
+       ret = of_property_read_string(of_node, "qcom,msm-bus,name", &qsd->name);
+       if (ret) {
+               dev_err(dev, "Error: (%d) Bus name missing!\n", ret);
+               return NULL;
+       }
+
+       ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
+               &qsd->num_usecase);
+       if (ret) {
+               pr_err("Error: num-usecases not found\n");
+               goto err;
+       }
+
+       usecase = devm_kzalloc(dev, (sizeof(struct qcom_bus_path) *
+                                  qsd->num_usecase), GFP_KERNEL);
+       if (!usecase)
+               return NULL;
+
+       ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
+                                  &num_paths);
+       if (ret) {
+               pr_err("Error: num_paths not found\n");
+               return NULL;
+       }
+
+       vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
+       if (vec_arr == NULL) {
+               pr_err("Error: Vector array not found\n");
+               return NULL;
+       }
+
+       for (i = 0; i < qsd->num_usecase; i++) {
+               usecase[i].num_paths = num_paths;
+               usecase[i].vec = devm_kzalloc(dev, num_paths *
+                                             sizeof(struct qcom_bus_vectors),
+                                             GFP_KERNEL);
+               if (!usecase[i].vec) {
+                       mem_err = true;
+                       dev_err(dev, "Error: Failed to alloc mem for 
vectors\n");
+                       goto err;
+               }
+
+               for (j = 0; j < num_paths; j++) {
+                       int idx = ((i * num_paths) + j) * 2;
+
+                       usecase[i].vec[j].ab = (uint64_t)
+                               be32_to_cpu(vec_arr[idx]);
+                       usecase[i].vec[j].ib = (uint64_t)
+                               be32_to_cpu(vec_arr[idx + 1]);
+               }
+       }
+
+       qsd->usecase = usecase;
+       return qsd;
+err:
+       if (mem_err) {
+               for (; i > 0; i--)
+                       kfree(usecase[i].vec);
+       }
+       return NULL;
+}
+
 static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
 {
        int err;
-       struct msm_bus_scale_pdata *bus_pdata;
        struct device *dev = host->hba->dev;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct device_node *np = dev->of_node;
+       struct qcom_bus_scale_data *qsd;
 
-       bus_pdata = msm_bus_cl_get_pdata(pdev);
-       if (!bus_pdata) {
-               dev_err(dev, "%s: failed to get bus vectors\n", __func__);
-               err = -ENODATA;
-               goto out;
+       qsd = ufs_qcom_get_bus_scale_data(dev);
+       if (!qsd) {
+               dev_err(dev, "Failed: getting bus_scale data\n");
+               return 0;
        }
+       host->qbsd = qsd;
 
-       err = of_property_count_strings(np, "qcom,bus-vector-names");
-       if (err < 0 || err != bus_pdata->num_usecases) {
-               dev_err(dev, "%s: qcom,bus-vector-names not specified correctly 
%d\n",
-                               __func__, err);
-               goto out;
+       qsd->ufs_ddr = of_icc_get(dev, UFS_DDR);
+       if (IS_ERR(qsd->ufs_ddr)) {
+               dev_err(dev, "Error: (%d) failed getting %s path\n",
+                       PTR_ERR(qsd->ufs_ddr), UFS_DDR);
+               return PTR_ERR(qsd->ufs_ddr);
        }
 
-       host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata);
-       if (!host->bus_vote.client_handle) {
-               dev_err(dev, "%s: msm_bus_scale_register_client failed\n",
-                               __func__);
-               err = -EFAULT;
-               goto out;
+       qsd->cpu_ufs = of_icc_get(dev, CPU_UFS);
+       if (IS_ERR(qsd->cpu_ufs)) {
+               dev_err(dev, "Error: (%d) failed getting %s path\n",
+                       PTR_ERR(qsd->cpu_ufs), CPU_UFS);
+               return PTR_ERR(qsd->cpu_ufs);
        }
 
        /* cache the vote index for minimum and maximum bandwidth */
@@ -877,25 +1021,19 @@ static int ufs_qcom_bus_register(struct ufs_qcom_host 
*host)
        host->bus_vote.max_bus_bw.attr.name = "max_bus_bw";
        host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
        err = device_create_file(dev, &host->bus_vote.max_bus_bw);
-out:
-       return err;
-}
-#else /* CONFIG_MSM_BUS_SCALING */
-static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
-{
-       return 0;
-}
+       if (err)
+               dev_err(dev, "Error: (%d) Failed to create sysfs entries\n",
+                       err);
 
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
-{
-       return 0;
-}
+       /* Full throttle */
+       err = ufs_qcom_set_bus_vote(host, host->bus_vote.max_bw_vote);
+       if (err)
+               dev_err(dev, "Error: (%d) Failed to set max bus vote\n", err);
 
-static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
-{
-       return 0;
+       dev_info(dev, "-- (%s) Registered bus voting! (%d) --\n", err);
+
+       return err;
 }
-#endif /* CONFIG_MSM_BUS_SCALING */
 
 static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
 {
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 295f4be..02140bd 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -207,6 +207,25 @@ struct ufs_qcom_testbus {
        u8 select_minor;
 };
 
+struct qcom_bus_vectors {
+       uint64_t ab;
+       uint64_t ib;
+};
+
+struct qcom_bus_path {
+       unsigned int num_paths;
+       struct qcom_bus_vectors *vec;
+};
+
+struct qcom_bus_scale_data {
+       struct qcom_bus_path *usecase;
+       unsigned int num_usecase;
+       struct icc_path *ufs_ddr;
+       struct icc_path *cpu_ufs;
+
+       const char *name;
+};
+
 struct ufs_qcom_host {
        /*
         * Set this capability if host controller supports the QUniPro mode
@@ -242,6 +261,7 @@ struct ufs_qcom_host {
        /* Bitmask for enabling debug prints */
        u32 dbg_print_en;
        struct ufs_qcom_testbus testbus;
+       struct qcom_bus_scale_data *qbsd;
 };
 
 static inline u32
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.

Reply via email to