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