
msm: camera: tfe: Fix variable initialization issues msm: camera: isp: Dual tfe event check with proper hw idx msm: camera: smmu: Add support for non-contiguous mermory region msm: camera: smmu: Use iommu best match algo for camera msm: camera: ope: Optimize allocation of IO configuration msm: camera: ope: Fix for KW Issues msm: camera: ope: Add support for stripe level height configuration msm: camera: tfe: Enable the delay line clc msm: camera: ope: Fix false alarm for OPE HW timeout msm: camera: tfe: Support register dump per request msm: camera: ope: Increase max number of stripes msm: camera: ope: Change packer and unpacker format in case NV12 msm: camera: tfe: Add packet code get command for tfe msm: camera: ope: Trigger recovery in case of violation on write bus msm: camera: ope: Protect ope hw reset with mutex msm: camera: ope: Add a check for valid request in cdm callback msm: camera: ope: Remove the BW & clock vote in release context msm: camera: ope: Reduce OPE BUS memory msm: camera: ope: Fix return value for ope acquire msm: camera: ope: Fix false alarm for OPE request timeout msm: camera: ope: Avoid deadlock during recovery after HW hang msm: camera: tfe: tfe debug enhancement msm: camera: cdm: Fix irq_data value in case of inline irq msm: camera: flash: Switch off flash on provider crash msm: camera: ope: Initialize ope hw mutex structure msm: camera: cdm: Flush all available FIFOs during reset msm: camera: cpas: Add mandatory bw option for axi ports clocks msm: camera: ope: Use vzalloc to allocate the write bus ctx structure msm: camera: ope: Fix handling of init hw failure msm: camera: tfe: Enable per frame register dump for rdi only context msm: camera: cdm: Protect cdm core status bits with mutex msm: camera: cdm: correct the error check in cmd submit irq msm: camera: ope: Fix unclock access during HW reset msm: camera: ope: Program frame level settings after idle event msm: camera: ope: Delay releasing of resources for last context msm: camera: isp: Increase default SOF freeze timeout msm: camera: smmu: Add map and unmap monitor msm: camera: isp: Add trace events across ISP msm: camera: smmu: Profile time taken for map, unmap msm: camera: ope: Start context timer on receiving new request msm: camera: tfe: Reduce stack size during set axi bw msm: camera: cdm: Check for HW state before dumping registers msm: camera: ope: Reduce stack footprint during acquire msm: camera: tfe: Disable clock if tfe2 is not supported msm: camera: cdm: Avoid cdm pause incase of BL submit msm: camera: tfe: Optimize CSID IRQ logging msm: camera: ope: Move request id validity check outside of lock msm: camera: tfe: Correct the tfe hw manager dump logic msm: camera: ope: Synchronize flush and submit BLs msm: camera: cdm: Protect cdm reset status msm: camera: cdm: Handle cdm deinit sequence properly msm: camera: tfe: Reduce reset timeout to 100ms msm: camera: ope: Fix hang detection msm: camera: ope: Make non-fatal logs as debug and info logs msm: camera: tfe: set overflow pending bit to zero after HW reset msm: camera: ope: Do not disable CDM during error handling msm: camera: ope: Add support for OPE Replay msm: camera: ope: Stop OPE in case of init failure msm: camera: ope: Synchronize process cmd and flush request msm: camera: cdm: Fix CDM IRQ handling msm: camera: tfe: LDAR dump for TFE msm: camera: ope: Fix the length check for debug buffer msm: camera: cdm: Fix CDM reset logic msm: camera: ope: Dump debug registers in case of HW hang msm: camera: tfe: Support the RDI bus port for line based mode msm: camera: cdm: Handle out of order reset done events msm: camera: ope: Consider other contexts during timeout msm: camera: ope: Put GenIRQ in last stripe BL msm: camera: tfe: Process the rdi interrupts for rdi only resource msm: camera: jpeg: Check the HW state before accessing register msm: camera: csiphy: Update csiphy power-up sequence for lito v2 msm: camera: cdm: Secure freeing of request lists using locks msm: camera: cpas: Add support for Scuba camnoc msm: camera: csiphy: Clear secure phy flags on release msm: camera: tfe: validate the tfe bw num paths msm: camera: ope: Reorder the reset order in ope acquire msm: camera: ope: Dump debug registers in case of reset failure msm: camera: ope: Add logic to detect hang in CDM msm: camera: isp: Increase max count of cfg to support more init packets msm: camera: core: Fix cpas axi clk rate overflow. CRs-Fixed: 2668666 Change-Id: I882ca4bd117bebc7d1c62bc82299d69d7b5c9388 Signed-off-by: Trishansh Bhardwaj <tbhardwa@codeaurora.org>
724 lines
17 KiB
C
724 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2017-2020, The Linux Foundation. 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;
|
|
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_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_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_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_destroy(&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 = 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");
|