Эх сурвалжийг харах

Merge "msm: camera: isp: Add support for AEB use-case" into camera-kernel.lnx.5.0

Camera Software Integration 4 жил өмнө
parent
commit
16710c7458

+ 25 - 0
drivers/cam_isp/cam_isp_context.c

@@ -5579,6 +5579,8 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 		(param.op_flags & CAM_IFE_CTX_APPLY_DEFAULT_CFG);
 	ctx_isp->support_consumed_addr =
 		(param.op_flags & CAM_IFE_CTX_CONSUME_ADDR_EN);
+	ctx_isp->aeb_enabled =
+		(param.op_flags & CAM_IFE_CTX_AEB_EN);
 
 	/* Query the context has rdi only resource */
 	hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map;
@@ -6387,6 +6389,28 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context,
 		(struct cam_isp_context *)ctx->ctx_priv;
 
 	spin_lock(&ctx->lock);
+	/*
+	 * In case of custom AEB ensure first exposure frame has
+	 * not moved forward with its settings without second/third
+	 * expoure frame coming in. If this scenario occurs flag as error,
+	 * and recover
+	 */
+	if ((ctx_isp->aeb_enabled) && (evt_id == CAM_ISP_HW_EVENT_SOF)) {
+		bool is_secondary_evt =
+			((struct cam_isp_hw_sof_event_data *)evt_data)->is_secondary_evt;
+
+		if (is_secondary_evt) {
+			if ((ctx_isp->substate_activated ==
+				CAM_ISP_CTX_ACTIVATED_APPLIED) ||
+				(ctx_isp->substate_activated ==
+				CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED)) {
+				CAM_ERR(CAM_ISP,
+					"AEB settings mismatch between exposures - needs a reset");
+				rc = -EAGAIN;
+			}
+			goto end;
+		}
+	}
 
 	trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id,
 		__cam_isp_ctx_get_event_ts(evt_id, evt_data));
@@ -6408,6 +6432,7 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context,
 	CAM_DBG(CAM_ISP, "Exit: State %d Substate[%s]",
 		ctx->state, __cam_isp_ctx_substate_val_to_type(
 		ctx_isp->substate_activated));
+end:
 	spin_unlock(&ctx->lock);
 	return rc;
 }

+ 2 - 0
drivers/cam_isp/cam_isp_context.h

@@ -269,6 +269,7 @@ struct cam_isp_context_event_record {
  * @custom_enabled:            Custom HW enabled for this ctx
  * @use_frame_header_ts:       Use frame header for qtimer ts
  * @support_consumed_addr:     Indicate whether HW has last consumed addr reg
+ * @aeb_enabled:               Indicate if stream is for AEB
  * @apply_in_progress          Whether request apply is in progress
  * @use_default_apply:         Use default settings in case of frame skip
  * @init_timestamp:            Timestamp at which this context is initialized
@@ -319,6 +320,7 @@ struct cam_isp_context {
 	bool                                  custom_enabled;
 	bool                                  use_frame_header_ts;
 	bool                                  support_consumed_addr;
+	bool                                  aeb_enabled;
 	atomic_t                              apply_in_progress;
 	bool                                  use_default_apply;
 	unsigned int                          init_timestamp;

+ 150 - 10
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -3403,6 +3403,21 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
 			CAM_DBG(CAM_ISP, "setting inline shdr mode for res: 0x%x",
 				out_port->res_type);
 			csid_acquire.sfe_inline_shdr = true;
+
+			/*
+			 * Merged output will only be from the first n RDIs
+			 * starting from RDI0. Any other RDI[1:2] resource
+			 * if only being dumped will be considered as a
+			 * no merge resource
+			 */
+			if ((ife_ctx->flags.is_aeb_mode) &&
+				((out_port->res_type - CAM_ISP_SFE_OUT_RES_RDI_0) >=
+				ife_ctx->sfe_info.num_fetches)) {
+				csid_acquire.en_secondary_evt = true;
+				CAM_DBG(CAM_ISP,
+					"Secondary evt enabled for path: 0x%x",
+					out_port->res_type);
+			}
 		}
 
 		/*
@@ -4201,6 +4216,10 @@ static int cam_ife_mgr_acquire_hw_for_ctx(
 	ife_ctx->flags.dsp_enabled = (bool)in_port->dsp_mode;
 	ife_ctx->flags.is_dual = (bool)in_port->usage_type;
 
+	/* Update aeb mode for the given in_port once */
+	if ((in_port->aeb_mode) && (!ife_ctx->flags.is_aeb_mode))
+		ife_ctx->flags.is_aeb_mode = true;
+
 	/* get root node resource */
 	rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port);
 	if (rc) {
@@ -4514,6 +4533,18 @@ static inline int cam_ife_mgr_hw_check_in_res_type(
 	}
 }
 
+static inline void cam_ife_mgr_acquire_get_feature_flag_params(
+	struct cam_isp_in_port_info_v2      *in,
+	struct cam_isp_in_port_generic_info *in_port)
+{
+	in_port->secure_mode              = in->feature_flag & CAM_ISP_PARAM_FETCH_SECURITY_MODE;
+	in_port->dynamic_sensor_switch_en = in->feature_flag & CAM_ISP_DYNAMIC_SENOR_SWITCH_EN;
+	in_port->can_use_lite             = in->feature_flag & CAM_ISP_CAN_USE_LITE_MODE;
+	in_port->sfe_binned_epoch_cfg     = in->feature_flag & CAM_ISP_SFE_BINNED_EPOCH_CFG_ENABLE;
+	in_port->epd_supported            = in->feature_flag & CAM_ISP_EPD_SUPPORT;
+	in_port->aeb_mode                 = in->feature_flag & CAM_ISP_AEB_MODE_EN;
+}
+
 static int cam_ife_mgr_acquire_get_unified_structure_v2(
 	struct cam_isp_acquire_hw_info *acquire_hw_info,
 	uint32_t offset, uint32_t *input_size,
@@ -4588,16 +4619,8 @@ static int cam_ife_mgr_acquire_get_unified_structure_v2(
 	in_port->num_out_res              =  in->num_out_res;
 	in_port->sfe_in_path_type         =  (in->sfe_in_path_type & 0xFFFF);
 	in_port->sfe_ife_enable           =  in->sfe_in_path_type >> 16;
-	in_port->secure_mode              = (in->feature_flag &
-		                           CAM_ISP_PARAM_FETCH_SECURITY_MODE);
-	in_port->dynamic_sensor_switch_en = (in->feature_flag &
-		                           CAM_ISP_DYNAMIC_SENOR_SWITCH_EN);
-	in_port->can_use_lite             =  in->feature_flag &
-						CAM_ISP_CAN_USE_LITE_MODE;
-	in_port->sfe_binned_epoch_cfg     = (in->feature_flag &
-		CAM_ISP_SFE_BINNED_EPOCH_CFG_ENABLE);
-	in_port->epd_supported            =  (in->feature_flag &
-					   CAM_ISP_EPD_SUPPORT);
+
+	cam_ife_mgr_acquire_get_feature_flag_params(in, in_port);
 
 	in_port->data = kcalloc(in->num_out_res,
 		sizeof(struct cam_isp_out_port_generic_info),
@@ -4874,6 +4897,9 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 		acquire_args->op_flags |=
 			CAM_IFE_CTX_SFE_EN;
 
+	if (ife_ctx->flags.is_aeb_mode)
+		acquire_args->op_flags |= CAM_IFE_CTX_AEB_EN;
+
 	ife_ctx->flags.ctx_in_use = true;
 	ife_ctx->num_reg_dump_buf = 0;
 
@@ -8376,6 +8402,50 @@ static inline int cam_isp_validate_bw_limiter_blob(
 	return 0;
 }
 
+static int cam_isp_blob_ife_init_config_update(
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_isp_init_config        *init_config)
+{
+	int i, rc = -EINVAL;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
+	struct cam_isp_hw_mgr_res             *hw_mgr_res;
+	struct cam_isp_hw_init_config_update   init_cfg_update;
+
+	ctx = prepare->ctxt_to_hw_map;
+
+	/* Assign init config */
+	init_cfg_update.init_config = init_config;
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF)
+				continue;
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				init_cfg_update.node_res =
+					hw_mgr_res->hw_res[i];
+				CAM_DBG(CAM_ISP, "Init config update for res_id: %u",
+					hw_mgr_res->res_id);
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE,
+					&init_cfg_update,
+					sizeof(
+					struct cam_isp_hw_init_config_update));
+				if (rc)
+					CAM_ERR(CAM_ISP, "Init cfg update failed rc: %d", rc);
+			}
+		}
+	}
+
+	return rc;
+}
+
 static int cam_isp_packet_generic_blob_handler(void *user_data,
 	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
 {
@@ -8959,6 +9029,38 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 			fps_config->fps, ife_mgr_ctx->ctx_index,
 			prepare_hw_data->packet->header.request_id);
 
+	}
+		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_INIT_CONFIG: {
+		struct cam_isp_init_config            *init_config;
+		struct cam_isp_prepare_hw_update_data *prepare_hw_data;
+
+		prepare_hw_data = (struct cam_isp_prepare_hw_update_data *)
+			prepare->priv;
+
+		if (prepare_hw_data->packet_opcode_type !=
+			CAM_ISP_PACKET_INIT_DEV) {
+			CAM_ERR(CAM_ISP,
+				"Init config blob not supported for packet type: %u req: %llu",
+				prepare_hw_data->packet_opcode_type,
+				 prepare->packet->header.request_id);
+			return -EINVAL;
+		}
+
+		if (blob_size < sizeof(struct cam_isp_init_config)) {
+			CAM_ERR(CAM_ISP,
+				"Invalid init config blob size %u expected %u",
+				blob_size, sizeof(struct cam_isp_init_config));
+			return -EINVAL;
+		}
+
+		init_config = (struct cam_isp_init_config *)blob_data;
+		rc = cam_isp_blob_ife_init_config_update(
+			prepare, init_config);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"Init config failed for req: %llu rc: %d",
+				 prepare->packet->header.request_id, rc);
 	}
 		break;
 	default:
@@ -9423,6 +9525,7 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 	case CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_BLANKING_CONFIG:
 	case CAM_ISP_GENERIC_BLOB_TYPE_DISCARD_INITIAL_FRAMES:
 	case CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG:
+	case CAM_ISP_GENERIC_BLOB_TYPE_INIT_CONFIG:
 		break;
 	default:
 		CAM_WARN(CAM_ISP, "Invalid blob type: %u", blob_type);
@@ -11594,6 +11697,40 @@ static int cam_ife_hw_mgr_handle_hw_epoch(
 	return 0;
 }
 
+static int cam_ife_hw_mgr_handle_csid_camif_sof(
+	struct cam_ife_hw_mgr_ctx            *ctx,
+	struct cam_isp_hw_event_info         *event_info)
+{
+	struct cam_isp_hw_sof_event_data      sof_done_event_data;
+	cam_hw_event_cb_func                  ife_hw_irq_sof_cb;
+
+	/*
+	 * Currently SOF update is from IFE TOP - this CSID CAMIF SOF
+	 * is only to monitor second/third exposure frame for custom
+	 * AEB use-case hence the checks
+	 */
+	if (!(ctx->flags.is_aeb_mode && event_info->is_secondary_evt)) {
+		CAM_DBG(CAM_ISP,
+			"Received CSID CAMIF SOF aeb_mode: %d secondary_evt: %d - skip update",
+			ctx->flags.is_aeb_mode, event_info->is_secondary_evt);
+		return 0;
+	}
+
+	CAM_DBG(CAM_ISP,
+		"Received CSID CAMIF SOF res: %d as secondary evt",
+		event_info->res_id);
+
+	ife_hw_irq_sof_cb = ctx->common.event_cb;
+	sof_done_event_data.is_secondary_evt = true;
+	sof_done_event_data.boot_time = 0;
+	sof_done_event_data.timestamp = 0;
+
+	ife_hw_irq_sof_cb(ctx->common.cb_priv,
+		CAM_ISP_HW_EVENT_SOF, (void *)&sof_done_event_data);
+
+	return 0;
+}
+
 static int cam_ife_hw_mgr_handle_hw_sof(
 	void                                 *ctx,
 	void                                 *evt_info)
@@ -11604,6 +11741,9 @@ static int cam_ife_hw_mgr_handle_hw_sof(
 	struct cam_isp_hw_sof_event_data      sof_done_event_data;
 	struct timespec64 ts;
 
+	if (event_info->hw_type == CAM_ISP_HW_TYPE_CSID)
+		return cam_ife_hw_mgr_handle_csid_camif_sof(ctx, event_info);
+
 	memset(&sof_done_event_data, 0, sizeof(sof_done_event_data));
 
 	ife_hw_irq_sof_cb = ife_hw_mgr_ctx->common.event_cb;

+ 2 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h

@@ -141,6 +141,7 @@ struct cam_ife_hw_mgr_sfe_info {
  * @is_sfe_fs:           indicate if stream is for inline SFE FS
  * @dump_on_flush:       Set if reg dump triggered on flush
  * @dump_on_error:       Set if reg dump triggered on error
+ * @custom_aeb_mode:     Set if custom AEB stream
  * @sys_cache_usage:     Per context sys cache usage
  *                       The corresponding index will be set
  *                       for the cache type
@@ -162,6 +163,7 @@ struct cam_ife_hw_mgr_ctx_flags {
 	bool   is_sfe_fs;
 	bool   dump_on_flush;
 	bool   dump_on_error;
+	bool   is_aeb_mode;
 	bool   sys_cache_usage[CAM_LLCC_MAX];
 };
 

+ 5 - 2
drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h

@@ -38,6 +38,7 @@
 #define CAM_IFE_CTX_CONSUME_ADDR_EN    BIT(2)
 #define CAM_IFE_CTX_APPLY_DEFAULT_CFG  BIT(3)
 #define CAM_IFE_CTX_SFE_EN             BIT(4)
+#define CAM_IFE_CTX_AEB_EN             BIT(5)
 
 /*
  * Maximum configuration entry size  - This is based on the
@@ -215,11 +216,13 @@ struct cam_isp_prepare_hw_update_data {
 /**
  * struct cam_isp_hw_sof_event_data - Event payload for CAM_HW_EVENT_SOF
  *
- * @timestamp:   Time stamp for the sof event
- * @boot_time:   Boot time stamp for the sof event
+ * @is_secondary_event: Event notified as secondary
+ * @timestamp         : Time stamp for the sof event
+ * @boot_time         : Boot time stamp for the sof event
  *
  */
 struct cam_isp_hw_sof_event_data {
+	bool           is_secondary_evt;
 	uint64_t       timestamp;
 	uint64_t       boot_time;
 };

+ 32 - 7
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c

@@ -1495,6 +1495,7 @@ static int cam_ife_csid_ver2_rdi_bottom_half(
 	uint32_t                                     err_type = 0;
 	uint32_t                                     expected_frame = 0;
 	uint32_t                                     actual_frame = 0;
+	bool                                         skip_sof_notify = false;
 	struct cam_isp_hw_event_info                 evt_info;
 
 	if (!handler_priv || !evt_payload_priv) {
@@ -1567,9 +1568,6 @@ static int cam_ife_csid_ver2_rdi_bottom_half(
 		goto end;
 	}
 
-	if (!path_cfg->handle_camif_irq)
-		goto end;
-
 	if (!csid_hw->event_cb) {
 		CAM_DBG(CAM_ISP, "CSID[%u] no cb registered",
 				csid_hw->hw_intf->hw_idx);
@@ -1578,13 +1576,30 @@ static int cam_ife_csid_ver2_rdi_bottom_half(
 
 	evt_info.res_id = res->res_id;
 	evt_info.reg_val = irq_status_rdi;
+	evt_info.hw_type = CAM_ISP_HW_TYPE_CSID;
+
+	/* Check for secondary evt */
+	if ((path_cfg->en_secondary_evt) &&
+		(irq_status_rdi & IFE_CSID_VER2_PATH_INFO_INPUT_SOF)) {
+		evt_info.is_secondary_evt = true;
+		CAM_DBG(CAM_ISP,
+			"CSID[%u] RDI:%u notify CAMIF SOF as secondary evt",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+
+		csid_hw->event_cb(csid_hw->token,
+			CAM_ISP_HW_EVENT_SOF, (void *)&evt_info);
+		skip_sof_notify = true;
+	}
+
+	if (!path_cfg->handle_camif_irq)
+		goto end;
 
 	if (irq_status_rdi & IFE_CSID_VER2_PATH_CAMIF_EOF)
 		csid_hw->event_cb(csid_hw->token,
 				CAM_ISP_HW_EVENT_EOF,
 				(void *)&evt_info);
 
-	if (irq_status_rdi & IFE_CSID_VER2_PATH_CAMIF_SOF)
+	if (!skip_sof_notify && (irq_status_rdi & IFE_CSID_VER2_PATH_CAMIF_SOF))
 		csid_hw->event_cb(csid_hw->token,
 				CAM_ISP_HW_EVENT_SOF,
 				(void *)&evt_info);
@@ -1885,6 +1900,8 @@ static int cam_ife_csid_hw_ver2_config_path_data(
 	path_cfg->vertical_bin = reserve->in_port->vertical_bin;
 	path_cfg->qcfa_bin = reserve->in_port->qcfa_bin;
 	path_cfg->num_bytes_out = reserve->in_port->num_bytes_out;
+	path_cfg->en_secondary_evt = reserve->en_secondary_evt;
+
 	if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) {
 		path_cfg->start_pixel = reserve->in_port->left_start;
 		path_cfg->end_pixel = reserve->in_port->left_stop;
@@ -1958,9 +1975,9 @@ static int cam_ife_csid_hw_ver2_config_rx(
 		reserve->in_port->lane_num;
 	csid_hw->res_type = reserve->in_port->res_type;
 	csid_hw->rx_cfg.dynamic_sensor_switch_en =
-		(bool)reserve->in_port->dynamic_sensor_switch_en;
-	csid_hw->rx_cfg.epd_supported =
-		reserve->in_port->epd_supported;
+		reserve->in_port->dynamic_sensor_switch_en;
+	if (reserve->in_port->epd_supported)
+		csid_hw->rx_cfg.epd_supported = 1;
 
 	switch (reserve->in_port->res_type) {
 	case CAM_ISP_IFE_IN_RES_TPG:
@@ -2769,6 +2786,14 @@ static int cam_ife_csid_ver2_program_rdi_path(
 		path_cfg->handle_camif_irq = true;
 	}
 
+	/* Currently CAMIF SOF is the secondary evt enabled for HW mgr */
+	if (path_cfg->en_secondary_evt) {
+		val |= IFE_CSID_VER2_PATH_CAMIF_SOF;
+		CAM_DBG(CAM_ISP,
+			"Enable camif SOF irq for res: %s",
+			res->res_name);
+	}
+
 	res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 
 	path_cfg->irq_reg_idx =

+ 3 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h

@@ -157,6 +157,8 @@ struct cam_ife_csid_ver2_camif_data {
  * @crop_enable:         flag to indicate crop enable
  * @drop_enable:         flag to indicate drop enable
  * @discard_init_frames: discard initial frames
+ * @en_secondary_evt:    Enable secondary evt for this path, to notify
+ *                       hw manager
  *
  */
 struct cam_ife_csid_ver2_path_cfg {
@@ -191,6 +193,7 @@ struct cam_ife_csid_ver2_path_cfg {
 	bool                                drop_enable;
 	bool                                handle_camif_irq;
 	bool                                discard_init_frames;
+	bool                                en_secondary_evt;
 };
 
 struct cam_ife_csid_ver2_top_reg_info {

+ 10 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -132,11 +132,13 @@ struct cam_isp_in_port_generic_info {
 	uint32_t                        lite_path_count;
 	uint32_t                        sfe_in_path_type;
 	uint32_t                        sfe_ife_enable;
-	uint32_t                        secure_mode;
-	uint32_t                        dynamic_sensor_switch_en;
-	uint32_t                        can_use_lite;
-	uint32_t                        sfe_binned_epoch_cfg;
-	uint32_t                        epd_supported;
+	uint32_t                        epoch_factor;
+	bool                            secure_mode;
+	bool                            dynamic_sensor_switch_en;
+	bool                            can_use_lite;
+	bool                            sfe_binned_epoch_cfg;
+	bool                            epd_supported;
+	bool                            aeb_mode;
 	struct cam_isp_out_port_generic_info    *data;
 };
 
@@ -162,6 +164,8 @@ struct cam_isp_in_port_generic_info {
  * @sfe_inline_shdr:     Flag to indicate if sfe is inline shdr
  * @is_offline :         Flag to indicate offline
  * @need_top_cfg:        Flag to indicate if top cfg is needed
+ * @en_secondary_evt:    Flag to enable secondary event for the given resource
+ *                       depending on the use-case
  * @tasklet:             Tasklet to schedule bottom halves
  * @buf_done_controller: IRQ controller for buf done for version 680 hw
  * @cdm_ops:             CDM Ops
@@ -186,6 +190,7 @@ struct cam_csid_hw_reserve_resource_args {
 	bool                                      sfe_inline_shdr;
 	bool                                      is_offline;
 	bool                                      need_top_cfg;
+	bool                                      en_secondary_evt;
 	void                                     *tasklet;
 	void                                     *buf_done_controller;
 	void                                     *cdm_ops;

+ 25 - 8
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -197,6 +197,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG,
 	CAM_ISP_HW_CMD_RM_ENABLE_DISABLE,
 	CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE,
+	CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE,
 	CAM_ISP_HW_CMD_MAX,
 };
 
@@ -270,19 +271,21 @@ struct cam_isp_blanking_config {
 /*
  * struct cam_isp_hw_event_info:
  *
- * @Brief:          Structure to pass event details to hw mgr
+ * @Brief:             Structure to pass event details to hw mgr
  *
- * @res_type:       Type of IFE resource
- * @res_id:         Unique resource ID
- * @hw_idx:         IFE hw index
- * @err_type:       Error type if any
- * @reg_val:        Any critical register value captured during irq handling
- * @hw_type:        Hw Type sending the event
- * @in_core_idx:   Input core type if CSID error evt
+ * @res_type:          Type of IFE resource
+ * @is_secondary_evt:  Indicates if event was requested by hw mgr
+ * @res_id:            Unique resource ID
+ * @hw_idx:            IFE hw index
+ * @err_type:          Error type if any
+ * @reg_val:           Any critical register value captured during irq handling
+ * @hw_type:           Hw Type sending the event
+ * @in_core_idx:       Input core type if CSID error evt
  *
  */
 struct cam_isp_hw_event_info {
 	enum cam_isp_resource_type     res_type;
+	bool                           is_secondary_evt;
 	uint32_t                       res_id;
 	uint32_t                       hw_idx;
 	uint32_t                       err_type;
@@ -502,4 +505,18 @@ struct cam_isp_hw_path_port_map {
 	uint32_t                entry[CAM_ISP_HW_PATH_PORT_MAP_MAX][2];
 };
 
+
+/**
+ * struct cam_isp_hw_init_config_update:
+ *
+ * @Brief:         Init config params for CSID/SFE/IFE resources
+ *
+ * @node_res:      HW Resource
+ * @init_config:   Init config params from userspace
+ */
+struct cam_isp_hw_init_config_update {
+	struct cam_isp_resource_node   *node_res;
+	struct cam_isp_init_config     *init_config;
+};
+
 #endif /* _CAM_ISP_HW_H_ */

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c

@@ -516,6 +516,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD:
 	case CAM_ISP_HW_CMD_GET_PATH_PORT_MAP:
 	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
+	case CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE:
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			arg_size);

+ 42 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c

@@ -69,6 +69,7 @@ struct cam_vfe_mux_ver4_data {
 	uint32_t                           qcfa_bin;
 	uint32_t                           dual_hw_idx;
 	uint32_t                           is_dual;
+	uint32_t                           epoch_factor;
 	bool                               is_fe_enabled;
 	bool                               is_offline;
 	bool                               is_lite;
@@ -1063,6 +1064,30 @@ static int cam_vfe_core_config_control(
 	return 0;
 }
 
+static int cam_vfe_init_config_update(
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_isp_hw_init_config_update *init_cfg = cmd_args;
+	struct cam_isp_resource_node *rsrc_node = init_cfg->node_res;
+	struct cam_vfe_mux_ver4_data *mux_data = rsrc_node->res_priv;
+
+	if (arg_size != sizeof(struct cam_isp_hw_init_config_update)) {
+		CAM_ERR(CAM_ISP, "Invalid args size expected: %zu actual: %zu",
+			sizeof(struct cam_isp_hw_init_config_update),
+			arg_size);
+		return -EINVAL;
+	}
+
+	mux_data->epoch_factor =
+		init_cfg->init_config->epoch_cfg.epoch_factor;
+
+	CAM_DBG(CAM_ISP,
+		"Init Update for res_name: %s epoch_factor: %u%%",
+		rsrc_node->res_name, mux_data->epoch_factor);
+
+	return 0;
+}
+
 static int cam_vfe_top_ver4_mux_get_reg_update(
 	struct cam_vfe_top_ver4_priv *top_priv,
 	void *cmd_args, uint32_t arg_size)
@@ -1185,7 +1210,7 @@ int cam_vfe_top_acquire_resource(
 		acquire_data->vfe_in.in_port->horizontal_bin;
 	res_data->vbi_value      = 0;
 	res_data->hbi_value      = 0;
-	res_data->sfe_binned_epoch_cfg = (bool)
+	res_data->sfe_binned_epoch_cfg =
 		acquire_data->vfe_in.in_port->sfe_binned_epoch_cfg;
 
 	if (res_data->is_dual)
@@ -1472,6 +1497,9 @@ int cam_vfe_top_ver4_process_cmd(void *device_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
 		rc = cam_vfe_top_apply_clk_bw_update(&top_priv->top_common, cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE:
+		rc = cam_vfe_init_config_update(cmd_args, arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);
@@ -1621,6 +1649,7 @@ static int cam_vfe_handle_irq_bottom_half(void *handler_priv,
 		irq_status[i] = payload->irq_reg_val[i];
 
 	evt_info.hw_idx   = vfe_res->hw_intf->hw_idx;
+	evt_info.hw_type  = CAM_ISP_HW_TYPE_VFE;
 	evt_info.res_id   = vfe_res->res_id;
 	evt_info.res_type = vfe_res->res_type;
 	evt_info.reg_val = 0;
@@ -1781,7 +1810,7 @@ static int cam_vfe_resource_start(
 	struct cam_isp_resource_node *vfe_res)
 {
 	struct cam_vfe_mux_ver4_data   *rsrc_data;
-	uint32_t                        val = 0;
+	uint32_t                        val = 0, epoch_factor = 50;
 	int                             rc = 0;
 	uint32_t                        err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX];
 	uint32_t                        irq_mask[CAM_IFE_IRQ_REGISTERS_MAX];
@@ -1817,8 +1846,13 @@ static int cam_vfe_resource_start(
 		cam_io_r_mb(rsrc_data->mem_base +
 			rsrc_data->common_reg->core_cfg_1));
 
+	/* % epoch factor from userland */
+	if ((rsrc_data->epoch_factor) && (rsrc_data->epoch_factor <= 100))
+		epoch_factor = rsrc_data->epoch_factor;
+
 	val = ((rsrc_data->last_line + rsrc_data->vbi_value) -
-						rsrc_data->first_line) / 2;
+		rsrc_data->first_line) * epoch_factor / 100;
+
 	if (val > rsrc_data->last_line)
 		val = rsrc_data->last_line;
 
@@ -1828,7 +1862,10 @@ static int cam_vfe_resource_start(
 
 	cam_io_w_mb(val, rsrc_data->mem_base +
 				rsrc_data->common_reg->epoch_height_cfg);
-	CAM_DBG(CAM_ISP, "epoch_line_cfg: 0x%X", val);
+	CAM_DBG(CAM_ISP,
+		"height [0x%x : 0x%x] vbi_val: 0x%x epoch_factor: %u%% epoch_line_cfg: 0x%x",
+		rsrc_data->first_line, rsrc_data->last_line,
+		rsrc_data->vbi_value, epoch_factor, val);
 
 skip_core_cfg:
 	vfe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
@@ -1986,6 +2023,7 @@ skip_core_decfg:
 		vfe_priv->irq_err_handle = 0;
 	}
 
+	vfe_priv->epoch_factor = 0;
 	CAM_DBG(CAM_ISP, "VFE:%d Res: %s Stopped",
 		vfe_res->hw_intf->hw_idx,
 		vfe_res->res_name);