Browse Source

msm: camera: common: Add support for variable fps feature

This change adds supoort for variable fps feature, this
feature needs to stream off the sensor at EOF. So, this
change sends an EOF event to sensor to do the streamimg
off. Since sensor only outputs one frame every round, so
we need to apply the IFE packet to HW immediately, then
the every frame will be valid frame.

CRs-Fixed: 3178221
Change-Id: Ifc57987aac11c9655edd979734e5568c19262571
Signed-off-by: Wang Kan <[email protected]>
Signed-off-by: Depeng Shao <[email protected]>
Depeng Shao 3 years ago
parent
commit
34bf7c2b95

+ 59 - 23
drivers/cam_isp/cam_isp_context.c

@@ -2299,7 +2299,7 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
 	return rc;
 	return rc;
 }
 }
 
 
-static int __cam_isp_ctx_apply_req_offline(
+static int __cam_isp_ctx_apply_pending_req(
 	void *priv, void *data)
 	void *priv, void *data)
 {
 {
 	int rc = 0;
 	int rc = 0;
@@ -2323,13 +2323,22 @@ static int __cam_isp_ctx_apply_req_offline(
 		goto end;
 		goto end;
 	}
 	}
 
 
-	if ((ctx->state != CAM_CTX_ACTIVATED) ||
-		(!atomic_read(&ctx_isp->rxd_epoch)) ||
-		(ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_APPLIED))
-		goto end;
+	if (ctx_isp->vfps_aux_context) {
+		if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_APPLIED)
+			goto end;
+
+		if (ctx_isp->active_req_cnt >= 1)
+			goto end;
+	} else {
+		if ((ctx->state != CAM_CTX_ACTIVATED) ||
+			(!atomic_read(&ctx_isp->rxd_epoch)) ||
+			(ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_APPLIED))
+			goto end;
+
+		if (ctx_isp->active_req_cnt >= 2)
+			goto end;
+	}
 
 
-	if (ctx_isp->active_req_cnt >= 2)
-		goto end;
 
 
 	spin_lock_bh(&ctx->lock);
 	spin_lock_bh(&ctx->lock);
 	req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request,
 	req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request,
@@ -2395,7 +2404,7 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
-static int __cam_isp_ctx_schedule_apply_req_offline(
+static int __cam_isp_ctx_schedule_apply_req(
 	struct cam_isp_context *ctx_isp)
 	struct cam_isp_context *ctx_isp)
 {
 {
 	int rc = 0;
 	int rc = 0;
@@ -2407,7 +2416,7 @@ static int __cam_isp_ctx_schedule_apply_req_offline(
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	task->process_cb = __cam_isp_ctx_apply_req_offline;
+	task->process_cb = __cam_isp_ctx_apply_pending_req;
 	rc = cam_req_mgr_workq_enqueue_task(task, ctx_isp, CRM_TASK_PRIORITY_0);
 	rc = cam_req_mgr_workq_enqueue_task(task, ctx_isp, CRM_TASK_PRIORITY_0);
 	if (rc)
 	if (rc)
 		CAM_ERR(CAM_ISP, "Failed to schedule task rc:%d", rc);
 		CAM_ERR(CAM_ISP, "Failed to schedule task rc:%d", rc);
@@ -2444,7 +2453,7 @@ static int __cam_isp_ctx_offline_epoch_in_activated_state(
 		}
 		}
 	}
 	}
 
 
-	__cam_isp_ctx_schedule_apply_req_offline(ctx_isp);
+	__cam_isp_ctx_schedule_apply_req(ctx_isp);
 
 
 	/*
 	/*
 	 * If no valid request, wait for RUP shutter posted after buf done
 	 * If no valid request, wait for RUP shutter posted after buf done
@@ -5872,6 +5881,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	ctx_isp->hw_acquired = false;
 	ctx_isp->hw_acquired = false;
 	ctx_isp->init_received = false;
 	ctx_isp->init_received = false;
 	ctx_isp->offline_context = false;
 	ctx_isp->offline_context = false;
+	ctx_isp->vfps_aux_context = false;
 	ctx_isp->rdi_only_context = false;
 	ctx_isp->rdi_only_context = false;
 	ctx_isp->req_info.last_bufdone_req_id = 0;
 	ctx_isp->req_info.last_bufdone_req_id = 0;
 	ctx_isp->v4l2_event_sub_ids = 0;
 	ctx_isp->v4l2_event_sub_ids = 0;
@@ -6046,7 +6056,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 			goto put_ref;
 			goto put_ref;
 		}
 		}
 
 
-		if (ctx_isp->offline_context) {
+		if ((ctx_isp->offline_context) || (ctx_isp->vfps_aux_context)) {
 			__cam_isp_ctx_enqueue_request_in_order(ctx, req, true);
 			__cam_isp_ctx_enqueue_request_in_order(ctx, req, true);
 		} else if (ctx->ctx_crm_intf->add_req) {
 		} else if (ctx->ctx_crm_intf->add_req) {
 			memset(&add_req, 0, sizeof(add_req));
 			memset(&add_req, 0, sizeof(add_req));
@@ -6078,9 +6088,11 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 		"Preprocessing Config req_id %lld successful on ctx %u",
 		"Preprocessing Config req_id %lld successful on ctx %u",
 		req->request_id, ctx->ctx_id);
 		req->request_id, ctx->ctx_id);
 
 
-	if (ctx_isp->offline_context && atomic_read(&ctx_isp->rxd_epoch)) {
-		__cam_isp_ctx_schedule_apply_req_offline(ctx_isp);
-	}
+	if (ctx_isp->offline_context && atomic_read(&ctx_isp->rxd_epoch))
+		__cam_isp_ctx_schedule_apply_req(ctx_isp);
+	else if (ctx_isp->vfps_aux_context &&
+		(req_isp->hw_update_data.packet_opcode_type != CAM_ISP_PACKET_INIT_DEV))
+		__cam_isp_ctx_schedule_apply_req(ctx_isp);
 
 
 	return rc;
 	return rc;
 
 
@@ -6537,7 +6549,7 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
-static void cam_req_mgr_process_workq_offline_ife_worker(struct work_struct *w)
+static void cam_req_mgr_process_workq_apply_req_worker(struct work_struct *w)
 {
 {
 	cam_req_mgr_process_workq(w);
 	cam_req_mgr_process_workq(w);
 }
 }
@@ -6685,14 +6697,6 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 			cam_isp_ctx_offline_state_machine_irq;
 			cam_isp_ctx_offline_state_machine_irq;
 		ctx_isp->substate_machine = NULL;
 		ctx_isp->substate_machine = NULL;
 		ctx_isp->offline_context = true;
 		ctx_isp->offline_context = true;
-
-		rc = cam_req_mgr_workq_create("offline_ife", 20,
-			&ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0,
-			cam_req_mgr_process_workq_offline_ife_worker);
-		if (rc)
-			CAM_ERR(CAM_ISP,
-				"Failed to create workq for offline IFE rc:%d",
-				rc);
 	} else {
 	} else {
 		CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources");
 		CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources");
 		ctx_isp->substate_machine_irq =
 		ctx_isp->substate_machine_irq =
@@ -6701,6 +6705,17 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 			cam_isp_ctx_activated_state_machine;
 			cam_isp_ctx_activated_state_machine;
 	}
 	}
 
 
+	if (ctx_isp->offline_context || ctx_isp->vfps_aux_context) {
+		rc = cam_req_mgr_workq_create("ife_apply_req", 20,
+			&ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0,
+			cam_req_mgr_process_workq_apply_req_worker);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"Failed to create workq for IFE rc:%d offline: %s vfps: %s",
+				rc, CAM_BOOL_TO_YESNO(ctx_isp->offline_context),
+				CAM_BOOL_TO_YESNO(ctx_isp->vfps_aux_context));
+	}
+
 	ctx_isp->hw_ctx = param.ctxt_to_hw_map;
 	ctx_isp->hw_ctx = param.ctxt_to_hw_map;
 	ctx_isp->hw_acquired = true;
 	ctx_isp->hw_acquired = true;
 	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
 	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
@@ -7450,9 +7465,20 @@ static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
 	struct cam_req_mgr_link_evt_data *link_evt_data)
 	struct cam_req_mgr_link_evt_data *link_evt_data)
 {
 {
 	int rc = 0;
 	int rc = 0;
+	struct cam_isp_context *ctx_isp =
+		(struct cam_isp_context *) ctx->ctx_priv;
+
+	if ((ctx->state == CAM_CTX_ACQUIRED) &&
+		(link_evt_data->evt_type != CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES)) {
+		CAM_WARN(CAM_ISP,
+			"Get unexpect evt:%d in acquired state",
+			link_evt_data->evt_type);
+		return -EINVAL;
+	}
 
 
 	switch (link_evt_data->evt_type) {
 	switch (link_evt_data->evt_type) {
 	case CAM_REQ_MGR_LINK_EVT_ERR:
 	case CAM_REQ_MGR_LINK_EVT_ERR:
+	case CAM_REQ_MGR_LINK_EVT_EOF:
 		/* No handling */
 		/* No handling */
 		break;
 		break;
 	case CAM_REQ_MGR_LINK_EVT_PAUSE:
 	case CAM_REQ_MGR_LINK_EVT_PAUSE:
@@ -7480,6 +7506,15 @@ static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
 		link_evt_data->try_for_recovery = internal_recovery_skipped;
 		link_evt_data->try_for_recovery = internal_recovery_skipped;
 	}
 	}
 		break;
 		break;
+	case CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES:
+		if (link_evt_data->u.properties_mask &
+			CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)
+			ctx_isp->vfps_aux_context = true;
+		else
+			ctx_isp->vfps_aux_context = false;
+		CAM_DBG(CAM_ISP, "vfps_aux_context:%s on ctx: %u",
+			CAM_BOOL_TO_YESNO(ctx_isp->vfps_aux_context), ctx->ctx_id);
+		break;
 	default:
 	default:
 		CAM_WARN(CAM_ISP,
 		CAM_WARN(CAM_ISP,
 			"Unsupported event type: 0x%x on ctx: %u",
 			"Unsupported event type: 0x%x on ctx: %u",
@@ -7721,6 +7756,7 @@ static struct cam_ctx_ops
 			.link = __cam_isp_ctx_link_in_acquired,
 			.link = __cam_isp_ctx_link_in_acquired,
 			.unlink = __cam_isp_ctx_unlink_in_acquired,
 			.unlink = __cam_isp_ctx_unlink_in_acquired,
 			.get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired,
 			.get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired,
+			.process_evt = __cam_isp_ctx_process_evt,
 			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
 			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
 			.dump_req = __cam_isp_ctx_dump_in_top_state,
 			.dump_req = __cam_isp_ctx_dump_in_top_state,
 		},
 		},

+ 3 - 0
drivers/cam_isp/cam_isp_context.h

@@ -1,6 +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.
  */
  */
 
 
 #ifndef _CAM_ISP_CONTEXT_H_
 #ifndef _CAM_ISP_CONTEXT_H_
@@ -269,6 +270,7 @@ struct cam_isp_context_event_record {
  * @rdi_only_context:          Get context type information.
  * @rdi_only_context:          Get context type information.
  *                             true, if context is rdi only context
  *                             true, if context is rdi only context
  * @offline_context:           Indicate whether context is for offline IFE
  * @offline_context:           Indicate whether context is for offline IFE
+ * @vfps_aux_context:          Indicate whether context is for VFPS aux link
  * @hw_acquired:               Indicate whether HW resources are acquired
  * @hw_acquired:               Indicate whether HW resources are acquired
  * @init_received:             Indicate whether init config packet is received
  * @init_received:             Indicate whether init config packet is received
  * @split_acquire:             Indicate whether a separate acquire is expected
  * @split_acquire:             Indicate whether a separate acquire is expected
@@ -324,6 +326,7 @@ struct cam_isp_context {
 		CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES];
 		CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES];
 	bool                                  rdi_only_context;
 	bool                                  rdi_only_context;
 	bool                                  offline_context;
 	bool                                  offline_context;
+	bool                                  vfps_aux_context;
 	bool                                  hw_acquired;
 	bool                                  hw_acquired;
 	bool                                  init_received;
 	bool                                  init_received;
 	bool                                  split_acquire;
 	bool                                  split_acquire;

+ 103 - 4
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -70,6 +70,7 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link)
 	link->wq_congestion = false;
 	link->wq_congestion = false;
 	link->try_for_internal_recovery = false;
 	link->try_for_internal_recovery = false;
 	atomic_set(&link->eof_event_cnt, 0);
 	atomic_set(&link->eof_event_cnt, 0);
+	link->properties_mask = CAM_LINK_PROPERTY_NONE;
 	__cam_req_mgr_reset_apply_data(link);
 	__cam_req_mgr_reset_apply_data(link);
 
 
 	for (i = 0; i < MAXIMUM_LINKS_PER_SESSION - 1; i++)
 	for (i = 0; i < MAXIMUM_LINKS_PER_SESSION - 1; i++)
@@ -3156,6 +3157,37 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
+/**
+ * cam_req_mgr_notify_eof_event()
+ *
+ * @brief  : This runs in workqueue thread context. Call core funcs to
+ *           notify eof event to sub devices.
+ * @link   : link info
+ *
+ */
+static void cam_req_mgr_notify_eof_event(struct cam_req_mgr_core_link *link)
+{
+	int                                  i;
+	struct cam_req_mgr_connected_device *dev = NULL;
+	struct cam_req_mgr_link_evt_data     evt_data;
+
+	for (i = 0; i < link->num_devs; i++) {
+		dev = &link->l_dev[i];
+		if (!dev)
+			continue;
+
+		evt_data.dev_hdl = dev->dev_hdl;
+		evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_EOF;
+		evt_data.link_hdl = link->link_hdl;
+
+		if (dev->ops && dev->ops->process_evt)
+			dev->ops->process_evt(&evt_data);
+	}
+
+	CAM_DBG(CAM_CRM, "Notify EOF event done on link:0x%x",
+		link->link_hdl);
+}
+
 /**
 /**
  * cam_req_mgr_process_trigger()
  * cam_req_mgr_process_trigger()
  *
  *
@@ -3222,6 +3254,9 @@ static int cam_req_mgr_process_trigger(void *priv, void *data)
 
 
 			__cam_req_mgr_reset_req_slot(link, idx);
 			__cam_req_mgr_reset_req_slot(link, idx);
 		}
 		}
+	} else if (trigger_data->trigger == CAM_TRIGGER_POINT_EOF) {
+		if (link->properties_mask & CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)
+			cam_req_mgr_notify_eof_event(link);
 	}
 	}
 
 
 	/*
 	/*
@@ -3657,10 +3692,12 @@ static int cam_req_mgr_cb_notify_trigger(
 	 * Reduce the workq overhead when there is
 	 * Reduce the workq overhead when there is
 	 * not any eof event found.
 	 * not any eof event found.
 	 */
 	 */
-	if ((!atomic_read(&link->eof_event_cnt)) &&
-		(trigger == CAM_TRIGGER_POINT_EOF)) {
-		CAM_DBG(CAM_CRM, "Not any request to schedule at EOF");
-		goto end;
+	if (trigger == CAM_TRIGGER_POINT_EOF) {
+		if (!atomic_read(&link->eof_event_cnt) &&
+			!(link->properties_mask & CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)) {
+			CAM_DBG(CAM_CRM, "No any request to schedule at EOF");
+			goto end;
+		}
 	}
 	}
 
 
 	spin_lock_bh(&link->link_state_spin_lock);
 	spin_lock_bh(&link->link_state_spin_lock);
@@ -4709,6 +4746,68 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
+int cam_req_mgr_link_properties(struct cam_req_mgr_link_properties *properties)
+{
+	int                                    i, rc = 0;
+	struct cam_req_mgr_core_link          *link = NULL;
+	struct cam_req_mgr_connected_device   *dev;
+	struct cam_req_mgr_link_evt_data       evt_data;
+
+	mutex_lock(&g_crm_core_dev->crm_lock);
+	link = (struct cam_req_mgr_core_link *)
+		cam_get_device_priv(properties->link_hdl);
+	if (!link || (link->link_hdl != properties->link_hdl)) {
+		CAM_ERR(CAM_CRM, "link: %s, properties->link_hdl:0x%x, link->link_hdl:0x%x",
+			CAM_IS_NULL_TO_STR(link), properties->link_hdl,
+			(!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (link->state != CAM_CRM_LINK_STATE_READY) {
+		CAM_ERR(CAM_CRM,
+			"Only can config link 0x%x properties in ready state",
+			link->link_hdl);
+		rc = -EAGAIN;
+		goto end;
+	}
+
+	mutex_lock(&link->lock);
+	link->properties_mask = properties->properties_mask;
+
+	for (i = 0; i < link->num_devs; i++) {
+		dev = &link->l_dev[i];
+
+		if (!dev)
+			continue;
+
+		evt_data.dev_hdl = dev->dev_hdl;
+		evt_data.link_hdl = link->link_hdl;
+		evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES;
+		evt_data.u.properties_mask = link->properties_mask;
+
+		if (dev->ops && dev->ops->process_evt) {
+			rc = dev->ops->process_evt(&evt_data);
+			if (rc) {
+				CAM_ERR(CAM_CRM,
+					"Failed to set properties on link 0x%x dev 0x%x",
+					link->link_hdl, dev->dev_hdl);
+				mutex_unlock(&link->lock);
+				goto end;
+			}
+		}
+	}
+
+	mutex_unlock(&link->lock);
+
+	CAM_DBG(CAM_CRM, "link 0x%x set properties successfully, properties mask:0x%x",
+		link->link_hdl, link->properties_mask);
+
+end:
+	mutex_unlock(&g_crm_core_dev->crm_lock);
+	return rc;
+}
+
 int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req)
 int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req)
 {
 {
 	int                                  rc = 0;
 	int                                  rc = 0;

+ 10 - 0
drivers/cam_req_mgr/cam_req_mgr_core.h

@@ -393,6 +393,7 @@ struct cam_req_mgr_connected_device {
  * @last_sof_trigger_jiffies : Record the jiffies of last sof trigger jiffies
  * @last_sof_trigger_jiffies : Record the jiffies of last sof trigger jiffies
  * @wq_congestion        : Indicates if WQ congestion is detected or not
  * @wq_congestion        : Indicates if WQ congestion is detected or not
  * @try_for_internal_recovery : If the link stalls try for RT internal recovery
  * @try_for_internal_recovery : If the link stalls try for RT internal recovery
+ * @properties_mask      : Indicates if current link enables some special properties
  */
  */
 struct cam_req_mgr_core_link {
 struct cam_req_mgr_core_link {
 	int32_t                              link_hdl;
 	int32_t                              link_hdl;
@@ -432,6 +433,7 @@ struct cam_req_mgr_core_link {
 	uint64_t                             last_sof_trigger_jiffies;
 	uint64_t                             last_sof_trigger_jiffies;
 	bool                                 wq_congestion;
 	bool                                 wq_congestion;
 	bool                                 try_for_internal_recovery;
 	bool                                 try_for_internal_recovery;
+	uint32_t                             properties_mask;
 };
 };
 
 
 /**
 /**
@@ -671,4 +673,12 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control);
  * @dump_req: Dump request
  * @dump_req: Dump request
  */
  */
 int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req);
 int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req);
+
+/**
+ * cam_req_mgr_link_properties()
+ * @brief:   Handles link properties
+ * @properties: Link properties
+ */
+int cam_req_mgr_link_properties(struct cam_req_mgr_link_properties *properties);
+
 #endif
 #endif

+ 16 - 0
drivers/cam_req_mgr/cam_req_mgr_dev.c

@@ -613,6 +613,22 @@ static long cam_private_ioctl(struct file *file, void *fh,
 			rc = -EFAULT;
 			rc = -EFAULT;
 		}
 		}
 		break;
 		break;
+	case CAM_REQ_MGR_LINK_PROPERTIES: {
+		struct cam_req_mgr_link_properties cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			u64_to_user_ptr(k_ioctl->handle),
+			sizeof(struct cam_req_mgr_link_properties))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = cam_req_mgr_link_properties(&cmd);
+		}
+		break;
 	default:
 	default:
 		return -ENOIOCTLCMD;
 		return -ENOIOCTLCMD;
 	}
 	}

+ 20 - 12
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -197,16 +197,20 @@ enum cam_req_mgr_device_id {
 
 
 /**
 /**
  * enum cam_req_mgr_link_evt_type
  * enum cam_req_mgr_link_evt_type
- * @CAM_REQ_MGR_LINK_EVT_ERR             : error on the link from any of the
- *                                         connected devices
- * @CAM_REQ_MGR_LINK_EVT_PAUSE           : to pause the link
- * @CAM_REQ_MGR_LINK_EVT_RESUME          : resumes the link which was paused
- * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE      : request manager has detected an
- *                                         sof freeze
- * @CAM_REQ_MGR_LINK_EVT_STALLED         : Indicate to all connected devices
- *                                         that the pipeline is stalled.
- *                                         Devices can handle accordingly
- * @CAM_REQ_MGR_LINK_EVT_MAX             : invalid event type
+ * @CAM_REQ_MGR_LINK_EVT_ERR               : error on the link from any of the
+ *                                           connected devices
+ * @CAM_REQ_MGR_LINK_EVT_PAUSE             : to pause the link
+ * @CAM_REQ_MGR_LINK_EVT_RESUME            : resumes the link which was paused
+ * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE        : request manager has detected an
+ *                                           sof freeze
+ * @CAM_REQ_MGR_LINK_EVT_STALLED           : Indicate to all connected devices
+ *                                           that the pipeline is stalled.
+ *                                           Devices can handle accordingly
+ * @CAM_REQ_MGR_LINK_EVT_EOF               : Indicate to all connected devices
+ *                                           that we get an EOF
+ * @CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES : Notify sub devices of the properties
+ *                                           updating
+ * @CAM_REQ_MGR_LINK_EVT_MAX               : invalid event type
  */
  */
 enum cam_req_mgr_link_evt_type {
 enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_ERR,
 	CAM_REQ_MGR_LINK_EVT_ERR,
@@ -214,6 +218,8 @@ enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_RESUME,
 	CAM_REQ_MGR_LINK_EVT_RESUME,
 	CAM_REQ_MGR_LINK_EVT_SOF_FREEZE,
 	CAM_REQ_MGR_LINK_EVT_SOF_FREEZE,
 	CAM_REQ_MGR_LINK_EVT_STALLED,
 	CAM_REQ_MGR_LINK_EVT_STALLED,
+	CAM_REQ_MGR_LINK_EVT_EOF,
+	CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES,
 	CAM_REQ_MGR_LINK_EVT_MAX,
 	CAM_REQ_MGR_LINK_EVT_MAX,
 };
 };
 
 
@@ -291,7 +297,6 @@ struct cam_req_mgr_add_request {
 	bool     trigger_eof;
 	bool     trigger_eof;
 };
 };
 
 
-
 /**
 /**
  * struct cam_req_mgr_notify_stop
  * struct cam_req_mgr_notify_stop
  * @link_hdl             : link identifier
  * @link_hdl             : link identifier
@@ -377,9 +382,11 @@ struct cam_req_mgr_flush_request {
  * struct cam_req_mgr_event_data
  * struct cam_req_mgr_event_data
  * @link_hdl          : link handle
  * @link_hdl          : link handle
  * @req_id            : request id
  * @req_id            : request id
- * @evt_type          : link event
  * @try_for_recovery  : Link is stalled allow subdevices to recover if
  * @try_for_recovery  : Link is stalled allow subdevices to recover if
  *                      possible
  *                      possible
+ * @evt_type          : link event
+ * @error             : error code
+ * @properties_mask   : properties mask
  */
  */
 struct cam_req_mgr_link_evt_data {
 struct cam_req_mgr_link_evt_data {
 	int32_t  link_hdl;
 	int32_t  link_hdl;
@@ -389,6 +396,7 @@ struct cam_req_mgr_link_evt_data {
 	enum cam_req_mgr_link_evt_type evt_type;
 	enum cam_req_mgr_link_evt_type evt_type;
 	union {
 	union {
 		enum cam_req_mgr_device_error error;
 		enum cam_req_mgr_device_error error;
+		uint32_t properties_mask;
 	} u;
 	} u;
 };
 };
 
 

+ 138 - 29
drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c

@@ -12,9 +12,42 @@
 #include "cam_trace.h"
 #include "cam_trace.h"
 #include "cam_common_util.h"
 #include "cam_common_util.h"
 #include "cam_packet_util.h"
 #include "cam_packet_util.h"
+#include "cam_req_mgr_dev.h"
 
 
 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(
+	struct cam_sensor_ctrl_t *s_ctrl,
+	uint32_t error_type, uint32_t error_code)
+{
+	int                        rc = 0;
+	struct cam_req_mgr_message req_msg;
+
+	req_msg.session_hdl = s_ctrl->bridge_intf.session_hdl;
+	req_msg.u.err_msg.device_hdl = s_ctrl->bridge_intf.device_hdl;
+	req_msg.u.err_msg.link_hdl = s_ctrl->bridge_intf.link_hdl;
+	req_msg.u.err_msg.error_type = error_type;
+	req_msg.u.err_msg.request_id = s_ctrl->last_applied_req;
+	req_msg.u.err_msg.resource_size = 0x0;
+	req_msg.u.err_msg.error_code = error_code;
+
+	CAM_DBG(CAM_SENSOR,
+		"v4l2 error event [type: %u code: %u] for req: %llu on %s",
+		error_type, error_code, s_ctrl->last_applied_req,
+		s_ctrl->sensor_name);
+
+	rc = cam_req_mgr_notify_message(&req_msg,
+		V4L_EVENT_CAM_REQ_MGR_ERROR,
+		V4L_EVENT_CAM_REQ_MGR_EVENT);
+	if (rc)
+		CAM_ERR(CAM_SENSOR,
+			"Notifying v4l2 error [type: %u code: %u] failed for req id:%llu on %s",
+			error_type, error_code, s_ctrl->last_applied_req,
+			s_ctrl->sensor_name);
+
+	return rc;
+}
+
 static int cam_sensor_update_req_mgr(
 static int cam_sensor_update_req_mgr(
 	struct cam_sensor_ctrl_t *s_ctrl,
 	struct cam_sensor_ctrl_t *s_ctrl,
 	struct cam_packet *csl_packet)
 	struct cam_packet *csl_packet)
@@ -783,6 +816,48 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl)
 	return rc;
 	return rc;
 }
 }
 
 
+int cam_sensor_stream_off(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int               rc = 0;
+	struct timespec64 ts;
+	uint64_t          ms, sec, min, hrs;
+
+	if (s_ctrl->sensor_state != CAM_SENSOR_START) {
+		rc = -EINVAL;
+		CAM_WARN(CAM_SENSOR,
+			"Not in right state to stop %s state: %d",
+			s_ctrl->sensor_name, s_ctrl->sensor_state);
+		goto end;
+	}
+
+	if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid &&
+		(s_ctrl->i2c_data.streamoff_settings.request_id == 0)) {
+		rc = cam_sensor_apply_settings(s_ctrl, 0,
+			CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
+		if (rc < 0)
+			CAM_ERR(CAM_SENSOR,
+				"cannot apply streamoff settings for %s",
+				s_ctrl->sensor_name);
+	}
+
+	cam_sensor_release_per_frame_resource(s_ctrl);
+	s_ctrl->last_flush_req = 0;
+	s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
+
+	CAM_GET_TIMESTAMP(ts);
+	CAM_CONVERT_TIMESTAMP_FORMAT(ts, hrs, min, sec, ms);
+
+	CAM_INFO(CAM_SENSOR,
+		"%llu:%llu:%llu.%llu CAM_STOP_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
+		hrs, min, sec, ms,
+		s_ctrl->sensor_name,
+		s_ctrl->sensordata->slave_info.sensor_id,
+		s_ctrl->sensordata->slave_info.sensor_slave_addr);
+
+end:
+	return rc;
+}
+
 int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 	void *arg)
 	void *arg)
 {
 {
@@ -1017,6 +1092,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 
 
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
 		s_ctrl->last_flush_req = 0;
 		s_ctrl->last_flush_req = 0;
+		s_ctrl->is_flushed = false;
 		CAM_INFO(CAM_SENSOR,
 		CAM_INFO(CAM_SENSOR,
 			"CAM_ACQUIRE_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
 			"CAM_ACQUIRE_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
 			s_ctrl->sensor_name,
 			s_ctrl->sensor_name,
@@ -1150,38 +1226,15 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 	}
 	}
 		break;
 		break;
 	case CAM_STOP_DEV: {
 	case CAM_STOP_DEV: {
-		if (s_ctrl->sensor_state != CAM_SENSOR_START) {
-			rc = -EINVAL;
-			CAM_WARN(CAM_SENSOR,
-			"Not in right state to stop %s state: %d",
-			s_ctrl->sensor_name, s_ctrl->sensor_state);
+		if ((s_ctrl->stream_off_after_eof) && (!s_ctrl->is_flushed)) {
+			CAM_DBG(CAM_SENSOR, "Ignore stop dev cmd for VFPS feature");
 			goto release_mutex;
 			goto release_mutex;
 		}
 		}
 
 
-		if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid &&
-			(s_ctrl->i2c_data.streamoff_settings.request_id == 0)) {
-			rc = cam_sensor_apply_settings(s_ctrl, 0,
-				CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
-			if (rc < 0) {
-				CAM_ERR(CAM_SENSOR,
-				"cannot apply streamoff settings for %s",
-				s_ctrl->sensor_name);
-			}
-		}
-
-		cam_sensor_release_per_frame_resource(s_ctrl);
-		s_ctrl->last_flush_req = 0;
-		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
-
-		CAM_GET_TIMESTAMP(ts);
-		CAM_CONVERT_TIMESTAMP_FORMAT(ts, hrs, min, sec, ms);
-
-		CAM_INFO(CAM_SENSOR,
-			"%llu:%llu:%llu.%llu CAM_STOP_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
-			hrs, min, sec, ms,
-			s_ctrl->sensor_name,
-			s_ctrl->sensordata->slave_info.sensor_id,
-			s_ctrl->sensordata->slave_info.sensor_slave_addr);
+		rc = cam_sensor_stream_off(s_ctrl);
+		if (rc)
+			goto release_mutex;
+		s_ctrl->is_flushed = false;
 	}
 	}
 		break;
 		break;
 	case CAM_CONFIG_DEV: {
 	case CAM_CONFIG_DEV: {
@@ -1578,6 +1631,8 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl,
 				"Invalid/NOP request to apply: %lld", req_id);
 				"Invalid/NOP request to apply: %lld", req_id);
 		}
 		}
 
 
+		s_ctrl->last_applied_req = req_id;
+
 		/* Change the logic dynamically */
 		/* Change the logic dynamically */
 		for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
 		for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
 			if ((req_id >=
 			if ((req_id >=
@@ -1769,6 +1824,60 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req)
 		CAM_DBG(CAM_SENSOR,
 		CAM_DBG(CAM_SENSOR,
 			"Flush request id:%lld not found in the pending list",
 			"Flush request id:%lld not found in the pending list",
 			flush_req->req_id);
 			flush_req->req_id);
+
+	if (s_ctrl->stream_off_after_eof)
+		s_ctrl->is_flushed = true;
+
+	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+	return rc;
+}
+
+int cam_sensor_process_evt(struct cam_req_mgr_link_evt_data *evt_data)
+{
+	int                       rc = 0;
+	struct cam_sensor_ctrl_t *s_ctrl = NULL;
+
+	if (!evt_data)
+		return -EINVAL;
+
+	s_ctrl = (struct cam_sensor_ctrl_t *)
+		cam_get_device_priv(evt_data->dev_hdl);
+	if (!s_ctrl) {
+		CAM_ERR(CAM_SENSOR, "Device data is NULL");
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_SENSOR, "Received evt:%d", evt_data->evt_type);
+
+	mutex_lock(&(s_ctrl->cam_sensor_mutex));
+
+	switch (evt_data->evt_type) {
+	case CAM_REQ_MGR_LINK_EVT_EOF:
+		if (s_ctrl->stream_off_after_eof) {
+			rc = cam_sensor_stream_off(s_ctrl);
+			if (rc) {
+				CAM_ERR(CAM_SENSOR, "Failed to stream off %s",
+					s_ctrl->sensor_name);
+
+				cam_sensor_notify_v4l2_error_event(s_ctrl,
+					CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY,
+					CAM_REQ_MGR_SENSOR_STREAM_OFF_FAILED);
+			}
+		}
+		break;
+	case CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES:
+		if (evt_data->u.properties_mask &
+			CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)
+			s_ctrl->stream_off_after_eof = true;
+		else
+			s_ctrl->stream_off_after_eof = false;
+		break;
+	default:
+		/* No handling */
+		break;
+	}
+
 	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
 	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+
 	return rc;
 	return rc;
 }
 }

+ 8 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
  * Copyright (c) 2017-2018,2020, The Linux Foundation. All rights reserved.
  * Copyright (c) 2017-2018,2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_SENSOR_CORE_H_
 #ifndef _CAM_SENSOR_CORE_H_
@@ -75,6 +76,13 @@ int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info);
  */
  */
 int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link);
 int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link);
 
 
+/**
+ * @evt_data: Event data info
+ *
+ * This API processes the event which is published by request mgr
+ */
+int cam_sensor_process_evt(struct cam_req_mgr_link_evt_data *evt_data);
+
 /**
 /**
  * @s_ctrl: Sensor ctrl structure
  * @s_ctrl: Sensor ctrl structure
  * @arg:    Camera control command argument
  * @arg:    Camera control command argument

+ 1 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c

@@ -447,6 +447,7 @@ static int cam_sensor_component_bind(struct device *dev,
 	s_ctrl->bridge_intf.ops.notify_frame_skip =
 	s_ctrl->bridge_intf.ops.notify_frame_skip =
 		cam_sensor_notify_frame_skip;
 		cam_sensor_notify_frame_skip;
 	s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request;
 	s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request;
+	s_ctrl->bridge_intf.ops.process_evt = cam_sensor_process_evt;
 
 
 	s_ctrl->sensordata->power_info.dev = &pdev->dev;
 	s_ctrl->sensordata->power_info.dev = &pdev->dev;
 	platform_set_drvdata(pdev, s_ctrl);
 	platform_set_drvdata(pdev, s_ctrl);

+ 6 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h

@@ -82,6 +82,9 @@ struct sensor_intf_params {
  * @pipeline_delay: Sensor pipeline delay
  * @pipeline_delay: Sensor pipeline 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 applied request id
+ * @is_flushed: Indicate if the request has been flushed
+ * @stream_off_after_eof: Indicates if sensor needs to stream off after eof
  */
  */
 struct cam_sensor_ctrl_t {
 struct cam_sensor_ctrl_t {
 	char                           device_name[CAM_CTX_DEV_NAME_MAX_LENGTH];
 	char                           device_name[CAM_CTX_DEV_NAME_MAX_LENGTH];
@@ -111,6 +114,9 @@ struct cam_sensor_ctrl_t {
 	uint16_t                       pipeline_delay;
 	uint16_t                       pipeline_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_applied_req;
+	bool                           is_flushed;
+	bool                           stream_off_after_eof;
 };
 };
 
 
 /**
 /**