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 <quic_kard@quicinc.com>
This commit is contained in:
Karthik Dillibabu
2023-03-13 11:00:08 +05:30
committed by Camera Software Integration
parent 0aa784b1d9
commit f910aa0b4f
20 changed files with 580 additions and 56 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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",

View File

@@ -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;

View File

@@ -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
*

View File

@@ -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()
*

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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()
*

View File

@@ -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);

View File

@@ -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);

View File

@@ -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()
*

View File

@@ -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()
*

View File

@@ -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);

View File

@@ -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,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);

View File

@@ -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

View File

@@ -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_ */

View File

@@ -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

View File

@@ -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
*