Ver código fonte

msm: camera: isp: Improve IFE/SFE/CSID debug infra

Add support to enable SFE/IFE perf counters by allowing
user to configure the counters. By default the counter
values are dumped at EOF.

To configure the counter-
adb shell cat /sys/kernel/debug/camera/ife/isp_perf_counters
adb shell "echo "ife_1_2162693" >
 /sys/kernel/debug/camera/ife/isp_perf_counters"

A read on the debugfs file will list the available counters
on the target for the different HW blocks.

The change also adds support to configure CSID test bus.
adb shell "echo <reg_val> >
 /sys/kernel/debug/camera/ife/ife_csid_testbus".

CRs-Fixed: 3110947
Change-Id: Idc3952e64c943acd1d1893ed24eea88cf9908100
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 3 anos atrás
pai
commit
d557934178
24 arquivos alterados com 695 adições e 132 exclusões
  1. 192 35
      drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
  2. 14 3
      drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
  3. 3 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid680.h
  4. 2 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid780.h
  5. 4 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.h
  6. 47 7
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c
  7. 2 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h
  8. 2 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
  9. 8 5
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
  10. 11 5
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h
  11. 17 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
  12. 20 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h
  13. 20 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe780.h
  14. 12 1
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c
  15. 3 3
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c
  16. 139 51
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c
  17. 14 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h
  18. 12 2
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
  19. 20 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe680.h
  20. 20 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe780.h
  21. 4 3
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
  22. 10 5
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c
  23. 105 12
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c
  24. 14 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.h

+ 192 - 35
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -3799,7 +3799,7 @@ static int cam_ife_mgr_check_and_update_fe_v2(
 		}
 
 		if ((in_port->num_out_res > (max_ife_out_res +
-			g_ife_hw_mgr.isp_bus_caps.max_sfe_out_res_type)) ||
+			g_ife_hw_mgr.isp_caps.max_sfe_out_res_type)) ||
 			(in_port->num_out_res <= 0)) {
 			CAM_ERR(CAM_ISP, "Invalid num output res %u",
 				in_port->num_out_res);
@@ -5088,7 +5088,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	atomic_set(&ife_ctx->cdm_done, 1);
 	ife_ctx->last_cdm_done_req = 0;
 
-	if (g_ife_hw_mgr.isp_bus_caps.support_consumed_addr)
+	if (g_ife_hw_mgr.isp_caps.support_consumed_addr)
 		acquire_args->op_flags |=
 			CAM_IFE_CTX_CONSUME_ADDR_EN;
 
@@ -5141,7 +5141,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	acquire_args->op_params.num_valid_params = 2;
 	acquire_args->op_params.param_list[0] = max_ife_out_res;
 	acquire_args->op_params.param_list[1] =
-		ife_hw_mgr->isp_bus_caps.max_sfe_out_res_type;
+		ife_hw_mgr->isp_caps.max_sfe_out_res_type;
 
 	cam_ife_hw_mgr_print_acquire_info(ife_ctx, total_pix_port,
 		total_pd_port, total_rdi_port, rc);
@@ -6648,21 +6648,30 @@ static void cam_ife_hw_mgr_set_hw_debug_config(
 	uint32_t hw_idx = 0;
 	struct cam_ife_hw_mgr *hw_mgr = ctx->hw_mgr;
 	struct cam_ife_csid_debug_cfg_args csid_debug_args;
-	struct cam_sfe_debug_cfg_params sfe_debug_args;
-	bool ife_bus_debug_args;
+	struct cam_sfe_debug_cfg_params sfe_debug_args = {0};
+	struct cam_vfe_generic_debug_config vfe_debug_args = {0};
 
 	/* Set CSID debug args */
 	csid_debug_args.csid_debug = hw_mgr->debug_cfg.csid_debug;
 	csid_debug_args.csid_rx_capture_debug = hw_mgr->debug_cfg.rx_capture_debug;
 	csid_debug_args.rx_capture_debug_set = hw_mgr->debug_cfg.rx_capture_debug_set;
+	csid_debug_args.csid_testbus_debug = hw_mgr->debug_cfg.csid_test_bus;
 
 	/* Set SFE debug args */
 	sfe_debug_args.cache_config = false;
 	sfe_debug_args.u.dbg_cfg.sfe_debug_cfg = hw_mgr->debug_cfg.sfe_debug;
 	sfe_debug_args.u.dbg_cfg.sfe_sensor_sel = hw_mgr->debug_cfg.sfe_sensor_diag_cfg;
+	sfe_debug_args.u.dbg_cfg.num_counters = hw_mgr->isp_caps.num_sfe_perf_counters;
+	for (i = 0; i < hw_mgr->isp_caps.num_sfe_perf_counters; i++)
+		sfe_debug_args.u.dbg_cfg.sfe_perf_counter_val[i] =
+			hw_mgr->debug_cfg.sfe_perf_counter_val[i];
 
 	/* Set IFE bus debug args */
-	ife_bus_debug_args = hw_mgr->debug_cfg.disable_ife_mmu_prefetch;
+	vfe_debug_args.disable_ife_mmu_prefetch = hw_mgr->debug_cfg.disable_ife_mmu_prefetch;
+	vfe_debug_args.num_counters = hw_mgr->isp_caps.num_ife_perf_counters;
+	for (i = 0; i < hw_mgr->isp_caps.num_ife_perf_counters; i++)
+		vfe_debug_args.vfe_perf_counter_val[i] =
+			hw_mgr->debug_cfg.ife_perf_counter_val[i];
 
 	/* Iterate over HW acquired for this stream and update debug config */
 	for (i = 0; i < ctx->num_base; i++) {
@@ -6673,8 +6682,8 @@ static void cam_ife_hw_mgr_set_hw_debug_config(
 			if (hw_mgr->ife_devices[hw_idx]) {
 				rc = hw_mgr->ife_devices[hw_idx]->hw_intf->hw_ops.process_cmd(
 					hw_mgr->ife_devices[hw_idx]->hw_intf->hw_priv,
-					CAM_ISP_HW_CMD_IFE_BUS_DEBUG_CFG,
-					&ife_bus_debug_args, sizeof(ife_bus_debug_args));
+					CAM_ISP_HW_CMD_IFE_DEBUG_CFG,
+					&vfe_debug_args, sizeof(vfe_debug_args));
 				if (rc)
 					CAM_DBG(CAM_ISP,
 						"Failed to set IFE_%u bus wr debug cfg rc: %d",
@@ -6730,7 +6739,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
 	struct cam_hw_intf                  *hw_intf;
 
 	primary_rdi_src_res = CAM_ISP_HW_VFE_IN_MAX;
-	primary_rdi_out_res = g_ife_hw_mgr.isp_bus_caps.max_vfe_out_res_type;
+	primary_rdi_out_res = g_ife_hw_mgr.isp_caps.max_vfe_out_res_type;
 	primary_rdi_csid_res = CAM_IFE_PIX_PATH_RES_MAX;
 
 	if (!hw_mgr_priv || !start_isp) {
@@ -6901,7 +6910,7 @@ start_only:
 		}
 	}
 
-	if (primary_rdi_out_res < g_ife_hw_mgr.isp_bus_caps.max_vfe_out_res_type) {
+	if (primary_rdi_out_res < g_ife_hw_mgr.isp_caps.max_vfe_out_res_type) {
 		primary_rdi_src_res =
 			cam_convert_rdi_out_res_id_to_src(primary_rdi_out_res);
 		primary_rdi_csid_res =
@@ -9052,7 +9061,7 @@ static inline int cam_isp_validate_bw_limiter_blob(
 	struct cam_isp_out_rsrc_bw_limiter_config *bw_limit_config)
 {
 	if ((bw_limit_config->num_ports >  (max_ife_out_res +
-		g_ife_hw_mgr.isp_bus_caps.max_sfe_out_res_type)) ||
+		g_ife_hw_mgr.isp_caps.max_sfe_out_res_type)) ||
 		(bw_limit_config->num_ports == 0)) {
 		CAM_ERR(CAM_ISP,
 			"Invalid num_ports:%u in bw limit config",
@@ -9223,7 +9232,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 
 		hfr_config = (struct cam_isp_resource_hfr_config *)blob_data;
 
-		if (hfr_config->num_ports > g_ife_hw_mgr.isp_bus_caps.max_vfe_out_res_type ||
+		if (hfr_config->num_ports > g_ife_hw_mgr.isp_caps.max_vfe_out_res_type ||
 			hfr_config->num_ports == 0) {
 			CAM_ERR(CAM_ISP, "Invalid num_ports %u in HFR config",
 				hfr_config->num_ports);
@@ -13168,14 +13177,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(cam_ife_sfe_cache_debug,
 static int cam_ife_set_csid_debug(void *data, u64 val)
 {
 	g_ife_hw_mgr.debug_cfg.csid_debug = val;
-	CAM_DBG(CAM_ISP, "Set CSID Debug value :%lld", val);
+	CAM_INFO(CAM_ISP, "Set CSID Debug value :%lld", val);
 	return 0;
 }
 
 static int cam_ife_get_csid_debug(void *data, u64 *val)
 {
 	*val = g_ife_hw_mgr.debug_cfg.csid_debug;
-	CAM_DBG(CAM_ISP, "Get CSID Debug value :%lld",
+	CAM_INFO(CAM_ISP, "Get CSID Debug value :%lld",
 		g_ife_hw_mgr.debug_cfg.csid_debug);
 
 	return 0;
@@ -13371,6 +13380,128 @@ static int cam_isp_get_test_irq_line(void *data, u64 *val)
 DEFINE_DEBUGFS_ATTRIBUTE(cam_isp_test_irq_line, cam_isp_get_test_irq_line,
 	cam_isp_set_test_irq_line, "%16llu");
 
+static ssize_t cam_ife_hw_mgr_perfcnt_write(
+	struct file *file, const char __user *ubuf,
+	size_t size, loff_t *loff_t)
+{
+	char *delimiter1, *delimiter2;
+	char input_buf[16];
+	uint32_t counter_idx = 0, counter_val = 0;
+	struct cam_ife_hw_mgr_debug *debug_cfg = &g_ife_hw_mgr.debug_cfg;
+
+	if (size >= 16)
+		return -EINVAL;
+
+	if (copy_from_user(input_buf, ubuf, sizeof(input_buf)))
+		return -EFAULT;
+
+	if ((!g_ife_hw_mgr.isp_caps.num_ife_perf_counters) &&
+		(!g_ife_hw_mgr.isp_caps.num_sfe_perf_counters))
+		return -EBADF;
+
+	delimiter1 = strnchr(input_buf, size, '_');
+	if (!delimiter1)
+		goto end;
+
+	delimiter2 = strnchr(delimiter1 + 1, size, '_');
+	if (!delimiter2)
+		goto end;
+
+	/* separate the strings */
+	*delimiter1 = '\0';
+	*delimiter2 = '\0';
+
+	/* Find the counter index after the first delimiter */
+	if (kstrtou32(delimiter1 + 1, 0, &counter_idx))
+		goto end;
+
+	/* Find the counter value after the second delimiter */
+	if (kstrtou32(delimiter2 + 1, 0, &counter_val))
+		goto end;
+
+	/* Check for supported HWs */
+	if (strcmp(input_buf, "ife") == 0) {
+		/* check if counter is available for given target */
+		if ((counter_idx) && (counter_idx <= g_ife_hw_mgr.isp_caps.num_ife_perf_counters))
+			debug_cfg->ife_perf_counter_val[counter_idx - 1] =
+				counter_val;
+		else
+			goto end;
+	} else if (strcmp(input_buf, "sfe") == 0) {
+		if ((counter_idx) && (counter_idx <= g_ife_hw_mgr.isp_caps.num_sfe_perf_counters))
+			debug_cfg->sfe_perf_counter_val[counter_idx - 1] =
+				counter_val;
+		else
+			goto end;
+	} else {
+		goto end;
+	}
+
+	return size;
+
+end:
+	CAM_INFO(CAM_ISP,
+		"Failed to set perf counter debug setting - invalid input format [input: %s counter: %u counter_val: %u]",
+		input_buf, counter_idx, counter_val);
+	return -EINVAL;
+}
+
+static ssize_t cam_ife_hw_mgr_perfcnt_read(
+	struct file *file, char __user *ubuf,
+	size_t size, loff_t *loff_t)
+{
+	char display_string[256];
+	int len = 0;
+
+	len += scnprintf(display_string + len, (256 - len),
+		"\n***** ISP PERF COUNTERS *****\n\n");
+
+	if ((!g_ife_hw_mgr.isp_caps.num_ife_perf_counters) &&
+		(!g_ife_hw_mgr.isp_caps.num_sfe_perf_counters)) {
+		len += scnprintf(display_string + len, (256 - len), "NOT SUPPORTED\n\n");
+	} else {
+		len += scnprintf(display_string + len, (256 - len),
+			"Available counters IFE: %u SFE: %u\n\n",
+			g_ife_hw_mgr.isp_caps.num_ife_perf_counters,
+			g_ife_hw_mgr.isp_caps.num_sfe_perf_counters);
+		len += scnprintf(display_string + len, (256 - len),
+			"To choose counter write to same file - \"<hw>_<counter_index>_<reg_val>\"\nEx. \"ife_1_6619140\"\n\n");
+	}
+
+	len += scnprintf(display_string + len, (256 - len),
+		"*****************************\n");
+
+	return simple_read_from_buffer(ubuf, size, loff_t, display_string,
+		strlen(display_string));
+}
+
+static const struct file_operations cam_ife_hw_mgr_perfcnter_debug = {
+	.owner = THIS_MODULE,
+	.open  = simple_open,
+	.read  = cam_ife_hw_mgr_perfcnt_read,
+	.write = cam_ife_hw_mgr_perfcnt_write,
+};
+
+static int cam_ife_set_csid_testbus_debug(void *data, u64 val)
+{
+	g_ife_hw_mgr.debug_cfg.csid_test_bus = val;
+	CAM_DBG(CAM_ISP, "Set CSID test bus value :%lld", val);
+	return 0;
+}
+
+static int cam_ife_get_csid_testbus_debug(void *data, u64 *val)
+{
+	*val = g_ife_hw_mgr.debug_cfg.csid_test_bus;
+	CAM_DBG(CAM_ISP, "Get CSID test bus value :%u",
+		g_ife_hw_mgr.debug_cfg.csid_test_bus);
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(cam_ife_csid_testbus_debug,
+	cam_ife_get_csid_testbus_debug,
+	cam_ife_set_csid_testbus_debug, "%16llu");
+
 static int cam_ife_hw_mgr_debug_register(void)
 {
 	int rc = 0;
@@ -13390,7 +13521,7 @@ static int cam_ife_hw_mgr_debug_register(void)
 
 	debugfs_create_file("ife_csid_debug", 0644,
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_csid_debug);
-	dbgfileptr = debugfs_create_file("ife_csid_rx_capture_debug", 0644,
+	debugfs_create_file("ife_csid_rx_capture_debug", 0644,
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_csid_rx_capture_debug);
 	debugfs_create_u32("enable_recovery", 0644, g_ife_hw_mgr.debug_cfg.dentry,
 		&g_ife_hw_mgr.debug_cfg.enable_recovery);
@@ -13419,6 +13550,10 @@ static int cam_ife_hw_mgr_debug_register(void)
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_sfe_cache_debug);
 	dbgfileptr = debugfs_create_file("test_irq_line", 0644,
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_isp_test_irq_line);
+	debugfs_create_file("isp_perf_counters", 0644,
+		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);
 end:
 	g_ife_hw_mgr.debug_cfg.enable_csid_recovery = 1;
 	return rc;
@@ -13550,7 +13685,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 	struct cam_iommu_handle cdm_handles;
 	struct cam_ife_hw_mgr_ctx *ctx_pool;
 	struct cam_isp_hw_mgr_res *res_list_ife_out;
-	struct cam_isp_hw_bus_cap isp_bus_cap = {0};
+	struct cam_isp_hw_cap isp_cap = {0};
 	struct cam_isp_hw_path_port_map path_port_map;
 	struct cam_isp_hw_mgr_res *res_list_sfe_out;
 
@@ -13579,11 +13714,12 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 			if (j == 0) {
 				ife_device->hw_ops.process_cmd(
 					vfe_hw,
-					CAM_ISP_HW_CMD_QUERY_BUS_CAP,
-					&isp_bus_cap,
-					sizeof(struct cam_isp_hw_bus_cap));
-				CAM_DBG(CAM_ISP, "max VFE out resources: 0x%x",
-					isp_bus_cap.max_out_res_type);
+					CAM_ISP_HW_CMD_QUERY_CAP,
+					&isp_cap,
+					sizeof(struct cam_isp_hw_cap));
+				CAM_DBG(CAM_ISP,
+					"max VFE out resources: 0x%x num perf counters: 0x%x",
+					isp_cap.max_out_res_type, isp_cap.num_perf_counters);
 
 				ife_device->hw_ops.process_cmd(
 					vfe_hw,
@@ -13613,13 +13749,15 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 		return -EINVAL;
 	}
 
-	g_ife_hw_mgr.isp_bus_caps.support_consumed_addr =
-		isp_bus_cap.support_consumed_addr;
-	g_ife_hw_mgr.isp_bus_caps.max_vfe_out_res_type =
-		isp_bus_cap.max_out_res_type;
+	g_ife_hw_mgr.isp_caps.support_consumed_addr =
+		isp_cap.support_consumed_addr;
+	g_ife_hw_mgr.isp_caps.max_vfe_out_res_type =
+		isp_cap.max_out_res_type;
+	g_ife_hw_mgr.isp_caps.num_ife_perf_counters =
+		isp_cap.num_perf_counters;
 	max_ife_out_res =
-		g_ife_hw_mgr.isp_bus_caps.max_vfe_out_res_type & 0xFF;
-	memset(&isp_bus_cap, 0x0, sizeof(struct cam_isp_hw_bus_cap));
+		g_ife_hw_mgr.isp_caps.max_vfe_out_res_type & 0xFF;
+	memset(&isp_cap, 0x0, sizeof(struct cam_isp_hw_cap));
 
 	for (i = 0; i < path_port_map.num_entries; i++) {
 		g_ife_hw_mgr.path_port_map.entry[i][0] = path_port_map.entry[i][0];
@@ -13651,14 +13789,18 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 
 				rc = sfe_device->hw_ops.process_cmd(
 					sfe_hw,
-					CAM_ISP_HW_CMD_QUERY_BUS_CAP,
-					&isp_bus_cap,
-					sizeof(struct cam_isp_hw_bus_cap));
-				CAM_DBG(CAM_ISP, "max SFE out resources: 0x%x",
-					isp_bus_cap.max_out_res_type);
-				if (!rc)
-					g_ife_hw_mgr.isp_bus_caps.max_sfe_out_res_type =
-						isp_bus_cap.max_out_res_type;
+					CAM_ISP_HW_CMD_QUERY_CAP,
+					&isp_cap,
+					sizeof(struct cam_isp_hw_cap));
+				CAM_DBG(CAM_ISP,
+					"max SFE out resources: 0x%x num_perf_counters: 0x%x",
+					isp_cap.max_out_res_type, isp_cap.num_perf_counters);
+				if (!rc) {
+					g_ife_hw_mgr.isp_caps.max_sfe_out_res_type =
+						isp_cap.max_out_res_type;
+					g_ife_hw_mgr.isp_caps.num_sfe_perf_counters =
+						isp_cap.num_perf_counters;
+				}
 
 				if (g_ife_hw_mgr.sfe_devices[i]->num_hw_pid)
 					g_ife_hw_mgr.hw_pid_support = true;
@@ -13812,6 +13954,19 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 		"CAM_ISP");
 	cam_ife_mgr_test_irq_lines_at_probe(&g_ife_hw_mgr);
 
+	/* Allocate memory for perf counters */
+	if (g_ife_hw_mgr.isp_caps.num_ife_perf_counters) {
+		g_ife_hw_mgr.debug_cfg.ife_perf_counter_val = kcalloc(
+			g_ife_hw_mgr.isp_caps.num_ife_perf_counters,
+			sizeof(uint32_t), GFP_KERNEL);
+	}
+
+	if (g_ife_hw_mgr.isp_caps.num_sfe_perf_counters) {
+		g_ife_hw_mgr.debug_cfg.sfe_perf_counter_val = kcalloc(
+			g_ife_hw_mgr.isp_caps.num_sfe_perf_counters,
+			sizeof(uint32_t), GFP_KERNEL);
+	}
+
 	CAM_DBG(CAM_ISP, "Exit");
 
 	return 0;
@@ -13841,6 +13996,8 @@ void cam_ife_hw_mgr_deinit(void)
 
 	cam_req_mgr_workq_destroy(&g_ife_hw_mgr.workq);
 	g_ife_hw_mgr.debug_cfg.dentry = NULL;
+	kfree(g_ife_hw_mgr.debug_cfg.sfe_perf_counter_val);
+	kfree(g_ife_hw_mgr.debug_cfg.ife_perf_counter_val);
 
 	for (i = 0; i < CAM_IFE_CTX_MAX; i++) {
 		cam_tasklet_deinit(

+ 14 - 3
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.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_IFE_HW_MGR_H_
@@ -48,7 +49,10 @@ enum cam_ife_ctx_master_type {
  * @enable_csid_recovery:      enable csid recovery
  * @sfe_debug:                 sfe debug config
  * @sfe_sensor_diag_cfg:       sfe sensor diag config
+ * @csid_test_bus:             csid test bus config
  * @sfe_cache_debug:           sfe cache debug info
+ * @ife_perf_counter_val:      ife perf counter values
+ * @sfe_perf_counter_val:      sfe perf counter values
  * @enable_req_dump:           Enable request dump on HW errors
  * @per_req_reg_dump:          Enable per request reg dump
  * @disable_ubwc_comp:         Disable UBWC compression
@@ -65,7 +69,10 @@ struct cam_ife_hw_mgr_debug {
 	uint32_t       enable_csid_recovery;
 	uint32_t       sfe_debug;
 	uint32_t       sfe_sensor_diag_cfg;
+	uint32_t       csid_test_bus;
 	uint32_t       sfe_cache_debug[CAM_SFE_HW_NUM_MAX];
+	uint32_t      *ife_perf_counter_val;
+	uint32_t      *sfe_perf_counter_val;
 	bool           enable_req_dump;
 	bool           per_req_reg_dump;
 	bool           disable_ubwc_comp;
@@ -331,11 +338,15 @@ struct cam_ife_hw_mgr_ctx {
  *
  * @max_vfe_out_res_type  :  max ife out res type value from hw
  * @max_sfe_out_res_type  :  max sfe out res type value from hw
+ * @num_ife_perf_counters :  max ife perf counters supported
+ * @num_sfe_perf_counters :  max sfe perf counters supported
  * @support_consumed_addr :  indicate whether hw supports last consumed address
  */
-struct cam_isp_bus_hw_caps {
+struct cam_isp_ife_sfe_hw_caps {
 	uint32_t     max_vfe_out_res_type;
 	uint32_t     max_sfe_out_res_type;
+	uint32_t     num_ife_perf_counters;
+	uint32_t     num_sfe_perf_counters;
 	bool         support_consumed_addr;
 };
 
@@ -373,7 +384,7 @@ struct cam_isp_sys_cache_info {
  * @hw_pid_support         hw pid support for this target
  * @csid_rup_en            Reg update at CSID side
  * @csid_global_reset_en   CSID global reset enable
- * @isp_bus_caps           Capability of underlying SFE/IFE bus HW
+ * @isp_caps               Capability of underlying SFE/IFE HW
  * @path_port_map          Mapping of outport to IFE mux
  */
 struct cam_ife_hw_mgr {
@@ -398,7 +409,7 @@ struct cam_ife_hw_mgr {
 	bool                             hw_pid_support;
 	bool                             csid_rup_en;
 	bool                             csid_global_reset_en;
-	struct cam_isp_bus_hw_caps       isp_bus_caps;
+	struct cam_isp_ife_sfe_hw_caps   isp_caps;
 	struct cam_isp_hw_path_port_map  path_port_map;
 
 	uint32_t                         num_caches_found;

+ 3 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid680.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_IFE_CSID_680_H_
@@ -1110,6 +1111,8 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.buf_done_irq_mask_addr                  = 0x90,
 	.buf_done_irq_clear_addr                 = 0x94,
 	.buf_done_irq_set_addr                   = 0x98,
+	.test_bus_ctrl                           = 0x1E8,
+	.test_bus_debug                          = 0x1EC,
 
 	/*configurations */
 	.major_version                           = 6,

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

@@ -1171,6 +1171,8 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.buf_done_irq_mask_addr                  = 0x90,
 	.buf_done_irq_clear_addr                 = 0x94,
 	.buf_done_irq_set_addr                   = 0x98,
+	.test_bus_ctrl                           = 0x1E8,
+	.test_bus_debug                          = 0x1EC,
 
 	/*configurations */
 	.major_version                           = 6,

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.h

@@ -297,7 +297,9 @@ struct cam_ife_csid_hw_counters {
  * @rst_capture_strobes:   rx packet capture rst strobes
  * @rx_mask:               Debug mask for rx irq
  * @path_mask:             Debug mask for path irq
+ * @test_bus_val:          CSID test bus value
  * @rx_capture_debug_set:  rx pkt capture debug set
+ * @test_bus_enabled:      test bus enabled
  */
 struct cam_ife_csid_debug_info {
 	uint32_t                          debug_val;
@@ -306,7 +308,9 @@ struct cam_ife_csid_debug_info {
 	uint32_t                          rst_capture_strobes;
 	uint32_t                          rx_mask;
 	uint32_t                          path_mask;
+	uint32_t                          test_bus_val;
 	bool                              rx_capture_debug_set;
+	bool                              test_bus_enabled;
 };
 
 /*

+ 47 - 7
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c

@@ -88,6 +88,8 @@ static int cam_ife_csid_ver2_set_debug(
 	memset(&csid_hw->debug_info, 0,
 		sizeof(struct cam_ife_csid_debug_info));
 	csid_hw->debug_info.debug_val = debug_args->csid_debug;
+	csid_hw->debug_info.test_bus_val = debug_args->csid_testbus_debug;
+
 	/*
 	 * RX capture debug
 	 * [0:3]   = rst strobes
@@ -1358,7 +1360,7 @@ static void cam_ife_csid_ver2_print_debug_reg_status(
 	struct cam_hw_soc_info                   *soc_info;
 	void __iomem *mem_base;
 	const struct cam_ife_csid_ver2_path_reg_info *path_reg = NULL;
-	uint32_t val0 = 0, val1 = 0, val2 = 0;
+	uint32_t val0 = 0, val1 = 0, val2 = 0, val3 = 0;
 
 	soc_info = &csid_hw->hw_info->soc_info;
 	csid_reg = (struct cam_ife_csid_ver2_reg_info *)
@@ -1375,9 +1377,15 @@ static void cam_ife_csid_ver2_print_debug_reg_status(
 	val2 = cam_io_r_mb(mem_base +
 		path_reg->debug_halt_status_addr);
 
+	/* Read test bus if enabled */
+	if (csid_hw->debug_info.test_bus_enabled)
+		val3 = cam_io_r_mb(mem_base +
+			csid_reg->cmn_reg->test_bus_debug);
+
 	CAM_INFO(CAM_ISP,
-		"debug_camif_0: 0x%x debug_camif_1: 0x%x halt_status: 0x%x for res: %s ",
-		 val0, val1, val2, res->res_name);
+		"debug_camif_0: 0x%x debug_camif_1: 0x%x halt_status: 0x%x test_bus: %s test_bus_val: 0x%x for res: %s ",
+		 val0, val1, val2, CAM_BOOL_TO_YESNO(csid_hw->debug_info.test_bus_enabled),
+		 val3, res->res_name);
 }
 
 static int cam_ife_csid_ver2_parse_path_irq_status(
@@ -1939,10 +1947,21 @@ static int cam_ife_csid_ver2_wait_for_reset(
 
 	if (rem_jiffies == 0) {
 		rc = -ETIMEDOUT;
-		CAM_ERR(CAM_ISP,
-			"CSID[%d], sync-mode[%d] reset time out",
-			csid_hw->hw_intf->hw_idx,
-			csid_hw->sync_mode);
+		if (csid_hw->debug_info.test_bus_enabled) {
+			struct cam_hw_soc_info *soc_info = &csid_hw->hw_info->soc_info;
+			struct cam_ife_csid_ver2_reg_info *csid_reg =
+				(struct cam_ife_csid_ver2_reg_info *) csid_hw->core_info->csid_reg;
+
+			CAM_ERR(CAM_ISP,
+				"CSID[%d], sync-mode[%d] test_bus: 0x%x reset timed out",
+				csid_hw->hw_intf->hw_idx, csid_hw->sync_mode,
+				cam_io_r_mb(
+					soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base +
+					csid_reg->cmn_reg->test_bus_debug));
+		} else {
+			CAM_ERR(CAM_ISP, "CSID[%d], sync-mode[%d] reset timed out",
+				csid_hw->hw_intf->hw_idx, csid_hw->sync_mode);
+		}
 	} else {
 		CAM_DBG(CAM_ISP,
 		"CSID[%d], sync-mode[%d] reset success",
@@ -4307,6 +4326,18 @@ disable_hw:
 	return rc;
 }
 
+static void cam_ife_csid_ver2_testbus_config(
+	struct cam_ife_csid_ver2_hw *csid_hw, uint32_t val)
+{
+	struct cam_hw_soc_info *soc_info = &csid_hw->hw_info->soc_info;
+	struct cam_ife_csid_ver2_reg_info *csid_reg =
+		(struct cam_ife_csid_ver2_reg_info *) csid_hw->core_info->csid_reg;
+
+	cam_io_w_mb(val, soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base +
+		csid_reg->cmn_reg->test_bus_ctrl);
+	CAM_DBG(CAM_ISP, "CSID [%u] test_bus_ctrl: 0x%x", csid_hw->hw_intf->hw_idx, val);
+}
+
 int cam_ife_csid_ver2_start(void *hw_priv, void *args,
 			uint32_t arg_size)
 {
@@ -4414,6 +4445,11 @@ int cam_ife_csid_ver2_start(void *hw_priv, void *args,
 		cam_ife_csid_ver2_enable_path(csid_hw, res);
 	}
 
+	if (csid_hw->debug_info.test_bus_val) {
+		cam_ife_csid_ver2_testbus_config(csid_hw, csid_hw->debug_info.test_bus_val);
+		csid_hw->debug_info.test_bus_enabled = true;
+	}
+
 	csid_hw->flags.reset_awaited = false;
 end:
 	mutex_unlock(&csid_hw->hw_info->hw_mutex);
@@ -4495,6 +4531,10 @@ int cam_ife_csid_ver2_stop(void *hw_priv,
 	}
 
 	cam_ife_csid_ver2_disable_csi2(csid_hw);
+	if (csid_hw->debug_info.test_bus_enabled)
+		cam_ife_csid_ver2_testbus_config(csid_hw, 0x0);
+
+	csid_hw->debug_info.test_bus_enabled = false;
 	mutex_unlock(&csid_hw->hw_info->hw_mutex);
 
 	return rc;

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

@@ -378,6 +378,8 @@ struct cam_ife_csid_ver2_common_reg_info {
 	uint32_t buf_done_irq_mask_addr;
 	uint32_t buf_done_irq_clear_addr;
 	uint32_t buf_done_irq_set_addr;
+	uint32_t test_bus_ctrl;
+	uint32_t test_bus_debug;
 
 	/*Shift Bit Configurations*/
 	uint32_t rst_done_shift_val;

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

@@ -466,11 +466,13 @@ struct cam_ife_csid_discard_init_frame_args {
  *
  * @csid_debug: CSID debug val
  * @csid_rx_capture_debug: CSID rx capture debug val
+ * @csid_testbus_debug: CSID test bus val
  * @rx_capture_debug_set: CSID rx capture debug set;
  */
 struct cam_ife_csid_debug_cfg_args {
 	uint64_t                          csid_debug;
 	uint32_t                          csid_rx_capture_debug;
+	uint32_t                          csid_testbus_debug;
 	bool                              rx_capture_debug_set;
 };
 

+ 8 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.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_ISP_HW_H_
@@ -179,7 +180,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_TPG_CORE_CFG_CMD,
 	CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
 	CAM_ISP_HW_CMD_SET_SFE_DEBUG_CFG,
-	CAM_ISP_HW_CMD_QUERY_BUS_CAP,
+	CAM_ISP_HW_CMD_QUERY_CAP,
 	CAM_IFE_CSID_CMD_GET_TIME_STAMP,
 	CAM_IFE_CSID_SET_CSID_DEBUG,
 	CAM_IFE_CSID_SOF_IRQ_DEBUG,
@@ -194,7 +195,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_NOTIFY_OVERFLOW,
 	CAM_ISP_HW_CMD_IS_PDAF_RDI2_MUX_EN,
 	CAM_ISP_HW_CMD_GET_PATH_PORT_MAP,
-	CAM_ISP_HW_CMD_IFE_BUS_DEBUG_CFG,
+	CAM_ISP_HW_CMD_IFE_DEBUG_CFG,
 	CAM_ISP_HW_SFE_SYS_CACHE_WM_CONFIG,
 	CAM_ISP_HW_SFE_SYS_CACHE_RM_CONFIG,
 	CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG,
@@ -495,13 +496,15 @@ struct cam_isp_hw_intf_data {
  *
  * @Brief:         ISP hw bus capabilities
  *
- * @support_consumed_addr:  Indicate whether HW has last consumed addr reg
  * @max_out_res_type:       Maximum value of out resource type supported by hw
+ * @num_perf_counters:      Number of perf counters supported
+ * @support_consumed_addr:  Indicate whether HW has last consumed addr reg
  *
  */
-struct cam_isp_hw_bus_cap {
-	bool                    support_consumed_addr;
+struct cam_isp_hw_cap {
 	uint32_t                max_out_res_type;
+	uint32_t                num_perf_counters;
+	bool                    support_consumed_addr;
 };
 
 /**

+ 11 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SFE_HW_INTF_H_
@@ -12,6 +13,7 @@
 
 #define SFE_CORE_BASE_IDX           0
 #define CAM_SFE_HW_NUM_MAX          2
+#define CAM_SFE_PERF_CNT_MAX        2
 
 enum cam_sfe_core_id {
 	CAM_SFE_CORE_0,
@@ -55,12 +57,16 @@ enum cam_sfe_bus_rd_irq_regs {
 /*
  * struct cam_sfe_generic_debug_config:
  *
- * @sfe_debug_cfg : SFE debug cfg value
- * @sfe_sensor_sel: SFE sensor sel for diag data
+ * @sfe_debug_cfg       : SFE debug cfg value
+ * @sfe_sensor_sel      : SFE sensor sel for diag data
+ * @num_counters        : Number of perf counters configured
+ * @sfe_perf_counter_val: SFE perf counter values
  */
 struct cam_sfe_generic_debug_config {
-	uint32_t sfe_debug_cfg;
-	uint32_t sfe_sensor_sel;
+	uint32_t  sfe_debug_cfg;
+	uint32_t  sfe_sensor_sel;
+	uint32_t  num_counters;
+	uint32_t  sfe_perf_counter_val[CAM_SFE_PERF_CNT_MAX];
 };
 
 /*
@@ -80,11 +86,11 @@ struct cam_sfe_sys_cache_debug_config {
  * @cache_config: If the config is for cache
  */
 struct cam_sfe_debug_cfg_params {
-	bool cache_config;
 	union {
 		struct cam_sfe_generic_debug_config   dbg_cfg;
 		struct cam_sfe_sys_cache_debug_config cache_cfg;
 	} u;
+	bool cache_config;
 };
 
 /*

+ 17 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_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_VFE_HW_INTF_H_
@@ -24,6 +25,8 @@
 
 #define CAM_VFE_MAX_UBWC_PORTS        4
 
+#define CAM_VFE_PERF_CNT_MAX          2
+
 enum cam_isp_hw_vfe_in_mux {
 	CAM_ISP_HW_VFE_IN_CAMIF       = 0,
 	CAM_ISP_HW_VFE_IN_TESTGEN     = 1,
@@ -371,6 +374,20 @@ struct cam_vfe_generic_ubwc_config {
 		ubwc_plane_cfg[CAM_PACKET_MAX_PLANES - 1];
 };
 
+
+/*
+ * struct cam_vfe_generic_debug_config:
+ *
+ * @num_counters            : Number of perf counters configured
+ * @vfe_perf_counter_val    : VFE perf counter values
+ * @disable_ife_mmu_prefetch: Disable IFE mmu prefetch
+ */
+struct cam_vfe_generic_debug_config {
+	uint32_t  num_counters;
+	uint32_t  vfe_perf_counter_val[CAM_VFE_PERF_CNT_MAX];
+	bool      disable_ife_mmu_prefetch;
+};
+
 /*
  * cam_vfe_hw_init()
  *

+ 20 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SFE680_H_
@@ -311,6 +312,25 @@ static struct cam_sfe_top_common_reg_offset  sfe680_top_commong_reg  = {
 	.hdr_throttle_cfg              = 0x000000C0,
 	.sfe_op_throttle_cfg           = 0x000000C4,
 	.bus_overflow_status           = 0x00000868,
+	.num_perf_counters             = 2,
+	.perf_count_reg = {
+		{
+			.perf_count_cfg        = 0x00000080,
+			.perf_pix_count        = 0x00000084,
+			.perf_line_count       = 0x00000088,
+			.perf_stall_count      = 0x0000008C,
+			.perf_always_count     = 0x00000090,
+			.perf_count_status     = 0x00000094,
+		},
+		{
+			.perf_count_cfg        = 0x00000098,
+			.perf_pix_count        = 0x0000009C,
+			.perf_line_count       = 0x000000A0,
+			.perf_stall_count      = 0x000000A4,
+			.perf_always_count     = 0x000000A8,
+			.perf_count_status     = 0x000000AC,
+		},
+	},
 	.top_debug_cfg                 = 0x0000007C,
 	.lcr_supported                 = true,
 	.ir_supported                  = false,

+ 20 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe780.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SFE780_H_
@@ -531,6 +532,25 @@ static struct cam_sfe_top_common_reg_offset  sfe780_top_commong_reg  = {
 	.irc_throttle_cfg              = 0x000000C8,
 	.sfe_single_dual_cfg           = 0x000000D0,
 	.bus_overflow_status           = 0x00000868,
+	.num_perf_counters             = 2,
+	.perf_count_reg = {
+		{
+			.perf_count_cfg        = 0x00000080,
+			.perf_pix_count        = 0x00000084,
+			.perf_line_count       = 0x00000088,
+			.perf_stall_count      = 0x0000008C,
+			.perf_always_count     = 0x00000090,
+			.perf_count_status     = 0x00000094,
+		},
+		{
+			.perf_count_cfg        = 0x00000098,
+			.perf_pix_count        = 0x0000009C,
+			.perf_line_count       = 0x000000A0,
+			.perf_stall_count      = 0x000000A4,
+			.perf_always_count     = 0x000000A8,
+			.perf_count_status     = 0x000000AC,
+		},
+	},
 	.top_debug_cfg                 = 0x0000007C,
 	.top_cc_test_bus_ctrl          = 0x000001F0,
 	.lcr_supported                 = false,

+ 12 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/slab.h>
@@ -408,7 +409,6 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_STRIPE_UPDATE:
 	case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE:
 	case CAM_ISP_HW_CMD_GET_WM_SECURE_MODE:
-	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
 	case CAM_ISP_HW_SFE_SYS_CACHE_WM_CONFIG:
 	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
 	case CAM_ISP_HW_USER_DUMP:
@@ -447,6 +447,17 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 			core_info->sfe_bus_rd->bus_priv, cmd_type,
 			cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_QUERY_CAP:
+		/* propagate to SFE top */
+		core_info->sfe_top->hw_ops.process_cmd(
+			core_info->sfe_top->top_priv, cmd_type,
+			cmd_args, arg_size);
+
+		/* propagate to SFE bus wr */
+		core_info->sfe_bus_wr->hw_ops.process_cmd(
+			core_info->sfe_bus_wr->bus_priv, cmd_type,
+			cmd_args, arg_size);
+		break;
 	case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA:
 		*((struct cam_hw_soc_info **)cmd_args) = soc_info;
 		rc = 0;

+ 3 - 3
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c

@@ -3298,11 +3298,11 @@ static int cam_sfe_bus_wr_process_cmd(
 	case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE:
 		rc = cam_sfe_bus_wr_update_wm_config(cmd_args);
 		break;
-	case CAM_ISP_HW_CMD_QUERY_BUS_CAP: {
-		struct cam_isp_hw_bus_cap *sfe_bus_cap;
+	case CAM_ISP_HW_CMD_QUERY_CAP: {
+		struct cam_isp_hw_cap *sfe_bus_cap;
 
 		bus_priv = (struct cam_sfe_bus_wr_priv  *) priv;
-		sfe_bus_cap = (struct cam_isp_hw_bus_cap *) cmd_args;
+		sfe_bus_cap = (struct cam_isp_hw_cap *) cmd_args;
 		sfe_bus_cap->max_out_res_type = bus_priv->num_out;
 		rc = 0;
 	}

+ 139 - 51
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/slab.h>
@@ -29,40 +30,46 @@ struct cam_sfe_top_common_data {
 	struct list_head                         free_payload_list;
 };
 
+struct cam_sfe_top_perf_counter_cfg {
+	uint32_t perf_counter_val;
+	bool     dump_counter;
+};
+
 struct cam_sfe_top_priv {
-	struct cam_sfe_top_common_data  common_data;
-	struct cam_isp_resource_node    in_rsrc[CAM_SFE_TOP_IN_PORT_MAX];
-	uint32_t                        num_in_ports;
-	unsigned long                   applied_clk_rate;
-	unsigned long                   req_clk_rate[CAM_SFE_TOP_IN_PORT_MAX];
-	uint32_t                        last_bw_counter;
-	uint32_t                        last_clk_counter;
-	uint64_t                        total_bw_applied;
-	struct cam_axi_vote             agg_incoming_vote;
-	struct cam_axi_vote             req_axi_vote[CAM_SFE_TOP_IN_PORT_MAX];
-	struct cam_axi_vote             last_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
-	uint64_t                        last_total_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
-	uint64_t                        last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
-	enum cam_clk_bw_state           clk_state;
-	enum cam_clk_bw_state           bw_state;
-	enum cam_isp_bw_control_action  axi_vote_control[
+	struct cam_sfe_top_common_data      common_data;
+	struct cam_isp_resource_node        in_rsrc[CAM_SFE_TOP_IN_PORT_MAX];
+	uint32_t                            num_in_ports;
+	unsigned long                       applied_clk_rate;
+	unsigned long                       req_clk_rate[CAM_SFE_TOP_IN_PORT_MAX];
+	uint32_t                            last_bw_counter;
+	uint32_t                            last_clk_counter;
+	uint64_t                            total_bw_applied;
+	struct cam_axi_vote                 agg_incoming_vote;
+	struct cam_axi_vote                 req_axi_vote[CAM_SFE_TOP_IN_PORT_MAX];
+	struct cam_axi_vote                 last_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint64_t                            last_total_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint64_t                            last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	enum cam_clk_bw_state               clk_state;
+	enum cam_clk_bw_state               bw_state;
+	enum cam_isp_bw_control_action      axi_vote_control[
 		CAM_SFE_TOP_IN_PORT_MAX];
-	struct cam_axi_vote             applied_axi_vote;
-	struct cam_sfe_core_cfg         core_cfg;
-	uint32_t                        sfe_debug_cfg;
-	uint32_t                        sensor_sel_diag_cfg;
-	uint32_t                        cc_testbus_sel_cfg;
-	int                             error_irq_handle;
-	uint16_t                        reserve_cnt;
-	uint16_t                        start_stop_cnt;
-	void                           *priv_per_stream;
-	spinlock_t                      spin_lock;
-	cam_hw_mgr_event_cb_func        event_cb;
-	struct cam_sfe_wr_client_desc  *wr_client_desc;
-	struct cam_sfe_top_hw_info     *hw_info;
-	uint32_t                        num_clc_module;
-	struct cam_sfe_top_debug_info  (*clc_dbg_mod_info)[CAM_SFE_TOP_DBG_REG_MAX][8];
-	bool                            skip_clk_data_rst;
+	struct cam_axi_vote                 applied_axi_vote;
+	struct cam_sfe_core_cfg             core_cfg;
+	uint32_t                            sfe_debug_cfg;
+	uint32_t                            sensor_sel_diag_cfg;
+	struct cam_sfe_top_perf_counter_cfg perf_counters[CAM_SFE_PERF_COUNTER_MAX];
+	uint32_t                            cc_testbus_sel_cfg;
+	int                                 error_irq_handle;
+	uint16_t                            reserve_cnt;
+	uint16_t                            start_stop_cnt;
+	void                               *priv_per_stream;
+	spinlock_t                          spin_lock;
+	cam_hw_mgr_event_cb_func            event_cb;
+	struct cam_sfe_wr_client_desc      *wr_client_desc;
+	struct cam_sfe_top_hw_info         *hw_info;
+	uint32_t                            num_clc_module;
+	struct cam_sfe_top_debug_info     (*clc_dbg_mod_info)[CAM_SFE_TOP_DBG_REG_MAX][8];
+	bool                                skip_clk_data_rst;
 };
 
 struct cam_sfe_path_data {
@@ -255,6 +262,41 @@ static void cam_sfe_top_print_cc_test_bus(
 		reg_val, log_buf);
 }
 
+static void cam_sfe_top_dump_perf_counters(
+	const char *event,
+	const char *res_name,
+	struct cam_sfe_top_priv *top_priv)
+{
+	int i;
+	void __iomem                         *mem_base;
+	struct cam_sfe_top_common_data       *common_data;
+	struct cam_hw_soc_info               *soc_info;
+	struct cam_sfe_top_common_reg_offset *common_reg;
+
+	common_data = &top_priv->common_data;
+	common_reg = common_data->common_reg;
+	soc_info = common_data->soc_info;
+	mem_base = soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base;
+
+	for (i = 0; i < top_priv->common_data.common_reg->num_perf_counters; i++) {
+		if (top_priv->perf_counters[i].dump_counter) {
+			CAM_INFO(CAM_SFE,
+				"SFE [%u] on %s %s counter: %d pixel_cnt: %d line_cnt: %d stall_cnt: %d always_cnt: %d status: 0x%x",
+				common_data->hw_intf->hw_idx, res_name, event, (i + 1),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_pix_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_line_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_stall_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_always_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_count_status));
+		}
+	}
+}
+
 static void cam_sfe_top_print_debug_reg_info(
 	struct cam_sfe_top_priv *top_priv)
 {
@@ -291,6 +333,8 @@ static void cam_sfe_top_print_debug_reg_info(
 		cam_sfe_top_print_cc_test_bus(top_priv);
 
 	kfree(reg_val);
+
+	cam_sfe_top_dump_perf_counters("ERROR", "", top_priv);
 }
 
 static struct cam_axi_vote *cam_sfe_top_delay_bw_reduction(
@@ -747,12 +791,19 @@ static int cam_sfe_set_top_debug(
 	struct cam_sfe_top_priv *top_priv,
 	void *cmd_args)
 {
+	int i;
+	uint32_t max_counters = top_priv->common_data.common_reg->num_perf_counters;
 	struct cam_sfe_debug_cfg_params *debug_cfg;
 
 	debug_cfg = (struct cam_sfe_debug_cfg_params *)cmd_args;
 	if (!debug_cfg->cache_config) {
 		top_priv->sfe_debug_cfg = debug_cfg->u.dbg_cfg.sfe_debug_cfg;
 		top_priv->sensor_sel_diag_cfg = debug_cfg->u.dbg_cfg.sfe_sensor_sel;
+
+		if (debug_cfg->u.dbg_cfg.num_counters <= max_counters)
+			for (i = 0; i < max_counters; i++)
+				top_priv->perf_counters[i].perf_counter_val =
+					debug_cfg->u.dbg_cfg.sfe_perf_counter_val[i];
 	}
 
 	return 0;
@@ -1059,6 +1110,15 @@ int cam_sfe_top_process_cmd(void *priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
 		rc = cam_sfe_top_apply_clk_bw_update(top_priv, cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_QUERY_CAP: {
+		struct cam_isp_hw_cap *sfe_cap;
+
+		sfe_cap = (struct cam_isp_hw_cap *) cmd_args;
+		sfe_cap->num_perf_counters =
+			top_priv->common_data.common_reg->num_perf_counters;
+		rc = 0;
+	}
+	break;
 	default:
 		CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type);
 		rc = -EINVAL;
@@ -1217,7 +1277,6 @@ static int cam_sfe_top_put_evt_payload(
 	return 0;
 }
 
-
 static int cam_sfe_top_handle_err_irq_top_half(
 	uint32_t evt_id,
 	struct cam_irq_th_payload *th_payload)
@@ -1470,13 +1529,17 @@ static int cam_sfe_top_handle_irq_bottom_half(
 				cam_sfe_top_sel_frame_counter(
 					res->res_id, &frame_cnt,
 					true, path_data);
-			}
+
+			cam_sfe_top_dump_perf_counters("SOF", res->res_name, top_priv);
+		}
 
 		if (irq_status[0] &
 			path_data->path_reg_data->eof_irq_mask) {
 			CAM_DBG(CAM_SFE, "SFE:%d Received %s EOF",
 				res->hw_intf->hw_idx,
 				res->res_name);
+
+			cam_sfe_top_dump_perf_counters("EOF", res->res_name, top_priv);
 		}
 		ret = CAM_SFE_IRQ_STATUS_SUCCESS;
 	}
@@ -1557,27 +1620,44 @@ int cam_sfe_top_start(
 		}
 	}
 
-	/* Enable debug cfg registers */
-	cam_io_w(path_data->common_reg_data->top_debug_cfg_en,
-		path_data->mem_base +
-		path_data->common_reg->top_debug_cfg);
-
-	/* Enables the context controller testbus*/
-	if (path_data->common_reg->top_cc_test_bus_supported) {
-		for (i = 0; i < top_priv->hw_info->num_of_testbus; i++) {
-			if ((top_priv->sfe_debug_cfg &
-				top_priv->hw_info->test_bus_info[i].debugfs_val) ||
-				top_priv->hw_info->test_bus_info[i].enable) {
-				top_priv->cc_testbus_sel_cfg =
-					top_priv->hw_info->test_bus_info[i].value;
-				break;
+	/* First resource stream on */
+	if (!top_priv->start_stop_cnt) {
+
+		/* Enable debug cfg registers */
+		cam_io_w(path_data->common_reg_data->top_debug_cfg_en,
+			path_data->mem_base +
+			path_data->common_reg->top_debug_cfg);
+
+		/* Enables the context controller testbus*/
+		if (path_data->common_reg->top_cc_test_bus_supported) {
+			for (i = 0; i < top_priv->hw_info->num_of_testbus; i++) {
+				if ((top_priv->sfe_debug_cfg &
+					top_priv->hw_info->test_bus_info[i].debugfs_val) ||
+					top_priv->hw_info->test_bus_info[i].enable) {
+					top_priv->cc_testbus_sel_cfg =
+						top_priv->hw_info->test_bus_info[i].value;
+					break;
+				}
 			}
+
+			if (top_priv->cc_testbus_sel_cfg)
+				cam_io_w(top_priv->cc_testbus_sel_cfg,
+					path_data->mem_base +
+					path_data->common_reg->top_cc_test_bus_ctrl);
 		}
 
-		if (top_priv->cc_testbus_sel_cfg)
-			cam_io_w(top_priv->cc_testbus_sel_cfg,
+		for (i = 0; i < top_priv->common_data.common_reg->num_perf_counters; i++) {
+			if (!top_priv->perf_counters[i].perf_counter_val)
+				continue;
+
+			top_priv->perf_counters[i].dump_counter = true;
+			cam_io_w_mb(top_priv->perf_counters[i].perf_counter_val,
 				path_data->mem_base +
-				path_data->common_reg->top_cc_test_bus_ctrl);
+				path_data->common_reg->perf_count_reg[i].perf_count_cfg);
+			CAM_DBG(CAM_SFE, "SFE [%u] perf_count_%d: 0x%x",
+				hw_info->soc_info.index, (i + 1),
+				top_priv->perf_counters[i].perf_counter_val);
+		}
 	}
 
 	/* Enable sensor diag info */
@@ -1748,6 +1828,14 @@ int cam_sfe_top_stop(
 				top_priv->error_irq_handle);
 			top_priv->error_irq_handle = 0;
 		}
+
+		/* Reset perf counters at stream off */
+		for (i = 0; i <  top_priv->common_data.common_reg->num_perf_counters; i++) {
+			if (top_priv->perf_counters[i].dump_counter)
+				cam_io_w_mb(0x0, path_data->mem_base +
+					path_data->common_reg->perf_count_reg[i].perf_count_cfg);
+			top_priv->perf_counters[i].dump_counter = false;
+		}
 	}
 
 	return 0;

+ 14 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SFE_TOP_H_
@@ -21,6 +22,7 @@
 
 #define CAM_SFE_TOP_DBG_REG_MAX                18
 #define CAM_SFE_TOP_TESTBUS_MAX                 2
+#define CAM_SFE_PERF_COUNTER_MAX                2
 
 struct cam_sfe_top_module_desc {
 	uint32_t id;
@@ -67,6 +69,15 @@ struct cam_sfe_testbus_info {
 	struct cam_sfe_top_cc_testbus_info *testbus;
 };
 
+struct cam_sfe_top_perf_count_reg_offset {
+	uint32_t perf_count_cfg;
+	uint32_t perf_pix_count;
+	uint32_t perf_line_count;
+	uint32_t perf_stall_count;
+	uint32_t perf_always_count;
+	uint32_t perf_count_status;
+};
+
 struct cam_sfe_top_common_reg_offset {
 	uint32_t hw_version;
 	uint32_t hw_capability;
@@ -89,6 +100,9 @@ struct cam_sfe_top_common_reg_offset {
 	uint32_t irc_throttle_cfg;
 	uint32_t sfe_single_dual_cfg;
 	uint32_t bus_overflow_status;
+	uint32_t num_perf_counters;
+	struct cam_sfe_top_perf_count_reg_offset
+		perf_count_reg[CAM_SFE_PERF_COUNTER_MAX];
 	uint32_t top_debug_cfg;
 	uint32_t top_cc_test_bus_ctrl;
 	bool     lcr_supported;

+ 12 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.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/delay.h>
@@ -533,8 +534,6 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_UNMASK_BUS_WR_IRQ:
 	case CAM_ISP_HW_CMD_DUMP_BUS_INFO:
 	case CAM_ISP_HW_CMD_GET_RES_FOR_MID:
-	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
-	case CAM_ISP_HW_CMD_IFE_BUS_DEBUG_CFG:
 	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
 	case CAM_ISP_HW_BUS_MINI_DUMP:
 	case CAM_ISP_HW_CMD_BUF_UPDATE:
@@ -555,6 +554,17 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 		*((struct cam_hw_soc_info **)cmd_args) = soc_info;
 		rc = 0;
 		break;
+	case CAM_ISP_HW_CMD_QUERY_CAP:
+	case CAM_ISP_HW_CMD_IFE_DEBUG_CFG:
+		/* forward to bus and top */
+		core_info->vfe_bus->hw_ops.process_cmd(
+			core_info->vfe_bus->bus_priv, cmd_type, cmd_args,
+			arg_size);
+
+		core_info->vfe_top->hw_ops.process_cmd(
+			core_info->vfe_top->top_priv, cmd_type, cmd_args,
+			arg_size);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "Invalid cmd type:%d", cmd_type);
 		rc = -EINVAL;

+ 20 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe680.h

@@ -1,6 +1,7 @@
 /* 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.
  */
 
 #ifndef _CAM_VFE680_H_
@@ -507,6 +508,25 @@ static struct cam_vfe_top_ver4_reg_offset_common vfe680_top_common_reg = {
 	.epoch_height_cfg         = 0x0000009C,
 	.bus_violation_status     = 0x00000C64,
 	.bus_overflow_status      = 0x00000C68,
+	.num_perf_counters        = 2,
+	.perf_count_reg = {
+		{
+			.perf_count_cfg    = 0x00000100,
+			.perf_pix_count    = 0x00000104,
+			.perf_line_count   = 0x00000108,
+			.perf_stall_count  = 0x0000010C,
+			.perf_always_count = 0x00000110,
+			.perf_count_status = 0x00000114,
+		},
+		{
+			.perf_count_cfg    = 0x00000118,
+			.perf_pix_count    = 0x0000011C,
+			.perf_line_count   = 0x00000120,
+			.perf_stall_count  = 0x00000124,
+			.perf_always_count = 0x00000128,
+			.perf_count_status = 0x0000012C,
+		},
+	},
 	.top_debug_cfg            = 0x000000FC,
 	.num_top_debug_reg        = CAM_VFE_680_NUM_DBG_REG,
 	.top_debug = {

+ 20 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe780.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_VFE780_H_
@@ -547,6 +548,25 @@ static struct cam_vfe_top_ver4_reg_offset_common vfe780_top_common_reg = {
 	.epoch_height_cfg         = 0x0000009C,
 	.bus_violation_status     = 0x00000C64,
 	.bus_overflow_status      = 0x00000C68,
+	.num_perf_counters        = 2,
+	.perf_count_reg = {
+		{
+			.perf_count_cfg    = 0x00000100,
+			.perf_pix_count    = 0x00000104,
+			.perf_line_count   = 0x00000108,
+			.perf_stall_count  = 0x0000010C,
+			.perf_always_count = 0x00000110,
+			.perf_count_status = 0x00000114,
+		},
+		{
+			.perf_count_cfg    = 0x00000118,
+			.perf_pix_count    = 0x0000011C,
+			.perf_line_count   = 0x00000120,
+			.perf_stall_count  = 0x00000124,
+			.perf_always_count = 0x00000128,
+			.perf_count_status = 0x0000012C,
+		},
+	},
 	.top_debug_cfg            = 0x000000FC,
 	.num_top_debug_reg        = CAM_VFE_780_NUM_DBG_REG,
 	.pdaf_input_cfg_0         = 0x00000130,

+ 4 - 3
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/ratelimit.h>
@@ -3805,7 +3806,7 @@ static int cam_vfe_bus_process_cmd(
 	int rc = -EINVAL;
 	struct cam_vfe_bus_ver2_priv		 *bus_priv;
 	uint32_t top_mask_0 = 0;
-	struct cam_isp_hw_bus_cap *vfe_bus_cap;
+	struct cam_isp_hw_cap *vfe_bus_cap;
 
 
 	if (!priv || !cmd_args) {
@@ -3857,9 +3858,9 @@ static int cam_vfe_bus_process_cmd(
 		bus_priv = (struct cam_vfe_bus_ver2_priv *) priv;
 		rc = cam_vfe_bus_get_res_for_mid(bus_priv, cmd_args, arg_size);
 		break;
-	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
+	case CAM_ISP_HW_CMD_QUERY_CAP:
 		bus_priv = (struct cam_vfe_bus_ver2_priv  *) priv;
-		vfe_bus_cap = (struct cam_isp_hw_bus_cap *) cmd_args;
+		vfe_bus_cap = (struct cam_isp_hw_cap *) cmd_args;
 		vfe_bus_cap->max_out_res_type = bus_priv->max_out_res;
 		vfe_bus_cap->support_consumed_addr =
 			bus_priv->common_data.support_consumed_addr;

+ 10 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c

@@ -4271,7 +4271,7 @@ static int cam_vfe_bus_ver3_process_cmd(
 	int rc = -EINVAL;
 	struct cam_vfe_bus_ver3_priv		 *bus_priv;
 	uint32_t top_mask_0 = 0;
-	struct cam_isp_hw_bus_cap *vfe_bus_cap;
+	struct cam_isp_hw_cap *vfe_bus_cap;
 
 
 	if (!priv || !cmd_args) {
@@ -4344,22 +4344,27 @@ static int cam_vfe_bus_ver3_process_cmd(
 		bus_priv = (struct cam_vfe_bus_ver3_priv *) priv;
 		rc = cam_vfe_bus_get_res_for_mid(bus_priv, cmd_args, arg_size);
 		break;
-	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
+	case CAM_ISP_HW_CMD_QUERY_CAP:
 		bus_priv = (struct cam_vfe_bus_ver3_priv  *) priv;
-		vfe_bus_cap = (struct cam_isp_hw_bus_cap *) cmd_args;
+		vfe_bus_cap = (struct cam_isp_hw_cap *) cmd_args;
 		vfe_bus_cap->max_out_res_type = bus_priv->max_out_res;
 		vfe_bus_cap->support_consumed_addr =
 			bus_priv->common_data.support_consumed_addr;
 		break;
-	case CAM_ISP_HW_CMD_IFE_BUS_DEBUG_CFG:
+	case CAM_ISP_HW_CMD_IFE_DEBUG_CFG: {
+		struct cam_vfe_generic_debug_config *debug_cfg;
+
 		bus_priv = (struct cam_vfe_bus_ver3_priv  *) priv;
+		debug_cfg = (struct cam_vfe_generic_debug_config *)cmd_args;
 		bus_priv->common_data.disable_mmu_prefetch =
-			(*((bool *)cmd_args));
+			debug_cfg->disable_ife_mmu_prefetch;
+
 		CAM_DBG(CAM_ISP, "IFE: %u bus WR prefetch %s",
 			bus_priv->common_data.core_index,
 			bus_priv->common_data.disable_mmu_prefetch ?
 			"disabled" : "enabled");
 		rc = 0;
+	}
 		break;
 	case CAM_ISP_HW_CMD_BUF_UPDATE:
 		rc = cam_vfe_bus_ver3_config_wm(priv, cmd_args, arg_size);

+ 105 - 12
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c

@@ -28,12 +28,18 @@ struct cam_vfe_top_ver4_common_data {
 	struct cam_vfe_top_ver4_hw_info            *hw_info;
 };
 
+struct cam_vfe_top_ver4_perf_counter_cfg {
+	uint32_t perf_counter_val;
+	bool     dump_counter;
+};
+
 struct cam_vfe_top_ver4_priv {
-	struct cam_vfe_top_ver4_common_data common_data;
-	struct cam_vfe_top_priv_common      top_common;
-	atomic_t                            overflow_pending;
-	uint8_t                             log_buf[CAM_VFE_LEN_LOG_BUF];
-	uint32_t                            sof_cnt;
+	struct cam_vfe_top_ver4_common_data      common_data;
+	struct cam_vfe_top_priv_common           top_common;
+	atomic_t                                 overflow_pending;
+	uint8_t                                  log_buf[CAM_VFE_LEN_LOG_BUF];
+	uint32_t                                 sof_cnt;
+	struct cam_vfe_top_ver4_perf_counter_cfg perf_counters[CAM_VFE_PERF_COUNTER_MAX];
 };
 
 enum cam_vfe_top_ver4_fsm_state {
@@ -379,6 +385,39 @@ static void cam_vfe_top_ver4_print_top_irq_error(
 		cam_vfe_top_ver4_print_pdaf_violation_info(vfe_priv);
 }
 
+static void cam_vfe_top_dump_perf_counters(
+	const char *event,
+	const char *res_name,
+	struct cam_vfe_top_ver4_priv *top_priv)
+{
+	int i;
+	void __iomem                              *mem_base;
+	struct cam_hw_soc_info                    *soc_info;
+	struct cam_vfe_top_ver4_reg_offset_common *common_reg;
+
+	soc_info = top_priv->top_common.soc_info;
+	common_reg = top_priv->common_data.common_reg;
+	mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base;
+
+	for (i = 0; i < top_priv->common_data.common_reg->num_perf_counters; i++) {
+		if (top_priv->perf_counters[i].dump_counter) {
+			CAM_INFO(CAM_ISP,
+				"VFE [%u] on %s %s counter: %d pixel_cnt: %d line_cnt: %d stall_cnt: %d always_cnt: %d status: 0x%x",
+				top_priv->common_data.hw_intf->hw_idx, res_name, event, (i + 1),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_pix_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_line_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_stall_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_always_count),
+				cam_io_r_mb(mem_base +
+					common_reg->perf_count_reg[i].perf_count_status));
+		}
+	}
+}
+
 static void cam_vfe_top_ver4_print_debug_reg_status(
 	struct cam_vfe_top_ver4_priv *top_priv)
 {
@@ -413,6 +452,7 @@ static void cam_vfe_top_ver4_print_debug_reg_status(
 
 	cam_vfe_top_ver4_check_module_status(num_reg, reg_val,
 		top_priv->common_data.hw_info->debug_reg_info);
+	cam_vfe_top_dump_perf_counters("ERROR", "", top_priv);
 }
 
 int cam_vfe_top_ver4_dump_timestamps(
@@ -806,12 +846,12 @@ int cam_vfe_top_ver4_release(void *device_priv,
 int cam_vfe_top_ver4_start(void *device_priv,
 	void *start_args, uint32_t arg_size)
 {
-	struct cam_vfe_top_ver4_priv            *top_priv;
-	struct cam_isp_resource_node            *mux_res;
-	struct cam_hw_info                      *hw_info = NULL;
-	struct cam_hw_soc_info                  *soc_info = NULL;
-	struct cam_vfe_soc_private              *soc_private = NULL;
-	int rc = 0;
+	struct cam_vfe_top_ver4_priv     *top_priv;
+	struct cam_isp_resource_node     *mux_res;
+	struct cam_hw_info               *hw_info = NULL;
+	struct cam_hw_soc_info           *soc_info = NULL;
+	struct cam_vfe_soc_private       *soc_private = NULL;
+	int rc = 0, i;
 
 	if (!device_priv || !start_args) {
 		CAM_ERR(CAM_ISP, "Error, Invalid input arguments");
@@ -853,6 +893,20 @@ int cam_vfe_top_ver4_start(void *device_priv,
 				"Invalid res id:%d", mux_res->res_id);
 			rc = -EINVAL;
 		}
+
+		/* Perf counter config */
+		for (i = 0; i < top_priv->common_data.common_reg->num_perf_counters; i++) {
+			if (!top_priv->perf_counters[i].perf_counter_val)
+				continue;
+
+			top_priv->perf_counters[i].dump_counter = true;
+			cam_io_w_mb(top_priv->perf_counters[i].perf_counter_val,
+				soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base +
+				top_priv->common_data.common_reg->perf_count_reg[i].perf_count_cfg);
+			CAM_DBG(CAM_ISP, "VFE [%u] perf_count_%d: 0x%x",
+				hw_info->soc_info.index, (i + 1),
+				top_priv->perf_counters[i].perf_counter_val);
+		}
 	} else {
 		CAM_ERR(CAM_ISP, "VFE HW not powered up");
 		rc = -EPERM;
@@ -867,6 +921,7 @@ int cam_vfe_top_ver4_stop(void *device_priv,
 {
 	struct cam_vfe_top_ver4_priv            *top_priv;
 	struct cam_isp_resource_node            *mux_res;
+	struct cam_hw_soc_info                  *soc_info = NULL;
 	struct cam_hw_info                      *hw_info = NULL;
 	int i, rc = 0;
 
@@ -876,6 +931,7 @@ int cam_vfe_top_ver4_stop(void *device_priv,
 	}
 
 	top_priv = (struct cam_vfe_top_ver4_priv   *)device_priv;
+	soc_info = top_priv->top_common.soc_info;
 	mux_res = (struct cam_isp_resource_node *)stop_args;
 	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
@@ -901,6 +957,15 @@ int cam_vfe_top_ver4_stop(void *device_priv,
 		}
 	}
 
+	/* Reset perf counters at stream off */
+	for (i = 0; i < top_priv->common_data.common_reg->num_perf_counters; i++) {
+		if (top_priv->perf_counters[i].dump_counter)
+			cam_io_w_mb(0x0,
+				soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base +
+				top_priv->common_data.common_reg->perf_count_reg[i].perf_count_cfg);
+		top_priv->perf_counters[i].dump_counter = false;
+	}
+
 	atomic_set(&top_priv->overflow_pending, 0);
 	return rc;
 }
@@ -993,6 +1058,26 @@ int cam_vfe_top_ver4_process_cmd(void *device_priv, uint32_t cmd_type,
 		rc = cam_vfe_top_ver4_pdaf_lcr_config(top_priv, cmd_args,
 			arg_size);
 		break;
+	case CAM_ISP_HW_CMD_QUERY_CAP: {
+		struct cam_isp_hw_cap *ife_cap;
+
+		ife_cap = (struct cam_isp_hw_cap *) cmd_args;
+		ife_cap->num_perf_counters =
+			top_priv->common_data.common_reg->num_perf_counters;
+	}
+		break;
+	case CAM_ISP_HW_CMD_IFE_DEBUG_CFG: {
+		int i;
+		uint32_t max_counters = top_priv->common_data.common_reg->num_perf_counters;
+		struct cam_vfe_generic_debug_config *debug_cfg;
+
+		debug_cfg = (struct cam_vfe_generic_debug_config *)cmd_args;
+		if (debug_cfg->num_counters <= max_counters)
+			for (i = 0; i < max_counters; i++)
+				top_priv->perf_counters[i].perf_counter_val =
+					debug_cfg->vfe_perf_counter_val[i];
+	}
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);
@@ -1282,7 +1367,6 @@ static int cam_vfe_handle_frame_timing_irqs(struct cam_isp_resource_node *vfe_re
 	return CAM_VFE_IRQ_STATUS_SUCCESS;
 }
 
-
 static int cam_vfe_handle_irq_bottom_half(void *handler_priv,
 	void *evt_payload_priv)
 {
@@ -1364,6 +1448,15 @@ static int cam_vfe_handle_irq_bottom_half(void *handler_priv,
 			vfe_priv->common_reg->diag_sensor_status_0));
 	}
 
+	/* Perf counter dump */
+	if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] &
+		vfe_priv->reg_data->eof_irq_mask)
+		cam_vfe_top_dump_perf_counters("EOF", vfe_res->res_name, vfe_priv->top_priv);
+
+	if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] &
+		vfe_priv->reg_data->sof_irq_mask)
+		cam_vfe_top_dump_perf_counters("SOF", vfe_res->res_name, vfe_priv->top_priv);
+
 	cam_vfe_top_put_evt_payload(vfe_priv, &payload);
 
 	CAM_DBG(CAM_ISP, "returning status = %d", ret);

+ 14 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.h

@@ -1,6 +1,7 @@
 /* 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.
  */
 
 #ifndef _CAM_VFE_TOP_VER4_H_
@@ -13,6 +14,16 @@
 #define CAM_VFE_RDI_VER2_MAX                           4
 #define CAM_VFE_CAMIF_LITE_EVT_MAX                     256
 #define CAM_VFE_TOP_DBG_REG_MAX                        17
+#define CAM_VFE_PERF_COUNTER_MAX                       2
+
+struct cam_vfe_top_ver4_perf_count_reg_offset {
+	uint32_t perf_count_cfg;
+	uint32_t perf_pix_count;
+	uint32_t perf_line_count;
+	uint32_t perf_stall_count;
+	uint32_t perf_always_count;
+	uint32_t perf_count_status;
+};
 
 struct cam_vfe_top_ver4_reg_offset_common {
 	uint32_t hw_version;
@@ -56,6 +67,9 @@ struct cam_vfe_top_ver4_reg_offset_common {
 	uint32_t epoch0_pattern_cfg;
 	uint32_t epoch1_pattern_cfg;
 	uint32_t epoch_height_cfg;
+	uint32_t num_perf_counters;
+	struct cam_vfe_top_ver4_perf_count_reg_offset
+		perf_count_reg[CAM_VFE_PERF_COUNTER_MAX];
 	uint32_t top_debug_cfg;
 	uint32_t pdaf_input_cfg_0;
 	uint32_t pdaf_input_cfg_1;