Accessing cdm_mgr.nodes.device without holding lock cam_cdm_intf_devices.lock. So added locks before shared variable access to avoid data race conditions. CRs-Fixed: 3372392 Change-Id: If3045410df6ed5a224e62392b5e17d5f45339fa5 Signed-off-by: Dharmender Sharma <quic_dharshar@quicinc.com>
831 lines
20 KiB
C
831 lines
20 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
#include <linux/module.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#include "cam_cdm_intf_api.h"
|
|
#include "cam_cdm.h"
|
|
#include "cam_cdm_virtual.h"
|
|
#include "cam_soc_util.h"
|
|
#include "cam_cdm_soc.h"
|
|
#include "cam_cdm_core_common.h"
|
|
#include "camera_main.h"
|
|
|
|
static struct cam_cdm_intf_mgr cdm_mgr;
|
|
static DEFINE_MUTEX(cam_cdm_mgr_lock);
|
|
|
|
static const struct of_device_id msm_cam_cdm_intf_dt_match[] = {
|
|
{ .compatible = "qcom,cam-cdm-intf", },
|
|
{}
|
|
};
|
|
|
|
static int get_cdm_mgr_refcount(void)
|
|
{
|
|
int rc = 0;
|
|
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
if (cdm_mgr.probe_done == false) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr not probed yet");
|
|
rc = -EPERM;
|
|
} else {
|
|
CAM_DBG(CAM_CDM, "CDM intf mgr get refcount=%d",
|
|
cdm_mgr.refcount);
|
|
cdm_mgr.refcount++;
|
|
}
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
return rc;
|
|
}
|
|
|
|
static void put_cdm_mgr_refcount(void)
|
|
{
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
if (cdm_mgr.probe_done == false) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr not probed yet");
|
|
} else {
|
|
CAM_DBG(CAM_CDM, "CDM intf mgr put refcount=%d",
|
|
cdm_mgr.refcount);
|
|
if (cdm_mgr.refcount > 0) {
|
|
cdm_mgr.refcount--;
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "Refcount put when zero");
|
|
WARN_ON(1);
|
|
}
|
|
}
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
}
|
|
|
|
static int get_cdm_iommu_handle(struct cam_iommu_handle *cdm_handles,
|
|
uint32_t hw_idx)
|
|
{
|
|
int rc = -EPERM;
|
|
struct cam_hw_intf *hw = cdm_mgr.nodes[hw_idx].device;
|
|
|
|
if (hw->hw_ops.get_hw_caps) {
|
|
rc = hw->hw_ops.get_hw_caps(hw->hw_priv, cdm_handles,
|
|
sizeof(struct cam_iommu_handle));
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int get_cdm_index_by_id(char *identifier,
|
|
uint32_t cell_index, uint32_t *hw_index)
|
|
{
|
|
int rc = -EPERM, i, j;
|
|
char client_name[128], name_index[160];
|
|
|
|
snprintf(client_name, sizeof(client_name), "%s", identifier);
|
|
snprintf(name_index, sizeof(name_index), "%s%d",
|
|
identifier, cell_index);
|
|
|
|
CAM_DBG(CAM_CDM,
|
|
"Looking for HW id of =%s or %s and index=%d cdm_count %d",
|
|
identifier, name_index, cell_index, cdm_mgr.cdm_count);
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
for (i = 0; i < cdm_mgr.cdm_count; i++) {
|
|
mutex_lock(&cdm_mgr.nodes[i].lock);
|
|
CAM_DBG(CAM_CDM, "dt_num_supported_clients=%d",
|
|
cdm_mgr.nodes[i].data->dt_num_supported_clients);
|
|
|
|
for (j = 0; j <
|
|
cdm_mgr.nodes[i].data->dt_num_supported_clients; j++) {
|
|
CAM_DBG(CAM_CDM, "client name:%s dev Index: %d",
|
|
cdm_mgr.nodes[i].data->dt_cdm_client_name[j],
|
|
i);
|
|
if (!strcmp(
|
|
cdm_mgr.nodes[i].data->dt_cdm_client_name[j],
|
|
client_name) || !strcmp(
|
|
cdm_mgr.nodes[i].data->dt_cdm_client_name[j],
|
|
name_index)) {
|
|
rc = 0;
|
|
*hw_index = i;
|
|
break;
|
|
}
|
|
}
|
|
mutex_unlock(&cdm_mgr.nodes[i].lock);
|
|
if (rc == 0)
|
|
break;
|
|
}
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int cam_cdm_get_iommu_handle(char *identifier,
|
|
struct cam_iommu_handle *cdm_handles)
|
|
{
|
|
int i, j, rc = -EPERM;
|
|
|
|
if ((!identifier) || (!cdm_handles))
|
|
return -EINVAL;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
return rc;
|
|
}
|
|
CAM_DBG(CAM_CDM, "Looking for Iommu handle of %s", identifier);
|
|
|
|
for (i = 0; i < cdm_mgr.cdm_count; i++) {
|
|
mutex_lock(&cdm_mgr.nodes[i].lock);
|
|
if (!cdm_mgr.nodes[i].data) {
|
|
mutex_unlock(&cdm_mgr.nodes[i].lock);
|
|
continue;
|
|
}
|
|
CAM_DBG(CAM_CDM, "dt_num_supported_clients=%d",
|
|
cdm_mgr.nodes[i].data->dt_num_supported_clients);
|
|
for (j = 0; j <
|
|
cdm_mgr.nodes[i].data->dt_num_supported_clients;
|
|
j++) {
|
|
CAM_DBG(CAM_CDM, "client name:%s dev Index: %d",
|
|
cdm_mgr.nodes[i].data->dt_cdm_client_name[j],
|
|
i);
|
|
if (!strcmp(
|
|
cdm_mgr.nodes[i].data->dt_cdm_client_name[j],
|
|
identifier)) {
|
|
rc = get_cdm_iommu_handle(cdm_handles, i);
|
|
break;
|
|
}
|
|
}
|
|
mutex_unlock(&cdm_mgr.nodes[i].lock);
|
|
if (rc == 0)
|
|
break;
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_get_iommu_handle);
|
|
|
|
int cam_cdm_acquire(struct cam_cdm_acquire_data *data)
|
|
{
|
|
int rc = -EPERM;
|
|
struct cam_hw_intf *hw;
|
|
struct cam_hw_info *cdm_hw;
|
|
struct cam_cdm *core = NULL;
|
|
uint32_t hw_index = 0;
|
|
|
|
if ((!data) || (!data->base_array_cnt))
|
|
return -EINVAL;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
return rc;
|
|
}
|
|
|
|
if (data->id > CAM_CDM_HW_ANY) {
|
|
CAM_ERR(CAM_CDM,
|
|
"only CAM_CDM_VIRTUAL/CAM_CDM_HW_ANY is supported");
|
|
rc = -EPERM;
|
|
goto end;
|
|
}
|
|
rc = get_cdm_index_by_id(data->identifier, data->cell_index,
|
|
&hw_index);
|
|
if ((rc < 0) && (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM)) {
|
|
CAM_ERR(CAM_CDM, "Failed to identify associated hw id");
|
|
goto end;
|
|
} else {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd) {
|
|
cdm_hw = hw->hw_priv;
|
|
core = (struct cam_cdm *)cdm_hw->core_info;
|
|
data->id = core->id;
|
|
data->hw_idx = hw->hw_idx;
|
|
CAM_DBG(CAM_CDM,
|
|
"Device = %s, hw_index = %d, CDM id = %d",
|
|
data->identifier, hw_index, data->id);
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_ACQUIRE, data,
|
|
sizeof(struct cam_cdm_acquire_data));
|
|
if (rc < 0) {
|
|
CAM_ERR(CAM_CDM, "CDM hw acquire failed");
|
|
goto end;
|
|
}
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "idx %d doesn't have acquire ops",
|
|
hw_index);
|
|
rc = -EPERM;
|
|
}
|
|
}
|
|
end:
|
|
if (rc < 0) {
|
|
CAM_ERR(CAM_CDM, "CDM acquire failed for id=%d name=%s, idx=%d",
|
|
data->id, data->identifier, data->cell_index);
|
|
put_cdm_mgr_refcount();
|
|
}
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_acquire);
|
|
|
|
struct cam_cdm_utils_ops *cam_cdm_publish_ops(void)
|
|
{
|
|
struct cam_hw_version cdm_version;
|
|
|
|
cdm_version.major = 1;
|
|
cdm_version.minor = 0;
|
|
cdm_version.incr = 0;
|
|
cdm_version.reserved = 0;
|
|
|
|
return cam_cdm_get_ops(0, &cdm_version, true);
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_publish_ops);
|
|
|
|
int cam_cdm_release(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EPERM;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd) {
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_RELEASE, &handle,
|
|
sizeof(handle));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM,
|
|
"hw release failed for handle=%x",
|
|
handle);
|
|
} else
|
|
CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops",
|
|
hw_index);
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
if (rc == 0)
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_release);
|
|
|
|
|
|
int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (!data)
|
|
return rc;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
struct cam_cdm_hw_intf_cmd_submit_bl req;
|
|
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd) {
|
|
req.data = data;
|
|
req.handle = handle;
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_SUBMIT_BL, &req,
|
|
sizeof(struct cam_cdm_hw_intf_cmd_submit_bl));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM,
|
|
"hw submit bl failed for handle=%x",
|
|
handle);
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "hw idx %d doesn't have submit ops",
|
|
hw_index);
|
|
}
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_submit_bls);
|
|
|
|
int cam_cdm_stream_on(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.start) {
|
|
rc = hw->hw_ops.start(hw->hw_priv, &handle,
|
|
sizeof(uint32_t));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM,
|
|
"hw start failed handle=%x",
|
|
handle);
|
|
} else {
|
|
CAM_ERR(CAM_CDM,
|
|
"hw idx %d doesn't have start ops",
|
|
hw_index);
|
|
}
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_stream_on);
|
|
|
|
int cam_cdm_stream_off(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.stop) {
|
|
rc = hw->hw_ops.stop(hw->hw_priv, &handle,
|
|
sizeof(uint32_t));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM, "hw stop failed handle=%x",
|
|
handle);
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "hw idx %d doesn't have stop ops",
|
|
hw_index);
|
|
}
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_stream_off);
|
|
|
|
int cam_cdm_reset_hw(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd) {
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_RESET_HW, &handle,
|
|
sizeof(handle));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM,
|
|
"CDM hw release failed for handle=%x",
|
|
handle);
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops",
|
|
hw_index);
|
|
}
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_reset_hw);
|
|
|
|
int cam_cdm_flush_hw(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd) {
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_FLUSH_HW, &handle,
|
|
sizeof(handle));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM,
|
|
"CDM hw release failed for handle=%x",
|
|
handle);
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops",
|
|
hw_index);
|
|
}
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_flush_hw);
|
|
|
|
int cam_cdm_handle_error(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd) {
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_HANDLE_ERROR,
|
|
&handle,
|
|
sizeof(handle));
|
|
if (rc < 0)
|
|
CAM_ERR(CAM_CDM,
|
|
"CDM hw release failed for handle=%x",
|
|
handle);
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops",
|
|
hw_index);
|
|
}
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_handle_error);
|
|
|
|
int cam_cdm_detect_hang_error(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd)
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_CMD_HANG_DETECT,
|
|
&handle,
|
|
sizeof(handle));
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(cam_cdm_detect_hang_error);
|
|
|
|
int cam_cdm_dump_debug_registers(uint32_t handle)
|
|
{
|
|
uint32_t hw_index;
|
|
int rc = -EINVAL;
|
|
struct cam_hw_intf *hw;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
hw_index = CAM_CDM_GET_HW_IDX(handle);
|
|
if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) {
|
|
hw = cdm_mgr.nodes[hw_index].device;
|
|
if (hw && hw->hw_ops.process_cmd)
|
|
rc = hw->hw_ops.process_cmd(hw->hw_priv,
|
|
CAM_CDM_HW_INTF_DUMP_DBG_REGS,
|
|
&handle,
|
|
sizeof(handle));
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
|
|
int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw,
|
|
struct cam_cdm_private_dt_data *data, enum cam_cdm_type type,
|
|
uint32_t *index)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if ((!hw) || (!data) || (!index))
|
|
return rc;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
return rc;
|
|
}
|
|
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
if ((type == CAM_VIRTUAL_CDM) &&
|
|
(!cdm_mgr.nodes[CAM_SW_CDM_INDEX].device)) {
|
|
mutex_lock(&cdm_mgr.nodes[CAM_SW_CDM_INDEX].lock);
|
|
cdm_mgr.nodes[CAM_SW_CDM_INDEX].device = hw;
|
|
cdm_mgr.nodes[CAM_SW_CDM_INDEX].data = data;
|
|
*index = cdm_mgr.cdm_count;
|
|
mutex_unlock(&cdm_mgr.nodes[CAM_SW_CDM_INDEX].lock);
|
|
cdm_mgr.cdm_count++;
|
|
rc = 0;
|
|
} else if ((type == CAM_HW_CDM) && (cdm_mgr.cdm_count > 0)) {
|
|
mutex_lock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock);
|
|
cdm_mgr.nodes[cdm_mgr.cdm_count].device = hw;
|
|
cdm_mgr.nodes[cdm_mgr.cdm_count].data = data;
|
|
*index = cdm_mgr.cdm_count;
|
|
mutex_unlock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock);
|
|
cdm_mgr.cdm_count++;
|
|
rc = 0;
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "CDM registration failed type=%d count=%d",
|
|
type, cdm_mgr.cdm_count);
|
|
}
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
|
|
int cam_cdm_intf_deregister_hw_cdm(struct cam_hw_intf *hw,
|
|
struct cam_cdm_private_dt_data *data, enum cam_cdm_type type,
|
|
uint32_t index)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if ((!hw) || (!data))
|
|
return rc;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
rc = -EPERM;
|
|
return rc;
|
|
}
|
|
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
if ((type == CAM_VIRTUAL_CDM) &&
|
|
(hw == cdm_mgr.nodes[CAM_SW_CDM_INDEX].device) &&
|
|
(index == CAM_SW_CDM_INDEX)) {
|
|
mutex_lock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock);
|
|
cdm_mgr.nodes[CAM_SW_CDM_INDEX].device = NULL;
|
|
cdm_mgr.nodes[CAM_SW_CDM_INDEX].data = NULL;
|
|
mutex_unlock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock);
|
|
rc = 0;
|
|
} else if ((type == CAM_HW_CDM) &&
|
|
(hw == cdm_mgr.nodes[index].device)) {
|
|
mutex_lock(&cdm_mgr.nodes[index].lock);
|
|
cdm_mgr.nodes[index].device = NULL;
|
|
cdm_mgr.nodes[index].data = NULL;
|
|
mutex_unlock(&cdm_mgr.nodes[index].lock);
|
|
cdm_mgr.cdm_count--;
|
|
rc = 0;
|
|
} else {
|
|
CAM_ERR(CAM_CDM, "CDM Deregistration failed type=%d index=%d",
|
|
type, index);
|
|
}
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int cam_cdm_set_irq_line_test(void *data, u64 val)
|
|
{
|
|
int i, rc = 0;
|
|
struct cam_hw_intf *hw_intf;
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
return rc;
|
|
}
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
|
|
for (i = 0 ; i < cdm_mgr.cdm_count; i++) {
|
|
if (!cdm_mgr.nodes[i].device || !cdm_mgr.nodes[i].data) {
|
|
CAM_ERR(CAM_CDM, "invalid node present in index=%d", i);
|
|
continue;
|
|
}
|
|
|
|
hw_intf = cdm_mgr.nodes[i].device;
|
|
|
|
if (hw_intf->hw_ops.test_irq_line) {
|
|
CAM_DBG(CAM_CDM, "Testing irq line for CDM at index %d", i);
|
|
|
|
rc = hw_intf->hw_ops.test_irq_line(hw_intf->hw_priv);
|
|
if (rc)
|
|
CAM_ERR(CAM_CDM,
|
|
"[%d] : CDM%d type %d - irq line test failed rc %d",
|
|
i, hw_intf->hw_idx, hw_intf->hw_type, rc);
|
|
else
|
|
CAM_INFO(CAM_CDM,
|
|
"[%d] : CDM%d type %d - irq line test passed",
|
|
i, hw_intf->hw_idx, hw_intf->hw_type);
|
|
} else {
|
|
CAM_WARN(CAM_CDM, "test irq line interface not present for cdm at index %d",
|
|
i);
|
|
}
|
|
}
|
|
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
put_cdm_mgr_refcount();
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int cam_cdm_get_irq_line_test(void *data, u64 *val)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
DEFINE_DEBUGFS_ATTRIBUTE(cam_cdm_irq_line_test, cam_cdm_get_irq_line_test,
|
|
cam_cdm_set_irq_line_test, "%16llu");
|
|
|
|
int cam_cdm_debugfs_init(struct cam_cdm_intf_mgr *mgr)
|
|
{
|
|
struct dentry *dbgfileptr = NULL;
|
|
int rc;
|
|
|
|
if (!cam_debugfs_available())
|
|
return 0;
|
|
|
|
rc = cam_debugfs_create_subdir("cdm", &dbgfileptr);
|
|
if (rc) {
|
|
CAM_ERR(CAM_CDM, "DebugFS could not create directory!");
|
|
return rc;
|
|
}
|
|
|
|
mgr->dentry = dbgfileptr;
|
|
|
|
debugfs_create_file("test_irq_line", 0644,
|
|
mgr->dentry, NULL, &cam_cdm_irq_line_test);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cam_cdm_intf_component_bind(struct device *dev,
|
|
struct device *master_dev, void *data)
|
|
{
|
|
int i, rc;
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
|
|
rc = cam_cdm_intf_mgr_soc_get_dt_properties(pdev, &cdm_mgr);
|
|
if (rc) {
|
|
CAM_ERR(CAM_CDM, "Failed to get dt properties");
|
|
return rc;
|
|
}
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) {
|
|
mutex_init(&cdm_mgr.nodes[i].lock);
|
|
cdm_mgr.nodes[i].device = NULL;
|
|
cdm_mgr.nodes[i].data = NULL;
|
|
cdm_mgr.nodes[i].refcount = 0;
|
|
}
|
|
cdm_mgr.probe_done = true;
|
|
cdm_mgr.refcount = 0;
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
rc = cam_virtual_cdm_probe(pdev);
|
|
if (rc) {
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
cdm_mgr.probe_done = false;
|
|
for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) {
|
|
if (cdm_mgr.nodes[i].device || cdm_mgr.nodes[i].data ||
|
|
(cdm_mgr.nodes[i].refcount != 0))
|
|
CAM_ERR(CAM_CDM,
|
|
"Valid node present in index=%d", i);
|
|
mutex_destroy(&cdm_mgr.nodes[i].lock);
|
|
cdm_mgr.nodes[i].device = NULL;
|
|
cdm_mgr.nodes[i].data = NULL;
|
|
cdm_mgr.nodes[i].refcount = 0;
|
|
}
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
}
|
|
|
|
cam_cdm_debugfs_init(&cdm_mgr);
|
|
|
|
CAM_DBG(CAM_CDM, "CDM Intf component bound successfully");
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void cam_cdm_intf_component_unbind(struct device *dev,
|
|
struct device *master_dev, void *data)
|
|
{
|
|
int i;
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
|
|
if (get_cdm_mgr_refcount()) {
|
|
CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed");
|
|
return;
|
|
}
|
|
|
|
if (cam_virtual_cdm_remove(pdev)) {
|
|
CAM_ERR(CAM_CDM, "Virtual CDM remove failed");
|
|
return;
|
|
}
|
|
put_cdm_mgr_refcount();
|
|
|
|
mutex_lock(&cam_cdm_mgr_lock);
|
|
if (cdm_mgr.refcount != 0) {
|
|
CAM_ERR(CAM_CDM, "cdm manger refcount not zero %d",
|
|
cdm_mgr.refcount);
|
|
goto end;
|
|
}
|
|
|
|
for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) {
|
|
if (cdm_mgr.nodes[i].device || cdm_mgr.nodes[i].data ||
|
|
(cdm_mgr.nodes[i].refcount != 0)) {
|
|
CAM_ERR(CAM_CDM, "Valid node present in index=%d", i);
|
|
goto end;
|
|
}
|
|
mutex_lock(&cdm_mgr.nodes[i].lock);
|
|
cdm_mgr.nodes[i].device = NULL;
|
|
cdm_mgr.nodes[i].data = NULL;
|
|
cdm_mgr.nodes[i].refcount = 0;
|
|
mutex_unlock(&cdm_mgr.nodes[i].lock);
|
|
mutex_destroy(&cdm_mgr.nodes[i].lock);
|
|
}
|
|
|
|
cdm_mgr.probe_done = false;
|
|
|
|
end:
|
|
mutex_unlock(&cam_cdm_mgr_lock);
|
|
}
|
|
|
|
const static struct component_ops cam_cdm_intf_component_ops = {
|
|
.bind = cam_cdm_intf_component_bind,
|
|
.unbind = cam_cdm_intf_component_unbind,
|
|
};
|
|
|
|
static int cam_cdm_intf_probe(struct platform_device *pdev)
|
|
{
|
|
int rc = 0;
|
|
|
|
CAM_DBG(CAM_CDM, "Adding CDM INTF component");
|
|
rc = component_add(&pdev->dev, &cam_cdm_intf_component_ops);
|
|
if (rc)
|
|
CAM_ERR(CAM_CDM, "failed to add component rc: %d", rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int cam_cdm_intf_remove(struct platform_device *pdev)
|
|
{
|
|
component_del(&pdev->dev, &cam_cdm_intf_component_ops);
|
|
return 0;
|
|
}
|
|
|
|
struct platform_driver cam_cdm_intf_driver = {
|
|
.probe = cam_cdm_intf_probe,
|
|
.remove = cam_cdm_intf_remove,
|
|
.driver = {
|
|
.name = "msm_cam_cdm_intf",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = msm_cam_cdm_intf_dt_match,
|
|
.suppress_bind_attrs = true,
|
|
},
|
|
};
|
|
|
|
int cam_cdm_intf_init_module(void)
|
|
{
|
|
return platform_driver_register(&cam_cdm_intf_driver);
|
|
}
|
|
|
|
void cam_cdm_intf_exit_module(void)
|
|
{
|
|
platform_driver_unregister(&cam_cdm_intf_driver);
|
|
}
|
|
|
|
MODULE_DESCRIPTION("MSM Camera CDM Intf driver");
|
|
MODULE_LICENSE("GPL v2");
|