blob: 0e3025382ee6ffe3522874b7d24d0ff108b2ec98 [file] [log] [blame]
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <soc/qcom/scm.h>
#include <uapi/media/cam_isp.h>
#include "cam_smmu_api.h"
#include "cam_req_mgr_workq.h"
#include "cam_isp_hw_mgr_intf.h"
#include "cam_isp_hw.h"
#include "cam_ife_csid_hw_intf.h"
#include "cam_vfe_hw_intf.h"
#include "cam_isp_packet_parser.h"
#include "cam_ife_hw_mgr.h"
#include "cam_cdm_intf_api.h"
#include "cam_packet_util.h"
#include "cam_debug_util.h"
#include "cam_cpas_api.h"
#include "cam_mem_mgr_api.h"
#include "cam_common_util.h"
#define CAM_IFE_HW_ENTRIES_MAX 20
#define TZ_SVC_SMMU_PROGRAM 0x15
#define TZ_SAFE_SYSCALL_ID 0x3
#define CAM_IFE_SAFE_DISABLE 0
#define CAM_IFE_SAFE_ENABLE 1
#define SMMU_SE_IFE 0
#define CAM_ISP_PACKET_META_MAX \
(CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1)
#define CAM_ISP_GENERIC_BLOB_TYPE_MAX \
(CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG + 1)
static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = {
CAM_ISP_HW_CMD_GET_HFR_UPDATE,
CAM_ISP_HW_CMD_CLOCK_UPDATE,
CAM_ISP_HW_CMD_BW_UPDATE,
};
static struct cam_ife_hw_mgr g_ife_hw_mgr;
static int cam_ife_notify_safe_lut_scm(bool safe_trigger)
{
uint32_t camera_hw_version, rc = 0;
struct scm_desc desc = {0};
rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
if (!rc) {
switch (camera_hw_version) {
case CAM_CPAS_TITAN_170_V100:
case CAM_CPAS_TITAN_170_V110:
case CAM_CPAS_TITAN_175_V100:
desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL);
desc.args[0] = SMMU_SE_IFE;
desc.args[1] = safe_trigger;
CAM_DBG(CAM_ISP, "Safe scm call %d", safe_trigger);
if (scm_call2(SCM_SIP_FNID(TZ_SVC_SMMU_PROGRAM,
TZ_SAFE_SYSCALL_ID), &desc)) {
CAM_ERR(CAM_ISP,
"scm call to Enable Safe failed");
rc = -EINVAL;
}
break;
default:
break;
}
}
return rc;
}
static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv,
void *hw_caps_args)
{
int rc = 0;
int i;
struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv;
struct cam_query_cap_cmd *query = hw_caps_args;
struct cam_isp_query_cap_cmd query_isp;
CAM_DBG(CAM_ISP, "enter");
if (copy_from_user(&query_isp,
u64_to_user_ptr(query->caps_handle),
sizeof(struct cam_isp_query_cap_cmd))) {
rc = -EFAULT;
return rc;
}
query_isp.device_iommu.non_secure = hw_mgr->mgr_common.img_iommu_hdl;
query_isp.device_iommu.secure = hw_mgr->mgr_common.img_iommu_hdl_secure;
query_isp.cdm_iommu.non_secure = hw_mgr->mgr_common.cmd_iommu_hdl;
query_isp.cdm_iommu.secure = hw_mgr->mgr_common.cmd_iommu_hdl_secure;
query_isp.num_dev = 2;
for (i = 0; i < query_isp.num_dev; i++) {
query_isp.dev_caps[i].hw_type = CAM_ISP_HW_IFE;
query_isp.dev_caps[i].hw_version.major = 1;
query_isp.dev_caps[i].hw_version.minor = 7;
query_isp.dev_caps[i].hw_version.incr = 0;
query_isp.dev_caps[i].hw_version.reserved = 0;
}
if (copy_to_user(u64_to_user_ptr(query->caps_handle),
&query_isp, sizeof(struct cam_isp_query_cap_cmd)))
rc = -EFAULT;
CAM_DBG(CAM_ISP, "exit rc :%d", rc);
return rc;
}
static int cam_ife_hw_mgr_is_rdi_res(uint32_t res_id)
{
int rc = 0;
switch (res_id) {
case CAM_ISP_IFE_OUT_RES_RDI_0:
case CAM_ISP_IFE_OUT_RES_RDI_1:
case CAM_ISP_IFE_OUT_RES_RDI_2:
case CAM_ISP_IFE_OUT_RES_RDI_3:
rc = 1;
break;
default:
break;
}
return rc;
}
static int cam_ife_hw_mgr_reset_csid_res(
struct cam_ife_hw_mgr_res *isp_hw_res)
{
int i;
int rc = 0;
struct cam_hw_intf *hw_intf;
struct cam_csid_reset_cfg_args csid_reset_args;
csid_reset_args.reset_type = CAM_IFE_CSID_RESET_PATH;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
csid_reset_args.node_res = isp_hw_res->hw_res[i];
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
CAM_DBG(CAM_ISP, "Resetting csid hardware %d",
hw_intf->hw_idx);
if (hw_intf->hw_ops.reset) {
rc = hw_intf->hw_ops.reset(hw_intf->hw_priv,
&csid_reset_args,
sizeof(struct cam_csid_reset_cfg_args));
if (rc <= 0)
goto err;
}
}
return 0;
err:
CAM_ERR(CAM_ISP, "RESET HW res failed: (type:%d, id:%d)",
isp_hw_res->res_type, isp_hw_res->res_id);
return rc;
}
static int cam_ife_hw_mgr_init_hw_res(
struct cam_ife_hw_mgr_res *isp_hw_res)
{
int i;
int rc = -1;
struct cam_hw_intf *hw_intf;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
CAM_DBG(CAM_ISP, "enabled vfe hardware %d",
hw_intf->hw_idx);
if (hw_intf->hw_ops.init) {
rc = hw_intf->hw_ops.init(hw_intf->hw_priv,
isp_hw_res->hw_res[i],
sizeof(struct cam_isp_resource_node));
if (rc)
goto err;
}
}
return 0;
err:
CAM_ERR(CAM_ISP, "INIT HW res failed: (type:%d, id:%d)",
isp_hw_res->res_type, isp_hw_res->res_id);
return rc;
}
static int cam_ife_hw_mgr_start_hw_res(
struct cam_ife_hw_mgr_res *isp_hw_res,
struct cam_ife_hw_mgr_ctx *ctx)
{
int i;
int rc = -1;
struct cam_hw_intf *hw_intf;
/* Start slave (which is right split) first */
for (i = CAM_ISP_HW_SPLIT_MAX - 1; i >= 0; i--) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
if (hw_intf->hw_ops.start) {
isp_hw_res->hw_res[i]->rdi_only_ctx =
ctx->is_rdi_only_context;
rc = hw_intf->hw_ops.start(hw_intf->hw_priv,
isp_hw_res->hw_res[i],
sizeof(struct cam_isp_resource_node));
if (rc) {
CAM_ERR(CAM_ISP, "Can not start HW resources");
goto err;
}
CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx,
isp_hw_res->hw_res[i]->res_id);
} else {
CAM_ERR(CAM_ISP, "function null");
goto err;
}
}
return 0;
err:
CAM_ERR(CAM_ISP, "Start hw res failed (type:%d, id:%d)",
isp_hw_res->res_type, isp_hw_res->res_id);
return rc;
}
static void cam_ife_hw_mgr_stop_hw_res(
struct cam_ife_hw_mgr_res *isp_hw_res)
{
int i;
struct cam_hw_intf *hw_intf;
uint32_t dummy_args;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
if (hw_intf->hw_ops.stop)
hw_intf->hw_ops.stop(hw_intf->hw_priv,
isp_hw_res->hw_res[i],
sizeof(struct cam_isp_resource_node));
else
CAM_ERR(CAM_ISP, "stop null");
if (hw_intf->hw_ops.process_cmd &&
isp_hw_res->res_type == CAM_IFE_HW_MGR_RES_IFE_OUT) {
hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ,
&dummy_args, sizeof(dummy_args));
}
}
}
static void cam_ife_hw_mgr_deinit_hw_res(
struct cam_ife_hw_mgr_res *isp_hw_res)
{
int i;
struct cam_hw_intf *hw_intf;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
if (hw_intf->hw_ops.deinit)
hw_intf->hw_ops.deinit(hw_intf->hw_priv,
isp_hw_res->hw_res[i],
sizeof(struct cam_isp_resource_node));
}
}
static int cam_ife_hw_mgr_init_hw(
struct cam_ife_hw_mgr_ctx *ctx)
{
struct cam_ife_hw_mgr_res *hw_mgr_res;
int rc = 0, i;
CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d",
ctx->ctx_index);
/* INIT IFE CID */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
if (rc) {
CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)",
hw_mgr_res->res_id);
return rc;
}
}
CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d",
ctx->ctx_index);
/* INIT IFE csid */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
if (rc) {
CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)",
hw_mgr_res->res_id);
return rc;
}
}
/* INIT IFE SRC */
CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d",
ctx->ctx_index);
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
if (rc) {
CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)",
hw_mgr_res->res_id);
return rc;
}
}
/* INIT IFE OUT */
CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d",
ctx->ctx_index);
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]);
if (rc) {
CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)",
ctx->res_list_ife_out[i].res_id);
return rc;
}
}
return rc;
}
static void cam_ife_hw_mgr_deinit_hw(
struct cam_ife_hw_mgr_ctx *ctx)
{
struct cam_ife_hw_mgr_res *hw_mgr_res;
int i = 0;
if (!ctx->init_done) {
CAM_WARN(CAM_ISP, "ctx is not in init state");
return;
}
/* Deinit IFE CID */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__);
cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
}
/* Deinit IFE CSID */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__);
cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
}
/* Deint IFE MUX(SRC) */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
}
/* Deinit IFE OUT */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]);
ctx->init_done = false;
}
static int cam_ife_hw_mgr_put_res(
struct list_head *src_list,
struct cam_ife_hw_mgr_res **res)
{
int rc = 0;
struct cam_ife_hw_mgr_res *res_ptr = NULL;
res_ptr = *res;
if (res_ptr)
list_add_tail(&res_ptr->list, src_list);
return rc;
}
static int cam_ife_hw_mgr_get_res(
struct list_head *src_list,
struct cam_ife_hw_mgr_res **res)
{
int rc = 0;
struct cam_ife_hw_mgr_res *res_ptr = NULL;
if (!list_empty(src_list)) {
res_ptr = list_first_entry(src_list,
struct cam_ife_hw_mgr_res, list);
list_del_init(&res_ptr->list);
} else {
CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx");
rc = -1;
}
*res = res_ptr;
return rc;
}
static int cam_ife_hw_mgr_free_hw_res(
struct cam_ife_hw_mgr_res *isp_hw_res)
{
int rc = 0;
int i;
struct cam_hw_intf *hw_intf;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
if (hw_intf->hw_ops.release) {
rc = hw_intf->hw_ops.release(hw_intf->hw_priv,
isp_hw_res->hw_res[i],
sizeof(struct cam_isp_resource_node));
if (rc)
CAM_ERR(CAM_ISP,
"Release hw resrouce id %d failed",
isp_hw_res->res_id);
isp_hw_res->hw_res[i] = NULL;
} else
CAM_ERR(CAM_ISP, "Release null");
}
/* caller should make sure the resource is in a list */
list_del_init(&isp_hw_res->list);
memset(isp_hw_res, 0, sizeof(*isp_hw_res));
INIT_LIST_HEAD(&isp_hw_res->list);
return 0;
}
static int cam_ife_mgr_csid_stop_hw(
struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list,
uint32_t base_idx, uint32_t stop_cmd)
{
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_isp_resource_node *isp_res;
struct cam_isp_resource_node *stop_res[CAM_IFE_PIX_PATH_RES_MAX - 1];
struct cam_csid_hw_stop_args stop;
struct cam_hw_intf *hw_intf;
uint32_t i, cnt;
cnt = 0;
list_for_each_entry(hw_mgr_res, stop_list, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
isp_res = hw_mgr_res->hw_res[i];
if (isp_res->hw_intf->hw_idx != base_idx)
continue;
CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u",
base_idx, isp_res->res_id, cnt);
stop_res[cnt] = isp_res;
cnt++;
}
}
if (cnt) {
hw_intf = stop_res[0]->hw_intf;
stop.num_res = cnt;
stop.node_res = stop_res;
stop.stop_cmd = stop_cmd;
hw_intf->hw_ops.stop(hw_intf->hw_priv, &stop, sizeof(stop));
}
return 0;
}
static int cam_ife_hw_mgr_release_hw_for_ctx(
struct cam_ife_hw_mgr_ctx *ife_ctx)
{
uint32_t i;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_ife_hw_mgr_res *hw_mgr_res_temp;
/* ife leaf resource */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_out[i]);
/* ife source resource */
list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
&ife_ctx->res_list_ife_src, list) {
cam_ife_hw_mgr_free_hw_res(hw_mgr_res);
cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res);
}
/* ife csid resource */
list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
&ife_ctx->res_list_ife_csid, list) {
cam_ife_hw_mgr_free_hw_res(hw_mgr_res);
cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res);
}
/* ife cid resource */
list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
&ife_ctx->res_list_ife_cid, list) {
cam_ife_hw_mgr_free_hw_res(hw_mgr_res);
cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res);
}
/* ife root node */
if (ife_ctx->res_list_ife_in.res_type != CAM_IFE_HW_MGR_RES_UNINIT)
cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_in);
/* clean up the callback function */
ife_ctx->common.cb_priv = NULL;
memset(ife_ctx->common.event_cb, 0, sizeof(ife_ctx->common.event_cb));
CAM_DBG(CAM_ISP, "release context completed ctx id:%d",
ife_ctx->ctx_index);
return 0;
}
static int cam_ife_hw_mgr_put_ctx(
struct list_head *src_list,
struct cam_ife_hw_mgr_ctx **ife_ctx)
{
int rc = 0;
struct cam_ife_hw_mgr_ctx *ctx_ptr = NULL;
mutex_lock(&g_ife_hw_mgr.ctx_mutex);
ctx_ptr = *ife_ctx;
if (ctx_ptr)
list_add_tail(&ctx_ptr->list, src_list);
*ife_ctx = NULL;
mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
return rc;
}
static int cam_ife_hw_mgr_get_ctx(
struct list_head *src_list,
struct cam_ife_hw_mgr_ctx **ife_ctx)
{
int rc = 0;
struct cam_ife_hw_mgr_ctx *ctx_ptr = NULL;
mutex_lock(&g_ife_hw_mgr.ctx_mutex);
if (!list_empty(src_list)) {
ctx_ptr = list_first_entry(src_list,
struct cam_ife_hw_mgr_ctx, list);
list_del_init(&ctx_ptr->list);
} else {
CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx");
rc = -1;
}
*ife_ctx = ctx_ptr;
mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
return rc;
}
static void cam_ife_mgr_add_base_info(
struct cam_ife_hw_mgr_ctx *ctx,
enum cam_isp_hw_split_id split_id,
uint32_t base_idx)
{
uint32_t i;
if (!ctx->num_base) {
ctx->base[0].split_id = split_id;
ctx->base[0].idx = base_idx;
ctx->num_base++;
CAM_DBG(CAM_ISP,
"Add split id = %d for base idx = %d num_base=%d",
split_id, base_idx, ctx->num_base);
} else {
/*Check if base index already exists in the list */
for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].idx == base_idx) {
if (split_id != CAM_ISP_HW_SPLIT_MAX &&
ctx->base[i].split_id ==
CAM_ISP_HW_SPLIT_MAX)
ctx->base[i].split_id = split_id;
break;
}
}
if (i == ctx->num_base) {
ctx->base[ctx->num_base].split_id = split_id;
ctx->base[ctx->num_base].idx = base_idx;
ctx->num_base++;
CAM_DBG(CAM_ISP,
"Add split_id=%d for base idx=%d num_base=%d",
split_id, base_idx, ctx->num_base);
}
}
}
static int cam_ife_mgr_process_base_info(
struct cam_ife_hw_mgr_ctx *ctx)
{
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_isp_resource_node *res = NULL;
uint32_t i;
if (list_empty(&ctx->res_list_ife_src)) {
CAM_ERR(CAM_ISP, "Mux List empty");
return -ENODEV;
}
/* IFE mux in resources */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT)
continue;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
res = hw_mgr_res->hw_res[i];
cam_ife_mgr_add_base_info(ctx, i,
res->hw_intf->hw_idx);
CAM_DBG(CAM_ISP, "add base info for hw %d",
res->hw_intf->hw_idx);
}
}
CAM_DBG(CAM_ISP, "ctx base num = %d", ctx->num_base);
return 0;
}
static int cam_ife_hw_mgr_acquire_res_ife_out_rdi(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_ife_hw_mgr_res *ife_src_res,
struct cam_isp_in_port_info *in_port)
{
int rc = -EINVAL;
struct cam_vfe_acquire_args vfe_acquire;
struct cam_isp_out_port_info *out_port = NULL;
struct cam_ife_hw_mgr_res *ife_out_res;
struct cam_hw_intf *hw_intf;
uint32_t i, vfe_out_res_id, vfe_in_res_id;
/* take left resource */
vfe_in_res_id = ife_src_res->hw_res[0]->res_id;
switch (vfe_in_res_id) {
case CAM_ISP_HW_VFE_IN_RDI0:
vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_0;
break;
case CAM_ISP_HW_VFE_IN_RDI1:
vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_1;
break;
case CAM_ISP_HW_VFE_IN_RDI2:
vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_2;
break;
case CAM_ISP_HW_VFE_IN_RDI3:
vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_3;
break;
default:
CAM_ERR(CAM_ISP, "invalid resource type");
goto err;
}
CAM_DBG(CAM_ISP, "vfe_in_res_id = %d, vfe_out_red_id = %d",
vfe_in_res_id, vfe_out_res_id);
vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT;
vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
ife_out_res = &ife_ctx->res_list_ife_out[vfe_out_res_id & 0xFF];
for (i = 0; i < in_port->num_out_res; i++) {
out_port = &in_port->data[i];
CAM_DBG(CAM_ISP, "i = %d, vfe_out_res_id = %d, out_port: %d",
i, vfe_out_res_id, out_port->res_type);
if (vfe_out_res_id != out_port->res_type)
continue;
vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops;
vfe_acquire.vfe_out.ctx = ife_ctx;
vfe_acquire.vfe_out.out_port_info = out_port;
vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT;
vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index;
vfe_acquire.vfe_out.is_dual = 0;
hw_intf = ife_src_res->hw_res[0]->hw_intf;
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&vfe_acquire,
sizeof(struct cam_vfe_acquire_args));
if (rc) {
CAM_ERR(CAM_ISP, "Can not acquire out resource 0x%x",
out_port->res_type);
goto err;
}
break;
}
if (i == in_port->num_out_res) {
CAM_ERR(CAM_ISP,
"Cannot acquire out resource, i=%d, num_out_res=%d",
i, in_port->num_out_res);
goto err;
}
ife_out_res->hw_res[0] = vfe_acquire.vfe_out.rsrc_node;
ife_out_res->is_dual_vfe = 0;
ife_out_res->res_id = vfe_out_res_id;
ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type)
CAM_ISP_RESOURCE_VFE_OUT;
ife_src_res->child[ife_src_res->num_children++] = ife_out_res;
return 0;
err:
return rc;
}
static int cam_ife_hw_mgr_acquire_res_ife_out_pixel(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_ife_hw_mgr_res *ife_src_res,
struct cam_isp_in_port_info *in_port)
{
int rc = -1;
uint32_t i, j, k;
struct cam_vfe_acquire_args vfe_acquire;
struct cam_isp_out_port_info *out_port;
struct cam_ife_hw_mgr_res *ife_out_res;
struct cam_hw_intf *hw_intf;
for (i = 0; i < in_port->num_out_res; i++) {
out_port = &in_port->data[i];
k = out_port->res_type & 0xFF;
if (k >= CAM_IFE_HW_OUT_RES_MAX) {
CAM_ERR(CAM_ISP, "invalid output resource type 0x%x",
out_port->res_type);
continue;
}
if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
continue;
CAM_DBG(CAM_ISP, "res_type 0x%x",
out_port->res_type);
ife_out_res = &ife_ctx->res_list_ife_out[k];
ife_out_res->is_dual_vfe = in_port->usage_type;
vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT;
vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops;
vfe_acquire.vfe_out.ctx = ife_ctx;
vfe_acquire.vfe_out.out_port_info = out_port;
vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe;
vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index;
for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) {
if (!ife_src_res->hw_res[j])
continue;
hw_intf = ife_src_res->hw_res[j]->hw_intf;
if (j == CAM_ISP_HW_SPLIT_LEFT) {
vfe_acquire.vfe_out.split_id =
CAM_ISP_HW_SPLIT_LEFT;
if (ife_src_res->is_dual_vfe) {
/*TBD */
vfe_acquire.vfe_out.is_master = 1;
vfe_acquire.vfe_out.dual_slave_core =
(hw_intf->hw_idx == 0) ? 1 : 0;
} else {
vfe_acquire.vfe_out.is_master = 0;
vfe_acquire.vfe_out.dual_slave_core =
0;
}
} else {
vfe_acquire.vfe_out.split_id =
CAM_ISP_HW_SPLIT_RIGHT;
vfe_acquire.vfe_out.is_master = 0;
vfe_acquire.vfe_out.dual_slave_core =
(hw_intf->hw_idx == 0) ? 1 : 0;
}
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&vfe_acquire,
sizeof(struct cam_vfe_acquire_args));
if (rc) {
CAM_ERR(CAM_ISP,
"Can not acquire out resource 0x%x",
out_port->res_type);
goto err;
}
ife_out_res->hw_res[j] =
vfe_acquire.vfe_out.rsrc_node;
CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x",
ife_out_res->hw_res[j]->res_type,
ife_out_res->hw_res[j]->res_id);
}
ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type)
CAM_ISP_RESOURCE_VFE_OUT;
ife_out_res->res_id = out_port->res_type;
ife_out_res->parent = ife_src_res;
ife_src_res->child[ife_src_res->num_children++] = ife_out_res;
}
return 0;
err:
/* release resource at the entry function */
return rc;
}
static int cam_ife_hw_mgr_acquire_res_ife_out(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port)
{
int rc = -EINVAL;
struct cam_ife_hw_mgr_res *ife_src_res;
list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) {
if (ife_src_res->num_children)
continue;
switch (ife_src_res->res_id) {
case CAM_ISP_HW_VFE_IN_CAMIF:
rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx,
ife_src_res, in_port);
break;
case CAM_ISP_HW_VFE_IN_RDI0:
case CAM_ISP_HW_VFE_IN_RDI1:
case CAM_ISP_HW_VFE_IN_RDI2:
case CAM_ISP_HW_VFE_IN_RDI3:
rc = cam_ife_hw_mgr_acquire_res_ife_out_rdi(ife_ctx,
ife_src_res, in_port);
break;
default:
CAM_ERR(CAM_ISP, "Unknown IFE SRC resource: %d",
ife_src_res->res_id);
break;
}
if (rc)
goto err;
}
return 0;
err:
/* release resource on entry function */
return rc;
}
static int cam_ife_hw_mgr_acquire_res_ife_src(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port)
{
int rc = -1;
int i;
struct cam_ife_hw_mgr_res *csid_res;
struct cam_ife_hw_mgr_res *ife_src_res;
struct cam_vfe_acquire_args vfe_acquire;
struct cam_hw_intf *hw_intf;
struct cam_ife_hw_mgr *ife_hw_mgr;
ife_hw_mgr = ife_ctx->hw_mgr;
list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) {
if (csid_res->num_children)
continue;
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
&ife_src_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto err;
}
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src,
&ife_src_res);
vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN;
vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops;
switch (csid_res->res_id) {
case CAM_IFE_PIX_PATH_RES_IPP:
vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_CAMIF;
vfe_acquire.vfe_in.in_port = in_port;
if (csid_res->is_dual_vfe)
vfe_acquire.vfe_in.sync_mode =
CAM_ISP_HW_SYNC_MASTER;
else
vfe_acquire.vfe_in.sync_mode =
CAM_ISP_HW_SYNC_NONE;
break;
case CAM_IFE_PIX_PATH_RES_RDI_0:
vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI0;
vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
break;
case CAM_IFE_PIX_PATH_RES_RDI_1:
vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI1;
vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
break;
case CAM_IFE_PIX_PATH_RES_RDI_2:
vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI2;
vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
break;
case CAM_IFE_PIX_PATH_RES_RDI_3:
vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI3;
vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
break;
default:
CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node");
goto err;
}
ife_src_res->res_type = (enum cam_ife_hw_mgr_res_type)
vfe_acquire.rsrc_type;
ife_src_res->res_id = vfe_acquire.vfe_in.res_id;
ife_src_res->is_dual_vfe = csid_res->is_dual_vfe;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!csid_res->hw_res[i])
continue;
hw_intf = ife_hw_mgr->ife_devices[
csid_res->hw_res[i]->hw_intf->hw_idx];
/* fill in more acquire information as needed */
/* slave Camif resource, */
if (i == CAM_ISP_HW_SPLIT_RIGHT &&
ife_src_res->is_dual_vfe)
vfe_acquire.vfe_in.sync_mode =
CAM_ISP_HW_SYNC_SLAVE;
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&vfe_acquire,
sizeof(struct cam_vfe_acquire_args));
if (rc) {
CAM_ERR(CAM_ISP,
"Can not acquire IFE HW res %d",
csid_res->res_id);
goto err;
}
ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node;
CAM_DBG(CAM_ISP,
"acquire success IFE:%d res type :0x%x res id:0x%x",
hw_intf->hw_idx,
ife_src_res->hw_res[i]->res_type,
ife_src_res->hw_res[i]->res_id);
}
/* It should be one to one mapping between
* csid resource and ife source resource
*/
csid_res->child[0] = ife_src_res;
ife_src_res->parent = csid_res;
csid_res->child[csid_res->num_children++] = ife_src_res;
CAM_DBG(CAM_ISP, "csid_res=%d num_children=%d ife_src_res=%d",
csid_res->res_id, csid_res->num_children,
ife_src_res->res_id);
}
return 0;
err:
/* release resource at the entry function */
return rc;
}
static int cam_ife_mgr_acquire_cid_res(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port,
struct cam_ife_hw_mgr_res **cid_res,
enum cam_ife_pix_path_res_id csid_path)
{
int rc = -1;
int i, j;
struct cam_ife_hw_mgr *ife_hw_mgr;
struct cam_hw_intf *hw_intf;
struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator;
struct cam_csid_hw_reserve_resource_args csid_acquire;
uint32_t acquired_cnt = 0;
ife_hw_mgr = ife_ctx->hw_mgr;
*cid_res = NULL;
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto end;
}
cid_res_temp = *cid_res;
csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
csid_acquire.in_port = in_port;
csid_acquire.res_id = csid_path;
CAM_DBG(CAM_ISP, "path %d", csid_path);
/* Try acquiring CID resource from previously acquired HW */
list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid,
list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!cid_res_iterator->hw_res[i])
continue;
hw_intf = cid_res_iterator->hw_res[i]->hw_intf;
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&csid_acquire, sizeof(csid_acquire));
if (rc) {
CAM_DBG(CAM_ISP,
"No ife cid resource from hw %d",
hw_intf->hw_idx);
continue;
}
cid_res_temp->hw_res[acquired_cnt++] =
csid_acquire.node_res;
CAM_DBG(CAM_ISP,
"acquired csid(%s)=%d CID rsrc successfully",
(i == 0) ? "left" : "right",
hw_intf->hw_idx);
if (in_port->usage_type && acquired_cnt == 1 &&
csid_path == CAM_IFE_PIX_PATH_RES_IPP)
/* Continue to acquire Right */
continue;
if (acquired_cnt)
/*
* If successfully acquired CID from
* previously acquired HW, skip the next
* part
*/
goto acquire_successful;
}
}
/* Acquire Left if not already acquired */
for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) {
if (!ife_hw_mgr->csid_devices[i])
continue;
hw_intf = ife_hw_mgr->csid_devices[i];
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire,
sizeof(csid_acquire));
if (rc)
continue;
else {
cid_res_temp->hw_res[acquired_cnt++] =
csid_acquire.node_res;
break;
}
}
if (i == -1 || !csid_acquire.node_res) {
CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d",
csid_path);
goto put_res;
}
acquire_successful:
CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d",
in_port->usage_type);
cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID;
/* CID(DT_ID) value of acquire device, require for path */
cid_res_temp->res_id = csid_acquire.node_res->res_id;
cid_res_temp->is_dual_vfe = in_port->usage_type;
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res);
/*
* Acquire Right if not already acquired.
* Dual IFE for RDI is not currently supported.
*/
if (cid_res_temp->is_dual_vfe && csid_path
== CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) {
csid_acquire.node_res = NULL;
csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
csid_acquire.in_port = in_port;
for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
if (!ife_hw_mgr->csid_devices[j])
continue;
if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx)
continue;
hw_intf = ife_hw_mgr->csid_devices[j];
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&csid_acquire, sizeof(csid_acquire));
if (rc)
continue;
else
break;
}
if (j == CAM_IFE_CSID_HW_NUM_MAX) {
CAM_ERR(CAM_ISP,
"Can not acquire ife csid rdi resource");
goto end;
}
cid_res_temp->hw_res[1] = csid_acquire.node_res;
CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d",
in_port->usage_type);
}
cid_res_temp->parent = &ife_ctx->res_list_ife_in;
ife_ctx->res_list_ife_in.child[
ife_ctx->res_list_ife_in.num_children++] = cid_res_temp;
return 0;
put_res:
cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res);
end:
return rc;
}
static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port)
{
int rc = -1;
int i;
int master_idx = -1;
struct cam_ife_hw_mgr *ife_hw_mgr;
struct cam_ife_hw_mgr_res *csid_res;
struct cam_ife_hw_mgr_res *cid_res;
struct cam_hw_intf *hw_intf;
struct cam_csid_hw_reserve_resource_args csid_acquire;
ife_hw_mgr = ife_ctx->hw_mgr;
/* get cid resource */
rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res,
CAM_IFE_PIX_PATH_RES_IPP);
if (rc) {
CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
goto end;
}
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto end;
}
csid_res->res_type = (enum cam_ife_hw_mgr_res_type)
CAM_ISP_RESOURCE_PIX_PATH;
csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP;
if (in_port->usage_type)
csid_res->is_dual_vfe = 1;
else {
csid_res->is_dual_vfe = 0;
csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
}
/* IPP resource needs to be from same HW as CID resource */
for (i = 0; i <= csid_res->is_dual_vfe; i++) {
CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe);
csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP;
csid_acquire.cid = cid_res->hw_res[i]->res_id;
csid_acquire.in_port = in_port;
csid_acquire.out_port = in_port->data;
csid_acquire.node_res = NULL;
hw_intf = cid_res->hw_res[i]->hw_intf;
if (csid_res->is_dual_vfe) {
if (i == CAM_ISP_HW_SPLIT_LEFT) {
master_idx = hw_intf->hw_idx;
csid_acquire.sync_mode =
CAM_ISP_HW_SYNC_MASTER;
} else {
if (master_idx == -1) {
CAM_ERR(CAM_ISP,
"No Master found");
goto put_res;
}
csid_acquire.sync_mode =
CAM_ISP_HW_SYNC_SLAVE;
csid_acquire.master_idx = master_idx;
}
}
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&csid_acquire, sizeof(csid_acquire));
if (rc) {
CAM_ERR(CAM_ISP,
"Cannot acquire ife csid ipp resource");
goto put_res;
}
csid_res->hw_res[i] = csid_acquire.node_res;
CAM_DBG(CAM_ISP,
"acquired csid(%s)=%d ipp rsrc successfully",
(i == 0) ? "left" : "right",
hw_intf->hw_idx);
}
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
csid_res->parent = cid_res;
cid_res->child[cid_res->num_children++] = csid_res;
CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id);
return 0;
put_res:
cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res);
end:
return rc;
}
static enum cam_ife_pix_path_res_id
cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
uint32_t out_port_type)
{
enum cam_ife_pix_path_res_id path_id;
switch (out_port_type) {
case CAM_ISP_IFE_OUT_RES_RDI_0:
path_id = CAM_IFE_PIX_PATH_RES_RDI_0;
break;
case CAM_ISP_IFE_OUT_RES_RDI_1:
path_id = CAM_IFE_PIX_PATH_RES_RDI_1;
break;
case CAM_ISP_IFE_OUT_RES_RDI_2:
path_id = CAM_IFE_PIX_PATH_RES_RDI_2;
break;
case CAM_ISP_IFE_OUT_RES_RDI_3:
path_id = CAM_IFE_PIX_PATH_RES_RDI_3;
break;
default:
path_id = CAM_IFE_PIX_PATH_RES_MAX;
CAM_DBG(CAM_ISP, "maximum rdi output type exceeded");
break;
}
CAM_DBG(CAM_ISP, "out_port %d path_id %d", out_port_type, path_id);
return path_id;
}
static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port)
{
int rc = -EINVAL;
int i;
struct cam_ife_hw_mgr *ife_hw_mgr;
struct cam_ife_hw_mgr_res *csid_res;
struct cam_ife_hw_mgr_res *cid_res;
struct cam_hw_intf *hw_intf;
struct cam_isp_out_port_info *out_port;
struct cam_csid_hw_reserve_resource_args csid_acquire;
enum cam_ife_pix_path_res_id path_type;
ife_hw_mgr = ife_ctx->hw_mgr;
for (i = 0; i < in_port->num_out_res; i++) {
out_port = &in_port->data[i];
path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
out_port->res_type);
if (path_type == CAM_IFE_PIX_PATH_RES_MAX)
continue;
/* get cid resource */
rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res,
path_type);
if (rc) {
CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
goto end;
}
/* For each RDI we need CID + PATH resource */
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
&csid_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto end;
}
memset(&csid_acquire, 0, sizeof(csid_acquire));
csid_acquire.res_id = path_type;
csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
csid_acquire.cid = cid_res->hw_res[0]->res_id;
csid_acquire.in_port = in_port;
csid_acquire.out_port = out_port;
csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
csid_acquire.node_res = NULL;
hw_intf = cid_res->hw_res[0]->hw_intf;
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&csid_acquire, sizeof(csid_acquire));
if (rc) {
CAM_ERR(CAM_ISP,
"CSID Path reserve failed hw=%d rc=%d cid=%d",
hw_intf->hw_idx, rc,
cid_res->hw_res[0]->res_id);
goto put_res;
}
if (csid_acquire.node_res == NULL) {
CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed");
goto put_res;
}
csid_res->res_type = (enum cam_ife_hw_mgr_res_type)
CAM_ISP_RESOURCE_PIX_PATH;
csid_res->res_id = csid_acquire.res_id;
csid_res->is_dual_vfe = 0;
csid_res->hw_res[0] = csid_acquire.node_res;
csid_res->hw_res[1] = NULL;
CAM_DBG(CAM_ISP, "acquire res %d",
csid_acquire.res_id);
csid_res->parent = cid_res;
cid_res->child[cid_res->num_children++] =
csid_res;
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
}
return 0;
put_res:
cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res);
end:
return rc;
}
static int cam_ife_hw_mgr_acquire_res_root(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port)
{
int rc = -1;
if (ife_ctx->res_list_ife_in.res_type == CAM_IFE_HW_MGR_RES_UNINIT) {
/* first acquire */
ife_ctx->res_list_ife_in.res_type = CAM_IFE_HW_MGR_RES_ROOT;
ife_ctx->res_list_ife_in.res_id = in_port->res_type;
ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type;
} else if (ife_ctx->res_list_ife_in.res_id != in_port->res_type) {
CAM_ERR(CAM_ISP, "No Free resource for this context");
goto err;
} else {
/* else do nothing */
}
return 0;
err:
/* release resource in entry function */
return rc;
}
static int cam_ife_hw_mgr_preprocess_out_port(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port,
int *pixel_count,
int *rdi_count)
{
int pixel_num = 0;
int rdi_num = 0;
uint32_t i;
struct cam_isp_out_port_info *out_port;
struct cam_ife_hw_mgr *ife_hw_mgr;
ife_hw_mgr = ife_ctx->hw_mgr;
for (i = 0; i < in_port->num_out_res; i++) {
out_port = &in_port->data[i];
if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
rdi_num++;
else
pixel_num++;
}
*pixel_count = pixel_num;
*rdi_count = rdi_num;
return 0;
}
static int cam_ife_mgr_acquire_hw_for_ctx(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port,
uint32_t *num_pix_port, uint32_t *num_rdi_port)
{
int rc = -1;
int is_dual_vfe = 0;
int pixel_count = 0;
int rdi_count = 0;
is_dual_vfe = in_port->usage_type;
/* get root node resource */
rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port);
if (rc) {
CAM_ERR(CAM_ISP, "Can not acquire csid rx resource");
goto err;
}
cam_ife_hw_mgr_preprocess_out_port(ife_ctx, in_port,
&pixel_count, &rdi_count);
if (!pixel_count && !rdi_count) {
CAM_ERR(CAM_ISP, "No PIX or RDI resource");
return -EINVAL;
}
if (pixel_count) {
/* get ife csid IPP resrouce */
rc = cam_ife_hw_mgr_acquire_res_ife_csid_ipp(ife_ctx, in_port);
if (rc) {
CAM_ERR(CAM_ISP,
"Acquire IFE CSID IPP resource Failed");
goto err;
}
}
if (rdi_count) {
/* get ife csid rdi resource */
rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port);
if (rc) {
CAM_ERR(CAM_ISP,
"Acquire IFE CSID RDI resource Failed");
goto err;
}
}
/* get ife src resource */
rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port);
if (rc) {
CAM_ERR(CAM_ISP, "Acquire IFE SRC resource Failed");
goto err;
}
rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port);
if (rc) {
CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed");
goto err;
}
*num_pix_port += pixel_count;
*num_rdi_port += rdi_count;
return 0;
err:
/* release resource at the acquire entry funciton */
return rc;
}
void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata,
enum cam_cdm_cb_status status, uint64_t cookie)
{
struct cam_ife_hw_mgr_ctx *ctx = NULL;
if (!userdata) {
CAM_ERR(CAM_ISP, "Invalid args");
return;
}
ctx = userdata;
if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) {
complete(&ctx->config_done_complete);
CAM_DBG(CAM_ISP,
"Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d",
handle, userdata, status, cookie, ctx->ctx_index);
} else {
CAM_WARN(CAM_ISP,
"Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu",
handle, userdata, status, cookie);
}
}
/* entry function: acquire_hw */
static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv,
void *acquire_hw_args)
{
struct cam_ife_hw_mgr *ife_hw_mgr = hw_mgr_priv;
struct cam_hw_acquire_args *acquire_args = acquire_hw_args;
int rc = -1;
int i, j;
struct cam_ife_hw_mgr_ctx *ife_ctx;
struct cam_isp_in_port_info *in_port = NULL;
struct cam_isp_resource *isp_resource = NULL;
struct cam_cdm_acquire_data cdm_acquire;
uint32_t num_pix_port_per_in = 0;
uint32_t num_rdi_port_per_in = 0;
uint32_t total_pix_port = 0;
uint32_t total_rdi_port = 0;
uint32_t in_port_length = 0;
CAM_DBG(CAM_ISP, "Enter...");
if (!acquire_args || acquire_args->num_acq <= 0) {
CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error");
return -EINVAL;
}
/* get the ife ctx */
rc = cam_ife_hw_mgr_get_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx);
if (rc || !ife_ctx) {
CAM_ERR(CAM_ISP, "Get ife hw context failed");
goto err;
}
ife_ctx->common.cb_priv = acquire_args->context_data;
for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++)
ife_ctx->common.event_cb[i] = acquire_args->event_cb;
ife_ctx->hw_mgr = ife_hw_mgr;
memcpy(cdm_acquire.identifier, "ife", sizeof("ife"));
cdm_acquire.cell_index = 0;
cdm_acquire.handle = 0;
cdm_acquire.userdata = ife_ctx;
cdm_acquire.base_array_cnt = CAM_IFE_HW_NUM_MAX;
for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
if (ife_hw_mgr->cdm_reg_map[i])
cdm_acquire.base_array[j++] =
ife_hw_mgr->cdm_reg_map[i];
}
cdm_acquire.base_array_cnt = j;
cdm_acquire.id = CAM_CDM_VIRTUAL;
cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback;
rc = cam_cdm_acquire(&cdm_acquire);
if (rc) {
CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW");
goto free_ctx;
}
CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x",
cdm_acquire.handle);
ife_ctx->cdm_handle = cdm_acquire.handle;
ife_ctx->cdm_ops = cdm_acquire.ops;
isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info;
/* acquire HW resources */
for (i = 0; i < acquire_args->num_acq; i++) {
if (isp_resource[i].resource_id != CAM_ISP_RES_ID_PORT)
continue;
CAM_DBG(CAM_ISP,
"start copy from user handle %lld with len = %d",
isp_resource[i].res_hdl,
isp_resource[i].length);
in_port_length = sizeof(struct cam_isp_in_port_info);
if (in_port_length > isp_resource[i].length) {
CAM_ERR(CAM_ISP, "buffer size is not enough");
rc = -EINVAL;
goto free_res;
}
in_port = memdup_user(
u64_to_user_ptr(isp_resource[i].res_hdl),
isp_resource[i].length);
if (!IS_ERR(in_port)) {
in_port_length = sizeof(struct cam_isp_in_port_info) +
(in_port->num_out_res - 1) *
sizeof(struct cam_isp_out_port_info);
if (in_port_length > isp_resource[i].length) {
CAM_ERR(CAM_ISP, "buffer size is not enough");
rc = -EINVAL;
kfree(in_port);
goto free_res;
}
rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port,
&num_pix_port_per_in, &num_rdi_port_per_in);
total_pix_port += num_pix_port_per_in;
total_rdi_port += num_rdi_port_per_in;
kfree(in_port);
if (rc) {
CAM_ERR(CAM_ISP, "can not acquire resource");
goto free_res;
}
} else {
CAM_ERR(CAM_ISP,
"Copy from user failed with in_port = %pK",
in_port);
rc = -EFAULT;
goto free_res;
}
}
/* Check whether context has only RDI resource */
if (!total_pix_port) {
ife_ctx->is_rdi_only_context = 1;
CAM_DBG(CAM_ISP, "RDI only context");
}
/* Process base info */
rc = cam_ife_mgr_process_base_info(ife_ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Process base info failed");
goto free_res;
}
acquire_args->ctxt_to_hw_map = ife_ctx;
ife_ctx->ctx_in_use = 1;
cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
CAM_DBG(CAM_ISP, "Exit...(success)");
return 0;
free_res:
cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx);
cam_cdm_release(ife_ctx->cdm_handle);
free_ctx:
cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx);
err:
CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc);
return rc;
}
static int cam_isp_blob_bw_update(
struct cam_isp_bw_config *bw_config,
struct cam_ife_hw_mgr_ctx *ctx)
{
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_hw_intf *hw_intf;
struct cam_vfe_bw_update_args bw_upd_args;
uint64_t cam_bw_bps = 0;
uint64_t ext_bw_bps = 0;
int rc = -EINVAL;
uint32_t i;
CAM_DBG(CAM_PERF,
"usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
"right cam_bw_bps=%llu ext_bw_bps=%llu",
bw_config->usage_type,
bw_config->left_pix_vote.cam_bw_bps,
bw_config->left_pix_vote.ext_bw_bps,
bw_config->right_pix_vote.cam_bw_bps,
bw_config->right_pix_vote.ext_bw_bps);
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
if (i == CAM_ISP_HW_SPLIT_LEFT) {
cam_bw_bps =
bw_config->left_pix_vote.cam_bw_bps;
ext_bw_bps =
bw_config->left_pix_vote.ext_bw_bps;
} else {
cam_bw_bps =
bw_config->right_pix_vote.cam_bw_bps;
ext_bw_bps =
bw_config->right_pix_vote.ext_bw_bps;
}
else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
&& (hw_mgr_res->res_id <=
CAM_ISP_HW_VFE_IN_RDI3)) {
uint32_t idx = hw_mgr_res->res_id -
CAM_ISP_HW_VFE_IN_RDI0;
if (idx >= bw_config->num_rdi)
continue;
cam_bw_bps =
bw_config->rdi_vote[idx].cam_bw_bps;
ext_bw_bps =
bw_config->rdi_vote[idx].ext_bw_bps;
} else
if (hw_mgr_res->hw_res[i]) {
CAM_ERR(CAM_ISP, "Invalid res_id %u",
hw_mgr_res->res_id);
rc = -EINVAL;
return rc;
}
hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
if (hw_intf && hw_intf->hw_ops.process_cmd) {
bw_upd_args.node_res =
hw_mgr_res->hw_res[i];
bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
bw_upd_args.external_bw_bytes = ext_bw_bps;
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_ISP_HW_CMD_BW_UPDATE,
&bw_upd_args,
sizeof(struct cam_vfe_bw_update_args));
if (rc)
CAM_ERR(CAM_ISP, "BW Update failed");
} else
CAM_WARN(CAM_ISP, "NULL hw_intf!");
}
}
return rc;
}
/* entry function: config_hw */
static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
void *config_hw_args)
{
int rc = -1, i;
struct cam_hw_config_args *cfg;
struct cam_hw_update_entry *cmd;
struct cam_cdm_bl_request *cdm_cmd;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_isp_prepare_hw_update_data *hw_update_data;
CAM_DBG(CAM_ISP, "Enter");
if (!hw_mgr_priv || !config_hw_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
cfg = config_hw_args;
ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map;
if (!ctx) {
CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
if (!ctx->ctx_in_use || !ctx->cdm_cmd) {
CAM_ERR(CAM_ISP, "Invalid context parameters");
return -EPERM;
}
if (atomic_read(&ctx->overflow_pending))
return -EINVAL;
hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv;
for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
if (hw_update_data->bw_config_valid[i] == true) {
rc = cam_isp_blob_bw_update(
(struct cam_isp_bw_config *)
&hw_update_data->bw_config[i], ctx);
if (rc)
CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
}
}
CAM_DBG(CAM_ISP, "Enter ctx id:%d num_hw_upd_entries %d",
ctx->ctx_index, cfg->num_hw_update_entries);
if (cfg->num_hw_update_entries > 0) {
cdm_cmd = ctx->cdm_cmd;
cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries;
cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE;
cdm_cmd->flag = true;
cdm_cmd->userdata = ctx;
cdm_cmd->cookie = cfg->request_id;
for (i = 0 ; i <= cfg->num_hw_update_entries; i++) {
cmd = (cfg->hw_update_entries + i);
cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle;
cdm_cmd->cmd[i].offset = cmd->offset;
cdm_cmd->cmd[i].len = cmd->len;
}
if (cfg->init_packet)
init_completion(&ctx->config_done_complete);
CAM_DBG(CAM_ISP, "Submit to CDM");
rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd);
if (rc) {
CAM_ERR(CAM_ISP, "Failed to apply the configs");
return rc;
}
if (cfg->init_packet) {
rc = wait_for_completion_timeout(
&ctx->config_done_complete,
msecs_to_jiffies(30));
if (rc <= 0) {
CAM_ERR(CAM_ISP,
"config done completion timeout for req_id=%llu rc=%d ctx_index %d",
cfg->request_id, rc, ctx->ctx_index);
if (rc == 0)
rc = -ETIMEDOUT;
} else {
rc = 0;
CAM_DBG(CAM_ISP,
"config done Success for req_id=%llu ctx_index %d",
cfg->request_id, ctx->ctx_index);
}
}
} else {
CAM_ERR(CAM_ISP, "No commands to config");
}
CAM_DBG(CAM_ISP, "Exit");
return rc;
}
static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args)
{
int rc = 0;
struct cam_hw_stop_args *stop_args = stop_hw_args;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_ife_hw_mgr_ctx *ctx;
uint32_t i, master_base_idx = 0;
if (!stop_hw_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
CAM_DBG(CAM_ISP, "Enter...ctx id:%d",
ctx->ctx_index);
if (!ctx->num_base) {
CAM_ERR(CAM_ISP, "Number of bases are zero");
return -EINVAL;
}
/* get master base index first */
for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) {
master_base_idx = ctx->base[i].idx;
break;
}
}
if (i == ctx->num_base)
master_base_idx = ctx->base[0].idx;
/* stop the master CIDs first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
master_base_idx, CAM_CSID_HALT_IMMEDIATELY);
/* stop rest of the CIDs */
for (i = 0; i < ctx->num_base; i++) {
if (i == master_base_idx)
continue;
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
ctx->base[i].idx, CAM_CSID_HALT_IMMEDIATELY);
}
/* stop the master CSID path first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
master_base_idx, CAM_CSID_HALT_IMMEDIATELY);
/* Stop rest of the CSID paths */
for (i = 0; i < ctx->num_base; i++) {
if (i == master_base_idx)
continue;
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
ctx->base[i].idx, CAM_CSID_HALT_IMMEDIATELY);
}
/* IFE mux in resources */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
}
/* IFE out resources */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]);
/* Stop tasklet for context */
cam_tasklet_stop(ctx->common.tasklet_info);
CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d",
ctx->ctx_index, rc);
return rc;
}
static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
enum cam_vfe_bw_control_action action)
{
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_hw_intf *hw_intf;
struct cam_vfe_bw_control_args bw_ctrl_args;
int rc = -EINVAL;
uint32_t i;
CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index);
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
if (hw_intf && hw_intf->hw_ops.process_cmd) {
bw_ctrl_args.node_res =
hw_mgr_res->hw_res[i];
bw_ctrl_args.action = action;
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_ISP_HW_CMD_BW_CONTROL,
&bw_ctrl_args,
sizeof(struct cam_vfe_bw_control_args));
if (rc)
CAM_ERR(CAM_ISP, "BW Update failed");
} else
CAM_WARN(CAM_ISP, "NULL hw_intf!");
}
}
return rc;
}
static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
{
return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
}
/* entry function: stop_hw */
static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
{
int rc = 0;
struct cam_hw_stop_args *stop_args = stop_hw_args;
struct cam_isp_stop_args *stop_isp;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_ife_hw_mgr_ctx *ctx;
enum cam_ife_csid_halt_cmd csid_halt_type;
uint32_t i, master_base_idx = 0;
if (!hw_mgr_priv || !stop_hw_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index);
stop_isp = (struct cam_isp_stop_args *)stop_args->args;
if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_IMMEDIATELY) &&
(stop_isp->stop_only)) {
CAM_ERR(CAM_ISP, "Invalid params hw_stop_cmd:%d stop_only:%d",
stop_isp->hw_stop_cmd, stop_isp->stop_only);
return -EPERM;
}
/* Set the csid halt command */
if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY)
csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY;
else
csid_halt_type = CAM_CSID_HALT_IMMEDIATELY;
/* Note:stop resource will remove the irq mask from the hardware */
if (!ctx->num_base) {
CAM_ERR(CAM_ISP, "number of bases are zero");
return -EINVAL;
}
CAM_DBG(CAM_ISP, "Halting CSIDs");
if (cam_cdm_stream_off(ctx->cdm_handle))
CAM_ERR(CAM_ISP, "CDM stream off failed %d",
ctx->cdm_handle);
CAM_DBG(CAM_ISP, "Going to stop IFE Mux");
/* IFE mux in resources */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
}
CAM_DBG(CAM_ISP, "Going to stop IFE Out");
/* IFE out resources */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]);
/* get master base index first */
for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) {
master_base_idx = ctx->base[i].idx;
break;
}
}
cam_tasklet_stop(ctx->common.tasklet_info);
/*
* If Context does not have PIX resources and has only RDI resource
* then take the first base index.
*/
if (i == ctx->num_base)
master_base_idx = ctx->base[0].idx;
CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx);
/* Stop the master CSID path first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
/* stop rest of the CSID paths */
for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].idx == master_base_idx)
continue;
CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d",
ctx->base[i].idx, i, master_base_idx);
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
}
CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx);
/* Stop the master CIDs first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
master_base_idx, csid_halt_type);
/* stop rest of the CIDs */
for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].idx == master_base_idx)
continue;
CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d",
ctx->base[i].idx, i, master_base_idx);
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
ctx->base[i].idx, csid_halt_type);
}
if (stop_isp->stop_only)
goto end;
cam_ife_hw_mgr_deinit_hw(ctx);
CAM_DBG(CAM_ISP,
"Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc);
end:
mutex_lock(&g_ife_hw_mgr.ctx_mutex);
if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) {
rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE);
if (rc) {
CAM_ERR(CAM_ISP,
"SAFE SCM call failed:Check TZ/HYP dependency");
rc = 0;
}
}
mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
return rc;
}
static int cam_ife_mgr_reset_vfe_hw(struct cam_ife_hw_mgr *hw_mgr,
uint32_t hw_idx)
{
uint32_t i = 0;
struct cam_hw_intf *vfe_hw_intf;
uint32_t vfe_reset_type;
if (!hw_mgr) {
CAM_DBG(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
/* Reset VFE HW*/
vfe_reset_type = CAM_VFE_HW_RESET_HW;
for (i = 0; i < CAM_VFE_HW_NUM_MAX; i++) {
if (hw_idx != hw_mgr->ife_devices[i]->hw_idx)
continue;
CAM_DBG(CAM_ISP, "VFE (id = %d) reset", hw_idx);
vfe_hw_intf = hw_mgr->ife_devices[i];
vfe_hw_intf->hw_ops.reset(vfe_hw_intf->hw_priv,
&vfe_reset_type, sizeof(vfe_reset_type));
break;
}
CAM_DBG(CAM_ISP, "Exit Successfully");
return 0;
}
static int cam_ife_mgr_restart_hw(void *start_hw_args)
{
int rc = -1;
struct cam_hw_start_args *start_args = start_hw_args;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_ife_hw_mgr_res *hw_mgr_res;
uint32_t i;
if (!start_hw_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", ctx->ctx_index);
cam_tasklet_start(ctx->common.tasklet_info);
/* start the IFE out devices */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_start_hw_res(
&ctx->res_list_ife_out[i], ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)", i);
goto err;
}
}
CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index);
/* Start the IFE mux in devices */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)",
hw_mgr_res->res_id);
goto err;
}
}
CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", ctx->ctx_index);
/* Start the IFE CSID HW devices */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
}
CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d", ctx->ctx_index);
/* Start IFE root node: do nothing */
CAM_DBG(CAM_ISP, "Exit...(success)");
return 0;
err:
cam_ife_mgr_stop_hw_in_overflow(start_hw_args);
CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc);
return rc;
}
static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
{
int rc = -1;
struct cam_isp_start_args *start_isp = start_hw_args;
struct cam_hw_stop_args stop_args;
struct cam_isp_stop_args stop_isp;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_isp_resource_node *rsrc_node = NULL;
uint32_t i, camif_debug;
if (!hw_mgr_priv || !start_isp) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
ctx = (struct cam_ife_hw_mgr_ctx *)
start_isp->hw_config.ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
CAM_DBG(CAM_ISP, "Enter... ctx id:%d",
ctx->ctx_index);
/* update Bandwidth should be done at the hw layer */
cam_tasklet_start(ctx->common.tasklet_info);
if (ctx->init_done && start_isp->start_only)
goto start_only;
/* set current csid debug information to CSID HW */
for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
if (g_ife_hw_mgr.csid_devices[i])
rc = g_ife_hw_mgr.csid_devices[i]->hw_ops.process_cmd(
g_ife_hw_mgr.csid_devices[i]->hw_priv,
CAM_IFE_CSID_SET_CSID_DEBUG,
&g_ife_hw_mgr.debug_cfg.csid_debug,
sizeof(g_ife_hw_mgr.debug_cfg.csid_debug));
}
camif_debug = g_ife_hw_mgr.debug_cfg.camif_debug;
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
rsrc_node = hw_mgr_res->hw_res[i];
if (rsrc_node->process_cmd && (rsrc_node->res_id ==
CAM_ISP_HW_VFE_IN_CAMIF)) {
rc = hw_mgr_res->hw_res[i]->process_cmd(
hw_mgr_res->hw_res[i],
CAM_ISP_HW_CMD_SET_CAMIF_DEBUG,
&camif_debug,
sizeof(camif_debug));
}
}
}
rc = cam_ife_hw_mgr_init_hw(ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Init failed");
goto err;
}
start_only:
mutex_lock(&g_ife_hw_mgr.ctx_mutex);
if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) {
rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_ENABLE);
if (rc) {
CAM_ERR(CAM_ISP,
"SAFE SCM call failed:Check TZ/HYP dependency");
rc = -1;
}
}
mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
CAM_DBG(CAM_ISP, "start cdm interface");
rc = cam_cdm_stream_on(ctx->cdm_handle);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start cdm (%d)",
ctx->cdm_handle);
goto err;
}
if (!start_isp->start_only) {
/* Apply initial configuration */
CAM_DBG(CAM_ISP, "Config HW");
rc = cam_ife_mgr_config_hw(hw_mgr_priv,
&start_isp->hw_config);
if (rc) {
CAM_ERR(CAM_ISP, "Config HW failed");
goto err;
}
}
CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d",
ctx->ctx_index);
/* start the IFE out devices */
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_start_hw_res(
&ctx->res_list_ife_out[i], ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)",
i);
goto err;
}
}
CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d",
ctx->ctx_index);
/* Start the IFE mux in devices */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)",
hw_mgr_res->res_id);
goto err;
}
}
CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d",
ctx->ctx_index);
/* Start the IFE CSID HW devices */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
}
CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d",
ctx->ctx_index);
/* Start the IFE CID HW devices */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
if (rc) {
CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
}
ctx->init_done = true;
/* Start IFE root node: do nothing */
CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index);
return 0;
err:
stop_isp.stop_only = false;
stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY;
stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map;
stop_args.args = (void *)(&stop_isp);
cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args);
CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc);
return rc;
}
static int cam_ife_mgr_read(void *hw_mgr_priv, void *read_args)
{
return -EPERM;
}
static int cam_ife_mgr_write(void *hw_mgr_priv, void *write_args)
{
return -EPERM;
}
static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
void *release_hw_args)
{
int rc = 0;
struct cam_hw_release_args *release_args = release_hw_args;
struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv;
struct cam_ife_hw_mgr_ctx *ctx;
uint32_t i;
if (!hw_mgr_priv || !release_hw_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
ctx = (struct cam_ife_hw_mgr_ctx *)release_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
CAM_DBG(CAM_ISP, "Enter...ctx id:%d",
ctx->ctx_index);
if (ctx->init_done)
cam_ife_hw_mgr_deinit_hw(ctx);
/* we should called the stop hw before this already */
cam_ife_hw_mgr_release_hw_for_ctx(ctx);
/* reset base info */
ctx->num_base = 0;
memset(ctx->base, 0, sizeof(ctx->base));
/* release cdm handle */
cam_cdm_release(ctx->cdm_handle);
/* clean context */
list_del_init(&ctx->list);
ctx->ctx_in_use = 0;
ctx->is_rdi_only_context = 0;
ctx->cdm_handle = 0;
ctx->cdm_ops = NULL;
atomic_set(&ctx->overflow_pending, 0);
for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
ctx->sof_cnt[i] = 0;
ctx->eof_cnt[i] = 0;
ctx->epoch_cnt[i] = 0;
}
CAM_DBG(CAM_ISP, "Exit...ctx id:%d",
ctx->ctx_index);
cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx);
return rc;
}
static int cam_isp_blob_hfr_update(
uint32_t blob_type,
struct cam_isp_generic_blob_info *blob_info,
struct cam_isp_resource_hfr_config *hfr_config,
struct cam_hw_prepare_update_args *prepare)
{
struct cam_isp_port_hfr_config *port_hfr_config;
struct cam_kmd_buf_info *kmd_buf_info;
struct cam_ife_hw_mgr_ctx *ctx = NULL;
struct cam_ife_hw_mgr_res *hw_mgr_res;
uint32_t res_id_out, i;
uint32_t total_used_bytes = 0;
uint32_t kmd_buf_remain_size;
uint32_t *cmd_buf_addr;
uint32_t bytes_used = 0;
int num_ent, rc = 0;
ctx = prepare->ctxt_to_hw_map;
CAM_DBG(CAM_ISP, "num_ports= %d",
hfr_config->num_ports);
/* Max one hw entries required for hfr config update */
if (prepare->num_hw_update_entries + 1 >=
prepare->max_hw_update_entries) {
CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d",
prepare->num_hw_update_entries,
prepare->max_hw_update_entries);
return -EINVAL;
}
kmd_buf_info = blob_info->kmd_buf_info;
for (i = 0; i < hfr_config->num_ports; i++) {
port_hfr_config = &hfr_config->port_hfr_config[i];
res_id_out = port_hfr_config->resource_type & 0xFF;
CAM_DBG(CAM_ISP, "hfr config idx %d, type=%d", i,
res_id_out);
if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) {
CAM_ERR(CAM_ISP, "invalid out restype:%x",
port_hfr_config->resource_type);
return -EINVAL;
}
if ((kmd_buf_info->used_bytes
+ total_used_bytes) < kmd_buf_info->size) {
kmd_buf_remain_size = kmd_buf_info->size -
(kmd_buf_info->used_bytes +
total_used_bytes);
} else {
CAM_ERR(CAM_ISP,
"no free kmd memory for base %d",
blob_info->base_info->idx);
rc = -ENOMEM;
return rc;
}
cmd_buf_addr = kmd_buf_info->cpu_addr +
kmd_buf_info->used_bytes/4 +
total_used_bytes/4;
hw_mgr_res = &ctx->res_list_ife_out[res_id_out];
rc = cam_isp_add_cmd_buf_update(
hw_mgr_res, blob_type,
blob_type_hw_cmd_map[blob_type],
blob_info->base_info->idx,
(void *)cmd_buf_addr,
kmd_buf_remain_size,
(void *)port_hfr_config,
&bytes_used);
if (rc < 0) {
CAM_ERR(CAM_ISP,
"Failed cmd_update, base_idx=%d, rc=%d",
blob_info->base_info->idx, bytes_used);
return rc;
}
total_used_bytes += bytes_used;
}
if (total_used_bytes) {
/* Update the HW entries */
num_ent = prepare->num_hw_update_entries;
prepare->hw_update_entries[num_ent].handle =
kmd_buf_info->handle;
prepare->hw_update_entries[num_ent].len = total_used_bytes;
prepare->hw_update_entries[num_ent].offset =
kmd_buf_info->offset;
num_ent++;
kmd_buf_info->used_bytes += total_used_bytes;
kmd_buf_info->offset += total_used_bytes;
prepare->num_hw_update_entries = num_ent;
}
return rc;
}
static int cam_isp_blob_clock_update(
uint32_t blob_type,
struct cam_isp_generic_blob_info *blob_info,
struct cam_isp_clock_config *clock_config,
struct cam_hw_prepare_update_args *prepare)
{
struct cam_ife_hw_mgr_ctx *ctx = NULL;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_hw_intf *hw_intf;
struct cam_vfe_clock_update_args clock_upd_args;
uint64_t clk_rate = 0;
int rc = -EINVAL;
uint32_t i;
uint32_t j;
ctx = prepare->ctxt_to_hw_map;
CAM_DBG(CAM_PERF,
"usage=%u left_clk= %lu right_clk=%lu",
clock_config->usage_type,
clock_config->left_pix_hz,
clock_config->right_pix_hz);
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
clk_rate = 0;
if (!hw_mgr_res->hw_res[i])
continue;
if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
if (i == CAM_ISP_HW_SPLIT_LEFT)
clk_rate =
clock_config->left_pix_hz;
else
clk_rate =
clock_config->right_pix_hz;
else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
&& (hw_mgr_res->res_id <=
CAM_ISP_HW_VFE_IN_RDI3))
for (j = 0; j < clock_config->num_rdi; j++)
clk_rate = max(clock_config->rdi_hz[j],
clk_rate);
else
if (hw_mgr_res->hw_res[i]) {
CAM_ERR(CAM_ISP, "Invalid res_id %u",
hw_mgr_res->res_id);
rc = -EINVAL;
return rc;
}
hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
if (hw_intf && hw_intf->hw_ops.process_cmd) {
clock_upd_args.node_res =
hw_mgr_res->hw_res[i];
CAM_DBG(CAM_ISP,
"res_id=%u i= %d clk=%llu\n",
hw_mgr_res->res_id, i, clk_rate);
clock_upd_args.clk_rate = clk_rate;
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_ISP_HW_CMD_CLOCK_UPDATE,
&clock_upd_args,
sizeof(
struct cam_vfe_clock_update_args));
if (rc)
CAM_ERR(CAM_ISP, "Clock Update failed");
} else
CAM_WARN(CAM_ISP, "NULL hw_intf!");
}
}
return rc;
}
static int cam_isp_packet_generic_blob_handler(void *user_data,
uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
{
int rc = 0;
struct cam_isp_generic_blob_info *blob_info = user_data;
struct cam_hw_prepare_update_args *prepare = NULL;
if (!blob_data || (blob_size == 0) || !blob_info) {
CAM_ERR(CAM_ISP, "Invalid info blob %pK %d prepare %pK",
blob_data, blob_size, prepare);
return -EINVAL;
}
if (blob_type >= CAM_ISP_GENERIC_BLOB_TYPE_MAX) {
CAM_ERR(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type,
CAM_ISP_GENERIC_BLOB_TYPE_MAX);
return -EINVAL;
}
prepare = blob_info->prepare;
if (!prepare) {
CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d",
blob_type);
return -EINVAL;
}
switch (blob_type) {
case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: {
struct cam_isp_resource_hfr_config *hfr_config =
(struct cam_isp_resource_hfr_config *)blob_data;
rc = cam_isp_blob_hfr_update(blob_type, blob_info,
hfr_config, prepare);
if (rc)
CAM_ERR(CAM_ISP, "HFR Update Failed");
}
break;
case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: {
struct cam_isp_clock_config *clock_config =
(struct cam_isp_clock_config *)blob_data;
rc = cam_isp_blob_clock_update(blob_type, blob_info,
clock_config, prepare);
if (rc)
CAM_ERR(CAM_ISP, "Clock Update Failed");
}
break;
case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
struct cam_isp_bw_config *bw_config =
(struct cam_isp_bw_config *)blob_data;
struct cam_isp_prepare_hw_update_data *prepare_hw_data;
if (!prepare || !prepare->priv ||
(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
CAM_ERR(CAM_ISP, "Invalid inputs");
rc = -EINVAL;
break;
}
prepare_hw_data = (struct cam_isp_prepare_hw_update_data *)
prepare->priv;
memcpy(&prepare_hw_data->bw_config[bw_config->usage_type],
bw_config, sizeof(prepare_hw_data->bw_config[0]));
prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
}
break;
default:
CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
break;
}
return rc;
}
static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
void *prepare_hw_update_args)
{
int rc = 0;
struct cam_hw_prepare_update_args *prepare =
(struct cam_hw_prepare_update_args *) prepare_hw_update_args;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_ife_hw_mgr *hw_mgr;
struct cam_kmd_buf_info kmd_buf;
uint32_t i;
bool fill_fence = true;
struct cam_isp_prepare_hw_update_data *prepare_hw_data;
if (!hw_mgr_priv || !prepare_hw_update_args) {
CAM_ERR(CAM_ISP, "Invalid args");
return -EINVAL;
}
CAM_DBG(CAM_REQ, "Enter for req_id %lld",
prepare->packet->header.request_id);
prepare_hw_data = (struct cam_isp_prepare_hw_update_data *)
prepare->priv;
ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map;
hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv;
rc = cam_packet_util_validate_packet(prepare->packet);
if (rc)
return rc;
/* Pre parse the packet*/
rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf);
if (rc)
return rc;
rc = cam_packet_util_process_patches(prepare->packet,
hw_mgr->mgr_common.cmd_iommu_hdl,
hw_mgr->mgr_common.cmd_iommu_hdl_secure);
if (rc) {
CAM_ERR(CAM_ISP, "Patch ISP packet failed.");
return rc;
}
prepare->num_hw_update_entries = 0;
prepare->num_in_map_entries = 0;
prepare->num_out_map_entries = 0;
memset(&prepare_hw_data->bw_config[0], 0x0,
sizeof(prepare_hw_data->bw_config[0]) *
CAM_IFE_HW_NUM_MAX);
memset(&prepare_hw_data->bw_config_valid[0], 0x0,
sizeof(prepare_hw_data->bw_config_valid[0]) *
CAM_IFE_HW_NUM_MAX);
for (i = 0; i < ctx->num_base; i++) {
CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i);
/* Add change base */
rc = cam_isp_add_change_base(prepare, &ctx->res_list_ife_src,
ctx->base[i].idx, &kmd_buf);
if (rc) {
CAM_ERR(CAM_ISP,
"Failed in change base i=%d, idx=%d, rc=%d",
i, ctx->base[i].idx, rc);
goto end;
}
/* get command buffers */
if (ctx->base[i].split_id != CAM_ISP_HW_SPLIT_MAX) {
rc = cam_isp_add_command_buffers(prepare, &kmd_buf,
&ctx->base[i],
cam_isp_packet_generic_blob_handler,
ctx->res_list_ife_out, CAM_IFE_HW_OUT_RES_MAX);
if (rc) {
CAM_ERR(CAM_ISP,
"Failed in add cmdbuf, i=%d, split_id=%d, rc=%d",
i, ctx->base[i].split_id, rc);
goto end;
}
}
/* get IO buffers */
rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl,
hw_mgr->mgr_common.img_iommu_hdl_secure,
prepare, ctx->base[i].idx,
&kmd_buf, ctx->res_list_ife_out,
CAM_IFE_HW_OUT_RES_MAX, fill_fence);
if (rc) {
CAM_ERR(CAM_ISP,
"Failed in io buffers, i=%d, rc=%d",
i, rc);
goto end;
}
/* fence map table entries need to fill only once in the loop */
if (fill_fence)
fill_fence = false;
}
/*
* reg update will be done later for the initial configure.
* need to plus one to the op_code and only take the lower
* bits to get the type of operation since UMD definition
* of op_code has some difference from KMD.
*/
if (((prepare->packet->header.op_code + 1) & 0xF) ==
CAM_ISP_PACKET_INIT_DEV) {
prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV;
goto end;
} else
prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV;
/* add reg update commands */
for (i = 0; i < ctx->num_base; i++) {
/* Add change base */
rc = cam_isp_add_change_base(prepare, &ctx->res_list_ife_src,
ctx->base[i].idx, &kmd_buf);
if (rc) {
CAM_ERR(CAM_ISP,
"Failed in change base adding reg_update cmd i=%d, idx=%d, rc=%d",
i, ctx->base[i].idx, rc);
goto end;
}
/*Add reg update */
rc = cam_isp_add_reg_update(prepare, &ctx->res_list_ife_src,
ctx->base[i].idx, &kmd_buf);
if (rc) {
CAM_ERR(CAM_ISP,
"Add Reg_update cmd Failed i=%d, idx=%d, rc=%d",
i, ctx->base[i].idx, rc);
goto end;
}
}
end:
return rc;
}
static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
{
return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
}
static int cam_ife_mgr_sof_irq_debug(
struct cam_ife_hw_mgr_ctx *ctx,
uint32_t sof_irq_enable)
{
int rc = 0;
uint32_t i = 0;
struct cam_ife_hw_mgr_res *hw_mgr_res = NULL;
struct cam_hw_intf *hw_intf = NULL;
struct cam_isp_resource_node *rsrc_node = NULL;
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
if (hw_intf->hw_ops.process_cmd) {
rc |= hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_IFE_CSID_SOF_IRQ_DEBUG,
&sof_irq_enable,
sizeof(sof_irq_enable));
}
}
}
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
rsrc_node = hw_mgr_res->hw_res[i];
if (rsrc_node->process_cmd && (rsrc_node->res_id ==
CAM_ISP_HW_VFE_IN_CAMIF)) {
rc |= hw_mgr_res->hw_res[i]->process_cmd(
hw_mgr_res->hw_res[i],
CAM_ISP_HW_CMD_SOF_IRQ_DEBUG,
&sof_irq_enable,
sizeof(sof_irq_enable));
}
}
}
return rc;
}
static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet,
int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info,
bool *mem_found)
{
dma_addr_t iova_addr;
size_t src_buf_size;
int i;
int j;
int rc = 0;
int32_t mmu_hdl;
struct cam_buf_io_cfg *io_cfg = NULL;
if (mem_found)
*mem_found = false;
io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload +
packet->io_configs_offset / 4);
for (i = 0; i < packet->num_io_configs; i++) {
for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) {
if (!io_cfg[i].mem_handle[j])
break;
if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) ==
GET_FD_FROM_HANDLE(pf_buf_info)) {
CAM_INFO(CAM_ISP,
"Found PF at port: %d mem %x fd: %x",
io_cfg[i].resource_type,
io_cfg[i].mem_handle[j],
pf_buf_info);
if (mem_found)
*mem_found = true;
}
CAM_INFO(CAM_ISP, "port: %d f: %u format: %d dir %d",
io_cfg[i].resource_type,
io_cfg[i].fence,
io_cfg[i].format,
io_cfg[i].direction);
mmu_hdl = cam_mem_is_secure_buf(
io_cfg[i].mem_handle[j]) ? sec_mmu_hdl :
iommu_hdl;
rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j],
mmu_hdl, &iova_addr, &src_buf_size);
if (rc < 0) {
CAM_ERR(CAM_ISP, "get src buf address fail");
continue;
}
CAM_INFO(CAM_ISP,
"pln %d w %d h %d size %d addr 0x%x offset 0x%x memh %x",
j, io_cfg[i].planes[j].width,
io_cfg[i].planes[j].height,
(int32_t)src_buf_size,
(unsigned int)iova_addr,
io_cfg[i].offsets[j],
io_cfg[i].mem_handle[j]);
}
}
}
static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
{
int rc = 0;
struct cam_hw_cmd_args *hw_cmd_args = cmd_args;
struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv;
struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_hw_mgr_ctx *)
hw_cmd_args->ctxt_to_hw_map;
if (!hw_mgr_priv || !cmd_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
if (!ctx || !ctx->ctx_in_use) {
CAM_ERR(CAM_ISP, "Fatal: Invalid context is used");
return -EPERM;
}
switch (hw_cmd_args->cmd_type) {
case CAM_HW_MGR_CMD_INTERNAL: {
struct cam_isp_hw_cmd_args *isp_hw_cmd_args =
(struct cam_isp_hw_cmd_args *)hw_cmd_args->
u.internal_args;
switch (isp_hw_cmd_args->cmd_type) {
case CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT:
if (ctx->is_rdi_only_context)
isp_hw_cmd_args->u.is_rdi_only_context = 1;
else
isp_hw_cmd_args->u.is_rdi_only_context = 0;
break;
case CAM_ISP_HW_MGR_CMD_PAUSE_HW:
cam_ife_mgr_pause_hw(ctx);
break;
case CAM_ISP_HW_MGR_CMD_RESUME_HW:
cam_ife_mgr_resume_hw(ctx);
break;
case CAM_ISP_HW_MGR_CMD_SOF_DEBUG:
cam_ife_mgr_sof_irq_debug(ctx,
isp_hw_cmd_args->u.sof_irq_enable);
break;
default:
CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x",
hw_cmd_args->cmd_type);
rc = -EINVAL;
break;
}
break;
}
case CAM_HW_MGR_CMD_DUMP_PF_INFO:
cam_ife_mgr_print_io_bufs(
hw_cmd_args->u.pf_args.pf_data.packet,
hw_mgr->mgr_common.img_iommu_hdl,
hw_mgr->mgr_common.img_iommu_hdl_secure,
hw_cmd_args->u.pf_args.buf_info,
hw_cmd_args->u.pf_args.mem_found);
break;
default:
CAM_ERR(CAM_ISP, "Invalid cmd");
}
return rc;
}
static int cam_ife_mgr_cmd_get_sof_timestamp(
struct cam_ife_hw_mgr_ctx *ife_ctx,
uint64_t *time_stamp,
uint64_t *boot_time_stamp)
{
int rc = -EINVAL;
uint32_t i;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_hw_intf *hw_intf;
struct cam_csid_get_time_stamp_args csid_get_time;
list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i] ||
(i == CAM_ISP_HW_SPLIT_RIGHT))
continue;
/*
* Get the SOF time stamp from left resource only.
* Left resource is master for dual vfe case and
* Rdi only context case left resource only hold
* the RDI resource
*/
hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
if (hw_intf->hw_ops.process_cmd) {
csid_get_time.node_res =
hw_mgr_res->hw_res[i];
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_IFE_CSID_CMD_GET_TIME_STAMP,
&csid_get_time,
sizeof(
struct cam_csid_get_time_stamp_args));
if (!rc) {
*time_stamp =
csid_get_time.time_stamp_val;
*boot_time_stamp =
csid_get_time.boot_timestamp;
}
/*
* Single VFE case, Get the time stamp from available
* one csid hw in the context
* Dual VFE case, get the time stamp from master(left)
* would be sufficient
*/
goto end;
}
}
}
end:
if (rc)
CAM_ERR(CAM_ISP, "Getting sof time stamp failed");
return rc;
}
static int cam_ife_mgr_process_recovery_cb(void *priv, void *data)
{
int32_t rc = 0;
struct cam_hw_event_recovery_data *recovery_data = data;
struct cam_hw_start_args start_args;
struct cam_hw_stop_args stop_args;
struct cam_ife_hw_mgr *ife_hw_mgr = priv;
struct cam_ife_hw_mgr_res *hw_mgr_res;
uint32_t i = 0;
uint32_t error_type = recovery_data->error_type;
struct cam_ife_hw_mgr_ctx *ctx = NULL;
/* Here recovery is performed */
CAM_DBG(CAM_ISP, "ErrorType = %d", error_type);
switch (error_type) {
case CAM_ISP_HW_ERROR_OVERFLOW:
case CAM_ISP_HW_ERROR_BUSIF_OVERFLOW:
if (!recovery_data->affected_ctx[0]) {
CAM_ERR(CAM_ISP,
"No context is affected but recovery called");
kfree(recovery_data);
return 0;
}
/* stop resources here */
CAM_DBG(CAM_ISP, "STOP: Number of affected context: %d",
recovery_data->no_of_context);
for (i = 0; i < recovery_data->no_of_context; i++) {
stop_args.ctxt_to_hw_map =
recovery_data->affected_ctx[i];
rc = cam_ife_mgr_stop_hw_in_overflow(&stop_args);
if (rc) {
CAM_ERR(CAM_ISP, "CTX stop failed(%d)", rc);
return rc;
}
}
CAM_DBG(CAM_ISP, "RESET: CSID PATH");
for (i = 0; i < recovery_data->no_of_context; i++) {
ctx = recovery_data->affected_ctx[i];
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid,
list) {
rc = cam_ife_hw_mgr_reset_csid_res(hw_mgr_res);
if (rc) {
CAM_ERR(CAM_ISP, "Failed RESET (%d)",
hw_mgr_res->res_id);
return rc;
}
}
}
CAM_DBG(CAM_ISP, "RESET: Calling VFE reset");
for (i = 0; i < CAM_VFE_HW_NUM_MAX; i++) {
if (recovery_data->affected_core[i])
cam_ife_mgr_reset_vfe_hw(ife_hw_mgr, i);
}
CAM_DBG(CAM_ISP, "START: Number of affected context: %d",
recovery_data->no_of_context);
for (i = 0; i < recovery_data->no_of_context; i++) {
ctx = recovery_data->affected_ctx[i];
start_args.ctxt_to_hw_map = ctx;
atomic_set(&ctx->overflow_pending, 0);
rc = cam_ife_mgr_restart_hw(&start_args);
if (rc) {
CAM_ERR(CAM_ISP, "CTX start failed(%d)", rc);
return rc;
}
CAM_DBG(CAM_ISP, "Started resources rc (%d)", rc);
}
CAM_DBG(CAM_ISP, "Recovery Done rc (%d)", rc);
break;
case CAM_ISP_HW_ERROR_P2I_ERROR:
break;
case CAM_ISP_HW_ERROR_VIOLATION:
break;
default:
CAM_ERR(CAM_ISP, "Invalid Error");
}
CAM_DBG(CAM_ISP, "Exit: ErrorType = %d", error_type);
kfree(recovery_data);
return rc;
}
static int cam_ife_hw_mgr_do_error_recovery(
struct cam_hw_event_recovery_data *ife_mgr_recovery_data)
{
int32_t rc = 0;
struct crm_workq_task *task = NULL;
struct cam_hw_event_recovery_data *recovery_data = NULL;
recovery_data = kzalloc(sizeof(struct cam_hw_event_recovery_data),
GFP_ATOMIC);
if (!recovery_data)
return -ENOMEM;
memcpy(recovery_data, ife_mgr_recovery_data,
sizeof(struct cam_hw_event_recovery_data));
CAM_DBG(CAM_ISP, "Enter: error_type (%d)", recovery_data->error_type);
task = cam_req_mgr_workq_get_task(g_ife_hw_mgr.workq);
if (!task) {
CAM_ERR(CAM_ISP, "No empty task frame");
kfree(recovery_data);
return -ENOMEM;
}
task->process_cb = &cam_ife_mgr_process_recovery_cb;
task->payload = recovery_data;
rc = cam_req_mgr_workq_enqueue_task(task,
recovery_data->affected_ctx[0]->hw_mgr,
CRM_TASK_PRIORITY_0);
return rc;
}
/*
* This function checks if any of the valid entry in affected_core[]
* is associated with this context. if YES
* a. It fills the other cores associated with this context.in
* affected_core[]
* b. Return 0 i.e.SUCCESS
*/
static int cam_ife_hw_mgr_is_ctx_affected(
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx,
uint32_t *affected_core, uint32_t size)
{
int32_t rc = -EPERM;
uint32_t i = 0, j = 0;
uint32_t max_idx = ife_hwr_mgr_ctx->num_base;
uint32_t ctx_affected_core_idx[CAM_IFE_HW_NUM_MAX] = {0};
CAM_DBG(CAM_ISP, "Enter:max_idx = %d", max_idx);
if ((max_idx >= CAM_IFE_HW_NUM_MAX) ||
(size > CAM_IFE_HW_NUM_MAX)) {
CAM_ERR(CAM_ISP, "invalid parameter = %d", max_idx);
return rc;
}
for (i = 0; i < max_idx; i++) {
if (affected_core[ife_hwr_mgr_ctx->base[i].idx])
rc = 0;
else {
ctx_affected_core_idx[j] = ife_hwr_mgr_ctx->base[i].idx;
j = j + 1;
}
}
if (rc == 0) {
while (j) {
if (affected_core[ctx_affected_core_idx[j-1]] != 1)
affected_core[ctx_affected_core_idx[j-1]] = 1;
j = j - 1;
}
}
CAM_DBG(CAM_ISP, "Exit");
return rc;
}
/*
* Loop through each context
* a. match core_idx
* b. For each context from ctx_list Stop the acquired resources
* c. Notify CRM with fatal error for the affected isp context
* d. For any dual VFE context, if copanion VFE is also serving
* other context it should also notify the CRM with fatal error
*/
static int cam_ife_hw_mgr_process_overflow(
struct cam_ife_hw_mgr_ctx *curr_ife_hwr_mgr_ctx,
struct cam_isp_hw_error_event_data *error_event_data,
uint32_t curr_core_idx,
struct cam_hw_event_recovery_data *recovery_data)
{
uint32_t affected_core[CAM_IFE_HW_NUM_MAX] = {0};
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL;
cam_hw_event_cb_func ife_hwr_irq_err_cb;
struct cam_ife_hw_mgr *ife_hwr_mgr = NULL;
struct cam_hw_stop_args stop_args;
uint32_t i = 0;
CAM_DBG(CAM_ISP, "Enter");
if (!recovery_data) {
CAM_ERR(CAM_ISP, "recovery_data parameter is NULL");
return -EINVAL;
}
recovery_data->no_of_context = 0;
/* affected_core is indexed by core_idx*/
affected_core[curr_core_idx] = 1;
ife_hwr_mgr = curr_ife_hwr_mgr_ctx->hw_mgr;
list_for_each_entry(ife_hwr_mgr_ctx,
&ife_hwr_mgr->used_ctx_list, list) {
/*
* Check if current core_idx matches the HW associated
* with this context
*/
CAM_DBG(CAM_ISP, "Calling match Hw idx");
if (cam_ife_hw_mgr_is_ctx_affected(ife_hwr_mgr_ctx,
affected_core, CAM_IFE_HW_NUM_MAX))
continue;
atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1);
ife_hwr_irq_err_cb =
ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_ERROR];
stop_args.ctxt_to_hw_map = ife_hwr_mgr_ctx;
/* Add affected_context in list of recovery data*/
CAM_DBG(CAM_ISP, "Add new entry in affected_ctx_list");
if (recovery_data->no_of_context < CAM_CTX_MAX)
recovery_data->affected_ctx[
recovery_data->no_of_context++] =
ife_hwr_mgr_ctx;
/*
* In the call back function corresponding ISP context
* will update CRM about fatal Error
*/
ife_hwr_irq_err_cb(ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_ERROR, error_event_data);
}
/* fill the affected_core in recovery data */
for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
recovery_data->affected_core[i] = affected_core[i];
CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)",
i, recovery_data->affected_core[i]);
}
CAM_DBG(CAM_ISP, "Exit");
return 0;
}
static int cam_ife_hw_mgr_get_err_type(
void *handler_priv,
void *payload)
{
struct cam_isp_resource_node *hw_res_l = NULL;
struct cam_isp_resource_node *hw_res_r = NULL;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
struct cam_ife_hw_mgr_res *isp_ife_camif_res = NULL;
uint32_t status = 0;
uint32_t core_idx;
ife_hwr_mgr_ctx = handler_priv;
evt_payload = payload;
if (!evt_payload) {
CAM_ERR(CAM_ISP, "No payload");
return IRQ_HANDLED;
}
core_idx = evt_payload->core_index;
evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR;
list_for_each_entry(isp_ife_camif_res,
&ife_hwr_mgr_ctx->res_list_ife_src, list) {
if ((isp_ife_camif_res->res_type ==
CAM_IFE_HW_MGR_RES_UNINIT) ||
(isp_ife_camif_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF))
continue;
hw_res_l = isp_ife_camif_res->hw_res[CAM_ISP_HW_SPLIT_LEFT];
hw_res_r = isp_ife_camif_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT];
CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d\n",
isp_ife_camif_res->is_dual_vfe);
/* ERROR check for Left VFE */
if (!hw_res_l) {
CAM_DBG(CAM_ISP, "VFE(L) Device is NULL");
break;
}
CAM_DBG(CAM_ISP, "core id= %d, HW id %d", core_idx,
hw_res_l->hw_intf->hw_idx);
if (core_idx == hw_res_l->hw_intf->hw_idx) {
status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
}
if (status)
break;
/* ERROR check for Right VFE */
if (!hw_res_r) {
CAM_DBG(CAM_ISP, "VFE(R) Device is NULL");
continue;
}
CAM_DBG(CAM_ISP, "core id= %d, HW id %d", core_idx,
hw_res_r->hw_intf->hw_idx);
if (core_idx == hw_res_r->hw_intf->hw_idx) {
status = hw_res_r->bottom_half_handler(
hw_res_r, evt_payload);
}
if (status)
break;
}
CAM_DBG(CAM_ISP, "Exit (status = %d)!", status);
return status;
}
static int cam_ife_hw_mgr_handle_camif_error(
void *handler_priv,
void *payload)
{
int32_t error_status;
uint32_t core_idx;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
struct cam_isp_hw_error_event_data error_event_data = {0};
struct cam_hw_event_recovery_data recovery_data = {0};
ife_hwr_mgr_ctx = handler_priv;
evt_payload = payload;
core_idx = evt_payload->core_index;
error_status = cam_ife_hw_mgr_get_err_type(ife_hwr_mgr_ctx,
evt_payload);
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
return error_status;
switch (error_status) {
case CAM_ISP_HW_ERROR_OVERFLOW:
case CAM_ISP_HW_ERROR_P2I_ERROR:
case CAM_ISP_HW_ERROR_VIOLATION:
CAM_ERR(CAM_ISP, "Enter: error_type (%d)", error_status);
error_event_data.error_type =
CAM_ISP_HW_ERROR_OVERFLOW;
cam_ife_hw_mgr_process_overflow(ife_hwr_mgr_ctx,
&error_event_data,
core_idx,
&recovery_data);
/* Trigger for recovery */
recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW;
cam_ife_hw_mgr_do_error_recovery(&recovery_data);
break;
default:
CAM_DBG(CAM_ISP, "None error (%d)", error_status);
}
return 0;
}
/*
* DUAL VFE is valid for PIX processing path
* This function assumes hw_res[0] is master in case
* of dual VFE.
* RDI path does not support DUAl VFE
*/
static int cam_ife_hw_mgr_handle_reg_update(
void *handler_priv,
void *payload)
{
struct cam_isp_resource_node *hw_res;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
struct cam_ife_hw_mgr_res *ife_src_res = NULL;
cam_hw_event_cb_func ife_hwr_irq_rup_cb;
struct cam_isp_hw_reg_update_event_data rup_event_data;
uint32_t core_idx;
uint32_t rup_status = -EINVAL;
CAM_DBG(CAM_ISP, "Enter");
ife_hwr_mgr_ctx = handler_priv;
evt_payload = payload;
if (!handler_priv || !payload) {
CAM_ERR(CAM_ISP, "Invalid Parameter");
return -EPERM;
}
core_idx = evt_payload->core_index;
ife_hwr_irq_rup_cb =
ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE];
evt_payload->evt_id = CAM_ISP_HW_EVENT_REG_UPDATE;
list_for_each_entry(ife_src_res,
&ife_hwr_mgr_ctx->res_list_ife_src, list) {
if (ife_src_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT)
continue;
CAM_DBG(CAM_ISP, "resource id = %d, curr_core_idx = %d",
ife_src_res->res_id, core_idx);
switch (ife_src_res->res_id) {
case CAM_ISP_HW_VFE_IN_CAMIF:
if (ife_src_res->is_dual_vfe)
/* It checks for slave core RUP ACK*/
hw_res = ife_src_res->hw_res[1];
else
hw_res = ife_src_res->hw_res[0];
if (!hw_res) {
CAM_ERR(CAM_ISP, "CAMIF device is NULL");
break;
}
CAM_DBG(CAM_ISP,
"current_core_id = %d , core_idx res = %d",
core_idx, hw_res->hw_intf->hw_idx);
if (core_idx == hw_res->hw_intf->hw_idx) {
rup_status = hw_res->bottom_half_handler(
hw_res, evt_payload);
}
if (ife_src_res->is_dual_vfe) {
hw_res = ife_src_res->hw_res[0];
if (core_idx == hw_res->hw_intf->hw_idx) {
hw_res->bottom_half_handler(
hw_res, evt_payload);
}
}
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!rup_status) {
ife_hwr_irq_rup_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_REG_UPDATE,
&rup_event_data);
}
break;
case CAM_ISP_HW_VFE_IN_RDI0:
case CAM_ISP_HW_VFE_IN_RDI1:
case CAM_ISP_HW_VFE_IN_RDI2:
case CAM_ISP_HW_VFE_IN_RDI3:
hw_res = ife_src_res->hw_res[0];
if (!hw_res) {
CAM_ERR(CAM_ISP, "RDI Device is NULL");
break;
}
if (core_idx == hw_res->hw_intf->hw_idx)
rup_status = hw_res->bottom_half_handler(
hw_res, evt_payload);
if (!ife_hwr_mgr_ctx->is_rdi_only_context)
continue;
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!rup_status) {
/* Send the Reg update hw event */
ife_hwr_irq_rup_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_REG_UPDATE,
&rup_event_data);
}
break;
default:
CAM_ERR(CAM_ISP, "Invalid resource id (%d)",
ife_src_res->res_id);
}
}
if (!rup_status)
CAM_DBG(CAM_ISP, "Exit rup_status = %d", rup_status);
return 0;
}
static int cam_ife_hw_mgr_check_irq_for_dual_vfe(
struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx,
uint32_t core_idx0,
uint32_t core_idx1,
uint32_t hw_event_type)
{
int32_t rc = -1;
uint32_t *event_cnt = NULL;
switch (hw_event_type) {
case CAM_ISP_HW_EVENT_SOF:
event_cnt = ife_hw_mgr_ctx->sof_cnt;
break;
case CAM_ISP_HW_EVENT_EPOCH:
event_cnt = ife_hw_mgr_ctx->epoch_cnt;
break;
case CAM_ISP_HW_EVENT_EOF:
event_cnt = ife_hw_mgr_ctx->eof_cnt;
break;
default:
return 0;
}
if (event_cnt[core_idx0] ==
event_cnt[core_idx1]) {
event_cnt[core_idx0] = 0;
event_cnt[core_idx1] = 0;
rc = 0;
return rc;
}
if ((event_cnt[core_idx0] &&
(event_cnt[core_idx0] - event_cnt[core_idx1] > 1)) ||
(event_cnt[core_idx1] &&
(event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) {
CAM_ERR_RATE_LIMIT(CAM_ISP,
"One of the VFE cound not generate hw event %d",
hw_event_type);
rc = -1;
return rc;
}
CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d",
hw_event_type);
return rc;
}
static int cam_ife_hw_mgr_handle_epoch_for_camif_hw_res(
void *handler_priv,
void *payload)
{
int32_t rc = -EINVAL;
struct cam_isp_resource_node *hw_res_l;
struct cam_isp_resource_node *hw_res_r;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
struct cam_ife_hw_mgr_res *isp_ife_camif_res = NULL;
cam_hw_event_cb_func ife_hwr_irq_epoch_cb;
struct cam_isp_hw_epoch_event_data epoch_done_event_data;
uint32_t core_idx;
uint32_t epoch_status = -EINVAL;
uint32_t core_index0;
uint32_t core_index1;
CAM_DBG(CAM_ISP, "Enter");
ife_hwr_mgr_ctx = handler_priv;
evt_payload = payload;
ife_hwr_irq_epoch_cb =
ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH];
core_idx = evt_payload->core_index;
evt_payload->evt_id = CAM_ISP_HW_EVENT_EPOCH;
list_for_each_entry(isp_ife_camif_res,
&ife_hwr_mgr_ctx->res_list_ife_src, list) {
if ((isp_ife_camif_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT)
|| (isp_ife_camif_res->res_id !=
CAM_ISP_HW_VFE_IN_CAMIF))
continue;
hw_res_l = isp_ife_camif_res->hw_res[0];
hw_res_r = isp_ife_camif_res->hw_res[1];
switch (isp_ife_camif_res->is_dual_vfe) {
/* Handling Single VFE Scenario */
case 0:
/* EPOCH check for Left side VFE */
if (!hw_res_l) {
CAM_ERR(CAM_ISP, "Left Device is NULL");
break;
}
if (core_idx == hw_res_l->hw_intf->hw_idx) {
epoch_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
if (atomic_read(
&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!epoch_status)
ife_hwr_irq_epoch_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_EPOCH,
&epoch_done_event_data);
}
break;
/* Handling Dual VFE Scenario */
case 1:
/* SOF check for Left side VFE (Master)*/
if ((!hw_res_l) || (!hw_res_r)) {
CAM_ERR(CAM_ISP, "Dual VFE Device is NULL");
break;
}
if (core_idx == hw_res_l->hw_intf->hw_idx) {
epoch_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
if (!epoch_status)
ife_hwr_mgr_ctx->epoch_cnt[core_idx]++;
else
break;
}
/* SOF check for Right side VFE */
if (core_idx == hw_res_r->hw_intf->hw_idx) {
epoch_status = hw_res_r->bottom_half_handler(
hw_res_r, evt_payload);
if (!epoch_status)
ife_hwr_mgr_ctx->epoch_cnt[core_idx]++;
else
break;
}
core_index0 = hw_res_l->hw_intf->hw_idx;
core_index1 = hw_res_r->hw_intf->hw_idx;
rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(
ife_hwr_mgr_ctx,
core_index0,
core_index1,
evt_payload->evt_id);
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!rc)
ife_hwr_irq_epoch_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_EPOCH,
&epoch_done_event_data);
break;
/* Error */
default:
CAM_ERR(CAM_ISP, "error with hw_res");
}
}
if (!epoch_status)
CAM_DBG(CAM_ISP, "Exit epoch_status = %d", epoch_status);
return 0;
}
static int cam_ife_hw_mgr_process_camif_sof(
struct cam_ife_hw_mgr_res *isp_ife_camif_res,
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx,
struct cam_vfe_top_irq_evt_payload *evt_payload)
{
struct cam_isp_resource_node *hw_res_l = NULL;
struct cam_isp_resource_node *hw_res_r = NULL;
int32_t rc = -EINVAL;
uint32_t core_idx;
uint32_t sof_status = 0;
uint32_t core_index0;
uint32_t core_index1;
CAM_DBG(CAM_ISP, "Enter");
core_idx = evt_payload->core_index;
hw_res_l = isp_ife_camif_res->hw_res[0];
hw_res_r = isp_ife_camif_res->hw_res[1];
CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d",
isp_ife_camif_res->is_dual_vfe);
switch (isp_ife_camif_res->is_dual_vfe) {
/* Handling Single VFE Scenario */
case 0:
/* SOF check for Left side VFE */
if (!hw_res_l) {
CAM_ERR(CAM_ISP, "VFE Device is NULL");
break;
}
CAM_DBG(CAM_ISP, "curr_core_idx = %d,core idx hw = %d",
core_idx, hw_res_l->hw_intf->hw_idx);
if (core_idx == hw_res_l->hw_intf->hw_idx) {
sof_status = hw_res_l->bottom_half_handler(hw_res_l,
evt_payload);
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!sof_status)
rc = 0;
}
break;
/* Handling Dual VFE Scenario */
case 1:
/* SOF check for Left side VFE */
if (!hw_res_l) {
CAM_ERR(CAM_ISP, "VFE Device is NULL");
break;
}
CAM_DBG(CAM_ISP, "curr_core_idx = %d, res hw idx= %d",
core_idx,
hw_res_l->hw_intf->hw_idx);
if (core_idx == hw_res_l->hw_intf->hw_idx) {
sof_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
if (!sof_status)
ife_hwr_mgr_ctx->sof_cnt[core_idx]++;
else
break;
}
/* SOF check for Right side VFE */
if (!hw_res_r) {
CAM_ERR(CAM_ISP, "VFE Device is NULL");
break;
}
CAM_DBG(CAM_ISP, "curr_core_idx = %d, ews hw idx= %d",
core_idx,
hw_res_r->hw_intf->hw_idx);
if (core_idx == hw_res_r->hw_intf->hw_idx) {
sof_status = hw_res_r->bottom_half_handler(hw_res_r,
evt_payload);
if (!sof_status)
ife_hwr_mgr_ctx->sof_cnt[core_idx]++;
else
break;
}
core_index0 = hw_res_l->hw_intf->hw_idx;
core_index1 = hw_res_r->hw_intf->hw_idx;
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hwr_mgr_ctx,
core_index0, core_index1, evt_payload->evt_id);
break;
default:
CAM_ERR(CAM_ISP, "error with hw_res");
break;
}
CAM_DBG(CAM_ISP, "Exit (sof_status = %d)", sof_status);
return rc;
}
static int cam_ife_hw_mgr_handle_sof(
void *handler_priv,
void *payload)
{
struct cam_isp_resource_node *hw_res = NULL;
struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
struct cam_ife_hw_mgr_res *ife_src_res = NULL;
cam_hw_event_cb_func ife_hw_irq_sof_cb;
struct cam_isp_hw_sof_event_data sof_done_event_data;
uint32_t sof_status = 0;
bool sof_sent = false;
CAM_DBG(CAM_ISP, "Enter");
ife_hw_mgr_ctx = handler_priv;
evt_payload = payload;
if (!evt_payload) {
CAM_ERR(CAM_ISP, "no payload");
return IRQ_HANDLED;
}
ife_hw_irq_sof_cb =
ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF];
evt_payload->evt_id = CAM_ISP_HW_EVENT_SOF;
list_for_each_entry(ife_src_res,
&ife_hw_mgr_ctx->res_list_ife_src, list) {
if (ife_src_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT)
continue;
switch (ife_src_res->res_id) {
case CAM_ISP_HW_VFE_IN_RDI0:
case CAM_ISP_HW_VFE_IN_RDI1:
case CAM_ISP_HW_VFE_IN_RDI2:
case CAM_ISP_HW_VFE_IN_RDI3:
hw_res = ife_src_res->hw_res[0];
sof_status = hw_res->bottom_half_handler(
hw_res, evt_payload);
/* check if it is rdi only context */
if (ife_hw_mgr_ctx->is_rdi_only_context) {
if (!sof_status && !sof_sent) {
cam_ife_mgr_cmd_get_sof_timestamp(
ife_hw_mgr_ctx,
&sof_done_event_data.timestamp,
&sof_done_event_data.boot_time);
ife_hw_irq_sof_cb(
ife_hw_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_SOF,
&sof_done_event_data);
CAM_DBG(CAM_ISP, "sof_status = %d",
sof_status);
sof_sent = true;
}
}
break;
case CAM_ISP_HW_VFE_IN_CAMIF:
sof_status = cam_ife_hw_mgr_process_camif_sof(
ife_src_res, ife_hw_mgr_ctx, evt_payload);
if (!sof_status && !sof_sent) {
cam_ife_mgr_cmd_get_sof_timestamp(
ife_hw_mgr_ctx,
&sof_done_event_data.timestamp,
&sof_done_event_data.boot_time);
ife_hw_irq_sof_cb(
ife_hw_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_SOF,
&sof_done_event_data);
CAM_DBG(CAM_ISP, "sof_status = %d",
sof_status);
sof_sent = true;
}
break;
default:
CAM_ERR(CAM_ISP, "Invalid resource id :%d",
ife_src_res->res_id);
break;
}
}
return 0;
}
static int cam_ife_hw_mgr_handle_eof_for_camif_hw_res(
void *handler_priv,
void *payload)
{
int32_t rc = -EINVAL;
struct cam_isp_resource_node *hw_res_l = NULL;
struct cam_isp_resource_node *hw_res_r = NULL;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
struct cam_ife_hw_mgr_res *isp_ife_camif_res = NULL;
cam_hw_event_cb_func ife_hwr_irq_eof_cb;
struct cam_isp_hw_eof_event_data eof_done_event_data;
uint32_t core_idx;
uint32_t eof_status = 0;
uint32_t core_index0;
uint32_t core_index1;
CAM_DBG(CAM_ISP, "Enter");
ife_hwr_mgr_ctx = handler_priv;
evt_payload = payload;
if (!evt_payload) {
pr_err("%s: no payload\n", __func__);
return IRQ_HANDLED;
}
core_idx = evt_payload->core_index;
ife_hwr_irq_eof_cb =
ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF];
evt_payload->evt_id = CAM_ISP_HW_EVENT_EOF;
list_for_each_entry(isp_ife_camif_res,
&ife_hwr_mgr_ctx->res_list_ife_src, list) {
if ((isp_ife_camif_res->res_type ==
CAM_IFE_HW_MGR_RES_UNINIT) ||
(isp_ife_camif_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF))
continue;
hw_res_l = isp_ife_camif_res->hw_res[0];
hw_res_r = isp_ife_camif_res->hw_res[1];
CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d",
isp_ife_camif_res->is_dual_vfe);
switch (isp_ife_camif_res->is_dual_vfe) {
/* Handling Single VFE Scenario */
case 0:
/* EOF check for Left side VFE */
if (!hw_res_l) {
pr_err("%s: VFE Device is NULL\n",
__func__);
break;
}
CAM_DBG(CAM_ISP, "curr_core_idx = %d, core idx hw = %d",
core_idx, hw_res_l->hw_intf->hw_idx);
if (core_idx == hw_res_l->hw_intf->hw_idx) {
eof_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
if (atomic_read(
&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!eof_status)
ife_hwr_irq_eof_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_EOF,
&eof_done_event_data);
}
break;
/* Handling dual VFE Scenario */
case 1:
if ((!hw_res_l) || (!hw_res_r)) {
CAM_ERR(CAM_ISP, "Dual VFE Device is NULL");
break;
}
if (core_idx == hw_res_l->hw_intf->hw_idx) {
eof_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
if (!eof_status)
ife_hwr_mgr_ctx->eof_cnt[core_idx]++;
else
break;
}
/* EOF check for Right side VFE */
if (core_idx == hw_res_r->hw_intf->hw_idx) {
eof_status = hw_res_r->bottom_half_handler(
hw_res_r, evt_payload);
if (!eof_status)
ife_hwr_mgr_ctx->eof_cnt[core_idx]++;
else
break;
}
core_index0 = hw_res_l->hw_intf->hw_idx;
core_index1 = hw_res_r->hw_intf->hw_idx;
rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(
ife_hwr_mgr_ctx,
core_index0,
core_index1,
evt_payload->evt_id);
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!rc)
ife_hwr_irq_eof_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_EOF,
&eof_done_event_data);
break;
default:
CAM_ERR(CAM_ISP, "error with hw_res");
}
}
CAM_DBG(CAM_ISP, "Exit (eof_status = %d)", eof_status);
return 0;
}
static int cam_ife_hw_mgr_handle_buf_done_for_hw_res(
void *handler_priv,
void *payload)
{
int32_t buf_done_status = 0;
int32_t i;
int32_t rc = 0;
cam_hw_event_cb_func ife_hwr_irq_wm_done_cb;
struct cam_isp_resource_node *hw_res_l = NULL;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL;
struct cam_vfe_bus_irq_evt_payload *evt_payload = payload;
struct cam_ife_hw_mgr_res *isp_ife_out_res = NULL;
struct cam_hw_event_recovery_data recovery_data;
struct cam_isp_hw_done_event_data buf_done_event_data = {0};
struct cam_isp_hw_error_event_data error_event_data = {0};
uint32_t error_resc_handle[CAM_IFE_HW_OUT_RES_MAX];
uint32_t num_of_error_handles = 0;
CAM_DBG(CAM_ISP, "Enter");
ife_hwr_mgr_ctx = evt_payload->ctx;
ife_hwr_irq_wm_done_cb =
ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE];
evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE;
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
isp_ife_out_res = &ife_hwr_mgr_ctx->res_list_ife_out[i];
if (isp_ife_out_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT)
continue;
hw_res_l = isp_ife_out_res->hw_res[0];
/*
* DUAL VFE: Index 0 is always a master. In case of composite
* Error, if the error is not in master, it needs to be checked
* in slave (for debuging purpose only) For other cases:
* Index zero is valid
*/
if (hw_res_l && (evt_payload->core_index ==
hw_res_l->hw_intf->hw_idx))
buf_done_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
else
continue;
switch (buf_done_status) {
case CAM_VFE_IRQ_STATUS_ERR_COMP:
/*
* Write interface can pipeline upto 2 buffer done
* strobes from each write client. If any of the client
* triggers a third buffer done strobe before a
* composite interrupt based on the first buffer doneis
* triggered an error irq is set. This scenario can
* only happen if a client is 3 frames ahead of the
* other clients enabled in the same composite mask.
*/
case CAM_VFE_IRQ_STATUS_COMP_OWRT:
/*
* It is an indication that bandwidth is not sufficient
* to generate composite done irq within the VBI time.
*/
error_resc_handle[num_of_error_handles++] =
isp_ife_out_res->res_id;
if (num_of_error_handles > 0) {
error_event_data.error_type =
CAM_ISP_HW_ERROR_BUSIF_OVERFLOW;
goto err;
}
break;
case CAM_VFE_IRQ_STATUS_ERR:
break;
case CAM_VFE_IRQ_STATUS_SUCCESS:
buf_done_event_data.num_handles = 1;
buf_done_event_data.resource_handle[0] =
isp_ife_out_res->res_id;
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
/* Report for Successful buf_done event if any */
if (buf_done_event_data.num_handles > 0 &&
ife_hwr_irq_wm_done_cb) {
CAM_DBG(CAM_ISP, "notify isp context");
ife_hwr_irq_wm_done_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_DONE,
&buf_done_event_data);
}
break;
default:
/* Do NOTHING */
error_resc_handle[num_of_error_handles++] =
isp_ife_out_res->res_id;
if (num_of_error_handles > 0) {
error_event_data.error_type =
CAM_ISP_HW_ERROR_BUSIF_OVERFLOW;
goto err;
}
break;
}
if (!buf_done_status)
CAM_DBG(CAM_ISP,
"buf_done status:(%d),out_res->res_id: 0x%x",
buf_done_status, isp_ife_out_res->res_id);
}
return rc;
err:
/*
* Report for error if any.
* For the first phase, Error is reported as overflow, for all
* the affected context and any successful buf_done event is not
* reported.
*/
rc = cam_ife_hw_mgr_process_overflow(ife_hwr_mgr_ctx,
&error_event_data, evt_payload->core_index,
&recovery_data);
/*
* We can temporarily return from here as
* for the first phase, we are going to reset entire HW.
*/
CAM_DBG(CAM_ISP, "Exit buf_done_status Error = %d",
buf_done_status);
return rc;
}
int cam_ife_mgr_do_tasklet_buf_done(void *handler_priv,
void *evt_payload_priv)
{
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = handler_priv;
struct cam_vfe_bus_irq_evt_payload *evt_payload;
int rc = -EINVAL;
if (!handler_priv)
return rc;
evt_payload = evt_payload_priv;
ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)evt_payload->ctx;
CAM_DBG(CAM_ISP, "addr of evt_payload = %pK core index:0x%x",
evt_payload, evt_payload->core_index);
CAM_DBG(CAM_ISP, "bus_irq_status_0: = %x", evt_payload->irq_reg_val[0]);
CAM_DBG(CAM_ISP, "bus_irq_status_1: = %x", evt_payload->irq_reg_val[1]);
CAM_DBG(CAM_ISP, "bus_irq_status_2: = %x", evt_payload->irq_reg_val[2]);
CAM_DBG(CAM_ISP, "bus_irq_comp_err: = %x", evt_payload->irq_reg_val[3]);
CAM_DBG(CAM_ISP, "bus_irq_comp_owrt: = %x",
evt_payload->irq_reg_val[4]);
CAM_DBG(CAM_ISP, "bus_irq_dual_comp_err: = %x",
evt_payload->irq_reg_val[5]);
CAM_DBG(CAM_ISP, "bus_irq_dual_comp_owrt: = %x",
evt_payload->irq_reg_val[6]);
/* WM Done */
return cam_ife_hw_mgr_handle_buf_done_for_hw_res(ife_hwr_mgr_ctx,
evt_payload_priv);
}
int cam_ife_mgr_do_tasklet(void *handler_priv, void *evt_payload_priv)
{
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = handler_priv;
struct cam_vfe_top_irq_evt_payload *evt_payload;
int rc = -EINVAL;
if (!evt_payload_priv)
return rc;
evt_payload = evt_payload_priv;
if (!handler_priv)
return rc;
ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)handler_priv;
CAM_DBG(CAM_ISP, "addr of evt_payload = %pK core_index:%d",
(void *)evt_payload,
evt_payload->core_index);
CAM_DBG(CAM_ISP, "irq_status_0: = %x", evt_payload->irq_reg_val[0]);
CAM_DBG(CAM_ISP, "irq_status_1: = %x", evt_payload->irq_reg_val[1]);
CAM_DBG(CAM_ISP, "Violation register: = %x",
evt_payload->irq_reg_val[2]);
/*
* If overflow/overwrite/error/violation are pending
* for this context it needs to be handled remaining
* interrupts are ignored.
*/
if (g_ife_hw_mgr.debug_cfg.enable_recovery) {
CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled");
rc = cam_ife_hw_mgr_handle_camif_error(ife_hwr_mgr_ctx,
evt_payload_priv);
} else {
CAM_DBG(CAM_ISP, "recovery is not enabled");
rc = 0;
}
if (rc) {
CAM_ERR(CAM_ISP, "Encountered Error (%d), ignoring other irqs",
rc);
goto put_payload;
}
CAM_DBG(CAM_ISP, "Calling EOF");
cam_ife_hw_mgr_handle_eof_for_camif_hw_res(ife_hwr_mgr_ctx,
evt_payload_priv);
CAM_DBG(CAM_ISP, "Calling SOF");
/* SOF IRQ */
cam_ife_hw_mgr_handle_sof(ife_hwr_mgr_ctx,
evt_payload_priv);
CAM_DBG(CAM_ISP, "Calling RUP");
/* REG UPDATE */
cam_ife_hw_mgr_handle_reg_update(ife_hwr_mgr_ctx,
evt_payload_priv);
CAM_DBG(CAM_ISP, "Calling EPOCH");
/* EPOCH IRQ */
cam_ife_hw_mgr_handle_epoch_for_camif_hw_res(ife_hwr_mgr_ctx,
evt_payload_priv);
put_payload:
cam_vfe_put_evt_payload(evt_payload->core_info, &evt_payload);
return IRQ_HANDLED;
}
static int cam_ife_hw_mgr_sort_dev_with_caps(
struct cam_ife_hw_mgr *ife_hw_mgr)
{
int i;
/* get caps for csid devices */
for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
if (!ife_hw_mgr->csid_devices[i])
continue;
if (ife_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps) {
ife_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps(
ife_hw_mgr->csid_devices[i]->hw_priv,
&ife_hw_mgr->ife_csid_dev_caps[i],
sizeof(ife_hw_mgr->ife_csid_dev_caps[i]));
}
}
/* get caps for ife devices */
for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
if (!ife_hw_mgr->ife_devices[i])
continue;
if (ife_hw_mgr->ife_devices[i]->hw_ops.get_hw_caps) {
ife_hw_mgr->ife_devices[i]->hw_ops.get_hw_caps(
ife_hw_mgr->ife_devices[i]->hw_priv,
&ife_hw_mgr->ife_dev_caps[i],
sizeof(ife_hw_mgr->ife_dev_caps[i]));
}
}
return 0;
}
static int cam_ife_set_csid_debug(void *data, u64 val)
{
g_ife_hw_mgr.debug_cfg.csid_debug = val;
CAM_DBG(CAM_ISP, "Set CSID Debug value :%lld", val);
return 0;
}
static int cam_ife_get_csid_debug(void *data, u64 *val)
{
*val = g_ife_hw_mgr.debug_cfg.csid_debug;
CAM_DBG(CAM_ISP, "Get CSID Debug value :%lld",
g_ife_hw_mgr.debug_cfg.csid_debug);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(cam_ife_csid_debug,
cam_ife_get_csid_debug,
cam_ife_set_csid_debug, "%16llu");
static int cam_ife_set_camif_debug(void *data, u64 val)
{
g_ife_hw_mgr.debug_cfg.camif_debug = val;
CAM_DBG(CAM_ISP,
"Set camif enable_diag_sensor_status value :%lld", val);
return 0;
}
static int cam_ife_get_camif_debug(void *data, u64 *val)
{
*val = g_ife_hw_mgr.debug_cfg.camif_debug;
CAM_DBG(CAM_ISP,
"Set camif enable_diag_sensor_status value :%lld",
g_ife_hw_mgr.debug_cfg.csid_debug);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(cam_ife_camif_debug,
cam_ife_get_camif_debug,
cam_ife_set_camif_debug, "%16llu");
static int cam_ife_hw_mgr_debug_register(void)
{
g_ife_hw_mgr.debug_cfg.dentry = debugfs_create_dir("camera_ife",
NULL);
if (!g_ife_hw_mgr.debug_cfg.dentry) {
CAM_ERR(CAM_ISP, "failed to create dentry");
return -ENOMEM;
}
if (!debugfs_create_file("ife_csid_debug",
0644,
g_ife_hw_mgr.debug_cfg.dentry, NULL,
&cam_ife_csid_debug)) {
CAM_ERR(CAM_ISP, "failed to create cam_ife_csid_debug");
goto err;
}
if (!debugfs_create_u32("enable_recovery",
0644,
g_ife_hw_mgr.debug_cfg.dentry,
&g_ife_hw_mgr.debug_cfg.enable_recovery)) {
CAM_ERR(CAM_ISP, "failed to create enable_recovery");
goto err;
}
if (!debugfs_create_file("ife_camif_debug",
0644,
g_ife_hw_mgr.debug_cfg.dentry, NULL,
&cam_ife_camif_debug)) {
CAM_ERR(CAM_ISP, "failed to create cam_ife_camif_debug");
goto err;
}
g_ife_hw_mgr.debug_cfg.enable_recovery = 0;
return 0;
err:
debugfs_remove_recursive(g_ife_hw_mgr.debug_cfg.dentry);
return -ENOMEM;
}
int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
{
int rc = -EFAULT;
int i, j;
struct cam_iommu_handle cdm_handles;
struct cam_ife_hw_mgr_ctx *ctx_pool;
struct cam_ife_hw_mgr_res *res_list_ife_out;
CAM_DBG(CAM_ISP, "Enter");
memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr));
mutex_init(&g_ife_hw_mgr.ctx_mutex);
if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) {
CAM_ERR(CAM_ISP, "CSID num is different then IFE num");
return -EINVAL;
}
/* fill ife hw intf information */
for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
rc = cam_vfe_hw_init(&g_ife_hw_mgr.ife_devices[i], i);
if (!rc) {
struct cam_hw_info *vfe_hw =
(struct cam_hw_info *)
g_ife_hw_mgr.ife_devices[i]->hw_priv;
struct cam_hw_soc_info *soc_info = &vfe_hw->soc_info;
j++;
g_ife_hw_mgr.cdm_reg_map[i] = &soc_info->reg_map[0];
CAM_DBG(CAM_ISP,
"reg_map: mem base = %pK cam_base = 0x%llx",
(void __iomem *)soc_info->reg_map[0].mem_base,
(uint64_t) soc_info->reg_map[0].mem_cam_base);
} else {
g_ife_hw_mgr.cdm_reg_map[i] = NULL;
}
}
if (j == 0) {
CAM_ERR(CAM_ISP, "no valid IFE HW");
return -EINVAL;
}
/* fill csid hw intf information */
for (i = 0, j = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
rc = cam_ife_csid_hw_init(&g_ife_hw_mgr.csid_devices[i], i);
if (!rc)
j++;
}
if (!j) {
CAM_ERR(CAM_ISP, "no valid IFE CSID HW");
return -EINVAL;
}
cam_ife_hw_mgr_sort_dev_with_caps(&g_ife_hw_mgr);
/* setup ife context list */
INIT_LIST_HEAD(&g_ife_hw_mgr.free_ctx_list);
INIT_LIST_HEAD(&g_ife_hw_mgr.used_ctx_list);
/*
* for now, we only support one iommu handle. later
* we will need to setup more iommu handle for other
* use cases.
* Also, we have to release them once we have the
* deinit support
*/
if (cam_smmu_get_handle("ife",
&g_ife_hw_mgr.mgr_common.img_iommu_hdl)) {
CAM_ERR(CAM_ISP, "Can not get iommu handle");
return -EINVAL;
}
if (cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl,
CAM_SMMU_ATTACH)) {
CAM_ERR(CAM_ISP, "Attach iommu handle failed.");
goto attach_fail;
}
if (cam_smmu_get_handle("cam-secure",
&g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure)) {
CAM_ERR(CAM_ISP, "Failed to get secure iommu handle");
goto secure_fail;
}
CAM_DBG(CAM_ISP, "iommu_handles: non-secure[0x%x], secure[0x%x]",
g_ife_hw_mgr.mgr_common.img_iommu_hdl,
g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure);
if (!cam_cdm_get_iommu_handle("ife", &cdm_handles)) {
CAM_DBG(CAM_ISP, "Successfully acquired the CDM iommu handles");
g_ife_hw_mgr.mgr_common.cmd_iommu_hdl = cdm_handles.non_secure;
g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure =
cdm_handles.secure;
} else {
CAM_DBG(CAM_ISP, "Failed to acquire the CDM iommu handles");
g_ife_hw_mgr.mgr_common.cmd_iommu_hdl = -1;
g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure = -1;
}
atomic_set(&g_ife_hw_mgr.active_ctx_cnt, 0);
for (i = 0; i < CAM_CTX_MAX; i++) {
memset(&g_ife_hw_mgr.ctx_pool[i], 0,
sizeof(g_ife_hw_mgr.ctx_pool[i]));
INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].list);
INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in.list);
INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_cid);
INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_csid);
INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_src);
ctx_pool = &g_ife_hw_mgr.ctx_pool[i];
for (j = 0; j < CAM_IFE_HW_OUT_RES_MAX; j++) {
res_list_ife_out = &ctx_pool->res_list_ife_out[j];
INIT_LIST_HEAD(&res_list_ife_out->list);
}
/* init context pool */
INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].free_res_list);
for (j = 0; j < CAM_IFE_HW_RES_POOL_MAX; j++) {
INIT_LIST_HEAD(
&g_ife_hw_mgr.ctx_pool[i].res_pool[j].list);
list_add_tail(
&g_ife_hw_mgr.ctx_pool[i].res_pool[j].list,
&g_ife_hw_mgr.ctx_pool[i].free_res_list);
}
g_ife_hw_mgr.ctx_pool[i].cdm_cmd =
kzalloc(((sizeof(struct cam_cdm_bl_request)) +
((CAM_IFE_HW_ENTRIES_MAX - 1) *
sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
if (!g_ife_hw_mgr.ctx_pool[i].cdm_cmd) {
rc = -ENOMEM;
CAM_ERR(CAM_ISP, "Allocation Failed for cdm command");
goto end;
}
g_ife_hw_mgr.ctx_pool[i].ctx_index = i;
g_ife_hw_mgr.ctx_pool[i].hw_mgr = &g_ife_hw_mgr;
cam_tasklet_init(&g_ife_hw_mgr.mgr_common.tasklet_pool[i],
&g_ife_hw_mgr.ctx_pool[i], i);
g_ife_hw_mgr.ctx_pool[i].common.tasklet_info =
g_ife_hw_mgr.mgr_common.tasklet_pool[i];
init_completion(&g_ife_hw_mgr.ctx_pool[i].config_done_complete);
list_add_tail(&g_ife_hw_mgr.ctx_pool[i].list,
&g_ife_hw_mgr.free_ctx_list);
}
/* Create Worker for ife_hw_mgr with 10 tasks */
rc = cam_req_mgr_workq_create("cam_ife_worker", 10,
&g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0);
if (rc < 0) {
CAM_ERR(CAM_ISP, "Unable to create worker");
goto end;
}
/* fill return structure */
hw_mgr_intf->hw_mgr_priv = &g_ife_hw_mgr;
hw_mgr_intf->hw_get_caps = cam_ife_mgr_get_hw_caps;
hw_mgr_intf->hw_acquire = cam_ife_mgr_acquire_hw;
hw_mgr_intf->hw_start = cam_ife_mgr_start_hw;
hw_mgr_intf->hw_stop = cam_ife_mgr_stop_hw;
hw_mgr_intf->hw_read = cam_ife_mgr_read;
hw_mgr_intf->hw_write = cam_ife_mgr_write;
hw_mgr_intf->hw_release = cam_ife_mgr_release_hw;
hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update;
hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd;
if (iommu_hdl)
*iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl;
cam_ife_hw_mgr_debug_register();
CAM_DBG(CAM_ISP, "Exit");
return 0;
end:
if (rc) {
for (i = 0; i < CAM_CTX_MAX; i++) {
cam_tasklet_deinit(
&g_ife_hw_mgr.mgr_common.tasklet_pool[i]);
kfree(g_ife_hw_mgr.ctx_pool[i].cdm_cmd);
g_ife_hw_mgr.ctx_pool[i].cdm_cmd = NULL;
g_ife_hw_mgr.ctx_pool[i].common.tasklet_info = NULL;
}
}
cam_smmu_destroy_handle(
g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure);
g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure = -1;
secure_fail:
cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl,
CAM_SMMU_DETACH);
attach_fail:
cam_smmu_destroy_handle(g_ife_hw_mgr.mgr_common.img_iommu_hdl);
g_ife_hw_mgr.mgr_common.img_iommu_hdl = -1;
return rc;
}