Jelajahi Sumber

msm: camera: common: Add support for icc and switching bus scaling

Add support for disabling bus scaling by moving bus driver
references from cpas to cam utils. The references can be
switched based on compile time flags in defconfig. Also, add
interconnect support which has bw voting based on source and
destination bus IDs.

CRs-Fixed: 2525881
Change-Id: I2a78523c0cad41503fe32aeb7bf4c794a26b16b6
Signed-off-by: Mukund Madhusudan Atre <[email protected]>
Signed-off-by: Jigarkumar Zala <[email protected]>
Jigarkumar Zala 5 tahun lalu
induk
melakukan
8a40a542fd

+ 8 - 0
drivers/Makefile

@@ -49,6 +49,14 @@ ifdef CONFIG_QCOM_CX_IPEAK
 camera-y += cam_utils/cam_cx_ipeak.o
 endif
 
+ifneq (,$(filter $(CONFIG_QCOM_BUS_SCALING),y m))
+camera-y += cam_utils/cam_soc_bus.o
+endif
+
+ifneq (,$(filter $(CONFIG_INTERCONNECT_QCOM),y m))
+camera-y += cam_utils/cam_soc_icc.o
+endif
+
 camera-$(CONFIG_SPECTRA_ISP) += \
 	cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.o \
 	cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.o \

+ 55 - 120
drivers/cam_cpas/cam_cpas_hw.c

@@ -6,7 +6,6 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
-#include <linux/msm-bus.h>
 #include <linux/pm_opp.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -56,73 +55,54 @@ int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw,
 static int cam_cpas_util_vote_bus_client_level(
 	struct cam_cpas_bus_client *bus_client, unsigned int level)
 {
-	if (!bus_client->valid || (bus_client->dyn_vote == true)) {
-		CAM_ERR(CAM_CPAS, "Invalid params %d %d", bus_client->valid,
-			bus_client->dyn_vote);
-		return -EINVAL;
-	}
+	int rc = 0;
 
-	if (level >= bus_client->num_usecases) {
-		CAM_ERR(CAM_CPAS, "Invalid vote level=%d, usecases=%d", level,
-			bus_client->num_usecases);
-		return -EINVAL;
+	if (!bus_client->valid) {
+		CAM_ERR(CAM_CPAS, "bus client not valid");
+		rc = -EINVAL;
+		goto end;
 	}
 
 	if (level == bus_client->curr_vote_level)
-		return 0;
+		goto end;
 
-	CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] index[%d]",
-		bus_client->client_id, bus_client->name, level);
-	msm_bus_scale_client_update_request(bus_client->client_id, level);
+	rc = cam_soc_bus_client_update_request(bus_client->soc_bus_client,
+		level);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Client: %s update request failed rc: %d",
+			bus_client->common_data.name, rc);
+		goto end;
+	}
 	bus_client->curr_vote_level = level;
 
-	return 0;
+end:
+	return rc;
 }
 
 static int cam_cpas_util_vote_bus_client_bw(
 	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib,
 	bool camnoc_bw)
 {
-	struct msm_bus_paths *path;
-	struct msm_bus_scale_pdata *pdata;
-	int idx = 0;
+	int rc = 0;
 	uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
 
-	if (cam_min_camnoc_ib_bw > 0)
-		min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L;
-
-	CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu",
-		cam_min_camnoc_ib_bw, min_camnoc_ib_bw);
-
 	if (!bus_client->valid) {
-		CAM_ERR(CAM_CPAS, "bus client not valid");
-		return -EINVAL;
-	}
-
-	if ((bus_client->num_usecases != 2) ||
-		(bus_client->num_paths != 1) ||
-		(bus_client->dyn_vote != true)) {
-		CAM_ERR(CAM_CPAS, "dynamic update not allowed %d %d %d",
-			bus_client->num_usecases, bus_client->num_paths,
-			bus_client->dyn_vote);
-		return -EINVAL;
+		CAM_ERR(CAM_CPAS, "bus client: %s not valid",
+			bus_client->common_data.name);
+		rc = -EINVAL;
+		goto end;
 	}
 
-	mutex_lock(&bus_client->lock);
-
-	if (bus_client->curr_vote_level > 1) {
-		CAM_ERR(CAM_CPAS, "curr_vote_level %d cannot be greater than 1",
-			bus_client->curr_vote_level);
-		mutex_unlock(&bus_client->lock);
-		return -EINVAL;
-	}
+	if (cam_min_camnoc_ib_bw > 0)
+		min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L;
 
-	idx = bus_client->curr_vote_level;
-	idx = 1 - idx;
-	bus_client->curr_vote_level = idx;
-	mutex_unlock(&bus_client->lock);
+	CAM_DBG(CAM_CPAS,
+		"Bus_client: %s, cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu",
+		bus_client->common_data.name, cam_min_camnoc_ib_bw,
+		min_camnoc_ib_bw);
 
-	if (camnoc_bw == true) {
+	mutex_lock(&bus_client->lock);
+	if (camnoc_bw) {
 		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW))
 			ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW;
 
@@ -136,96 +116,51 @@ static int cam_cpas_util_vote_bus_client_bw(
 			ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
 	}
 
-	pdata = bus_client->pdata;
-	path = &(pdata->usecase[idx]);
-	path->vectors[0].ab = ab;
-	path->vectors[0].ib = ib;
-
-	CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]",
-		bus_client->client_id, bus_client->name, ab, ib, idx);
-	msm_bus_scale_client_update_request(bus_client->client_id, idx);
+	rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib);
+	if (rc) {
+		CAM_ERR(CAM_CPAS,
+			"Update bw failed, ab[%llu] ib[%llu]",
+			ab, ib);
+		goto unlock_client;
+	}
 
-	return 0;
+unlock_client:
+	mutex_unlock(&bus_client->lock);
+end:
+	return rc;
 }
 
 static int cam_cpas_util_register_bus_client(
 	struct cam_hw_soc_info *soc_info, struct device_node *dev_node,
 	struct cam_cpas_bus_client *bus_client)
 {
-	struct msm_bus_scale_pdata *pdata = NULL;
-	uint32_t client_id;
-	int rc;
-
-	pdata = msm_bus_pdata_from_node(soc_info->pdev,
-		dev_node);
-	if (!pdata) {
-		CAM_ERR(CAM_CPAS, "failed get_pdata");
-		return -EINVAL;
-	}
-
-	if ((pdata->num_usecases == 0) ||
-		(pdata->usecase[0].num_paths == 0)) {
-		CAM_ERR(CAM_CPAS, "usecase=%d", pdata->num_usecases);
-		rc = -EINVAL;
-		goto error;
-	}
-
-	client_id = msm_bus_scale_register_client(pdata);
-	if (!client_id) {
-		CAM_ERR(CAM_CPAS, "failed in register ahb bus client");
-		rc = -EINVAL;
-		goto error;
-	}
-
-	bus_client->dyn_vote = of_property_read_bool(dev_node,
-		"qcom,msm-bus-vector-dyn-vote");
+	int rc = 0;
 
-	if (bus_client->dyn_vote && (pdata->num_usecases != 2)) {
-		CAM_ERR(CAM_CPAS, "Excess or less vectors %d",
-			pdata->num_usecases);
-		rc = -EINVAL;
-		goto fail_unregister_client;
+	rc = cam_soc_bus_client_register(soc_info->pdev, dev_node,
+		&bus_client->soc_bus_client, &bus_client->common_data);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Bus client: %s registertion failed ,rc: %d",
+			bus_client->common_data.name, rc);
+		return rc;
 	}
-
-	msm_bus_scale_client_update_request(client_id, 0);
-
-	bus_client->src = pdata->usecase[0].vectors[0].src;
-	bus_client->dst = pdata->usecase[0].vectors[0].dst;
-	bus_client->pdata = pdata;
-	bus_client->client_id = client_id;
-	bus_client->num_usecases = pdata->num_usecases;
-	bus_client->num_paths = pdata->usecase[0].num_paths;
 	bus_client->curr_vote_level = 0;
 	bus_client->valid = true;
-	bus_client->name = pdata->name;
 	mutex_init(&bus_client->lock);
 
-	CAM_DBG(CAM_CPAS, "Bus Client=[%d][%s] : src=%d, dst=%d",
-		bus_client->client_id, bus_client->name,
-		bus_client->src, bus_client->dst);
-
 	return 0;
-fail_unregister_client:
-	msm_bus_scale_unregister_client(bus_client->client_id);
-error:
-	return rc;
-
 }
 
 static int cam_cpas_util_unregister_bus_client(
 	struct cam_cpas_bus_client *bus_client)
 {
-	if (!bus_client->valid)
+	if (!bus_client->valid) {
+		CAM_ERR(CAM_CPAS, "bus client not valid");
 		return -EINVAL;
+	}
 
-	if (bus_client->dyn_vote)
-		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false);
-	else
-		cam_cpas_util_vote_bus_client_level(bus_client, 0);
-
-	msm_bus_scale_unregister_client(bus_client->client_id);
+	cam_soc_bus_client_unregister(&bus_client->soc_bus_client);
+	bus_client->curr_vote_level = 0;
 	bus_client->valid = false;
-
 	mutex_destroy(&bus_client->lock);
 
 	return 0;
@@ -765,7 +700,7 @@ vote_start_clients:
 			continue;
 
 		CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld",
-			axi_port->axi_port_name, axi_port->ab_bw,
+			axi_port->bus_client.common_data.name, axi_port->ab_bw,
 			axi_port->ib_bw, axi_port->additional_bw);
 
 		if (axi_port->ab_bw)
@@ -920,9 +855,9 @@ static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw,
 	mutex_lock(&ahb_bus_client->lock);
 	cpas_client->ahb_level = required_level;
 
-	CAM_DBG(CAM_CPAS, "Client=[%d][%s] required level[%d], curr_level[%d]",
-		ahb_bus_client->client_id, ahb_bus_client->name,
-		required_level, ahb_bus_client->curr_vote_level);
+	CAM_DBG(CAM_CPAS, "Client[%s] required level[%d], curr_level[%d]",
+		ahb_bus_client->common_data.name, required_level,
+		ahb_bus_client->curr_vote_level);
 
 	if (required_level == ahb_bus_client->curr_vote_level)
 		goto unlock_bus_client;

+ 9 - 22
drivers/cam_cpas/cam_cpas_hw.h

@@ -10,6 +10,7 @@
 #include "cam_cpas_api.h"
 #include "cam_cpas_hw_intf.h"
 #include "cam_common_util.h"
+#include "cam_soc_bus.h"
 
 #define CAM_CPAS_INFLIGHT_WORKS              5
 #define CAM_CPAS_MAX_CLIENTS                 40
@@ -117,37 +118,24 @@ struct cam_cpas_client {
 /**
  * struct cam_cpas_bus_client : Bus client information
  *
- * @src: Bus master/src id
- * @dst: Bus slave/dst id
- * @pdata: Bus pdata information
- * @client_id: Bus client id
- * @num_usecases: Number of use cases for this client
- * @num_paths: Number of paths for this client
- * @curr_vote_level: current voted index
- * @dyn_vote: Whether dynamic voting enabled
- * @lock: Mutex lock used while voting on this client
  * @valid: Whether bus client is valid
  * @name: Name of the bus client
- *
+ * @lock: Mutex lock used while voting on this client
+ * @curr_vote_level: current voted index
+ * @common_data: Common data fields for bus client
+ * @soc_bus_client: Bus client private information
  */
 struct cam_cpas_bus_client {
-	int src;
-	int dst;
-	struct msm_bus_scale_pdata *pdata;
-	uint32_t client_id;
-	int num_usecases;
-	int num_paths;
-	unsigned int curr_vote_level;
-	bool dyn_vote;
-	struct mutex lock;
 	bool valid;
-	const char *name;
+	struct mutex lock;
+	unsigned int curr_vote_level;
+	struct cam_soc_bus_client_common_data common_data;
+	void *soc_bus_client;
 };
 
 /**
  * struct cam_cpas_axi_port : AXI port information
  *
- * @axi_port_name: Name of this AXI port
  * @bus_client: bus client info for this port
  * @ib_bw_voting_needed: if this port can update ib bw dynamically
  * @axi_port_node: Node representing AXI Port info in device tree
@@ -156,7 +144,6 @@ struct cam_cpas_bus_client {
  * @additional_bw: Additional bandwidth to cover non-hw cpas clients
  */
 struct cam_cpas_axi_port {
-	const char *axi_port_name;
 	struct cam_cpas_bus_client bus_client;
 	bool ib_bw_voting_needed;
 	struct device_node *axi_port_node;

+ 186 - 12
drivers/cam_cpas/cam_cpas_soc.c

@@ -163,7 +163,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 		rc = of_property_read_u32(level_node, "level-index",
 			&level_idx);
 		if (rc) {
-			CAM_ERR(CAM_CPAS, "Error raeding level idx rc: %d", rc);
+			CAM_ERR(CAM_CPAS, "Error reading level idx rc: %d", rc);
 			return rc;
 		}
 		if (level_idx >= CAM_CPAS_MAX_TREE_LEVELS) {
@@ -229,19 +229,82 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 
 				cpas_core->axi_port[mnoc_idx].axi_port_node
 					= mnoc_node;
-				rc =  of_property_read_string(
-					curr_node, "qcom,axi-port-name",
-					&cpas_core->axi_port[mnoc_idx]
-					.axi_port_name);
-				if (rc) {
-					CAM_ERR(CAM_CPAS,
-					"failed to read mnoc-port-name rc=%d",
-						rc);
-					return rc;
+				if (soc_private->bus_icc_based) {
+					struct of_phandle_args src_args = {0},
+						dst_args = {0};
+
+					rc = of_property_read_string(mnoc_node,
+						"interconnect-names",
+						&cpas_core->axi_port[mnoc_idx]
+						.bus_client.common_data.name);
+					if (rc) {
+						CAM_ERR(CAM_CPAS,
+							"failed to read interconnect-names rc=%d",
+							rc);
+						return rc;
+					}
+
+					rc = of_parse_phandle_with_args(
+						mnoc_node, "interconnects",
+						"#interconnect-cells", 0,
+						&src_args);
+					if (rc) {
+						CAM_ERR(CAM_CPAS,
+							"failed to read axi bus src info rc=%d",
+							rc);
+						return -EINVAL;
+					}
+
+					of_node_put(src_args.np);
+					if (src_args.args_count != 1) {
+						CAM_ERR(CAM_CPAS,
+							"Invalid number of axi src args: %d",
+							src_args.args_count);
+						return -EINVAL;
+					}
+
+					cpas_core->axi_port[mnoc_idx].bus_client
+					.common_data.src_id = src_args.args[0];
+
+					rc = of_parse_phandle_with_args(
+						mnoc_node, "interconnects",
+						"#interconnect-cells", 1,
+						&dst_args);
+					if (rc) {
+						CAM_ERR(CAM_CPAS,
+							"failed to read axi bus dst info rc=%d",
+							rc);
+						return -EINVAL;
+					}
+
+					of_node_put(dst_args.np);
+					if (dst_args.args_count != 1) {
+						CAM_ERR(CAM_CPAS,
+							"Invalid number of axi dst args: %d",
+							dst_args.args_count);
+						return -EINVAL;
+					}
+
+					cpas_core->axi_port[mnoc_idx].bus_client
+					.common_data.dst_id = dst_args.args[0];
+					cpas_core->axi_port[mnoc_idx].bus_client
+						.common_data.num_usecases = 2;
+				} else {
+					rc =  of_property_read_string(
+						curr_node, "qcom,axi-port-name",
+						&cpas_core->axi_port[mnoc_idx]
+						.bus_client.common_data.name);
+					if (rc) {
+						CAM_ERR(CAM_CPAS,
+							"failed to read mnoc-port-name rc=%d",
+							rc);
+						return rc;
+					}
 				}
+
 				cpas_core->axi_port
 					[mnoc_idx].ib_bw_voting_needed
-				= of_property_read_bool(curr_node,
+					= of_property_read_bool(curr_node,
 					"ib-bw-voting-needed");
 				curr_node_ptr->axi_port_idx = mnoc_idx;
 				mnoc_idx++;
@@ -392,7 +455,8 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 	struct platform_device *pdev, struct cam_cpas_private_soc *soc_private)
 {
 	struct device_node *of_node;
-	int count = 0, i = 0, rc = 0;
+	struct of_phandle_args src_args = {0}, dst_args = {0};
+	int count = 0, i = 0, rc = 0, num_bw_values = 0, num_levels = 0;
 	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 
 	if (!soc_private || !pdev) {
@@ -437,6 +501,116 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 
 	soc_private->client_id_based = of_property_read_bool(of_node,
 		"client-id-based");
+	soc_private->bus_icc_based = of_property_read_bool(of_node,
+		"interconnects");
+
+	if (soc_private->bus_icc_based) {
+		rc = of_property_read_string(of_node, "interconnect-names",
+			&cpas_core->ahb_bus_client.common_data.name);
+		if (rc) {
+			CAM_ERR(CAM_CPAS,
+				"device %s failed to read interconnect-names",
+				pdev->name);
+			return rc;
+		}
+
+		rc = of_parse_phandle_with_args(of_node, "interconnects",
+			"#interconnect-cells", 0, &src_args);
+		if (rc) {
+			CAM_ERR(CAM_CPAS,
+				"device %s failed to read ahb bus src info",
+				pdev->name);
+			return rc;
+		}
+
+		of_node_put(src_args.np);
+		if (src_args.args_count != 1) {
+			CAM_ERR(CAM_CPAS,
+				"Invalid number of ahb src args: %d",
+				src_args.args_count);
+			return -EINVAL;
+		}
+
+		cpas_core->ahb_bus_client.common_data.src_id = src_args.args[0];
+
+		rc = of_parse_phandle_with_args(of_node, "interconnects",
+			"#interconnect-cells", 1, &dst_args);
+		if (rc) {
+			CAM_ERR(CAM_CPAS,
+				"device %s failed to read ahb bus dst info",
+				pdev->name);
+			return rc;
+		}
+
+		of_node_put(dst_args.np);
+		if (dst_args.args_count != 1) {
+			CAM_ERR(CAM_CPAS,
+				"Invalid number of ahb dst args: %d",
+				dst_args.args_count);
+			return -EINVAL;
+		}
+
+		cpas_core->ahb_bus_client.common_data.dst_id = dst_args.args[0];
+
+		rc = of_property_read_u32(of_node, "cam-ahb-num-cases",
+			&cpas_core->ahb_bus_client.common_data.num_usecases);
+		if (rc) {
+			CAM_ERR(CAM_CPAS,
+				"device %s failed to read ahb num usecases",
+				pdev->name);
+			return rc;
+		}
+
+		if (cpas_core->ahb_bus_client.common_data.num_usecases >
+			CAM_SOC_BUS_MAX_NUM_USECASES) {
+			CAM_ERR(CAM_UTIL, "Invalid number of usecases: %d",
+				cpas_core->ahb_bus_client.common_data
+				.num_usecases);
+			return -EINVAL;
+		}
+
+		num_bw_values = of_property_count_u64_elems(of_node,
+			"cam-ahb-bw-KBps");
+		if (num_bw_values <= 0) {
+			CAM_ERR(CAM_UTIL, "Error counting ahb bw values");
+			return -EINVAL;
+		}
+
+		num_levels = (num_bw_values / 2);
+
+		if (num_levels !=
+			cpas_core->ahb_bus_client.common_data.num_usecases) {
+			CAM_ERR(CAM_UTIL, "Invalid number of levels: %d",
+				num_bw_values/2);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < num_levels; i++) {
+			rc = of_property_read_u64_index(of_node,
+				"cam-ahb-bw-KBps",
+				(i * 2),
+				&cpas_core->ahb_bus_client.common_data
+				.bw_pair[i].ab);
+			if (rc) {
+				CAM_ERR(CAM_UTIL,
+					"Error reading ab bw value, rc=%d",
+					rc);
+				return rc;
+			}
+
+			rc = of_property_read_u64_index(of_node,
+				"cam-ahb-bw-KBps",
+				((i * 2) + 1),
+				&cpas_core->ahb_bus_client.common_data
+				.bw_pair[i].ib);
+			if (rc) {
+				CAM_ERR(CAM_UTIL,
+					"Error reading ib bw value, rc=%d",
+					rc);
+				return rc;
+			}
+		}
+	}
 
 	count = of_property_count_strings(of_node, "client-names");
 	if (count <= 0) {

+ 2 - 0
drivers/cam_cpas/cam_cpas_soc.h

@@ -74,6 +74,7 @@ struct cam_cpas_tree_node {
  *
  * @arch_compat: ARCH compatible string
  * @client_id_based: Whether clients are id based
+ * @bus_icc_based: Interconnect based bus interaction
  * @num_clients: Number of clients supported
  * @client_name: Client names
  * @tree_node: Array of pointers to all tree nodes required to calculate
@@ -93,6 +94,7 @@ struct cam_cpas_tree_node {
 struct cam_cpas_private_soc {
 	const char *arch_compat;
 	bool client_id_based;
+	bool bus_icc_based;
 	uint32_t num_clients;
 	const char *client_name[CAM_CPAS_MAX_CLIENTS];
 	struct cam_cpas_tree_node *tree_node[CAM_CPAS_MAX_TREE_NODES];

+ 232 - 0
drivers/cam_utils/cam_soc_bus.c

@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/msm-bus.h>
+#include "cam_soc_bus.h"
+
+/**
+ * struct cam_soc_bus_client_data : Bus client data
+ *
+ * @pdata: Bus pdata information
+ * @client_id: Bus client id
+ * @num_paths: Number of paths for this client
+ * @curr_vote_level: current voted index
+ * @dyn_vote: whether dynamic voting enabled
+ */
+struct cam_soc_bus_client_data {
+	struct msm_bus_scale_pdata *pdata;
+	uint32_t client_id;
+	int num_paths;
+	unsigned int curr_vote_level;
+	bool dyn_vote;
+};
+
+int cam_soc_bus_client_update_request(void *client, unsigned int idx)
+{
+	int rc = 0;
+	struct cam_soc_bus_client *bus_client =
+		(struct cam_soc_bus_client *) client;
+	struct cam_soc_bus_client_data *bus_client_data =
+		(struct cam_soc_bus_client_data *) bus_client->client_data;
+
+	if (bus_client_data->dyn_vote) {
+		CAM_ERR(CAM_UTIL,
+			"Dyn update not allowed client[%d][%s], dyn_vote: %d",
+			bus_client_data->client_id,
+			bus_client->common_data->name,
+			bus_client_data->dyn_vote);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (idx >= bus_client->common_data->num_usecases) {
+		CAM_ERR(CAM_UTIL, "Invalid vote level=%d, usecases=%d", idx,
+			bus_client->common_data->num_usecases);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_UTIL, "Bus client=[%d][%s] index[%d]",
+		bus_client_data->client_id, bus_client->common_data->name, idx);
+
+	rc = msm_bus_scale_client_update_request(bus_client_data->client_id,
+		idx);
+	if (rc) {
+		CAM_ERR(CAM_UTIL,
+			"Update request failed, client[%d][%s], idx: %d",
+			bus_client_data->client_id,
+			bus_client->common_data->name, idx);
+		goto end;
+	}
+
+end:
+	return rc;
+}
+
+int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
+{
+	int idx = 0;
+	struct msm_bus_paths *path;
+	struct msm_bus_scale_pdata *pdata;
+	struct cam_soc_bus_client *bus_client =
+		(struct cam_soc_bus_client *) client;
+	struct cam_soc_bus_client_data *bus_client_data =
+		(struct cam_soc_bus_client_data *) bus_client->client_data;
+	int rc = 0;
+
+	if ((bus_client->common_data->num_usecases != 2) ||
+		(bus_client_data->num_paths != 1) ||
+		(!bus_client_data->dyn_vote)) {
+		CAM_ERR(CAM_UTIL,
+			"dynamic update not allowed Bus client=[%d][%s], %d %d %d",
+			bus_client_data->client_id,
+			bus_client->common_data->name,
+			bus_client->common_data->num_usecases,
+			bus_client_data->num_paths,
+			bus_client_data->dyn_vote);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	idx = bus_client_data->curr_vote_level;
+	idx = 1 - idx;
+	bus_client_data->curr_vote_level = idx;
+
+	pdata = bus_client_data->pdata;
+	path = &(pdata->usecase[idx]);
+	path->vectors[0].ab = ab;
+	path->vectors[0].ib = ib;
+
+	CAM_DBG(CAM_UTIL, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]",
+		bus_client_data->client_id, bus_client->common_data->name, ab,
+		ib, idx);
+	rc = msm_bus_scale_client_update_request(bus_client_data->client_id,
+		idx);
+	if (rc) {
+		CAM_ERR(CAM_UTIL,
+			"Update request failed, client[%d][%s], idx: %d",
+			bus_client_data->client_id,
+			bus_client->common_data->name, idx);
+		return rc;
+	}
+
+end:
+	return rc;
+}
+
+int cam_soc_bus_client_register(struct platform_device *pdev,
+	struct device_node *dev_node, void **client,
+	struct cam_soc_bus_client_common_data *common_data)
+{
+	struct msm_bus_scale_pdata *pdata = NULL;
+	struct cam_soc_bus_client *bus_client = NULL;
+	struct cam_soc_bus_client_data *bus_client_data = NULL;
+	uint32_t client_id;
+	int rc;
+
+	bus_client = kzalloc(sizeof(struct cam_soc_bus_client), GFP_KERNEL);
+	if (!bus_client) {
+		CAM_ERR(CAM_UTIL, "Non Enought Memroy");
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	*client = bus_client;
+
+	bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data),
+		GFP_KERNEL);
+	if (!bus_client_data) {
+		kfree(bus_client);
+		*client = NULL;
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	bus_client->client_data = bus_client_data;
+	pdata = msm_bus_pdata_from_node(pdev,
+		dev_node);
+	if (!pdata) {
+		CAM_ERR(CAM_UTIL, "failed get_pdata");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if ((pdata->num_usecases == 0) ||
+		(pdata->usecase[0].num_paths == 0)) {
+		CAM_ERR(CAM_UTIL, "usecase=%d", pdata->num_usecases);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	client_id = msm_bus_scale_register_client(pdata);
+	if (!client_id) {
+		CAM_ERR(CAM_UTIL, "failed in register bus client_data");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	bus_client->common_data = common_data;
+
+	bus_client_data->dyn_vote = of_property_read_bool(dev_node,
+		"qcom,msm-bus-vector-dyn-vote");
+
+	if (bus_client_data->dyn_vote && (pdata->num_usecases != 2)) {
+		CAM_ERR(CAM_UTIL, "Excess or less vectors %d",
+			pdata->num_usecases);
+		rc = -EINVAL;
+		goto fail_unregister_client;
+	}
+
+	rc = msm_bus_scale_client_update_request(client_id, 0);
+	if (rc) {
+		CAM_ERR(CAM_UTIL, "Bus client update request failed, rc = %d",
+			rc);
+		goto fail_unregister_client;
+	}
+
+	bus_client->common_data->src_id = pdata->usecase[0].vectors[0].src;
+	bus_client->common_data->dst_id = pdata->usecase[0].vectors[0].dst;
+	bus_client_data->pdata = pdata;
+	bus_client_data->client_id = client_id;
+	bus_client->common_data->num_usecases = pdata->num_usecases;
+	bus_client_data->num_paths = pdata->usecase[0].num_paths;
+	bus_client->common_data->name = pdata->name;
+
+	CAM_DBG(CAM_UTIL, "Bus Client=[%d][%s] : src=%d, dst=%d",
+		bus_client_data->client_id, bus_client->common_data->name,
+		bus_client->common_data->src_id,
+		bus_client->common_data->dst_id);
+
+	return 0;
+fail_unregister_client:
+	msm_bus_scale_unregister_client(bus_client_data->client_id);
+error:
+	kfree(bus_client_data);
+	bus_client->client_data = NULL;
+	kfree(bus_client);
+	*client = NULL;
+end:
+	return rc;
+
+}
+
+void cam_soc_bus_client_unregister(void **client)
+{
+	struct cam_soc_bus_client *bus_client =
+		(struct cam_soc_bus_client *) (*client);
+	struct cam_soc_bus_client_data *bus_client_data =
+		(struct cam_soc_bus_client_data *) bus_client->client_data;
+
+	if (bus_client_data->dyn_vote)
+		cam_soc_bus_client_update_bw(bus_client, 0, 0);
+	else
+		cam_soc_bus_client_update_request(bus_client, 0);
+
+	msm_bus_scale_unregister_client(bus_client_data->client_id);
+	kfree(bus_client_data);
+	bus_client->client_data = NULL;
+	kfree(bus_client);
+	*client = NULL;
+}

+ 96 - 0
drivers/cam_utils/cam_soc_bus.h

@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _CAM_SOC_BUS_H_
+#define _CAM_SOC_BUS_H_
+
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include "cam_debug_util.h"
+
+#define CAM_SOC_BUS_MAX_NUM_USECASES 8
+
+/**
+ * struct cam_soc_bus_client_ab_ib : Bandwidth values for selected usecase
+ *
+ * @ab: Arbitrated Bandwidth
+ * @ib: Instantaneous Bandwidth
+ */
+struct cam_soc_bus_client_ab_ib {
+	uint64_t ab;
+	uint64_t ib;
+};
+
+/**
+ * struct cam_soc_bus_client_common_data : Common data fields for bus client
+ *
+ * @name: Name of bus client
+ * @src_id: Bus master/src id
+ * @dst_id: Bus slave/dst id
+ * @num_usecases: Number of use cases for this client
+ * @bw_pair: Bandwidth values for applicable usecases
+ */
+struct cam_soc_bus_client_common_data {
+	const char *name;
+	uint32_t src_id;
+	uint32_t dst_id;
+	int num_usecases;
+	struct cam_soc_bus_client_ab_ib bw_pair[CAM_SOC_BUS_MAX_NUM_USECASES];
+};
+
+/**
+ * struct cam_soc_bus_client : Bus client information
+ *
+ * @client_data: Bus client data
+ * @common_data: Common data fields for bus client
+ */
+struct cam_soc_bus_client {
+	void *client_data;
+	struct cam_soc_bus_client_common_data *common_data;
+};
+
+
+#if IS_REACHABLE(CONFIG_QCOM_BUS_SCALING) || \
+	IS_REACHABLE(CONFIG_INTERCONNECT_QCOM)
+
+int cam_soc_bus_client_update_request(void *client, unsigned int idx);
+
+int cam_soc_bus_client_update_bw(void *client, uint64_t ab,
+	uint64_t ib);
+
+int cam_soc_bus_client_register(struct platform_device *pdev,
+	struct device_node *dev_node, void **client,
+	struct cam_soc_bus_client_common_data *common_data);
+
+void cam_soc_bus_client_unregister(void **client);
+
+#else
+static inline int cam_soc_bus_client_update_request(void *client,
+	unsigned int idx)
+{
+	return 0;
+}
+
+static inline int cam_soc_bus_client_update_bw(void *client,
+	uint64_t ab, uint64_t ib)
+{
+	return 0;
+}
+
+static inline int cam_soc_bus_client_register(
+	struct platform_device *pdev, struct device_node *dev_node,
+	void **client, struct cam_soc_bus_client_common_data *common_data)
+{
+	return 0;
+}
+
+static inline void cam_soc_bus_client_unregister(void **client)
+{
+}
+
+#endif
+
+#endif /* _CAM_SOC_BUS_H_ */

+ 149 - 0
drivers/cam_utils/cam_soc_icc.c

@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/interconnect.h>
+#include "cam_soc_bus.h"
+
+/**
+ * struct cam_soc_bus_client_data : Bus client data
+ *
+ * @icc_data: Bus icc path information
+ */
+struct cam_soc_bus_client_data {
+	struct icc_path *icc_data;
+};
+
+int cam_soc_bus_client_update_request(void *client, unsigned int idx)
+{
+	int rc = 0;
+	uint64_t ab = 0, ib = 0;
+	struct cam_soc_bus_client *bus_client =
+		(struct cam_soc_bus_client *) client;
+	struct cam_soc_bus_client_data *bus_client_data =
+		(struct cam_soc_bus_client_data *) bus_client->client_data;
+
+	if (idx >= bus_client->common_data->num_usecases) {
+		CAM_ERR(CAM_UTIL, "Invalid vote level=%d, usecases=%d", idx,
+			bus_client->common_data->num_usecases);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	ab = bus_client->common_data->bw_pair[idx].ab;
+	ib = bus_client->common_data->bw_pair[idx].ib;
+
+	CAM_DBG(CAM_UTIL, "Bus client=[%s] index[%d]",
+		bus_client->common_data->name, idx);
+
+	rc = icc_set_bw(bus_client_data->icc_data, ab, ib);
+	if (rc) {
+		CAM_ERR(CAM_UTIL,
+			"Update request failed, client[%s], idx: %d",
+			bus_client->common_data->name, idx);
+		goto end;
+	}
+
+end:
+	return rc;
+}
+
+int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
+{
+	struct cam_soc_bus_client *bus_client =
+		(struct cam_soc_bus_client *) client;
+	struct cam_soc_bus_client_data *bus_client_data =
+		(struct cam_soc_bus_client_data *) bus_client->client_data;
+	int rc = 0;
+
+	CAM_DBG(CAM_UTIL, "Bus client=[%s] :ab[%llu] ib[%llu]",
+		bus_client->common_data->name, ab, ib);
+	rc = icc_set_bw(bus_client_data->icc_data, ab, ib);
+	if (rc) {
+		CAM_ERR(CAM_UTIL, "Update request failed, client[%s]",
+			bus_client->common_data->name);
+		goto end;
+	}
+
+end:
+	return rc;
+}
+
+int cam_soc_bus_client_register(struct platform_device *pdev,
+	struct device_node *dev_node, void **client,
+	struct cam_soc_bus_client_common_data *common_data)
+{
+	struct cam_soc_bus_client *bus_client = NULL;
+	struct cam_soc_bus_client_data *bus_client_data = NULL;
+	int rc = 0;
+
+	bus_client = kzalloc(sizeof(struct cam_soc_bus_client), GFP_KERNEL);
+	if (!bus_client) {
+		CAM_ERR(CAM_UTIL, "soc bus client is NULL");
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	*client = bus_client;
+
+	bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data),
+		GFP_KERNEL);
+	if (!bus_client_data) {
+		kfree(bus_client);
+		*client = NULL;
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	bus_client->client_data = bus_client_data;
+	bus_client_data->icc_data = icc_get(&pdev->dev,
+		bus_client->common_data->src_id,
+		bus_client->common_data->dst_id);
+	if (!bus_client_data->icc_data) {
+		CAM_ERR(CAM_UTIL, "failed in register bus client");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	bus_client->common_data = common_data;
+
+	rc = icc_set_bw(bus_client_data->icc_data, 0, 0);
+	if (rc) {
+		CAM_ERR(CAM_UTIL, "Bus client update request failed, rc = %d",
+			rc);
+		goto fail_unregister_client;
+	}
+
+	CAM_DBG(CAM_UTIL, "Bus Client=[%s] : src=%d, dst=%d",
+		bus_client->common_data->name, bus_client->common_data->src_id,
+		bus_client->common_data->dst_id);
+
+	return 0;
+
+fail_unregister_client:
+	icc_put(bus_client_data->icc_data);
+error:
+	kfree(bus_client_data);
+	bus_client->client_data = NULL;
+	kfree(bus_client);
+	*client = NULL;
+end:
+	return rc;
+
+}
+
+void cam_soc_bus_client_unregister(void **client)
+{
+	struct cam_soc_bus_client *bus_client =
+		(struct cam_soc_bus_client *) (*client);
+	struct cam_soc_bus_client_data *bus_client_data =
+		(struct cam_soc_bus_client_data *) bus_client->client_data;
+
+	icc_put(bus_client_data->icc_data);
+	kfree(bus_client_data);
+	bus_client->client_data = NULL;
+	kfree(bus_client);
+	*client = NULL;
+
+}