msm: camera: isp: Added CSID recovery mechanism
CSID is not able to recover from the fatal errors like lane overflows, continuous unbound frames and ESD errors. To recover from such errors, it is necessary to restart the sensor as just starting the ISP hw do not make any change as the sensor can still be in bad state. This commit implements tasklet based CSID recovery mechanism. On detecting an error in CSID interrupt, tasklet is scheduled which in turn will call the ISP hw manager to notify the ISP context, from here a notification is sent to CRM to send a message to trigger full recovery. This full recovery includes the sensor release and start. This feature is debugfs based. Based on need this can be turned on. CRs-Fixed: 2674109 Change-Id: I7e4612e9bd24a20691146ae0b9dc6f77ccbc0714 Signed-off-by: Shravya Samala <shravyas@codeaurora.org>
This commit is contained in:
1 parent
e5d41356bd
commit
5db1153338
12 files changed
+801
-94
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <media/cam_req_mgr.h>
|
||||
#include <dt-bindings/msm/msm-camera.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "cam_isp_hw_mgr_intf.h"
|
||||
#include <dt-bindings/msm/msm-camera.h>
|
||||
#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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user