diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 034e80e99169..1e772dedc24f 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1818,8 +1818,14 @@ end: if (notify.error == CRM_KMD_ERR_FATAL) { req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; - req_msg.u.err_msg.error_type = - CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + + if (error_type == CAM_ISP_HW_ERROR_CSID_FATAL) + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY; + else + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.err_msg.request_id = error_request_id; req_msg.u.err_msg.resource_size = 0x0; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 6b0ac2797417..c822b22a7918 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1918,6 +1918,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_acquire.in_port = in_port; csid_acquire.out_port = in_port->data; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_ife_hw_mgr_event_handler; + csid_acquire.priv = ife_ctx; csid_acquire.crop_enable = crop_enable; csid_acquire.drop_enable = false; @@ -2046,6 +2048,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_ife_hw_mgr_event_handler; + csid_acquire.priv = ife_ctx; /* * Enable RDI pixel drop by default. CSID will enable only for @@ -6363,6 +6367,12 @@ static int cam_ife_hw_mgr_find_affected_ctx( affected_core, CAM_IFE_HW_NUM_MAX)) continue; + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) { + CAM_INFO(CAM_ISP, "CTX:%d already error reported", + ife_hwr_mgr_ctx->ctx_index); + continue; + } + atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1); notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type]; @@ -6378,8 +6388,13 @@ static int cam_ife_hw_mgr_find_affected_ctx( * In the call back function corresponding ISP context * will update CRM about fatal Error */ - notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, - CAM_ISP_HW_EVENT_ERROR, error_event_data); + if (notify_err_cb) { + notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_ERROR, error_event_data); + } else { + CAM_WARN(CAM_ISP, "Error call back is not set"); + goto end; + } } /* fill the affected_core in recovery data */ @@ -6388,7 +6403,34 @@ static int cam_ife_hw_mgr_find_affected_ctx( CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)", i, recovery_data->affected_core[i]); } +end: + return 0; +} +static int cam_ife_hw_mgr_handle_csid_event( + struct cam_isp_hw_event_info *event_info) +{ + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_ife_hw_event_recovery_data recovery_data = {0}; + + /* this can be extended based on the types of error + * received from CSID + */ + switch (event_info->err_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: { + + if (!g_ife_hw_mgr.debug_cfg.enable_csid_recovery) + break; + + error_event_data.error_type = event_info->err_type; + cam_ife_hw_mgr_find_affected_ctx(&error_event_data, + event_info->hw_idx, + &recovery_data); + break; + } + default: + break; + } return 0; } @@ -6408,6 +6450,13 @@ static int cam_ife_hw_mgr_handle_hw_err( else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + spin_lock(&g_ife_hw_mgr.ctx_lock); + if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) { + rc = cam_ife_hw_mgr_handle_csid_event(event_info); + spin_unlock(&g_ife_hw_mgr.ctx_lock); + return rc; + } + core_idx = event_info->hw_idx; if (g_ife_hw_mgr.debug_cfg.enable_recovery) @@ -6418,6 +6467,8 @@ static int cam_ife_hw_mgr_handle_hw_err( rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); + if (rc || !(recovery_data.no_of_context)) + goto end; if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; @@ -6425,7 +6476,8 @@ static int cam_ife_hw_mgr_handle_hw_err( recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; cam_ife_hw_mgr_do_error_recovery(&recovery_data); - +end: + spin_unlock(&g_ife_hw_mgr.ctx_lock); return rc; } @@ -6875,6 +6927,14 @@ static int cam_ife_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_u32("enable_csid_recovery", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_csid_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery"); + goto err; + } + if (!debugfs_create_bool("enable_req_dump", 0644, g_ife_hw_mgr.debug_cfg.dentry, @@ -6921,6 +6981,7 @@ 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)); mutex_init(&g_ife_hw_mgr.ctx_mutex); + spin_lock_init(&g_ife_hw_mgr.ctx_lock); if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "CSID num is different then IFE num"); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 18183cb76bb1..63ac13323a41 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -24,6 +24,7 @@ * @dentry: Debugfs entry * @csid_debug: csid debug information * @enable_recovery: enable recovery + * @enable_csid_recovery: enable csid recovery * @enable_diag_sensor_status: enable sensor diagnosis status * @enable_req_dump: Enable request dump on HW errors * @per_req_reg_dump: Enable per request reg dump @@ -33,6 +34,7 @@ struct cam_ife_hw_mgr_debug { struct dentry *dentry; uint64_t csid_debug; uint32_t enable_recovery; + uint32_t enable_csid_recovery; uint32_t camif_debug; bool enable_req_dump; bool per_req_reg_dump; @@ -148,6 +150,7 @@ struct cam_ife_hw_mgr_ctx { * @ife_dev_caps ife device capability per core * @work q work queue for IFE hw manager * @debug_cfg debug configuration + * @ctx_lock Spinlock for HW manager */ struct cam_ife_hw_mgr { struct cam_isp_hw_mgr mgr_common; @@ -166,6 +169,7 @@ struct cam_ife_hw_mgr { struct cam_vfe_hw_get_hw_cap ife_dev_caps[CAM_IFE_HW_NUM_MAX]; struct cam_req_mgr_core_workq *workq; struct cam_ife_hw_mgr_debug debug_cfg; + spinlock_t ctx_lock; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c index dcdfeff17458..db9a93ced4e5 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c @@ -1458,6 +1458,8 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi( csid_acquire.out_port = out_port; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + csid_acquire.event_cb_prv = tfe_ctx; if (tfe_ctx->is_tpg) { if (tfe_ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx == @@ -4904,6 +4906,12 @@ static int cam_tfe_hw_mgr_find_affected_ctx( affected_core, CAM_TFE_HW_NUM_MAX)) continue; + if (atomic_read(&tfe_hwr_mgr_ctx->overflow_pending)) { + CAM_INFO(CAM_ISP, "CTX:%d already error reported", + tfe_hwr_mgr_ctx->ctx_index); + continue; + } + atomic_set(&tfe_hwr_mgr_ctx->overflow_pending, 1); notify_err_cb = tfe_hwr_mgr_ctx->common.event_cb[event_type]; @@ -4919,8 +4927,13 @@ static int cam_tfe_hw_mgr_find_affected_ctx( * In the call back function corresponding ISP context * will update CRM about fatal Error */ - notify_err_cb(tfe_hwr_mgr_ctx->common.cb_priv, + if (notify_err_cb) { + notify_err_cb(tfe_hwr_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_ERROR, error_event_data); + } else { + CAM_WARN(CAM_ISP, "Error call back is not set"); + goto end; + } } /* fill the affected_core in recovery data */ @@ -4929,7 +4942,34 @@ static int cam_tfe_hw_mgr_find_affected_ctx( CAM_DBG(CAM_ISP, "tfe core %d is affected (%d)", i, recovery_data->affected_core[i]); } +end: + return 0; +} +static int cam_tfe_hw_mgr_handle_csid_event( + struct cam_isp_hw_event_info *event_info) +{ + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_tfe_hw_event_recovery_data recovery_data = {0}; + + /* this can be extended based on the types of error + * received from CSID + */ + switch (event_info->err_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: { + + if (!g_tfe_hw_mgr.debug_cfg.enable_csid_recovery) + break; + + error_event_data.error_type = event_info->err_type; + cam_tfe_hw_mgr_find_affected_ctx(&error_event_data, + event_info->hw_idx, + &recovery_data); + break; + } + default: + break; + } return 0; } @@ -4950,6 +4990,13 @@ static int cam_tfe_hw_mgr_handle_hw_err( else if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + spin_lock(&g_tfe_hw_mgr.ctx_lock); + if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) { + rc = cam_tfe_hw_mgr_handle_csid_event(event_info); + spin_unlock(&g_tfe_hw_mgr.ctx_lock); + return rc; + } + core_idx = event_info->hw_idx; if (g_tfe_hw_mgr.debug_cfg.enable_recovery) @@ -4959,9 +5006,13 @@ static int cam_tfe_hw_mgr_handle_hw_err( rc = cam_tfe_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); + if (rc || !(recovery_data.no_of_context)) + goto end; - if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) + if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) { + spin_unlock(&g_tfe_hw_mgr.ctx_lock); return rc; + } if (g_tfe_hw_mgr.debug_cfg.enable_recovery) { /* Trigger for recovery */ @@ -4974,7 +5025,8 @@ static int cam_tfe_hw_mgr_handle_hw_err( CAM_DBG(CAM_ISP, "recovery is not enabled"); rc = 0; } - +end: + spin_unlock(&g_tfe_hw_mgr.ctx_lock); return rc; } @@ -5422,6 +5474,14 @@ static int cam_tfe_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_u32("enable_csid_recovery", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, + &g_tfe_hw_mgr.debug_cfg.enable_csid_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery"); + goto err; + } + if (!debugfs_create_u32("enable_reg_dump", 0644, g_tfe_hw_mgr.debug_cfg.dentry, @@ -5469,6 +5529,7 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) memset(&g_tfe_hw_mgr, 0, sizeof(g_tfe_hw_mgr)); mutex_init(&g_tfe_hw_mgr.ctx_mutex); + spin_lock_init(&g_tfe_hw_mgr.ctx_lock); if (CAM_TFE_HW_NUM_MAX != CAM_TFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "CSID num is different then TFE num"); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h index d8205cd9097a..7b3d62b92c6a 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h @@ -28,6 +28,7 @@ * @dentry: Debugfs entry * @csid_debug: csid debug information * @enable_recovery: enable recovery + * @enable_csid_recovery: enable csid recovery * @camif_debug: enable sensor diagnosis status * @enable_reg_dump: enable reg dump on error; * @per_req_reg_dump: Enable per request reg dump @@ -37,6 +38,7 @@ struct cam_tfe_hw_mgr_debug { struct dentry *dentry; uint64_t csid_debug; uint32_t enable_recovery; + uint32_t enable_csid_recovery; uint32_t camif_debug; uint32_t enable_reg_dump; uint32_t per_req_reg_dump; @@ -152,6 +154,7 @@ struct cam_tfe_hw_mgr_ctx { * @tfe_dev_caps tfe device capability per core * @work q work queue for TFE hw manager * @debug_cfg debug configuration + * @ctx_lock Spinlock for HW manager */ struct cam_tfe_hw_mgr { struct cam_isp_hw_mgr mgr_common; @@ -170,6 +173,7 @@ struct cam_tfe_hw_mgr { struct cam_tfe_hw_get_hw_cap tfe_dev_caps[CAM_TFE_HW_NUM_MAX]; struct cam_req_mgr_core_workq *workq; struct cam_tfe_hw_mgr_debug debug_cfg; + spinlock_t ctx_lock; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 4ad63a7a0a8c..7b2bea80ffc8 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -52,6 +52,7 @@ enum cam_isp_hw_err_type { CAM_ISP_HW_ERROR_P2I_ERROR, CAM_ISP_HW_ERROR_VIOLATION, CAM_ISP_HW_ERROR_BUSIF_OVERFLOW, + CAM_ISP_HW_ERROR_CSID_FATAL, CAM_ISP_HW_ERROR_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 02bbe73925de..0da6d5117e27 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -10,6 +10,7 @@ #include #include +#include "cam_isp_hw_mgr_intf.h" #include "cam_ife_csid_core.h" #include "cam_isp_hw.h" #include "cam_soc_util.h" @@ -17,6 +18,7 @@ #include "cam_debug_util.h" #include "cam_cpas_api.h" #include "cam_subdev.h" +#include "cam_tasklet_util.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -1168,6 +1170,8 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->width, path_data->height); reserve->node_res = res; + csid_hw->event_cb = reserve->event_cb; + csid_hw->priv = reserve->priv; end: return rc; @@ -1266,8 +1270,10 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->fatal_err_detected = false; csid_hw->device_enabled = 1; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + cam_tasklet_start(csid_hw->tasklet); return 0; @@ -1319,6 +1325,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + cam_tasklet_stop(csid_hw->tasklet); spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); @@ -3163,6 +3170,8 @@ int cam_ife_csid_release(void *hw_priv, res = (struct cam_isp_resource_node *)release_args; mutex_lock(&csid_hw->hw_info->hw_mutex); + csid_hw->event_cb = NULL; + csid_hw->priv = NULL; if ((res->res_type == CAM_ISP_RESOURCE_CID && res->res_id >= CAM_IFE_CSID_CID_MAX) || (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && @@ -3876,16 +3885,209 @@ static int cam_ife_csid_process_cmd(void *hw_priv, } +static int cam_csid_get_evt_payload( + struct cam_ife_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + + spin_lock(&csid_hw->lock_state); + + if (list_empty(&csid_hw->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&csid_hw->lock_state); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return -ENOMEM; + } + + *evt_payload = list_first_entry(&csid_hw->free_payload_list, + struct cam_csid_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&csid_hw->lock_state); + + return 0; +} + +static int cam_csid_put_evt_payload( + struct cam_ife_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + unsigned long flags; + + if (*evt_payload == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid payload core %d", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + spin_lock_irqsave(&csid_hw->lock_state, flags); + list_add_tail(&(*evt_payload)->list, + &csid_hw->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + return 0; +} +static char *cam_csid_status_to_str(uint32_t status) +{ + switch (status) { + case CAM_IFE_CSID_IRQ_REG_TOP: + return "TOP"; + case CAM_IFE_CSID_IRQ_REG_RX: + return "RX"; + case CAM_IFE_CSID_IRQ_REG_IPP: + return "IPP"; + case CAM_IFE_CSID_IRQ_REG_PPP: + return "PPP"; + case CAM_IFE_CSID_IRQ_REG_RDI_0: + return "RDI0"; + case CAM_IFE_CSID_IRQ_REG_RDI_1: + return "RDI1"; + case CAM_IFE_CSID_IRQ_REG_RDI_2: + return "RDI2"; + case CAM_IFE_CSID_IRQ_REG_RDI_3: + return "RDI3"; + case CAM_IFE_CSID_IRQ_REG_UDI_0: + return "UDI0"; + case CAM_IFE_CSID_IRQ_REG_UDI_1: + return "UDI1"; + case CAM_IFE_CSID_IRQ_REG_UDI_2: + return "UDI2"; + default: + return "Invalid IRQ"; + } +} + +static int cam_csid_evt_bottom_half_handler( + void *handler_priv, + void *evt_payload_priv) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_csid_evt_payload *evt_payload; + int i; + int rc = 0; + struct cam_isp_hw_event_info event_info; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid Param handler_priv %pK evt_payload_priv %pK", + handler_priv, evt_payload_priv); + return 0; + } + + csid_hw = (struct cam_ife_csid_hw *)handler_priv; + evt_payload = (struct cam_csid_evt_payload *)evt_payload_priv; + + if (!csid_hw->event_cb || !csid_hw->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d Invalid args %pK %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb, + csid_hw->priv); + goto end; + } + + if (csid_hw->priv != evt_payload->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d priv mismatch %pK, %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->priv, + evt_payload->priv); + goto end; + } + + CAM_ERR_RATE_LIMIT(CAM_ISP, "idx %d err %d phy %d cnt %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type, + csid_hw->csi2_rx_cfg.phy_sel, + csid_hw->csi2_cfg_cnt); + + for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) + CAM_ERR_RATE_LIMIT(CAM_ISP, "status %s: %x", + cam_csid_status_to_str(i), + evt_payload->irq_status[i]); + + /* this hunk can be extended to handle more cases + * which we want to offload to bottom half from + * irq handlers + */ + event_info.err_type = evt_payload->evt_type; + event_info.hw_idx = evt_payload->hw_idx; + + switch (evt_payload->evt_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: + if (csid_hw->fatal_err_detected) + break; + csid_hw->fatal_err_detected = true; + rc = csid_hw->event_cb(NULL, + CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); + break; + + default: + CAM_DBG(CAM_ISP, "CSID[%d] invalid error type %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type); + break; + } +end: + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return 0; +} + +static int cam_csid_handle_hw_err_irq( + struct cam_ife_csid_hw *csid_hw, + int evt_type, + uint32_t *irq_status) +{ + int rc = 0; + int i; + void *bh_cmd = NULL; + struct cam_csid_evt_payload *evt_payload; + + CAM_DBG(CAM_ISP, "CSID[%d] error %d", + csid_hw->hw_intf->hw_idx, evt_type); + + rc = cam_csid_get_evt_payload(csid_hw, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return rc; + } + + rc = tasklet_bh_api.get_bh_payload_func(csid_hw->tasklet, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID[%d] Can not get cmd for tasklet, evt_type %d", + csid_hw->hw_intf->hw_idx, + evt_type); + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return rc; + } + + evt_payload->evt_type = evt_type; + evt_payload->priv = csid_hw->priv; + evt_payload->hw_idx = csid_hw->hw_intf->hw_idx; + + for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) + evt_payload->irq_status[i] = irq_status[i]; + + tasklet_bh_api.bottom_half_enqueue_func(csid_hw->tasklet, + bh_cmd, + csid_hw, + evt_payload, + cam_csid_evt_bottom_half_handler); + + return rc; +} + irqreturn_t cam_ife_csid_irq(int irq_num, void *data) { struct cam_ife_csid_hw *csid_hw; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; - uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; - uint32_t irq_status_rdi[CAM_IFE_CSID_RDI_MAX] = {0, 0, 0, 0}; - uint32_t irq_status_udi[CAM_IFE_CSID_UDI_MAX] = {0, 0, 0}; - uint32_t val, irq_status_ppp = 0; + uint32_t i, val; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX] = {0}; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; unsigned long flags; @@ -3904,23 +4106,27 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csi2_reg = csid_reg->csi2_reg; /* read */ - irq_status_top = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_TOP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_status_addr); - irq_status_rx = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_RX] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); if (csid_reg->cmn_reg->num_pix) - irq_status_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_IPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_irq_status_addr); if (csid_reg->cmn_reg->num_ppp) - irq_status_ppp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_PPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_status_addr); if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - irq_status_rdi[i] = + irq_status[i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); } @@ -3928,7 +4134,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - irq_status_udi[i] = + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->udi_reg[i]->csid_udi_irq_status_addr); } @@ -3936,22 +4142,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* clear */ - cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_TOP], + soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); - cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_RX], + soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) - cam_io_w_mb(irq_status_ipp, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_IPP], + soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); if (csid_reg->cmn_reg->num_ppp) - cam_io_w_mb(irq_status_ppp, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_PPP], + soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - cam_io_w_mb(irq_status_rdi[i], + cam_io_w_mb(irq_status[i], soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); } @@ -3959,7 +4169,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - cam_io_w_mb(irq_status_udi[i], + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i], soc_info->reg_map[0].mem_base + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); } @@ -3970,94 +4180,120 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); - CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); - CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); - CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); - CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_TOP]); + CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_RX]); + CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_IPP]); + CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_PPP]); CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x irq_status_rdi1= 0x%x irq_status_rdi2= 0x%x", - irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); + irq_status[0], irq_status[1], irq_status[2]); CAM_DBG(CAM_ISP, "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", - irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0], + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_1], + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_2]); - if (irq_status_top & CSID_TOP_IRQ_DONE) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_TOP] & CSID_TOP_IRQ_DONE) { CAM_DBG(CAM_ISP, "csid top reset complete"); complete(&csid_hw->csid_top_complete); } - if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); } spin_lock_irqsave(&csid_hw->lock_state, flags); if (csid_hw->device_enabled == 1) { - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_ECC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } } +handle_fatal_error: spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > @@ -4066,26 +4302,33 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count = 0; } - if (fatal_err_detected) + if (fatal_err_detected) { cam_ife_csid_halt_csi2(csid_hw); + cam_csid_handle_hw_err_irq(csid_hw, + CAM_ISP_HW_ERROR_CSID_FATAL, irq_status); + } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL0_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL1_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL2_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL3_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); @@ -4093,22 +4336,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) { - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL0_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL1_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL2_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL3_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); @@ -4116,7 +4363,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d LONG_PKT_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4136,7 +4385,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->hw_intf->hw_idx, (val >> 16), (val & 0xFFFF)); } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d SHORT_PKT_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4152,7 +4403,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PKT_HDR_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4166,13 +4418,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /*read the IPP errors */ if (csid_reg->cmn_reg->num_pix) { /* IPP reset done bit */ - if (irq_status_ipp & + if (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID IPP reset complete"); complete(&csid_hw->csid_ipp_complete); } - if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", csid_hw->hw_intf->hw_idx); @@ -4180,22 +4433,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP CCIF violation", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP Overflow due to back pressure", csid_hw->hw_intf->hw_idx); - if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4209,13 +4466,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /*read PPP errors */ if (csid_reg->cmn_reg->num_ppp) { /* PPP reset done bit */ - if (irq_status_ppp & + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID PPP reset complete"); complete(&csid_hw->csid_ppp_complete); } - if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP SOF received", csid_hw->hw_intf->hw_idx); @@ -4223,22 +4481,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP CCIF violation", csid_hw->hw_intf->hw_idx); - if ((irq_status_ppp & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP Overflow due to back pressure", csid_hw->hw_intf->hw_idx); - if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d PPP fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4250,13 +4512,13 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - if (irq_status_rdi[i] & + if (irq_status[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); complete(&csid_hw->csid_rdin_complete[i]); } - if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[i] & CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d SOF received", i); @@ -4264,21 +4526,21 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); - if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI :%d CCIF violation", i); - if ((irq_status_rdi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[i] & CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI :%d Overflow due to back pressure", i); - if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d RDI fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4290,13 +4552,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - if (irq_status_udi[i] & + if (irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID UDI%d reset complete", i); complete(&csid_hw->csid_udin_complete[i]); } - if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID UDI:%d SOF received", i); @@ -4304,21 +4567,25 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID UDI:%d EOF received", i); - if ((irq_status_udi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_WARN_RATE_LIMIT(CAM_ISP, "CSID UDI :%d CCIF violation", i); - if ((irq_status_udi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_WARN_RATE_LIMIT(CAM_ISP, "CSID UDI :%d Overflow due to back pressure", i); - if (irq_status_udi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UDI fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4497,6 +4764,19 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->udi_res[i].res_priv = path_data; } + rc = cam_tasklet_init(&ife_csid_hw->tasklet, ife_csid_hw, csid_idx); + if (rc) { + CAM_ERR(CAM_ISP, "Unable to create CSID tasklet rc %d", rc); + goto err; + } + + INIT_LIST_HEAD(&ife_csid_hw->free_payload_list); + for (i = 0; i < CAM_CSID_EVT_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&ife_csid_hw->evt_payload[i].list); + list_add_tail(&ife_csid_hw->evt_payload[i].list, + &ife_csid_hw->free_payload_list); + } + ife_csid_hw->csid_debug = 0; ife_csid_hw->error_irq_count = 0; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 6d7a9c3aa0c2..a65783c29d18 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_HW_H_ @@ -72,6 +72,8 @@ #define CSID_DEBUG_ENABLE_HBI_VBI_INFO BIT(7) #define CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) +#define CAM_CSID_EVT_PAYLOAD_MAX 10 + /* enum cam_csid_path_halt_mode select the path halt mode control */ enum cam_csid_path_halt_mode { CSID_HALT_MODE_INTERNAL, @@ -91,6 +93,24 @@ enum cam_csid_path_timestamp_stb_sel { CSID_TIMESTAMP_STB_MAX, }; +/** + * enum cam_ife_pix_path_res_id - Specify the csid patch + */ +enum cam_ife_csid_irq_reg { + CAM_IFE_CSID_IRQ_REG_RDI_0, + CAM_IFE_CSID_IRQ_REG_RDI_1, + CAM_IFE_CSID_IRQ_REG_RDI_2, + CAM_IFE_CSID_IRQ_REG_RDI_3, + CAM_IFE_CSID_IRQ_REG_TOP, + CAM_IFE_CSID_IRQ_REG_RX, + CAM_IFE_CSID_IRQ_REG_IPP, + CAM_IFE_CSID_IRQ_REG_PPP, + CAM_IFE_CSID_IRQ_REG_UDI_0, + CAM_IFE_CSID_IRQ_REG_UDI_1, + CAM_IFE_CSID_IRQ_REG_UDI_2, + CAM_IFE_CSID_IRQ_REG_MAX, +}; + struct cam_ife_csid_pxl_reg_offset { /* Pxl path register offsets*/ uint32_t csid_pxl_irq_status_addr; @@ -517,12 +537,32 @@ struct cam_ife_csid_path_cfg { uint32_t num_bytes_out; }; +/** + * struct cam_csid_evt_payload- payload for csid hw event + * @list : list head + * @evt_type : Event type from CSID + * @irq_status : IRQ Status register + * @hw_idx : Hw index + * @priv : Private data of payload + */ +struct cam_csid_evt_payload { + struct list_head list; + uint32_t evt_type; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX]; + uint32_t hw_idx; + void *priv; +}; + /** * struct cam_ife_csid_hw- csid hw device resources data * * @hw_intf: contain the csid hw interface information * @hw_info: csid hw device information * @csid_info: csid hw specific information + * @tasklet: tasklet to handle csid errors + * @priv: private data to be sent with callback + * @free_payload_list: list head for payload + * @evt_payload: Event payload to be passed to tasklet * @res_type: CSID in resource type * @csi2_rx_cfg: Csi2 rx decoder configuration for csid * @tpg_cfg: TPG configuration @@ -553,11 +593,17 @@ struct cam_ife_csid_path_cfg { * * @prev_boot_timestamp first bootime stamp at the start * @prev_qtimer_ts stores csid timestamp + * @fatal_err_detected flag to indicate fatal errror is reported + * @event_cb Callback to hw manager if CSID event reported */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; struct cam_hw_info *hw_info; struct cam_ife_csid_hw_info *csid_info; + void *tasklet; + void *priv; + struct list_head free_payload_list; + struct cam_csid_evt_payload evt_payload[CAM_CSID_EVT_PAYLOAD_MAX]; uint32_t res_type; struct cam_ife_csid_csi2_rx_cfg csi2_rx_cfg; struct cam_ife_csid_tpg_cfg tpg_cfg; @@ -586,6 +632,8 @@ struct cam_ife_csid_hw { uint32_t binning_supported; uint64_t prev_boot_timestamp; uint64_t prev_qtimer_ts; + bool fatal_err_detected; + cam_hw_mgr_event_cb_func event_cb; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 56ce59636dda..62c49ed8be9e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSID_HW_INTF_H_ @@ -123,6 +123,8 @@ struct cam_isp_in_port_generic_info { * @node_res : Reserved resource structure pointer * @crop_enable : Flag to indicate CSID crop enable * @drop_enable : Flag to indicate CSID drop enable + * @priv: private data to be sent in callback + * @event_cb: CSID event callback to hw manager * */ struct cam_csid_hw_reserve_resource_args { @@ -136,6 +138,8 @@ struct cam_csid_hw_reserve_resource_args { struct cam_isp_resource_node *node_res; bool crop_enable; bool drop_enable; + void *priv; + cam_hw_mgr_event_cb_func event_cb; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c index 97282ede31c3..8a90958c2065 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c @@ -18,6 +18,7 @@ #include "cam_isp_hw_mgr_intf.h" #include #include "cam_subdev.h" +#include "cam_tasklet_util.h" /* Timeout value in msec */ #define TFE_CSID_TIMEOUT 1000 @@ -908,8 +909,10 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) goto disable_soc; spin_lock_irqsave(&csid_hw->spin_lock, flags); + csid_hw->fatal_err_detected = false; csid_hw->device_enabled = 1; spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + cam_tasklet_start(csid_hw->tasklet); return rc; @@ -964,6 +967,7 @@ static int cam_tfe_csid_disable_hw(struct cam_tfe_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + cam_tasklet_stop(csid_hw->tasklet); spin_lock_irqsave(&csid_hw->spin_lock, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->spin_lock, flags); @@ -1846,6 +1850,9 @@ static int cam_tfe_csid_release(void *hw_priv, goto end; } + csid_hw->event_cb = NULL; + csid_hw->event_cb_priv = NULL; + if ((res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE) || (res->res_state >= CAM_ISP_RESOURCE_STATE_STREAMING)) { CAM_WARN(CAM_ISP, @@ -2498,6 +2505,189 @@ static int cam_tfe_csid_process_cmd(void *hw_priv, return rc; } +static int cam_csid_get_evt_payload( + struct cam_tfe_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + + spin_lock(&csid_hw->spin_lock); + + if (list_empty(&csid_hw->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&csid_hw->spin_lock); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return -ENOMEM; + } + + *evt_payload = list_first_entry(&csid_hw->free_payload_list, + struct cam_csid_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&csid_hw->spin_lock); + + return 0; +} + +static int cam_csid_put_evt_payload( + struct cam_tfe_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + unsigned long flags; + + if (*evt_payload == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid payload core %d", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + spin_lock_irqsave(&csid_hw->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, + &csid_hw->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + + return 0; +} +static char *cam_csid_status_to_str(uint32_t status) +{ + switch (status) { + case TFE_CSID_IRQ_REG_TOP: + return "TOP"; + case TFE_CSID_IRQ_REG_RX: + return "RX"; + case TFE_CSID_IRQ_REG_IPP: + return "IPP"; + case TFE_CSID_IRQ_REG_RDI0: + return "RDI0"; + case TFE_CSID_IRQ_REG_RDI1: + return "RDI1"; + case TFE_CSID_IRQ_REG_RDI2: + return "RDI2"; + default: + return "Invalid IRQ"; + } +} + +static int cam_csid_evt_bottom_half_handler( + void *handler_priv, + void *evt_payload_priv) +{ + struct cam_tfe_csid_hw *csid_hw; + struct cam_csid_evt_payload *evt_payload; + int i; + int rc = 0; + struct cam_isp_hw_event_info event_info; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid Param handler_priv %pK evt_payload_priv %pK", + handler_priv, evt_payload_priv); + return 0; + } + + csid_hw = (struct cam_tfe_csid_hw *)handler_priv; + evt_payload = (struct cam_csid_evt_payload *)evt_payload_priv; + + if (!csid_hw->event_cb || !csid_hw->event_cb_priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d Invalid args %pK %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb, + csid_hw->event_cb_priv); + goto end; + } + + if (csid_hw->event_cb_priv != evt_payload->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d priv mismatch %pK, %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb_priv, + evt_payload->priv); + goto end; + } + + CAM_ERR_RATE_LIMIT(CAM_ISP, "idx %d err %d phy %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type, + csid_hw->csi2_rx_cfg.phy_sel); + + for (i = 0; i < TFE_CSID_IRQ_REG_MAX; i++) + CAM_ERR_RATE_LIMIT(CAM_ISP, "status %s: %x", + cam_csid_status_to_str(i), + evt_payload->irq_status[i]); + + /* this hunk can be extended to handle more cases + * which we want to offload to bottom half from + * irq handlers + */ + event_info.err_type = evt_payload->evt_type; + event_info.hw_idx = evt_payload->hw_idx; + + switch (evt_payload->evt_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: + if (csid_hw->fatal_err_detected) + break; + csid_hw->fatal_err_detected = true; + rc = csid_hw->event_cb(NULL, + CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); + break; + + default: + CAM_DBG(CAM_ISP, "CSID[%d] invalid error type %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type); + break; + } +end: + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return 0; +} + +static int cam_csid_handle_hw_err_irq( + struct cam_tfe_csid_hw *csid_hw, + int evt_type, + uint32_t *irq_status) +{ + int rc = 0; + int i; + void *bh_cmd = NULL; + struct cam_csid_evt_payload *evt_payload; + + CAM_DBG(CAM_ISP, "CSID[%d] error %d", + csid_hw->hw_intf->hw_idx, evt_type); + + rc = cam_csid_get_evt_payload(csid_hw, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return rc; + } + + rc = tasklet_bh_api.get_bh_payload_func(csid_hw->tasklet, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID[%d] Can not get cmd for tasklet, evt_type %d", + csid_hw->hw_intf->hw_idx, + evt_type); + return rc; + } + + evt_payload->evt_type = evt_type; + evt_payload->priv = csid_hw->event_cb_priv; + evt_payload->hw_idx = csid_hw->hw_intf->hw_idx; + + for (i = 0; i < TFE_CSID_IRQ_REG_MAX; i++) + evt_payload->irq_status[i] = irq_status[i]; + + tasklet_bh_api.bottom_half_enqueue_func(csid_hw->tasklet, + bh_cmd, + csid_hw, + evt_payload, + cam_csid_evt_bottom_half_handler); + + return rc; +} + irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) { struct cam_tfe_csid_hw *csid_hw; @@ -2576,20 +2766,24 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & @@ -2620,6 +2814,7 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) TFE_CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) is_error_irq = true; } +handle_fatal_error: spin_unlock_irqrestore(&csid_hw->spin_lock, flags); if (csid_hw->error_irq_count || fatal_err_detected) @@ -2645,6 +2840,8 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) CAM_SUBDEV_MESSAGE_IRQ_ERR, (csid_hw->csi2_rx_cfg.phy_sel - 1)); } + cam_csid_handle_hw_err_irq(csid_hw, + CAM_ISP_HW_ERROR_CSID_FATAL, irq_status); } if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOT_IRQ) { @@ -2993,6 +3190,19 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->rdi_res[i].res_priv = path_data; } + rc = cam_tasklet_init(&tfe_csid_hw->tasklet, tfe_csid_hw, csid_idx); + if (rc) { + CAM_ERR(CAM_ISP, "Unable to create CSID tasklet rc %d", rc); + goto err; + } + + INIT_LIST_HEAD(&tfe_csid_hw->free_payload_list); + for (i = 0; i < CAM_CSID_EVT_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&tfe_csid_hw->evt_payload[i].list); + list_add_tail(&tfe_csid_hw->evt_payload[i].list, + &tfe_csid_hw->free_payload_list); + } + tfe_csid_hw->csid_debug = 0; tfe_csid_hw->error_irq_count = 0; tfe_csid_hw->prev_boot_timestamp = 0; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h index 481fbe9b611f..4b50eeb4bbd6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h @@ -73,6 +73,8 @@ #define TFE_CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) #define TFE_CSID_DEBUG_ENABLE_RST_IRQ_LOG BIT(9) +#define CAM_CSID_EVT_PAYLOAD_MAX 10 + /* enum cam_csid_path_halt_mode select the path halt mode control */ enum cam_tfe_csid_path_halt_mode { TFE_CSID_HALT_MODE_INTERNAL, @@ -353,12 +355,31 @@ struct cam_tfe_csid_path_cfg { uint32_t sensor_vbi; }; +/** + * struct cam_csid_evt_payload- payload for csid hw event + * @list : list head + * @evt_type : Event type from CSID + * @irq_status : IRQ Status register + * @hw_idx : Hw index + * @priv : Private data of payload + */ +struct cam_csid_evt_payload { + struct list_head list; + uint32_t evt_type; + uint32_t irq_status[TFE_CSID_IRQ_REG_MAX]; + uint32_t hw_idx; + void *priv; +}; + /** * struct cam_tfe_csid_hw- csid hw device resources data * * @hw_intf: contain the csid hw interface information * @hw_info: csid hw device information * @csid_info: csid hw specific information + * @tasklet: tasklet to handle csid errors + * @free_payload_list: list head for payload + * @evt_payload: Event payload to be passed to tasklet * @in_res_id: csid in resource type * @csi2_rx_cfg: csi2 rx decoder configuration for csid * @csi2_rx_reserve_cnt: csi2 reservations count value @@ -381,6 +402,7 @@ struct cam_tfe_csid_path_cfg { * @device_enabled Device enabled will set once CSID powered on and * initial configuration are done. * @lock_state csid spin lock + * @fatal_err_detected flag to indicate fatal errror is reported * @event_cb: Callback function to hw mgr in case of hw events * @event_cb_priv: Context data * @prev_boot_timestamp previous frame bootime stamp @@ -391,6 +413,9 @@ struct cam_tfe_csid_hw { struct cam_hw_intf *hw_intf; struct cam_hw_info *hw_info; struct cam_tfe_csid_hw_info *csid_info; + void *tasklet; + struct list_head free_payload_list; + struct cam_csid_evt_payload evt_payload[CAM_CSID_EVT_PAYLOAD_MAX]; uint32_t in_res_id; struct cam_tfe_csid_csi2_rx_cfg csi2_rx_cfg; uint32_t csi2_reserve_cnt; @@ -409,6 +434,7 @@ struct cam_tfe_csid_hw { uint32_t error_irq_count; uint32_t device_enabled; spinlock_t spin_lock; + bool fatal_err_detected; cam_hw_mgr_event_cb_func event_cb; void *event_cb_priv; uint64_t prev_boot_timestamp; diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 4b11c6a3a9ed..ebec0b04b916 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -422,12 +422,14 @@ struct cam_mem_cache_ops_cmd { * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered * @CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE: SOF freeze, can be recovered + * @CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY: Full recovery, can be recovered */ #define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 #define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 #define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 #define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 #define CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE 4 +#define CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY 5 /** * struct cam_req_mgr_error_msg