Parcourir la source

msm: camera: common: Add support for DRV config

Add DRV config blob handling for programming required
registers per request. Also, add debugfs entry for
disabling DRV feature from ife hw manager. Update
existing BW voting logs to reflect DRV vote level info.
Add support for communicating with rsc device upon update
in MNOC BW. Also, update BW voting logic in cpas to accommodate
DRV voting to interconnect framework.

CRs-Fixed: 3065551
Change-Id: I8ac4820b7af824f5ff46614ae6804001deca9b01
Signed-off-by: Mukund Madhusudan Atre <[email protected]>
Mukund Madhusudan Atre il y a 3 ans
Parent
commit
65878f05bb
26 fichiers modifiés avec 1669 ajouts et 489 suppressions
  1. 1 0
      config/kalama.mk
  2. 536 194
      drivers/cam_cpas/cam_cpas_hw.c
  3. 81 16
      drivers/cam_cpas/cam_cpas_hw.h
  4. 18 0
      drivers/cam_cpas/cam_cpas_hw_intf.h
  5. 94 0
      drivers/cam_cpas/cam_cpas_intf.c
  6. 257 188
      drivers/cam_cpas/cam_cpas_soc.c
  7. 9 22
      drivers/cam_cpas/cam_cpas_soc.h
  8. 49 0
      drivers/cam_cpas/include/cam_cpas_api.h
  9. 156 12
      drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
  10. 4 0
      drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
  11. 4 0
      drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
  12. 27 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid780.h
  13. 27 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid880.h
  14. 4 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c
  15. 77 1
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c
  16. 9 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h
  17. 16 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
  18. 1 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
  19. 39 2
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c
  20. 7 7
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
  21. 12 4
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c
  22. 96 0
      drivers/cam_utils/cam_compat.c
  23. 8 0
      drivers/cam_utils/cam_compat.h
  24. 3 1
      drivers/cam_utils/cam_soc_bus.c
  25. 23 4
      drivers/cam_utils/cam_soc_bus.h
  26. 111 38
      drivers/cam_utils/cam_soc_icc.c

+ 1 - 0
config/kalama.mk

@@ -6,6 +6,7 @@ CONFIG_SPECTRA_ICP := y
 CONFIG_SPECTRA_JPEG := y
 CONFIG_SPECTRA_CUSTOM := y
 CONFIG_SPECTRA_SENSOR := y
+CONFIG_USE_RPMH_DRV_API := n
 
 # Flags to pass into C preprocessor
 ccflags-y += -DCONFIG_SPECTRA_ISP=1

Fichier diff supprimé car celui-ci est trop grand
+ 536 - 194
drivers/cam_cpas/cam_cpas_hw.c


+ 81 - 16
drivers/cam_cpas/cam_cpas_hw.h

@@ -17,6 +17,7 @@
 #define CAM_CPAS_INFLIGHT_WORKS              5
 #define CAM_CPAS_MAX_CLIENTS                 42
 #define CAM_CPAS_MAX_AXI_PORTS               6
+#define CAM_CPAS_MAX_DRV_PORTS               4
 #define CAM_CPAS_MAX_TREE_LEVELS             4
 #define CAM_CPAS_MAX_RT_WR_NIU_NODES         10
 #define CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT   32
@@ -65,6 +66,66 @@ enum cam_cpas_access_type {
 	CAM_REG_TYPE_READ_WRITE,
 };
 
+/**
+ * enum cam_cpas_vote_type - Enum for cpas vote type
+ */
+enum cam_cpas_vote_type {
+	CAM_CPAS_VOTE_TYPE_HLOS,
+	CAM_CPAS_VOTE_TYPE_DRV,
+};
+
+/**
+ * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
+ *
+ * @vdd_corner : Voltage corner value
+ * @ahb_level : AHB vote level corresponds to this vdd_corner
+ *
+ */
+struct cam_cpas_vdd_ahb_mapping {
+	unsigned int vdd_corner;
+	enum cam_vote_level ahb_level;
+};
+
+/**
+ * struct cam_cpas_bw_vote : AXI bw vote
+ *
+ * @ab: AB bw value
+ * @ib: IB bw value
+ *
+ */
+struct cam_cpas_bw_vote {
+	uint64_t ab;
+	uint64_t ib;
+};
+
+/**
+ * struct cam_cpas_drv_vote : DRV bw vote
+ *
+ * @high: Active bw values
+ * @low:  Sleep bw values
+ *
+ */
+struct cam_cpas_drv_vote {
+	struct cam_cpas_bw_vote high;
+	struct cam_cpas_bw_vote low;
+};
+
+/**
+ * struct cam_cpas_axi_bw_info : AXI bw info
+ *
+ * @vote_type:  HLOS or DRV vote type
+ * @hlos_vote: HLOS bw values
+ * @drv_vote:  DRV bw values
+ *
+ */
+struct cam_cpas_axi_bw_info {
+	enum cam_cpas_vote_type vote_type;
+	union {
+		struct cam_cpas_bw_vote hlos_vote;
+		struct cam_cpas_drv_vote drv_vote;
+	};
+};
+
 /**
  * struct cam_cpas_internal_ops - CPAS Hardware layer internal ops
  *
@@ -124,6 +185,7 @@ struct cam_cpas_reg {
  * @registered: Whether client has registered with cpas
  * @started: Whether client has streamed on
  * @tree_node_valid: Indicates whether tree node has at least one valid node
+ * @is_drv_dyn: Indicates whether this client is DRV dynamic voting client
  * @ahb_level: Determined/Applied ahb level for the client
  * @axi_vote: Determined/Applied axi vote for the client
  * @axi_port: Client's parent axi port
@@ -135,6 +197,7 @@ struct cam_cpas_client {
 	bool registered;
 	bool started;
 	bool tree_node_valid;
+	bool is_drv_dyn;
 	enum cam_vote_level ahb_level;
 	struct cam_axi_vote axi_vote;
 	struct cam_cpas_axi_port *axi_port;
@@ -168,12 +231,13 @@ struct cam_cpas_bus_client {
  * @ib_bw_voting_needed: if this port can update ib bw dynamically
  * @is_rt: if this port represents a real time axi port
  * @axi_port_node: Node representing AXI Port info in device tree
- * @ab_bw: AB bw value for this port
- * @ib_bw: IB bw value for this port
+ * @drv_idx: DRV index for axi port node
+ * @cam_rsc_dev: Cam RSC device for DRV
+ * @is_drv_started: Indicates if DRV started for RSC device corresponding to port
+ * @curr_bw: Current voted bw after cpas consolidation
  * @camnoc_bw: CAMNOC bw value for this port
  * @additional_bw: Additional bandwidth to cover non-hw cpas clients
- * @applied_ab_bw: applied ab bw for this port
- * @applied_ib_bw: applied ib bw for this port
+ * @applied_bw: Actual applied bw to port
  */
 struct cam_cpas_axi_port {
 	const char *axi_port_name;
@@ -181,31 +245,30 @@ struct cam_cpas_axi_port {
 	bool ib_bw_voting_needed;
 	bool is_rt;
 	struct device_node *axi_port_node;
-	uint64_t ab_bw;
-	uint64_t ib_bw;
+	uint32_t drv_idx;
+	const struct device *cam_rsc_dev;
+	bool is_drv_started;
+	struct cam_cpas_axi_bw_info curr_bw;
 	uint64_t camnoc_bw;
 	uint64_t additional_bw;
-	uint64_t applied_ab_bw;
-	uint64_t applied_ib_bw;
+	struct cam_cpas_axi_bw_info applied_bw;
 };
 
 /**
  * struct cam_cpas_axi_port_debug_info : AXI port information
  *
  * @axi_port_name: Name of this AXI port
- * @ab_bw: AB bw value for this port
- * @ib_bw: IB bw value for this port
+ * @curr_bw: Current voted bw after cpas consolidation
  * @camnoc_bw: CAMNOC bw value for this port
- * @applied_ab_bw: applied ab bw for this port
- * @applied_ib_bw: applied ib bw for this port
+ * @applied_bw: Actual applied bw to port
+ * @is_drv_started: Indicates if DRV started for RSC device corresponding to port
  */
 struct cam_cpas_axi_port_debug_info {
 	const char *axi_port_name;
-	uint64_t ab_bw;
-	uint64_t ib_bw;
+	struct cam_cpas_axi_bw_info curr_bw;
 	uint64_t camnoc_bw;
-	uint64_t applied_ab_bw;
-	uint64_t applied_ib_bw;
+	struct cam_cpas_axi_bw_info applied_bw;
+	bool is_drv_started;
 };
 
 /**
@@ -285,6 +348,7 @@ struct cam_cpas_monitor {
  * @slave_err_irq_en: Whether slave error irq is enabled to detect memory
  *                    config issues
  * @smmu_fault_handled: Handled address decode error, on fault at SMMU
+ * @force_hlos_drv: Whether to force disable DRV voting
  */
 struct cam_cpas {
 	struct cam_cpas_hw_caps hw_caps;
@@ -315,6 +379,7 @@ struct cam_cpas {
 	bool smart_qos_dump;
 	bool slave_err_irq_en;
 	bool smmu_fault_handled;
+	bool force_hlos_drv;
 };
 
 int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);

+ 18 - 0
drivers/cam_cpas/cam_cpas_hw_intf.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_CPAS_HW_INTF_H_
@@ -47,9 +48,26 @@ enum cam_cpas_hw_cmd_process {
 	CAM_CPAS_HW_CMD_ACTIVATE_LLC,
 	CAM_CPAS_HW_CMD_DEACTIVATE_LLC,
 	CAM_CPAS_HW_CMD_DUMP_BUFF_FILL_INFO,
+	CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE,
+	CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME,
 	CAM_CPAS_HW_CMD_INVALID,
 };
 
+/**
+ * struct cam_cpas_hw_cmd_csid_input_core_info_update : CPAS cmd struct for updating acquired
+ *                                                      csid core info to cpas
+ *
+ * @csid_idx: CSID core index
+ * @sfe_idx:  SFE core index corresponding to CSID core
+ * @set_port: Indicates whether to set or reset port for given client
+ *
+ */
+struct cam_cpas_hw_cmd_csid_input_core_info_update {
+	int csid_idx;
+	int sfe_idx;
+	bool set_port;
+};
+
 /**
  * struct cam_cpas_hw_cmd_reg_read_write : CPAS cmd struct for reg read, write
  *

+ 94 - 0
drivers/cam_cpas/cam_cpas_intf.c

@@ -144,6 +144,100 @@ const char *cam_cpas_axi_util_trans_type_to_string(
 }
 EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
 
+const char *cam_cpas_axi_util_drv_vote_lvl_to_string(
+	uint32_t vote_lvl)
+{
+	switch (vote_lvl) {
+	case CAM_CPAS_VOTE_LEVEL_LOW:
+		return "VOTE_LVL_LOW";
+	case CAM_CPAS_VOTE_LEVEL_HIGH:
+		return "VOTE_LVL_HIGH";
+	default:
+		return "VOTE_LVL_INVALID";
+	}
+}
+EXPORT_SYMBOL(cam_cpas_axi_util_drv_vote_lvl_to_string);
+
+int cam_cpas_query_drv_enable(bool *is_drv_enabled)
+{
+	struct cam_hw_info *cpas_hw = NULL;
+	struct cam_cpas_private_soc *soc_private = NULL;
+
+	if (!CAM_CPAS_INTF_INITIALIZED()) {
+		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
+		return -ENODEV;
+	}
+
+	if (!is_drv_enabled) {
+		CAM_ERR(CAM_CPAS, "invalid input %pK", is_drv_enabled);
+		return -EINVAL;
+	}
+
+	cpas_hw = (struct cam_hw_info  *) g_cpas_intf->hw_intf->hw_priv;
+	soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+
+	*is_drv_enabled = soc_private->enable_cam_ddr_drv;
+
+	return 0;
+}
+EXPORT_SYMBOL(cam_cpas_query_drv_enable);
+
+int cam_cpas_csid_process_resume(uint32_t csid_idx)
+{
+	int rc;
+
+	if (!CAM_CPAS_INTF_INITIALIZED()) {
+		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
+		return -ENODEV;
+	}
+
+	if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
+		rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
+			g_cpas_intf->hw_intf->hw_priv,
+			CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME, &csid_idx,
+			sizeof(uint32_t));
+		if (rc)
+			CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
+	} else {
+		CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(cam_cpas_csid_process_resume);
+
+
+int cam_cpas_csid_input_core_info_update(int csid_idx, int sfe_idx, bool set_port)
+{
+	int rc;
+
+	if (!CAM_CPAS_INTF_INITIALIZED()) {
+		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
+		return -ENODEV;
+	}
+
+	if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
+		struct cam_cpas_hw_cmd_csid_input_core_info_update core_info_update;
+
+		core_info_update.csid_idx = csid_idx;
+		core_info_update.sfe_idx = sfe_idx;
+		core_info_update.set_port = set_port;
+		rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
+			g_cpas_intf->hw_intf->hw_priv,
+			CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE, &core_info_update,
+			sizeof(core_info_update));
+		if (rc)
+			CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
+	} else {
+		CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(cam_cpas_csid_input_core_info_update);
+
 int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle)
 {
 	int rc;

+ 257 - 188
drivers/cam_cpas/cam_cpas_soc.c

@@ -17,8 +17,9 @@
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_hw.h"
 #include "cam_cpas_soc.h"
+#include "cam_compat.h"
 
-static uint cpas_dump;
+static uint cpas_dump = 1;
 module_param(cpas_dump, uint, 0644);
 
 #define CAM_ICP_CLK_NAME "cam_icp_clk"
@@ -42,11 +43,12 @@ void cam_cpas_dump_axi_vote_info(
 
 	for (i = 0; i < axi_vote->num_paths; i++) {
 		CAM_INFO(CAM_PERF,
-		"Client [%s][%d] : [%s], Path=[%d] [%d], camnoc[%llu], mnoc_ab[%llu], mnoc_ib[%llu]",
+		"Client [%s][%d] : [%s], Path=[%d] [%d], [%s], camnoc[%llu], mnoc_ab[%llu], mnoc_ib[%llu]",
 		cpas_client->data.identifier, cpas_client->data.cell_index,
 		identifier,
 		axi_vote->axi_path[i].path_data_type,
 		axi_vote->axi_path[i].transac_type,
+		cam_cpas_axi_util_drv_vote_lvl_to_string(axi_vote->axi_path[i].vote_level),
 		axi_vote->axi_path[i].camnoc_bw,
 		axi_vote->axi_path[i].mnoc_ab_bw,
 		axi_vote->axi_path[i].mnoc_ib_bw);
@@ -71,7 +73,7 @@ void cam_cpas_util_debug_parse_data(
 		CAM_INFO(CAM_CPAS,
 			"NODE cell_idx: %d, level: %d, name: %s, axi_port_idx: %d, merge_type: %d, parent_name: %s camnoc_max_needed: %d",
 			curr_node->cell_idx, curr_node->level_idx,
-			curr_node->node_name, curr_node->axi_port_idx,
+			curr_node->node_name, curr_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV],
 			curr_node->merge_type, curr_node->parent_node ?
 			curr_node->parent_node->node_name : "no parent",
 			curr_node->camnoc_max_needed);
@@ -79,10 +81,10 @@ void cam_cpas_util_debug_parse_data(
 		if (curr_node->level_idx)
 			continue;
 
-		CAM_INFO(CAM_CPAS, "path_type: %d, transac_type: %s",
+		CAM_INFO(CAM_CPAS, "path_type: %d, transac_type: %s drv_voting_idx:%d",
 			curr_node->path_data_type,
 			cam_cpas_axi_util_trans_type_to_string(
-			curr_node->path_trans_type));
+			curr_node->path_trans_type), curr_node->drv_voting_idx);
 
 		for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) {
 			CAM_INFO(CAM_CPAS, "Constituent path: %d",
@@ -100,6 +102,10 @@ int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core,
 
 	for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) {
 		if (soc_private->tree_node[i]) {
+			kfree(soc_private->tree_node[i]->bw_info);
+			kfree(soc_private->tree_node[i]->axi_port_idx_arr);
+			soc_private->tree_node[i]->bw_info = NULL;
+			soc_private->tree_node[i]->axi_port_idx_arr = NULL;
 			of_node_put(soc_private->tree_node[i]->tree_dev_node);
 			kfree(soc_private->tree_node[i]);
 			soc_private->tree_node[i] = NULL;
@@ -182,6 +188,151 @@ static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core,
 	return 0;
 }
 
+static int cam_cpas_parse_mnoc_node(struct cam_cpas *cpas_core,
+	struct cam_cpas_private_soc *soc_private, struct cam_cpas_tree_node *curr_node_ptr,
+	struct device_node *mnoc_node, int *mnoc_idx)
+{
+	int rc = 0, count = 0, i;
+	bool ib_voting_needed = false, is_rt_port = false;
+	struct of_phandle_args src_args = {0}, dst_args = {0};
+
+	ib_voting_needed = of_property_read_bool(curr_node_ptr->tree_dev_node,
+		"ib-bw-voting-needed");
+	is_rt_port = of_property_read_bool(curr_node_ptr->tree_dev_node, "rt-axi-port");
+
+	if (soc_private->bus_icc_based) {
+		count = of_property_count_strings(mnoc_node, "interconnect-names");
+		if (count <= 0) {
+			CAM_ERR(CAM_CPAS, "no interconnect-names found");
+			count = 0;
+			return -EINVAL;
+		} else if (count > CAM_CPAS_MAX_DRV_PORTS) {
+			CAM_ERR(CAM_CPAS, "Number of interconnects %d greater than max ports %d",
+				count, CAM_CPAS_MAX_DRV_PORTS);
+			count = 0;
+			return -EINVAL;
+		}
+
+		for (i = 0; i < count; i++) {
+			if ((i > 0) && !soc_private->enable_cam_ddr_drv)
+				break;
+
+			if (*mnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) {
+				CAM_ERR(CAM_CPAS, "Invalid mnoc index: %d", *mnoc_idx);
+				return -EINVAL;
+			}
+
+			cpas_core->axi_port[*mnoc_idx].axi_port_node = mnoc_node;
+			rc = of_property_read_string_index(mnoc_node, "interconnect-names", i,
+				&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", (2 * i), &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", ((2 * i) + 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;
+			cpas_core->axi_port[*mnoc_idx].axi_port_name =
+				cpas_core->axi_port[*mnoc_idx].bus_client.common_data.name;
+			cpas_core->axi_port[*mnoc_idx].drv_idx = i;
+
+			if (i > CAM_CPAS_PORT_HLOS_DRV) {
+				cpas_core->axi_port[*mnoc_idx].bus_client.common_data.is_drv_port =
+					true;
+				cpas_core->axi_port[*mnoc_idx].curr_bw.vote_type =
+					CAM_CPAS_VOTE_TYPE_DRV;
+				cpas_core->axi_port[*mnoc_idx].applied_bw.vote_type =
+					CAM_CPAS_VOTE_TYPE_DRV;
+				cpas_core->axi_port[*mnoc_idx].cam_rsc_dev =
+					cam_cpas_get_rsc_dev_for_drv(i - CAM_CPAS_PORT_DRV_0);
+				if (!cpas_core->axi_port[*mnoc_idx].cam_rsc_dev) {
+					CAM_ERR(CAM_CPAS,
+						"Port[%s][%d] Failed to get rsc device drv_idx:%d",
+						cpas_core->axi_port[*mnoc_idx].axi_port_name,
+						*mnoc_idx, i);
+					rc = -ENODEV;
+					goto err;
+				}
+			}
+
+			/*
+			 * The indexes of axi_port_idx_arr map to drv_voting_idx,
+			 * with 0 pointing to hlos drv bus ID
+			 */
+			curr_node_ptr->axi_port_idx_arr[i] = *mnoc_idx;
+			cpas_core->axi_port[*mnoc_idx].ib_bw_voting_needed = ib_voting_needed;
+			cpas_core->axi_port[*mnoc_idx].is_rt = is_rt_port;
+			CAM_DBG(CAM_PERF, "Adding Bus Client=[%s] : src=%d, dst=%d mnoc_idx:%d",
+				cpas_core->axi_port[*mnoc_idx].bus_client.common_data.name,
+				cpas_core->axi_port[*mnoc_idx].bus_client.common_data.src_id,
+				cpas_core->axi_port[*mnoc_idx].bus_client.common_data.dst_id,
+				*mnoc_idx);
+			(*mnoc_idx)++;
+			cpas_core->num_axi_ports++;
+		}
+	} else {
+		if (soc_private->enable_cam_ddr_drv) {
+			CAM_ERR(CAM_CPAS, "DRV not supported for old bus scaling clients");
+			return -EPERM;
+		}
+
+		cpas_core->axi_port[*mnoc_idx].axi_port_node = mnoc_node;
+		rc =  of_property_read_string(curr_node_ptr->tree_dev_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].axi_port_name =
+			cpas_core->axi_port[*mnoc_idx].bus_client.common_data.name;
+		curr_node_ptr->axi_port_idx_arr[0] = *mnoc_idx;
+		cpas_core->axi_port[*mnoc_idx].ib_bw_voting_needed = ib_voting_needed;
+		cpas_core->axi_port[*mnoc_idx].is_rt = is_rt_port;
+		(*mnoc_idx)++;
+		cpas_core->num_axi_ports++;
+	}
+
+err:
+	return rc;
+}
+
 static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 	struct device_node *of_node, struct cam_cpas_private_soc *soc_private)
 {
@@ -198,7 +349,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 	const char *client_name = NULL;
 	uint32_t client_idx = 0, cell_idx = 0;
 	uint8_t niu_idx = 0;
-	int rc = 0, count = 0, i;
+	int rc = 0, count = 0, i, j, num_drv_ports;
 
 	camera_bus_node = of_get_child_by_name(of_node, "camera-bus-nodes");
 	if (!camera_bus_node) {
@@ -209,8 +360,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 	soc_private->camera_bus_node = camera_bus_node;
 
 	for_each_available_child_of_node(camera_bus_node, level_node) {
-		rc = of_property_read_u32(level_node, "level-index",
-			&level_idx);
+		rc = of_property_read_u32(level_node, "level-index", &level_idx);
 		if (rc) {
 			CAM_ERR(CAM_CPAS, "Error reading level idx rc: %d", rc);
 			return rc;
@@ -226,6 +376,11 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 	if (soc_private->enable_smart_qos)
 		soc_private->smart_qos_info->num_rt_wr_nius = 0;
 
+	if (soc_private->enable_cam_ddr_drv)
+		num_drv_ports = CAM_CPAS_MAX_DRV_PORTS;
+	else
+		num_drv_ports = 1;
+
 	for (level_idx = (CAM_CPAS_MAX_TREE_LEVELS - 1); level_idx >= 0;
 		level_idx--) {
 		level_node = soc_private->level_node[level_idx];
@@ -234,12 +389,9 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 
 		CAM_DBG(CAM_CPAS, "Parsing level %d nodes", level_idx);
 
-		camnoc_max_needed = of_property_read_bool(level_node,
-			"camnoc-max-needed");
+		camnoc_max_needed = of_property_read_bool(level_node, "camnoc-max-needed");
 		for_each_available_child_of_node(level_node, curr_node) {
-			curr_node_ptr =
-				kzalloc(sizeof(struct cam_cpas_tree_node),
-				GFP_KERNEL);
+			curr_node_ptr = kzalloc(sizeof(struct cam_cpas_tree_node), GFP_KERNEL);
 			if (!curr_node_ptr)
 				return -ENOMEM;
 
@@ -256,50 +408,54 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 
 			if (curr_node_ptr->cell_idx >=
 				CAM_CPAS_MAX_TREE_NODES) {
-				CAM_ERR(CAM_CPAS, "Invalid cell idx: %d",
-					curr_node_ptr->cell_idx);
+				CAM_ERR(CAM_CPAS, "Invalid cell idx: %d", curr_node_ptr->cell_idx);
 				return -EINVAL;
 			}
 
-			soc_private->tree_node[curr_node_ptr->cell_idx] =
-				curr_node_ptr;
+			soc_private->tree_node[curr_node_ptr->cell_idx] = curr_node_ptr;
 			curr_node_ptr->level_idx = level_idx;
 
 			rc = of_property_read_string(curr_node, "node-name",
 				&curr_node_ptr->node_name);
 			if (rc) {
-				CAM_ERR(CAM_CPAS,
-					"failed to read node-name rc=%d",
-					rc);
+				CAM_ERR(CAM_CPAS, "failed to read node-name rc=%d", rc);
 				return rc;
 			}
 
-			if (soc_private->enable_smart_qos &&
-				(level_idx == 1) &&
+			curr_node_ptr->bw_info = kzalloc((sizeof(struct cam_cpas_axi_bw_info) *
+				num_drv_ports), GFP_KERNEL);
+			if (!curr_node_ptr->bw_info) {
+				CAM_ERR(CAM_CPAS, "Failed in allocating memory for bw info");
+				return -ENOMEM;
+			}
+
+			curr_node_ptr->axi_port_idx_arr = kzalloc((sizeof(int) * num_drv_ports),
+				GFP_KERNEL);
+			if (!curr_node_ptr->axi_port_idx_arr) {
+				CAM_ERR(CAM_CPAS, "Failed in allocating memory for port indices");
+				return -ENOMEM;
+			}
+
+			if (soc_private->enable_smart_qos && (level_idx == 1) &&
 				of_property_read_bool(curr_node, "rt-wr-niu")) {
 
-				rc = of_property_read_u32(curr_node,
-					"priority-lut-low-offset",
+				rc = of_property_read_u32(curr_node, "priority-lut-low-offset",
 					&curr_node_ptr->pri_lut_low_offset);
 				if (rc) {
-					CAM_ERR(CAM_CPAS,
-						"Invalid priority offset rc %d",
-						rc);
+					CAM_ERR(CAM_CPAS, "Invalid priority offset rc %d", rc);
 					return rc;
 				}
 
 				rc = of_property_read_u32(curr_node, "niu-size",
 					&curr_node_ptr->niu_size);
 				if (rc || !curr_node_ptr->niu_size) {
-					CAM_ERR(CAM_CPAS,
-						"Invalid niu size rc %d", rc);
+					CAM_ERR(CAM_CPAS, "Invalid niu size rc %d", rc);
 					return rc;
 				}
 
 				niu_idx = soc_private->smart_qos_info->num_rt_wr_nius;
 				if (niu_idx >= CAM_CPAS_MAX_RT_WR_NIU_NODES) {
-					CAM_ERR(CAM_CPAS,
-						"Invalid number of level1 nodes %d",
+					CAM_ERR(CAM_CPAS, "Invalid number of level1 nodes %d",
 						soc_private->smart_qos_info->num_rt_wr_nius);
 					return -EINVAL;
 				}
@@ -310,8 +466,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 
 				CAM_DBG(CAM_CPAS,
 					"level1[%d] : Node %s idx %d priority offset 0x%x, NIU size %dKB",
-					niu_idx,
-					curr_node_ptr->node_name, curr_node_ptr->cell_idx,
+					niu_idx, curr_node_ptr->node_name, curr_node_ptr->cell_idx,
 					curr_node_ptr->pri_lut_low_offset, curr_node_ptr->niu_size);
 			}
 
@@ -321,221 +476,130 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 			if (rc)
 				curr_node_ptr->bus_width_factor = 1;
 
-			rc = of_property_read_u32(curr_node,
-				"traffic-merge-type",
+			rc = of_property_read_u32(curr_node, "traffic-merge-type",
 				&curr_node_ptr->merge_type);
 
-			curr_node_ptr->axi_port_idx = -1;
-			mnoc_node = of_get_child_by_name(curr_node,
-				"qcom,axi-port-mnoc");
-			if (mnoc_node) {
-				if (mnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) {
-					CAM_ERR(CAM_CPAS,
-						"Invalid mnoc index: %d",
-						mnoc_idx);
-					return -EINVAL;
-				}
-
-				cpas_core->axi_port[mnoc_idx].axi_port_node
-					= mnoc_node;
-				if (soc_private->bus_icc_based) {
-					struct of_phandle_args src_args = {0},
-						dst_args = {0};
+			for (j = 0; j < num_drv_ports; j++)
+				curr_node_ptr->axi_port_idx_arr[j] = -1;
 
-					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;
-					}
+			mnoc_node = of_get_child_by_name(curr_node, "qcom,axi-port-mnoc");
+			if (mnoc_node) {
+				rc = cam_cpas_parse_mnoc_node(cpas_core, soc_private, curr_node_ptr,
+					mnoc_node, &mnoc_idx);
+				if (rc) {
+					CAM_ERR(CAM_CPAS, "failed to parse mnoc node info rc=%d",
+						rc);
+					return rc;
 				}
-
-				cpas_core->axi_port[mnoc_idx].axi_port_name =
-					cpas_core->axi_port[mnoc_idx]
-						.bus_client.common_data.name;
-				cpas_core->axi_port
-					[mnoc_idx].ib_bw_voting_needed
-					= of_property_read_bool(curr_node,
-					"ib-bw-voting-needed");
-				cpas_core->axi_port
-					[mnoc_idx].is_rt
-					= of_property_read_bool(curr_node,
-					"rt-axi-port");
-				curr_node_ptr->axi_port_idx = mnoc_idx;
-				mnoc_idx++;
-				cpas_core->num_axi_ports++;
 			}
 
 			if (!soc_private->control_camnoc_axi_clk) {
-				rc = cam_cpas_update_camnoc_node(
-					cpas_core, curr_node, curr_node_ptr,
-					&camnoc_idx);
+				rc = cam_cpas_update_camnoc_node(cpas_core, curr_node,
+					curr_node_ptr, &camnoc_idx);
 				if (rc) {
-					CAM_ERR(CAM_CPAS,
-						"Parse Camnoc port fail");
+					CAM_ERR(CAM_CPAS, "failed to parse camnoc node info rc=%d",
+						rc);
 					return rc;
 				}
 			}
 
-			rc = of_property_read_string(curr_node,
-				"client-name", &client_name);
+			rc = of_property_read_string(curr_node, "client-name", &client_name);
 			if (!rc) {
-				rc = of_property_read_u32(curr_node,
-				"traffic-data", &curr_node_ptr->path_data_type);
+				rc = of_property_read_u32(curr_node, "traffic-data",
+					&curr_node_ptr->path_data_type);
 				if (rc) {
 					CAM_ERR(CAM_CPAS,
 						"Path Data type not found");
 					return rc;
 				}
 
-				rc = cam_cpas_util_path_type_to_idx(
-					&curr_node_ptr->path_data_type);
+				rc = cam_cpas_util_path_type_to_idx(&curr_node_ptr->path_data_type);
 				if (rc) {
 					CAM_ERR(CAM_CPAS, "Incorrect path type for client: %s",
 						client_name);
 					return rc;
 				}
 
-				rc = of_property_read_u32(curr_node,
-					"traffic-transaction-type",
+				rc = of_property_read_u32(curr_node, "traffic-transaction-type",
 					&curr_node_ptr->path_trans_type);
 				if (rc) {
-					CAM_ERR(CAM_CPAS,
-						"Path Transac type not found");
+					CAM_ERR(CAM_CPAS, "Path Transac type not found");
 					return rc;
 				}
 
-				if (curr_node_ptr->path_trans_type >=
-					CAM_CPAS_TRANSACTION_MAX) {
-					CAM_ERR(CAM_CPAS,
-						"Invalid transac type: %d",
+				if (curr_node_ptr->path_trans_type >= CAM_CPAS_TRANSACTION_MAX) {
+					CAM_ERR(CAM_CPAS, "Invalid transac type: %d",
 						curr_node_ptr->path_trans_type);
 					return -EINVAL;
 				}
 
-				count = of_property_count_u32_elems(curr_node,
-					"constituent-paths");
+				count = of_property_count_u32_elems(curr_node, "constituent-paths");
 				for (i = 0; i < count; i++) {
-					rc = of_property_read_u32_index(
-						curr_node, "constituent-paths",
-						i, &path_idx);
+					rc = of_property_read_u32_index(curr_node,
+						"constituent-paths", i, &path_idx);
 					if (rc) {
-						CAM_ERR(CAM_CPAS,
-						"No constituent path at %d", i);
+						CAM_ERR(CAM_CPAS, "No constituent path at %d", i);
 						return rc;
 					}
 
-					rc = cam_cpas_util_path_type_to_idx(
-						&path_idx);
+					rc = cam_cpas_util_path_type_to_idx(&path_idx);
 					if (rc)
 						return rc;
 
-					curr_node_ptr->constituent_paths
-						[path_idx] = true;
+					curr_node_ptr->constituent_paths[path_idx] = true;
 				}
 
-				rc = cam_common_util_get_string_index(
-					soc_private->client_name,
-					soc_private->num_clients,
-					client_name, &client_idx);
+				rc = cam_common_util_get_string_index(soc_private->client_name,
+					soc_private->num_clients, client_name, &client_idx);
 				if (rc) {
-					CAM_ERR(CAM_CPAS,
-					"client name not found in list: %s",
-					client_name);
+					CAM_ERR(CAM_CPAS, "client name not found in list: %s",
+						client_name);
 					return rc;
 				}
 
 				if (client_idx >= CAM_CPAS_MAX_CLIENTS)
 					return -EINVAL;
 
-				curr_client =
-					cpas_core->cpas_client[client_idx];
+				curr_client = cpas_core->cpas_client[client_idx];
 				curr_client->tree_node_valid = true;
-				curr_client->tree_node
-					[curr_node_ptr->path_data_type]
-					[curr_node_ptr->path_trans_type] =
-					curr_node_ptr;
-				CAM_DBG(CAM_CPAS,
-					"CLIENT NODE ADDED: %d %d %s",
+				curr_client->tree_node[curr_node_ptr->path_data_type]
+					[curr_node_ptr->path_trans_type] = curr_node_ptr;
+
+				if (soc_private->enable_cam_ddr_drv) {
+					rc = of_property_read_u32(curr_node, "drv-voting-index",
+						&curr_node_ptr->drv_voting_idx);
+					if (curr_node_ptr->drv_voting_idx == CAM_CPAS_PORT_DRV_DYN)
+						curr_client->is_drv_dyn = true;
+
+					if (curr_client->is_drv_dyn &&
+						(curr_node_ptr->drv_voting_idx !=
+						CAM_CPAS_PORT_DRV_DYN))
+						CAM_ERR(CAM_CPAS,
+							"Invalid config for drv dyn client: %s drv_idx: %d",
+							client_name, curr_node_ptr->drv_voting_idx);
+				}
+
+				CAM_DBG(CAM_CPAS, "Client Node Added: %d %d %s %d",
 					curr_node_ptr->path_data_type,
-					curr_node_ptr->path_trans_type,
-					client_name);
+					curr_node_ptr->path_trans_type, client_name,
+					curr_node_ptr->drv_voting_idx);
 			}
 
-			parent_node = of_parse_phandle(curr_node,
-				"parent-node", 0);
+			if (soc_private->enable_cam_ddr_drv)
+				for (j = CAM_CPAS_PORT_DRV_0; j < num_drv_ports; j++)
+					curr_node_ptr->bw_info[j].vote_type =
+						CAM_CPAS_VOTE_TYPE_DRV;
+
+			parent_node = of_parse_phandle(curr_node, "parent-node", 0);
 			if (parent_node) {
-				of_property_read_u32(parent_node, "cell-index",
-					&cell_idx);
-				curr_node_ptr->parent_node =
-					soc_private->tree_node[cell_idx];
+				of_property_read_u32(parent_node, "cell-index", &cell_idx);
+				curr_node_ptr->parent_node = soc_private->tree_node[cell_idx];
 			} else {
-				CAM_DBG(CAM_CPAS,
-					"no parent node at this level");
+				CAM_DBG(CAM_CPAS, "no parent node at this level");
 			}
 		}
 	}
+
 	mutex_init(&cpas_core->tree_lock);
 	cam_cpas_util_debug_parse_data(soc_private);
 
@@ -807,6 +871,7 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 	struct device_node *of_node;
 	struct of_phandle_args src_args = {0}, dst_args = {0};
 	int count = 0, i = 0, rc = 0, num_bw_values = 0, num_levels = 0;
+	uint32_t cam_drv_en_mask_val = 0;
 	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 
 	if (!soc_private || !pdev) {
@@ -1120,6 +1185,10 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 		soc_private->smart_qos_info = NULL;
 	}
 
+	rc = of_property_read_u32(of_node, "enable-cam-drv", &cam_drv_en_mask_val);
+	if (cam_drv_en_mask_val & CAM_DDR_DRV)
+		soc_private->enable_cam_ddr_drv = true;
+
 	rc = cam_cpas_parse_node_tree(cpas_core, of_node, soc_private);
 	if (rc) {
 		CAM_ERR(CAM_CPAS, "Node tree parsing failed rc: %d", rc);

+ 9 - 22
drivers/cam_cpas/cam_cpas_soc.h

@@ -15,34 +15,21 @@
 #define CAM_CPAS_MAX_TREE_NODES 61
 #define CAM_CPAS_MAX_FUSE_FEATURE 10
 
-/**
- * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
- *
- * @vdd_corner : Voltage corner value
- * @ahb_level : AHB vote level corresponds to this vdd_corner
- *
- */
-struct cam_cpas_vdd_ahb_mapping {
-	unsigned int vdd_corner;
-	enum cam_vote_level ahb_level;
-};
-
 /**
  * struct cpas_tree_node: Generic cpas tree node for BW voting
  *
  * @cell_idx: Index to identify node from device tree and its parent
  * @level_idx: Index to identify at what level the node is present
- * @axi_port_idx: Index to identify which axi port to vote the consolidated bw
+ * @axi_port_idx_arr: Index to identify which axi port to vote the consolidated bw.
+ *                    It can point to multiple indexes in case of camera DRV
+ * @drv_voting_idx: Specifies the index to which the child node would finally vote.
  * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw
  * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc)
  * @path_trans_type: Transaction type info from device tree (rd, wr)
  * @merge_type: Traffic merge type (calculation info) from device tree
  * @bus_width_factor: Factor for accounting bus width in CAMNOC bw calculation
  * @camnoc_bw: CAMNOC bw value at current node
- * @mnoc_ab_bw: MNOC AB bw value at current node
- * @mnoc_ib_bw: MNOC IB bw value at current node
- * @ddr_ab_bw: DDR AB bw value at current node
- * @ddr_ib_bw: DDR IB bw value at current node
+ * @bw_info: AXI BW info for all drv ports
  * @camnoc_max_needed: If node is needed for CAMNOC BW calculation then true
  * @constituent_paths: Constituent paths presence info from device tree
  *     Ex: For CAM_CPAS_PATH_DATA_IFE_UBWC_STATS, index corresponding to
@@ -61,7 +48,8 @@ struct cam_cpas_vdd_ahb_mapping {
 struct cam_cpas_tree_node {
 	uint32_t cell_idx;
 	int level_idx;
-	int axi_port_idx;
+	int *axi_port_idx_arr;
+	int drv_voting_idx;
 	int camnoc_axi_port_idx;
 	const char *node_name;
 	uint32_t path_data_type;
@@ -69,10 +57,7 @@ struct cam_cpas_tree_node {
 	uint32_t merge_type;
 	uint32_t bus_width_factor;
 	uint64_t camnoc_bw;
-	uint64_t mnoc_ab_bw;
-	uint64_t mnoc_ib_bw;
-	uint64_t ddr_ab_bw;
-	uint64_t ddr_ib_bw;
+	struct cam_cpas_axi_bw_info *bw_info;
 	bool camnoc_max_needed;
 	bool constituent_paths[CAM_CPAS_PATH_DATA_MAX];
 	struct device_node *tree_dev_node;
@@ -163,6 +148,7 @@ struct cam_cpas_smart_qos_info {
  * @num_caches: Number of last level caches
  * @llcc_info: Cache info
  * @enable_smart_qos: Whether to enable Smart QoS mechanism on current chipset
+ * @enable_cam_ddr_drv: Whether to enable Camera DDR DRV on current chipset
  * @smart_qos_info: Pointer to smart qos info
  * @icp_clk_index: Index of optional icp clk
  */
@@ -188,6 +174,7 @@ struct cam_cpas_private_soc {
 	uint32_t num_caches;
 	struct cam_sys_cache_info *llcc_info;
 	bool enable_smart_qos;
+	bool enable_cam_ddr_drv;
 	struct cam_cpas_smart_qos_info *smart_qos_info;
 	int32_t icp_clk_index;
 };

+ 49 - 0
drivers/cam_cpas/include/cam_cpas_api.h

@@ -750,6 +750,19 @@ const char *cam_cpas_axi_util_path_type_to_string(
 const char *cam_cpas_axi_util_trans_type_to_string(
 	uint32_t path_data_type);
 
+/**
+ * cam_cpas_axi_util_drv_vote_lvl_to_string()
+ *
+ * @brief: API to get string for given DRV vote level
+ *
+ * @vote_lvl  : DRV vote level
+ *
+ * @return string.
+ *
+ */
+const char *cam_cpas_axi_util_drv_vote_lvl_to_string(
+	uint32_t vote_lvl);
+
 /**
  * cam_cpas_log_votes()
  *
@@ -838,4 +851,40 @@ int cam_cpas_deactivate_llcc(enum cam_sys_cache_config_types type);
  */
 int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle);
 
+/**
+ * cam_cpas_csid_input_core_info_update()
+ *
+ * @brief: API to communicate csid input core info to cpas
+ *
+ * @csid_idx: csid hw index connected to particular sfe
+ * @sfe_idx:  sfe idx to be connected to particular DRV path
+ * @set_port: Indicates whether to set or reset DRV port info in dynamic client
+ *
+ * @return 0 on success
+ *
+ */
+int cam_cpas_csid_input_core_info_update(int csid_idx, int sfe_idx, bool set_port);
+
+/**
+ * cam_cpas_csid_process_resume()
+ *
+ * @brief: API to process csid resume in cpas
+ * @csid_idx: CSID idx to notify resume for
+ *
+ * @return 0 on success
+ *
+ */
+int cam_cpas_csid_process_resume(uint32_t csid_idx);
+
+/**
+ * cam_cpas_query_drv_enable()
+ *
+ * @brief: API to indicate DRV enabled on hw or not
+ * @is_drv_enabled: Indication to be set by the API
+ *
+ * @return 0 on success
+ *
+ */
+int cam_cpas_query_drv_enable(bool *is_drv_enabled);
+
 #endif /* _CAM_CPAS_API_H_ */

+ 156 - 12
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -65,6 +65,9 @@ static struct cam_ife_hw_mgr g_ife_hw_mgr;
 static uint32_t g_num_ife, g_num_ife_lite, g_num_sfe;
 static uint32_t max_ife_out_res, max_sfe_out_res;
 
+static int cam_ife_mgr_find_core_idx(int split_id, struct cam_ife_hw_mgr_ctx *ctx,
+	enum cam_isp_hw_type hw_type, uint32_t *core_idx);
+
 static int cam_isp_blob_ife_clock_update(
 	struct cam_isp_clock_config           *clock_config,
 	struct cam_ife_hw_mgr_ctx             *ctx);
@@ -85,6 +88,88 @@ static int cam_ife_mgr_prog_default_settings(
 static int cam_ife_mgr_cmd_get_sof_timestamp(struct cam_ife_hw_mgr_ctx *ife_ctx,
 	uint64_t *time_stamp, uint64_t *boot_time_stamp, uint64_t *prev_time_stamp);
 
+static int cam_ife_mgr_update_core_info_to_cpas(struct cam_ife_hw_mgr_ctx           *ctx,
+	bool set_port)
+{
+	struct cam_isp_hw_mgr_res *hw_mgr_res;
+	int i, sfe_core_idx, csid_core_idx, rc = 0;
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			rc = cam_ife_mgr_find_core_idx(i, ctx, CAM_ISP_HW_TYPE_CSID,
+				&csid_core_idx);
+			if (rc)
+				return rc;
+
+			rc = cam_ife_mgr_find_core_idx(i, ctx, CAM_ISP_HW_TYPE_SFE, &sfe_core_idx);
+			if (rc)
+				return rc;
+
+			rc = cam_cpas_csid_input_core_info_update(csid_core_idx, sfe_core_idx,
+				set_port);
+			if (rc) {
+				CAM_ERR(CAM_PERF, "Failed in updating core info to cpas rc: %d",
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int cam_isp_blob_drv_config(struct cam_ife_hw_mgr_ctx         *ctx,
+	uint64_t request_id, struct cam_isp_prepare_hw_update_data *prepare_hw_data)
+{
+	struct cam_ife_hw_mgr                  *ife_hw_mgr;
+	struct cam_hw_intf                     *hw_intf;
+	struct cam_isp_drv_config              *drv_config;
+	struct cam_ife_csid_drv_config_args     drv_config_args = {0};
+	int i, rc = 0;
+
+	ife_hw_mgr = ctx->hw_mgr;
+	drv_config = &prepare_hw_data->isp_drv_config;
+
+	CAM_DBG(CAM_PERF,
+		"DRV config blob opcode:%u req_id:%llu disable_drv_override:%s ctx_idx:%u drv_en:%u path_idle_en:0x%x timeout_val:%u",
+		prepare_hw_data->packet_opcode_type, request_id,
+		CAM_BOOL_TO_YESNO(g_ife_hw_mgr.debug_cfg.disable_isp_drv),
+		ctx->ctx_index, drv_config->drv_en, drv_config->path_idle_en,
+		drv_config->timeout_val);
+
+	if (!g_ife_hw_mgr.cam_ddr_drv_support || g_ife_hw_mgr.debug_cfg.disable_isp_drv)
+		return rc;
+
+	if (prepare_hw_data->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV)
+		drv_config_args.is_init_config = true;
+
+	drv_config_args.drv_en = drv_config->drv_en;
+	drv_config_args.path_idle_en = drv_config->path_idle_en;
+	drv_config_args.timeout_val = drv_config->timeout_val;
+	for (i = 0; i < ctx->num_base; i++) {
+		if (ctx->base[i].hw_type != CAM_ISP_HW_TYPE_CSID)
+			continue;
+
+		hw_intf = ife_hw_mgr->csid_devices[ctx->base[i].idx];
+		if (hw_intf && hw_intf->hw_ops.process_cmd) {
+			rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
+				CAM_ISP_HW_CMD_DRV_CONFIG, &drv_config_args,
+				sizeof(struct cam_ife_csid_drv_config_args));
+			if (rc) {
+				CAM_ERR(CAM_PERF,
+					"DRV config failed req_id:%d i:%d hw_idx=%d rc:%d",
+					request_id, i, ctx->base[i].idx, rc);
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static bool cam_isp_is_ctx_primary_rdi(struct cam_ife_hw_mgr_ctx  *ctx)
 {
 	/* check for RDI only and RDI PD context*/
@@ -1807,6 +1892,7 @@ static int cam_ife_mgr_process_base_info(
 				res->hw_intf->hw_idx);
 		}
 	}
+
 	CAM_DBG(CAM_ISP, "ctx base num = %d", ctx->num_base);
 
 	return 0;
@@ -5190,6 +5276,12 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 		goto free_res;
 	}
 
+	if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
+		rc = cam_ife_mgr_update_core_info_to_cpas(ife_ctx, true);
+		if (rc)
+			goto free_res;
+	}
+
 	rc = cam_ife_mgr_allocate_cdm_cmd(
 		(ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE ? true : false),
 		&ife_ctx->cdm_cmd);
@@ -5526,6 +5618,12 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
 		goto free_res;
 	}
 
+	if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
+		rc = cam_ife_mgr_update_core_info_to_cpas(ife_ctx, true);
+		if (rc)
+			goto free_res;
+	}
+
 	rc = cam_ife_mgr_allocate_cdm_cmd(false,
 		&ife_ctx->cdm_cmd);
 	if (rc)
@@ -5843,13 +5941,15 @@ static int cam_isp_classify_vote_info(
 
 	for (i = 0; i < isp_vote->num_paths; i++) {
 		CAM_DBG(CAM_PERF,
-			"CLASSIFY_VOTE [%s] [%s] [%s] [%llu] [%llu] [%llu]",
+			"CLASSIFY_VOTE [%s] [%s] [%s] [%s] [%llu] [%llu] [%llu]",
 			cam_isp_util_usage_data_to_string(
 			isp_vote->axi_path[i].usage_data),
 			cam_cpas_axi_util_path_type_to_string(
 			isp_vote->axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			isp_vote->axi_path[i].transac_type),
+			cam_cpas_axi_util_drv_vote_lvl_to_string(
+			isp_vote->axi_path[i].vote_level),
 			isp_vote->axi_path[i].camnoc_bw,
 			isp_vote->axi_path[i].mnoc_ab_bw,
 			isp_vote->axi_path[i].mnoc_ib_bw);
@@ -5873,7 +5973,7 @@ static int cam_isp_blob_bw_update_v2(
 
 	for (i = 0; i < bw_config->num_paths; i++) {
 		CAM_DBG(CAM_PERF,
-			"ISP_BLOB usage_type=%u [%s] [%s] [%s] [%llu] [%llu] [%llu]",
+			"ISP_BLOB usage_type=%u [%s] [%s] [%s] [%s] [%llu] [%llu] [%llu]",
 			bw_config->usage_type,
 			cam_isp_util_usage_data_to_string(
 			bw_config->axi_path[i].usage_data),
@@ -5881,6 +5981,8 @@ static int cam_isp_blob_bw_update_v2(
 			bw_config->axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			bw_config->axi_path[i].transac_type),
+			cam_cpas_axi_util_drv_vote_lvl_to_string(
+			bw_config->axi_path[i].vote_level),
 			bw_config->axi_path[i].camnoc_bw,
 			bw_config->axi_path[i].mnoc_ab_bw,
 			bw_config->axi_path[i].mnoc_ib_bw);
@@ -6167,6 +6269,14 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
 		hw_update_data->bw_clk_config.ife_clock_config_valid,
 		hw_update_data->bw_clk_config.sfe_clock_config_valid);
 
+	if (hw_update_data->drv_config_valid) {
+		rc = cam_isp_blob_drv_config(ctx, cfg->request_id, hw_update_data);
+		if (rc) {
+			CAM_ERR(CAM_ISP, "DRV config failed for req: %llu rc:%d", cfg->request_id,
+				rc);
+		}
+	}
+
 	/*
 	 * Update clock and bw values to top layer, the actual application of these
 	 * votes to hw will happen for all relevant hw indices at once, in a separate
@@ -6780,29 +6890,27 @@ err:
 	return rc;
 }
 
-/* To find SFE core idx for CSID wrapper config */
-static int cam_ife_mgr_find_sfe_core_idx(
+static int cam_ife_mgr_find_core_idx(
 	int split_id,
 	struct cam_ife_hw_mgr_ctx *ctx,
+	enum cam_isp_hw_type hw_type,
 	uint32_t *core_idx)
 {
 	int i;
 
 	for (i = 0; i < ctx->num_base; i++) {
-		if (ctx->base[i].hw_type != CAM_ISP_HW_TYPE_SFE)
+		if (ctx->base[i].hw_type != hw_type)
 			continue;
 
 		if (ctx->base[i].split_id == split_id) {
-			CAM_DBG(CAM_ISP, "Found SFE core: %u for split_id: %d",
-				ctx->base[i].idx, split_id);
+			CAM_DBG(CAM_ISP, "Found core: %u for split_id: %d hw_type: %d",
+				ctx->base[i].idx, split_id, hw_type);
 			*core_idx = ctx->base[i].idx;
 			goto end;
 		}
 	}
 
-	CAM_ERR(CAM_ISP,
-		"Failed to find SFE core idx for split_id %d",
-		split_id);
+	CAM_ERR(CAM_ISP, "Failed to find core idx for hw_type: %d split_id %d", hw_type, split_id);
 	return -EINVAL;
 
 end:
@@ -6962,8 +7070,8 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
 				if (ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
 					csid_top_args.input_core_type =
 						CAM_IFE_CSID_INPUT_CORE_SFE_IFE;
-					rc = cam_ife_mgr_find_sfe_core_idx(
-						i, ctx, &csid_top_args.core_idx);
+					rc = cam_ife_mgr_find_core_idx(i, ctx, CAM_ISP_HW_TYPE_SFE,
+						&csid_top_args.core_idx);
 					if (rc)
 						goto tasklet_stop;
 				} else {
@@ -7035,6 +7143,12 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
 		goto safe_disable;
 	}
 
+	rc = cam_cpas_query_drv_enable(&g_ife_hw_mgr.cam_ddr_drv_support);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Failed to query DRV enable rc: %d", rc);
+		goto cdm_streamoff;
+	}
+
 start_only:
 
 	atomic_set(&ctx->overflow_pending, 0);
@@ -7270,6 +7384,12 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
 	/* we should called the stop hw before this already */
 	cam_ife_hw_mgr_release_hw_for_ctx(ctx);
 
+	if (ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
+		rc = cam_ife_mgr_update_core_info_to_cpas(ctx, false);
+		if (rc)
+			CAM_ERR(CAM_ISP, "Failed to update core info to cpas rc:%d", rc);
+	}
+
 	/* reset base info */
 	ctx->num_base = 0;
 	memset(ctx->base, 0, sizeof(ctx->base));
@@ -10209,6 +10329,28 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 
 	}
 		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_DRV_CONFIG: {
+		struct cam_isp_drv_config *drv_config;
+		struct cam_isp_prepare_hw_update_data   *prepare_hw_data;
+
+		if (blob_size < sizeof(struct cam_isp_drv_config)) {
+			CAM_ERR(CAM_ISP, "Invalid DRV blob size %u expected %u",
+				blob_size, sizeof(struct cam_isp_drv_config));
+			return -EINVAL;
+		}
+
+		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+			prepare->priv;
+		drv_config = (struct cam_isp_drv_config *)blob_data;
+		memcpy(&prepare_hw_data->isp_drv_config, drv_config,
+			sizeof(prepare_hw_data->isp_drv_config));
+
+		CAM_DBG(CAM_ISP, "DRV config blob en:%d timeout_val:%u path_idle_en: 0x%x",
+			drv_config->drv_en, drv_config->timeout_val, drv_config->path_idle_en);
+		prepare_hw_data->drv_config_valid = true;
+	}
+		break;
+
 	default:
 		CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
 		break;
@@ -14188,6 +14330,8 @@ static int cam_ife_hw_mgr_debug_register(void)
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_hw_mgr_perfcnter_debug);
 	debugfs_create_file("ife_csid_testbus", 0644,
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_csid_testbus_debug);
+	debugfs_create_bool("disable_isp_drv", 0644, g_ife_hw_mgr.debug_cfg.dentry,
+		&g_ife_hw_mgr.debug_cfg.disable_isp_drv);
 end:
 	g_ife_hw_mgr.debug_cfg.enable_csid_recovery = 1;
 	return rc;

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h

@@ -58,6 +58,7 @@ enum cam_ife_ctx_master_type {
  * @disable_ubwc_comp:         Disable UBWC compression
  * @disable_ife_mmu_prefetch:  Disable MMU prefetch for IFE bus WR
  * @rx_capture_debug_set:      If rx capture debug is set by user
+ * @disable_isp_drv:           Disable ISP DRV config
  *
  */
 struct cam_ife_hw_mgr_debug {
@@ -78,6 +79,7 @@ struct cam_ife_hw_mgr_debug {
 	bool           disable_ubwc_comp;
 	bool           disable_ife_mmu_prefetch;
 	bool           rx_capture_debug_set;
+	bool           disable_isp_drv;
 };
 
 /**
@@ -420,6 +422,7 @@ struct cam_isp_sfe_cache_info {
  * @csid_rup_en            Reg update at CSID side
  * @csid_global_reset_en   CSID global reset enable
  * @csid_camif_irq_support CSID camif IRQ support
+ * @cam_ddr_drv_support    DDR DRV support
  * @isp_caps               Capability of underlying SFE/IFE HW
  * @path_port_map          Mapping of outport to IFE mux
  * @num_caches_found       Number of caches supported
@@ -449,6 +452,7 @@ struct cam_ife_hw_mgr {
 	bool                             csid_rup_en;
 	bool                             csid_global_reset_en;
 	bool                             csid_camif_irq_support;
+	bool                             cam_ddr_drv_support;
 	struct cam_isp_ife_sfe_hw_caps   isp_caps;
 	struct cam_isp_hw_path_port_map  path_port_map;
 

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h

@@ -240,6 +240,8 @@ struct cam_isp_bw_clk_config_info {
  * @frame_header_iova:      Frame header iova
  * @frame_header_res_id:    Out port res_id corresponding to frame header
  * @bw_clk_config:          BW and clock config info
+ * @isp_drv_config:         DRV config info
+ * @bw_config_valid:        Flag indicating if DRV config is valid for current request
  * @reg_dump_buf_desc:     cmd buffer descriptors for reg dump
  * @num_reg_dump_buf:      Count of descriptors in reg_dump_buf_desc
  * @packet:                CSL packet from user mode driver
@@ -255,6 +257,8 @@ struct cam_isp_prepare_hw_update_data {
 	uint64_t                              frame_header_iova;
 	uint32_t                              frame_header_res_id;
 	struct cam_isp_bw_clk_config_info     bw_clk_config;
+	struct cam_isp_drv_config             isp_drv_config;
+	bool                                  drv_config_valid;
 	struct cam_cmd_buf_desc               reg_dump_buf_desc[
 						CAM_REG_DUMP_MAX_BUF_ENTRIES];
 	uint32_t                              num_reg_dump_buf;

+ 27 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid780.h

@@ -1241,6 +1241,9 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.buf_done_irq_set_addr                   = 0x98,
 	.test_bus_ctrl                           = 0x1E8,
 	.test_bus_debug                          = 0x1EC,
+	.drv_cfg0_addr                           = 0x13c,
+	.drv_cfg1_addr                           = 0x140,
+	.drv_cfg2_addr                           = 0x144,
 
 	/*configurations */
 	.major_version                           = 6,
@@ -1273,6 +1276,8 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.shdr_slave_rdi1_shift                   = 21,
 	.shdr_master_rdi0_shift                  = 5,
 	.shdr_master_slave_en_shift              = 0,
+	.drv_en_shift                            = 0,
+	.drv_rup_en_shift                        = 0,
 	.early_eof_supported                     = 1,
 	.vfr_supported                           = 1,
 	.multi_vcdt_supported                    = 1,
@@ -1312,6 +1317,28 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.timestamp_enabled_in_cfg0               = true,
 	.camif_irq_support                       = true,
 	.sfe_ipp_input_rdi_res                   = BIT(CAM_IFE_PIX_PATH_RES_RDI_0),
+	.drv_rup_en_val_map = {
+		2, //RDI0
+		3, //RDI1
+		4, //RDI2
+		5, //RDI3
+		6, //RDI4
+		0, //IPP
+		1, //PPP
+		0, //UDI0
+		0, //UDI1
+		0, //UDI2
+	},
+	.drv_path_idle_en_val_map = {
+		BIT(4), //CAM_ISP_PXL_PATH
+		BIT(5), //CAM_ISP_PPP_PATH
+		0,      // LCR not applicable
+		BIT(6), //CAM_ISP_RDI0_PATH
+		BIT(7), //CAM_ISP_RDI1_PATH
+		BIT(8), //CAM_ISP_RDI2_PATH
+		BIT(9), //CAM_ISP_RDI3_PATH
+		BIT(10), //CAM_ISP_RDI4_PATH
+	},
 };
 
 static struct cam_ife_csid_ver2_top_reg_info

+ 27 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid880.h

@@ -1280,6 +1280,9 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.test_bus_debug                          = 0x11EC,
 	.path_domain_id_cfg0                     = 0x0,
 	.path_domain_id_cfg1                     = 0x4,
+	.drv_cfg0_addr                           = 0x13c,
+	.drv_cfg1_addr                           = 0x140,
+	.drv_cfg2_addr                           = 0x144,
 
 	/*configurations */
 	.major_version                           = 6,
@@ -1312,6 +1315,8 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.shdr_slave_rdi1_shift                   = 21,
 	.shdr_master_rdi0_shift                  = 5,
 	.shdr_master_slave_en_shift              = 0,
+	.drv_en_shift                            = 0,
+	.drv_rup_en_shift                        = 0,
 	.early_eof_supported                     = 1,
 	.vfr_supported                           = 1,
 	.multi_vcdt_supported                    = 1,
@@ -1351,6 +1356,28 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.timestamp_enabled_in_cfg0               = true,
 	.sfe_ipp_input_rdi_res                   = BIT(CAM_IFE_PIX_PATH_RES_RDI_0),
 	.camif_irq_support                       = true,
+	.drv_rup_en_val_map = {
+		2, //RDI0
+		3, //RDI1
+		4, //RDI2
+		5, //RDI3
+		6, //RDI4
+		0, //IPP
+		1, //PPP
+		0, //UDI0
+		0, //UDI1
+		0, //UDI2
+	},
+	.drv_path_idle_en_val_map = {
+		BIT(4), //CAM_ISP_PXL_PATH
+		BIT(5), //CAM_ISP_PPP_PATH
+		0,      // LCR not applicable
+		BIT(6), //CAM_ISP_RDI0_PATH
+		BIT(7), //CAM_ISP_RDI1_PATH
+		BIT(8), //CAM_ISP_RDI2_PATH
+		BIT(9), //CAM_ISP_RDI3_PATH
+		BIT(10), //CAM_ISP_RDI4_PATH
+	},
 };
 
 static struct cam_ife_csid_ver2_top_reg_info

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c

@@ -3756,6 +3756,10 @@ static int cam_ife_csid_ver1_process_cmd(void *hw_priv,
 		/* Not supported for V1 */
 		rc = 0;
 		break;
+	case CAM_ISP_HW_CMD_DRV_CONFIG:
+		/* Not supported for V1 */
+		rc = 0;
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);

+ 77 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c

@@ -4415,6 +4415,15 @@ int cam_ife_csid_ver2_start(void *hw_priv, void *args,
 	csid_hw->flags.sof_irq_triggered = false;
 	csid_hw->counters.irq_debug_cnt = 0;
 
+	if (start_args->is_internal_start) {
+		rc = cam_cpas_csid_process_resume(csid_hw->hw_intf->hw_idx);
+		if (rc) {
+			CAM_ERR(CAM_ISP, "CSID:%u Failed to process resume rc: %d",
+				csid_hw->hw_intf->hw_idx, rc);
+			goto end;
+		}
+	}
+
 	rc = cam_ife_csid_ver2_enable_hw(csid_hw);
 
 	for (i = 0; i < start_args->num_res; i++) {
@@ -4690,7 +4699,6 @@ static int cam_ife_csid_ver2_top_cfg(
 		hw_idx, top_args->input_core_type, top_args->core_idx);
 
 	/*config dual sync params */
-
 	if (csid_hw->sync_mode == CAM_ISP_HW_SYNC_NONE)
 		return rc;
 	else if (csid_hw->sync_mode == CAM_ISP_HW_SYNC_MASTER)
@@ -5378,6 +5386,71 @@ static int cam_ife_csid_init_config_update(
 	return 0;
 }
 
+static int cam_ife_csid_ver2_drv_config(
+	struct cam_ife_csid_ver2_hw  *csid_hw, void *cmd_args)
+{
+	struct cam_hw_soc_info *soc_info;
+	struct cam_ife_csid_ver2_reg_info *csid_reg;
+	struct cam_ife_csid_drv_config_args *drv_config;
+	uint32_t cfg0_val = 0, cfg1_val = 0;
+	void __iomem *mem_base;
+	int i;
+
+	if (!csid_hw || !cmd_args) {
+		CAM_ERR(CAM_ISP, "Invalid params");
+		return -EINVAL;
+	}
+
+	drv_config = (struct cam_ife_csid_drv_config_args *) cmd_args;
+	soc_info = &csid_hw->hw_info->soc_info;
+	csid_reg = (struct cam_ife_csid_ver2_reg_info *) csid_hw->core_info->csid_reg;
+	mem_base = soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base;
+
+	cfg0_val = drv_config->drv_en << csid_reg->cmn_reg->drv_en_shift;
+
+	/* Configure DRV RUP EN for init request, one time */
+	if (drv_config->is_init_config) {
+		if (csid_hw->path_res[CAM_IFE_PIX_PATH_RES_IPP].res_state >=
+			CAM_ISP_RESOURCE_STATE_RESERVED) {
+			cfg1_val = csid_reg->cmn_reg->drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_IPP];
+		} else if (csid_hw->path_res[CAM_IFE_PIX_PATH_RES_RDI_0].res_state >=
+			CAM_ISP_RESOURCE_STATE_RESERVED) {
+			cfg1_val =
+				csid_reg->cmn_reg->drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_RDI_0];
+		} else if (csid_hw->path_res[CAM_IFE_PIX_PATH_RES_PPP].res_state >=
+			CAM_ISP_RESOURCE_STATE_RESERVED) {
+			cfg1_val = csid_reg->cmn_reg->drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_PPP];
+		} else {
+			CAM_ERR(CAM_ISP, "Failed to configure rup_en for drv");
+			return -EINVAL;
+		}
+
+		cam_io_w_mb(cfg1_val, mem_base + csid_reg->cmn_reg->drv_cfg1_addr);
+		csid_hw->drv_init_done = true;
+	}
+
+	if (!csid_hw->drv_init_done) {
+		CAM_ERR(CAM_ISP, "Failed to update drv config, init config not done");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_ISP_MAX_PATHS; i++)
+		cfg0_val |= ((drv_config->path_idle_en & BIT(i)) ?
+			csid_reg->cmn_reg->drv_path_idle_en_val_map[i] : 0);
+
+	cam_io_w_mb(cfg0_val, mem_base + csid_reg->cmn_reg->drv_cfg0_addr);
+
+	cam_io_w_mb(drv_config->timeout_val, mem_base + csid_reg->cmn_reg->drv_cfg2_addr);
+
+	CAM_DBG(CAM_ISP,
+		"CSID[%u] sfe_en:%s DRV config init_req:%s cfg0_val:0x%x cfg1_val:0x%x cfg2_val:0x%x",
+		csid_hw->hw_intf->hw_idx, CAM_BOOL_TO_YESNO(csid_hw->flags.sfe_en),
+		CAM_BOOL_TO_YESNO(drv_config->is_init_config), cfg0_val, cfg1_val,
+		drv_config->timeout_val);
+
+	return 0;
+}
+
 static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
 {
@@ -5468,6 +5541,9 @@ static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 	case CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE:
 		rc = cam_ife_csid_init_config_update(cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_DRV_CONFIG:
+		rc = cam_ife_csid_ver2_drv_config(csid_hw, cmd_args);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);

+ 9 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h

@@ -379,6 +379,9 @@ struct cam_ife_csid_ver2_common_reg_info {
 	uint32_t test_bus_debug;
 	uint32_t path_domain_id_cfg0;
 	uint32_t path_domain_id_cfg1;
+	uint32_t drv_cfg0_addr;
+	uint32_t drv_cfg1_addr;
+	uint32_t drv_cfg2_addr;
 
 	/*Shift Bit Configurations*/
 	uint32_t rst_done_shift_val;
@@ -437,6 +440,8 @@ struct cam_ife_csid_ver2_common_reg_info {
 	uint32_t shdr_slave_rdi1_shift;
 	uint32_t shdr_master_rdi0_shift;
 	uint32_t shdr_master_slave_en_shift;
+	uint32_t drv_en_shift;
+	uint32_t drv_rup_en_shift;
 	/* config Values */
 	uint32_t major_version;
 	uint32_t minor_version;
@@ -466,6 +471,8 @@ struct cam_ife_csid_ver2_common_reg_info {
 	uint32_t sfe_ipp_input_rdi_res;
 	bool     timestamp_enabled_in_cfg0;
 	bool     camif_irq_support;
+	uint32_t drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_MAX];
+	uint32_t drv_path_idle_en_val_map[CAM_ISP_MAX_PATHS];
 
 	/* Masks */
 	uint32_t pxl_cnt_mask;
@@ -554,6 +561,7 @@ struct cam_ife_csid_ver2_reg_info {
  * @sync_mode:                Master/Slave modes
  * @mup:                      MUP for incoming VC of next frame
  * @discard_frame_per_path:   Count of paths dropping initial frames
+ * @drv_init_done:            Indicates if drv init config is done
  *
  */
 struct cam_ife_csid_ver2_hw {
@@ -596,6 +604,7 @@ struct cam_ife_csid_ver2_hw {
 	enum cam_isp_hw_sync_mode              sync_mode;
 	uint32_t                               mup;
 	atomic_t                               discard_frame_per_path;
+	bool                                   drv_init_done;
 };
 
 /*

+ 16 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -14,6 +14,7 @@
 #define CAM_IFE_CSID_HW_NUM_MAX                        8
 #define CAM_IFE_CSID_UDI_MAX                           3
 #define RT_BASE_IDX                                    2
+#define CAM_ISP_MAX_PATHS                              8
 
 /**
  * enum cam_ife_csid_input_core_type - Specify the csid input core
@@ -480,4 +481,19 @@ struct cam_ife_csid_debug_cfg_args {
 	bool                              rx_capture_debug_set;
 };
 
+/*
+ * struct cam_ife_csid_drv_config_args:
+ *
+ * @is_init_config: Indicator for init config
+ * @drv_en:         Indicator for camera DRV enable
+ * @timeout_val:    Timeout value from SOF to trigger up vote, given in number of GC cycles
+ * @path_idle_en:   Mask for paths to be considered for consolidated IDLE
+ */
+struct cam_ife_csid_drv_config_args {
+	bool                               is_init_config;
+	bool                               drv_en;
+	uint32_t                           timeout_val;
+	uint32_t                           path_idle_en;
+};
+
 #endif /* _CAM_CSID_HW_INTF_H_ */

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -216,6 +216,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_BUS_MINI_DUMP,
 	CAM_ISP_HW_USER_DUMP,
 	CAM_ISP_HW_CMD_RDI_LCR_CFG,
+	CAM_ISP_HW_CMD_DRV_CONFIG,
 	CAM_ISP_HW_CMD_MAX,
 };
 

+ 39 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c

@@ -114,6 +114,7 @@ static int cam_sfe_top_set_axi_bw_vote(
 	int rc = 0;
 	struct cam_hw_soc_info        *soc_info = NULL;
 	struct cam_sfe_soc_private    *soc_private = NULL;
+	int i, j;
 
 	soc_info = top_priv->common_data.soc_info;
 	soc_private = (struct cam_sfe_soc_private *)soc_info->soc_private;
@@ -131,6 +132,38 @@ static int cam_sfe_top_set_axi_bw_vote(
 		top_priv->total_bw_applied = total_bw_new_vote;
 	} else {
 		CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc);
+		for (i = 0; i < final_bw_vote->num_paths; i++) {
+			CAM_INFO(CAM_PERF,
+				"sfe[%d] : Applied BW Vote : [%s][%s][%s] [%llu %llu %llu]",
+				top_priv->common_data.hw_intf->hw_idx,
+				cam_cpas_axi_util_path_type_to_string(
+				final_bw_vote->axi_path[i].path_data_type),
+				cam_cpas_axi_util_trans_type_to_string(
+				final_bw_vote->axi_path[i].transac_type),
+				cam_cpas_axi_util_drv_vote_lvl_to_string(
+				final_bw_vote->axi_path[i].vote_level),
+				final_bw_vote->axi_path[i].camnoc_bw,
+				final_bw_vote->axi_path[i].mnoc_ab_bw,
+				final_bw_vote->axi_path[i].mnoc_ib_bw);
+		}
+
+		for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
+			for (j = 0; j < top_priv->last_bw_vote[i].num_paths; j++) {
+				CAM_INFO(CAM_PERF,
+					"sfe[%d] : History[%d] BW Vote : [%s][%s] [%s] [%llu %llu %llu]",
+					top_priv->common_data.hw_intf->hw_idx, i,
+					cam_cpas_axi_util_path_type_to_string(
+					top_priv->last_bw_vote[i].axi_path[j].path_data_type),
+					cam_cpas_axi_util_trans_type_to_string(
+					top_priv->last_bw_vote[i].axi_path[j].transac_type),
+					cam_cpas_axi_util_drv_vote_lvl_to_string(
+					top_priv->last_bw_vote[i].axi_path[j].vote_level),
+					top_priv->last_bw_vote[i].axi_path[j].camnoc_bw,
+					top_priv->last_bw_vote[i].axi_path[j].mnoc_ab_bw,
+					top_priv->last_bw_vote[i].axi_path[j].mnoc_ib_bw);
+			}
+		}
+
 	}
 
 	return rc;
@@ -399,13 +432,15 @@ int cam_sfe_top_calc_axi_bw_vote(struct cam_sfe_top_priv *top_priv,
 
 	for (i = 0; i < top_priv->agg_incoming_vote.num_paths; i++) {
 		CAM_DBG(CAM_PERF,
-			"sfe[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
+			"sfe[%d] : New BW Vote : counter[%d] [%s][%s][%s] [%llu %llu %llu]",
 			top_priv->common_data.hw_intf->hw_idx,
 			top_priv->last_bw_counter,
 			cam_cpas_axi_util_path_type_to_string(
 			top_priv->agg_incoming_vote.axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			top_priv->agg_incoming_vote.axi_path[i].transac_type),
+			cam_cpas_axi_util_drv_vote_lvl_to_string(
+			top_priv->agg_incoming_vote.axi_path[i].vote_level),
 			top_priv->agg_incoming_vote.axi_path[i].camnoc_bw,
 			top_priv->agg_incoming_vote.axi_path[i].mnoc_ab_bw,
 			top_priv->agg_incoming_vote.axi_path[i].mnoc_ib_bw);
@@ -463,12 +498,14 @@ int cam_sfe_top_calc_axi_bw_vote(struct cam_sfe_top_priv *top_priv,
 
 	for (i = 0; i < final_bw_vote->num_paths; i++) {
 		CAM_DBG(CAM_PERF,
-			"sfe[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
+			"sfe[%d] : Apply BW Vote : [%s][%s][%s] [%llu %llu %llu]",
 			top_priv->common_data.hw_intf->hw_idx,
 			cam_cpas_axi_util_path_type_to_string(
 			final_bw_vote->axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			final_bw_vote->axi_path[i].transac_type),
+			cam_cpas_axi_util_drv_vote_lvl_to_string(
+			final_bw_vote->axi_path[i].vote_level),
 			final_bw_vote->axi_path[i].camnoc_bw,
 			final_bw_vote->axi_path[i].mnoc_ab_bw,
 			final_bw_vote->axi_path[i].mnoc_ib_bw);

+ 7 - 7
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/slab.h>
@@ -186,6 +187,7 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
 	cpas_register_param.dev = soc_info->dev;
 	cpas_register_param.cam_cpas_client_cb = cam_vfe_cpas_cb;
 	cpas_register_param.userdata = soc_info;
+
 	rc = cam_cpas_register_client(&cpas_register_param);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc);
@@ -252,18 +254,16 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
 		rc = -EINVAL;
 		goto end;
 	}
-	soc_private = soc_info->soc_private;
 
+	soc_private = soc_info->soc_private;
 	ahb_vote.type       = CAM_VOTE_ABSOLUTE;
 	ahb_vote.vote.level = CAM_LOWSVS_VOTE;
 	axi_vote.num_paths = 1;
-	if (strnstr(soc_info->compatible, "lite",
-		strlen(soc_info->compatible))) {
-		axi_vote.axi_path[0].path_data_type =
-			CAM_AXI_PATH_DATA_IFE_RDI1;
+	if (soc_private->is_ife_lite) {
+		axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_IFE_RDI1;
 	} else {
-		axi_vote.axi_path[0].path_data_type =
-			CAM_AXI_PATH_DATA_IFE_VID;
+		axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_IFE_VID;
+		axi_vote.axi_path[0].vote_level = CAM_CPAS_VOTE_LEVEL_LOW;
 	}
 
 	axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE;

+ 12 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c

@@ -49,12 +49,14 @@ static int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_top_priv_common *top_commo
 			final_bw_vote->num_paths, rc);
 		for (i = 0; i < final_bw_vote->num_paths; i++) {
 			CAM_INFO(CAM_PERF,
-				"ife[%d] : Applied BW Vote : [%s][%s] [%llu %llu %llu]",
+				"ife[%d] : Applied BW Vote : [%s][%s][%s] [%llu %llu %llu]",
 				top_common->hw_idx,
 				cam_cpas_axi_util_path_type_to_string(
 				final_bw_vote->axi_path[i].path_data_type),
 				cam_cpas_axi_util_trans_type_to_string(
 				final_bw_vote->axi_path[i].transac_type),
+				cam_cpas_axi_util_drv_vote_lvl_to_string(
+				final_bw_vote->axi_path[i].vote_level),
 				final_bw_vote->axi_path[i].camnoc_bw,
 				final_bw_vote->axi_path[i].mnoc_ab_bw,
 				final_bw_vote->axi_path[i].mnoc_ib_bw);
@@ -63,12 +65,14 @@ static int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_top_priv_common *top_commo
 		for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
 			for (j = 0; j < top_common->last_bw_vote[i].num_paths; j++) {
 				CAM_INFO(CAM_PERF,
-					"ife[%d] : History[%d] BW Vote : [%s][%s] [%llu %llu %llu]",
+					"ife[%d] : History[%d] BW Vote : [%s][%s] [%s] [%llu %llu %llu]",
 					top_common->hw_idx, i,
 					cam_cpas_axi_util_path_type_to_string(
 					top_common->last_bw_vote[i].axi_path[j].path_data_type),
 					cam_cpas_axi_util_trans_type_to_string(
 					top_common->last_bw_vote[i].axi_path[j].transac_type),
+					cam_cpas_axi_util_drv_vote_lvl_to_string(
+					top_common->last_bw_vote[i].axi_path[j].vote_level),
 					top_common->last_bw_vote[i].axi_path[j].camnoc_bw,
 					top_common->last_bw_vote[i].axi_path[j].mnoc_ab_bw,
 					top_common->last_bw_vote[i].axi_path[j].mnoc_ib_bw);
@@ -294,13 +298,15 @@ static int cam_vfe_top_calc_axi_bw_vote(
 
 	for (i = 0; i < top_common->agg_incoming_vote.num_paths; i++) {
 		CAM_DBG(CAM_PERF,
-			"ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
+			"ife[%d] : New BW Vote : counter[%d] [%s][%s][%s] [%llu %llu %llu]",
 			top_common->hw_idx,
 			top_common->last_bw_counter,
 			cam_cpas_axi_util_path_type_to_string(
 			top_common->agg_incoming_vote.axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			top_common->agg_incoming_vote.axi_path[i].transac_type),
+			cam_cpas_axi_util_drv_vote_lvl_to_string(
+			top_common->agg_incoming_vote.axi_path[i].vote_level),
 			top_common->agg_incoming_vote.axi_path[i].camnoc_bw,
 			top_common->agg_incoming_vote.axi_path[i].mnoc_ab_bw,
 			top_common->agg_incoming_vote.axi_path[i].mnoc_ib_bw);
@@ -360,12 +366,14 @@ static int cam_vfe_top_calc_axi_bw_vote(
 
 	for (i = 0; i < final_bw_vote->num_paths; i++) {
 		CAM_DBG(CAM_PERF,
-			"ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
+			"ife[%d] : Apply BW Vote : [%s][%s][%s] [%llu %llu %llu]",
 			top_common->hw_idx,
 			cam_cpas_axi_util_path_type_to_string(
 			final_bw_vote->axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			final_bw_vote->axi_path[i].transac_type),
+			cam_cpas_axi_util_drv_vote_lvl_to_string(
+			final_bw_vote->axi_path[i].vote_level),
 			final_bw_vote->axi_path[i].camnoc_bw,
 			final_bw_vote->axi_path[i].mnoc_ab_bw,
 			final_bw_vote->axi_path[i].mnoc_ib_bw);

+ 96 - 0
drivers/cam_utils/cam_compat.c

@@ -9,11 +9,107 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 
+#include <soc/qcom/rpmh.h>
+
 #include "cam_compat.h"
 #include "cam_debug_util.h"
 #include "cam_cpas_api.h"
 #include "camera_main.h"
 
+#if IS_ENABLED(CONFIG_USE_RPMH_DRV_API)
+#define CAM_RSC_DRV_IDENTIFIER "cam_rsc"
+
+const struct device *cam_cpas_get_rsc_dev_for_drv(uint32_t index)
+{
+	const struct device *rsc_dev;
+
+	rsc_dev = rpmh_get_device(CAM_RSC_DRV_IDENTIFIER, index);
+	if (!rsc_dev) {
+		CAM_ERR(CAM_CPAS, "Invalid dev for index: %u", index);
+		return NULL;
+	}
+
+	return rsc_dev;
+}
+
+int cam_cpas_start_drv_for_dev(const struct device *dev)
+{
+	int rc = 0;
+
+	if (!dev) {
+		CAM_ERR(CAM_CPAS, "Invalid dev for DRV enable");
+		return -EINVAL;
+	}
+
+	rc = rpmh_drv_start(dev);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "[%s] Failed in DRV start", dev_name(dev));
+		return rc;
+	}
+
+	return rc;
+}
+
+int cam_cpas_stop_drv_for_dev(const struct device *dev)
+{
+	int rc = 0;
+
+	if (!dev) {
+		CAM_ERR(CAM_CPAS, "Invalid dev for DRV disable");
+		return -EINVAL;
+	}
+
+	rc = rpmh_drv_stop(dev);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "[%s] Failed in DRV stop", dev_name(dev));
+		return rc;
+	}
+
+	return rc;
+}
+
+int cam_cpas_drv_channel_switch_for_dev(const struct device *dev)
+{
+	int rc = 0;
+
+	if (!dev) {
+		CAM_ERR(CAM_CPAS, "Invalid dev for DRV channel switch");
+		return -EINVAL;
+	}
+
+	rc = rpmh_write_sleep_and_wake_no_child(dev);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "[%s] Failed in DRV channel switch", dev_name(dev));
+		return rc;
+	}
+
+	return rc;
+}
+
+#else
+const struct device *cam_cpas_get_rsc_dev_for_drv(uint32_t index)
+{
+	return NULL;
+}
+
+int cam_cpas_start_drv_for_dev(const struct device *dev)
+
+{
+	return 0;
+}
+
+int cam_cpas_stop_drv_for_dev(const struct device *dev)
+{
+	return 0;
+}
+
+int cam_cpas_drv_channel_switch_for_dev(const struct device *dev)
+{
+	return 0;
+}
+#endif
+
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
 int cam_reserve_icp_fw(struct cam_fw_alloc_info *icp_fw, size_t fw_length)
 {

+ 8 - 0
drivers/cam_utils/cam_compat.h

@@ -55,6 +55,14 @@ void cam_compat_util_put_dmabuf_va(struct dma_buf *dmabuf, void *vaddr);
 void cam_smmu_util_iommu_custom(struct device *dev,
 	dma_addr_t discard_start, size_t discard_length);
 
+const struct device *cam_cpas_get_rsc_dev_for_drv(uint32_t index);
+
+int cam_cpas_start_drv_for_dev(const struct device *dev);
+
+int cam_cpas_stop_drv_for_dev(const struct device *dev);
+
+int cam_cpas_drv_channel_switch_for_dev(const struct device *dev);
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
 int cam_req_mgr_ordered_list_cmp(void *priv,
 	const struct list_head *head_1, const struct list_head *head_2);

+ 3 - 1
drivers/cam_utils/cam_soc_bus.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/msm-bus.h>
@@ -65,7 +66,8 @@ end:
 	return rc;
 }
 
-int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
+int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib,
+	enum cam_soc_bus_path_data bus_path_data)
 {
 	int idx = 0;
 	struct msm_bus_paths *path;

+ 23 - 4
drivers/cam_utils/cam_soc_bus.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SOC_BUS_H_
@@ -10,9 +11,17 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include "cam_debug_util.h"
+#include "cam_cpas.h"
 
 #define CAM_SOC_BUS_MAX_NUM_USECASES 8
 
+enum cam_soc_bus_path_data {
+	CAM_SOC_BUS_PATH_DATA_HLOS,
+	CAM_SOC_BUS_PATH_DATA_DRV_HIGH,
+	CAM_SOC_BUS_PATH_DATA_DRV_LOW,
+	CAM_SOC_BUS_PATH_DATA_MAX,
+};
+
 /**
  * struct cam_soc_bus_client_ab_ib : Bandwidth values for selected usecase
  *
@@ -30,6 +39,7 @@ struct cam_soc_bus_client_ab_ib {
  * @name: Name of bus client
  * @src_id: Bus master/src id
  * @dst_id: Bus slave/dst id
+ * @is_drv_port: If DRV bus client
  * @num_usecases: Number of use cases for this client
  * @bw_pair: Bandwidth values for applicable usecases
  */
@@ -37,6 +47,7 @@ struct cam_soc_bus_client_common_data {
 	const char *name;
 	uint32_t src_id;
 	uint32_t dst_id;
+	bool is_drv_port;
 	int num_usecases;
 	struct cam_soc_bus_client_ab_ib bw_pair[CAM_SOC_BUS_MAX_NUM_USECASES];
 };
@@ -56,10 +67,12 @@ struct cam_soc_bus_client {
 #if IS_REACHABLE(CONFIG_QCOM_BUS_SCALING) || \
 	IS_REACHABLE(CONFIG_INTERCONNECT_QCOM)
 
+const char *cam_soc_bus_path_data_to_str(enum cam_soc_bus_path_data bus_path_data);
+
 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_update_bw(void *client, uint64_t ab, uint64_t ib,
+	enum cam_soc_bus_path_data bus_path_data);
 
 int cam_soc_bus_client_register(struct platform_device *pdev,
 	struct device_node *dev_node, void **client,
@@ -68,14 +81,20 @@ int cam_soc_bus_client_register(struct platform_device *pdev,
 void cam_soc_bus_client_unregister(void **client);
 
 #else
+
+static const char *cam_soc_bus_path_data_to_str(enum cam_soc_bus_path_data bus_path_data)
+{
+	return NULL;
+}
+
 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)
+int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib,
+	enum cam_soc_bus_path_data bus_path_data)
 {
 	return 0;
 }

+ 111 - 38
drivers/cam_utils/cam_soc_icc.c

@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/interconnect.h>
+#include <dt-bindings/interconnect/qcom,icc.h>
 #include "cam_soc_bus.h"
 
 /**
@@ -12,9 +14,22 @@
  * @icc_data: Bus icc path information
  */
 struct cam_soc_bus_client_data {
-	struct icc_path *icc_data;
+	struct icc_path *icc_data[CAM_SOC_BUS_PATH_DATA_MAX];
 };
 
+const char *cam_soc_bus_path_data_to_str(enum cam_soc_bus_path_data bus_path_data)
+{
+	switch (bus_path_data) {
+	case CAM_SOC_BUS_PATH_DATA_HLOS:
+		return "BUS_PATH_HLOS";
+	case CAM_SOC_BUS_PATH_DATA_DRV_HIGH:
+		return "BUS_PATH_DRV_HIGH";
+	case CAM_SOC_BUS_PATH_DATA_DRV_LOW:
+		return "BUS_PATH_DRV_LOW";
+	default:
+		return "BUS_PATH_INVALID";
+	}
+}
 int cam_soc_bus_client_update_request(void *client, unsigned int idx)
 {
 	int rc = 0;
@@ -37,7 +52,7 @@ int cam_soc_bus_client_update_request(void *client, unsigned int idx)
 	CAM_DBG(CAM_PERF, "Bus client=[%s] index[%d] ab[%llu] ib[%llu]",
 		bus_client->common_data->name, idx, ab, ib);
 
-	rc = icc_set_bw(bus_client_data->icc_data, Bps_to_icc(ab),
+	rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS], Bps_to_icc(ab),
 		Bps_to_icc(ib));
 	if (rc) {
 		CAM_ERR(CAM_UTIL,
@@ -50,26 +65,29 @@ end:
 	return rc;
 }
 
-int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
+int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib,
+	enum cam_soc_bus_path_data bus_path_data)
 {
-	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_PERF, "Bus client=[%s] :ab[%llu] ib[%llu]",
-		bus_client->common_data->name, ab, ib);
-	rc = icc_set_bw(bus_client_data->icc_data, Bps_to_icc(ab),
-		Bps_to_icc(ib));
-	if (rc) {
-		CAM_ERR(CAM_UTIL, "Update request failed, client[%s]",
-			bus_client->common_data->name);
-		goto end;
-	}
+		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_PERF, "Bus client=[%s] [%s] :ab[%llu] ib[%llu]",
+			bus_client->common_data->name, cam_soc_bus_path_data_to_str(bus_path_data),
+			ab, ib);
+		rc = icc_set_bw(bus_client_data->icc_data[bus_path_data], Bps_to_icc(ab),
+			Bps_to_icc(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,
@@ -89,8 +107,7 @@ int cam_soc_bus_client_register(struct platform_device *pdev,
 
 	*client = bus_client;
 
-	bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data),
-		GFP_KERNEL);
+	bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data), GFP_KERNEL);
 	if (!bus_client_data) {
 		kfree(bus_client);
 		*client = NULL;
@@ -100,30 +117,80 @@ int cam_soc_bus_client_register(struct platform_device *pdev,
 
 	bus_client->client_data = bus_client_data;
 	bus_client->common_data = common_data;
-	bus_client_data->icc_data = icc_get(&pdev->dev,
-		bus_client->common_data->src_id,
-		bus_client->common_data->dst_id);
-	if (IS_ERR_OR_NULL(bus_client_data->icc_data)) {
-		CAM_ERR(CAM_UTIL, "failed in register bus client");
-		rc = -EINVAL;
-		goto error;
+	if (bus_client->common_data->is_drv_port) {
+		bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH] = icc_get(&pdev->dev,
+			bus_client->common_data->src_id, bus_client->common_data->dst_id);
+		if (IS_ERR_OR_NULL(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH])) {
+			CAM_ERR(CAM_UTIL,
+				"Failed to register DRV bus client Bus Client=[%s] : src=%d, dst=%d bus_path:%d",
+				bus_client->common_data->src_id, bus_client->common_data->dst_id,
+				CAM_SOC_BUS_PATH_DATA_DRV_HIGH);
+			rc = -EINVAL;
+			goto error;
+		}
+
+		bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW] = icc_get(&pdev->dev,
+			bus_client->common_data->src_id, bus_client->common_data->dst_id);
+		if (IS_ERR_OR_NULL(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW])) {
+			CAM_ERR(CAM_UTIL,
+				"Failed to register DRV bus client Bus Client=[%s] : src=%d, dst=%d bus_path:%d",
+				bus_client->common_data->src_id, bus_client->common_data->dst_id,
+				CAM_SOC_BUS_PATH_DATA_DRV_LOW);
+			rc = -EINVAL;
+			goto error;
+		}
+
+		/* Set appropriate tags for HIGH and LOW vote paths */
+		icc_set_tag(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH],
+			QCOM_ICC_TAG_ACTIVE_ONLY);
+		icc_set_tag(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW],
+			QCOM_ICC_TAG_SLEEP);
+
+		rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH], 0, 0);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Bus client[%s] update request failed, rc = %d",
+				bus_client->common_data->name, rc);
+			goto fail_unregister_client;
+		}
+
+		rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW], 0, 0);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Bus client[%s] update request failed, rc = %d",
+				bus_client->common_data->name, rc);
+			goto fail_unregister_client;
+		}
+	} else {
+		bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS] = icc_get(&pdev->dev,
+			bus_client->common_data->src_id, bus_client->common_data->dst_id);
+		if (IS_ERR_OR_NULL(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS])) {
+			CAM_ERR(CAM_UTIL, "failed to register HLOS bus client");
+			rc = -EINVAL;
+			goto error;
+		}
+
+		rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS], 0, 0);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Bus client[%s] update request failed, rc = %d",
+				bus_client->common_data->name, rc);
+			goto fail_unregister_client;
+		}
 	}
 
-	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_PERF, "Register Bus Client=[%s] : src=%d, dst=%d",
+	CAM_DBG(CAM_PERF, "Register Bus Client=[%s] : src=%d, dst=%d is_drv_port:%s",
 		bus_client->common_data->name, bus_client->common_data->src_id,
-		bus_client->common_data->dst_id);
+		bus_client->common_data->dst_id,
+		CAM_BOOL_TO_YESNO(bus_client->common_data->is_drv_port));
 
 	return 0;
 
 fail_unregister_client:
-	icc_put(bus_client_data->icc_data);
+	if (bus_client->common_data->is_drv_port) {
+		icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH]);
+		icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW]);
+	} else {
+		icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS]);
+	}
+
 error:
 	kfree(bus_client_data);
 	bus_client->client_data = NULL;
@@ -141,7 +208,13 @@ void cam_soc_bus_client_unregister(void **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);
+	if (bus_client->common_data->is_drv_port) {
+		icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH]);
+		icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW]);
+	} else {
+		icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS]);
+	}
+
 	kfree(bus_client_data);
 	bus_client->client_data = NULL;
 	kfree(bus_client);

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff