Forráskód Böngészése

msm: camera: common: Partial Camera Support

This change creates a sysfs entry(subparts_info) which
has info about number of IFEs, IFE-LITEs, SFEs & CUSTOM,
whose values are populated in their respective drivers.
Also, validates whether a particular IFE, SFE and CUSTOM
is supported or not. Based on this, probe of IFE, SFE and
CUSTOM drivers will happen accordingly.

CRs-Fixed: 3482745
Change-Id: Iff6e79a7793b14b1f368f215020617f10dbd4bb5
Signed-off-by: Karthik Dillibabu <[email protected]>
Karthik Dillibabu 2 éve
szülő
commit
f910aa0b4f

+ 149 - 2
drivers/cam_cpas/cam_cpas_hw.c

@@ -34,6 +34,24 @@ static void cam_cpas_dump_monitor_array(
 	struct cam_hw_info *cpas_hw);
 static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw, bool ddr_only);
 
+static struct cam_cpas_subpart_info g_cam_cpas_camera_subpart_info = {
+	.num_bits = 8,
+	/*
+	 * Below fuse indexing is based on software fuse definition which is in SMEM and provided
+	 * by XBL team.
+	 */
+	.hw_bitmap_mask = {
+		{CAM_CPAS_CAM_FUSE, BIT(0)},
+		{CAM_CPAS_ISP_FUSE, BIT(0)},
+		{CAM_CPAS_ISP_FUSE, BIT(1)},
+		{CAM_CPAS_ISP_FUSE, BIT(2)},
+		{CAM_CPAS_SFE_FUSE, BIT(0)},
+		{CAM_CPAS_SFE_FUSE, BIT(1)},
+		{CAM_CPAS_SFE_FUSE, BIT(2)},
+		{CAM_CPAS_CUSTOM_FUSE, BIT(0)},
+	}
+};
+
 static void cam_cpas_process_drv_bw_overrides(
 	struct cam_cpas_bus_client *bus_client, uint64_t *high_ab, uint64_t *high_ib,
 	uint64_t *low_ab, uint64_t *low_ib, const struct cam_cpas_debug_settings *cpas_settings)
@@ -2912,8 +2930,7 @@ static int cam_cpas_hw_get_hw_info(void *hw_priv,
 		cpas_hw->soc_info.soc_private;
 
 	hw_caps->fuse_info = soc_private->fuse_info;
-	CAM_INFO(CAM_CPAS, "fuse info->num_fuses %d",
-		hw_caps->fuse_info.num_fuses);
+	CAM_DBG(CAM_CPAS, "fuse info->num_fuses %d", hw_caps->fuse_info.num_fuses);
 
 	return 0;
 }
@@ -4445,6 +4462,118 @@ end:
 	return rc;
 }
 
+static struct cam_hw_info *cam_cpas_kobj_to_cpas_hw(struct kobject *kobj)
+{
+	return container_of(kobj, struct cam_cpas_kobj_map, base_kobj)->cpas_hw;
+}
+
+static ssize_t cam_cpas_sysfs_get_subparts_info(struct kobject *kobj, struct kobj_attribute *attr,
+	char *buf)
+{
+	int len = 0;
+	struct cam_hw_info *cpas_hw = cam_cpas_kobj_to_cpas_hw(kobj);
+	struct cam_cpas_private_soc *soc_private = NULL;
+	struct cam_cpas_sysfs_info *sysfs_info = NULL;
+
+	mutex_lock(&cpas_hw->hw_mutex);
+	soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+	sysfs_info  = &soc_private->sysfs_info;
+
+	len += scnprintf(buf, PAGE_SIZE, "num_ifes: 0x%x, 0x%x\nnum_ife_lites: 0x%x, 0x%x\n"
+		"num_sfes: 0x%x, 0x%x\nnum_custom: 0x%x, 0x%x\n",
+		sysfs_info->num_ifes[CAM_CPAS_AVAILABLE_NUM_SUBPARTS],
+		sysfs_info->num_ifes[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS],
+		sysfs_info->num_ife_lites[CAM_CPAS_AVAILABLE_NUM_SUBPARTS],
+		sysfs_info->num_ife_lites[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS],
+		sysfs_info->num_sfes[CAM_CPAS_AVAILABLE_NUM_SUBPARTS],
+		sysfs_info->num_sfes[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS],
+		sysfs_info->num_custom[CAM_CPAS_AVAILABLE_NUM_SUBPARTS],
+		sysfs_info->num_custom[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS]);
+	/*
+	 * subparts_info sysfs string looks like below.
+	 * num_ifes: 0x3, 0x3 (If all IFEs are available)/0x2 (If 1 IFE is unavailable)
+	 * num_ife_lites: 0x2, 0x2
+	 * num_sfes: 0x3, 0x3 (If all SFEs are available)/0x2 (If 1 SFE is unavailable)
+	 * num_custom: 0x0, 0x0
+	 */
+
+	if (len >= PAGE_SIZE) {
+		CAM_ERR(CAM_CPAS, "camera subparts info sysfs string is truncated, len: %d", len);
+		mutex_unlock(&cpas_hw->hw_mutex);
+		return -EOVERFLOW;
+	}
+
+	mutex_unlock(&cpas_hw->hw_mutex);
+	return len;
+}
+
+static struct kobj_attribute cam_subparts_info_attribute = __ATTR(subparts_info, 0444,
+	cam_cpas_sysfs_get_subparts_info, NULL);
+
+static void cam_cpas_hw_kobj_release(struct kobject *kobj)
+{
+	CAM_DBG(CAM_CPAS, "Release kobj");
+	kfree(container_of(kobj, struct cam_cpas_kobj_map, base_kobj));
+}
+
+static struct kobj_type kobj_cam_cpas_hw_type = {
+	.release = cam_cpas_hw_kobj_release,
+	.sysfs_ops = &kobj_sysfs_ops
+};
+
+static void cam_cpas_remove_sysfs(struct cam_hw_info *cpas_hw)
+{
+	struct cam_cpas_private_soc *soc_private = NULL;
+
+	mutex_lock(&cpas_hw->hw_mutex);
+	soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+
+	sysfs_remove_file(soc_private->sysfs_info.kobj, &cam_subparts_info_attribute.attr);
+	kobject_put(soc_private->sysfs_info.kobj);
+	mutex_unlock(&cpas_hw->hw_mutex);
+}
+
+static int cam_cpas_create_sysfs(struct cam_hw_info *cpas_hw)
+{
+	int rc = 0;
+	struct cam_cpas_kobj_map *kobj_camera = NULL;
+	struct cam_cpas_private_soc *soc_private = NULL;
+
+	mutex_lock(&cpas_hw->hw_mutex);
+	soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+
+	kobj_camera = kzalloc(sizeof(*kobj_camera), GFP_KERNEL);
+	if (!kobj_camera) {
+		CAM_ERR(CAM_CPAS, "failed to allocate memory for kobj_camera");
+		mutex_unlock(&cpas_hw->hw_mutex);
+		return -ENOMEM;
+	}
+
+	kobject_init(&kobj_camera->base_kobj, &kobj_cam_cpas_hw_type);
+	kobj_camera->cpas_hw = cpas_hw;
+	soc_private->sysfs_info.kobj = &kobj_camera->base_kobj;
+
+	rc = kobject_add(&kobj_camera->base_kobj, kernel_kobj, "%s", "camera");
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "failed to add camera entry in sysfs");
+		goto end;
+	}
+
+	/* sysfs file is created in /sys/kernel/camera */
+	rc = sysfs_create_file(&kobj_camera->base_kobj, &cam_subparts_info_attribute.attr);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "failed to create subparts_info file, rc: %d", rc);
+		goto end;
+	}
+
+	mutex_unlock(&cpas_hw->hw_mutex);
+	return 0;
+end:
+	kobject_put(&kobj_camera->base_kobj);
+	mutex_unlock(&cpas_hw->hw_mutex);
+	return rc;
+}
+
 int cam_cpas_hw_probe(struct platform_device *pdev,
 	struct cam_hw_intf **hw_intf)
 {
@@ -4525,6 +4654,13 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
 
 	soc_private = (struct cam_cpas_private_soc *)
 		cpas_hw->soc_info.soc_private;
+
+	rc = cam_cpas_create_sysfs(cpas_hw);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Failed to create sysfs entries, rc: %d", rc);
+		goto sysfs_fail;
+	}
+
 	cpas_core->num_clients = soc_private->num_clients;
 	atomic_set(&cpas_core->soc_access_count, 0);
 	init_waitqueue_head(&cpas_core->soc_access_count_wq);
@@ -4583,6 +4719,14 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
 	if (rc)
 		goto disable_soc_res;
 
+	cpas_core->cam_subpart_info = &g_cam_cpas_camera_subpart_info;
+
+	rc = cam_get_subpart_info(&soc_private->part_info, CAM_CPAS_CAMERA_INSTANCES);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Failed to get subpart_info, rc = %d", rc);
+		goto disable_soc_res;
+	}
+
 	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
 	if (rc) {
 		CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc);
@@ -4612,6 +4756,8 @@ client_cleanup:
 	cam_cpas_util_client_cleanup(cpas_hw);
 	cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private);
 deinit_platform_res:
+	cam_cpas_remove_sysfs(cpas_hw);
+sysfs_fail:
 	cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
 release_workq:
 	flush_workqueue(cpas_core->work_queue);
@@ -4643,6 +4789,7 @@ int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf)
 		return -EINVAL;
 	}
 
+	cam_cpas_remove_sysfs(cpas_hw);
 	cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info);
 	cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private);
 	cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client);

+ 16 - 0
drivers/cam_cpas/cam_cpas_hw.h

@@ -27,6 +27,9 @@
 #define CAM_CPAS_MAX_SLOPE_FACTOR            100
 #define CAM_CPAS_MAX_STRESS_INDICATOR        100
 
+/* Number of camera (CAM_SS) instances */
+#define CAM_CPAS_CAMERA_INSTANCES            1
+
 #define CAM_CPAS_AXI_MIN_MNOC_AB_BW   (2048 * 1024)
 #define CAM_CPAS_AXI_MIN_MNOC_IB_BW   (2048 * 1024)
 #define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024)
@@ -143,6 +146,17 @@ struct cam_cpas_axi_bw_info {
 	};
 };
 
+/**
+ * struct cam_cpas_kobj_map: wrapper structure for base kobject
+ *                               and cam cpas private soc info
+ * @base_kobj: kernel object for camera sysfs
+ * @cpas_hw: pointer to cam_hw_info structure
+ */
+struct cam_cpas_kobj_map {
+	struct kobject base_kobj;
+	struct cam_hw_info *cpas_hw;
+};
+
 /**
  * struct cam_cpas_internal_ops - CPAS Hardware layer internal ops
  *
@@ -372,6 +386,7 @@ struct cam_cpas_monitor {
  * @ahb_bus_client: AHB Bus client info
  * @axi_port: AXI port info for a specific axi index
  * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index
+ * @cam_subpart_info: camera subparts fuse description
  * @internal_ops: CPAS HW internal ops
  * @work_queue: Work queue handle
  * @soc_access_count: atomic soc_access_count count
@@ -410,6 +425,7 @@ struct cam_cpas {
 	struct cam_cpas_bus_client ahb_bus_client;
 	struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS];
 	struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS];
+	struct cam_cpas_subpart_info *cam_subpart_info;
 	struct cam_cpas_internal_ops internal_ops;
 	struct workqueue_struct *work_queue;
 	atomic_t soc_access_count;

+ 96 - 2
drivers/cam_cpas/cam_cpas_intf.c

@@ -20,7 +20,9 @@
 #include "cam_subdev.h"
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_soc.h"
+#include "cam_cpastop_hw.h"
 #include "camera_main.h"
+
 #include <linux/soc/qcom/llcc-qcom.h>
 #include "cam_req_mgr_interface.h"
 
@@ -309,6 +311,37 @@ int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle)
 }
 EXPORT_SYMBOL(cam_cpas_dump_camnoc_buff_fill_info);
 
+bool cam_cpas_is_part_supported(uint32_t flag, uint32_t hw_map, uint32_t part_info)
+{
+	int32_t i;
+	struct cam_hw_info *cpas_hw = g_cpas_intf->hw_intf->hw_priv;
+	struct cam_cpas *cpas_core = NULL;
+	struct cam_cpas_subpart_info *cam_subpart_info = NULL;
+
+	mutex_lock(&cpas_hw->hw_mutex);
+	cpas_core = cpas_hw->core_info;
+	cam_subpart_info = cpas_core->cam_subpart_info;
+
+	if (!cam_subpart_info) {
+		CAM_DBG(CAM_CPAS, "Invalid address of cam_subpart_info");
+		mutex_unlock(&cpas_hw->hw_mutex);
+		return true;
+	}
+
+	for (i = 0; i < cam_subpart_info->num_bits; i++) {
+		if ((cam_subpart_info->hw_bitmap_mask[i][0] == flag) &&
+				(cam_subpart_info->hw_bitmap_mask[i][1] == hw_map)) {
+			CAM_DBG(CAM_CPAS, "flag: %u hw_map: %u part_info:0x%x",
+					flag, hw_map, part_info);
+			mutex_unlock(&cpas_hw->hw_mutex);
+			return ((part_info & BIT(i)) == 0);
+		}
+	}
+
+	mutex_unlock(&cpas_hw->hw_mutex);
+	return true;
+}
+
 bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
 	uint32_t *fuse_val)
 {
@@ -331,6 +364,8 @@ bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
 		return false;
 	}
 
+	supported = cam_cpas_is_part_supported(flag, hw_map, soc_private->part_info);
+
 	for (i = 0; i < soc_private->num_feature_info; i++)
 		if (soc_private->feature_info[i].feature == flag)
 			break;
@@ -341,8 +376,10 @@ bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
 	if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE
 		|| (soc_private->feature_info[i].type ==
 		CAM_CPAS_FEATURE_TYPE_ENABLE)) {
-		if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map)
-			supported = soc_private->feature_info[i].enable;
+		if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map) {
+			if (!(supported && soc_private->feature_info[i].enable))
+				supported = false;
+		}
 	} else {
 		if (!fuse_val) {
 			CAM_ERR(CAM_CPAS,
@@ -836,6 +873,63 @@ int cam_cpas_get_scid(
 }
 EXPORT_SYMBOL(cam_cpas_get_scid);
 
+int cam_cpas_prepare_subpart_info(enum cam_subparts_index idx, uint32_t num_subpart_available,
+	uint32_t num_subpart_functional)
+{
+	struct cam_hw_info *cpas_hw = NULL;
+	struct cam_cpas_private_soc *soc_private = NULL;
+
+	if (!CAM_CPAS_INTF_INITIALIZED()) {
+		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
+		return -ENODEV;
+	}
+	cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
+
+	mutex_lock(&cpas_hw->hw_mutex);
+	soc_private = (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
+
+	if (!soc_private) {
+		CAM_ERR(CAM_CPAS, "Invalid soc_private: 0x%x", soc_private);
+		mutex_unlock(&cpas_hw->hw_mutex);
+		return -EINVAL;
+	}
+
+	switch (idx) {
+	case CAM_IFE_HW_IDX:
+		soc_private->sysfs_info.num_ifes[CAM_CPAS_AVAILABLE_NUM_SUBPARTS] =
+			num_subpart_available;
+		soc_private->sysfs_info.num_ifes[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS] =
+			num_subpart_functional;
+		break;
+	case CAM_IFE_LITE_HW_IDX:
+		soc_private->sysfs_info.num_ife_lites[CAM_CPAS_AVAILABLE_NUM_SUBPARTS] =
+			num_subpart_available;
+		soc_private->sysfs_info.num_ife_lites[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS] =
+			num_subpart_functional;
+		break;
+	case CAM_SFE_HW_IDX:
+		soc_private->sysfs_info.num_sfes[CAM_CPAS_AVAILABLE_NUM_SUBPARTS] =
+			num_subpart_available;
+		soc_private->sysfs_info.num_sfes[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS] =
+			num_subpart_functional;
+		break;
+	case CAM_CUSTOM_HW_IDX:
+		soc_private->sysfs_info.num_custom[CAM_CPAS_AVAILABLE_NUM_SUBPARTS] =
+			num_subpart_available;
+		soc_private->sysfs_info.num_custom[CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS] =
+			num_subpart_functional;
+		break;
+	default:
+		CAM_ERR(CAM_CPAS, "Invalid camera subpart index : %d", idx);
+		mutex_unlock(&cpas_hw->hw_mutex);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&cpas_hw->hw_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(cam_cpas_prepare_subpart_info);
+
 int cam_cpas_activate_llcc(
 	enum cam_sys_cache_config_types type)
 {

+ 0 - 4
drivers/cam_cpas/cam_cpas_soc.c

@@ -761,8 +761,6 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 	return 0;
 }
 
-
-
 int cam_cpas_get_hw_features(struct platform_device *pdev,
 	struct cam_cpas_private_soc *soc_private)
 {
@@ -780,8 +778,6 @@ int cam_cpas_get_hw_features(struct platform_device *pdev,
 	CAM_DBG(CAM_CPAS, "fuse info elements count %d", count);
 
 	if (count <= 0) {
-		CAM_INFO(CAM_CPAS, "No or invalid fuse entries count: %d",
-			count);
 		goto end;
 	} else if (count%5 != 0) {
 		CAM_INFO(CAM_CPAS, "fuse entries should be multiple of 5 %d",

+ 30 - 0
drivers/cam_cpas/cam_cpas_soc.h

@@ -15,6 +15,15 @@
 #define CAM_CPAS_MAX_TREE_NODES 63
 #define CAM_CPAS_MAX_FUSE_FEATURE 10
 
+/**
+ * enum cam_cpas_num_subparts_types - Enum for types of number of camera subparts
+ */
+enum cam_cpas_num_subparts_types {
+	CAM_CPAS_AVAILABLE_NUM_SUBPARTS,
+	CAM_CPAS_FUNCTIONAL_NUM_SUBPARTS,
+	CAM_CPAS_NUM_SUBPARTS_MAX_TYPES,
+};
+
 /**
  * struct cpas_tree_node: Generic cpas tree node for BW voting
  *
@@ -215,6 +224,23 @@ struct cam_cpas_soc_irq_data {
 	enum cam_camnoc_hw_type camnoc_type;
 };
 
+/**
+ * struct cam_cpas_sysfs_info - cpas sysfs info
+ *
+ * @kobj:          Kobj for camera directory
+ * @num_ifes:      Number of available and functional IFEs
+ * @num_ife_lites: Number of available and functional IFE-LITEs
+ * @num_sfes:      Number of available and functional SFEs
+ * @num_custom:    Number of available and functional CUSTOM
+ */
+struct cam_cpas_sysfs_info {
+	struct kobject *kobj;
+	uint32_t        num_ifes[CAM_CPAS_NUM_SUBPARTS_MAX_TYPES];
+	uint32_t        num_ife_lites[CAM_CPAS_NUM_SUBPARTS_MAX_TYPES];
+	uint32_t        num_sfes[CAM_CPAS_NUM_SUBPARTS_MAX_TYPES];
+	uint32_t        num_custom[CAM_CPAS_NUM_SUBPARTS_MAX_TYPES];
+};
+
 /**
  * struct cam_cpas_private_soc : CPAS private DT info
  *
@@ -235,10 +261,12 @@ struct cam_cpas_soc_irq_data {
  *      camnoc axi clock
  * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target
  * @fuse_info: fuse information
+ * @sysfs_info: Camera subparts sysfs information
  * @rpmh_info: RPMH BCM info
  * @num_feature_info: number of feature_info entries
  * @feature_info: Structure for storing feature information
  * @num_caches: Number of last level caches
+ * @part_info: Camera Hw subpart info
  * @llcc_info: Cache info
  * @enable_smart_qos: Whether to enable Smart QoS mechanism on current chipset
  * @enable_cam_ddr_drv: Whether to enable Camera DDR DRV on current chipset
@@ -265,10 +293,12 @@ struct cam_cpas_private_soc {
 	uint32_t camnoc_axi_clk_bw_margin;
 	uint64_t camnoc_axi_min_ib_bw;
 	struct cam_cpas_fuse_info fuse_info;
+	struct cam_cpas_sysfs_info sysfs_info;
 	uint32_t rpmh_info[CAM_RPMH_BCM_INFO_MAX];
 	uint32_t num_feature_info;
 	struct cam_cpas_feature_info  feature_info[CAM_CPAS_MAX_FUSE_FEATURE];
 	uint32_t num_caches;
+	uint32_t part_info;
 	struct cam_sys_cache_info *llcc_info;
 	bool enable_smart_qos;
 	bool enable_cam_ddr_drv;

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

@@ -10,6 +10,10 @@
 #include "cam_cpas_api.h"
 #include "cam_cpas_hw.h"
 
+/* Camera Hw parts array indices */
+#define CAM_CPAS_PART_MAX_FUSE_BITS 8
+#define CAM_CPAS_PART_MAX_FUSE_BIT_INFO 2
+
 /**
  * enum cam_camnoc_hw_irq_type - Enum for camnoc error types
  *
@@ -307,6 +311,18 @@ struct cam_cpas_hw_errata_wa {
 	} data;
 };
 
+/**
+ * struct cam_cpas_subpart_info : Struct for camera Hw parts info
+ *
+ * @num_bits: Number of entries in hw_bitmap_mask
+ * @hw_bitmap_mask: Contains Fuse flag and hw_map info
+ *
+ */
+struct cam_cpas_subpart_info {
+	uint32_t num_bits;
+	uint32_t hw_bitmap_mask[CAM_CPAS_PART_MAX_FUSE_BITS][CAM_CPAS_PART_MAX_FUSE_BIT_INFO];
+};
+
 /**
  * struct cam_cpas_hw_errata_wa_list : List of HW Errata workaround info
  *

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

@@ -296,6 +296,16 @@ enum cam_sys_cache_llcc_staling_op_type {
 	CAM_LLCC_NOTIFY_STALING_OPS_MAX
 };
 
+/**
+ * enum cam_subparts_index - Enum for camera subparts indices
+ */
+enum cam_subparts_index {
+	CAM_IFE_HW_IDX,
+	CAM_IFE_LITE_HW_IDX,
+	CAM_SFE_HW_IDX,
+	CAM_CUSTOM_HW_IDX
+};
+
 /**
  * struct cam_camnoc_irq_slave_err_data : Data for Slave error.
  *
@@ -573,6 +583,23 @@ struct cam_axi_vote {
 	struct cam_cpas_axi_per_path_bw_vote axi_path[CAM_CPAS_MAX_PATHS_PER_CLIENT];
 };
 
+/**
+ * cam_cpas_prepare_subpart_info()
+ *
+ * @brief: API to update the number of ifes, ife_lites, sfes and custom
+ *         in the struct cam_cpas_private_soc.
+ *
+ * @idx                   : Camera subpart index
+ * @num_subpart_available : Number of available subparts
+ * @num_subpart_functional: Number of functional subparts
+ *
+ * @returns 0 on success & -EINVAL when @subpart_type is invalid.
+ *
+ */
+int cam_cpas_prepare_subpart_info(
+	enum cam_subparts_index idx, uint32_t num_subpart_available,
+	uint32_t num_subpart_functional);
+
 /**
  * cam_cpas_register_client()
  *

+ 18 - 0
drivers/cam_cust/cam_custom_dev.c

@@ -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.
  */
 
 #include <linux/delay.h>
@@ -10,6 +11,7 @@
 #include <linux/iommu.h>
 #include <linux/timer.h>
 #include <linux/kernel.h>
+#include <dt-bindings/msm-camera.h>
 
 #include <media/cam_req_mgr.h>
 
@@ -23,6 +25,7 @@
 #include "camera_main.h"
 
 static struct cam_custom_dev g_custom_dev;
+static uint32_t g_num_custom_hws;
 
 static void cam_custom_dev_iommu_fault_handler(
 	struct cam_smmu_pf_info *pf_info)
@@ -117,6 +120,11 @@ static int cam_custom_component_bind(struct device *dev,
 	g_custom_dev.sd.internal_ops = &cam_custom_subdev_internal_ops;
 	g_custom_dev.sd.close_seq_prior = CAM_SD_CLOSE_HIGH_PRIORITY;
 
+	if (!cam_cpas_is_feature_supported(CAM_CPAS_CUSTOM_FUSE, BIT(0), NULL)) {
+		CAM_DBG(CAM_CUSTOM, "CUSTOM:0 is not supported");
+		goto err;
+	}
+
 	rc = cam_subdev_probe(&g_custom_dev.sd, pdev, CAM_CUSTOM_DEV_NAME,
 		CAM_CUSTOM_DEVICE_TYPE);
 	if (rc) {
@@ -167,6 +175,14 @@ err:
 	return rc;
 }
 
+void cam_custom_get_num_hws(uint32_t *custom_num)
+{
+	if (custom_num)
+		*custom_num = g_num_custom_hws;
+	else
+		CAM_ERR(CAM_CUSTOM, "Invalid argument, g_num_custom_hws: %u", g_num_custom_hws);
+}
+
 static void cam_custom_component_unbind(struct device *dev,
 	struct device *master_dev, void *data)
 {
@@ -204,6 +220,8 @@ static int cam_custom_dev_probe(struct platform_device *pdev)
 	int rc = 0;
 
 	CAM_DBG(CAM_CUSTOM, "Adding Custom HW component");
+	g_num_custom_hws++;
+
 	rc = component_add(&pdev->dev, &cam_custom_component_ops);
 	if (rc)
 		CAM_ERR(CAM_CUSTOM, "failed to add component rc: %d", rc);

+ 18 - 0
drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c

@@ -150,6 +150,16 @@ enum cam_isp_resource_type
 	}
 }
 
+static void cam_custom_mgr_count_functional_hws(uint32_t num_custom_functional)
+{
+	int i;
+
+	for (i = 0; i < CAM_CUSTOM_CSID_HW_MAX; i++) {
+		if (g_custom_hw_mgr.custom_hw[i])
+			num_custom_functional++;
+	}
+}
+
 static int cam_custom_hw_mgr_deinit_hw_res(
 	struct cam_custom_hw_mgr_res *hw_mgr_res)
 {
@@ -1467,6 +1477,7 @@ int cam_custom_hw_mgr_init(struct device_node *of_node,
 {
 	int rc = 0;
 	int i, j;
+	uint32_t num_custom_available, num_custom_functional = 0;
 
 	memset(&g_custom_hw_mgr, 0, sizeof(g_custom_hw_mgr));
 	mutex_init(&g_custom_hw_mgr.ctx_mutex);
@@ -1545,6 +1556,13 @@ int cam_custom_hw_mgr_init(struct device_node *of_node,
 	if (iommu_hdl)
 		*iommu_hdl = g_custom_hw_mgr.img_iommu_hdl;
 
+	cam_custom_get_num_hws(&num_custom_available);
+	cam_custom_mgr_count_functional_hws(&num_custom_functional);
+	rc = cam_cpas_prepare_subpart_info(CAM_CUSTOM_HW_IDX, num_custom_available,
+		num_custom_functional);
+	if (rc)
+		CAM_ERR(CAM_CUSTOM, "Failed to populate num_custom, rc: %d", rc);
+
 	CAM_DBG(CAM_CUSTOM, "HW manager initialized");
 	return 0;
 }

+ 11 - 0
drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only
  *
  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_CUSTOM_HW_MGR_H_
@@ -126,6 +127,16 @@ struct cam_custom_hw_mgr {
 	struct cam_custom_hw_mgr_ctx   ctx_pool[CAM_CTX_MAX];
 };
 
+/**
+ * cam_custom_get_num_hws()
+ *
+ * @brief : Populates number of custom.
+ *
+ * @num_custom : Fills number of custom hws in the address passed.
+ *
+ */
+void cam_custom_get_num_hws(uint32_t *num_custom);
+
 /**
  * cam_custom_hw_mgr_init()
  *

+ 40 - 19
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -72,7 +72,8 @@ static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = {
 };
 
 static struct cam_ife_hw_mgr g_ife_hw_mgr;
-static uint32_t g_num_ife, g_num_ife_lite, g_num_sfe;
+static uint32_t g_num_ife_available, g_num_ife_lite_available, g_num_sfe_available;
+static uint32_t g_num_ife_functional, g_num_ife_lite_functional, g_num_sfe_functional;
 static uint32_t max_ife_out_res, max_sfe_out_res;
 
 static int cam_ife_mgr_find_core_idx(int split_id, struct cam_ife_hw_mgr_ctx *ctx,
@@ -2535,48 +2536,49 @@ err:
 	return rc;
 }
 
-static inline void cam_ife_mgr_count_sfe(void)
+static inline void cam_ife_mgr_count_functional_sfe(void)
 {
 	int i;
 
-	g_num_sfe = 0;
+	g_num_sfe_functional = 0;
 
 	for (i = 0; i < CAM_SFE_HW_NUM_MAX; i++) {
 		if (g_ife_hw_mgr.sfe_devices[i])
-			g_num_sfe++;
+			g_num_sfe_functional++;
 	}
 
-	CAM_DBG(CAM_ISP, "counted %u SFEs", g_num_sfe);
+	CAM_DBG(CAM_ISP, "counted %u functional SFEs", g_num_sfe_functional);
 }
 
-static inline void cam_ife_mgr_count_ife(void)
+static inline void cam_ife_mgr_count_functional_ife(void)
 {
 	int i;
 
-	g_num_ife = 0;
-	g_num_ife_lite = 0;
+	g_num_ife_functional = 0;
+	g_num_ife_lite_functional = 0;
 
 	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
 		if (g_ife_hw_mgr.ife_devices[i]) {
 			if (g_ife_hw_mgr.ife_dev_caps[i].is_lite)
-				g_num_ife_lite++;
+				g_num_ife_lite_functional++;
 			else
-				g_num_ife++;
+				g_num_ife_functional++;
 		}
 	}
-	CAM_DBG(CAM_ISP, "counted %d IFE and %d IFE lite", g_num_ife, g_num_ife_lite);
+	CAM_DBG(CAM_ISP, "counted functional %d IFE and %d IFE lite", g_num_ife_functional,
+		g_num_ife_lite_functional);
 }
 
 static int cam_convert_hw_idx_to_sfe_hw_num(int hw_idx)
 {
-	if (hw_idx < g_num_sfe) {
+	if (hw_idx < g_num_sfe_available) {
 		switch (hw_idx) {
 		case 0: return CAM_ISP_SFE0_HW;
 		case 1: return CAM_ISP_SFE1_HW;
 		}
 	} else {
-		CAM_ERR(CAM_ISP, "SFE hw idx %d out-of-bounds max %u",
-			hw_idx, g_num_sfe);
+		CAM_ERR(CAM_ISP, "SFE hw idx %d out-of-bounds max available %u",
+			hw_idx, g_num_sfe_available);
 	}
 
 	return 0;
@@ -2584,14 +2586,14 @@ static int cam_convert_hw_idx_to_sfe_hw_num(int hw_idx)
 
 static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx)
 {
-	if (hw_idx < g_num_ife) {
+	if (hw_idx < g_num_ife_available) {
 		switch (hw_idx) {
 		case 0: return CAM_ISP_IFE0_HW;
 		case 1: return CAM_ISP_IFE1_HW;
 		case 2: return CAM_ISP_IFE2_HW;
 		}
-	} else if (hw_idx < g_num_ife + g_num_ife_lite) {
-		switch (hw_idx - g_num_ife) {
+	} else if (hw_idx < g_num_ife_available + g_num_ife_lite_available) {
+		switch (hw_idx - g_num_ife_available) {
 		case 0: return CAM_ISP_IFE0_LITE_HW;
 		case 1: return CAM_ISP_IFE1_LITE_HW;
 		case 2: return CAM_ISP_IFE2_LITE_HW;
@@ -16076,8 +16078,27 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl,
 		*iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl;
 
 	cam_ife_hw_mgr_debug_register();
-	cam_ife_mgr_count_ife();
-	cam_ife_mgr_count_sfe();
+	cam_ife_mgr_count_functional_ife();
+	cam_ife_mgr_count_functional_sfe();
+
+	cam_vfe_get_num_ifes(&g_num_ife_available);
+	rc = cam_cpas_prepare_subpart_info(CAM_IFE_HW_IDX, g_num_ife_available,
+		g_num_ife_functional);
+	if (rc)
+		CAM_ERR(CAM_ISP, "Failed to populate num_ifes, rc: %d", rc);
+
+	cam_vfe_get_num_ife_lites(&g_num_ife_lite_available);
+	rc = cam_cpas_prepare_subpart_info(CAM_IFE_LITE_HW_IDX, g_num_ife_lite_available,
+		g_num_ife_lite_functional);
+	if (rc)
+		CAM_ERR(CAM_ISP, "Failed to populate num_ife_lites, rc: %d", rc);
+
+	cam_sfe_get_num_hws(&g_num_sfe_available);
+	rc = cam_cpas_prepare_subpart_info(CAM_SFE_HW_IDX, g_num_sfe_available,
+		g_num_sfe_functional);
+	if (rc)
+		CAM_ERR(CAM_ISP, "Failed to populate num_sfes, rc: %d", rc);
+
 	cam_common_register_mini_dump_cb(cam_ife_hw_mgr_mini_dump_cb,
 		"CAM_ISP", NULL);
 	cam_ife_mgr_test_irq_lines_at_probe(&g_ife_hw_mgr);

+ 15 - 11
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_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/slab.h>
@@ -31,6 +31,20 @@ static int cam_ife_csid_component_bind(struct device *dev,
 
 	CAM_DBG(CAM_ISP, "Binding IFE CSID component");
 
+	/* get ife csid hw index */
+	rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Failed to read cell-index of IFE CSID HW, rc: %d", rc);
+		goto err;
+	}
+
+	if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_FUSE, BIT(csid_dev_idx), NULL) ||
+		!cam_cpas_is_feature_supported(CAM_CPAS_ISP_LITE_FUSE,
+		BIT(csid_dev_idx), NULL)) {
+		CAM_DBG(CAM_ISP, "CSID[%d] not supported based on fuse", csid_dev_idx);
+		goto err;
+	}
+
 	hw_intf = kzalloc(sizeof(*hw_intf), GFP_KERNEL);
 	if (!hw_intf) {
 		rc = -ENOMEM;
@@ -43,8 +57,6 @@ static int cam_ife_csid_component_bind(struct device *dev,
 		goto free_hw_intf;
 	}
 
-	/* get ife csid hw index */
-	of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx);
 	/* get ife csid hw information */
 	match_dev = of_match_device(pdev->dev.driver->of_match_table,
 		&pdev->dev);
@@ -65,14 +77,6 @@ static int cam_ife_csid_component_bind(struct device *dev,
 
 	csid_core_info = (struct cam_ife_csid_core_info  *)match_dev->data;
 
-	if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_FUSE,
-		(1 << hw_intf->hw_idx), NULL) ||
-		!cam_cpas_is_feature_supported(CAM_CPAS_ISP_LITE_FUSE,
-		(1 << hw_intf->hw_idx), NULL)) {
-		CAM_DBG(CAM_ISP, "CSID[%d] not supported based on fuse",
-			csid_dev_idx);
-		goto free_hw_info;
-	}
 	/* call the driver init and fill csid_hw_info->core_info */
 	rc = cam_ife_csid_hw_probe_init(hw_intf, csid_core_info, false);
 

+ 9 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h

@@ -356,6 +356,15 @@ struct cam_sfe_acquire_args {
 	};
 };
 
+/*
+ * cam_sfe_get_num_hws()
+ *
+ * @brief : Populates number of SFEs.
+ *
+ * @num_sfes : Fills number of SFEs in the address passed.
+ */
+void cam_sfe_get_num_hws(uint32_t *num_sfes);
+
 /*
  * cam_sfe_hw_init()
  *

+ 18 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h

@@ -408,6 +408,24 @@ struct cam_vfe_generic_debug_config {
 	bool      enable_ife_frame_irqs;
 };
 
+/*
+ * cam_vfe_get_num_ifes()
+ *
+ * @brief:         Gets number of IFEs
+ *
+ * @num_ifes:      Fills number of IFES in the address passed
+ */
+void cam_vfe_get_num_ifes(uint32_t *num_ifes);
+
+/*
+ * cam_vfe_get_num_ife_lites()
+ *
+ * @brief:         Gets number of IFE-LITEs
+ *
+ * @num_ifes:      Fills number of IFE-LITES in the address passed
+ */
+void cam_vfe_get_num_ife_lites(uint32_t *num_ife_lites);
+
 /*
  * cam_vfe_hw_init()
  *

+ 27 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c

@@ -1,13 +1,14 @@
 // 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.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/slab.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of_device.h>
 #include <linux/module.h>
+#include <dt-bindings/msm-camera.h>
 #include "cam_sfe_dev.h"
 #include "cam_sfe_core.h"
 #include "cam_sfe_soc.h"
@@ -18,6 +19,7 @@
 #include "camera_main.h"
 
 static struct cam_isp_hw_intf_data cam_sfe_hw_list[CAM_SFE_HW_NUM_MAX];
+static uint32_t g_num_sfe_hws;
 
 static int cam_sfe_component_bind(struct device *dev,
 	struct device *master_dev, void *data)
@@ -30,18 +32,28 @@ static int cam_sfe_component_bind(struct device *dev,
 	struct cam_sfe_hw_info            *hw_info = NULL;
 	struct platform_device            *pdev = NULL;
 	struct cam_sfe_soc_private        *soc_priv;
+	uint32_t                           sfe_dev_idx;
 	int                                i, rc = 0;
 
 	pdev = to_platform_device(dev);
+
+	rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &sfe_dev_idx);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "Failed to read cell-index of SFE HW, rc: %d", rc);
+		goto end;
+	}
+
+	if (!cam_cpas_is_feature_supported(CAM_CPAS_SFE_FUSE, BIT(sfe_dev_idx), NULL)) {
+		CAM_DBG(CAM_SFE, "SFE:%d is not supported", sfe_dev_idx);
+		goto end;
+	}
+
 	sfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
 	if (!sfe_hw_intf) {
 		rc = -ENOMEM;
 		goto end;
 	}
 
-	of_property_read_u32(pdev->dev.of_node,
-		"cell-index", &sfe_hw_intf->hw_idx);
-
 	sfe_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
 	if (!sfe_info) {
 		rc = -ENOMEM;
@@ -52,6 +64,7 @@ static int cam_sfe_component_bind(struct device *dev,
 	sfe_info->soc_info.dev = &pdev->dev;
 	sfe_info->soc_info.dev_name = pdev->name;
 	sfe_hw_intf->hw_priv = sfe_info;
+	sfe_hw_intf->hw_idx = sfe_dev_idx;
 	sfe_hw_intf->hw_ops.get_hw_caps = cam_sfe_get_hw_caps;
 	sfe_hw_intf->hw_ops.init = cam_sfe_init_hw;
 	sfe_hw_intf->hw_ops.deinit = cam_sfe_deinit_hw;
@@ -196,11 +209,21 @@ const static struct component_ops cam_sfe_component_ops = {
 	.unbind = cam_sfe_component_unbind,
 };
 
+void cam_sfe_get_num_hws(uint32_t *sfe_num)
+{
+	if (sfe_num)
+		*sfe_num = g_num_sfe_hws;
+	else
+		CAM_ERR(CAM_SFE, "Invalid argument, g_num_sfe_hws: %u", g_num_sfe_hws);
+}
+
 int cam_sfe_probe(struct platform_device *pdev)
 {
 	int rc = 0;
 
 	CAM_DBG(CAM_SFE, "Adding SFE component");
+	g_num_sfe_hws++;
+
 	rc = component_add(&pdev->dev, &cam_sfe_component_ops);
 	if (rc)
 		CAM_ERR(CAM_SFE, "failed to add component rc: %d", rc);

+ 50 - 13
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 
@@ -9,13 +10,13 @@
 #include <linux/of_device.h>
 #include <linux/component.h>
 
-#include "cam_vfe_dev.h"
 #include "cam_vfe_core.h"
 #include "cam_vfe_soc.h"
 #include "cam_debug_util.h"
 #include <dt-bindings/msm-camera.h>
 
 static  struct cam_isp_hw_intf_data cam_vfe_hw_list[CAM_VFE_HW_NUM_MAX];
+static uint32_t g_num_ife_hws, g_num_ife_lite_hws;
 
 static int cam_vfe_component_bind(struct device *dev,
 	struct device *master_dev, void *data)
@@ -28,24 +29,26 @@ static int cam_vfe_component_bind(struct device *dev,
 	int                                rc = 0;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct cam_vfe_soc_private   *vfe_soc_priv;
+	uint32_t  vfe_dev_idx;
 	uint32_t  i;
 
-	vfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
-	if (!vfe_hw_intf) {
-		rc = -ENOMEM;
+	rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &vfe_dev_idx);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Failed to read cell-index of IFE HW, rc: %d", rc);
 		goto end;
 	}
 
-	of_property_read_u32(pdev->dev.of_node,
-		"cell-index", &vfe_hw_intf->hw_idx);
-
-	if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_FUSE,
-		(1 << vfe_hw_intf->hw_idx), 0) ||
+	if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_FUSE, BIT(vfe_dev_idx), NULL) ||
 		!cam_cpas_is_feature_supported(CAM_CPAS_ISP_LITE_FUSE,
-		(1 << vfe_hw_intf->hw_idx), 0)) {
-		CAM_DBG(CAM_ISP, "IFE:%d is not supported",
-			vfe_hw_intf->hw_idx);
-		goto free_vfe_hw_intf;
+		BIT(vfe_dev_idx), NULL)) {
+		CAM_DBG(CAM_ISP, "IFE:%d is not supported", vfe_dev_idx);
+		goto end;
+	}
+
+	vfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!vfe_hw_intf) {
+		rc = -ENOMEM;
+		goto end;
 	}
 
 	vfe_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
@@ -58,6 +61,7 @@ static int cam_vfe_component_bind(struct device *dev,
 	vfe_hw->soc_info.dev = &pdev->dev;
 	vfe_hw->soc_info.dev_name = pdev->name;
 	vfe_hw_intf->hw_priv = vfe_hw;
+	vfe_hw_intf->hw_idx = vfe_dev_idx;
 	vfe_hw_intf->hw_ops.get_hw_caps = cam_vfe_get_hw_caps;
 	vfe_hw_intf->hw_ops.init = cam_vfe_init_hw;
 	vfe_hw_intf->hw_ops.deinit = cam_vfe_deinit_hw;
@@ -199,11 +203,44 @@ const static struct component_ops cam_vfe_component_ops = {
 	.unbind = cam_vfe_component_unbind,
 };
 
+void cam_vfe_get_num_ifes(uint32_t *num_ifes)
+{
+	if (num_ifes)
+		*num_ifes = g_num_ife_hws;
+	else
+		CAM_ERR(CAM_ISP, "Invalid argument, g_num_ife_hws: %u", g_num_ife_hws);
+}
+
+void cam_vfe_get_num_ife_lites(uint32_t *num_ife_lites)
+{
+	if (num_ife_lites)
+		*num_ife_lites = g_num_ife_lite_hws;
+	else
+		CAM_ERR(CAM_ISP, "Invalid argument, g_num_ife_lite_hws: %u", g_num_ife_lite_hws);
+}
+
 int cam_vfe_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	const char *compatible_name;
+	struct device_node *of_node = NULL;
 
 	CAM_DBG(CAM_ISP, "Adding VFE component");
+	of_node = pdev->dev.of_node;
+
+	rc = of_property_read_string_index(of_node, "compatible", 0,
+			(const char **)&compatible_name);
+	if (rc)
+		CAM_ERR(CAM_ISP, "No compatible string present for: %s, rc: %d",
+			pdev->name, rc);
+
+	if (strnstr(compatible_name, "lite", strlen(compatible_name)) != NULL)
+		g_num_ife_lite_hws++;
+	else if (strnstr(compatible_name, "vfe", strlen(compatible_name)) != NULL)
+		g_num_ife_hws++;
+	else
+		CAM_ERR(CAM_ISP, "Failed to increment number of IFEs/IFE-LITEs");
+
 	rc = component_add(&pdev->dev, &cam_vfe_component_ops);
 	if (rc)
 		CAM_ERR(CAM_ISP, "failed to add component rc: %d", rc);

+ 31 - 0
drivers/cam_utils/cam_compat.c

@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 
 #include <soc/qcom/rpmh.h>
+#include <soc/qcom/socinfo.h>
 
 #include "cam_compat.h"
 #include "cam_debug_util.h"
@@ -819,3 +820,33 @@ bool cam_secure_get_vfe_fd_port_config(void)
 #endif
 }
 
+#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
+int cam_get_subpart_info(uint32_t *part_info, uint32_t max_num_cam)
+{
+	int rc = 0;
+	int num_cam;
+
+	num_cam = socinfo_get_part_count(PART_CAMERA);
+	if (num_cam != max_num_cam) {
+		CAM_ERR(CAM_CPAS, "Unsupported number of parts: %d", num_cam);
+		return -EINVAL;
+	}
+
+	/*
+	 * If bit value in part_info is "0" then HW is available.
+	 * If bit value in part_info is "1" then HW is unavailable.
+	 */
+	rc = socinfo_get_subpart_info(PART_CAMERA, part_info, num_cam);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Failed while getting subpart_info, rc = %d.", rc);
+		return rc;
+	}
+
+	return 0;
+}
+#else
+int cam_get_subpart_info(uint32_t *part_info, uint32_t max_num_cam)
+{
+	return 0;
+}
+#endif

+ 2 - 0
drivers/cam_utils/cam_compat.h

@@ -113,4 +113,6 @@ unsigned long cam_update_dma_map_attributes(unsigned long attr);
 
 size_t cam_align_dma_buf_size(size_t len);
 
+int cam_get_subpart_info(uint32_t *part_info, uint32_t max_num_cam);
+
 #endif /* _CAM_COMPAT_H_ */

+ 4 - 1
dt-bindings/msm-camera.h

@@ -115,7 +115,10 @@
 #define CAM_CPAS_ISP_LITE_FUSE 6
 #define CAM_CPAS_CSIPHY_FUSE   7
 #define CAM_CPAS_IPE_VID_OUT_8BPP_LIMIT_ENABLE 8
-#define CAM_CPAS_FUSE_FEATURE_MAX 9
+#define CAM_CPAS_SFE_FUSE 9
+#define CAM_CPAS_CUSTOM_FUSE 10
+#define CAM_CPAS_CAM_FUSE 11
+#define CAM_CPAS_FUSE_FEATURE_MAX 12
 
 #define CCI_MASTER_0         0
 #define CCI_MASTER_1         1

+ 3 - 0
include/uapi/camera/media/cam_cpas.h

@@ -99,6 +99,9 @@
 #define CAM_CPAS_NON_SECURE_DOMAIN  0
 #define CAM_CPAS_SECURE_DOMAIN      1
 
+/* sysfs entry of camera subparts info */
+#define CAM_SYSFS_SUBPARTS_INFO_FILENAME "subparts_info"
+
 /**
  * struct cam_cpas_fuse_value - CPAS fuse value
  *