diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 13f19b8fba..c265f587ed 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/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); diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index f05cab42fa..82a320e1a8 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/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; diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index 1228a27edd..428594f069 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/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 #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) { diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index 9fca373057..fc70e0c7dd 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/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", diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index cce7264bac..c6f1d8b420 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/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; diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index 140ad2c181..27f47ecd01 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/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 * diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index f80758ba7c..a653bc4224 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/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() * diff --git a/drivers/cam_cust/cam_custom_dev.c b/drivers/cam_cust/cam_custom_dev.c index a093883e5c..781d9aeb01 100644 --- a/drivers/cam_cust/cam_custom_dev.c +++ b/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 @@ -10,6 +11,7 @@ #include #include #include +#include #include @@ -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); diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c index b4ed085463..5291aee65c 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c +++ b/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; } diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h index bd8a119f25..f5add5d149 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h +++ b/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() * diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 32906d82dd..d306b64717 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/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); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c index bd5d675396..8a3dfa1546 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c +++ b/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 @@ -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); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h index 2cf6521e6c..c6fcb422b0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h +++ b/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() * diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index ac8163fb92..1aae5eac35 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/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() * diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c index f5c8e3689c..645e73cdec 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c +++ b/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 #include #include #include +#include #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); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c index 4ef9f0b0c1..d0cdbddbb9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c +++ b/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 #include -#include "cam_vfe_dev.h" #include "cam_vfe_core.h" #include "cam_vfe_soc.h" #include "cam_debug_util.h" #include 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,26 +29,28 @@ 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; + 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; + } + + 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, + 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; } - 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) || - !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; - } - vfe_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); if (!vfe_hw) { rc = -ENOMEM; @@ -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); diff --git a/drivers/cam_utils/cam_compat.c b/drivers/cam_utils/cam_compat.c index 7dbfd26fa5..889fc58d62 100644 --- a/drivers/cam_utils/cam_compat.c +++ b/drivers/cam_utils/cam_compat.c @@ -10,6 +10,7 @@ #include #include +#include #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 diff --git a/drivers/cam_utils/cam_compat.h b/drivers/cam_utils/cam_compat.h index 6358c3d35f..febfe9b9ad 100644 --- a/drivers/cam_utils/cam_compat.h +++ b/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_ */ diff --git a/dt-bindings/msm-camera.h b/dt-bindings/msm-camera.h index 766a0dad33..4857b0de94 100644 --- a/dt-bindings/msm-camera.h +++ b/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 diff --git a/include/uapi/camera/media/cam_cpas.h b/include/uapi/camera/media/cam_cpas.h index ed07894f43..f662aba783 100644 --- a/include/uapi/camera/media/cam_cpas.h +++ b/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 *