Pārlūkot izejas kodu

msm: camera: tfe: Handle overflow internal recovery

Handle internal recovery in case of csid and bus overflow.
Handle frame size error detection for pixel and line count
mismatch as fatal errors.
Fixed csid side error reproting to hw_mgr layer.

CRs-Fixed: 3532076
Change-Id: Id4f572caf6774797396d70d7a20a4f54fc1b9ea9
Signed-off-by: Pranav Sanwal <[email protected]>
Pranav Sanwal 2 gadi atpakaļ
vecāks
revīzija
fe4bd2e6a1

+ 94 - 10
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -6194,31 +6194,113 @@ end:
 	return rc;
 }
 
+static int cam_tfe_hw_mgr_check_and_notify_overflow(
+	struct cam_isp_hw_event_info    *evt,
+	struct cam_tfe_hw_mgr_ctx       *hw_mgr_ctx,
+	bool                            *is_bus_overflow)
+{
+	int                             i;
+	struct cam_hw_intf             *hw_if = NULL;
+	struct cam_isp_hw_overflow_info overflow_info;
+
+	for (i = 0; i < hw_mgr_ctx->num_base; i++) {
+		if (hw_mgr_ctx->base[i].idx != evt->hw_idx)
+			continue;
+
+		hw_if = g_tfe_hw_mgr.tfe_devices[evt->hw_idx]->hw_intf;
+		if (!hw_if) {
+			CAM_ERR_RATE_LIMIT(CAM_ISP, "hw_intf is null");
+			return -EINVAL;
+		}
+
+		if (hw_if->hw_ops.process_cmd) {
+			overflow_info.res_id = evt->res_id;
+			hw_if->hw_ops.process_cmd(hw_if->hw_priv,
+				CAM_ISP_HW_NOTIFY_OVERFLOW,
+				&overflow_info,
+				sizeof(struct cam_isp_hw_overflow_info));
+
+			CAM_DBG(CAM_ISP,
+				"check and notify hw idx %d type %d bus overflow happened %d",
+				hw_mgr_ctx->base[i].idx, hw_mgr_ctx->base[i].hw_type,
+				overflow_info.is_bus_overflow);
+
+			if (overflow_info.is_bus_overflow)
+				*is_bus_overflow = true;
+		}
+	}
+
+	return 0;
+}
+
 static int cam_tfe_hw_mgr_handle_csid_event(
 	uint32_t                      err_type,
-	struct cam_isp_hw_event_info *event_info)
+	struct cam_isp_hw_event_info *event_info,
+	void                         *ctx)
 {
 	struct cam_isp_hw_error_event_data  error_event_data = {0};
 	struct cam_tfe_hw_event_recovery_data     recovery_data = {0};
+	bool                                is_bus_overflow = false;
+	struct cam_tfe_hw_mgr_ctx           *tfe_hw_mgr_ctx = ctx;
+
+	/* Default error types */
+	error_event_data.error_type = CAM_ISP_HW_ERROR_CSID_FATAL;
+	recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW;
 
 	/* this can be extended based on the types of error
 	 * received from CSID
 	 */
 	switch (err_type) {
+	case CAM_ISP_HW_ERROR_CSID_FRAME_SIZE:
 	case CAM_ISP_HW_ERROR_CSID_FATAL: {
 
-		if (!g_tfe_hw_mgr.debug_cfg.enable_csid_recovery)
-			break;
+		if (!g_tfe_hw_mgr.debug_cfg.enable_csid_recovery) {
+			CAM_ERR(CAM_ISP,
+				"CSID:%d err: %d not handled, csid_recovery_enable: %d",
+				event_info->hw_idx, err_type,
+				g_tfe_hw_mgr.debug_cfg.enable_csid_recovery);
+			return 0;
+		}
+		break;
+	}
+	case CAM_ISP_HW_ERROR_CSID_OUTPUT_FIFO_OVERFLOW: {
+		cam_tfe_hw_mgr_check_and_notify_overflow(event_info,
+			tfe_hw_mgr_ctx, &is_bus_overflow);
 
-		error_event_data.error_type = err_type;
-		cam_tfe_hw_mgr_find_affected_ctx(&error_event_data,
-			event_info->hw_idx,
-			&recovery_data);
+		if (is_bus_overflow) {
+			if (tfe_hw_mgr_ctx->try_recovery_cnt <
+				MAX_TFE_INTERNAL_RECOVERY_ATTEMPTS) {
+
+				error_event_data.try_internal_recovery = true;
+				if (!atomic_read(&tfe_hw_mgr_ctx->overflow_pending))
+					tfe_hw_mgr_ctx->try_recovery_cnt++;
+
+				if (!tfe_hw_mgr_ctx->recovery_req_id)
+					tfe_hw_mgr_ctx->recovery_req_id =
+						tfe_hw_mgr_ctx->applied_req_id;
+
+				error_event_data.error_type = err_type;
+			}
+
+			CAM_DBG(CAM_ISP,
+				"CSID[%u] error: %u current_recovery_cnt: %u  recovery_req: %llu",
+				event_info->hw_idx, err_type, tfe_hw_mgr_ctx->try_recovery_cnt,
+				tfe_hw_mgr_ctx->recovery_req_id);
+		}
 		break;
 	}
 	default:
-		break;
+		CAM_ERR(CAM_ISP, "CSID:%d, unahandled error: %d",
+			event_info->hw_idx, err_type);
+		return 0;
 	}
+
+	CAM_ERR(CAM_ISP, "CSID:[%u] error: %u on ctx: %u", event_info->hw_idx,
+		error_event_data.error_type, tfe_hw_mgr_ctx->ctx_index);
+
+	cam_tfe_hw_mgr_find_affected_ctx(&error_event_data, event_info->hw_idx,
+		&recovery_data);
+
 	return 0;
 }
 
@@ -6273,8 +6355,10 @@ static int cam_tfe_hw_mgr_handle_hw_err(
 	}
 
 	spin_lock(&g_tfe_hw_mgr.ctx_lock);
-	if (err_evt_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) {
-		rc = cam_tfe_hw_mgr_handle_csid_event(err_evt_info->err_type, event_info);
+	/* CAM_ISP_RESOURCE_PIX_PATH denotes error event coming from CSID */
+	if (event_info->res_type == CAM_ISP_RESOURCE_PIX_PATH) {
+		rc = cam_tfe_hw_mgr_handle_csid_event(err_evt_info->err_type, event_info,
+			tfe_hw_mgr_ctx);
 		spin_unlock(&g_tfe_hw_mgr.ctx_lock);
 		return rc;
 	}

+ 27 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c

@@ -3702,14 +3702,17 @@ static int cam_tfe_csid_evt_bottom_half_handler(
 	 */
 	err_evt_info.err_type = evt_payload->evt_type;
 	event_info.hw_idx = evt_payload->hw_idx;
+	event_info.res_type = CAM_ISP_RESOURCE_PIX_PATH;
 
 	switch (evt_payload->evt_type) {
+	case CAM_ISP_HW_ERROR_CSID_FRAME_SIZE:
 	case CAM_ISP_HW_ERROR_CSID_FATAL:
 		if (csid_hw->fatal_err_detected)
 			break;
-		event_info.event_data = (void *)&err_evt_info;
 		csid_hw->fatal_err_detected = true;
-		rc = csid_hw->event_cb(NULL,
+	case CAM_ISP_HW_ERROR_CSID_OUTPUT_FIFO_OVERFLOW:
+		event_info.event_data = (void *)&err_evt_info;
+		rc = csid_hw->event_cb(csid_hw->event_cb_priv,
 			CAM_ISP_HW_EVENT_ERROR, (void *)&event_info);
 		break;
 
@@ -3786,6 +3789,7 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data)
 	unsigned long flags;
 	uint32_t i, val, val1;
 	uint32_t data_idx;
+	uint32_t report_err_type = CAM_ISP_HW_ERROR_NONE;
 
 	if (!data) {
 		CAM_ERR(CAM_ISP, "CSID: Invalid arguments");
@@ -3938,8 +3942,9 @@ handle_fatal_error:
 			cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE,
 				CAM_SUBDEV_MESSAGE_REG_DUMP, (void *)&data_idx);
 		}
+		report_err_type = CAM_ISP_HW_ERROR_CSID_FATAL;
 		cam_tfe_csid_handle_hw_err_irq(csid_hw,
-			CAM_ISP_HW_ERROR_CSID_FATAL, irq_status);
+			report_err_type, irq_status);
 	}
 
 	if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOT_IRQ) {
@@ -4118,6 +4123,13 @@ handle_fatal_error:
 				soc_info->reg_map[0].mem_base +
 				csid_reg->ipp_reg->csid_pxl_ctrl_addr);
 			is_error_irq = true;
+			report_err_type = CAM_ISP_HW_ERROR_CSID_OUTPUT_FIFO_OVERFLOW;
+		}
+
+		if (irq_status[TFE_CSID_IRQ_REG_IPP] &
+			(TFE_CSID_PATH_ERROR_PIX_COUNT | TFE_CSID_PATH_ERROR_LINE_COUNT)) {
+			is_error_irq = true;
+			report_err_type = CAM_ISP_HW_ERROR_CSID_FRAME_SIZE;
 		}
 
 		if (irq_status[TFE_CSID_IRQ_REG_IPP] &
@@ -4189,6 +4201,13 @@ handle_fatal_error:
 				soc_info->reg_map[0].mem_base +
 				csid_reg->ppp_reg->csid_pxl_ctrl_addr);
 			is_error_irq = true;
+			report_err_type = CAM_ISP_HW_ERROR_CSID_OUTPUT_FIFO_OVERFLOW;
+		}
+
+		if (irq_status[TFE_CSID_IRQ_REG_PPP] &
+			(TFE_CSID_PATH_ERROR_PIX_COUNT | TFE_CSID_PATH_ERROR_LINE_COUNT)) {
+			is_error_irq = true;
+			report_err_type = CAM_ISP_HW_ERROR_CSID_FRAME_SIZE;
 		}
 
 		if (irq_status[TFE_CSID_IRQ_REG_PPP] &
@@ -4269,6 +4288,7 @@ handle_fatal_error:
 			cam_io_w_mb(CAM_TFE_CSID_HALT_IMMEDIATELY,
 				soc_info->reg_map[0].mem_base +
 				csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr);
+			report_err_type = CAM_ISP_HW_ERROR_CSID_OUTPUT_FIFO_OVERFLOW;
 		}
 
 		if ((irq_status[i] & TFE_CSID_PATH_RDI_OVERFLOW_IRQ) ||
@@ -4298,6 +4318,9 @@ handle_fatal_error:
 				cmn_reg->format_measure_height_mask_val),
 				val &
 				cmn_reg->format_measure_width_mask_val);
+
+			is_error_irq = true;
+			report_err_type = CAM_ISP_HW_ERROR_CSID_FRAME_SIZE;
 		}
 	}
 
@@ -4317,7 +4340,7 @@ handle_fatal_error:
 			soc_info->applied_src_clk_rates.sw_client);
 
 		cam_tfe_csid_handle_hw_err_irq(csid_hw,
-			CAM_ISP_HW_ERROR_NONE, irq_status);
+			report_err_type, irq_status);
 	}
 
 	if (csid_hw->irq_debug_cnt >= CAM_TFE_CSID_IRQ_SOF_DEBUG_CNT_MAX) {

+ 37 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c

@@ -2752,6 +2752,40 @@ static int cam_tfe_bus_deinit_hw(void *hw_priv,
 	return rc;
 }
 
+static int cam_tfe_bus_check_overflow(
+	struct cam_tfe_bus_priv    *bus_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_tfe_bus_wm_resource_data  *rsrc_data;
+	struct cam_isp_hw_overflow_info      *overflow_info = NULL;
+	uint32_t                             bus_overflow_status = 0, i = 0, tmp = 0;
+
+	overflow_info = (struct cam_isp_hw_overflow_info *)cmd_args;
+
+	bus_overflow_status  = cam_io_r(bus_priv->common_data.mem_base +
+		bus_priv->common_data.common_reg->overflow_status);
+
+	if (bus_overflow_status) {
+		overflow_info->is_bus_overflow = true;
+		CAM_INFO(CAM_ISP, "TFE[%d] Bus overflow status: 0x%x",
+				bus_priv->common_data.core_index, bus_overflow_status);
+	}
+
+	tmp = bus_overflow_status;
+	while (tmp) {
+		if (tmp & 0x1) {
+			rsrc_data = bus_priv->bus_client[i].res_priv;
+			CAM_ERR(CAM_ISP, "TFE[%d] WM : %d %s overflow",
+				bus_priv->common_data.core_index, i,
+				rsrc_data->hw_regs->client_name);
+		}
+		tmp = tmp >> 1;
+		i++;
+	}
+
+	return 0;
+}
+
 static int cam_tfe_bus_process_cmd(void *priv,
 	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
 {
@@ -2821,6 +2855,9 @@ static int cam_tfe_bus_process_cmd(void *priv,
 	case CAM_ISP_HW_CMD_BUS_WM_DISABLE:
 		rc = cam_tfe_bus_diable_wm(priv, cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_NOTIFY_OVERFLOW:
+		rc = cam_tfe_bus_check_overflow(priv, cmd_args, arg_size);
+		break;
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d",
 			cmd_type);

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c

@@ -3428,6 +3428,7 @@ int cam_tfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 		rc = cam_tfe_top_init_config_update(core_info->top_priv, cmd_args,
 			arg_size);
 		break;
+	case CAM_ISP_HW_NOTIFY_OVERFLOW:
 	case CAM_ISP_HW_CMD_GET_BUF_UPDATE:
 	case CAM_ISP_HW_CMD_GET_HFR_UPDATE:
 	case CAM_ISP_HW_CMD_STRIPE_UPDATE: