Просмотр исходного кода

msm: camera: common: Enhance seamless switch support

Mode switch delay is an inherent property of a sensor.
Similarly IFE has a static switch delay of 1. For sensors
with switch delay > 1 need special handling on certain
occasions. It is possible that switch settings was applied
to sensor, and on the next frame if there is a flash inject
delay or a packet delay, sensor & IFE are bound to go out of sync.
To address such cases, IFE will decide if it needs to apply
MUP on a dropped frame or not, along with any corresponding
IQ settings.

CRs-Fixed: 3320774
Change-Id: I355fa0f8b767d44bd3fb87c91b3cbf56fb9c3933
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 2 лет назад
Родитель
Сommit
a5b60b58b2

+ 117 - 17
drivers/cam_isp/cam_isp_context.c

@@ -4511,6 +4511,10 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
 
 
 	ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
 	ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
 
 
+	/* Reset mswitch ref cnt */
+	atomic_set(&ctx_isp->mswitch_default_apply_delay_ref_cnt,
+		ctx_isp->mswitch_default_apply_delay_max_cnt);
+
 	if (apply->re_apply)
 	if (apply->re_apply)
 		if (apply->request_id <= ctx_isp->last_applied_req_id) {
 		if (apply->request_id <= ctx_isp->last_applied_req_id) {
 			CAM_INFO_RATE_LIMIT(CAM_ISP,
 			CAM_INFO_RATE_LIMIT(CAM_ISP,
@@ -4676,6 +4680,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
 			"ctx_id:%d ,Can not apply (req %lld) the configuration, rc %d",
 			"ctx_id:%d ,Can not apply (req %lld) the configuration, rc %d",
 			ctx->ctx_id, apply->request_id, rc);
 			ctx->ctx_id, apply->request_id, rc);
 	}
 	}
+
 	atomic_set(&ctx_isp->apply_in_progress, 0);
 	atomic_set(&ctx_isp->apply_in_progress, 0);
 end:
 end:
 	return rc;
 	return rc;
@@ -4753,29 +4758,100 @@ static int __cam_isp_ctx_apply_req_in_bubble(
 	return rc;
 	return rc;
 }
 }
 
 
+static void __cam_isp_ctx_find_mup_for_default_settings(
+	int64_t req_id, struct cam_context *ctx,
+	struct cam_ctx_request **switch_req)
+{
+	struct cam_ctx_request *req, *temp_req;
+
+	if (list_empty(&ctx->pending_req_list)) {
+		CAM_DBG(CAM_ISP,
+			"Pending list empty, unable to find mup for req: %lld ctx: %u",
+			req_id, ctx->ctx_id);
+		return;
+	}
+
+	list_for_each_entry_safe(
+		req, temp_req, &ctx->pending_req_list, list) {
+		if (req->request_id == req_id) {
+			struct cam_isp_ctx_req *req_isp = (struct cam_isp_ctx_req *)req->req_priv;
+
+			if (req_isp->hw_update_data.mup_en) {
+				*switch_req = req;
+				CAM_DBG(CAM_ISP,
+					"Found mup for last applied max pd req: %lld in ctx: %u",
+					req_id, ctx->ctx_id);
+			}
+		}
+	}
+}
+
 static int __cam_isp_ctx_apply_default_req_settings(
 static int __cam_isp_ctx_apply_default_req_settings(
 	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply)
 	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply)
 {
 {
 	int rc = 0;
 	int rc = 0;
+	bool skip_rup_aup = false;
+	struct cam_ctx_request *req = NULL;
+	struct cam_isp_ctx_req *req_isp = NULL;
 	struct cam_isp_context *isp_ctx =
 	struct cam_isp_context *isp_ctx =
 		(struct cam_isp_context *) ctx->ctx_priv;
 		(struct cam_isp_context *) ctx->ctx_priv;
-	struct cam_hw_cmd_args        hw_cmd_args;
-	struct cam_isp_hw_cmd_args    isp_hw_cmd_args;
+	struct cam_hw_cmd_args hw_cmd_args;
+	struct cam_isp_hw_cmd_args isp_hw_cmd_args;
+	struct cam_hw_config_args cfg = {0};
 
 
-	hw_cmd_args.ctxt_to_hw_map = isp_ctx->hw_ctx;
-	hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
-	isp_hw_cmd_args.cmd_type =
-		CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG;
-	hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
+	if (isp_ctx->mode_switch_en && isp_ctx->handle_mswitch) {
+		if ((apply->last_applied_max_pd_req > 0) &&
+			(atomic_dec_and_test(&isp_ctx->mswitch_default_apply_delay_ref_cnt))) {
+			__cam_isp_ctx_find_mup_for_default_settings(
+				apply->last_applied_max_pd_req, ctx, &req);
+		}
 
 
-	rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
+		if (req) {
+			req_isp = (struct cam_isp_ctx_req *)req->req_priv;
+
+			CAM_DBG(CAM_ISP,
+				"Applying IQ for mode switch req: %lld ctx: %u",
+				req->request_id, ctx->ctx_id);
+			cfg.ctxt_to_hw_map = isp_ctx->hw_ctx;
+			cfg.request_id = req->request_id;
+			cfg.hw_update_entries = req_isp->cfg;
+			cfg.num_hw_update_entries = req_isp->num_cfg;
+			cfg.priv  = &req_isp->hw_update_data;
+			cfg.init_packet = 0;
+			cfg.reapply_type = CAM_CONFIG_REAPPLY_IQ;
+			cfg.cdm_reset_before_apply = req_isp->cdm_reset_before_apply;
+
+			rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"Failed to apply req: %lld IQ settings in ctx: %u",
+					req->request_id, ctx->ctx_id);
+				goto end;
+			}
+			skip_rup_aup = true;
+		}
+	}
+
+	if (isp_ctx->use_default_apply) {
+		hw_cmd_args.ctxt_to_hw_map = isp_ctx->hw_ctx;
+		hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
+		isp_hw_cmd_args.cmd_type =
+			CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG;
+
+		isp_hw_cmd_args.cmd_data = (void *)&skip_rup_aup;
+		hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
+
+		rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
 			&hw_cmd_args);
 			&hw_cmd_args);
-	if (rc)
-		CAM_ERR(CAM_ISP,
-			"Failed to apply default settings rc %d", rc);
-	else
-		CAM_DBG(CAM_ISP, "Applied default settings rc %d", rc);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"Failed to apply default settings rc %d", rc);
+		else
+			CAM_DBG(CAM_ISP, "Applied default settings rc %d ctx: %u",
+				rc, ctx->ctx_id);
+	}
 
 
+end:
 	return rc;
 	return rc;
 }
 }
 
 
@@ -6939,6 +7015,8 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 		(param.op_flags & CAM_IFE_CTX_CONSUME_ADDR_EN);
 		(param.op_flags & CAM_IFE_CTX_CONSUME_ADDR_EN);
 	ctx_isp->aeb_enabled =
 	ctx_isp->aeb_enabled =
 		(param.op_flags & CAM_IFE_CTX_AEB_EN);
 		(param.op_flags & CAM_IFE_CTX_AEB_EN);
+	ctx_isp->mode_switch_en =
+		(param.op_flags & CAM_IFE_CTX_DYNAMIC_SWITCH_EN);
 
 
 	/* Query the context bus comp group information */
 	/* Query the context bus comp group information */
 	ctx_isp->vfe_bus_comp_grp = kcalloc(CAM_IFE_BUS_COMP_NUM_MAX,
 	ctx_isp->vfe_bus_comp_grp = kcalloc(CAM_IFE_BUS_COMP_NUM_MAX,
@@ -7206,6 +7284,19 @@ static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx,
 	ctx_isp->subscribe_event =
 	ctx_isp->subscribe_event =
 		CAM_TRIGGER_POINT_SOF | CAM_TRIGGER_POINT_EOF;
 		CAM_TRIGGER_POINT_SOF | CAM_TRIGGER_POINT_EOF;
 	ctx_isp->trigger_id = link->trigger_id;
 	ctx_isp->trigger_id = link->trigger_id;
+	ctx_isp->mswitch_default_apply_delay_max_cnt = 0;
+	atomic_set(&ctx_isp->mswitch_default_apply_delay_ref_cnt, 0);
+
+	if ((link->mode_switch_max_delay - CAM_MODESWITCH_DELAY_1) > 0) {
+		ctx_isp->handle_mswitch = true;
+		ctx_isp->mswitch_default_apply_delay_max_cnt =
+			link->mode_switch_max_delay - CAM_MODESWITCH_DELAY_1;
+		CAM_DBG(CAM_ISP,
+			"Enabled mode switch handling on ctx: %u max delay cnt: %u",
+			ctx->ctx_id, ctx_isp->mswitch_default_apply_delay_max_cnt);
+		atomic_set(&ctx_isp->mswitch_default_apply_delay_ref_cnt,
+			ctx_isp->mswitch_default_apply_delay_max_cnt);
+	}
 
 
 	/* change state only if we had the init config */
 	/* change state only if we had the init config */
 	if (ctx_isp->init_received) {
 	if (ctx_isp->init_received) {
@@ -7228,6 +7319,8 @@ static int __cam_isp_ctx_unlink_in_acquired(struct cam_context *ctx,
 	ctx->link_hdl = -1;
 	ctx->link_hdl = -1;
 	ctx->ctx_crm_intf = NULL;
 	ctx->ctx_crm_intf = NULL;
 	ctx_isp->trigger_id = -1;
 	ctx_isp->trigger_id = -1;
+	ctx_isp->mswitch_default_apply_delay_max_cnt = 0;
+	atomic_set(&ctx_isp->mswitch_default_apply_delay_ref_cnt, 0);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -7240,7 +7333,8 @@ static int __cam_isp_ctx_get_dev_info_in_acquired(struct cam_context *ctx,
 	dev_info->dev_hdl = ctx->dev_hdl;
 	dev_info->dev_hdl = ctx->dev_hdl;
 	strlcpy(dev_info->name, CAM_ISP_DEV_NAME, sizeof(dev_info->name));
 	strlcpy(dev_info->name, CAM_ISP_DEV_NAME, sizeof(dev_info->name));
 	dev_info->dev_id = CAM_REQ_MGR_DEVICE_IFE;
 	dev_info->dev_id = CAM_REQ_MGR_DEVICE_IFE;
-	dev_info->p_delay = 1;
+	dev_info->p_delay = CAM_PIPELINE_DELAY_1;
+	dev_info->m_delay = CAM_MODESWITCH_DELAY_1;
 	dev_info->trigger = CAM_TRIGGER_POINT_SOF;
 	dev_info->trigger = CAM_TRIGGER_POINT_SOF;
 	dev_info->trigger_on = true;
 	dev_info->trigger_on = true;
 
 
@@ -7934,11 +8028,17 @@ static int __cam_isp_ctx_apply_default_settings(
 	if (atomic_read(&ctx_isp->internal_recovery_set))
 	if (atomic_read(&ctx_isp->internal_recovery_set))
 		return __cam_isp_ctx_reset_and_recover(false, ctx);
 		return __cam_isp_ctx_reset_and_recover(false, ctx);
 
 
-	if (ctx_isp->use_default_apply) {
+	/*
+	 * Call notify frame skip for static offline cases or
+	 * mode switch cases where IFE mode switch delay differs
+	 * from other devices on the link
+	 */
+	if ((ctx_isp->use_default_apply) ||
+		(ctx_isp->mode_switch_en && ctx_isp->handle_mswitch)) {
 		CAM_DBG(CAM_ISP,
 		CAM_DBG(CAM_ISP,
 			"Enter: apply req in Substate:%d request _id:%lld ctx:%u on link:0x%x",
 			"Enter: apply req in Substate:%d request _id:%lld ctx:%u on link:0x%x",
-			 ctx_isp->substate_activated, apply->request_id,
-			 ctx->ctx_id, ctx->link_hdl);
+			ctx_isp->substate_activated, apply->request_id,
+			ctx->ctx_id, ctx->link_hdl);
 
 
 		ctx_ops = &ctx_isp->substate_machine[
 		ctx_ops = &ctx_isp->substate_machine[
 			ctx_isp->substate_activated];
 			ctx_isp->substate_activated];

+ 13 - 0
drivers/cam_isp/cam_isp_context.h

@@ -303,6 +303,15 @@ struct cam_isp_context_event_record {
  * @last_applied_jiffies:      Record the jiffiest of last applied req
  * @last_applied_jiffies:      Record the jiffiest of last applied req
  * @vfe_bus_comp_grp:          Vfe bus comp group record
  * @vfe_bus_comp_grp:          Vfe bus comp group record
  * @sfe_bus_comp_grp:          Sfe bus comp group record
  * @sfe_bus_comp_grp:          Sfe bus comp group record
+ * @mswitch_default_apply_delay_max_cnt: Max mode switch delay among all devices connected
+ *                                       on the same link as this ISP context
+ * @mswitch_default_apply_delay_ref_cnt: Ref cnt for this context to decide when to apply
+ *                                       mode switch settings
+ * @handle_mswitch:            Indicates if IFE needs to explicitly handle mode switch
+ *                             on frame skip callback from request manager.
+ *                             This is decided based on the max mode switch delay published
+ *                             by other devices on the link as part of link setup
+ * @mode_switch_en:            Indicates if mode switch is enabled
  *
  *
  */
  */
 struct cam_isp_context {
 struct cam_isp_context {
@@ -366,6 +375,10 @@ struct cam_isp_context {
 	uint64_t                              last_applied_jiffies;
 	uint64_t                              last_applied_jiffies;
 	struct cam_isp_context_comp_record   *vfe_bus_comp_grp;
 	struct cam_isp_context_comp_record   *vfe_bus_comp_grp;
 	struct cam_isp_context_comp_record   *sfe_bus_comp_grp;
 	struct cam_isp_context_comp_record   *sfe_bus_comp_grp;
+	int32_t                               mswitch_default_apply_delay_max_cnt;
+	atomic_t                              mswitch_default_apply_delay_ref_cnt;
+	bool                                  handle_mswitch;
+	bool                                  mode_switch_en;
 };
 };
 
 
 /**
 /**

+ 18 - 5
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -5517,11 +5517,14 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_CUSTOM)
 	if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_CUSTOM)
 		acquire_args->op_flags |= CAM_IFE_CTX_CUSTOM_EN;
 		acquire_args->op_flags |= CAM_IFE_CTX_CUSTOM_EN;
 
 
-	if (ife_ctx->ctx_config &
-		CAM_IFE_CTX_CFG_FRAME_HEADER_TS)
+	if (ife_ctx->ctx_config & CAM_IFE_CTX_CFG_FRAME_HEADER_TS)
 		acquire_args->op_flags |=
 		acquire_args->op_flags |=
 			CAM_IFE_CTX_FRAME_HEADER_EN;
 			CAM_IFE_CTX_FRAME_HEADER_EN;
 
 
+	if (ife_ctx->ctx_config & CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON)
+		acquire_args->op_flags |=
+			CAM_IFE_CTX_DYNAMIC_SWITCH_EN;
+
 	if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE)
 	if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE)
 		acquire_args->op_flags |=
 		acquire_args->op_flags |=
 			CAM_IFE_CTX_SFE_EN;
 			CAM_IFE_CTX_SFE_EN;
@@ -12793,9 +12796,19 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 			isp_hw_cmd_args->u.last_cdm_done =
 			isp_hw_cmd_args->u.last_cdm_done =
 				ctx->last_cdm_done_req;
 				ctx->last_cdm_done_req;
 			break;
 			break;
-		case CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG:
-			rc = cam_ife_mgr_prog_default_settings(false, ctx);
-			break;
+		case CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG: {
+			bool skip_rup_aup = false;
+
+			if (!isp_hw_cmd_args->cmd_data) {
+				CAM_ERR(CAM_ISP, "Invalid cmd data");
+				rc = -EINVAL;
+				break;
+			}
+
+			skip_rup_aup = *((bool *)isp_hw_cmd_args->cmd_data);
+			rc = cam_ife_mgr_prog_default_settings((false || skip_rup_aup), ctx);
+		}
+		break;
 		case CAM_ISP_HW_MGR_GET_SOF_TS:
 		case CAM_ISP_HW_MGR_GET_SOF_TS:
 			rc = cam_ife_mgr_cmd_get_sof_timestamp(ctx,
 			rc = cam_ife_mgr_cmd_get_sof_timestamp(ctx,
 				&isp_hw_cmd_args->u.sof_ts.curr,
 				&isp_hw_cmd_args->u.sof_ts.curr,

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h

@@ -46,6 +46,7 @@
 #define CAM_IFE_CTX_APPLY_DEFAULT_CFG  BIT(3)
 #define CAM_IFE_CTX_APPLY_DEFAULT_CFG  BIT(3)
 #define CAM_IFE_CTX_SFE_EN             BIT(4)
 #define CAM_IFE_CTX_SFE_EN             BIT(4)
 #define CAM_IFE_CTX_AEB_EN             BIT(5)
 #define CAM_IFE_CTX_AEB_EN             BIT(5)
+#define CAM_IFE_CTX_DYNAMIC_SWITCH_EN  BIT(6)
 
 
 /*
 /*
  * Maximum configuration entry size  - This is based on the
  * Maximum configuration entry size  - This is based on the

+ 29 - 2
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -364,10 +364,13 @@ static int __cam_req_mgr_notify_frame_skip(
 			apply_data[pd].req_id;
 			apply_data[pd].req_id;
 		frame_skip.trigger_point = trigger;
 		frame_skip.trigger_point = trigger;
 		frame_skip.report_if_bubble = 0;
 		frame_skip.report_if_bubble = 0;
+		frame_skip.last_applied_max_pd_req =
+			 link->req.prev_apply_data[link->max_delay].req_id;
 
 
 		CAM_DBG(CAM_REQ,
 		CAM_DBG(CAM_REQ,
-			"Notify_frame_skip: link: 0x%x pd %d req_id %lld",
-			link->link_hdl, pd, apply_data[pd].req_id);
+			"Notify_frame_skip: link: 0x%x pd %d req_id %lld last_applied %lld",
+			link->link_hdl, pd, apply_data[pd].req_id,
+			link->req.prev_apply_data[link->max_delay].req_id);
 		if ((dev->ops) && (dev->ops->notify_frame_skip))
 		if ((dev->ops) && (dev->ops->notify_frame_skip))
 			dev->ops->notify_frame_skip(&frame_skip);
 			dev->ops->notify_frame_skip(&frame_skip);
 	}
 	}
@@ -1123,6 +1126,8 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link,
 				link->req.prev_apply_data[pd].req_id;
 				link->req.prev_apply_data[pd].req_id;
 			apply_req.trigger_point = trigger;
 			apply_req.trigger_point = trigger;
 			apply_req.report_if_bubble = 0;
 			apply_req.report_if_bubble = 0;
+			apply_req.last_applied_max_pd_req =
+				link->req.prev_apply_data[link->max_delay].req_id;
 			if ((dev->ops) && (dev->ops->notify_frame_skip))
 			if ((dev->ops) && (dev->ops->notify_frame_skip))
 				dev->ops->notify_frame_skip(&apply_req);
 				dev->ops->notify_frame_skip(&apply_req);
 			continue;
 			continue;
@@ -1203,6 +1208,8 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link,
 					link->req.prev_apply_data[pd].req_id;
 					link->req.prev_apply_data[pd].req_id;
 				apply_req.trigger_point = trigger;
 				apply_req.trigger_point = trigger;
 				apply_req.report_if_bubble = 0;
 				apply_req.report_if_bubble = 0;
+				apply_req.last_applied_max_pd_req =
+					link->req.prev_apply_data[link->max_delay].req_id;
 				if ((dev->ops) && (dev->ops->notify_frame_skip))
 				if ((dev->ops) && (dev->ops->notify_frame_skip))
 					dev->ops->notify_frame_skip(&apply_req);
 					dev->ops->notify_frame_skip(&apply_req);
 				continue;
 				continue;
@@ -4147,6 +4154,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 	struct cam_req_mgr_connected_device    *dev;
 	struct cam_req_mgr_connected_device    *dev;
 	struct cam_req_mgr_req_tbl             *pd_tbl;
 	struct cam_req_mgr_req_tbl             *pd_tbl;
 	enum cam_pipeline_delay                 max_delay;
 	enum cam_pipeline_delay                 max_delay;
+	enum cam_modeswitch_delay               max_modeswitch;
 	uint32_t num_trigger_devices = 0;
 	uint32_t num_trigger_devices = 0;
 	if (link_info->version == VERSION_1) {
 	if (link_info->version == VERSION_1) {
 		if (link_info->u.link_info_v1.num_devices >
 		if (link_info->u.link_info_v1.num_devices >
@@ -4167,6 +4175,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 		return rc;
 		return rc;
 
 
 	max_delay = CAM_PIPELINE_DELAY_0;
 	max_delay = CAM_PIPELINE_DELAY_0;
+	max_modeswitch = CAM_MODESWITCH_DELAY_0;
 	if (link_info->version == VERSION_1)
 	if (link_info->version == VERSION_1)
 		num_devices = link_info->u.link_info_v1.num_devices;
 		num_devices = link_info->u.link_info_v1.num_devices;
 	else if (link_info->version == VERSION_2)
 	else if (link_info->version == VERSION_2)
@@ -4219,6 +4228,12 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 			CAM_PIPELINE_DELAY_0) {
 			CAM_PIPELINE_DELAY_0) {
 			CAM_ERR(CAM_CRM, "get device info failed");
 			CAM_ERR(CAM_CRM, "get device info failed");
 			goto error;
 			goto error;
+		} else if (dev->dev_info.m_delay >=
+			CAM_MODESWITCH_DELAY_MAX ||
+			dev->dev_info.m_delay <
+			CAM_MODESWITCH_DELAY_0) {
+			CAM_ERR(CAM_CRM, "get mode switch info failed");
+			goto error;
 		} else {
 		} else {
 			if (link_info->version == VERSION_1) {
 			if (link_info->version == VERSION_1) {
 				CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d",
 				CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d",
@@ -4234,6 +4249,9 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 				}
 				}
 			if (dev->dev_info.p_delay > max_delay)
 			if (dev->dev_info.p_delay > max_delay)
 				max_delay = dev->dev_info.p_delay;
 				max_delay = dev->dev_info.p_delay;
+
+			if (dev->dev_info.m_delay > max_modeswitch)
+				max_modeswitch = dev->dev_info.m_delay;
 		}
 		}
 
 
 		if (dev->dev_info.trigger_on)
 		if (dev->dev_info.trigger_on)
@@ -4252,6 +4270,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 	link_data.link_hdl = link->link_hdl;
 	link_data.link_hdl = link->link_hdl;
 	link_data.crm_cb = &cam_req_mgr_ops;
 	link_data.crm_cb = &cam_req_mgr_ops;
 	link_data.max_delay = max_delay;
 	link_data.max_delay = max_delay;
+	link_data.mode_switch_max_delay = max_modeswitch;
 	if (num_trigger_devices == CAM_REQ_MGR_MAX_TRIGGERS)
 	if (num_trigger_devices == CAM_REQ_MGR_MAX_TRIGGERS)
 		link->dual_trigger = true;
 		link->dual_trigger = true;
 
 
@@ -4304,11 +4323,19 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 		/* Communicate with dev to establish the link */
 		/* Communicate with dev to establish the link */
 		dev->ops->link_setup(&link_data);
 		dev->ops->link_setup(&link_data);
 
 
+		/* Compute max/min pipeline delay */
 		if (dev->dev_info.p_delay > link->max_delay)
 		if (dev->dev_info.p_delay > link->max_delay)
 			link->max_delay = dev->dev_info.p_delay;
 			link->max_delay = dev->dev_info.p_delay;
 		if (dev->dev_info.p_delay < link->min_delay)
 		if (dev->dev_info.p_delay < link->min_delay)
 			link->min_delay = dev->dev_info.p_delay;
 			link->min_delay = dev->dev_info.p_delay;
+
+		/* Compute max/min modeswitch delay */
+		if (dev->dev_info.m_delay > link->max_mswitch_delay)
+			link->max_mswitch_delay = dev->dev_info.m_delay;
+		if (dev->dev_info.m_delay < link->min_mswitch_delay)
+			link->min_mswitch_delay = dev->dev_info.m_delay;
 	}
 	}
+
 	link->num_devs = num_devices;
 	link->num_devs = num_devices;
 
 
 	/* Assign id for pd tables */
 	/* Assign id for pd tables */

+ 5 - 1
drivers/cam_req_mgr/cam_req_mgr_core.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 #ifndef _CAM_REQ_MGR_CORE_H_
 #ifndef _CAM_REQ_MGR_CORE_H_
 #define _CAM_REQ_MGR_CORE_H_
 #define _CAM_REQ_MGR_CORE_H_
@@ -370,6 +370,8 @@ struct cam_req_mgr_connected_device {
  * @num_devs             : num of connected devices to this link
  * @num_devs             : num of connected devices to this link
  * @max_delay            : Max of pipeline delay of all connected devs
  * @max_delay            : Max of pipeline delay of all connected devs
  * @min_delay            : Min of pipeline delay of all connected devs
  * @min_delay            : Min of pipeline delay of all connected devs
+ * @max_mswitch_delay    : Max of modeswitch delay of all connected devs
+ * @min_mswitch_delay    : Min of modeswitch delay of all connected devs
  * @workq                : Pointer to handle workq related jobs
  * @workq                : Pointer to handle workq related jobs
  * @pd_mask              : each set bit indicates the device with pd equal to
  * @pd_mask              : each set bit indicates the device with pd equal to
  *                          bit position is available.
  *                          bit position is available.
@@ -425,6 +427,8 @@ struct cam_req_mgr_core_link {
 	int32_t                              num_devs;
 	int32_t                              num_devs;
 	enum cam_pipeline_delay              max_delay;
 	enum cam_pipeline_delay              max_delay;
 	enum cam_pipeline_delay              min_delay;
 	enum cam_pipeline_delay              min_delay;
+	enum cam_modeswitch_delay            max_mswitch_delay;
+	enum cam_modeswitch_delay            min_mswitch_delay;
 	struct cam_req_mgr_core_workq       *workq;
 	struct cam_req_mgr_core_workq       *workq;
 	int32_t                              pd_mask;
 	int32_t                              pd_mask;
 	struct cam_req_mgr_connected_device *l_dev;
 	struct cam_req_mgr_connected_device *l_dev;

+ 33 - 9
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_REQ_MGR_INTERFACE_H
 #ifndef _CAM_REQ_MGR_INTERFACE_H
@@ -115,6 +115,23 @@ enum cam_pipeline_delay {
 	CAM_PIPELINE_DELAY_MAX,
 	CAM_PIPELINE_DELAY_MAX,
 };
 };
 
 
+/**
+ * enum cam_modeswitch_delay
+ * @brief     : enumerator for different modeswitch delays in camera
+ *
+ * @DELAY_0   : device processed mode switch settings after 0 frame
+ * @DELAY_1   : device processed mode switch settings after 1 frame
+ * @DELAY_2   : device processed mode switch settings after 2 frames
+ * @DELAY_MAX : maximum supported mode switch delay
+ */
+enum cam_modeswitch_delay {
+	CAM_MODESWITCH_DELAY_0,
+	CAM_MODESWITCH_DELAY_1,
+	CAM_MODESWITCH_DELAY_2,
+	CAM_MODESWITCH_DELAY_MAX,
+};
+
+
 /**
 /**
  * @CAM_TRIGGER_POINT_SOF   : Trigger point for Start Of Frame
  * @CAM_TRIGGER_POINT_SOF   : Trigger point for Start Of Frame
  * @CAM_TRIGGER_POINT_EOF   : Trigger point for End Of Frame
  * @CAM_TRIGGER_POINT_EOF   : Trigger point for End Of Frame
@@ -314,6 +331,7 @@ struct cam_req_mgr_notify_stop {
  * @name    : link link or unlink
  * @name    : link link or unlink
  * @dev_id  : device id info
  * @dev_id  : device id info
  * @p_delay : delay between time settings applied and take effect
  * @p_delay : delay between time settings applied and take effect
+ * @m_delay : delay between time modeswitch settings applied and take effect
  * @trigger : Trigger point for the client
  * @trigger : Trigger point for the client
  * @trigger_on : This device provides trigger
  * @trigger_on : This device provides trigger
  */
  */
@@ -322,6 +340,7 @@ struct cam_req_mgr_device_info {
 	char                        name[256];
 	char                        name[256];
 	enum cam_req_mgr_device_id  dev_id;
 	enum cam_req_mgr_device_id  dev_id;
 	enum cam_pipeline_delay     p_delay;
 	enum cam_pipeline_delay     p_delay;
+	enum cam_modeswitch_delay   m_delay;
 	uint32_t                    trigger;
 	uint32_t                    trigger;
 	bool                        trigger_on;
 	bool                        trigger_on;
 };
 };
@@ -332,6 +351,7 @@ struct cam_req_mgr_device_info {
  * @link_hdl        : link identifier
  * @link_hdl        : link identifier
  * @dev_hdl         : device handle for reference
  * @dev_hdl         : device handle for reference
  * @max_delay       : max pipeline delay on this link
  * @max_delay       : max pipeline delay on this link
+ * @mode_switch_max_delay : max modeswitch delay on this link
  * @crm_cb          : callback funcs to communicate with req mgr
  * @crm_cb          : callback funcs to communicate with req mgr
  * @trigger_id      : Unique ID provided to the triggering device
  * @trigger_id      : Unique ID provided to the triggering device
  */
  */
@@ -340,25 +360,29 @@ struct cam_req_mgr_core_dev_link_setup {
 	int32_t                    link_hdl;
 	int32_t                    link_hdl;
 	int32_t                    dev_hdl;
 	int32_t                    dev_hdl;
 	enum cam_pipeline_delay    max_delay;
 	enum cam_pipeline_delay    max_delay;
+	enum cam_modeswitch_delay  mode_switch_max_delay;
 	struct cam_req_mgr_crm_cb *crm_cb;
 	struct cam_req_mgr_crm_cb *crm_cb;
 	int32_t                    trigger_id;
 	int32_t                    trigger_id;
 };
 };
 
 
 /**
 /**
  * struct cam_req_mgr_apply_request
  * struct cam_req_mgr_apply_request
- * @link_hdl         : link identifier
- * @dev_hdl          : device handle for cross check
- * @request_id       : request id settings to apply
- * @report_if_bubble : report to crm if failure in applying
- * @trigger_point    : the trigger point of this apply
- * @re_apply         : to skip re_apply for buf_done request
- * @recovery         : Indicate if it is recovery req
+ * @link_hdl                 : link identifier
+ * @dev_hdl                  : device handle for cross check
+ * @request_id               : request id settings to apply
+ * @last_applied_max_pd_req  : Last applied request on highest pd device
+ *                             -1 is considered invalid
+ * @report_if_bubble         : report to crm if failure in applying
+ * @trigger_point            : the trigger point of this apply
+ * @re_apply                 : to skip re_apply for buf_done request
+ * @recovery                 : Indicate if it is recovery req
  *
  *
  */
  */
 struct cam_req_mgr_apply_request {
 struct cam_req_mgr_apply_request {
 	int32_t    link_hdl;
 	int32_t    link_hdl;
 	int32_t    dev_hdl;
 	int32_t    dev_hdl;
-	int64_t    request_id;
+	uint64_t   request_id;
+	int64_t    last_applied_max_pd_req;
 	int32_t    report_if_bubble;
 	int32_t    report_if_bubble;
 	uint32_t   trigger_point;
 	uint32_t   trigger_point;
 	bool       re_apply;
 	bool       re_apply;

+ 3 - 2
drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // SPDX-License-Identifier: GPL-2.0-only
 /*
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -417,7 +417,8 @@ int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info)
 
 
 	info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR;
 	info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR;
 	strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name));
 	strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name));
-	info->p_delay = 1;
+	info->p_delay = CAM_PIPELINE_DELAY_1;
+	info->m_delay = CAM_MODESWITCH_DELAY_1;
 	info->trigger = CAM_TRIGGER_POINT_SOF;
 	info->trigger = CAM_TRIGGER_POINT_SOF;
 
 
 	return 0;
 	return 0;

+ 3 - 2
drivers/cam_sensor_module/cam_flash/cam_flash_core.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // SPDX-License-Identifier: GPL-2.0-only
 /*
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -1791,7 +1791,8 @@ int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info)
 {
 {
 	info->dev_id = CAM_REQ_MGR_DEVICE_FLASH;
 	info->dev_id = CAM_REQ_MGR_DEVICE_FLASH;
 	strlcpy(info->name, CAM_FLASH_NAME, sizeof(info->name));
 	strlcpy(info->name, CAM_FLASH_NAME, sizeof(info->name));
-	info->p_delay = CAM_FLASH_PIPELINE_DELAY;
+	info->p_delay = CAM_PIPELINE_DELAY_1;
+	info->m_delay = CAM_MODESWITCH_DELAY_1;
 	info->trigger = CAM_TRIGGER_POINT_SOF;
 	info->trigger = CAM_TRIGGER_POINT_SOF;
 	return 0;
 	return 0;
 }
 }

+ 15 - 6
drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // SPDX-License-Identifier: GPL-2.0-only
 /*
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -14,6 +14,9 @@
 #include "cam_packet_util.h"
 #include "cam_packet_util.h"
 #include "cam_req_mgr_dev.h"
 #include "cam_req_mgr_dev.h"
 
 
+#define CAM_SENSOR_PIPELINE_DELAY_MASK        0xFF
+#define CAM_SENSOR_MODESWITCH_DELAY_SHIFT     8
+
 extern struct completion *cam_sensor_get_i3c_completion(uint32_t index);
 extern struct completion *cam_sensor_get_i3c_completion(uint32_t index);
 
 
 static int cam_sensor_notify_v4l2_error_event(
 static int cam_sensor_notify_v4l2_error_event(
@@ -661,6 +664,7 @@ int32_t cam_sensor_update_slave_info(void *probe_info,
 			sensor_probe_info->data_mask;
 			sensor_probe_info->data_mask;
 		s_ctrl->pipeline_delay =
 		s_ctrl->pipeline_delay =
 			sensor_probe_info->reserved;
 			sensor_probe_info->reserved;
+		s_ctrl->modeswitch_delay = 0;
 
 
 		s_ctrl->sensor_probe_addr_type = sensor_probe_info->addr_type;
 		s_ctrl->sensor_probe_addr_type = sensor_probe_info->addr_type;
 		s_ctrl->sensor_probe_data_type = sensor_probe_info->data_type;
 		s_ctrl->sensor_probe_data_type = sensor_probe_info->data_type;
@@ -673,8 +677,10 @@ int32_t cam_sensor_update_slave_info(void *probe_info,
 		s_ctrl->sensordata->slave_info.sensor_id_mask =
 		s_ctrl->sensordata->slave_info.sensor_id_mask =
 			sensor_probe_info_v2->data_mask;
 			sensor_probe_info_v2->data_mask;
 		s_ctrl->pipeline_delay =
 		s_ctrl->pipeline_delay =
-			sensor_probe_info_v2->pipeline_delay;
-
+			(sensor_probe_info_v2->pipeline_delay &
+			CAM_SENSOR_PIPELINE_DELAY_MASK);
+		s_ctrl->modeswitch_delay = (sensor_probe_info_v2->pipeline_delay >>
+			CAM_SENSOR_MODESWITCH_DELAY_SHIFT);
 		s_ctrl->sensor_probe_addr_type =
 		s_ctrl->sensor_probe_addr_type =
 			sensor_probe_info_v2->addr_type;
 			sensor_probe_info_v2->addr_type;
 		s_ctrl->sensor_probe_data_type =
 		s_ctrl->sensor_probe_data_type =
@@ -1552,10 +1558,13 @@ int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info)
 
 
 	info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR;
 	info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR;
 	strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name));
 	strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name));
-	if (s_ctrl->pipeline_delay >= 1 && s_ctrl->pipeline_delay <= 3)
+	if (s_ctrl->pipeline_delay >= 1 && s_ctrl->pipeline_delay <= 3) {
 		info->p_delay = s_ctrl->pipeline_delay;
 		info->p_delay = s_ctrl->pipeline_delay;
-	else
-		info->p_delay = 2;
+		info->m_delay = s_ctrl->modeswitch_delay;
+	} else {
+		info->p_delay = CAM_PIPELINE_DELAY_2;
+		info->m_delay = CAM_MODESWITCH_DELAY_2;
+	}
 	info->trigger = CAM_TRIGGER_POINT_SOF;
 	info->trigger = CAM_TRIGGER_POINT_SOF;
 
 
 	return rc;
 	return rc;

+ 3 - 1
drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
  * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved.
  * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_SENSOR_DEV_H_
 #ifndef _CAM_SENSOR_DEV_H_
@@ -106,6 +106,7 @@ struct cam_sensor_dev_res_info {
  * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator
  * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator
  * @last_flush_req: Last request to flush
  * @last_flush_req: Last request to flush
  * @pipeline_delay: Sensor pipeline delay
  * @pipeline_delay: Sensor pipeline delay
+ * @modeswitch_delay: Mode switch delay
  * @sensor_name: Sensor name
  * @sensor_name: Sensor name
  * @aon_camera_id: AON Camera ID associated with this sensor
  * @aon_camera_id: AON Camera ID associated with this sensor
  * @last_applied_req: Last updated request id
  * @last_applied_req: Last updated request id
@@ -141,6 +142,7 @@ struct cam_sensor_ctrl_t {
 	bool                           bob_pwm_switch;
 	bool                           bob_pwm_switch;
 	uint32_t                       last_flush_req;
 	uint32_t                       last_flush_req;
 	uint16_t                       pipeline_delay;
 	uint16_t                       pipeline_delay;
+	uint16_t                       modeswitch_delay;
 	char                           sensor_name[CAM_SENSOR_NAME_MAX_SIZE];
 	char                           sensor_name[CAM_SENSOR_NAME_MAX_SIZE];
 	uint8_t                        aon_camera_id;
 	uint8_t                        aon_camera_id;
 	int64_t                        last_updated_req;
 	int64_t                        last_updated_req;