Browse Source

Merge "msm: camera: isp: Add support to discard set number of frames" into camera-kernel.lnx.5.0

Haritha Chintalapati 4 years ago
parent
commit
5427c398a4

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

@@ -7318,6 +7318,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,
@@ -8439,6 +8487,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:
@@ -8878,6 +8946,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,