msm: camera: isp: Isp irq injection framework

This change constructs a framework of ISP IRQ injection which
adds support for HW err IRQ simulation.

CRs-Fixed: 3430944
Change-Id: I9552d0aa8b4672bfa04bfc78714d87b72140ad9a
Signed-off-by: Stark Lin <quic_starlin@quicinc.com>
This commit is contained in:
Stark Lin
2023-07-26 14:53:35 -07:00
committed by Camera Software Integration
parent 5346e6db3f
commit c0377f2bff
23 changed files with 1524 additions and 48 deletions

View File

@@ -44,6 +44,33 @@
#define MAX_INTERNAL_RECOVERY_ATTEMPTS 1
#define MAX_PARAMS_FOR_IRQ_INJECT 5
#define IRQ_INJECT_DISPLAY_BUF_LEN 4096
typedef int (*cam_isp_irq_inject_cmd_parse_handler)(
struct cam_isp_irq_inject_param *irq_inject_param,
uint32_t param_index, char *token, bool *is_query);
#define IRQ_INJECT_USAGE_STRING \
"######################################################\n" \
"Usage:\n" \
"$INJECT_NODE : /sys/kernel/debug/camera/ife/isp_irq_inject\n\n" \
" - cat $INJECT_NODE\n" \
" print Usage, injected params and current active HW info.\n" \
" Also we need to cat the node to get output info after echo params to node.\n\n"\
" - echo ?:?:?:? > $INJECT_NODE\n" \
" print query info, entering '?' to any param besides req_id to query.\n\n" \
" - echo hw_type:hw_idx:res_id:irq_mask:req_id > $INJECT_NODE\n" \
" hw_type : Hw to inject IRQ\n" \
" hw_idx : Index of the selected hw\n" \
" reg_unit : Register to set irq\n" \
" irq_mask : IRQ to be triggered\n" \
" req_id : Req to trigger the IRQ, entering 'now' to this param will trigger " \
"irq immediately\n\n" \
"Up to 10 sets of inject params are supported.\n" \
"######################################################\n"
#define CAM_ISP_NON_RECOVERABLE_CSID_ERRORS \
(CAM_ISP_HW_ERROR_CSID_LANE_FIFO_OVERFLOW | \
CAM_ISP_HW_ERROR_CSID_PKT_HDR_CORRUPTED | \
@@ -75,6 +102,7 @@ static struct cam_ife_hw_mgr g_ife_hw_mgr;
static uint32_t g_num_ife_available, g_num_ife_lite_available, g_num_sfe_available;
static uint32_t g_num_ife_functional, g_num_ife_lite_functional, g_num_sfe_functional;
static uint32_t max_ife_out_res, max_sfe_out_res;
static char irq_inject_display_buf[IRQ_INJECT_DISPLAY_BUF_LEN];
static int cam_ife_mgr_find_core_idx(int split_id, struct cam_ife_hw_mgr_ctx *ctx,
enum cam_isp_hw_type hw_type, uint32_t *core_idx);
@@ -6644,6 +6672,206 @@ static void cam_ife_mgr_send_frame_event(uint64_t request_id, uint32_t ctx_index
}
}
static void cam_isp_irq_inject_clear_params(
struct cam_isp_irq_inject_param *param)
{
param->hw_type = -1;
param->hw_idx = -1;
param->reg_unit = -1;
param->irq_mask = -1;
param->req_id = 0;
param->is_valid = false;
memset(param->line_buf, '\0', LINE_BUFFER_LEN);
}
static int cam_ife_hw_mgr_sfe_irq_inject_or_dump_desc(
struct cam_ife_hw_mgr *hw_mgr,
struct cam_isp_irq_inject_param *params,
bool dump_irq_desc)
{
int i, rc = 0, offset = 0;
char *line_buf = NULL;
struct cam_hw_intf *hw_intf = NULL;
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
for (i = 0; i < CAM_SFE_HW_NUM_MAX; i++) {
if ((!hw_mgr->sfe_devices[i]) ||
(hw_mgr->sfe_devices[i]->hw_intf->hw_idx != params->hw_idx))
continue;
hw_intf = hw_mgr->sfe_devices[i]->hw_intf;
if (dump_irq_desc) {
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION, params,
sizeof(struct cam_isp_irq_inject_param));
goto clear_param;
}
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_IRQ_INJECTION, params,
sizeof(struct cam_isp_irq_inject_param));
if (rc)
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Injecting IRQ %x failed for SFE at req: %d\n",
params->irq_mask, params->req_id);
else
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"IRQ %#x injected for SFE at req: %d\n",
params->irq_mask, params->req_id);
break;
}
clear_param:
strlcat(irq_inject_display_buf, params->line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
/* Clear the param injected */
cam_isp_irq_inject_clear_params(params);
kfree(line_buf);
return rc;
}
static int cam_ife_hw_mgr_vfe_irq_inject_or_dump_desc(
struct cam_ife_hw_mgr *hw_mgr,
struct cam_isp_irq_inject_param *params,
bool dump_irq_desc)
{
int i, rc = 0, offset = 0;
char *line_buf = NULL;
struct cam_hw_intf *hw_intf = NULL;
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
if ((!hw_mgr->ife_devices[i]) ||
(hw_mgr->ife_devices[i]->hw_intf->hw_idx != params->hw_idx))
continue;
hw_intf = hw_mgr->ife_devices[i]->hw_intf;
if (dump_irq_desc) {
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION, params,
sizeof(struct cam_isp_irq_inject_param));
goto clear_param;
}
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_IRQ_INJECTION, params,
sizeof(struct cam_isp_irq_inject_param));
if (rc)
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Injecting IRQ %x failed for IFE at req: %d\n",
params->irq_mask, params->req_id);
else
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"IRQ %#x injected for IFE at req: %d\n",
params->irq_mask, params->req_id);
break;
}
clear_param:
strlcat(irq_inject_display_buf, params->line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
/* Clear the param injected */
cam_isp_irq_inject_clear_params(params);
kfree(line_buf);
return rc;
}
static int cam_ife_hw_mgr_csid_irq_inject_or_dump_desc(
struct cam_ife_hw_mgr *hw_mgr,
struct cam_isp_irq_inject_param *params,
bool dump_irq_desc)
{
int i, rc = 0, offset = 0;
char *line_buf = NULL;
struct cam_hw_intf *hw_intf = NULL;
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
if ((!hw_mgr->csid_devices[i]) ||
(hw_mgr->csid_devices[i]->hw_idx != params->hw_idx))
continue;
hw_intf = hw_mgr->csid_devices[i];
if (dump_irq_desc) {
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION, params,
sizeof(struct cam_isp_irq_inject_param));
goto clear_param;
}
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
CAM_ISP_HW_CMD_IRQ_INJECTION, params,
sizeof(struct cam_isp_irq_inject_param));
if (rc)
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Injecting IRQ %x failed for CSID at req: %d\n",
params->irq_mask, params->req_id);
else
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"IRQ %#x injected for CSID at req: %d\n",
params->irq_mask, params->req_id);
break;
}
clear_param:
strlcat(irq_inject_display_buf, params->line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
/* Clear the param injected */
cam_isp_irq_inject_clear_params(params);
kfree(line_buf);
return rc;
}
static int cam_ife_hw_mgr_irq_injection(struct cam_ife_hw_mgr *hw_mgr,
uint64_t request_id)
{
int i, rc = 0;
for (i = 0; i < MAX_INJECT_SET; i++) {
if ((!hw_mgr->irq_inject_param[i].is_valid) ||
((hw_mgr->irq_inject_param[i].req_id != request_id) &&
(hw_mgr->irq_inject_param[i].req_id != 0xFFFFFFFF)))
continue;
switch (hw_mgr->irq_inject_param[i].hw_type) {
case CAM_ISP_HW_TYPE_CSID:
rc = cam_ife_hw_mgr_csid_irq_inject_or_dump_desc(
hw_mgr, &hw_mgr->irq_inject_param[i], false);
break;
case CAM_ISP_HW_TYPE_VFE:
rc = cam_ife_hw_mgr_vfe_irq_inject_or_dump_desc(
hw_mgr, &hw_mgr->irq_inject_param[i], false);
break;
case CAM_ISP_HW_TYPE_SFE:
rc = cam_ife_hw_mgr_sfe_irq_inject_or_dump_desc(
hw_mgr, &hw_mgr->irq_inject_param[i], false);
break;
default:
strlcat(irq_inject_display_buf, "No matched HW_TYPE\n",
IRQ_INJECT_DISPLAY_BUF_LEN);
rc = -EINVAL;
return rc;
}
}
return rc;
}
/* entry function: config_hw */
static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
void *config_hw_args)
@@ -6654,6 +6882,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
struct cam_cdm_bl_request *cdm_cmd;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_isp_prepare_hw_update_data *hw_update_data;
struct cam_ife_hw_mgr *ife_hw_mgr;
unsigned long rem_jiffies = 0;
bool is_cdm_hung = false;
@@ -6663,6 +6892,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
hw_mgr_priv, config_hw_args);
return -EINVAL;
}
ife_hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv;
cfg = config_hw_args;
ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map;
@@ -6699,6 +6929,11 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
ctx, ctx->ctx_index, cfg->request_id);
}
rc = cam_ife_hw_mgr_irq_injection(ife_hw_mgr, cfg->request_id);
if (rc)
CAM_ERR(CAM_ISP, "Failed to inject IRQ at req %d",
cfg->request_id);
hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv;
hw_update_data->isp_mgr_ctx = ctx;
ctx->cdm_userdata.request_id = cfg->request_id;
@@ -15477,6 +15712,469 @@ DEFINE_DEBUGFS_ATTRIBUTE(cam_ife_csid_testbus_debug,
cam_ife_get_csid_testbus_debug,
cam_ife_set_csid_testbus_debug, "%16llu");
static int cam_ife_hw_mgr_dump_irq_desc(struct cam_ife_hw_mgr *hw_mgr,
struct cam_isp_irq_inject_param *param)
{
int rc = 0;
switch (param->hw_type) {
case CAM_ISP_HW_TYPE_CSID:
rc = cam_ife_hw_mgr_csid_irq_inject_or_dump_desc(
hw_mgr, param, true);
break;
case CAM_ISP_HW_TYPE_VFE:
rc = cam_ife_hw_mgr_vfe_irq_inject_or_dump_desc(
hw_mgr, param, true);
break;
case CAM_ISP_HW_TYPE_SFE:
rc = cam_ife_hw_mgr_sfe_irq_inject_or_dump_desc(
hw_mgr, param, true);
break;
default:
strlcat(irq_inject_display_buf, "No matched HW_TYPE\n", IRQ_INJECT_DISPLAY_BUF_LEN);
rc = -EINVAL;
return rc;
}
return rc;
}
static void cam_ife_hw_mgr_dump_active_hw(char *buffer, int *offset)
{
uint32_t i;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_isp_hw_mgr_res *hw_mgr_res;
struct cam_isp_hw_mgr_res *hw_mgr_res_temp;
struct cam_ife_hw_mgr_ctx *ctx_temp;
mutex_lock(&g_ife_hw_mgr.ctx_mutex);
if (list_empty(&g_ife_hw_mgr.used_ctx_list)) {
*offset += scnprintf(buffer + *offset, LINE_BUFFER_LEN - *offset,
"Currently no ctx in use\n");
mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
return;
}
list_for_each_entry_safe(ctx, ctx_temp,
&g_ife_hw_mgr.used_ctx_list, list) {
list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
&ctx->res_list_ife_csid, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
*offset += scnprintf(buffer + *offset,
LINE_BUFFER_LEN - *offset,
"hw_type:CSID hw_idx:%d ctx id:%u res: %s\n",
hw_mgr_res->hw_res[i]->hw_intf->hw_idx, ctx->ctx_index,
hw_mgr_res->hw_res[i]->res_name);
}
}
list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
&ctx->res_list_ife_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
*offset += scnprintf(buffer + *offset,
LINE_BUFFER_LEN - *offset,
"hw_type:IFE hw_idx:%d ctx id:%u res: %s\n",
hw_mgr_res->hw_res[i]->hw_intf->hw_idx, ctx->ctx_index,
hw_mgr_res->hw_res[i]->res_name);
}
}
list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
&ctx->res_list_sfe_src, list) {
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
*offset += scnprintf(buffer + *offset,
LINE_BUFFER_LEN - *offset,
"hw_type:SFE hw_idx:%d ctx id:%u res: %s\n",
hw_mgr_res->hw_res[i]->hw_intf->hw_idx, ctx->ctx_index,
hw_mgr_res->hw_res[i]->res_name);
}
}
}
mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
}
static inline char *__cam_isp_irq_inject_reg_unit_to_name(int32_t reg_unit)
{
switch (reg_unit) {
case CAM_ISP_CSID_TOP_REG:
return "CAM_ISP_CSID_TOP_REG";
case CAM_ISP_CSID_RX_REG:
return "CAM_ISP_CSID_RX_REG";
case CAM_ISP_CSID_PATH_IPP_REG:
return "CAM_ISP_CSID_PATH_IPP_REG";
case CAM_ISP_CSID_PATH_PPP_REG:
return "CAM_ISP_CSID_PATH_PPP_REG";
case CAM_ISP_CSID_PATH_RDI0_REG:
return "CAM_ISP_CSID_PATH_RDI0_REG";
case CAM_ISP_CSID_PATH_RDI1_REG:
return "CAM_ISP_CSID_PATH_RDI1_REG";
case CAM_ISP_CSID_PATH_RDI2_REG:
return "CAM_ISP_CSID_PATH_RDI2_REG";
case CAM_ISP_CSID_PATH_RDI3_REG:
return "CAM_ISP_CSID_PATH_RDI3_REG";
case CAM_ISP_CSID_PATH_RDI4_REG:
return "CAM_ISP_CSID_PATH_RDI4_REG";
case CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG:
return "CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG";
case CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_1_REG:
return "CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_1_REG";
case CAM_ISP_SFE_0_BUS_RD_INPUT_IF_IRQ_SET_REG:
return "CAM_ISP_SFE_0_BUS_RD_INPUT_IF_IRQ_SET_REG";
case CAM_ISP_SFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG:
return "CAM_ISP_SFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG";
default:
return "Invalid reg_unit";
}
}
static inline char *__cam_isp_irq_inject_hw_type_to_name(int32_t hw_type)
{
switch (hw_type) {
case CAM_ISP_HW_TYPE_CSID:
return "CSID";
case CAM_ISP_HW_TYPE_VFE:
return "VFE";
case CAM_ISP_HW_TYPE_SFE:
return "SFE";
default:
return "Invalid hw_type";
}
}
static inline int cam_isp_irq_inject_get_hw_type(
int32_t *hw_type, char *token)
{
if (strcmp(token, "CSID") == 0)
*hw_type = CAM_ISP_HW_TYPE_CSID;
else if (strcmp(token, "VFE") == 0)
*hw_type = CAM_ISP_HW_TYPE_VFE;
else if (strcmp(token, "SFE") == 0)
*hw_type = CAM_ISP_HW_TYPE_SFE;
else
return -EINVAL;
return 0;
}
static int cam_isp_irq_inject_parse_common_params(
struct cam_isp_irq_inject_param *irq_inject_param,
uint32_t param_index, char *token, bool *is_query)
{
int i, rc = 0, offset = 0;
char *line_buf = NULL;
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
switch (param_index) {
case HW_TYPE:
if (strnstr(token, "?", 1)) {
*is_query = true;
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Interruptable HW : CSID | IFE | SFE\n");
break;
}
rc = cam_isp_irq_inject_get_hw_type(&irq_inject_param->hw_type, token);
if (rc) {
irq_inject_param->hw_type = -1;
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Invalid camera hardware [ %s ]\n", token);
}
break;
case HW_IDX:
if (strnstr(token, "?", 1)) {
*is_query = true;
if (irq_inject_param->hw_type == -1) {
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"HW_IDX : Enter hw_type first\n");
break;
}
switch (irq_inject_param->hw_type) {
case CAM_ISP_HW_TYPE_CSID:
for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
if (!g_ife_hw_mgr.csid_devices[i])
break;
}
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"Max index of CSID : %d\n", i - 1);
break;
case CAM_ISP_HW_TYPE_VFE:
for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
if (!g_ife_hw_mgr.ife_devices[i])
break;
}
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"Max index of VFE : %d\n", i - 1);
break;
case CAM_ISP_HW_TYPE_SFE:
for (i = 0; i < CAM_SFE_HW_NUM_MAX; i++) {
if (!g_ife_hw_mgr.sfe_devices[i])
break;
}
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"Max index of SFE : %d\n", i - 1);
break;
default:
break;
}
} else if (kstrtou32(token, 0, &irq_inject_param->hw_idx)) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Invalid hw index %s\n", token);
rc = -EINVAL;
}
break;
case REG_UNIT:
if (strnstr(token, "?", 1)) {
*is_query = true;
if (irq_inject_param->hw_type == -1) {
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"REG_UNIT : Enter hw_type first\n");
break;
}
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Printing available res for hw_type: %s\n",
__cam_isp_irq_inject_hw_type_to_name(
irq_inject_param->hw_type));
for (i = 0; i < CAM_ISP_REG_UNIT_MAX; i++) {
if ((irq_inject_param->hw_type == CAM_ISP_HW_TYPE_CSID) &&
i > CAM_ISP_CSID_PATH_RDI4_REG)
continue;
else if ((irq_inject_param->hw_type == CAM_ISP_HW_TYPE_VFE) &&
((i < CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG) ||
(i > CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_1_REG)))
continue;
else if ((irq_inject_param->hw_type == CAM_ISP_HW_TYPE_SFE) &&
((i < CAM_ISP_SFE_0_BUS_RD_INPUT_IF_IRQ_SET_REG) ||
(i > CAM_ISP_SFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG)))
continue;
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset, "%d : %s\n", i,
__cam_isp_irq_inject_reg_unit_to_name(i));
}
} else if (kstrtou32(token, 0, &irq_inject_param->reg_unit)) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Invalid register %s\n", token);
rc = -EINVAL;
}
break;
case IRQ_MASK:
if (strnstr(token, "?", 1)) {
*is_query = true;
if ((irq_inject_param->hw_type == -1) ||
(irq_inject_param->reg_unit == -1)) {
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"IRQ_MASK : Enter hw_type and reg_unit first\n");
break;
}
if (cam_ife_hw_mgr_dump_irq_desc(&g_ife_hw_mgr,
irq_inject_param)) {
offset += scnprintf(line_buf + offset,
LINE_BUFFER_LEN - offset,
"Dump irq description failed\n");
rc = -EINVAL;
}
} else if (kstrtou32(token, 0, &irq_inject_param->irq_mask)) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Invalid irq mask %s\n", token);
rc = -EINVAL;
}
break;
case INJECT_REQ:
if (strnstr(token, "now", 3)) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Trigger IRQ now\n");
irq_inject_param->req_id = 0xFFFFFFFF;
} else if (kstrtou64(token, 0, &irq_inject_param->req_id)) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Invalid request id %s\n", token);
rc = -EINVAL;
}
break;
default:
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Invalid extra parameter: %s\n", token);
rc = -EINVAL;
}
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
kfree(line_buf);
return rc;
}
static int cam_isp_irq_inject_command_parser(
struct cam_isp_irq_inject_param *irq_inject_param,
char **msg, uint32_t max_params,
cam_isp_irq_inject_cmd_parse_handler cmd_parse_cb,
bool *is_query)
{
char *token = NULL;
char *line_buf = NULL;
int rc, param_index = 0, offset = 0;
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
token = strsep(msg, ":");
while (token != NULL) {
rc = cmd_parse_cb(irq_inject_param, param_index, token, is_query);
if (rc) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Parsed Command failed rc: %d\n", rc);
return rc;
}
param_index++;
if (param_index == max_params)
break;
token = strsep(msg, ":");
}
if ((param_index < max_params) && !(*is_query)) {
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Insufficient parameters passed for total parameters: %u\n",
param_index);
return -EINVAL;
}
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
kfree(line_buf);
return param_index;
}
static ssize_t cam_isp_irq_injection_read(struct file *file,
char __user *ubuf,
size_t size, loff_t *ppos)
{
int i, offset = 0;
int count = 0;
uint32_t hw_type = 0;
char *line_buf = NULL;
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
if (!(*ppos) && strlen(irq_inject_display_buf))
goto end;
else if ((*ppos) && (strlen(irq_inject_display_buf) == 0))
return 0;
strlcat(irq_inject_display_buf, IRQ_INJECT_USAGE_STRING, IRQ_INJECT_DISPLAY_BUF_LEN);
for (i = 0; i < MAX_INJECT_SET; i++) {
if (!g_ife_hw_mgr.irq_inject_param[i].is_valid)
continue;
hw_type = g_ife_hw_mgr.irq_inject_param[i].hw_type;
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"injected param[%d] : hw_type:%s hw_idx:%d reg_unit:%d irq_mask:%#x req_id:%d\n",
i, __cam_isp_irq_inject_hw_type_to_name(hw_type),
g_ife_hw_mgr.irq_inject_param[i].hw_idx,
g_ife_hw_mgr.irq_inject_param[i].reg_unit,
g_ife_hw_mgr.irq_inject_param[i].irq_mask,
g_ife_hw_mgr.irq_inject_param[i].req_id);
}
cam_ife_hw_mgr_dump_active_hw(line_buf, &offset);
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
end:
if (clear_user(ubuf, size))
return -EIO;
count = simple_read_from_buffer(ubuf, size, ppos, irq_inject_display_buf,
strlen(irq_inject_display_buf));
memset(irq_inject_display_buf, '\0', IRQ_INJECT_DISPLAY_BUF_LEN);
kfree(line_buf);
return count;
}
static ssize_t cam_isp_irq_injection_write(struct file *file,
const char __user *ubuf, size_t size, loff_t *ppos)
{
bool is_query = false;
int i, rc = 0;
int offset = 0;
uint32_t hw_type = 0;
char *msg = NULL;
char *line_buf = NULL;
char input_buf[LINE_BUFFER_LEN] = {'\0'};
line_buf = kzalloc(sizeof(char) * LINE_BUFFER_LEN, GFP_KERNEL);
if (!line_buf)
return -ENOMEM;
memset(irq_inject_display_buf, '\0', IRQ_INJECT_DISPLAY_BUF_LEN);
if (copy_from_user(input_buf, ubuf, sizeof(input_buf)))
return -EFAULT;
msg = input_buf;
for (i = 0; i < MAX_INJECT_SET; i++) {
if (g_ife_hw_mgr.irq_inject_param[i].is_valid)
continue;
rc = cam_isp_irq_inject_command_parser(
&g_ife_hw_mgr.irq_inject_param[i], &msg,
MAX_PARAMS_FOR_IRQ_INJECT,
cam_isp_irq_inject_parse_common_params, &is_query);
if ((rc != MAX_PARAMS_FOR_IRQ_INJECT) || is_query) {
cam_isp_irq_inject_clear_params(&g_ife_hw_mgr.irq_inject_param[i]);
if (!is_query)
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Parsed Command failed, param_index = %d\n", rc);
} else {
g_ife_hw_mgr.irq_inject_param[i].is_valid = true;
hw_type = g_ife_hw_mgr.irq_inject_param[i].hw_type;
offset += scnprintf(line_buf + offset, LINE_BUFFER_LEN - offset,
"Setting param[%d] : hw_type:%s hw_idx:%d reg_unit:%d irq_mask:%#x req_id:%d\n",
i, __cam_isp_irq_inject_hw_type_to_name(hw_type),
g_ife_hw_mgr.irq_inject_param[i].hw_idx,
g_ife_hw_mgr.irq_inject_param[i].reg_unit,
g_ife_hw_mgr.irq_inject_param[i].irq_mask,
g_ife_hw_mgr.irq_inject_param[i].req_id);
}
break;
}
strlcat(irq_inject_display_buf, line_buf, IRQ_INJECT_DISPLAY_BUF_LEN);
kfree(line_buf);
return size;
}
static const struct file_operations cam_isp_irq_injection = {
.owner = THIS_MODULE,
.open = simple_open,
.read = cam_isp_irq_injection_read,
.write = cam_isp_irq_injection_write,
};
static int cam_ife_hw_mgr_debug_register(void)
{
int rc = 0;
@@ -15537,6 +16235,8 @@ static int cam_ife_hw_mgr_debug_register(void)
debugfs_create_bool("enable_presil_reg_dump", 0644,
g_ife_hw_mgr.debug_cfg.dentry,
&g_ife_hw_mgr.debug_cfg.enable_presil_reg_dump);
debugfs_create_file("isp_irq_inject", 0644,
g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_isp_irq_injection);
end:
g_ife_hw_mgr.debug_cfg.enable_csid_recovery = 1;
return rc;
@@ -15808,6 +16508,9 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl,
memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr));
memset(&path_port_map, 0, sizeof(path_port_map));
for (i = 0; i < MAX_INJECT_SET; i++)
cam_isp_irq_inject_clear_params(&g_ife_hw_mgr.irq_inject_param[i]);
mutex_init(&g_ife_hw_mgr.ctx_mutex);
spin_lock_init(&g_ife_hw_mgr.ctx_lock);

View File

@@ -38,6 +38,9 @@ enum cam_ife_ctx_master_type {
#define CAM_IFE_CTX_CFG_SW_SYNC_ON BIT(1)
#define CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON BIT(2)
/* Maximum set for irq injection*/
#define MAX_INJECT_SET 10
/**
* struct cam_ife_hw_mgr_debug - contain the debug information
*
@@ -455,6 +458,36 @@ struct cam_isp_sfe_cache_info {
bool activated[CAM_ISP_EXPOSURE_MAX];
};
/*
* struct cam_isp_irq_inject_irq_desc: Structure to hold IRQ description
*
* @bitmask : Bitmask of the IRQ
* @desc : String to describe the IRQ bit
*/
struct cam_isp_irq_inject_irq_desc {
uint32_t bitmask;
char *desc;
};
/*
* enum cam_isp_irq_inject_common_param_pos - Irq injection param
*
* HW_TYPE : hw to inject IRQ
* HW_IDX : index of the selected hw
* RES_ID : register to set irq
* IRQ_MASK : IRQ to be triggered
* INJECT_REQ : req to trigger the IRQ
* INJECT_PARAM_MAX: max allowed num of injected param
*/
enum cam_isp_irq_inject_common_param_pos {
HW_TYPE,
HW_IDX,
REG_UNIT,
IRQ_MASK,
INJECT_REQ,
INJECT_PARAM_MAX
};
/**
* struct cam_ife_hw_mgr - IFE HW Manager
*
@@ -486,6 +519,7 @@ struct cam_isp_sfe_cache_info {
* @sfe_cache_info SFE Cache Info
* @isp_device_type: If device supports single-context(ife) or multi-
* context(mc_tfe)
* @irq_inject_param Param for isp irq injection
*/
struct cam_ife_hw_mgr {
struct cam_isp_hw_mgr mgr_common;
@@ -519,6 +553,8 @@ struct cam_ife_hw_mgr {
struct cam_isp_sys_cache_info sys_cache_info[CAM_LLCC_MAX];
struct cam_isp_sfe_cache_info sfe_cache_info[CAM_SFE_HW_NUM_MAX];
uint32_t isp_device_type;
struct cam_isp_irq_inject_param irq_inject_param[MAX_INJECT_SET];
};
/**

View File

@@ -122,6 +122,10 @@ static const struct cam_ife_csid_irq_desc cam_ife_csid_780_rx_irq_desc[][32] = {
},
};
static const uint32_t cam_ife_csid_780_num_rx_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_780_rx_irq_desc[0]),
};
static const struct cam_ife_csid_irq_desc cam_ife_csid_780_path_irq_desc[] = {
{
.bitmask = BIT(0),
@@ -283,6 +287,10 @@ static const struct cam_ife_csid_top_irq_desc cam_ife_csid_780_top_irq_desc[][32
},
};
static const uint32_t cam_ife_csid_780_num_top_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_780_top_irq_desc[0]),
};
static struct cam_irq_register_set cam_ife_csid_780_irq_reg_set[9] = {
/* Top */
{
@@ -354,8 +362,6 @@ static struct cam_irq_controller_reg_info cam_ife_csid_780_top_irq_reg_info[] =
},
};
static uint32_t cam_ife_csid_780_num_top_regs[] = {ARRAY_SIZE(cam_ife_csid_780_top_irq_reg_info),};
static struct cam_irq_controller_reg_info cam_ife_csid_780_rx_irq_reg_info[] = {
{
.num_registers = 1,
@@ -1458,7 +1464,9 @@ static struct cam_ife_csid_ver2_reg_info cam_ife_csid_780_reg_info = {
.rx_irq_desc = &cam_ife_csid_780_rx_irq_desc,
.path_irq_desc = cam_ife_csid_780_path_irq_desc,
.top_irq_desc = &cam_ife_csid_780_top_irq_desc,
.num_top_err_irqs = cam_ife_csid_780_num_top_regs,
.num_top_err_irqs = cam_ife_csid_780_num_top_irq_desc,
.num_rx_err_irqs = cam_ife_csid_780_num_rx_irq_desc,
.num_path_err_irqs = ARRAY_SIZE(cam_ife_csid_780_path_irq_desc),
.num_top_regs = 1,
.num_rx_regs = 1,
};

View File

@@ -132,6 +132,10 @@ static const struct cam_ife_csid_irq_desc cam_ife_csid_880_rx_irq_desc[][32] = {
},
};
static const uint32_t cam_ife_csid_880_num_rx_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_880_rx_irq_desc[0]),
};
static const struct cam_ife_csid_irq_desc cam_ife_csid_880_path_irq_desc[] = {
{
.bitmask = BIT(0),
@@ -1496,10 +1500,12 @@ static struct cam_ife_csid_ver2_reg_info cam_ife_csid_880_reg_info = {
},
.need_top_cfg = 0x1,
.csid_cust_node_map = {0x1, 0x0, 0x2},
.top_irq_desc = &cam_ife_csid_880_top_irq_desc,
.rx_irq_desc = &cam_ife_csid_880_rx_irq_desc,
.path_irq_desc = cam_ife_csid_880_path_irq_desc,
.top_irq_desc = &cam_ife_csid_880_top_irq_desc,
.num_top_err_irqs = cam_ife_csid_880_num_top_irq_desc,
.num_rx_err_irqs = cam_ife_csid_880_num_rx_irq_desc,
.num_path_err_irqs = ARRAY_SIZE(cam_ife_csid_880_path_irq_desc),
.num_top_regs = 1,
.num_rx_regs = 1,
};

View File

@@ -1795,11 +1795,12 @@ static struct cam_ife_csid_ver2_reg_info cam_ife_csid_980_reg_info = {
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_4] = &cam_ife_csid_980_rdi_4_reg_info,
.ipp_mc_reg = &cam_ife_csid_980_ipp_mc_reg_info,
.need_top_cfg = 0x0,
.top_irq_desc = &cam_ife_csid_980_top_irq_desc,
.rx_irq_desc = &cam_ife_csid_980_rx_irq_desc,
.path_irq_desc = cam_ife_csid_980_path_irq_desc,
.top_irq_desc = &cam_ife_csid_980_top_irq_desc,
.num_top_err_irqs = cam_ife_csid_980_num_top_irq_desc,
.num_rx_err_irqs = cam_ife_csid_980_num_rx_irq_desc,
.num_path_err_irqs = ARRAY_SIZE(cam_ife_csid_980_path_irq_desc),
.num_top_regs = 1,
.num_rx_regs = 1,
};

View File

@@ -6535,6 +6535,160 @@ end:
return 0;
}
static int cam_ife_csid_ver2_dump_irq_desc(
struct cam_ife_csid_ver2_hw *csid_hw, void *args)
{
int i, offset = 0;
struct cam_isp_irq_inject_param *inject_params = NULL;
const struct cam_ife_csid_ver2_reg_info *csid_reg = NULL;
if (!args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
inject_params = (struct cam_isp_irq_inject_param *)args;
csid_reg = (struct cam_ife_csid_ver2_reg_info *)
csid_hw->core_info->csid_reg;
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset,
"Printing executable IRQ for hw_type: CSID reg_unit: %d\n",
inject_params->reg_unit);
switch (inject_params->reg_unit) {
case CAM_ISP_CSID_TOP_REG:
for (i = 0; i < csid_reg->num_top_err_irqs[CAM_IFE_CSID_TOP_IRQ_STATUS_REG0]; i++) {
if (!(*csid_reg->top_irq_desc)
[CAM_IFE_CSID_TOP_IRQ_STATUS_REG0][i].bitmask)
break;
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset, "%#12x : %s - %s\n",
(*csid_reg->top_irq_desc)
[CAM_IFE_CSID_TOP_IRQ_STATUS_REG0][i].bitmask,
(*csid_reg->top_irq_desc)
[CAM_IFE_CSID_TOP_IRQ_STATUS_REG0][i].err_name,
(*csid_reg->top_irq_desc)
[CAM_IFE_CSID_TOP_IRQ_STATUS_REG0][i].desc);
}
break;
case CAM_ISP_CSID_RX_REG:
for (i = 0; i < csid_reg->num_rx_err_irqs[CAM_IFE_CSID_RX_IRQ_STATUS_REG0]; i++) {
if (!(*csid_reg->rx_irq_desc)
[CAM_IFE_CSID_RX_IRQ_STATUS_REG0][i].bitmask)
break;
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset, "%#12x : %s\n",
(*csid_reg->rx_irq_desc)
[CAM_IFE_CSID_RX_IRQ_STATUS_REG0][i].bitmask,
(*csid_reg->rx_irq_desc)
[CAM_IFE_CSID_RX_IRQ_STATUS_REG0][i].desc);
}
break;
case CAM_ISP_CSID_PATH_IPP_REG:
case CAM_ISP_CSID_PATH_PPP_REG:
case CAM_ISP_CSID_PATH_RDI0_REG:
case CAM_ISP_CSID_PATH_RDI1_REG:
case CAM_ISP_CSID_PATH_RDI2_REG:
case CAM_ISP_CSID_PATH_RDI3_REG:
case CAM_ISP_CSID_PATH_RDI4_REG:
for (i = 0; i < csid_reg->num_path_err_irqs; i++)
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset, "%#12x : %s\n",
csid_reg->path_irq_desc[i].bitmask,
csid_reg->path_irq_desc[i].desc);
break;
default:
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset,
"No matched reg unit for injection\n");
return -EINVAL;
}
return 0;
}
static int cam_ife_csid_ver2_irq_inject(
struct cam_ife_csid_ver2_hw *csid_hw, void *args)
{
uint32_t irq_set_addr = 0;
struct cam_hw_soc_info *soc_info;
struct cam_isp_irq_inject_param *inject_params = NULL;
const struct cam_ife_csid_ver2_reg_info *csid_reg = NULL;
void __iomem *mem_base;
if (!args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
inject_params = (struct cam_isp_irq_inject_param *)args;
csid_reg = (struct cam_ife_csid_ver2_reg_info *)
csid_hw->core_info->csid_reg;
soc_info = &csid_hw->hw_info->soc_info;
mem_base = soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base;
switch (inject_params->reg_unit) {
case CAM_ISP_CSID_TOP_REG: {
irq_set_addr =
csid_reg->cmn_reg->top_irq_set_addr[CAM_IFE_CSID_TOP_IRQ_STATUS_REG0];
break;
}
case CAM_ISP_CSID_RX_REG: {
irq_set_addr =
csid_reg->csi2_reg->irq_set_addr[CAM_IFE_CSID_RX_IRQ_STATUS_REG0];
break;
}
case CAM_ISP_CSID_PATH_IPP_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_IPP]->irq_set_addr;
break;
}
case CAM_ISP_CSID_PATH_PPP_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_PPP]->irq_set_addr;
break;
}
case CAM_ISP_CSID_PATH_RDI0_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_RDI_0]->irq_set_addr;
break;
}
case CAM_ISP_CSID_PATH_RDI1_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_RDI_1]->irq_set_addr;
break;
}
case CAM_ISP_CSID_PATH_RDI2_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_RDI_2]->irq_set_addr;
break;
}
case CAM_ISP_CSID_PATH_RDI3_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_RDI_3]->irq_set_addr;
break;
}
case CAM_ISP_CSID_PATH_RDI4_REG: {
irq_set_addr =
csid_reg->path_reg[CAM_IFE_PIX_PATH_RES_RDI_4]->irq_set_addr;
break;
}
default:
CAM_INFO(CAM_ISP, "No matched reg unit for injection");
return -EINVAL;
}
cam_io_w_mb(inject_params->irq_mask, mem_base + irq_set_addr);
cam_io_w_mb(0x10, mem_base + csid_reg->cmn_reg->irq_cmd_addr);
CAM_INFO(CAM_ISP, "Injected : irq_mask %#x set_reg_offset %#x",
inject_params->irq_mask, irq_set_addr);
return 0;
}
static int cam_ife_csid_ver2_reset_out_of_sync_cnt(
struct cam_ife_csid_ver2_hw *csid_hw, void *args)
{
@@ -6784,6 +6938,12 @@ static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
case CAM_ISP_HW_CMD_IRQ_COMP_CFG:
rc = cam_ife_csid_ver2_irq_comp_cfg(csid_hw, cmd_args, arg_size);
break;
case CAM_ISP_HW_CMD_IRQ_INJECTION:
rc = cam_ife_csid_ver2_irq_inject(csid_hw, cmd_args);
break;
case CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION:
rc = cam_ife_csid_ver2_dump_irq_desc(csid_hw, cmd_args);
break;
default:
CAM_ERR(CAM_ISP, "CSID:%u unsupported cmd:%d",
csid_hw->hw_intf->hw_idx, cmd_type);

View File

@@ -733,11 +733,12 @@ struct cam_ife_csid_ver2_reg_info {
CAM_IFE_CSID_HW_NUM_MAX];
const int input_core_sel[
CAM_IFE_CSID_HW_NUM_MAX][CAM_IFE_CSID_INPUT_CORE_SEL_MAX];
const struct cam_ife_csid_top_irq_desc (*top_irq_desc)[][32];
const struct cam_ife_csid_irq_desc (*rx_irq_desc)[][32];
const struct cam_ife_csid_irq_desc *path_irq_desc;
const struct cam_ife_csid_top_irq_desc (*top_irq_desc)[][32];
const uint32_t *num_top_err_irqs;
const uint32_t *num_rx_err_irqs;
const uint32_t num_path_err_irqs;
const uint32_t num_top_regs;
const uint32_t num_rx_regs;
};

View File

@@ -118,8 +118,6 @@ static const struct cam_ife_csid_irq_desc cam_ife_csid_lite_780_rx_irq_desc[][32
},
};
static const struct cam_ife_csid_irq_desc cam_ife_csid_lite_780_path_irq_desc[] = {
{
.bitmask = BIT(0),
@@ -284,6 +282,9 @@ static const struct cam_ife_csid_top_irq_desc cam_ife_csid_lite_780_top_irq_desc
static const uint32_t cam_ife_csid_lite_780_num_top_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_lite_780_top_irq_desc[0]),
};
static const uint32_t cam_ife_csid_lite_780_num_rx_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_lite_780_rx_irq_desc[0]),
};
static struct cam_irq_register_set cam_ife_csid_lite_780_irq_reg_set[9] = {
/* Top */
@@ -1049,10 +1050,12 @@ static struct cam_ife_csid_ver2_reg_info cam_ife_csid_lite_780_reg_info = {
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_2] = &cam_ife_csid_lite_780_rdi_2_reg_info,
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_3] = &cam_ife_csid_lite_780_rdi_3_reg_info,
.need_top_cfg = 0,
.top_irq_desc = &cam_ife_csid_lite_780_top_irq_desc,
.rx_irq_desc = &cam_ife_csid_lite_780_rx_irq_desc,
.path_irq_desc = cam_ife_csid_lite_780_path_irq_desc,
.top_irq_desc = &cam_ife_csid_lite_780_top_irq_desc,
.num_top_err_irqs = cam_ife_csid_lite_780_num_top_irq_desc,
.num_rx_err_irqs = cam_ife_csid_lite_780_num_rx_irq_desc,
.num_path_err_irqs = ARRAY_SIZE(cam_ife_csid_lite_780_path_irq_desc),
.num_top_regs = 1,
.num_rx_regs = 1,
};

View File

@@ -290,7 +290,11 @@ static const struct cam_ife_csid_top_irq_desc cam_ife_csid_lite_880_top_irq_desc
};
static const uint32_t cam_ife_csid_lite_880_num_top_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_lite_880_top_irq_desc[0])};
ARRAY_SIZE(cam_ife_csid_lite_880_top_irq_desc[0]),
};
static const uint32_t cam_ife_csid_lite_880_num_rx_irq_desc[] = {
ARRAY_SIZE(cam_ife_csid_lite_880_rx_irq_desc[0]),
};
static struct cam_irq_register_set cam_ife_csid_lite_880_irq_reg_set[9] = {
/* Top */
@@ -1055,10 +1059,12 @@ static struct cam_ife_csid_ver2_reg_info cam_ife_csid_lite_880_reg_info = {
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_2] = &cam_ife_csid_lite_880_rdi_2_reg_info,
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_3] = &cam_ife_csid_lite_880_rdi_3_reg_info,
.need_top_cfg = 0,
.top_irq_desc = &cam_ife_csid_lite_880_top_irq_desc,
.rx_irq_desc = &cam_ife_csid_lite_880_rx_irq_desc,
.path_irq_desc = cam_ife_csid_lite_880_path_irq_desc,
.top_irq_desc = &cam_ife_csid_lite_880_top_irq_desc,
.num_top_err_irqs = cam_ife_csid_lite_880_num_top_irq_desc,
.num_rx_err_irqs = cam_ife_csid_lite_880_num_rx_irq_desc,
.num_path_err_irqs = ARRAY_SIZE(cam_ife_csid_lite_880_path_irq_desc),
.num_top_regs = 1,
.num_rx_regs = 1,
};

View File

@@ -29,10 +29,12 @@ static struct cam_ife_csid_ver2_reg_info cam_ife_csid_lite_980_reg_info = {
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_2] = &cam_ife_csid_lite_880_rdi_2_reg_info,
.path_reg[CAM_IFE_PIX_PATH_RES_RDI_3] = &cam_ife_csid_lite_880_rdi_3_reg_info,
.need_top_cfg = 0,
.top_irq_desc = &cam_ife_csid_lite_880_top_irq_desc,
.rx_irq_desc = &cam_ife_csid_lite_880_rx_irq_desc,
.path_irq_desc = cam_ife_csid_lite_880_path_irq_desc,
.top_irq_desc = &cam_ife_csid_lite_880_top_irq_desc,
.num_top_err_irqs = cam_ife_csid_lite_880_num_top_irq_desc,
.num_rx_err_irqs = cam_ife_csid_lite_880_num_rx_irq_desc,
.num_path_err_irqs = ARRAY_SIZE(cam_ife_csid_lite_880_path_irq_desc),
.num_top_regs = 1,
.num_rx_regs = 1,
};

View File

@@ -28,6 +28,11 @@
*/
#define CAM_ISP_RES_NAME_LEN 16
/*
* MAX len of line_buffer
*/
#define LINE_BUFFER_LEN 1500
/* Access core_info of isp resource node */
#define cam_isp_res_core_info(res) (((struct cam_hw_info *)res->hw_intf->hw_priv)->core_info)
@@ -233,6 +238,8 @@ enum cam_isp_hw_cmd_type {
CAM_ISP_HW_CMD_CSID_DUMP_CROP_REG,
CAM_ISP_HW_CMD_MC_CTXT_SEL,
CAM_ISP_HW_CMD_IRQ_COMP_CFG,
CAM_ISP_HW_CMD_IRQ_INJECTION,
CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION,
CAM_ISP_HW_CMD_MAX,
};
@@ -580,4 +587,59 @@ struct cam_isp_hw_overflow_info {
bool is_bus_overflow;
};
enum cam_isp_irq_inject_reg_unit_type {
CAM_ISP_CSID_TOP_REG,
CAM_ISP_CSID_RX_REG,
CAM_ISP_CSID_PATH_IPP_REG,
CAM_ISP_CSID_PATH_PPP_REG,
CAM_ISP_CSID_PATH_RDI0_REG,
CAM_ISP_CSID_PATH_RDI1_REG,
CAM_ISP_CSID_PATH_RDI2_REG,
CAM_ISP_CSID_PATH_RDI3_REG,
CAM_ISP_CSID_PATH_RDI4_REG,
CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG,
CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_1_REG,
CAM_ISP_SFE_0_BUS_RD_INPUT_IF_IRQ_SET_REG,
CAM_ISP_SFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG,
CAM_ISP_REG_UNIT_MAX
};
/*
* struct cam_isp_irq_inject_param:
*
* @Brief: Params for isp irq injection
*
* @hw_type : Hw to inject IRQ
* @hw_idx : Index of the selected hw
* @reg_unit : Register to set irq
* @irq_mask : IRQ to be triggered
* @req_id : Req to trigger the IRQ
* @is_valid : Flag to indicate current set of params is valid or not
* @line_buf : Buffer to temporarily keep log
*/
struct cam_isp_irq_inject_param {
int32_t hw_type;
int32_t hw_idx;
int32_t reg_unit;
int32_t irq_mask;
uint64_t req_id;
bool is_valid;
char line_buf[LINE_BUFFER_LEN];
};
/*
* struct cam_isp_params_injection:
*
* @Brief: args for irq injection or irq desc dump
*
* @param : Params for isp irq injection
* @vfe_hw_info : Vfe hw info
* @sfe_hw_info : Sfe hw info
*/
struct cam_isp_params_injection {
struct cam_isp_irq_inject_param *param;
void *vfe_hw_info;
void *sfe_hw_info;
};
#endif /* _CAM_ISP_HW_H_ */

View File

@@ -691,6 +691,18 @@ static struct cam_irq_register_set sfe780_bus_rd_irq_reg[1] = {
},
};
static struct cam_sfe_bus_rd_err_irq_desc sfe780_bus_rd_irq_err_desc[] = {
{
.bitmask = BIT(0),
.err_name = "INFO_CONS_VIOLATION",
.desc = "Clients have illegal programming, check CONS_VIOLATION_STATUS",
},
{
.bitmask = BIT(31),
.err_name = "INFO_CCIF_VIOLATION",
},
};
static struct cam_sfe_bus_rd_constraint_error_desc
sfe780_bus_rd_cons_error_desc[CAM_SFE_BUS_RD_CONS_ERR_MAX] = {
{
@@ -820,6 +832,8 @@ static struct cam_sfe_bus_rd_hw_info sfe780_bus_rd_hw_info = {
.max_height = -1,
},
},
.num_bus_rd_errors = ARRAY_SIZE(sfe780_bus_rd_irq_err_desc),
.bus_rd_err_desc = sfe780_bus_rd_irq_err_desc,
.top_irq_shift = 0x1,
.latency_buf_allocation = 2048,
.sys_cache_default_val = 0x20,
@@ -828,6 +842,34 @@ static struct cam_sfe_bus_rd_hw_info sfe780_bus_rd_hw_info = {
.constraint_error_info = &sfe780_bus_rd_constraint_error_info,
};
static struct cam_sfe_bus_wr_err_irq_desc sfe780_bus_wr_irq_err_desc[] = {
{
.bitmask = BIT(26),
.err_name = "IPCC_FENCE_DATA_ERR",
.desc = "IPCC or FENCE Data was not available in the Input Fifo",
},
{
.bitmask = BIT(27),
.err_name = "IPCC_FENCE_ADDR_ERR",
.desc = "IPCC or FENCE address fifo was empty and read was attempted",
},
{
.bitmask = BIT(28),
.err_name = "CONS_VIOLATION",
.desc = "Programming of software registers violated the constraints",
},
{
.bitmask = BIT(30),
.err_name = "VIOLATION",
.desc = "Client has a violation in ccif protocol at input",
},
{
.bitmask = BIT(31),
.err_name = "IMAGE_SIZE_VIOLATION",
.desc = "Programmed image size is not same as image size from the CCIF",
},
};
static struct cam_sfe_bus_wr_constraint_error_desc
sfe780_bus_wr_cons_error_desc[CAM_SFE_BUS_CONS_ERR_MAX] = {
{
@@ -1674,6 +1716,8 @@ static struct cam_sfe_bus_wr_hw_info sfe780_bus_wr_hw_info = {
},
},
.constraint_error_info = &sfe780_bus_wr_constraint_error_info,
.num_bus_wr_errors = ARRAY_SIZE(sfe780_bus_wr_irq_err_desc),
.bus_wr_err_desc = sfe780_bus_wr_irq_err_desc,
.comp_done_mask = {
BIT(17), BIT(18), BIT(19), BIT(20), BIT(21), BIT(22), BIT(23),
BIT(24), BIT(25), BIT(26),

View File

@@ -728,6 +728,18 @@ static struct cam_irq_register_set sfe880_bus_rd_irq_reg[1] = {
},
};
static struct cam_sfe_bus_rd_err_irq_desc sfe880_bus_rd_irq_err_desc[] = {
{
.bitmask = BIT(0),
.err_name = "INFO_CONS_VIOLATION",
.desc = "Clients have illegal programming, check CONS_VIOLATION_STATUS",
},
{
.bitmask = BIT(31),
.err_name = "INFO_CCIF_VIOLATION",
},
};
static struct cam_sfe_bus_rd_constraint_error_desc
sfe880_bus_rd_cons_error_desc[CAM_SFE_BUS_RD_CONS_ERR_MAX] = {
{
@@ -859,6 +871,8 @@ static struct cam_sfe_bus_rd_hw_info sfe880_bus_rd_hw_info = {
.max_height = -1,
},
},
.num_bus_rd_errors = ARRAY_SIZE(sfe880_bus_rd_irq_err_desc),
.bus_rd_err_desc = sfe880_bus_rd_irq_err_desc,
.top_irq_shift = 0x1,
.latency_buf_allocation = 2048,
.sys_cache_default_val = 0x20,
@@ -867,6 +881,34 @@ static struct cam_sfe_bus_rd_hw_info sfe880_bus_rd_hw_info = {
.constraint_error_info = &sfe880_bus_rd_constraint_error_info,
};
static struct cam_sfe_bus_wr_err_irq_desc sfe880_bus_wr_irq_err_desc[] = {
{
.bitmask = BIT(26),
.err_name = "IPCC_FENCE_DATA_ERR",
.desc = "IPCC or FENCE Data was not available in the Input Fifo",
},
{
.bitmask = BIT(27),
.err_name = "IPCC_FENCE_ADDR_ERR",
.desc = "IPCC or FENCE address fifo was empty and read was attempted",
},
{
.bitmask = BIT(28),
.err_name = "CONS_VIOLATION",
.desc = "Programming of software registers violated the constraints",
},
{
.bitmask = BIT(30),
.err_name = "VIOLATION",
.desc = "Client has a violation in ccif protocol at input",
},
{
.bitmask = BIT(31),
.err_name = "IMAGE_SIZE_VIOLATION",
.desc = "Programmed image size is not same as image size from the CCIF",
},
};
static struct cam_sfe_bus_wr_constraint_error_desc
sfe880_bus_wr_cons_error_desc[CAM_SFE_BUS_CONS_ERR_MAX] = {
{
@@ -1767,6 +1809,8 @@ static struct cam_sfe_bus_wr_hw_info sfe880_bus_wr_hw_info = {
},
},
.constraint_error_info = &sfe880_bus_wr_constraint_error_info,
.num_bus_wr_errors = ARRAY_SIZE(sfe880_bus_wr_irq_err_desc),
.bus_wr_err_desc = sfe880_bus_wr_irq_err_desc,
.comp_done_mask = {
BIT(17), BIT(18), BIT(19), BIT(20), BIT(21), BIT(23),
BIT(24), BIT(25), BIT(26), BIT(27), BIT(22),

View File

@@ -377,6 +377,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
struct cam_hw_info *sfe_hw = hw_priv;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_sfe_hw_core_info *core_info = NULL;
struct cam_sfe_hw_info *hw_info = NULL;
int rc = 0;
if (!hw_priv) {
@@ -386,6 +387,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
soc_info = &sfe_hw->soc_info;
core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info;
hw_info = core_info->sfe_hw_info;
switch (cmd_type) {
case CAM_ISP_HW_CMD_GET_CHANGE_BASE:
@@ -435,6 +437,8 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
fallthrough;
case CAM_ISP_HW_CMD_GET_RES_FOR_MID:
case CAM_ISP_HW_CMD_DUMP_BUS_INFO:
case CAM_ISP_HW_CMD_IRQ_INJECTION:
case CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION:
/* propagate to SFE bus wr */
core_info->sfe_bus_wr->hw_ops.process_cmd(
core_info->sfe_bus_wr->bus_priv, cmd_type,

View File

@@ -60,6 +60,7 @@ struct cam_sfe_bus_rd_common_data {
void __iomem *mem_base;
struct cam_hw_intf *hw_intf;
struct cam_sfe_bus_rd_reg_offset_common *common_reg;
struct cam_hw_soc_info *soc_info;
uint32_t io_buf_update[
MAX_REG_VAL_PAIR_SIZE];
void *bus_irq_controller;
@@ -1796,6 +1797,80 @@ end:
return 0;
}
static int cam_sfe_bus_rd_irq_inject(
void *priv, void *cmd_args, uint32_t arg_size)
{
struct cam_sfe_bus_rd_priv *bus_priv = NULL;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_sfe_bus_rd_hw_info *bus_rd_hw_info = NULL;
struct cam_irq_controller_reg_info *irq_reg_info = NULL;
struct cam_irq_register_set *inject_reg = NULL;
struct cam_isp_irq_inject_param *inject_params = NULL;
if (!cmd_args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
bus_priv = (struct cam_sfe_bus_rd_priv *)priv;
soc_info = bus_priv->common_data.soc_info;
bus_rd_hw_info = (struct cam_sfe_bus_rd_hw_info *)bus_priv->bus_rd_hw_info;
irq_reg_info = &bus_rd_hw_info->common_reg.irq_reg_info;
inject_reg = irq_reg_info->irq_reg_set;
inject_params = (struct cam_isp_irq_inject_param *)cmd_args;
if (!inject_reg) {
CAM_INFO(CAM_SFE, "Invalid inject_reg");
return -EINVAL;
}
if (inject_params->reg_unit ==
CAM_ISP_SFE_0_BUS_RD_INPUT_IF_IRQ_SET_REG) {
cam_io_w_mb(inject_params->irq_mask,
soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base +
inject_reg->set_reg_offset);
cam_io_w_mb(0x10, soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base +
irq_reg_info->global_irq_cmd_offset);
CAM_INFO(CAM_SFE, "Injected : irq_mask %#x set_reg_offset %#x",
inject_params->irq_mask, inject_reg->set_reg_offset);
}
return 0;
}
static int cam_sfe_bus_rd_dump_irq_desc(
void *priv, void *cmd_args, uint32_t arg_size)
{
int i, offset = 0;
struct cam_sfe_bus_rd_priv *bus_priv = NULL;
struct cam_sfe_bus_rd_hw_info *bus_rd_hw_info = NULL;
struct cam_isp_irq_inject_param *inject_params = NULL;
if (!cmd_args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
bus_priv = (struct cam_sfe_bus_rd_priv *)priv;
bus_rd_hw_info = (struct cam_sfe_bus_rd_hw_info *)bus_priv->bus_rd_hw_info;
inject_params = (struct cam_isp_irq_inject_param *)cmd_args;
if (inject_params->reg_unit ==
CAM_ISP_SFE_0_BUS_RD_INPUT_IF_IRQ_SET_REG) {
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset,
"Printing executable IRQ for hw_type: SFE reg_unit: %d\n",
inject_params->reg_unit);
for (i = 0; i < bus_rd_hw_info->num_bus_rd_errors; i++)
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset, "%#12x : %s - %s\n",
bus_rd_hw_info->bus_rd_err_desc[i].bitmask,
bus_rd_hw_info->bus_rd_err_desc[i].err_name,
bus_rd_hw_info->bus_rd_err_desc[i].desc);
}
return 0;
}
static int cam_sfe_bus_init_hw(void *hw_priv,
void *init_hw_args, uint32_t arg_size)
{
@@ -1974,6 +2049,12 @@ static int cam_sfe_bus_rd_process_cmd(
(struct cam_sfe_bus_rd_priv *)priv);
break;
}
case CAM_ISP_HW_CMD_IRQ_INJECTION:
rc = cam_sfe_bus_rd_irq_inject(priv, cmd_args, arg_size);
break;
case CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION:
rc = cam_sfe_bus_rd_dump_irq_desc(priv, cmd_args, arg_size);
break;
default:
CAM_ERR_RATE_LIMIT(CAM_SFE,
"Invalid SFE BUS RD command type: %d",
@@ -2032,6 +2113,7 @@ int cam_sfe_bus_rd_init(
bus_priv->common_data.irq_err_mask = bus_rd_hw_info->irq_err_mask;
bus_priv->common_data.cons_chk_en_avail =
bus_rd_hw_info->constraint_error_info->cons_chk_en_avail;
bus_priv->common_data.soc_info = soc_info;
bus_priv->top_irq_shift = bus_rd_hw_info->top_irq_shift;
bus_priv->latency_buf_allocation = bus_rd_hw_info->latency_buf_allocation;
bus_priv->sys_cache_default_cfg = bus_rd_hw_info->sys_cache_default_val;

View File

@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_SFE_BUS_RD_H_
@@ -31,6 +31,17 @@ enum cam_sfe_bus_rd_type {
CAM_SFE_BUS_RD_MAX,
};
/*
* struct cam_sfe_bus_rd_err_irq_desc:
*
* @Brief: Bus rd error irq description
*/
struct cam_sfe_bus_rd_err_irq_desc {
uint32_t bitmask;
char *err_name;
char *desc;
};
/*
* struct cam_sfe_bus_rd_constraint_error_desc:
*
@@ -133,6 +144,8 @@ struct cam_sfe_bus_rd_hw_info {
uint32_t num_bus_rd_resc;
struct cam_sfe_bus_rd_info
sfe_bus_rd_info[CAM_SFE_BUS_RD_MAX];
uint32_t num_bus_rd_errors;
struct cam_sfe_bus_rd_err_irq_desc *bus_rd_err_desc;
uint32_t top_irq_shift;
uint32_t latency_buf_allocation;
uint32_t sys_cache_default_val;

View File

@@ -94,6 +94,7 @@ struct cam_sfe_bus_wr_common_data {
uint32_t sys_cache_default_cfg;
uint32_t sfe_debug_cfg;
struct cam_sfe_bus_cache_dbg_cfg cache_dbg_cfg;
struct cam_hw_soc_info *soc_info;
};
struct cam_sfe_wr_scratch_buf_info {
@@ -195,7 +196,8 @@ struct cam_sfe_bus_wr_priv {
int error_irq_handle;
void *tasklet_info;
struct cam_sfe_bus_wr_constraint_error_info *constraint_error_info;
struct cam_sfe_bus_sfe_out_hw_info *sfe_out_hw_info;
struct cam_sfe_bus_sfe_out_hw_info *sfe_out_hw_info;
struct cam_sfe_bus_wr_hw_info *bus_wr_hw_info;
};
static int cam_sfe_bus_subscribe_error_irq(
@@ -3166,6 +3168,76 @@ end:
return 0;
}
static int cam_sfe_bus_wr_irq_inject(
void *priv, void *cmd_args, uint32_t arg_size)
{
struct cam_sfe_bus_wr_priv *bus_priv = NULL;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_sfe_bus_wr_hw_info *bus_wr_hw_info = NULL;
struct cam_irq_controller_reg_info *irq_reg_info = NULL;
struct cam_irq_register_set *inject_reg = NULL;
struct cam_isp_irq_inject_param *inject_params = NULL;
bus_priv = (struct cam_sfe_bus_wr_priv *)priv;
soc_info = bus_priv->common_data.soc_info;
bus_wr_hw_info = (struct cam_sfe_bus_wr_hw_info *)bus_priv->bus_wr_hw_info;
irq_reg_info = &bus_wr_hw_info->common_reg.irq_reg_info;
inject_reg = irq_reg_info->irq_reg_set;
inject_params = (struct cam_isp_irq_inject_param *)cmd_args;
if (!inject_params || !inject_reg) {
CAM_INFO(CAM_SFE, "Invalid inject_params or inject_reg");
return -EINVAL;
}
if (inject_params->reg_unit ==
CAM_ISP_SFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG) {
cam_io_w_mb(inject_params->irq_mask,
soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base +
inject_reg->set_reg_offset);
cam_io_w_mb(0x10, soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base +
irq_reg_info->global_irq_cmd_offset);
CAM_INFO(CAM_SFE, "Injected : irq_mask %#x set_reg_offset %#x",
inject_params->irq_mask, inject_reg->set_reg_offset);
}
return 0;
}
static int cam_sfe_bus_wr_dump_irq_desc(
void *priv, void *cmd_args, uint32_t arg_size)
{
int i, offset = 0;
struct cam_sfe_bus_wr_priv *bus_priv = NULL;
struct cam_sfe_bus_wr_hw_info *bus_wr_hw_info = NULL;
struct cam_isp_irq_inject_param *inject_params = NULL;
if (!cmd_args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
bus_priv = (struct cam_sfe_bus_wr_priv *)priv;
bus_wr_hw_info = (struct cam_sfe_bus_wr_hw_info *)bus_priv->bus_wr_hw_info;
inject_params = (struct cam_isp_irq_inject_param *)cmd_args;
if (inject_params->reg_unit ==
CAM_ISP_SFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG) {
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset,
"Printing executable IRQ for hw_type: SFE reg_unit: %d\n",
inject_params->reg_unit);
for (i = 0; i < bus_wr_hw_info->num_bus_wr_errors; i++)
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset, "%#12x : %s - %s\n",
bus_wr_hw_info->bus_wr_err_desc[i].bitmask,
bus_wr_hw_info->bus_wr_err_desc[i].err_name,
bus_wr_hw_info->bus_wr_err_desc[i].desc);
}
return 0;
}
static int cam_sfe_bus_wr_start_hw(void *hw_priv,
void *start_hw_args, uint32_t arg_size)
{
@@ -3353,6 +3425,12 @@ static int cam_sfe_bus_wr_process_cmd(
case CAM_ISP_HW_CMD_GET_RES_FOR_MID:
rc = cam_sfe_bus_wr_get_res_for_mid(priv, cmd_args, arg_size);
break;
case CAM_ISP_HW_CMD_IRQ_INJECTION:
rc = cam_sfe_bus_wr_irq_inject(priv, cmd_args, arg_size);
break;
case CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION:
rc = cam_sfe_bus_wr_dump_irq_desc(priv, cmd_args, arg_size);
break;
default:
CAM_ERR_RATE_LIMIT(CAM_SFE, "Invalid HW command type:%d",
cmd_type);
@@ -3400,27 +3478,29 @@ int cam_sfe_bus_wr_init(
}
sfe_bus_local->bus_priv = bus_priv;
bus_priv->num_client = hw_info->num_client;
bus_priv->num_out = hw_info->num_out;
bus_priv->max_out_res = hw_info->max_out_res;
bus_priv->num_comp_grp = hw_info->num_comp_grp;
bus_priv->top_irq_shift = hw_info->top_irq_shift;
bus_priv->common_data.num_sec_out = 0;
bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE;
bus_priv->common_data.core_index = soc_info->index;
bus_priv->common_data.mem_base =
bus_priv->num_client = hw_info->num_client;
bus_priv->num_out = hw_info->num_out;
bus_priv->max_out_res = hw_info->max_out_res;
bus_priv->num_comp_grp = hw_info->num_comp_grp;
bus_priv->top_irq_shift = hw_info->top_irq_shift;
bus_priv->common_data.num_sec_out = 0;
bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE;
bus_priv->common_data.core_index = soc_info->index;
bus_priv->common_data.mem_base =
CAM_SOC_GET_REG_MAP_START(soc_info, SFE_CORE_BASE_IDX);
bus_priv->common_data.hw_intf = hw_intf;
bus_priv->common_data.common_reg = &hw_info->common_reg;
bus_priv->common_data.line_done_cfg = hw_info->line_done_cfg;
bus_priv->common_data.pack_align_shift = hw_info->pack_align_shift;
bus_priv->common_data.max_bw_counter_limit = hw_info->max_bw_counter_limit;
bus_priv->common_data.err_irq_subscribe = false;
bus_priv->common_data.sfe_irq_controller = sfe_irq_controller;
bus_priv->common_data.irq_err_mask = hw_info->irq_err_mask;
bus_priv->common_data.hw_intf = hw_intf;
bus_priv->common_data.common_reg = &hw_info->common_reg;
bus_priv->common_data.line_done_cfg = hw_info->line_done_cfg;
bus_priv->common_data.pack_align_shift = hw_info->pack_align_shift;
bus_priv->common_data.max_bw_counter_limit = hw_info->max_bw_counter_limit;
bus_priv->common_data.err_irq_subscribe = false;
bus_priv->common_data.sfe_irq_controller = sfe_irq_controller;
bus_priv->common_data.irq_err_mask = hw_info->irq_err_mask;
bus_priv->common_data.sys_cache_default_cfg = hw_info->sys_cache_default_val;
bus_priv->constraint_error_info = hw_info->constraint_error_info;
bus_priv->sfe_out_hw_info = hw_info->sfe_out_hw_info;
bus_priv->common_data.soc_info = soc_info;
bus_priv->constraint_error_info = hw_info->constraint_error_info;
bus_priv->sfe_out_hw_info = hw_info->sfe_out_hw_info;
bus_priv->bus_wr_hw_info = hw_info;
rc = cam_cpas_get_cpas_hw_version(&bus_priv->common_data.hw_version);
if (rc) {
CAM_ERR(CAM_SFE, "Failed to get hw_version rc:%d", rc);

View File

@@ -65,6 +65,17 @@ enum cam_sfe_bus_sfe_out_type {
CAM_SFE_BUS_SFE_OUT_MAX,
};
/*
* struct cam_sfe_bus_wr_err_irq_desc:
*
* @Brief: Bus wr error irq description
*/
struct cam_sfe_bus_wr_err_irq_desc {
uint32_t bitmask;
char *err_name;
char *desc;
};
/*
* struct cam_sfe_constraint_error_desc:
*
@@ -198,6 +209,8 @@ struct cam_sfe_bus_wr_hw_info {
sfe_out_hw_info[CAM_SFE_BUS_SFE_OUT_MAX];
struct cam_sfe_bus_wr_constraint_error_info
*constraint_error_info;
uint32_t num_bus_wr_errors;
struct cam_sfe_bus_wr_err_irq_desc *bus_wr_err_desc;
uint32_t comp_done_mask[CAM_SFE_BUS_WR_COMP_GRP_MAX];
uint32_t num_comp_grp;
uint32_t line_done_cfg;

View File

@@ -486,6 +486,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
struct cam_hw_info *vfe_hw = hw_priv;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_vfe_hw_core_info *core_info = NULL;
struct cam_vfe_hw_info *hw_info = NULL;
int rc = 0;
if (!hw_priv) {
@@ -495,6 +496,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
soc_info = &vfe_hw->soc_info;
core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
hw_info = core_info->vfe_hw_info;
switch (cmd_type) {
case CAM_ISP_HW_CMD_GET_CHANGE_BASE:
@@ -535,6 +537,8 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
case CAM_ISP_HW_CMD_BUF_UPDATE:
case CAM_ISP_HW_USER_DUMP:
case CAM_ISP_HW_CMD_MC_CTXT_SEL:
case CAM_ISP_HW_CMD_IRQ_INJECTION:
case CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION:
rc = core_info->vfe_bus->hw_ops.process_cmd(
core_info->vfe_bus->bus_priv, cmd_type, cmd_args,
arg_size);

View File

@@ -963,6 +963,47 @@ static uint32_t vfe780_out_port_mid[][4] = {
{22, 0, 0, 0},
};
static struct cam_vfe_bus_ver3_err_irq_desc vfe780_bus_irq_err_desc_0[] = {
{
.bitmask = BIT(26),
.err_name = "IPCC_FENCE_DATA_ERR",
.desc = "IPCC or FENCE Data was not available in the Input Fifo",
},
{
.bitmask = BIT(27),
.err_name = "IPCC_FENCE_ADDR_ERR",
.desc = "IPCC or FENCE address fifo was empty and read was attempted",
},
{
.bitmask = BIT(28),
.err_name = "CONS_VIOLATION",
.desc = "Programming of software registers violated the constraints",
},
{
.bitmask = BIT(30),
.err_name = "VIOLATION",
.desc = "Client has a violation in ccif protocol at input",
},
{
.bitmask = BIT(31),
.err_name = "IMAGE_SIZE_VIOLATION",
.desc = "Programmed image size is not same as image size from the CCIF",
},
};
static struct cam_vfe_bus_ver3_err_irq_desc vfe780_bus_irq_err_desc_1[] = {
{
.bitmask = BIT(28),
.err_name = "EARLY_DONE",
.desc = "Buf done for each client. Early done irq for clients STATS_BAF",
},
{
.bitmask = BIT(29),
.err_name = "EARLY_DONE",
.desc = "Buf done for each client. Early done irq for clients STATS_BAF",
},
};
static struct cam_vfe_bus_ver3_hw_info vfe780_bus_hw_info = {
.common_reg = {
.hw_version = 0x00000C00,
@@ -2312,6 +2353,10 @@ static struct cam_vfe_bus_ver3_hw_info vfe780_bus_hw_info = {
.error_description = "Meta Stride unalign"
},
},
.num_bus_errors_0 = ARRAY_SIZE(vfe780_bus_irq_err_desc_0),
.num_bus_errors_1 = ARRAY_SIZE(vfe780_bus_irq_err_desc_1),
.bus_err_desc_0 = vfe780_bus_irq_err_desc_0,
.bus_err_desc_1 = vfe780_bus_irq_err_desc_1,
.num_comp_grp = 15,
.support_consumed_addr = true,
.comp_done_mask = {

View File

@@ -1008,6 +1008,47 @@ static uint32_t vfe880_out_port_mid[][4] = {
{30, 0, 0, 0},
};
static struct cam_vfe_bus_ver3_err_irq_desc vfe880_bus_irq_err_desc_0[] = {
{
.bitmask = BIT(26),
.err_name = "IPCC_FENCE_DATA_ERR",
.desc = "IPCC or FENCE Data was not available in the Input Fifo",
},
{
.bitmask = BIT(27),
.err_name = "IPCC_FENCE_ADDR_ERR",
.desc = "IPCC or FENCE address fifo was empty and read was attempted",
},
{
.bitmask = BIT(28),
.err_name = "CONS_VIOLATION",
.desc = "Programming of software registers violated the constraints",
},
{
.bitmask = BIT(30),
.err_name = "VIOLATION",
.desc = "Client has a violation in ccif protocol at input",
},
{
.bitmask = BIT(31),
.err_name = "IMAGE_SIZE_VIOLATION",
.desc = "Programmed image size is not same as image size from the CCIF",
},
};
static struct cam_vfe_bus_ver3_err_irq_desc vfe880_bus_irq_err_desc_1[] = {
{
.bitmask = BIT(28),
.err_name = "EARLY_DONE",
.desc = "Buf done for each client. Early done irq for clients STATS_BAF",
},
{
.bitmask = BIT(29),
.err_name = "EARLY_DONE",
.desc = "Buf done for each client. Early done irq for clients STATS_BAF",
},
};
static struct cam_vfe_bus_ver3_hw_info vfe880_bus_hw_info = {
.common_reg = {
.hw_version = 0x00000C00,
@@ -2404,6 +2445,10 @@ static struct cam_vfe_bus_ver3_hw_info vfe880_bus_hw_info = {
.error_description = "Meta Stride unalign"
},
},
.num_bus_errors_0 = ARRAY_SIZE(vfe880_bus_irq_err_desc_0),
.num_bus_errors_1 = ARRAY_SIZE(vfe880_bus_irq_err_desc_1),
.bus_err_desc_0 = vfe880_bus_irq_err_desc_0,
.bus_err_desc_1 = vfe880_bus_irq_err_desc_1,
.num_comp_grp = 16,
.support_consumed_addr = true,
.comp_done_mask = {

View File

@@ -88,6 +88,7 @@ struct cam_vfe_bus_ver3_common_data {
void *vfe_irq_controller;
void *buf_done_controller;
void *priv;
struct cam_hw_soc_info *soc_info;
struct cam_vfe_bus_ver3_reg_offset_common *common_reg;
struct cam_cdm_utils_ops *cdm_util_ops;
uint32_t io_buf_update[
@@ -209,24 +210,25 @@ struct cam_vfe_bus_ver3_vfe_out_data {
};
struct cam_vfe_bus_ver3_priv {
struct cam_vfe_bus_ver3_common_data common_data;
uint32_t num_client;
uint32_t num_out;
uint32_t num_comp_grp;
uint32_t top_irq_shift;
struct cam_vfe_bus_ver3_common_data common_data;
uint32_t num_client;
uint32_t num_out;
uint32_t num_comp_grp;
uint32_t top_irq_shift;
struct cam_isp_resource_node *bus_client;
struct cam_isp_resource_node *comp_grp;
struct cam_isp_resource_node *vfe_out;
struct cam_isp_resource_node *bus_client;
struct cam_isp_resource_node *comp_grp;
struct cam_isp_resource_node *vfe_out;
uint32_t vfe_out_map_outtype[CAM_VFE_BUS_VER3_VFE_OUT_MAX];
int bus_irq_handle;
int rup_irq_handle;
int error_irq_handle;
void *tasklet_info;
uint32_t max_out_res;
uint32_t num_cons_err;
struct cam_vfe_constraint_error_info *constraint_error_list;
int bus_irq_handle;
int rup_irq_handle;
int error_irq_handle;
void *tasklet_info;
uint32_t max_out_res;
uint32_t num_cons_err;
struct cam_vfe_constraint_error_info *constraint_error_list;
struct cam_vfe_bus_ver3_hw_info *bus_hw_info;
};
static void cam_vfe_bus_ver3_unsubscribe_init_irq(
@@ -4179,6 +4181,95 @@ static int cam_vfe_bus_ver3_mc_ctxt_sel(
return 0;
}
static int cam_vfe_bus_ver3_irq_inject(
void *priv, void *cmd_args, uint32_t arg_size)
{
struct cam_vfe_bus_ver3_priv *bus_priv = NULL;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_vfe_bus_ver3_hw_info *bus_hw_info = NULL;
struct cam_isp_irq_inject_param *inject_params = NULL;
struct cam_irq_register_set *inject_reg = NULL;
if (!cmd_args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
bus_priv = (struct cam_vfe_bus_ver3_priv *)priv;
soc_info = bus_priv->common_data.soc_info;
bus_hw_info = (struct cam_vfe_bus_ver3_hw_info *)bus_priv->bus_hw_info;
inject_params = (struct cam_isp_irq_inject_param *)cmd_args;
if (inject_params->reg_unit ==
CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG)
inject_reg = &bus_hw_info->common_reg.irq_reg_info.irq_reg_set[0];
else if (inject_params->reg_unit ==
CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_1_REG)
inject_reg = &bus_hw_info->common_reg.irq_reg_info.irq_reg_set[1];
else
return -EINVAL;
if (!inject_reg) {
CAM_INFO(CAM_ISP, "Invalid inject_reg");
return -EINVAL;
}
cam_io_w_mb(inject_params->irq_mask,
soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base +
inject_reg->set_reg_offset);
cam_io_w_mb(0x10, soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base +
bus_hw_info->common_reg.irq_reg_info.global_irq_cmd_offset);
CAM_INFO(CAM_ISP, "Injected : irq_mask %#x set_reg_offset %#x",
inject_params->irq_mask, inject_reg->set_reg_offset);
return 0;
}
static int cam_vfe_bus_ver3_dump_irq_desc(
void *priv, void *cmd_args, uint32_t arg_size)
{
int i, offset = 0;
int num_irq_desc = 0;
struct cam_vfe_bus_ver3_priv *bus_priv = NULL;
struct cam_vfe_bus_ver3_hw_info *bus_hw_info = NULL;
struct cam_isp_irq_inject_param *inject_params = NULL;
struct cam_vfe_bus_ver3_err_irq_desc *err_irq_desc = NULL;
if (!cmd_args) {
CAM_ERR(CAM_ISP, "Invalid params");
return -EINVAL;
}
bus_priv = (struct cam_vfe_bus_ver3_priv *)priv;
bus_hw_info = (struct cam_vfe_bus_ver3_hw_info *)bus_priv->bus_hw_info;
inject_params = (struct cam_isp_irq_inject_param *)cmd_args;
if (inject_params->reg_unit ==
CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_0_REG) {
err_irq_desc = bus_hw_info->bus_err_desc_0;
num_irq_desc = bus_hw_info->num_bus_errors_0;
} else if (inject_params->reg_unit ==
CAM_ISP_IFE_0_BUS_WR_INPUT_IF_IRQ_SET_1_REG) {
err_irq_desc = bus_hw_info->bus_err_desc_1;
num_irq_desc = bus_hw_info->num_bus_errors_1;
} else
return -EINVAL;
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset,
"Printing executable IRQ for hw_type: VFE reg_unit: %d\n",
inject_params->reg_unit);
for (i = 0; i < num_irq_desc; i++)
offset += scnprintf(inject_params->line_buf + offset,
LINE_BUFFER_LEN - offset, "%#12x : %s - %s\n",
err_irq_desc[i].bitmask,
err_irq_desc[i].err_name,
err_irq_desc[i].desc);
return 0;
}
static int cam_vfe_bus_ver3_start_hw(void *hw_priv,
void *start_hw_args, uint32_t arg_size)
{
@@ -4412,6 +4503,12 @@ static int cam_vfe_bus_ver3_process_cmd(
rc = cam_vfe_bus_ver3_mc_ctxt_sel(priv, cmd_args, arg_size);
break;
case CAM_ISP_HW_CMD_IRQ_INJECTION:
rc = cam_vfe_bus_ver3_irq_inject(priv, cmd_args, arg_size);
break;
case CAM_ISP_HW_CMD_DUMP_IRQ_DESCRIPTION:
rc = cam_vfe_bus_ver3_dump_irq_desc(priv, cmd_args, arg_size);
break;
default:
CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%u Invalid camif process command:%d",
priv->hw_intf->hw_idx, cmd_type);
@@ -4498,6 +4595,8 @@ int cam_vfe_bus_ver3_init(
ver3_hw_info->max_bw_counter_limit;
bus_priv->num_cons_err = ver3_hw_info->num_cons_err;
bus_priv->constraint_error_list = ver3_hw_info->constraint_error_list;
bus_priv->common_data.soc_info = soc_info;
bus_priv->bus_hw_info = ver3_hw_info;
if (bus_priv->num_out >= CAM_VFE_BUS_VER3_VFE_OUT_MAX) {
CAM_ERR(CAM_ISP, "VFE:%u number of vfe out:%d more than max value:%d ",

View File

@@ -99,6 +99,17 @@ enum cam_vfe_bus_ver3_vfe_out_type {
CAM_VFE_BUS_VER3_VFE_OUT_MAX,
};
/*
* struct cam_vfe_bus_ver3_err_irq_desc:
*
* @Brief: Bus error irq description
*/
struct cam_vfe_bus_ver3_err_irq_desc {
uint32_t bitmask;
char *err_name;
char *desc;
};
/*
* struct cam_vfe_constraint_error_info:
*
@@ -249,6 +260,10 @@ struct cam_vfe_bus_ver3_hw_info {
uint32_t num_cons_err;
struct cam_vfe_constraint_error_info
constraint_error_list[CAM_VFE_BUS_VER3_CONS_ERR_MAX];
uint32_t num_bus_errors_0;
uint32_t num_bus_errors_1;
struct cam_vfe_bus_ver3_err_irq_desc *bus_err_desc_0;
struct cam_vfe_bus_ver3_err_irq_desc *bus_err_desc_1;
uint32_t num_comp_grp;
uint32_t comp_done_mask[CAM_VFE_BUS_VER3_COMP_GRP_MAX];
uint32_t top_irq_shift;