Parcourir la source

msm: camera: cpas: Support Multiple HW Capability Registers

Update CPAS HW driver to read multiple hw caps registers for v880
and v980 targets. Upgate CPAS API interface to provide multiple camera
caps to clients.

Move hw capability register offsets to cpas header files.

Update ICP driver to check the second hw capability mask
for OFE presence.

Based on the type of device(ICP/IPE/BPS/OFE) populated from DT, verify
with cpas titan hw capability to check if the device is supported for
the target. Verifying CPAS HW capability after populated devices from DT
removes the need for checking CPAS HW version.

CRs-Fixed: 3405111
Change-Id: I11a58920d97f25908e6bde49fd918b2cc90c1479
Signed-off-by: Sokchetra Eung <[email protected]>
Sokchetra Eung il y a 2 ans
Parent
commit
ac82a263b7
35 fichiers modifiés avec 438 ajouts et 152 suppressions
  1. 7 2
      drivers/cam_cpas/cam_cpas_hw_intf.h
  2. 16 7
      drivers/cam_cpas/cam_cpas_intf.c
  3. 86 34
      drivers/cam_cpas/cpas_top/cam_cpastop_hw.c
  4. 25 0
      drivers/cam_cpas/cpas_top/cam_cpastop_hw.h
  5. 8 0
      drivers/cam_cpas/cpas_top/cpastop100.h
  6. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v150_100.h
  7. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v165_100.h
  8. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v170_110.h
  9. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v170_200.h
  10. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v175_100.h
  11. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v175_101.h
  12. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v175_120.h
  13. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v175_130.h
  14. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v480_100.h
  15. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v480_custom.h
  16. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v520_100.h
  17. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v540_100.h
  18. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v545_100.h
  19. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v570_100.h
  20. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v570_200.h
  21. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v580_100.h
  22. 8 0
      drivers/cam_cpas/cpas_top/cpastop_v580_custom.h
  23. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v640_200.h
  24. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v680_100.h
  25. 11 1
      drivers/cam_cpas/cpas_top/cpastop_v680_110.h
  26. 11 1
      drivers/cam_cpas/cpas_top/cpastop_v780_100.h
  27. 10 0
      drivers/cam_cpas/cpas_top/cpastop_v880_100.h
  28. 11 0
      drivers/cam_cpas/cpas_top/cpastop_v980_100.h
  29. 5 4
      drivers/cam_cpas/include/cam_cpas_api.h
  30. 55 89
      drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
  31. 2 0
      drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
  32. 9 1
      drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
  33. 1 8
      drivers/cam_icp/icp_hw/icp_proc/cam_icp_proc.c
  34. 1 1
      drivers/cam_icp/icp_hw/icp_proc/cam_icp_proc.h
  35. 4 4
      drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c

+ 7 - 2
drivers/cam_cpas/cam_cpas_hw_intf.h

@@ -23,6 +23,9 @@
 /* Number of times to retry while polling */
 #define CAM_CPAS_POLL_QH_RETRY_CNT 50
 
+/* Number of CPAS hw caps registers */
+#define CAM_CPAS_MAX_CAPS_REGS 2
+
 /**
  * enum cam_cpas_hw_type - Enum for CPAS HW type
  */
@@ -169,7 +172,8 @@ struct cam_cpas_hw_cmd_notify_event {
  * @camera_family: Camera family type
  * @camera_version: Camera version
  * @cpas_version: CPAS version
- * @camera_capability: Camera hw capabilities
+ * @camera_capability: array of camera hw capabilities
+ * @num_capability_reg: Number of camera hw capabilities registers
  * @fuse_info: Fuse information
  *
  */
@@ -177,7 +181,8 @@ struct cam_cpas_hw_caps {
 	uint32_t camera_family;
 	struct cam_hw_version camera_version;
 	struct cam_hw_version cpas_version;
-	uint32_t camera_capability;
+	uint32_t camera_capability[CAM_CPAS_MAX_CAPS_REGS];
+	uint32_t num_capability_reg;
 	struct cam_cpas_fuse_info fuse_info;
 };
 

+ 16 - 7
drivers/cam_cpas/cam_cpas_intf.c

@@ -385,7 +385,7 @@ int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
 int cam_cpas_get_hw_info(uint32_t *camera_family,
 	struct cam_hw_version *camera_version,
 	struct cam_hw_version *cpas_version,
-	uint32_t *cam_caps,
+	uint32_t **cam_caps, uint32_t *num_cap_mask,
 	struct cam_cpas_fuse_info *cam_fuse_info,
 	struct cam_cpas_domain_id_caps *domain_id_info)
 {
@@ -399,9 +399,9 @@ int cam_cpas_get_hw_info(uint32_t *camera_family,
 		return -ENODEV;
 	}
 
-	if (!camera_family || !camera_version || !cpas_version || !cam_caps) {
-		CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK",
-			camera_family, camera_version, cpas_version, cam_caps);
+	if (!camera_family || !camera_version || !cpas_version || !cam_caps || !num_cap_mask) {
+		CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK %pK",
+			camera_family, camera_version, cpas_version, cam_caps, num_cap_mask);
 		return -EINVAL;
 	}
 
@@ -413,6 +413,8 @@ int cam_cpas_get_hw_info(uint32_t *camera_family,
 	*camera_version = g_cpas_intf->hw_caps.camera_version;
 	*cpas_version   = g_cpas_intf->hw_caps.cpas_version;
 	*cam_caps       = g_cpas_intf->hw_caps.camera_capability;
+	*num_cap_mask   = g_cpas_intf->hw_caps.num_capability_reg;
+
 	if (cam_fuse_info)
 		*cam_fuse_info  = g_cpas_intf->hw_caps.fuse_info;
 	if (domain_id_info) {
@@ -1003,6 +1005,7 @@ int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
 	struct cam_control *cmd)
 {
 	int rc = 0;
+	uint32_t *camera_capability, num_cap_mask;
 
 	if (!cmd) {
 		CAM_ERR(CAM_CPAS, "Invalid input cmd");
@@ -1023,10 +1026,12 @@ int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
 
 		rc = cam_cpas_get_hw_info(&query.camera_family,
 			&query.camera_version, &query.cpas_version,
-			&query.reserved, NULL, NULL);
+			&camera_capability, &num_cap_mask, NULL, NULL);
 		if (rc)
 			break;
 
+		query.reserved = camera_capability[0];
+
 		rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
 			sizeof(query));
 		if (rc)
@@ -1047,11 +1052,13 @@ int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
 
 		rc = cam_cpas_get_hw_info(&query.camera_family,
 			&query.camera_version, &query.cpas_version,
-			&query.reserved,
+			&camera_capability, &num_cap_mask,
 			&query.fuse_info, NULL);
 		if (rc)
 			break;
 
+		query.reserved = camera_capability[0];
+
 		rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
 			sizeof(query));
 		if (rc)
@@ -1072,11 +1079,13 @@ int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
 
 		rc = cam_cpas_get_hw_info(&query.camera_family,
 			&query.camera_version, &query.cpas_version,
-			&query.camera_caps, &query.fuse_info,
+			&camera_capability, &num_cap_mask, &query.fuse_info,
 			&query.domain_id_info);
 		if (rc)
 			break;
 
+		query.camera_caps = camera_capability[0];
+
 		rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
 			sizeof(query));
 		if (rc)

+ 86 - 34
drivers/cam_cpas/cpas_top/cam_cpastop_hw.c

@@ -42,7 +42,7 @@
 #include "cam_common_util.h"
 
 struct cam_camnoc_info *camnoc_info[CAM_CAMNOC_HW_TYPE_MAX];
-struct cam_cpas_camnoc_qchannel *qchannel_info[CAM_CAMNOC_HW_TYPE_MAX];
+struct cam_cpas_info *cpas_info;
 
 #if (defined(CONFIG_CAM_TEST_IRQ_LINE) && defined(CONFIG_CAM_TEST_IRQ_LINE_AT_PROBE))
 	struct completion test_irq_hw_complete[CAM_CAMNOC_HW_TYPE_MAX];
@@ -324,13 +324,14 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw,
 	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
 	int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP];
-	uint32_t reg_value;
 	uint32_t cam_version, cpas_version;
 	uint32_t cam_version_id, cpas_version_id;
 	int rc;
 
-	if (reg_indx == -1)
+	if (reg_indx == -1) {
+		CAM_ERR(CAM_CPAS, "Invalid arguments");
 		return -EINVAL;
+	}
 
 	hw_caps->camera_family = CAM_FAMILY_CPAS_SS;
 
@@ -350,14 +351,11 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw,
 	hw_caps->cpas_version.incr =
 		CAM_BITS_MASK_SHIFT(cpas_version, 0xffff, 0x0);
 
-	reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x8);
-	hw_caps->camera_capability = reg_value;
-
-	CAM_DBG(CAM_CPAS, "Family %d, version %d.%d.%d, cpas %d.%d.%d, cap 0x%x",
+	CAM_DBG(CAM_CPAS, "Family %d, version %d.%d.%d, cpas %d.%d.%d",
 		hw_caps->camera_family, hw_caps->camera_version.major,
 		hw_caps->camera_version.minor, hw_caps->camera_version.incr,
 		hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
-		hw_caps->cpas_version.incr, hw_caps->camera_capability);
+		hw_caps->cpas_version.incr);
 
 	soc_info->hw_version = CAM_CPAS_TITAN_NONE;
 	rc = cam_cpas_translate_camera_cpas_version_id(cam_version,
@@ -370,6 +368,7 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw,
 
 	soc_info->hw_version =
 		cam_cpas_hw_version_map[cam_version_id][cpas_version_id];
+
 	CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version);
 
 	return 0;
@@ -1082,11 +1081,14 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
 		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
 	struct cam_cpas_hw_errata_wa_list *errata_wa_list;
 	bool icp_clk_enabled = false;
+	struct cam_cpas_camnoc_qchannel *qchannel_info;
 
 	if (reg_indx == -1)
 		return -EINVAL;
 
-	for (i = 0; i < cpas_core->num_valid_camnoc; i++) {
+	for (i = 0; i < cpas_info->num_qchannel; i++) {
+		qchannel_info = cpas_info->qchannel_info[i];
+
 		if (!icp_clk_enabled) {
 			errata_wa_list = camnoc_info[i]->errata_wa_list;
 			if (errata_wa_list && errata_wa_list->enable_icp_clk_for_qchannel.enable) {
@@ -1112,7 +1114,7 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
 			if (force_on) {
 				cam_io_w_mb(0x1,
 					soc_info->reg_map[reg_indx].mem_base +
-					qchannel_info[i]->qchannel_ctrl);
+					qchannel_info->qchannel_ctrl);
 				CAM_DBG(CAM_CPAS, "Force qchannel on for %s",
 						camnoc_info[i]->camnoc_name);
 			}
@@ -1123,7 +1125,7 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
 
 			/* Clear the quiecience request in QCHANNEL ctrl*/
 			cam_io_w_mb(0, soc_info->reg_map[reg_indx].mem_base +
-				qchannel_info[i]->qchannel_ctrl);
+				qchannel_info->qchannel_ctrl);
 			/* wait for QACCEPTN and QDENY in QCHANNEL status*/
 			mask = BIT(1) | BIT(0);
 			wait_data = 0;
@@ -1131,23 +1133,22 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
 
 		rc = cam_io_poll_value_wmask(
 			soc_info->reg_map[reg_indx].mem_base +
-			qchannel_info[i]->qchannel_status,
+			qchannel_info->qchannel_status,
 			wait_data, mask, CAM_CPAS_POLL_QH_RETRY_CNT,
 			CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS);
 		if (rc) {
 			CAM_ERR(CAM_CPAS,
 				"CPAS_%s %s idle sequence failed, qstat 0x%x",
 				power_on ? "START" : "STOP", camnoc_info[i]->camnoc_name,
-				cam_io_r(soc_info->reg_map[reg_indx].mem_base +
-					qchannel_info[i]->qchannel_status));
+			cam_io_r(soc_info->reg_map[reg_indx].mem_base +
+				qchannel_info->qchannel_status));
 			ret = rc;
 			/* Do not return error, passthrough */
 		}
 
 		/* check if deny bit is set */
 		qchannel_status = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base +
-			qchannel_info[i]->qchannel_status);
-
+			qchannel_info->qchannel_status);
 		CAM_DBG(CAM_CPAS,
 			"CPAS_%s %s : qchannel status 0x%x", power_on ? "START" : "STOP",
 			camnoc_info[i]->camnoc_name, qchannel_status);
@@ -1168,7 +1169,7 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
 }
 
 static int cam_cpastop_set_up_camnoc_info(struct cam_cpas *cpas_core,
-	struct cam_camnoc_info **alloc_camnoc, struct cam_cpas_camnoc_qchannel **alloc_qchannel)
+	struct cam_camnoc_info **alloc_camnoc)
 {
 	int i, j, camnoc_cnt = 0;
 
@@ -1178,7 +1179,6 @@ static int cam_cpastop_set_up_camnoc_info(struct cam_cpas *cpas_core,
 			camnoc_info[camnoc_cnt] = alloc_camnoc[i];
 			cpas_core->camnoc_info[camnoc_cnt] = alloc_camnoc[i];
 			cpas_core->camnoc_info_idx[i] = camnoc_cnt;
-			qchannel_info[camnoc_cnt] = alloc_qchannel[i];
 
 			switch (i) {
 			case CAM_CAMNOC_HW_COMBINED:
@@ -1212,6 +1212,12 @@ static int cam_cpastop_set_up_camnoc_info(struct cam_cpas *cpas_core,
 		return -EINVAL;
 	}
 
+	if (cpas_info->num_qchannel && cpas_info->num_qchannel != camnoc_cnt) {
+		CAM_ERR(CAM_CPAS, "Invalid number of qchannel: %u number of camnoc: %u",
+			cpas_info->num_qchannel, camnoc_cnt);
+		return -EINVAL;
+	}
+
 	cpas_core->num_valid_camnoc = camnoc_cnt;
 
 	if (cpas_core->camnoc_info_idx[CAM_CAMNOC_HW_COMBINED] >= 0)
@@ -1241,6 +1247,36 @@ static int cam_cpastop_set_up_camnoc_info(struct cam_cpas *cpas_core,
 	return 0;
 }
 
+static int cam_cpastop_get_hw_capability(struct cam_hw_info *cpas_hw)
+{
+	int i, reg_idx;
+	struct cam_cpas *cpas_core = cpas_hw->core_info;
+	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+	struct cam_cpas_hw_cap_info *hw_caps_info;
+	struct cam_cpas_hw_caps *hw_caps = &cpas_core->hw_caps;
+
+	hw_caps_info = &cpas_info->hw_caps_info;
+	reg_idx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP];
+
+	/* At least one hw caps register must be present */
+	if (!hw_caps_info->num_caps_registers ||
+		hw_caps_info->num_caps_registers > CAM_CPAS_MAX_CAPS_REGS) {
+		CAM_ERR(CAM_CPAS,
+			"Invalid number of populated caps registers: %u",
+			hw_caps_info->num_caps_registers);
+		return -EINVAL;
+	}
+
+	hw_caps->num_capability_reg = hw_caps_info->num_caps_registers;
+	for (i = 0; i < hw_caps_info->num_caps_registers; i++) {
+		hw_caps->camera_capability[i] = cam_io_r_mb(soc_info->reg_map[reg_idx].mem_base +
+			hw_caps_info->hw_caps_offsets[i]);
+		CAM_DBG(CAM_CPAS, "camera_caps_%d = 0x%x", i, hw_caps->camera_capability[i]);
+	}
+
+	return 0;
+}
+
 static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 	struct cam_cpas_hw_caps *hw_caps)
 {
@@ -1249,7 +1285,6 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 	struct cam_cpas_cesta_info *cesta_info = NULL;
 	struct cam_camnoc_info *alloc_camnoc_info[CAM_CAMNOC_HW_TYPE_MAX] = {0};
-	struct cam_cpas_camnoc_qchannel *alloc_qchannel[CAM_CAMNOC_HW_TYPE_MAX] = {0};
 
 	CAM_DBG(CAM_CPAS,
 		"hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d",
@@ -1264,84 +1299,93 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 	switch (soc_info->hw_version) {
 	case CAM_CPAS_TITAN_170_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam170_cpas100_camnoc_info;
+		cpas_info = &cam170_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_170_V110:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam170_cpas110_camnoc_info;
+		cpas_info = &cam170_cpas110_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_170_V200:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam170_cpas200_camnoc_info;
+		cpas_info = &cam170_cpas200_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_175_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam175_cpas100_camnoc_info;
+		cpas_info = &cam175_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_175_V101:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam175_cpas101_camnoc_info;
+		cpas_info = &cam175_cpas101_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_175_V120:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam175_cpas120_camnoc_info;
+		cpas_info = &cam175_cpas120_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_175_V130:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam175_cpas130_camnoc_info;
+		cpas_info = &cam175_cpas130_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_150_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam150_cpas100_camnoc_info;
+		cpas_info = &cam150_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_480_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam480_cpas100_camnoc_info;
+		cpas_info = &cam480_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_580_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam580_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam580_cpas100_qchannel_info;
+		cpas_info = &cam580_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_540_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam540_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam540_cpas100_qchannel_info;
+		cpas_info = &cam540_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_520_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam520_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam520_cpas100_qchannel_info;
+		cpas_info = &cam520_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_545_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam545_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam545_cpas100_qchannel_info;
+		cpas_info = &cam545_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_570_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam570_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam570_cpas100_qchannel_info;
+		cpas_info = &cam570_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_570_V200:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam570_cpas200_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam570_cpas200_qchannel_info;
+		cpas_info = &cam570_cpas200_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_680_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam680_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam680_cpas100_qchannel_info;
+		cpas_info = &cam680_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_680_V110:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam680_cpas110_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam680_cpas110_qchannel_info;
+		cpas_info = &cam680_cpas110_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_165_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam165_cpas100_camnoc_info;
+		cpas_info = &cam165_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_780_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam780_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam780_cpas100_qchannel_info;
+		cpas_info = &cam780_cpas100_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_640_V200:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam640_cpas200_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam640_cpas200_qchannel_info;
+		cpas_info = &cam640_cpas200_cpas_info;
 		break;
 	case CAM_CPAS_TITAN_880_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_COMBINED] = &cam880_cpas100_camnoc_info;
-		alloc_qchannel[CAM_CAMNOC_HW_COMBINED] = &cam880_cpas100_qchannel_info;
+		cpas_info = &cam880_cpas100_cpas_info;
 		cesta_info = &cam_v880_cesta_info;
 		break;
 	case CAM_CPAS_TITAN_980_V100:
 		alloc_camnoc_info[CAM_CAMNOC_HW_RT] = &cam980_cpas100_camnoc_info_rt;
 		alloc_camnoc_info[CAM_CAMNOC_HW_NRT] = &cam980_cpas100_camnoc_info_nrt;
-		alloc_qchannel[CAM_CAMNOC_HW_RT] = &cam980_cpas100_qchannel_info_rt;
-		alloc_qchannel[CAM_CAMNOC_HW_NRT] = &cam980_cpas100_qchannel_info_nrt;
+		cpas_info = &cam980_cpas100_cpas_info;
 		cesta_info = &cam_v980_cesta_info;
 		break;
 	default:
@@ -1354,9 +1398,17 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 
 	cpas_core->cesta_info = cesta_info;
 
-	rc = cam_cpastop_set_up_camnoc_info(cpas_core, alloc_camnoc_info, alloc_qchannel);
-	if (rc)
+	rc = cam_cpastop_set_up_camnoc_info(cpas_core, alloc_camnoc_info);
+	if (rc) {
 		CAM_ERR(CAM_CPAS, "Failed to set up camnoc info rc=%d", rc);
+		return rc;
+	}
+
+	rc = cam_cpastop_get_hw_capability(cpas_hw);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Failed to get titan hw capability rc=%d", rc);
+		return rc;
+	}
 
 	return rc;
 }

+ 25 - 0
drivers/cam_cpas/cpas_top/cam_cpastop_hw.h

@@ -426,6 +426,18 @@ struct cam_cpas_cesta_info {
 	struct cam_cpas_cesta_vcd_reg_info *cesta_reg_info;
 };
 
+/**
+ * struct cam_cpas_hw_cap_info : CPAS Hardware capability information
+ *
+ * @num_caps_registers: number of hw capability registers
+ * @hw_caps_offsets: array of hw cap register offsets
+ *
+ */
+struct cam_cpas_hw_cap_info {
+	uint32_t num_caps_registers;
+	uint32_t hw_caps_offsets[CAM_CPAS_MAX_CAPS_REGS];
+};
+
 /**
  * struct cam_camnoc_info : Overall CAMNOC settings info
  *
@@ -493,4 +505,17 @@ struct cam_cpas_camnoc_qchannel {
 	uint32_t qchannel_status;
 };
 
+/**
+ * struct cam_cpas_info: CPAS information
+ *
+ * @qchannel_info: CPAS qchannel info
+ * @hw_cap_info: CPAS Hardware capability information
+ * @num_qchannel: Number of qchannel
+ */
+struct cam_cpas_info {
+	struct cam_cpas_camnoc_qchannel *qchannel_info[CAM_CAMNOC_HW_TYPE_MAX];
+	struct cam_cpas_hw_cap_info hw_caps_info;
+	uint8_t num_qchannel;
+};
+
 #endif /* _CAM_CPASTOP_HW_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP100_H_
@@ -528,4 +529,11 @@ struct cam_camnoc_info cam170_cpas100_camnoc_info = {
 	.errata_wa_list = &cam170_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_info cam170_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP100_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v150_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V150_100_H_
@@ -527,4 +528,11 @@ static struct cam_camnoc_info cam150_cpas100_camnoc_info = {
 	.errata_wa_list = &cam150_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_info cam150_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V150_100_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v165_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
  #ifndef _CPASTOP_V165_100_H_
@@ -707,5 +708,12 @@ static struct cam_camnoc_info cam165_cpas100_camnoc_info = {
 	.errata_wa_list = &cam165_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_info cam165_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V165_100_H_ */
 

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v170_110.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V170_110_H_
@@ -535,4 +536,11 @@ static struct cam_camnoc_info cam170_cpas110_camnoc_info = {
 	.errata_wa_list = &cam170_cpas110_errata_wa_list,
 };
 
+static struct cam_cpas_info cam170_cpas110_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V170_110_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v170_200.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V170_200_H_
@@ -571,4 +572,11 @@ static struct cam_camnoc_info cam170_cpas200_camnoc_info = {
 	.errata_wa_list = &cam170_cpas200_errata_wa_list,
 };
 
+static struct cam_cpas_info cam170_cpas200_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V170_200_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v175_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V175_100_H_
@@ -555,4 +556,11 @@ static struct cam_camnoc_info cam175_cpas100_camnoc_info = {
 	.errata_wa_list = &cam175_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_info cam175_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V175_100_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v175_101.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V175_101_H_
@@ -555,4 +556,11 @@ static struct cam_camnoc_info cam175_cpas101_camnoc_info = {
 	.errata_wa_list = &cam175_cpas101_errata_wa_list,
 };
 
+static struct cam_cpas_info cam175_cpas101_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V175_101_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v175_120.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V175_120_H_
@@ -757,4 +758,11 @@ static struct cam_camnoc_info cam175_cpas120_camnoc_info = {
 	.errata_wa_list = &cam175_cpas120_errata_wa_list,
 };
 
+static struct cam_cpas_info cam175_cpas120_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V175_120_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v175_130.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V175_130_H_
@@ -829,4 +830,11 @@ static struct cam_camnoc_info cam175_cpas130_camnoc_info = {
 	.errata_wa_list = &cam175_cpas130_errata_wa_list,
 };
 
+static struct cam_cpas_info cam175_cpas130_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V175_130_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v480_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V480_100_H_
@@ -761,4 +762,11 @@ static struct cam_camnoc_info cam480_cpas100_camnoc_info = {
 	.errata_wa_list = &cam480_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_info cam480_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V480_100_H_ */

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v480_custom.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V480_CUSTOM_H_
@@ -708,4 +709,11 @@ static struct cam_camnoc_info cam480_custom_camnoc_info = {
 	.errata_wa_list = &cam480_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_info cam480_custom_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V480_CUSTOM_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v520_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V520_100_H_
@@ -257,4 +258,14 @@ static struct cam_cpas_camnoc_qchannel cam520_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x14,
 	.qchannel_status = 0x18,
 };
+
+static struct cam_cpas_info cam520_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam520_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V520_100_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v540_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V540_100_H_
@@ -258,4 +259,14 @@ static struct cam_cpas_camnoc_qchannel cam540_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x14,
 	.qchannel_status = 0x18,
 };
+
+static struct cam_cpas_info cam540_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam540_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V540_100_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v545_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V545_100_H_
@@ -351,4 +352,14 @@ static struct cam_cpas_camnoc_qchannel cam545_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x14,
 	.qchannel_status = 0x18,
 };
+
+static struct cam_cpas_info cam545_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam545_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V545_100_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v570_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V570_100_H_
@@ -925,4 +926,14 @@ static struct cam_cpas_camnoc_qchannel cam570_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam570_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam570_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V570_100_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v570_200.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V570_200_H_
@@ -930,4 +931,14 @@ static struct cam_cpas_camnoc_qchannel cam570_cpas200_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam570_cpas200_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam570_cpas200_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V570_200_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v580_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V580_100_H_
@@ -1107,5 +1108,15 @@ static struct cam_cpas_camnoc_qchannel cam580_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam580_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam580_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V580_100_H_ */
 

+ 8 - 0
drivers/cam_cpas/cpas_top/cpastop_v580_custom.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V580_CUSTOM_H_
@@ -1042,5 +1043,12 @@ static struct cam_camnoc_info cam580_custom_camnoc_info = {
 	}
 };
 
+static struct cam_cpas_info cam580_custom_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+};
+
 #endif /* _CPASTOP_V580_CUSTOM_H_ */
 

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v640_200.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V640_200_H_
@@ -562,5 +563,15 @@ static struct cam_cpas_camnoc_qchannel cam640_cpas200_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam640_cpas200_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam640_cpas200_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V640_200_H_ */
 

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v680_100.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V680_100_H_
@@ -1290,5 +1291,15 @@ static struct cam_cpas_camnoc_qchannel cam680_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam680_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam680_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V680_100_H_ */
 

+ 11 - 1
drivers/cam_cpas/cpas_top/cpastop_v680_110.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V680_110_H_
@@ -1292,5 +1292,15 @@ static struct cam_cpas_camnoc_qchannel cam680_cpas110_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam680_cpas110_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam680_cpas110_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V680_110_H_ */
 

+ 11 - 1
drivers/cam_cpas/cpas_top/cpastop_v780_100.h

@@ -1,7 +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.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CPASTOP_V780_100_H_
@@ -1216,4 +1216,14 @@ static struct cam_cpas_camnoc_qchannel cam780_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam780_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 1,
+		.hw_caps_offsets = {0x8},
+	},
+	.qchannel_info = {&cam780_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V780_100_H_ */

+ 10 - 0
drivers/cam_cpas/cpas_top/cpastop_v880_100.h

@@ -1338,4 +1338,14 @@ static struct cam_cpas_camnoc_qchannel cam880_cpas100_qchannel_info = {
 	.qchannel_ctrl   = 0x5C,
 	.qchannel_status = 0x60,
 };
+
+static struct cam_cpas_info cam880_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 2,
+		.hw_caps_offsets = {0x8, 0xDC},
+	},
+	.qchannel_info = {&cam880_cpas100_qchannel_info},
+	.num_qchannel = 1,
+};
+
 #endif /* _CPASTOP_V880_100_H_ */

+ 11 - 0
drivers/cam_cpas/cpas_top/cpastop_v980_100.h

@@ -1601,4 +1601,15 @@ static struct cam_cpas_camnoc_qchannel cam980_cpas100_qchannel_info_nrt = {
 	.qchannel_ctrl   = 0xF4,
 	.qchannel_status = 0xF8,
 };
+
+static struct cam_cpas_info cam980_cpas100_cpas_info = {
+	.hw_caps_info = {
+		.num_caps_registers = 2,
+		.hw_caps_offsets = {0x8, 0xDC},
+	},
+	.qchannel_info = {&cam980_cpas100_qchannel_info_rt,
+		&cam980_cpas100_qchannel_info_nrt},
+	.num_qchannel = 2,
+};
+
 #endif /* _CPASTOP_V980_100_H_ */

+ 5 - 4
drivers/cam_cpas/include/cam_cpas_api.h

@@ -722,7 +722,8 @@ int cam_cpas_reg_read(
  *                   CAM_FAMILY_CPAS_SS
  * @camera_version : Camera platform version
  * @cpas_version   : Camera cpas version
- * @cam_caps       : Camera capability
+ * @cam_caps       : Camera capability array
+ * @num_cap_mask   : number of capability masks
  * @cam_fuse_info  : Camera fuse info
  * @domain_id_info : Domain id info
  *
@@ -733,7 +734,8 @@ int cam_cpas_get_hw_info(
 	uint32_t                       *camera_family,
 	struct cam_hw_version          *camera_version,
 	struct cam_hw_version          *cpas_version,
-	uint32_t                       *cam_caps,
+	uint32_t                      **cam_caps,
+	uint32_t                       *num_cap_mask,
 	struct cam_cpas_fuse_info      *cam_fuse_info,
 	struct cam_cpas_domain_id_caps *domain_id_info);
 
@@ -747,8 +749,7 @@ int cam_cpas_get_hw_info(
  * @return 0 on success.
  *
  */
-int cam_cpas_get_cpas_hw_version(
-	uint32_t				 *hw_version);
+int cam_cpas_get_cpas_hw_version(uint32_t *hw_version);
 
 /**
  * cam_cpas_is_feature_supported()

+ 55 - 89
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

@@ -66,6 +66,8 @@ DECLARE_RWSEM(frame_in_process_sem);
 
 static struct cam_icp_hw_mgr *g_icp_hw_mgr[CAM_ICP_SUBDEV_MAX];
 
+uint32_t icp_cpas_mask[CAM_ICP_SUBDEV_MAX] = {CPAS_ICP_BIT, CPAS_ICP1_BIT};
+
 static void cam_icp_mgr_process_dbg_buf(struct cam_icp_hw_mgr *hw_mgr);
 
 static int cam_icp_dump_io_cfg(struct cam_icp_hw_ctx_data *ctx_data,
@@ -7486,18 +7488,48 @@ static void cam_icp_mgr_free_devs(struct cam_icp_hw_mgr *hw_mgr)
 		kfree(hw_mgr->devices[i]);
 }
 
-static int cam_icp_mgr_alloc_devs(struct device_node *np,
-	struct cam_icp_hw_mgr *hw_mgr, uint32_t cpas_cap_dev_cnt[CAM_ICP_HW_MAX])
+static int cam_icp_mgr_verify_hw_caps(struct cam_icp_hw_mgr *hw_mgr, uint32_t *icp_dev_mask,
+	uint32_t num_icp_dev_mask)
+{
+	struct cam_cpas_query_cap query;
+	int rc, i;
+	uint32_t *cam_caps, num_cpas_cap_mask;
+
+	rc = cam_cpas_get_hw_info(&query.camera_family, &query.camera_version,
+			&query.cpas_version, &cam_caps, &num_cpas_cap_mask,
+			NULL, NULL);
+	if (rc)
+		return rc;
+
+	if (num_icp_dev_mask > num_cpas_cap_mask) {
+		CAM_ERR(CAM_ICP,
+			"[%s] Number of found icp device caps mask %u exceeds cpas cap mask %u",
+			hw_mgr->hw_mgr_name, num_icp_dev_mask, num_cpas_cap_mask);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_icp_dev_mask; i++) {
+		if ((icp_dev_mask[i] & cam_caps[i]) != icp_dev_mask[i]) {
+			CAM_ERR(CAM_ICP,
+				"[%s] Found unsupported HW, cpas caps mask: %u icp device mask: %u",
+				hw_mgr->hw_mgr_name, cam_caps[i], icp_dev_mask[i]);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int cam_icp_mgr_alloc_devs(struct device_node *np, struct cam_icp_hw_mgr *hw_mgr)
 {
 	struct cam_hw_intf **devices = NULL;
 	int rc;
 	enum cam_icp_hw_type icp_hw_type;
-	uint32_t num = 0;
+	uint32_t num = 0, num_cpas_mask = 0, cpas_hw_mask[MAX_HW_CAPS_MASK] = {0};
 
 	memset(hw_mgr->devices, 0, sizeof(hw_mgr->devices));
 
-	rc = cam_icp_alloc_processor_devs(np, &icp_hw_type,
-		&devices, hw_mgr->hw_dev_cnt, cpas_cap_dev_cnt);
+	rc = cam_icp_alloc_processor_devs(np, &icp_hw_type, &devices, hw_mgr->hw_dev_cnt);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "[%s] proc devices allocation failed rc=%d",
 			hw_mgr->hw_mgr_name, rc);
@@ -7514,16 +7546,11 @@ static int cam_icp_mgr_alloc_devs(struct device_node *np,
 
 	hw_mgr->devices[icp_hw_type] = devices;
 	hw_mgr->hw_cap_mask |= BIT(icp_hw_type);
+	num_cpas_mask = max(num_cpas_mask, (uint32_t)(ICP_CAPS_MASK_IDX + 1));
+	cpas_hw_mask[ICP_CAPS_MASK_IDX] |= icp_cpas_mask[hw_mgr->hw_mgr_id];
 
 	rc = of_property_read_u32(np, "num-ipe", &num);
 	if (!rc) {
-		if (num > cpas_cap_dev_cnt[CAM_ICP_DEV_IPE]) {
-			CAM_ERR(CAM_ICP,
-				"[%s] Number of listed IPE: %u exceed supported IPE number: %u",
-				hw_mgr->hw_mgr_name, num, cpas_cap_dev_cnt[CAM_ICP_DEV_IPE]);
-			rc = -EINVAL;
-			goto free_devs;
-		}
 		hw_mgr->hw_dev_cnt[CAM_ICP_DEV_IPE] = num;
 
 		devices = kcalloc(num, sizeof(*devices), GFP_KERNEL);
@@ -7534,17 +7561,12 @@ static int cam_icp_mgr_alloc_devs(struct device_node *np,
 		}
 		hw_mgr->devices[CAM_ICP_DEV_IPE] = devices;
 		hw_mgr->hw_cap_mask |= BIT(CAM_ICP_DEV_IPE);
+		num_cpas_mask = max(num_cpas_mask, (uint32_t)(IPE_CAPS_MASK_IDX + 1));
+		cpas_hw_mask[IPE_CAPS_MASK_IDX] |= CPAS_TITAN_IPE0_CAP_BIT;
 	}
 
 	rc = of_property_read_u32(np, "num-bps", &num);
 	if (!rc) {
-		if (num > cpas_cap_dev_cnt[CAM_ICP_DEV_BPS]) {
-			CAM_ERR(CAM_ICP,
-				"[%s] Number of listed BPS: %u exceed supported BPS number: %u",
-				hw_mgr->hw_mgr_name, num, cpas_cap_dev_cnt[CAM_ICP_DEV_BPS]);
-			rc = -EINVAL;
-			goto free_devs;
-		}
 		hw_mgr->hw_dev_cnt[CAM_ICP_DEV_BPS] = num;
 
 		devices = kcalloc(num, sizeof(*devices), GFP_KERNEL);
@@ -7555,17 +7577,12 @@ static int cam_icp_mgr_alloc_devs(struct device_node *np,
 		}
 		hw_mgr->devices[CAM_ICP_DEV_BPS] = devices;
 		hw_mgr->hw_cap_mask |= BIT(CAM_ICP_DEV_BPS);
+		num_cpas_mask = max(num_cpas_mask, (uint32_t)(BPS_CAPS_MASK_IDX + 1));
+		cpas_hw_mask[BPS_CAPS_MASK_IDX] |= CPAS_BPS_BIT;
 	}
 
 	rc = of_property_read_u32(np, "num-ofe", &num);
 	if (!rc) {
-		if (num > cpas_cap_dev_cnt[CAM_ICP_DEV_OFE]) {
-			CAM_ERR(CAM_ICP,
-				"[%s] Number of listed OFE: %u exceed supported OFE number: %u",
-				hw_mgr->hw_mgr_name, num, cpas_cap_dev_cnt[CAM_ICP_DEV_OFE]);
-			rc = -EINVAL;
-			goto free_devs;
-		}
 		hw_mgr->hw_dev_cnt[CAM_ICP_DEV_OFE] = num;
 
 		devices = kcalloc(num, sizeof(*devices), GFP_KERNEL);
@@ -7577,6 +7594,14 @@ static int cam_icp_mgr_alloc_devs(struct device_node *np,
 
 		hw_mgr->devices[CAM_ICP_DEV_OFE] = devices;
 		hw_mgr->hw_cap_mask |= BIT(CAM_ICP_DEV_OFE);
+		num_cpas_mask = max(num_cpas_mask, (uint32_t)(OFE_CAPS_MASK_IDX + 1));
+		cpas_hw_mask[OFE_CAPS_MASK_IDX] |= CPAS_OFE_BIT;
+	}
+
+	rc = cam_icp_mgr_verify_hw_caps(hw_mgr, cpas_hw_mask, num_cpas_mask);
+	if (rc) {
+		CAM_ERR(CAM_ICP, "CPAS ICP HW capability verification fails rc=%d", rc);
+		goto free_devs;
 	}
 
 	hw_mgr->dev_pc_flag = of_property_read_bool(np, "ipe_bps_pc_en");
@@ -7592,12 +7617,11 @@ free_devs:
 	return rc;
 }
 
-static int cam_icp_mgr_init_devs(struct device_node *np,
-	struct cam_icp_hw_mgr *hw_mgr, uint32_t cpas_cap_dev_cnt[CAM_ICP_HW_MAX])
+static int cam_icp_mgr_init_devs(struct device_node *np, struct cam_icp_hw_mgr *hw_mgr)
 {
 	int rc, i, j, count, num_hw;
 
-	rc = cam_icp_mgr_alloc_devs(np, hw_mgr, cpas_cap_dev_cnt);
+	rc = cam_icp_mgr_alloc_devs(np, hw_mgr);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "[%s] devices allocation failed rc=%d",
 			hw_mgr->hw_mgr_name, rc);
@@ -7857,57 +7881,6 @@ static void cam_icp_mgr_inject_evt(void *hw_mgr_priv, void *evt_args)
 	ctx_data->evt_inject_params.is_valid = true;
 }
 
-static int cam_icp_mgr_get_device_capability(struct cam_icp_hw_mgr *hw_mgr,
-	uint32_t *cpas_cap_dev_cnt)
-{
-	struct cam_cpas_query_cap query;
-	uint32_t cam_caps, cpas_hw_version;
-	int rc = 0;
-
-	rc = cam_cpas_get_hw_info(&query.camera_family,
-		&query.camera_version, &query.cpas_version,
-		&cam_caps, NULL, NULL);
-	if (rc) {
-		CAM_ERR(CAM_ICP, "[%s] failed to get hw info rc=%d",
-			hw_mgr->hw_mgr_name, rc);
-		return rc;
-	}
-
-	rc = cam_cpas_get_cpas_hw_version(&cpas_hw_version);
-	if (rc) {
-		CAM_ERR(CAM_ICP, "[%s] failed to get hw version rc=%d",
-			hw_mgr->hw_mgr_name, rc);
-		return rc;
-	}
-
-	memset(cpas_cap_dev_cnt, 0, sizeof(*cpas_cap_dev_cnt) * CAM_ICP_HW_MAX);
-
-	if ((cpas_hw_version == CAM_CPAS_TITAN_480_V100) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_580_V100) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_570_V100) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_570_V200) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_680_V100) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_680_V110) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_780_V100) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_640_V200) ||
-		(cpas_hw_version == CAM_CPAS_TITAN_880_V100)) {
-		cpas_cap_dev_cnt[CAM_ICP_DEV_IPE] =
-			__builtin_popcount(cam_caps & CPAS_TITAN_IPE0_CAP_BIT);
-		cpas_cap_dev_cnt[CAM_ICP_DEV_BPS] =
-			__builtin_popcount(cam_caps & CPAS_BPS_BIT);
-		cpas_cap_dev_cnt[CAM_ICP_HW_ICP_V2] =
-			__builtin_popcount(cam_caps & CPAS_ICP_BIT);
-	} else {
-		cpas_cap_dev_cnt[CAM_ICP_HW_ICP_V1] = 1;
-		cpas_cap_dev_cnt[CAM_ICP_DEV_IPE] =
-			__builtin_popcount(cam_caps & (CPAS_IPE0_BIT | CPAS_IPE1_BIT));
-		cpas_cap_dev_cnt[CAM_ICP_DEV_BPS] =
-			__builtin_popcount(cam_caps & CPAS_BPS_BIT);
-	}
-
-	return rc;
-}
-
 static int cam_icp_mgr_register_hfi_client(struct cam_icp_hw_mgr *hw_mgr)
 {
 
@@ -7987,7 +7960,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	int i, rc = 0;
 	struct cam_icp_hw_mgr  *hw_mgr = NULL;
 	struct cam_hw_mgr_intf *hw_mgr_intf;
-	uint32_t size = 0, cpas_cap_dev_cnt[CAM_ICP_HW_MAX];
+	uint32_t size = 0;
 
 	hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
 	if (!of_node || !hw_mgr_intf) {
@@ -8052,14 +8025,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 		}
 	}
 
-	rc = cam_icp_mgr_get_device_capability(hw_mgr, cpas_cap_dev_cnt);
-	if (rc) {
-		CAM_ERR(CAM_ICP, "[%s] Fail to get device capability rc: %d",
-			hw_mgr->hw_mgr_name, rc);
-		goto destroy_mutex;
-	}
-
-	rc = cam_icp_mgr_init_devs(of_node, hw_mgr, cpas_cap_dev_cnt);
+	rc = cam_icp_mgr_init_devs(of_node, hw_mgr);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "[%s] cam_icp_mgr_init_devs fail: rc: %d",
 			hw_mgr->hw_mgr_name, rc);

+ 2 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h

@@ -56,6 +56,8 @@
 #define CPAS_IPE1_BIT           0x2000
 #define CPAS_BPS_BIT            0x400
 #define CPAS_ICP_BIT            0x1
+#define CPAS_ICP1_BIT           0x4
+#define CPAS_OFE_BIT            0x10
 
 /* Used for targets >= 480 and its variants */
 #define CPAS_TITAN_IPE0_CAP_BIT 0x800

+ 9 - 1
drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h

@@ -1,7 +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.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef CAM_ICP_HW_INTF_H
@@ -26,6 +26,14 @@
 #define CAM_ICP_MAX_ICP_HW_TYPE 2
 #define CAM_ICP_DEV_START_IDX CAM_ICP_MAX_ICP_HW_TYPE
 
+#define ICP_CAPS_MASK_IDX 0
+#define IPE_CAPS_MASK_IDX 0
+#define BPS_CAPS_MASK_IDX 0
+#define OFE_CAPS_MASK_IDX 1
+
+/* max caps mask is max value of all device caps mask index added by 1 */
+#define MAX_HW_CAPS_MASK 2
+
 enum cam_icp_hw_type {
 	CAM_ICP_HW_ICP_V1,
 	CAM_ICP_HW_ICP_V2,

+ 1 - 8
drivers/cam_icp/icp_hw/icp_proc/cam_icp_proc.c

@@ -28,7 +28,7 @@ static int cam_icp_get_device_num(enum cam_icp_hw_type dev_type, uint32_t *num_d
 }
 
 int cam_icp_alloc_processor_devs(struct device_node *np, enum cam_icp_hw_type *icp_hw_type,
-	struct cam_hw_intf ***devices, uint32_t *hw_dev_cnt, uint32_t *dev_cap_cnt)
+	struct cam_hw_intf ***devices, uint32_t *hw_dev_cnt)
 {
 	uint32_t num_icp_found = 0, num_icp_listed;
 	int rc, i;
@@ -66,13 +66,6 @@ int cam_icp_alloc_processor_devs(struct device_node *np, enum cam_icp_hw_type *i
 		return -ENODEV;
 	}
 
-	if (num_icp_found != dev_cap_cnt[i]) {
-		CAM_ERR(CAM_ICP,
-			"Number of ICP core probed: %u is not equal to CPAS supported devices: %u",
-			num_icp_found, dev_cap_cnt[i]);
-		return -EINVAL;
-	}
-
 	icp_request_cnt[i] += num_icp_listed;
 
 	if (icp_request_cnt[i] > num_icp_found) {

+ 1 - 1
drivers/cam_icp/icp_hw/icp_proc/cam_icp_proc.h

@@ -15,7 +15,7 @@
  * @brief : Get ICP device type (ICP_V1/ICP_V2/...)
  */
 int cam_icp_alloc_processor_devs(struct device_node *np, enum cam_icp_hw_type *icp_hw_type,
-	struct cam_hw_intf ***devices, uint32_t *hw_dev_cnt, uint32_t *dev_cap_cnt);
+	struct cam_hw_intf ***devices, uint32_t *hw_dev_cnt);
 
 /**
  * @brief : Get device operations per device type

+ 4 - 4
drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c

@@ -1,7 +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.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -79,7 +79,7 @@ static int cam_ipe_component_bind(struct device *dev,
 	struct cam_ipe_device_hw_info     *hw_info = NULL;
 	int                                rc = 0;
 	struct cam_cpas_query_cap query;
-	uint32_t cam_caps;
+	uint32_t *cam_caps, num_cap_mask;
 	uint32_t hw_idx;
 	struct platform_device *pdev = to_platform_device(dev);
 
@@ -88,13 +88,13 @@ static int cam_ipe_component_bind(struct device *dev,
 
 	rc = cam_cpas_get_hw_info(&query.camera_family,
 			&query.camera_version, &query.cpas_version,
-			&cam_caps, NULL, NULL);
+			&cam_caps, &num_cap_mask, NULL, NULL);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "failed to get hw info rc=%d", rc);
 		return rc;
 	}
 
-	if ((!(cam_caps & CPAS_IPE1_BIT)) && (hw_idx)) {
+	if ((!(cam_caps[IPE_CAPS_MASK_IDX] & CPAS_IPE1_BIT)) && (hw_idx)) {
 		CAM_ERR(CAM_ICP, "IPE1 hw idx = %d\n", hw_idx);
 		return -EINVAL;
 	}