소스 검색

msm: camera: isp: Add support to discard set number of frames

Add support to discard initial number of frames for all paths
at CSID input. The number of frames to discard is obtained
from userland in blob config.

CRs-Fixed: 2841729
Change-Id: I86ce1109b507fe12ee06da870b9242d2aa40c5e0
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 4 년 전
부모
커밋
c9002665c5

+ 69 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -7159,6 +7159,54 @@ static int cam_isp_blob_hfr_update(
 	return rc;
 }
 
+static int cam_isp_blob_csid_discard_init_frame_update(
+	struct cam_isp_generic_blob_info       *blob_info,
+	struct cam_isp_discard_initial_frames  *discard_config,
+	struct cam_hw_prepare_update_args      *prepare)
+{
+	struct cam_ife_hw_mgr_ctx                   *ctx = NULL;
+	struct cam_ife_hw_mgr                       *ife_hw_mgr;
+	struct cam_hw_intf                          *hw_intf;
+	struct cam_isp_hw_mgr_res                   *hw_mgr_res;
+	struct cam_isp_resource_node                *res;
+	struct cam_ife_csid_discard_init_frame_args discard_args;
+	int rc = -EINVAL, i;
+
+	ctx = prepare->ctxt_to_hw_map;
+	ife_hw_mgr = ctx->hw_mgr;
+	discard_args.num_frames = discard_config->num_frames;
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			res = hw_mgr_res->hw_res[i];
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				if (hw_intf->hw_idx != blob_info->base_info->idx)
+					continue;
+
+				discard_args.res = res;
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_CSID_DISCARD_INIT_FRAMES,
+					&discard_args,
+					sizeof(struct cam_ife_csid_discard_init_frame_args));
+				if (rc) {
+					CAM_ERR(CAM_ISP,
+						"Failed to update discard frame cfg for res: %s on CSID[%u]",
+						res->res_name, blob_info->base_info->idx);
+					break;
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+
 static int cam_isp_blob_csid_mup_update(
 	uint32_t                               blob_type,
 	struct cam_isp_generic_blob_info      *blob_info,
@@ -8280,6 +8328,26 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		if (rc)
 			CAM_ERR(CAM_ISP,
 				"TPG config failed rc: %d", rc);
+	}
+		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_DISCARD_INITIAL_FRAMES: {
+		struct cam_isp_discard_initial_frames *discard_config;
+
+		if (blob_size < sizeof(struct cam_isp_discard_initial_frames)) {
+			CAM_ERR(CAM_ISP,
+				"Invalid discard frames blob size %u expected %u",
+				blob_size,
+				sizeof(struct cam_isp_discard_initial_frames));
+			return -EINVAL;
+		}
+
+		discard_config = (struct cam_isp_discard_initial_frames *)blob_data;
+
+		rc = cam_isp_blob_csid_discard_init_frame_update(
+			blob_info, discard_config, prepare);
+		if (rc)
+			CAM_ERR(CAM_ISP, "Discard initial frames update failed rc: %d", rc);
+
 	}
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_CLOCK_CONFIG:
@@ -8655,6 +8723,7 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 	case CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG:
 	case CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_BLANKING_CONFIG:
 	case CAM_ISP_GENERIC_BLOB_TYPE_TPG_CORE_CONFIG:
+	case CAM_ISP_GENERIC_BLOB_TYPE_DISCARD_INITIAL_FRAMES:
 		break;
 	default:
 		CAM_WARN(CAM_ISP, "Invalid blob type: %u", blob_type);

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c

@@ -3762,6 +3762,10 @@ static int cam_ife_csid_ver1_process_cmd(void *hw_priv,
 	case CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE:
 		rc = cam_ife_csid_halt(csid_hw, cmd_args);
 		break;
+	case CAM_ISP_HW_CMD_CSID_DISCARD_INIT_FRAMES:
+		/* Not supported for V1 */
+		rc = 0;
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);

+ 295 - 9
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c

@@ -535,6 +535,153 @@ static int cam_ife_csid_ver2_path_top_half(
 	return 0;
 }
 
+static inline void cam_ife_csid_ver2_reset_discard_frame_cfg(
+	char                                        *res_name,
+	struct cam_ife_csid_ver2_hw                 *csid_hw,
+	struct cam_ife_csid_ver2_path_cfg           *path_cfg)
+{
+	int rc;
+
+	/* Reset discard config params */
+	path_cfg->discard_init_frames = false;
+	path_cfg->num_frames_discard = 0;
+	path_cfg->sof_cnt = 0;
+
+	/* Decrement discard frame ref cnt for this path */
+	atomic_dec(&csid_hw->discard_frame_per_path);
+
+	/* If input SOF irq is enabled explicitly - unsubscribe in th*/
+	if (path_cfg->discard_irq_handle > 0) {
+		rc = cam_irq_controller_unsubscribe_irq(
+			csid_hw->csid_irq_controller,
+			path_cfg->discard_irq_handle);
+		if (rc)
+			CAM_WARN(CAM_ISP,
+				"Failed to unsubscribe input SOF for res: %s",
+				res_name);
+
+		path_cfg->discard_irq_handle = 0;
+	}
+
+	CAM_DBG(CAM_ISP, "CSID[%u] Reset discard frame config for res: %s discard_ref_cnt: %u",
+		csid_hw->hw_intf->hw_idx, res_name,
+		atomic_read(&csid_hw->discard_frame_per_path));
+}
+
+static int cam_ife_csid_ver2_discard_sof_pix_top_half(
+	uint32_t                                   evt_id,
+	struct cam_irq_th_payload                 *th_payload)
+{
+	struct cam_hw_info                          *hw_info;
+	struct cam_ife_csid_ver2_hw                 *csid_hw = NULL;
+	struct cam_isp_resource_node                *res;
+	struct cam_ife_csid_ver2_reg_info           *csid_reg = NULL;
+	const struct cam_ife_csid_ver2_pxl_reg_info *path_reg = NULL;
+	struct cam_ife_csid_ver2_path_cfg           *path_cfg;
+	struct cam_hw_soc_info                      *soc_info;
+	void    __iomem                             *base;
+	uint32_t                                     val;
+
+	res  = th_payload->handler_priv;
+
+	if (!res) {
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "No private returned");
+		return -ENODEV;
+	}
+
+	hw_info = (struct cam_hw_info *)res->hw_intf->hw_priv;
+	csid_hw = (struct cam_ife_csid_ver2_hw *)hw_info->core_info;
+	csid_reg = (struct cam_ife_csid_ver2_reg_info *)
+			csid_hw->core_info->csid_reg;
+	path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
+	soc_info = &csid_hw->hw_info->soc_info;
+	base  = soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base;
+
+	if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) {
+		path_reg = csid_reg->ipp_reg;
+	} else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) {
+		path_reg = csid_reg->ppp_reg;
+	} else {
+		CAM_WARN(CAM_ISP, "Invalid res_id: 0x%x", res->res_id);
+		return -ENODEV;
+	}
+
+	/* Count SOFs */
+	path_cfg->sof_cnt++;
+
+	CAM_DBG(CAM_ISP, "CSID[%u] Discard frame on %s path, num SOFs: %u",
+		csid_hw->hw_intf->hw_idx, res->res_name, path_cfg->sof_cnt);
+
+	/* Check with requested number of frames to be dropped */
+	if (path_cfg->sof_cnt == path_cfg->num_frames_discard) {
+		if (path_cfg->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
+			path_cfg->sync_mode == CAM_ISP_HW_SYNC_NONE) {
+			val = cam_io_r_mb(base + path_reg->ctrl_addr);
+			val |= path_reg->resume_frame_boundary;
+			cam_io_w_mb(val, base + path_reg->ctrl_addr);
+			CAM_DBG(CAM_ISP,
+				"CSID[%u] start cmd programmed for %s sof_cnt %u",
+				csid_hw->hw_intf->hw_idx,
+				res->res_name,
+				path_cfg->sof_cnt);
+		}
+		cam_ife_csid_ver2_reset_discard_frame_cfg(res->res_name, csid_hw, path_cfg);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int cam_ife_csid_ver2_discard_sof_rdi_top_half(
+	uint32_t                                   evt_id,
+	struct cam_irq_th_payload                 *th_payload)
+{
+	struct cam_hw_info                          *hw_info;
+	struct cam_ife_csid_ver2_hw                 *csid_hw = NULL;
+	struct cam_isp_resource_node                *res;
+	struct cam_ife_csid_ver2_reg_info           *csid_reg = NULL;
+	const struct cam_ife_csid_ver2_rdi_reg_info *path_reg = NULL;
+	struct cam_ife_csid_ver2_path_cfg           *path_cfg;
+	struct cam_hw_soc_info                      *soc_info;
+	void    __iomem                             *base;
+	uint32_t                                     val;
+
+	res  = th_payload->handler_priv;
+
+	if (!res) {
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "No private returned");
+		return -ENODEV;
+	}
+
+	hw_info = (struct cam_hw_info *)res->hw_intf->hw_priv;
+	csid_hw = (struct cam_ife_csid_ver2_hw *)hw_info->core_info;
+	csid_reg = (struct cam_ife_csid_ver2_reg_info *)
+			csid_hw->core_info->csid_reg;
+	path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
+	soc_info = &csid_hw->hw_info->soc_info;
+	base  = soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base;
+	path_reg = csid_reg->rdi_reg[res->res_id];
+
+	/* Count SOFs */
+	path_cfg->sof_cnt++;
+	CAM_DBG(CAM_ISP, "CSID[%u] Discard frame on %s path, num SOFs: %u",
+		csid_hw->hw_intf->hw_idx, res->res_name, path_cfg->sof_cnt);
+
+	/* Check with requested number of frames to be dropped */
+	if (path_cfg->sof_cnt == path_cfg->num_frames_discard) {
+		val = cam_io_r_mb(base + path_reg->ctrl_addr);
+		val |= path_reg->resume_frame_boundary;
+		cam_io_w_mb(val, base + path_reg->ctrl_addr);
+		CAM_DBG(CAM_ISP,
+			"CSID[%u] start cmd programmed for %s sof_cnt %u",
+			csid_hw->hw_intf->hw_idx,
+			res->res_name, path_cfg->sof_cnt);
+
+		cam_ife_csid_ver2_reset_discard_frame_cfg(res->res_name, csid_hw, path_cfg);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int cam_ife_csid_ver2_stop_csi2_in_err(
 	struct cam_ife_csid_ver2_hw  *csid_hw)
 {
@@ -631,6 +778,8 @@ static int cam_ife_csid_ver2_rx_err_top_half(
 				csid_hw->core_info->csid_reg;
 	csi2_reg = csid_reg->csi2_reg;
 
+	if (atomic_read(&csid_hw->discard_frame_per_path))
+		return -ENODEV;
 
 	if (csid_hw->flags.fatal_err_detected) {
 		CAM_INFO_RATE_LIMIT(CAM_ISP,
@@ -1177,6 +1326,9 @@ static int cam_ife_csid_ver2_ipp_bottom_half(
 	path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
 	irq_status_ipp = payload->irq_reg_val[path_cfg->irq_reg_idx];
 
+	CAM_DBG(CAM_ISP, "CSID[%u] IPP status:0x%x", csid_hw->hw_intf->hw_idx,
+		irq_status_ipp);
+
 	evt_info.hw_idx   = csid_hw->hw_intf->hw_idx;
 	evt_info.res_id   = CAM_IFE_PIX_PATH_RES_IPP;
 	evt_info.res_type = CAM_ISP_RESOURCE_PIX_PATH;
@@ -1292,8 +1444,6 @@ static int cam_ife_csid_ver2_ppp_bottom_half(
 	csid_reg = (struct cam_ife_csid_ver2_reg_info *)
 			csid_hw->core_info->csid_reg;
 
-	res = &csid_hw->path_res[CAM_IFE_CSID_IRQ_REG_PPP];
-
 	err_mask = csid_reg->ppp_reg->fatal_err_mask |
 			csid_reg->ppp_reg->non_fatal_err_mask;
 
@@ -1724,6 +1874,17 @@ static int cam_ife_csid_ver2_disable_path(
 		path_cfg->err_irq_handle = 0;
 	}
 
+	if (path_cfg->discard_irq_handle) {
+		rc = cam_irq_controller_unsubscribe_irq(
+			csid_hw->csid_irq_controller,
+			path_cfg->discard_irq_handle);
+		path_cfg->discard_irq_handle = 0;
+	}
+
+	/* Reset frame drop fields at stream off */
+	path_cfg->discard_init_frames = false;
+	path_cfg->num_frames_discard = 0;
+	path_cfg->sof_cnt = 0;
 	return rc;
 }
 
@@ -2539,6 +2700,41 @@ static int cam_ife_csid_ver2_init_config_pxl_path(
 	return rc;
 }
 
+static inline int cam_ife_csid_ver2_subscribe_sof_for_discard(
+	struct cam_ife_csid_ver2_path_cfg *path_cfg,
+	struct cam_ife_csid_ver2_hw       *csid_hw,
+	struct cam_isp_resource_node      *res,
+	CAM_IRQ_HANDLER_TOP_HALF           top_half_handler)
+{
+	int rc = 0;
+	uint32_t val;
+	uint32_t irq_mask[CAM_IFE_CSID_IRQ_REG_MAX] = {0};
+
+	val = IFE_CSID_VER2_PATH_INFO_INPUT_SOF;
+	irq_mask[path_cfg->irq_reg_idx] = val;
+	path_cfg->discard_irq_handle = cam_irq_controller_subscribe_irq(
+		csid_hw->csid_irq_controller,
+		CAM_IRQ_PRIORITY_1,
+		irq_mask,
+		res,
+		top_half_handler,
+		NULL,
+		NULL,
+		NULL);
+
+	if (path_cfg->discard_irq_handle < 1) {
+		CAM_ERR(CAM_ISP,
+			"CSID[%d] Subscribing input SOF failed for discarding %d",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+		rc = -EINVAL;
+	}
+
+	CAM_DBG(CAM_ISP,
+		"Subscribing input SOF for discard done res: %s rc: %d",
+		res->res_name, rc);
+	return rc;
+}
+
 static int cam_ife_csid_ver2_start_rdi_path(
 	struct cam_ife_csid_ver2_hw *csid_hw,
 	struct cam_isp_resource_node    *res)
@@ -2588,9 +2784,10 @@ static int cam_ife_csid_ver2_start_rdi_path(
 	mem_base = soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base;
 	path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
 	if (!csid_hw->flags.offline_mode) {
-		/* Resume at frame boundary */
-		cam_io_w_mb(path_reg->resume_frame_boundary,
-			mem_base + path_reg->ctrl_addr);
+		/* Resume at frame boundary if skip not requested */
+		if (!path_cfg->discard_init_frames)
+			cam_io_w_mb(path_reg->resume_frame_boundary,
+				mem_base + path_reg->ctrl_addr);
 
 		CAM_DBG(CAM_ISP, "CSID:%d Rdi res: %d",
 			csid_hw->hw_intf->hw_idx, res->res_id);
@@ -2662,6 +2859,14 @@ static int cam_ife_csid_ver2_start_rdi_path(
 		goto end;
 	}
 
+	if (path_cfg->discard_init_frames) {
+		rc = cam_ife_csid_ver2_subscribe_sof_for_discard(
+			path_cfg, csid_hw, res,
+			cam_ife_csid_ver2_discard_sof_rdi_top_half);
+		if (rc)
+			goto end;
+	}
+
 	val = path_reg->fatal_err_mask | path_reg->non_fatal_err_mask;
 	irq_mask[path_cfg->irq_reg_idx] = val;
 	path_cfg->err_irq_handle = cam_irq_controller_subscribe_irq(
@@ -2790,6 +2995,14 @@ static int cam_ife_csid_ver2_start_ipp_path(
 		goto end;
 	}
 
+	if (path_cfg->discard_init_frames) {
+		rc = cam_ife_csid_ver2_subscribe_sof_for_discard(
+			path_cfg, csid_hw, res,
+			cam_ife_csid_ver2_discard_sof_pix_top_half);
+		if (rc)
+			goto end;
+	}
+
 	val = path_reg->fatal_err_mask | path_reg->non_fatal_err_mask;
 	irq_mask[path_cfg->irq_reg_idx] = val;
 	path_cfg->err_irq_handle = cam_irq_controller_subscribe_irq(
@@ -2831,9 +3044,11 @@ static int cam_ife_csid_ver2_start_ipp_path(
 	/*
 	 * Resume at frame boundary if Master or No Sync.
 	 * Slave will get resume command from Master.
+	 * If init frame drop requested skip resume
 	 */
-	if (path_cfg->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
-		path_cfg->sync_mode == CAM_ISP_HW_SYNC_NONE)
+	if ((!path_cfg->discard_init_frames) &&
+		(path_cfg->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
+		path_cfg->sync_mode == CAM_ISP_HW_SYNC_NONE))
 		val |= path_reg->resume_frame_boundary;
 
 	cam_io_w_mb(val, mem_base + path_reg->ctrl_addr);
@@ -2940,9 +3155,11 @@ static int cam_ife_csid_ver2_start_ppp_path(
 	/*
 	 * Resume at frame boundary if Master or No Sync.
 	 * Slave will get resume command from Master.
+	 * If init frame drop requested skip resume
 	 */
-	if (csid_hw->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
-		csid_hw->sync_mode == CAM_ISP_HW_SYNC_NONE)
+	if ((!path_cfg->discard_init_frames) &&
+		(csid_hw->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
+		csid_hw->sync_mode == CAM_ISP_HW_SYNC_NONE))
 		val |= path_reg->resume_frame_boundary;
 
 	cam_io_w_mb(val, mem_base + path_reg->ctrl_addr);
@@ -2980,6 +3197,14 @@ static int cam_ife_csid_ver2_start_ppp_path(
 		goto end;
 	}
 
+	if (path_cfg->discard_init_frames) {
+		rc = cam_ife_csid_ver2_subscribe_sof_for_discard(
+			path_cfg, csid_hw, res,
+			cam_ife_csid_ver2_discard_sof_pix_top_half);
+		if (rc)
+			goto end;
+	}
+
 	val = path_reg->fatal_err_mask | path_reg->non_fatal_err_mask;
 	irq_mask[path_cfg->irq_reg_idx] = val;
 	path_cfg->err_irq_handle = cam_irq_controller_subscribe_irq(
@@ -3661,6 +3886,7 @@ int cam_ife_csid_ver2_stop(void *hw_priv,
 		csid_hw->hw_intf->hw_idx,
 		csid_stop->num_res);
 
+	atomic_set(&csid_hw->discard_frame_per_path, 0);
 	mutex_lock(&csid_hw->hw_info->hw_mutex);
 	for (i = 0; i < csid_stop->num_res; i++) {
 
@@ -4197,6 +4423,62 @@ static int cam_ife_csid_ver2_dual_sync_cfg(
 	return 0;
 }
 
+static int cam_ife_csid_ver2_set_discard_frame_cfg(
+	struct cam_ife_csid_ver2_hw    *csid_hw,
+	void                           *cmd_args)
+{
+	struct cam_isp_resource_node                 *res;
+	struct cam_ife_csid_ver2_path_cfg            *path_cfg;
+	struct cam_ife_csid_discard_init_frame_args  *discard_config = NULL;
+
+	if (!csid_hw)
+		return -EINVAL;
+
+	discard_config =
+		(struct cam_ife_csid_discard_init_frame_args *)cmd_args;
+
+	if (discard_config->num_frames == 0xffffffff) {
+		CAM_ERR(CAM_ISP, "Invalid number of frames: 0x%x",
+			discard_config->num_frames);
+		return -EINVAL;
+	}
+
+	if (!discard_config->num_frames) {
+		CAM_DBG(CAM_ISP, "No discard requested");
+		return 0;
+	}
+
+	res = discard_config->res;
+	if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH ||
+		res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) {
+		CAM_ERR(CAM_ISP, "CSID[%u] Invalid res_type: %d res id: %d",
+			csid_hw->hw_intf->hw_idx, res->res_type,
+			res->res_id);
+		return -EINVAL;
+	}
+
+	/* Handle first stream on and consecutive streamons post flush */
+	if ((res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) ||
+		(res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW)) {
+		/* Skip if already set */
+		path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
+		if (path_cfg->discard_init_frames)
+			goto end;
+
+		path_cfg->discard_init_frames = true;
+		path_cfg->sof_cnt = 0;
+		path_cfg->num_frames_discard = discard_config->num_frames;
+		atomic_inc(&csid_hw->discard_frame_per_path);
+		CAM_DBG(CAM_ISP,
+			"CSID[%u] discard num of frames: %u for path: %s discard_ref_cnt: %u",
+			csid_hw->hw_intf->hw_idx, discard_config->num_frames, res->res_name,
+			atomic_read(&csid_hw->discard_frame_per_path));
+	}
+
+end:
+	return 0;
+}
+
 static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
 {
@@ -4268,6 +4550,9 @@ static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 		*((struct cam_hw_soc_info **)cmd_args) = soc_info;
 		break;
 	}
+	case CAM_ISP_HW_CMD_CSID_DISCARD_INIT_FRAMES:
+		rc = cam_ife_csid_ver2_set_discard_frame_cfg(csid_hw, cmd_args);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);
@@ -4526,6 +4811,7 @@ int cam_ife_csid_hw_ver2_init(struct cam_hw_intf *hw_intf,
 	spin_lock_init(&csid_hw->hw_info->hw_lock);
 	spin_lock_init(&csid_hw->lock_state);
 	init_completion(&csid_hw->hw_info->hw_complete);
+	atomic_set(&csid_hw->discard_frame_per_path, 0);
 
 	for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++)
 		init_completion(&csid_hw->irq_complete[i]);

+ 36 - 26
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h

@@ -144,32 +144,36 @@ struct cam_ife_csid_ver2_camif_data {
 /*
  * struct cam_ife_csid_ver2_path_cfg: place holder for path parameters
  *
- * @camif_data:       CAMIF data
- * @error_ts:         Error timestamp
- * @cid:              cid value for path
- * @in_format:        input format
- * @out_format:       output format
- * @start_pixel:      start pixel for horizontal crop
- * @end_pixel:        end pixel for horizontal  crop
- * @start_line:       start line for vertical crop
- * @end_line:         end line for vertical crop
- * @width:            width of incoming data
- * @height:           height of incoming data
- * @master_idx:       master idx
- * @horizontal_bin:   horizontal binning enable/disable on path
- * @vertical_bin:     vertical binning enable/disable on path
- * @qcfa_bin    :     qcfa binning enable/disable on path
- * @hor_ver_bin :     horizontal vertical binning enable/disable on path
- * @num_bytes_out:    Number of bytes out
- * @pix_pattern:      Pixel Pattern
- * @irq_handle:       IRQ handle
- * @err_irq_handle:   Error IRQ handle
- * @irq_reg_idx:      IRQ Reg index
- * @sync_mode   :     Sync mode--> master/slave/none
- * @vfr_en   :        flag to indicate if variable frame rate is enabled
- * @frame_id_dec_en:  flag to indicate if frame id decoding is enabled
- * @crop_enable:      flag to indicate crop enable
- * @drop_enable:      flag to indicate drop enable
+ * @camif_data:          CAMIF data
+ * @error_ts:            Error timestamp
+ * @cid:                 cid value for path
+ * @in_format:           input format
+ * @out_format:          output format
+ * @start_pixel:         start pixel for horizontal crop
+ * @end_pixel:           end pixel for horizontal  crop
+ * @start_line:          start line for vertical crop
+ * @end_line:            end line for vertical crop
+ * @width:               width of incoming data
+ * @height:              height of incoming data
+ * @master_idx:          master idx
+ * @horizontal_bin:      horizontal binning enable/disable on path
+ * @vertical_bin:        vertical binning enable/disable on path
+ * @qcfa_bin    :        qcfa binning enable/disable on path
+ * @hor_ver_bin :        horizontal vertical binning enable/disable on path
+ * @num_bytes_out:       Number of bytes out
+ * @pix_pattern:         Pixel Pattern
+ * @irq_handle:          IRQ handle
+ * @err_irq_handle:      Error IRQ handle
+ * @discard_irq_handle:  IRQ handle for SOF when discarding initial frames
+ * @irq_reg_idx:         IRQ Reg index
+ * @sof_cnt:             SOF counter
+ * @num_frames_discard:  number of frames to discard
+ * @sync_mode   :        Sync mode--> master/slave/none
+ * @vfr_en   :           flag to indicate if variable frame rate is enabled
+ * @frame_id_dec_en:     flag to indicate if frame id decoding is enabled
+ * @crop_enable:         flag to indicate crop enable
+ * @drop_enable:         flag to indicate drop enable
+ * @discard_init_frames: discard initial frames
  *
  */
 struct cam_ife_csid_ver2_path_cfg {
@@ -194,13 +198,17 @@ struct cam_ife_csid_ver2_path_cfg {
 	uint32_t                            pix_pattern;
 	uint32_t                            irq_handle;
 	uint32_t                            err_irq_handle;
+	uint32_t                            discard_irq_handle;
 	uint32_t                            irq_reg_idx;
+	uint32_t                            sof_cnt;
+	uint32_t                            num_frames_discard;
 	enum cam_isp_hw_sync_mode           sync_mode;
 	bool                                vfr_en;
 	bool                                frame_id_dec_en;
 	bool                                crop_enable;
 	bool                                drop_enable;
 	bool                                handle_camif_irq;
+	bool                                discard_init_frames;
 };
 
 struct cam_ife_csid_ver2_top_reg_info {
@@ -606,6 +614,7 @@ struct cam_ife_csid_ver2_reg_info {
  * @buf_done_irq_handle:      Buf done irq handle
  * @sync_mode:                Master/Slave modes
  * @mup:                      MUP for incoming VC of next frame
+ * @discard_frame_per_path:   Count of paths dropping initial frames
  *
  */
 struct cam_ife_csid_ver2_hw {
@@ -646,6 +655,7 @@ struct cam_ife_csid_ver2_hw {
 	int                                    buf_done_irq_handle;
 	enum cam_isp_hw_sync_mode              sync_mode;
 	uint32_t                               mup;
+	atomic_t                               discard_frame_per_path;
 };
 
 int cam_ife_csid_hw_ver2_init(struct cam_hw_intf  *csid_hw_intf,

+ 12 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -382,4 +382,16 @@ struct cam_ife_csid_offline_cmd_update_args {
 struct cam_ife_csid_mup_update_args {
 	uint32_t                           mup;
 };
+
+/*
+ * struct cam_ife_csid_discard_init_frame_args:
+ *
+ * @num_frames: Num frames to discard
+ * @res: Node res for this path
+ */
+struct cam_ife_csid_discard_init_frame_args {
+	uint32_t                          num_frames;
+	struct cam_isp_resource_node     *res;
+};
+
 #endif /* _CAM_CSID_HW_INTF_H_ */

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -151,6 +151,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_IFE_CSID_PROGRAM_OFFLINE_CMD,
 	CAM_IFE_CSID_SET_DUAL_SYNC_CONFIG,
 	CAM_ISP_HW_CMD_CSID_MUP_UPDATE,
+	CAM_ISP_HW_CMD_CSID_DISCARD_INIT_FRAMES,
 	CAM_ISP_HW_CMD_BUF_UPDATE,
 	CAM_ISP_HW_CMD_BUF_UPDATE_RM,
 	CAM_ISP_HW_NOTIFY_OVERFLOW,