Przeglądaj źródła

msm: camera: isp: Obtain timestamp as part of frame header

In use-cases that involve custom HW retrieve the timestamp
for shutter from frame header as opposed to csid registers.

CRs-Fixed: 2524308
Change-Id: I5de789cf939546affbfe6d537d8090982f39189d
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 5 lat temu
rodzic
commit
381bb12c68

+ 5 - 1
drivers/cam_core/cam_hw_mgr_intf.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_HW_MGR_INTF_H_
@@ -101,6 +101,8 @@ struct cam_hw_done_event_data {
  * @num_acq:               Total number of acquire in the payload
  * @acquire_info:          Acquired resource array pointer
  * @ctxt_to_hw_map:        HW context (returned)
+ * @custom_enabled:        ctx has custom enabled
+ * @use_frame_header_ts:   Use frame header for qtimer ts
  * @acquired_hw_id:        Acquired hardware mask
  * @acquired_hw_path:      Acquired path mask for an input
  *                         if input splits into multiple paths,
@@ -115,6 +117,8 @@ struct cam_hw_acquire_args {
 	uint32_t                     acquire_info_size;
 	uintptr_t                    acquire_info;
 	void                        *ctxt_to_hw_map;
+	bool                         custom_enabled;
+	bool                         use_frame_header_ts;
 
 	uint32_t    acquired_hw_id[CAM_MAX_ACQ_RES];
 	uint32_t    acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT];

+ 79 - 11
drivers/cam_isp/cam_isp_context.c

@@ -425,6 +425,7 @@ static int __cam_isp_ctx_enqueue_init_request(
 	struct cam_isp_ctx_req                *req_isp_new;
 	struct cam_isp_prepare_hw_update_data *req_update_old;
 	struct cam_isp_prepare_hw_update_data *req_update_new;
+	struct cam_isp_prepare_hw_update_data *hw_update_data;
 
 	spin_lock_bh(&ctx->lock);
 	if (list_empty(&ctx->pending_req_list)) {
@@ -487,6 +488,13 @@ static int __cam_isp_ctx_enqueue_init_request(
 					req_update_new->num_reg_dump_buf;
 			}
 
+			/* Update frame header params for EPCR */
+			hw_update_data = &req_isp_new->hw_update_data;
+			req_isp_old->hw_update_data.frame_header_res_id =
+				req_isp_new->hw_update_data.frame_header_res_id;
+			req_isp_old->hw_update_data.frame_header_cpu_addr =
+				hw_update_data->frame_header_cpu_addr;
+
 			req_old->request_id = req->request_id;
 
 			list_add_tail(&req->list, &ctx->free_req_list);
@@ -645,9 +653,9 @@ static void __cam_isp_ctx_send_sof_boot_timestamp(
 	req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta;
 
 	CAM_DBG(CAM_ISP,
-		"request id:%lld frame number:%lld boot time stamp:0x%llx",
+		"request id:%lld frame number:%lld boot time stamp:0x%llx status:%u",
 		 request_id, ctx_isp->frame_id,
-		 ctx_isp->boot_timestamp);
+		 ctx_isp->boot_timestamp, sof_event_status);
 
 	if (cam_req_mgr_notify_message(&req_msg,
 		V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS,
@@ -657,6 +665,41 @@ static void __cam_isp_ctx_send_sof_boot_timestamp(
 			request_id);
 }
 
+static void __cam_isp_ctx_send_sof_timestamp_frame_header(
+	struct cam_isp_context *ctx_isp, uint32_t *frame_header_cpu_addr,
+	uint64_t request_id, uint32_t sof_event_status)
+{
+	uint32_t *time32 = NULL;
+	uint64_t timestamp = 0;
+	struct cam_req_mgr_message   req_msg;
+
+	time32 = frame_header_cpu_addr;
+	timestamp = (uint64_t) time32[1];
+	timestamp = timestamp << 24;
+	timestamp |= (uint64_t)(time32[0] >> 8);
+	timestamp = mul_u64_u32_div(timestamp,
+			CAM_IFE_QTIMER_MUL_FACTOR,
+			CAM_IFE_QTIMER_DIV_FACTOR);
+
+	ctx_isp->sof_timestamp_val = timestamp;
+	req_msg.session_hdl = ctx_isp->base->session_hdl;
+	req_msg.u.frame_msg.frame_id = ctx_isp->frame_id;
+	req_msg.u.frame_msg.request_id = request_id;
+	req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val;
+	req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl;
+	req_msg.u.frame_msg.sof_status = sof_event_status;
+
+	CAM_DBG(CAM_ISP,
+		"request id:%lld frame number:%lld SOF time stamp:0x%llx status:%u",
+		 request_id, ctx_isp->frame_id,
+		ctx_isp->sof_timestamp_val, sof_event_status);
+
+	if (cam_req_mgr_notify_message(&req_msg,
+		V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT))
+		CAM_ERR(CAM_ISP,
+			"Error in notifying the sof time for req id:%lld",
+			request_id);
+}
 
 static void __cam_isp_ctx_send_sof_timestamp(
 	struct cam_isp_context *ctx_isp, uint64_t request_id,
@@ -664,6 +707,10 @@ static void __cam_isp_ctx_send_sof_timestamp(
 {
 	struct cam_req_mgr_message   req_msg;
 
+	if ((ctx_isp->use_frame_header_ts) && (request_id) &&
+		(sof_event_status == CAM_REQ_MGR_SOF_EVENT_SUCCESS))
+		goto end;
+
 	req_msg.session_hdl = ctx_isp->base->session_hdl;
 	req_msg.u.frame_msg.frame_id = ctx_isp->frame_id;
 	req_msg.u.frame_msg.request_id = request_id;
@@ -673,10 +720,9 @@ static void __cam_isp_ctx_send_sof_timestamp(
 	req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta;
 
 	CAM_DBG(CAM_ISP,
-		"request id:%lld frame number:%lld SOF time stamp:0x%llx",
+		"request id:%lld frame number:%lld SOF time stamp:0x%llx status:%u",
 		 request_id, ctx_isp->frame_id,
-		ctx_isp->sof_timestamp_val);
-	CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status);
+		ctx_isp->sof_timestamp_val, sof_event_status);
 
 	if (cam_req_mgr_notify_message(&req_msg,
 		V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT))
@@ -684,9 +730,9 @@ static void __cam_isp_ctx_send_sof_timestamp(
 			"Error in notifying the sof time for req id:%lld",
 			request_id);
 
+end:
 	__cam_isp_ctx_send_sof_boot_timestamp(ctx_isp,
 		request_id, sof_event_status);
-
 }
 
 static void __cam_isp_ctx_handle_buf_done_fail_log(
@@ -738,7 +784,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
 {
 	int rc = 0;
 	int i, j;
-	struct cam_isp_ctx_req  *req_isp;
+	struct cam_isp_ctx_req *req_isp;
 	struct cam_context *ctx = ctx_isp->base;
 	uint64_t buf_done_req_id;
 	const char *handle_type;
@@ -840,6 +886,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
 			req_isp->num_acked++;
 			req_isp->fence_map_out[j].sync_id = -1;
 		}
+
+		if ((ctx_isp->use_frame_header_ts) &&
+			(req_isp->hw_update_data.frame_header_res_id ==
+			req_isp->fence_map_out[j].resource_handle))
+			__cam_isp_ctx_send_sof_timestamp_frame_header(
+				ctx_isp,
+				req_isp->hw_update_data.frame_header_cpu_addr,
+				req->request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 	}
 
 	if (req_isp->num_acked > req_isp->num_fence_map_out) {
@@ -883,10 +937,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
 				ctx->ctx_id);
 		}
 	} else {
-		if (ctx_isp->reported_req_id < buf_done_req_id) {
-			ctx_isp->reported_req_id = buf_done_req_id;
-			__cam_isp_ctx_send_sof_timestamp(ctx_isp,
-				buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
+		if (!ctx_isp->use_frame_header_ts) {
+			if (ctx_isp->reported_req_id < buf_done_req_id) {
+				ctx_isp->reported_req_id = buf_done_req_id;
+				__cam_isp_ctx_send_sof_timestamp(ctx_isp,
+					buf_done_req_id,
+					CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+			}
 		}
 		list_del_init(&req->list);
 		list_add_tail(&req->list, &ctx->free_req_list);
@@ -3375,6 +3433,8 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx,
 	}
 
 	ctx->last_flush_req = 0;
+	ctx_isp->custom_enabled = false;
+	ctx_isp->use_frame_header_ts = false;
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
 	ctx_isp->reported_req_id = 0;
@@ -4030,6 +4090,12 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 		goto free_res;
 	}
 
+	/* Set custom flag if applicable
+	 * custom hw is supported only on v2
+	 */
+	ctx_isp->custom_enabled = param.custom_enabled;
+	ctx_isp->use_frame_header_ts = param.use_frame_header_ts;
+
 	/* Query the context has rdi only resource */
 	hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map;
 	hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
@@ -4935,6 +5001,8 @@ int cam_isp_context_init(struct cam_isp_context *ctx,
 
 	ctx->base = ctx_base;
 	ctx->frame_id = 0;
+	ctx->custom_enabled = false;
+	ctx->use_frame_header_ts = false;
 	ctx->active_req_cnt = 0;
 	ctx->reported_req_id = 0;
 	ctx->req_info.last_bufdone_req_id = 0;

+ 8 - 0
drivers/cam_isp/cam_isp_context.h

@@ -15,6 +15,10 @@
 #include "cam_context.h"
 #include "cam_isp_hw_mgr_intf.h"
 
+
+#define CAM_IFE_QTIMER_MUL_FACTOR        10000
+#define CAM_IFE_QTIMER_DIV_FACTOR        192
+
 /*
  * Maximum hw resource - This number is based on the maximum
  * output port resource. The current maximum resource number
@@ -246,6 +250,8 @@ struct cam_isp_context_event_record {
  * @hw_acquired:               Indicate whether HW resources are acquired
  * @init_received:             Indicate whether init config packet is received
  * @split_acquire:             Indicate whether a separate acquire is expected
+ * @custom_enabled:            Custom HW enabled for this ctx
+ * @use_frame_header_ts:       Use frame header for qtimer ts
  * @init_timestamp:            Timestamp at which this context is initialized
  * @isp_device_type            ISP device type
  *
@@ -283,6 +289,8 @@ struct cam_isp_context {
 	bool                                  hw_acquired;
 	bool                                  init_received;
 	bool                                  split_acquire;
+	bool                                  custom_enabled;
+	bool                                  use_frame_header_ts;
 	unsigned int                          init_timestamp;
 	uint32_t                              isp_device_type;
 };

+ 104 - 3
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -2695,6 +2695,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 		goto err;
 	}
 
+	ife_ctx->custom_enabled = false;
 	ife_ctx->common.cb_priv = acquire_args->context_data;
 	for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++)
 		ife_ctx->common.event_cb[i] = acquire_args->event_cb;
@@ -2748,6 +2749,12 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 		}
 		CAM_DBG(CAM_ISP, "in_res_type %x", in_port->res_type);
 
+		if ((in_port->cust_node) && (!ife_ctx->custom_enabled)) {
+			ife_ctx->custom_enabled = true;
+			/* This can be obtained from uapi */
+			ife_ctx->use_frame_header_ts = true;
+		}
+
 		rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port,
 			&num_pix_port_per_in, &num_rdi_port_per_in,
 			&acquire_args->acquired_hw_id[i],
@@ -2782,6 +2789,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	}
 
 	acquire_args->ctxt_to_hw_map = ife_ctx;
+	acquire_args->custom_enabled = ife_ctx->custom_enabled;
+	acquire_args->use_frame_header_ts = ife_ctx->use_frame_header_ts;
 	ife_ctx->ctx_in_use = 1;
 	ife_ctx->num_reg_dump_buf = 0;
 
@@ -4193,6 +4202,8 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
 	ctx->cdm_handle = 0;
 	ctx->cdm_ops = NULL;
 	ctx->num_reg_dump_buf = 0;
+	ctx->custom_enabled = false;
+	ctx->use_frame_header_ts = false;
 	atomic_set(&ctx->overflow_pending, 0);
 	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
 		ctx->sof_cnt[i] = 0;
@@ -5555,6 +5566,58 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 	return rc;
 }
 
+static int cam_ife_mgr_util_insert_frame_header(
+	struct cam_kmd_buf_info *kmd_buf,
+	struct cam_isp_prepare_hw_update_data *prepare_hw_data)
+{
+	int mmu_hdl = -1, rc = 0;
+	dma_addr_t iova_addr;
+	uint32_t frame_header_iova, padded_bytes = 0;
+	size_t len;
+	struct cam_ife_hw_mgr *hw_mgr = &g_ife_hw_mgr;
+
+	mmu_hdl = cam_mem_is_secure_buf(
+			kmd_buf->handle) ?
+			hw_mgr->mgr_common.img_iommu_hdl_secure :
+			hw_mgr->mgr_common.img_iommu_hdl;
+
+	rc = cam_mem_get_io_buf(kmd_buf->handle, mmu_hdl,
+		&iova_addr, &len);
+	if (rc) {
+		CAM_ERR(CAM_ISP,
+			"Failed to get io addr for handle = %d for mmu_hdl = %u",
+			kmd_buf->handle, mmu_hdl);
+		return rc;
+	}
+
+	frame_header_iova = (uint32_t)iova_addr;
+	frame_header_iova += kmd_buf->offset;
+
+	/* frame header address needs to be 16 byte aligned */
+	if (frame_header_iova % 16) {
+		padded_bytes = (uint32_t)(16 - (frame_header_iova % 16));
+		iova_addr += padded_bytes;
+	}
+
+	prepare_hw_data->frame_header_iova = frame_header_iova;
+
+	/* update the padding if any for the cpu addr as well */
+	prepare_hw_data->frame_header_cpu_addr = kmd_buf->cpu_addr +
+			(padded_bytes / 4);
+
+	CAM_DBG(CAM_ISP,
+		"Frame Header iova_addr: %pK cpu_addr: %pK padded_bytes: %llu",
+		prepare_hw_data->frame_header_iova,
+		prepare_hw_data->frame_header_cpu_addr,
+		padded_bytes);
+
+	/* Reserve memory for frame header */
+	kmd_buf->used_bytes += 128;
+	kmd_buf->offset += kmd_buf->used_bytes;
+
+	return rc;
+}
+
 static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 	void *prepare_hw_update_args)
 {
@@ -5566,7 +5629,9 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 	struct cam_kmd_buf_info                  kmd_buf;
 	uint32_t                                 i;
 	bool                                     fill_fence = true;
+	bool                                     frame_header_enable = false;
 	struct cam_isp_prepare_hw_update_data   *prepare_hw_data;
+	struct cam_isp_frame_header_info         frame_header_info;
 
 	if (!hw_mgr_priv || !prepare_hw_update_args) {
 		CAM_ERR(CAM_ISP, "Invalid args");
@@ -5593,6 +5658,15 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 	if (rc)
 		return rc;
 
+	if (ctx->use_frame_header_ts) {
+		rc = cam_ife_mgr_util_insert_frame_header(&kmd_buf,
+			prepare_hw_data);
+		if (rc)
+			return rc;
+
+		frame_header_enable = true;
+	}
+
 	rc = cam_packet_util_process_patches(prepare->packet,
 		hw_mgr->mgr_common.cmd_iommu_hdl,
 		hw_mgr->mgr_common.cmd_iommu_hdl_secure);
@@ -5641,13 +5715,23 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 			}
 		}
 
+		memset(&frame_header_info, 0,
+			sizeof(struct cam_isp_frame_header_info));
+		if (frame_header_enable) {
+			frame_header_info.frame_header_enable = true;
+			frame_header_info.frame_header_iova_addr =
+				prepare_hw_data->frame_header_iova;
+		}
+
 		/* get IO buffers */
-		rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl,
+		rc = cam_isp_add_io_buffers(
+			hw_mgr->mgr_common.img_iommu_hdl,
 			hw_mgr->mgr_common.img_iommu_hdl_secure,
 			prepare, ctx->base[i].idx,
 			&kmd_buf, ctx->res_list_ife_out,
 			&ctx->res_list_ife_in_rd,
-			CAM_IFE_HW_OUT_RES_MAX, fill_fence);
+			CAM_IFE_HW_OUT_RES_MAX, fill_fence,
+			&frame_header_info);
 
 		if (rc) {
 			CAM_ERR(CAM_ISP,
@@ -5659,6 +5743,18 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 		/* fence map table entries need to fill only once in the loop */
 		if (fill_fence)
 			fill_fence = false;
+
+		if (frame_header_info.frame_header_res_id &&
+			frame_header_enable) {
+			frame_header_enable = false;
+			prepare_hw_data->frame_header_res_id =
+				frame_header_info.frame_header_res_id;
+
+			CAM_DBG(CAM_ISP,
+				"Frame header enabled for res_id 0x%x cpu_addr %pK",
+				prepare_hw_data->frame_header_res_id,
+				prepare_hw_data->frame_header_cpu_addr);
+		}
 	}
 
 	/*
@@ -6643,10 +6739,15 @@ static int cam_ife_hw_mgr_handle_hw_sof(
 		rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx,
 			CAM_ISP_HW_EVENT_SOF);
 		if (!rc) {
-			cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx,
+			cam_ife_mgr_cmd_get_sof_timestamp(
+				ife_hw_mgr_ctx,
 				&sof_done_event_data.timestamp,
 				&sof_done_event_data.boot_time);
 
+			/* if frame header is enabled reset qtimer ts */
+			if (ife_hw_mgr_ctx->use_frame_header_ts)
+				sof_done_event_data.timestamp = 0x0;
+
 			if (atomic_read(&ife_hw_mgr_ctx->overflow_pending))
 				break;
 

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

@@ -82,6 +82,8 @@ struct cam_ife_hw_mgr_debug {
  * @init_done               indicate whether init hw is done
  * @is_fe_enable            indicate whether fetch engine\read path is enabled
  * @is_dual                 indicate whether context is in dual VFE mode
+ * @custom_enabled          update the flag if context is connected to custom HW
+ * @use_frame_header_ts     obtain qtimer ts using frame header
  * @ts                      captured timestamp when the ctx is acquired
  */
 struct cam_ife_hw_mgr_ctx {
@@ -129,6 +131,8 @@ struct cam_ife_hw_mgr_ctx {
 	bool                            init_done;
 	bool                            is_fe_enable;
 	bool                            is_dual;
+	bool                            custom_enabled;
+	bool                            use_frame_header_ts;
 	struct timespec64               ts;
 };
 

+ 7 - 1
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -3809,6 +3809,7 @@ static int cam_tfe_mgr_prepare_hw_update(void *hw_mgr_priv,
 	uint32_t                                 i;
 	bool                                     fill_fence = true;
 	struct cam_isp_prepare_hw_update_data   *prepare_hw_data;
+	struct cam_isp_frame_header_info         frame_header_info;
 
 	if (!hw_mgr_priv || !prepare_hw_update_args) {
 		CAM_ERR(CAM_ISP, "Invalid args");
@@ -3886,13 +3887,18 @@ static int cam_tfe_mgr_prepare_hw_update(void *hw_mgr_priv,
 			}
 		}
 
+		memset(&frame_header_info, 0,
+			sizeof(struct cam_isp_frame_header_info));
+		frame_header_info.frame_header_enable = false;
+
 		/* get IO buffers */
 		rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl,
 			hw_mgr->mgr_common.img_iommu_hdl_secure,
 			prepare, ctx->base[i].idx,
 			&kmd_buf, ctx->res_list_tfe_out,
 			NULL,
-			CAM_TFE_HW_OUT_RES_MAX, fill_fence);
+			CAM_TFE_HW_OUT_RES_MAX, fill_fence,
+			&frame_header_info);
 
 		if (rc) {
 			CAM_ERR(CAM_ISP,

+ 18 - 1
drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c

@@ -463,7 +463,8 @@ int cam_isp_add_io_buffers(
 	struct cam_isp_hw_mgr_res            *res_list_isp_out,
 	struct list_head                     *res_list_ife_in_rd,
 	uint32_t                              size_isp_out,
-	bool                                  fill_fence)
+	bool                                  fill_fence,
+	struct cam_isp_frame_header_info     *frame_header_info)
 {
 	int                                 rc = 0;
 	dma_addr_t                          io_addr[CAM_PACKET_MAX_PLANES];
@@ -480,6 +481,7 @@ int cam_isp_add_io_buffers(
 	uint32_t                            i, j, num_out_buf, num_in_buf;
 	uint32_t                            res_id_out, res_id_in, plane_id;
 	uint32_t                            io_cfg_used_bytes, num_ent;
+	uint64_t                            iova_addr;
 	size_t                              size;
 	int32_t                             hdl;
 	int                                 mmu_hdl;
@@ -693,6 +695,21 @@ int cam_isp_add_io_buffers(
 			wm_update.image_buf = io_addr;
 			wm_update.num_buf   = plane_id;
 			wm_update.io_cfg    = &io_cfg[i];
+			wm_update.frame_header = 0;
+			iova_addr = frame_header_info->frame_header_iova_addr;
+			if ((frame_header_info->frame_header_enable) &&
+				!(frame_header_info->frame_header_res_id)) {
+				wm_update.frame_header = iova_addr;
+				frame_header_info->frame_header_res_id =
+					res->res_id;
+				wm_update.local_id =
+					prepare->packet->header.request_id;
+				CAM_DBG(CAM_ISP,
+					"Frame header enabled for res: 0x%x iova: %pK",
+					frame_header_info->frame_header_res_id,
+					wm_update.frame_header);
+			}
+
 			update_buf.cmd.size = kmd_buf_remain_size;
 			update_buf.wm_update = &wm_update;
 

+ 16 - 2
drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h

@@ -34,6 +34,19 @@ struct cam_isp_generic_blob_info {
 	struct cam_kmd_buf_info               *kmd_buf_info;
 };
 
+/*
+ * struct cam_isp_frame_header_info
+ *
+ * @frame_header_enable:    Enable frame header
+ * @frame_header_iova_addr: frame header iova
+ * @frame_header_res_id:    res id for which frame header is enabled
+ */
+struct cam_isp_frame_header_info {
+	bool                     frame_header_enable;
+	uint64_t                 frame_header_iova_addr;
+	uint32_t                 frame_header_res_id;
+};
+
 /*
  * cam_isp_add_change_base()
  *
@@ -127,7 +140,7 @@ int cam_isp_add_command_buffers(
  * @res_list_ife_in_rd:    IFE /VFE in rd resource list
  * @size_isp_out:          Size of the res_list_isp_out array
  * @fill_fence:            If true, Fence map table will be filled
- *
+ * @frame_header_info:     Frame header related params
  * @return:                0 for success
  *                         -EINVAL for Fail
  */
@@ -140,7 +153,8 @@ int cam_isp_add_io_buffers(
 	struct cam_isp_hw_mgr_res            *res_list_isp_out,
 	struct list_head                     *res_list_ife_in_rd,
 	uint32_t                              size_isp_out,
-	bool                                  fill_fence);
+	bool                                  fill_fence,
+	struct cam_isp_frame_header_info     *frame_header_info);
 
 /*
  * cam_isp_add_reg_update()

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

@@ -121,6 +121,9 @@ struct cam_isp_bw_config_internal {
  * @packet_opcode_type:     Packet header opcode in the packet header
  *                          this opcode defines, packet is init packet or
  *                          update packet
+ * @frame_header_cpu_addr:  Frame header cpu addr
+ * @frame_header_iova:      Frame header iova
+ * @frame_header_res_id:    Out port res_id corresponding to frame header
  * @bw_config_version:      BW config version indicator
  * @bw_config:              BW config information
  * @bw_config_v2:           BW config info for AXI bw voting v2
@@ -133,10 +136,13 @@ struct cam_isp_bw_config_internal {
 struct cam_isp_prepare_hw_update_data {
 	void                                 *isp_mgr_ctx;
 	uint32_t                              packet_opcode_type;
+	uint32_t                             *frame_header_cpu_addr;
+	uint64_t                              frame_header_iova;
+	uint32_t                              frame_header_res_id;
 	uint32_t                              bw_config_version;
 	struct cam_isp_bw_config_internal     bw_config[CAM_IFE_HW_NUM_MAX];
 	struct cam_isp_bw_config_internal_v2  bw_config_v2[CAM_IFE_HW_NUM_MAX];
-	bool                                bw_config_valid[CAM_IFE_HW_NUM_MAX];
+	bool                               bw_config_valid[CAM_IFE_HW_NUM_MAX];
 	struct cam_cmd_buf_desc               reg_dump_buf_desc[
 						CAM_REG_DUMP_MAX_BUF_ENTRIES];
 	uint32_t                              num_reg_dump_buf;

+ 4 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_CSID_HW_INTF_H_
@@ -187,9 +187,9 @@ struct cam_csid_reset_cfg_args {
 
 /**
  * struct cam_csid_get_time_stamp_args-  time stamp capture arguments
- * @res_node :   resource to get the time stamp
- * @time_stamp_val : captured time stamp
- * @boot_timestamp : boot time stamp
+ * @node_res         : resource to get the time stamp
+ * @time_stamp_val   : captured time stamp
+ * @boot_timestamp   : boot time stamp
  */
 struct cam_csid_get_time_stamp_args {
 	struct cam_isp_resource_node      *node_res;

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

@@ -211,12 +211,16 @@ struct cam_isp_hw_cmd_buf_update {
  *
  * @ image_buf:    image buffer address array
  * @ num_buf:      Number of buffers in the image_buf array
+ * @ frame_header: frame header iova
+ * @ local_id:     local id for the wm
  * @ io_cfg:       IO buffer config information sent from UMD
  *
  */
 struct cam_isp_hw_get_wm_update {
 	dma_addr_t                     *image_buf;
 	uint32_t                        num_buf;
+	uint64_t                        frame_header;
+	uint32_t                        local_id;
 	struct cam_buf_io_cfg          *io_cfg;
 };
 

+ 22 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c

@@ -3010,6 +3010,7 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args,
 	uint32_t  i, j, k, size = 0;
 	uint32_t  frame_inc = 0, val;
 	uint32_t loop_size = 0;
+	bool frame_header_enable = false;
 
 	bus_priv = (struct cam_vfe_bus_ver3_priv  *) priv;
 	update_buf =  (struct cam_isp_hw_get_cmd_update *) cmd_args;
@@ -3043,6 +3044,27 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args,
 		wm_data = vfe_out_data->wm_res[i]->res_priv;
 		ubwc_client = wm_data->hw_regs->ubwc_regs;
 
+		/* Disable frame header in case it was previously enabled */
+		if ((wm_data->en_cfg) & (1 << 2))
+			wm_data->en_cfg &= ~(1 << 2);
+
+		if (update_buf->wm_update->frame_header &&
+			!frame_header_enable) {
+			wm_data->en_cfg |= 1 << 2;
+			frame_header_enable = true;
+			CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
+					wm_data->hw_regs->frame_header_addr,
+					update_buf->wm_update->frame_header);
+			CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
+					wm_data->hw_regs->frame_header_cfg,
+					update_buf->wm_update->local_id);
+			CAM_DBG(CAM_ISP,
+				"WM: %d en_cfg 0x%x frame_header %pK local_id %u",
+				wm_data->index, wm_data->en_cfg,
+				update_buf->wm_update->frame_header,
+				update_buf->wm_update->local_id);
+		}
+
 		CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
 			wm_data->hw_regs->cfg, wm_data->en_cfg);
 		CAM_DBG(CAM_ISP, "WM:%d en_cfg 0x%X",