Browse Source

msm: camera: isp: Add support for offline IFE

This change adds new IRQ state machine and updates the acquire
logic to enable offline IFE. This change also adds the fixes
necessary to enable bus read for various buffer formats and
append go command at the end of each packet for offline
context.

CRs-Fixed: 2513939
Change-Id: Ie068670ed11aa6713e8f0cb817e4b5d4c209e696
Signed-off-by: Venkat Chinta <[email protected]>
Venkat Chinta 5 years ago
parent
commit
8e79606ada

+ 199 - 7
drivers/cam_isp/cam_isp_context.c

@@ -1028,6 +1028,96 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
 	return rc;
 	return rc;
 }
 }
 
 
+static int __cam_isp_ctx_apply_req_offline(
+	struct cam_context *ctx, uint32_t next_state,
+	struct cam_isp_context *ctx_isp)
+{
+	int rc = 0;
+	struct cam_ctx_request          *req;
+	struct cam_isp_ctx_req          *req_isp;
+	struct cam_hw_config_args        cfg;
+
+	if (list_empty(&ctx->pending_req_list)) {
+		CAM_DBG(CAM_ISP, "No pending requests to apply");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if (ctx->state != CAM_CTX_ACTIVATED)
+		goto end;
+
+	if (ctx_isp->active_req_cnt >= 2)
+		goto end;
+
+	req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request,
+		list);
+
+	CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u",
+		req->request_id, ctx_isp->substate_activated, ctx->ctx_id);
+	req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	cfg.ctxt_to_hw_map = ctx_isp->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;
+
+	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
+	if (rc) {
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration");
+	} else {
+		atomic_set(&ctx_isp->rxd_epoch, 0);
+		ctx_isp->substate_activated = next_state;
+		ctx_isp->last_applied_req_id = req->request_id;
+		list_del_init(&req->list);
+		list_add_tail(&req->list, &ctx->wait_req_list);
+		CAM_DBG(CAM_ISP, "New substate state %d, applied req %lld",
+			next_state, ctx_isp->last_applied_req_id);
+
+		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
+			CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED,
+			req->request_id);
+	}
+end:
+	return rc;
+}
+
+static int __cam_isp_ctx_offline_epoch_in_activated_state(
+	struct cam_isp_context *ctx_isp, void *evt_data)
+{
+	struct cam_context *ctx = ctx_isp->base;
+	struct cam_ctx_request *req, *req_temp;
+	uint64_t request_id = 0;
+
+	atomic_set(&ctx_isp->rxd_epoch, 1);
+
+	CAM_DBG(CAM_ISP, "SOF frame %lld ctx %u", ctx_isp->frame_id,
+		ctx->ctx_id);
+
+	list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) {
+		if (req->request_id > ctx_isp->reported_req_id) {
+			request_id = req->request_id;
+			ctx_isp->reported_req_id = request_id;
+			break;
+		}
+	}
+
+	__cam_isp_ctx_apply_req_offline(ctx, CAM_ISP_CTX_ACTIVATED_APPLIED,
+		ctx_isp);
+
+	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+		CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
+	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
+		CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH,
+		request_id);
+
+	return 0;
+}
+
 static int __cam_isp_ctx_reg_upd_in_epoch_bubble_state(
 static int __cam_isp_ctx_reg_upd_in_epoch_bubble_state(
 	struct cam_isp_context *ctx_isp, void *evt_data)
 	struct cam_isp_context *ctx_isp, void *evt_data)
 {
 {
@@ -1811,6 +1901,9 @@ end:
 
 
 	} while (req->request_id < ctx_isp->last_applied_req_id);
 	} while (req->request_id < ctx_isp->last_applied_req_id);
 
 
+	if (ctx_isp->offline_context)
+		goto exit;
+
 	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) {
 	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) {
 		notify.link_hdl = ctx->link_hdl;
 		notify.link_hdl = ctx->link_hdl;
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.dev_hdl = ctx->dev_hdl;
@@ -1861,6 +1954,7 @@ end:
 
 
 	CAM_DBG(CAM_ISP, "Exit");
 	CAM_DBG(CAM_ISP, "Exit");
 
 
+exit:
 	return rc;
 	return rc;
 }
 }
 
 
@@ -2244,6 +2338,63 @@ static struct cam_isp_ctx_irq_ops
 	},
 	},
 };
 };
 
 
+static struct cam_isp_ctx_irq_ops
+	cam_isp_ctx_offline_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = {
+	/* SOF */
+	{
+		.irq_ops = {
+			__cam_isp_ctx_handle_error,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		},
+	},
+	/* APPLIED */
+	{
+		.irq_ops = {
+			__cam_isp_ctx_handle_error,
+			__cam_isp_ctx_sof_in_activated_state,
+			__cam_isp_ctx_reg_upd_in_applied_state,
+			NULL,
+			NULL,
+			__cam_isp_ctx_buf_done_in_applied,
+		},
+	},
+	/* EPOCH */
+	{
+		.irq_ops = {
+			__cam_isp_ctx_handle_error,
+			NULL,
+			NULL,
+			__cam_isp_ctx_offline_epoch_in_activated_state,
+			NULL,
+			__cam_isp_ctx_buf_done_in_epoch,
+		},
+	},
+	/* BUBBLE */
+	{
+	},
+	/* Bubble Applied */
+	{
+	},
+	/* HW ERROR */
+	{
+		.irq_ops = {
+			NULL,
+			__cam_isp_ctx_sof_in_activated_state,
+			__cam_isp_ctx_reg_upd_in_hw_error,
+			NULL,
+			NULL,
+			NULL,
+		},
+	},
+	/* HALT */
+	{
+	},
+};
+
 static int __cam_isp_ctx_apply_req_in_activated_state(
 static int __cam_isp_ctx_apply_req_in_activated_state(
 	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply,
 	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply,
 	enum cam_isp_ctx_activated_substate next_state)
 	enum cam_isp_ctx_activated_substate next_state)
@@ -2796,6 +2947,7 @@ static int __cam_isp_ctx_flush_req_in_top_state(
 end:
 end:
 	ctx_isp->bubble_frame_cnt = 0;
 	ctx_isp->bubble_frame_cnt = 0;
 	atomic_set(&ctx_isp->process_bubble, 0);
 	atomic_set(&ctx_isp->process_bubble, 0);
+	atomic_set(&ctx_isp->rxd_epoch, 0);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -3685,8 +3837,11 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 				ctx->state);
 				ctx->state);
 		}
 		}
 	} else {
 	} else {
-		if (ctx->state != CAM_CTX_FLUSHED && ctx->state >= CAM_CTX_READY
-			&& ctx->ctx_crm_intf->add_req) {
+		if (ctx_isp->offline_context) {
+			__cam_isp_ctx_enqueue_request_in_order(ctx, req);
+		} else if ((ctx->state != CAM_CTX_FLUSHED) &&
+			(ctx->state >= CAM_CTX_READY) &&
+			ctx->ctx_crm_intf->add_req) {
 			add_req.link_hdl = ctx->link_hdl;
 			add_req.link_hdl = ctx->link_hdl;
 			add_req.dev_hdl  = ctx->dev_hdl;
 			add_req.dev_hdl  = ctx->dev_hdl;
 			add_req.req_id   = req->request_id;
 			add_req.req_id   = req->request_id;
@@ -3713,6 +3868,13 @@ 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)) {
+		spin_lock_bh(&ctx->lock);
+		__cam_isp_ctx_apply_req_offline(ctx,
+			CAM_ISP_CTX_ACTIVATED_APPLIED, ctx_isp);
+		spin_unlock_bh(&ctx->lock);
+	}
+
 	return rc;
 	return rc;
 
 
 put_ref:
 put_ref:
@@ -3827,11 +3989,15 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
 			cam_isp_ctx_rdi_only_activated_state_machine;
 			cam_isp_ctx_rdi_only_activated_state_machine;
 		ctx_isp->rdi_only_context = true;
 		ctx_isp->rdi_only_context = true;
 	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
 	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
-		CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI");
+		CAM_DBG(CAM_ISP, "FS2 Session has PIX, RD and RDI");
 		ctx_isp->substate_machine_irq =
 		ctx_isp->substate_machine_irq =
 			cam_isp_ctx_fs2_state_machine_irq;
 			cam_isp_ctx_fs2_state_machine_irq;
 		ctx_isp->substate_machine =
 		ctx_isp->substate_machine =
 			cam_isp_ctx_fs2_state_machine;
 			cam_isp_ctx_fs2_state_machine;
+	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_OFFLINE) {
+		CAM_DBG(CAM_ISP, "offline Session has PIX and RD resources");
+		ctx_isp->substate_machine_irq =
+			cam_isp_ctx_offline_state_machine_irq;
 	} 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 =
@@ -3985,11 +4151,16 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
 			cam_isp_ctx_rdi_only_activated_state_machine;
 			cam_isp_ctx_rdi_only_activated_state_machine;
 		ctx_isp->rdi_only_context = true;
 		ctx_isp->rdi_only_context = true;
 	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
 	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
-		CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI");
+		CAM_DBG(CAM_ISP, "FS2 Session has PIX, RD and RDI");
 		ctx_isp->substate_machine_irq =
 		ctx_isp->substate_machine_irq =
 			cam_isp_ctx_fs2_state_machine_irq;
 			cam_isp_ctx_fs2_state_machine_irq;
 		ctx_isp->substate_machine =
 		ctx_isp->substate_machine =
 			cam_isp_ctx_fs2_state_machine;
 			cam_isp_ctx_fs2_state_machine;
+	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_OFFLINE) {
+		CAM_DBG(CAM_ISP, "Offline session has PIX and RD resources");
+		ctx_isp->substate_machine_irq =
+			cam_isp_ctx_offline_state_machine_irq;
+		ctx_isp->substate_machine = NULL;
 	} 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 =
@@ -4136,11 +4307,17 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 			cam_isp_ctx_rdi_only_activated_state_machine;
 			cam_isp_ctx_rdi_only_activated_state_machine;
 		ctx_isp->rdi_only_context = true;
 		ctx_isp->rdi_only_context = true;
 	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
 	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
-		CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI");
+		CAM_DBG(CAM_ISP, "FS2 Session has PIX, RD and RDI");
 		ctx_isp->substate_machine_irq =
 		ctx_isp->substate_machine_irq =
 			cam_isp_ctx_fs2_state_machine_irq;
 			cam_isp_ctx_fs2_state_machine_irq;
 		ctx_isp->substate_machine =
 		ctx_isp->substate_machine =
 			cam_isp_ctx_fs2_state_machine;
 			cam_isp_ctx_fs2_state_machine;
+	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_OFFLINE) {
+		CAM_DBG(CAM_ISP, "Offline Session has PIX and RD resources");
+		ctx_isp->substate_machine_irq =
+			cam_isp_ctx_offline_state_machine_irq;
+		ctx_isp->substate_machine = NULL;
+		ctx_isp->offline_context = true;
 	} 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 =
@@ -4207,7 +4384,7 @@ static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx,
 
 
 	rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd);
 	rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd);
 
 
-	if (!rc && (ctx->link_hdl >= 0)) {
+	if (!rc && ((ctx->link_hdl >= 0) || ctx_isp->offline_context)) {
 		ctx->state = CAM_CTX_READY;
 		ctx->state = CAM_CTX_READY;
 		trace_cam_context_state("ISP", ctx);
 		trace_cam_context_state("ISP", ctx);
 	}
 	}
@@ -4368,6 +4545,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 		start_isp.start_only = false;
 		start_isp.start_only = false;
 
 
 	atomic_set(&ctx_isp->process_bubble, 0);
 	atomic_set(&ctx_isp->process_bubble, 0);
+	atomic_set(&ctx_isp->rxd_epoch, 0);
 	ctx_isp->frame_id = 0;
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
 	ctx_isp->active_req_cnt = 0;
 	ctx_isp->reported_req_id = 0;
 	ctx_isp->reported_req_id = 0;
@@ -4390,11 +4568,24 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 	 */
 	 */
 	list_del_init(&req->list);
 	list_del_init(&req->list);
 
 
-	if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) {
+	if (ctx_isp->offline_context && !req_isp->num_fence_map_out) {
+		list_add_tail(&req->list, &ctx->free_req_list);
+		atomic_set(&ctx_isp->rxd_epoch, 1);
+		CAM_DBG(CAM_REQ,
+			"Move pending req: %lld to free list(cnt: %d) offline ctx %u",
+			req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
+	} else if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) {
 		list_add_tail(&req->list, &ctx->wait_req_list);
 		list_add_tail(&req->list, &ctx->wait_req_list);
+		CAM_DBG(CAM_REQ,
+			"Move pending req: %lld to wait list(cnt: %d) ctx %u",
+			req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
 	} else {
 	} else {
 		list_add_tail(&req->list, &ctx->active_req_list);
 		list_add_tail(&req->list, &ctx->active_req_list);
 		ctx_isp->active_req_cnt++;
 		ctx_isp->active_req_cnt++;
+		CAM_DBG(CAM_REQ,
+			"Move pending req: %lld to active list(cnt: %d) ctx %u offline %d",
+			req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id,
+			ctx_isp->offline_context);
 	}
 	}
 
 
 	/*
 	/*
@@ -4539,6 +4730,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
 	ctx_isp->last_applied_req_id = 0;
 	ctx_isp->last_applied_req_id = 0;
 	ctx_isp->req_info.last_bufdone_req_id = 0;
 	ctx_isp->req_info.last_bufdone_req_id = 0;
 	atomic_set(&ctx_isp->process_bubble, 0);
 	atomic_set(&ctx_isp->process_bubble, 0);
+	atomic_set(&ctx_isp->rxd_epoch, 0);
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
 
 	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
 	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)

+ 6 - 1
drivers/cam_isp/cam_isp_context.h

@@ -247,13 +247,16 @@ struct cam_isp_context_event_record {
  * @event_record:              Event record array
  * @event_record:              Event record array
  * @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
  * @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
  * @custom_enabled:            Custom HW enabled for this ctx
  * @custom_enabled:            Custom HW enabled for this ctx
  * @use_frame_header_ts:       Use frame header for qtimer ts
  * @use_frame_header_ts:       Use frame header for qtimer ts
  * @init_timestamp:            Timestamp at which this context is initialized
  * @init_timestamp:            Timestamp at which this context is initialized
- * @isp_device_type            ISP device type
+ * @isp_device_type:           ISP device type
+ * @rxd_epoch:                 Indicate whether epoch has been received. Used to
+ *                             decide whether to apply request in offline ctx
  *
  *
  */
  */
 struct cam_isp_context {
 struct cam_isp_context {
@@ -286,6 +289,7 @@ struct cam_isp_context {
 	struct cam_isp_context_event_record   event_record[
 	struct cam_isp_context_event_record   event_record[
 		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                                  hw_acquired;
 	bool                                  hw_acquired;
 	bool                                  init_received;
 	bool                                  init_received;
 	bool                                  split_acquire;
 	bool                                  split_acquire;
@@ -293,6 +297,7 @@ struct cam_isp_context {
 	bool                                  use_frame_header_ts;
 	bool                                  use_frame_header_ts;
 	unsigned int                          init_timestamp;
 	unsigned int                          init_timestamp;
 	uint32_t                              isp_device_type;
 	uint32_t                              isp_device_type;
+	atomic_t                              rxd_epoch;
 };
 };
 
 
 /**
 /**

+ 412 - 288
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -979,90 +979,6 @@ static int cam_ife_mgr_process_base_info(
 	return 0;
 	return 0;
 }
 }
 
 
-static int cam_ife_hw_mgr_acquire_res_bus_rd(
-	struct cam_ife_hw_mgr_ctx       *ife_ctx,
-	struct cam_isp_in_port_generic_info *in_port)
-{
-	int rc = -EINVAL;
-	struct cam_vfe_acquire_args               vfe_acquire;
-	struct cam_isp_hw_mgr_res                *ife_in_rd_res;
-	struct cam_hw_intf                       *hw_intf;
-	struct cam_isp_hw_mgr_res                *ife_src_res;
-	int i;
-
-	CAM_DBG(CAM_ISP, "Enter");
-
-	list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) {
-		if (ife_src_res->res_id != CAM_ISP_HW_VFE_IN_RD)
-			continue;
-
-		rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
-			&ife_in_rd_res);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-			goto err;
-		}
-		cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd,
-			&ife_in_rd_res);
-
-		vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD;
-		vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
-		vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops;
-		vfe_acquire.priv = ife_ctx;
-		vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index;
-		vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_isp;
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!ife_src_res->hw_res[i])
-				continue;
-
-			hw_intf = ife_src_res->hw_res[i]->hw_intf;
-			if (i == CAM_ISP_HW_SPLIT_LEFT) {
-				vfe_acquire.vfe_out.split_id  =
-					CAM_ISP_HW_SPLIT_LEFT;
-				if (ife_src_res->is_dual_isp) {
-					/*TBD */
-					vfe_acquire.vfe_out.is_master     = 1;
-					vfe_acquire.vfe_out.dual_slave_core =
-					ife_ctx->slave_hw_idx;
-				} else {
-					vfe_acquire.vfe_out.is_master   = 0;
-					vfe_acquire.vfe_out.dual_slave_core =
-						0;
-				}
-			} else {
-				vfe_acquire.vfe_out.split_id  =
-					CAM_ISP_HW_SPLIT_RIGHT;
-				vfe_acquire.vfe_out.is_master       = 0;
-				vfe_acquire.vfe_out.dual_slave_core =
-					ife_ctx->master_hw_idx;
-			}
-			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-				&vfe_acquire,
-				sizeof(struct cam_vfe_acquire_args));
-			if (rc) {
-				CAM_ERR(CAM_ISP,
-					"Can not acquire out resource 0x%x",
-					vfe_acquire.rsrc_type);
-				goto err;
-			}
-
-			ife_in_rd_res->hw_res[i] =
-				vfe_acquire.vfe_out.rsrc_node;
-			CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x",
-				ife_in_rd_res->hw_res[i]->res_type,
-				ife_in_rd_res->hw_res[i]->res_id);
-
-		}
-		ife_in_rd_res->is_dual_isp = in_port->usage_type;
-		ife_in_rd_res->res_type = CAM_ISP_RESOURCE_VFE_BUS_RD;
-	}
-
-	return 0;
-err:
-	CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc);
-	return rc;
-}
-
 static int cam_ife_hw_mgr_acquire_res_ife_out_rdi(
 static int cam_ife_hw_mgr_acquire_res_ife_out_rdi(
 	struct cam_ife_hw_mgr_ctx       *ife_ctx,
 	struct cam_ife_hw_mgr_ctx       *ife_ctx,
 	struct cam_isp_hw_mgr_res       *ife_src_res,
 	struct cam_isp_hw_mgr_res       *ife_src_res,
@@ -1297,125 +1213,6 @@ err:
 	return rc;
 	return rc;
 }
 }
 
 
-static int cam_ife_hw_mgr_acquire_res_ife_rd_src(
-	struct cam_ife_hw_mgr_ctx *ife_ctx,
-	struct cam_isp_in_port_generic_info *in_port)
-{
-	int rc                = -1;
-	struct cam_isp_hw_mgr_res                  *csid_res;
-	struct cam_isp_hw_mgr_res                  *ife_src_res;
-	struct cam_vfe_acquire_args                 vfe_acquire;
-	struct cam_hw_intf                         *hw_intf;
-	struct cam_ife_hw_mgr                      *ife_hw_mgr;
-	int vfe_idx = -1, i = 0;
-
-	ife_hw_mgr = ife_ctx->hw_mgr;
-
-	CAM_DBG(CAM_ISP, "Enter");
-	list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) {
-		if (csid_res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0) {
-			CAM_DBG(CAM_ISP, "not RDI0: %d", csid_res->res_id);
-			continue;
-		}
-
-		rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
-			&ife_src_res);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-			goto err;
-		}
-		cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src,
-			&ife_src_res);
-
-		CAM_DBG(CAM_ISP, "csid_res_id %d", csid_res->res_id);
-		vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN;
-		vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
-		vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops;
-		vfe_acquire.vfe_in.in_port = in_port;
-		vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD;
-		vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
-
-		ife_src_res->res_type = vfe_acquire.rsrc_type;
-		ife_src_res->res_id = vfe_acquire.vfe_in.res_id;
-		ife_src_res->is_dual_isp = csid_res->is_dual_isp;
-
-		hw_intf =
-			ife_hw_mgr->ife_devices[csid_res->hw_res[
-			CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx];
-
-		vfe_idx = csid_res->hw_res[
-			CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx;
-
-		/*
-		 * fill in more acquire information as needed
-		 */
-		if (ife_src_res->is_dual_isp)
-			vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER;
-
-		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-				&vfe_acquire,
-				sizeof(struct cam_vfe_acquire_args));
-		if (rc) {
-			CAM_ERR(CAM_ISP,
-				"Can not acquire IFE HW res %d",
-				csid_res->res_id);
-			goto err;
-		}
-		ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT] =
-			vfe_acquire.vfe_in.rsrc_node;
-		CAM_DBG(CAM_ISP,
-			"acquire success IFE:%d  res type :0x%x res id:0x%x",
-			hw_intf->hw_idx,
-			ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type,
-			ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id);
-
-		if (!ife_src_res->is_dual_isp)
-			goto acq;
-
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (i == CAM_ISP_HW_SPLIT_LEFT) {
-				CAM_DBG(CAM_ISP, "vfe_idx %d is acquired",
-					vfe_idx);
-				continue;
-			}
-
-			hw_intf = ife_hw_mgr->ife_devices[i];
-
-			/* fill in more acquire information as needed */
-			if (i == CAM_ISP_HW_SPLIT_RIGHT)
-				vfe_acquire.vfe_in.sync_mode =
-					CAM_ISP_HW_SYNC_SLAVE;
-
-			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-					&vfe_acquire,
-					sizeof(struct cam_vfe_acquire_args));
-			if (rc) {
-				CAM_ERR(CAM_ISP,
-					"Can not acquire IFE HW res %d",
-					csid_res->res_id);
-				goto err;
-			}
-			ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node;
-			CAM_DBG(CAM_ISP,
-				"acquire success IFE:%d  res type :0x%x res id:0x%x",
-				hw_intf->hw_idx,
-				ife_src_res->hw_res[i]->res_type,
-				ife_src_res->hw_res[i]->res_id);
-		}
-acq:
-		/*
-		 * It should be one to one mapping between
-		 * csid resource and ife source resource
-		 */
-		csid_res->num_children++;
-	}
-
-err:
-	/* release resource at the entry function */
-	CAM_DBG(CAM_ISP, "Exit rc %d", rc);
-	return rc;
-}
-
 static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx)
 static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx)
 {
 {
 	uint32_t hw_version, rc = 0;
 	uint32_t hw_version, rc = 0;
@@ -1547,6 +1344,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src(
 		vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
 		vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
 		vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops;
 		vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops;
 		vfe_acquire.vfe_in.in_port = in_port;
 		vfe_acquire.vfe_in.in_port = in_port;
+		vfe_acquire.vfe_in.is_fe_enabled = ife_ctx->is_fe_enabled;
+		vfe_acquire.vfe_in.is_offline = ife_ctx->is_offline;
 		vfe_acquire.priv = ife_ctx;
 		vfe_acquire.priv = ife_ctx;
 		vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler;
 		vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler;
 
 
@@ -1800,7 +1599,7 @@ static int cam_ife_mgr_acquire_cid_res(
 
 
 	/* Acquire Left if not already acquired */
 	/* Acquire Left if not already acquired */
 	/* For dual IFE cases, start acquiring the lower idx first */
 	/* For dual IFE cases, start acquiring the lower idx first */
-	if (ife_ctx->is_fe_enable || in_port->usage_type)
+	if (ife_ctx->is_fe_enabled || in_port->usage_type)
 		rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr,
 		rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr,
 			&csid_acquire, true);
 			&csid_acquire, true);
 	else
 	else
@@ -2166,7 +1965,7 @@ static int cam_ife_hw_mgr_acquire_res_root(
 		ife_ctx->res_list_ife_in.res_id = in_port->res_type;
 		ife_ctx->res_list_ife_in.res_id = in_port->res_type;
 		ife_ctx->res_list_ife_in.is_dual_isp = in_port->usage_type;
 		ife_ctx->res_list_ife_in.is_dual_isp = in_port->usage_type;
 	} else if ((ife_ctx->res_list_ife_in.res_id !=
 	} else if ((ife_ctx->res_list_ife_in.res_id !=
-		in_port->res_type) && (!ife_ctx->is_fe_enable))  {
+		in_port->res_type) && (!ife_ctx->is_fe_enabled))  {
 		CAM_ERR(CAM_ISP, "No Free resource for this context");
 		CAM_ERR(CAM_ISP, "No Free resource for this context");
 		goto err;
 		goto err;
 	} else {
 	} else {
@@ -2211,14 +2010,14 @@ static int cam_ife_mgr_check_and_update_fe_v0(
 		CAM_DBG(CAM_ISP, "in_port%d res_type %d", i,
 		CAM_DBG(CAM_ISP, "in_port%d res_type %d", i,
 			in_port->res_type);
 			in_port->res_type);
 		if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) {
 		if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) {
-			ife_ctx->is_fe_enable = true;
+			ife_ctx->is_fe_enabled = true;
 			break;
 			break;
 		}
 		}
 
 
 		in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port +
 		in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port +
 			in_port_length);
 			in_port_length);
 	}
 	}
-	CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable);
+	CAM_DBG(CAM_ISP, "is_fe_enabled %d", ife_ctx->is_fe_enabled);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2256,14 +2055,17 @@ static int cam_ife_mgr_check_and_update_fe_v2(
 		CAM_DBG(CAM_ISP, "in_port%d res_type %d", i,
 		CAM_DBG(CAM_ISP, "in_port%d res_type %d", i,
 			in_port->res_type);
 			in_port->res_type);
 		if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) {
 		if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) {
-			ife_ctx->is_fe_enable = true;
+			ife_ctx->is_fe_enabled = true;
+			if (in_port->offline_mode)
+				ife_ctx->is_offline = true;
 			break;
 			break;
 		}
 		}
 
 
 		in_port = (struct cam_isp_in_port_info_v2 *)
 		in_port = (struct cam_isp_in_port_info_v2 *)
 			((uint8_t *)in_port + in_port_length);
 			((uint8_t *)in_port + in_port_length);
 	}
 	}
-	CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable);
+	CAM_DBG(CAM_ISP, "is_fe_enabled %d is_offline %d",
+		ife_ctx->is_fe_enabled, ife_ctx->is_offline);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2316,22 +2118,21 @@ static int cam_ife_hw_mgr_preprocess_port(
 
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
 	ife_hw_mgr = ife_ctx->hw_mgr;
 
 
-	if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) {
+	if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD)
 		ife_rd_num++;
 		ife_rd_num++;
-	} else {
-		for (i = 0; i < in_port->num_out_res; i++) {
-			out_port = &in_port->data[i];
-			if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
-				rdi_num++;
-			else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD)
-				ppp_num++;
-			else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR)
-				lcr_num++;
-			else {
-				CAM_DBG(CAM_ISP, "out_res_type %d",
-				out_port->res_type);
-				ipp_num++;
-			}
+
+	for (i = 0; i < in_port->num_out_res; i++) {
+		out_port = &in_port->data[i];
+		if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
+			rdi_num++;
+		else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD)
+			ppp_num++;
+		else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR)
+			lcr_num++;
+		else {
+			CAM_DBG(CAM_ISP, "out_res_type %d",
+			out_port->res_type);
+			ipp_num++;
 		}
 		}
 	}
 	}
 
 
@@ -2347,6 +2148,290 @@ static int cam_ife_hw_mgr_preprocess_port(
 	return 0;
 	return 0;
 }
 }
 
 
+static int cam_ife_hw_mgr_acquire_offline_res_ife_bus_rd(
+	struct cam_ife_hw_mgr_ctx                  *ife_ctx,
+	struct cam_isp_in_port_generic_info        *in_port)
+{
+	int                                         rc = -EINVAL, j;
+	int                                         i = CAM_ISP_HW_SPLIT_LEFT;
+	struct cam_vfe_acquire_args                 vfe_acquire;
+	struct cam_isp_hw_mgr_res                  *ife_bus_rd_res;
+	struct cam_hw_intf                         *hw_intf;
+	struct cam_ife_hw_mgr                      *ife_hw_mgr;
+
+	ife_hw_mgr = ife_ctx->hw_mgr;
+
+	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &ife_bus_rd_res);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
+		goto end;
+	}
+
+	vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD;
+	vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
+	vfe_acquire.priv = ife_ctx;
+	vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler;
+
+	vfe_acquire.vfe_bus_rd.cdm_ops = ife_ctx->cdm_ops;
+	vfe_acquire.vfe_bus_rd.is_dual = (uint32_t)ife_ctx->is_dual;
+	vfe_acquire.vfe_bus_rd.is_offline = ife_ctx->is_offline;
+	vfe_acquire.vfe_bus_rd.res_id = CAM_ISP_HW_VFE_IN_RD;
+	vfe_acquire.vfe_bus_rd.unpacker_fmt = in_port->fe_unpacker_fmt;
+
+	for (j = 0; j < CAM_IFE_HW_NUM_MAX; j++) {
+		if (!ife_hw_mgr->ife_devices[j])
+			continue;
+
+		hw_intf = ife_hw_mgr->ife_devices[j];
+		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+			&vfe_acquire, sizeof(struct cam_vfe_acquire_args));
+
+		if (!rc) {
+			ife_bus_rd_res->hw_res[i] =
+				vfe_acquire.vfe_bus_rd.rsrc_node;
+
+			CAM_DBG(CAM_ISP, "Acquired VFE:%d BUS RD for LEFT", j);
+			break;
+		}
+	}
+
+	if (j == CAM_IFE_HW_NUM_MAX || !vfe_acquire.vfe_bus_rd.rsrc_node) {
+		CAM_ERR(CAM_ISP, "Failed to acquire BUS RD for LEFT", i);
+		goto put_res;
+	}
+
+	ife_bus_rd_res->res_type = vfe_acquire.rsrc_type;
+	ife_bus_rd_res->res_id = vfe_acquire.vfe_in.res_id;
+	ife_bus_rd_res->is_dual_isp = (uint32_t)ife_ctx->is_dual;
+	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, &ife_bus_rd_res);
+
+	if (ife_ctx->is_dual) {
+		for (j = 0; j < CAM_IFE_HW_NUM_MAX; j++) {
+			if (!ife_hw_mgr->ife_devices[j])
+				continue;
+
+			if (j == ife_bus_rd_res->hw_res[i]->hw_intf->hw_idx)
+				continue;
+
+			hw_intf = ife_hw_mgr->ife_devices[j];
+			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+				&vfe_acquire,
+				sizeof(struct cam_vfe_acquire_args));
+
+			if (!rc) {
+				ife_bus_rd_res->hw_res[++i] =
+					vfe_acquire.vfe_bus_rd.rsrc_node;
+
+				CAM_DBG(CAM_ISP,
+					"Acquired VFE:%d BUS RD for RIGHT", j);
+				break;
+			}
+		}
+
+		if (j == CAM_IFE_HW_NUM_MAX ||
+			!vfe_acquire.vfe_bus_rd.rsrc_node) {
+			CAM_ERR(CAM_ISP, "Failed to acquire BUS RD for RIGHT");
+			goto end;
+		}
+	}
+
+	return 0;
+
+put_res:
+	cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &ife_bus_rd_res);
+
+end:
+	return rc;
+}
+
+static int cam_ife_hw_mgr_acquire_offline_res_ife_camif(
+	struct cam_ife_hw_mgr_ctx                  *ife_ctx,
+	struct cam_isp_in_port_generic_info        *in_port,
+	bool                                        acquire_lcr,
+	uint32_t                                   *acquired_hw_id,
+	uint32_t                                   *acquired_hw_path)
+{
+	int                                         rc = -1;
+	int                                         i = CAM_ISP_HW_SPLIT_LEFT;
+	struct cam_isp_hw_mgr_res                  *ife_src_res;
+	struct cam_isp_hw_mgr_res                  *ife_bus_rd_res;
+	struct cam_vfe_acquire_args                 vfe_acquire;
+	struct cam_hw_intf                         *hw_intf;
+	struct cam_ife_hw_mgr                      *ife_hw_mgr;
+
+	ife_hw_mgr = ife_ctx->hw_mgr;
+
+	ife_bus_rd_res = list_first_entry(&ife_ctx->res_list_ife_in_rd,
+		struct cam_isp_hw_mgr_res, list);
+
+	if (!ife_bus_rd_res) {
+		CAM_ERR(CAM_ISP, "BUS RD resource has not been acquired");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &ife_src_res);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "No free resource");
+		goto end;
+	}
+
+	vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN;
+	vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
+	vfe_acquire.priv = ife_ctx;
+	vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler;
+
+	vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops;
+	vfe_acquire.vfe_in.in_port = in_port;
+	vfe_acquire.vfe_in.is_fe_enabled = ife_ctx->is_fe_enabled;
+	vfe_acquire.vfe_in.is_offline = ife_ctx->is_offline;
+
+	if (!acquire_lcr)
+		vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_CAMIF;
+	else
+		vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_LCR;
+
+	if (ife_ctx->is_dual)
+		vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER;
+	else
+		vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
+
+	hw_intf = ife_hw_mgr->ife_devices[
+		ife_bus_rd_res->hw_res[i]->hw_intf->hw_idx];
+
+	rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire,
+		sizeof(struct cam_vfe_acquire_args));
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Failed to acquire CAMIF for LEFT");
+		goto put_res;
+	}
+
+	ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node;
+
+	*acquired_hw_id |= cam_convert_hw_idx_to_ife_hw_num(
+		hw_intf->hw_idx);
+
+	acquired_hw_path[i] |= cam_convert_res_id_to_hw_path(
+		ife_src_res->hw_res[i]->res_id);
+
+	CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF for LEFT",
+		ife_src_res->hw_res[i]->hw_intf->hw_idx);
+
+	ife_src_res->res_type = vfe_acquire.rsrc_type;
+	ife_src_res->res_id = vfe_acquire.vfe_in.res_id;
+	ife_src_res->is_dual_isp = (uint32_t)ife_ctx->is_dual;
+	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, &ife_src_res);
+
+	if (ife_ctx->is_dual) {
+		vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_SLAVE;
+
+		hw_intf = ife_hw_mgr->ife_devices[
+			ife_bus_rd_res->hw_res[++i]->hw_intf->hw_idx];
+
+		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire,
+			sizeof(struct cam_vfe_acquire_args));
+
+		if (rc) {
+			CAM_ERR(CAM_ISP, "Failed to acquire CAMIF for RIGHT");
+			goto end;
+		}
+
+		ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node;
+
+		*acquired_hw_id |= cam_convert_hw_idx_to_ife_hw_num(
+			hw_intf->hw_idx);
+
+		acquired_hw_path[i] |= cam_convert_res_id_to_hw_path(
+			ife_src_res->hw_res[i]->res_id);
+
+		CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF for RIGHT",
+			ife_src_res->hw_res[i]->hw_intf->hw_idx);
+	}
+
+	ife_bus_rd_res->num_children++;
+
+	return rc;
+
+put_res:
+	cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &ife_src_res);
+
+end:
+	return rc;
+}
+
+static int cam_ife_mgr_acquire_hw_for_fe_ctx(
+	struct cam_ife_hw_mgr_ctx           *ife_ctx,
+	struct cam_isp_in_port_generic_info *in_port,
+	uint32_t                            *num_pix_port,
+	uint32_t                            *acquired_hw_id,
+	uint32_t                            *acquired_hw_path)
+{
+	int                                  rc = -1;
+	int                                  ipp_count = 0;
+	int                                  rdi_count = 0;
+	int                                  ppp_count = 0;
+	int                                  ife_rd_count = 0;
+	int                                  lcr_count = 0;
+
+	ife_ctx->is_dual = (bool)in_port->usage_type;
+
+	cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count,
+		&rdi_count, &ppp_count, &ife_rd_count, &lcr_count);
+
+	if ((!ipp_count && !lcr_count) || !ife_rd_count) {
+		CAM_ERR(CAM_ISP,
+			"Invalid %d BUS RD %d PIX %d LCR ports for FE ctx");
+		return -EINVAL;
+	}
+
+	if (rdi_count || ppp_count) {
+		CAM_ERR(CAM_ISP,
+			"%d RDI %d PPP ports invalid for FE ctx",
+			rdi_count, ppp_count);
+		return -EINVAL;
+	}
+
+	rc = cam_ife_hw_mgr_acquire_offline_res_ife_bus_rd(ife_ctx, in_port);
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Acquire IFE BUS RD resource Failed");
+		goto err;
+	}
+
+	if (ipp_count)
+		rc = cam_ife_hw_mgr_acquire_offline_res_ife_camif(ife_ctx,
+			in_port, false, acquired_hw_id, acquired_hw_path);
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Acquire IFE IPP SRC resource Failed");
+		goto err;
+	}
+
+	if (lcr_count)
+		rc = cam_ife_hw_mgr_acquire_offline_res_ife_camif(ife_ctx,
+			in_port, true, acquired_hw_id, acquired_hw_path);
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Acquire IFE LCR SRC resource Failed");
+		goto err;
+	}
+
+	rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed");
+		goto err;
+	}
+
+	*num_pix_port += ipp_count + lcr_count;
+
+	return 0;
+
+err:
+	return rc;
+}
+
+
 static int cam_ife_mgr_acquire_hw_for_ctx(
 static int cam_ife_mgr_acquire_hw_for_ctx(
 	struct cam_ife_hw_mgr_ctx           *ife_ctx,
 	struct cam_ife_hw_mgr_ctx           *ife_ctx,
 	struct cam_isp_in_port_generic_info *in_port,
 	struct cam_isp_in_port_generic_info *in_port,
@@ -2373,10 +2458,14 @@ static int cam_ife_mgr_acquire_hw_for_ctx(
 	cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count,
 	cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count,
 		&rdi_count, &ppp_count, &ife_rd_count, &lcr_count);
 		&rdi_count, &ppp_count, &ife_rd_count, &lcr_count);
 
 
-	if (!ipp_count && !rdi_count && !ppp_count && !ife_rd_count
-		&& !lcr_count) {
+	if (ife_rd_count) {
+		CAM_ERR(CAM_ISP, "Invalid BUS RD port for non-FE ctx");
+		return -EINVAL;
+	}
+
+	if (!ipp_count && !rdi_count && !ppp_count && !lcr_count) {
 		CAM_ERR(CAM_ISP,
 		CAM_ERR(CAM_ISP,
-			"No PIX or RDI or PPP or IFE RD or LCR resource");
+			"No PIX or RDI or PPP or LCR resource");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -2421,15 +2510,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx(
 	}
 	}
 
 
 	/* get ife src resource */
 	/* get ife src resource */
-	if (ife_rd_count) {
-		rc = cam_ife_hw_mgr_acquire_res_ife_rd_src(ife_ctx, in_port);
-		rc = cam_ife_hw_mgr_acquire_res_bus_rd(ife_ctx, in_port);
-
-		if (rc) {
-			CAM_ERR(CAM_ISP, "Acquire IFE RD SRC resource Failed");
-			goto err;
-		}
-	} else if (ipp_count || ppp_count || rdi_count) {
+	if (ipp_count || ppp_count || rdi_count) {
 		rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx,
 		rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx,
 			in_port, false,
 			in_port, false,
 			acquired_hw_id, acquired_hw_path);
 			acquired_hw_id, acquired_hw_path);
@@ -2633,10 +2714,12 @@ static int cam_ife_mgr_acquire_get_unified_structure_v2(
 
 
 	if (port_info->num_valid_vc_dt == 0 ||
 	if (port_info->num_valid_vc_dt == 0 ||
 		port_info->num_valid_vc_dt >= CAM_ISP_VC_DT_CFG) {
 		port_info->num_valid_vc_dt >= CAM_ISP_VC_DT_CFG) {
-		CAM_ERR(CAM_ISP, "Invalid i/p arg invalid vc-dt: %d",
-			in->num_valid_vc_dt);
-		rc = -EINVAL;
-		goto release_mem;
+		if (in->res_type != CAM_ISP_IFE_IN_RES_RD) {
+			CAM_ERR(CAM_ISP, "Invalid i/p arg invalid vc-dt: %d",
+				in->num_valid_vc_dt);
+			rc = -EINVAL;
+			goto release_mem;
+		}
 	}
 	}
 
 
 	for (i = 0; i < port_info->num_valid_vc_dt; i++) {
 	for (i = 0; i < port_info->num_valid_vc_dt; i++) {
@@ -2644,26 +2727,27 @@ static int cam_ife_mgr_acquire_get_unified_structure_v2(
 		port_info->dt[i]      =  in->dt[i];
 		port_info->dt[i]      =  in->dt[i];
 	}
 	}
 
 
-	port_info->format         =  in->format;
-	port_info->test_pattern   =  in->test_pattern;
-	port_info->usage_type     =  in->usage_type;
-	port_info->left_start     =  in->left_start;
-	port_info->left_stop      =  in->left_stop;
-	port_info->left_width     =  in->left_width;
-	port_info->right_start    =  in->right_start;
-	port_info->right_stop     =  in->right_stop;
-	port_info->right_width    =  in->right_width;
-	port_info->line_start     =  in->line_start;
-	port_info->line_stop      =  in->line_stop;
-	port_info->height         =  in->height;
-	port_info->pixel_clk      =  in->pixel_clk;
-	port_info->batch_size     =  in->batch_size;
-	port_info->dsp_mode       =  in->dsp_mode;
-	port_info->hbi_cnt        =  in->hbi_cnt;
-	port_info->cust_node      =  in->cust_node;
-	port_info->horizontal_bin =  in->horizontal_bin;
-	port_info->qcfa_bin       =  in->qcfa_bin;
-	port_info->num_out_res    =  in->num_out_res;
+	port_info->format          =  in->format;
+	port_info->test_pattern    =  in->test_pattern;
+	port_info->usage_type      =  in->usage_type;
+	port_info->left_start      =  in->left_start;
+	port_info->left_stop       =  in->left_stop;
+	port_info->left_width      =  in->left_width;
+	port_info->right_start     =  in->right_start;
+	port_info->right_stop      =  in->right_stop;
+	port_info->right_width     =  in->right_width;
+	port_info->line_start      =  in->line_start;
+	port_info->line_stop       =  in->line_stop;
+	port_info->height          =  in->height;
+	port_info->pixel_clk       =  in->pixel_clk;
+	port_info->batch_size      =  in->batch_size;
+	port_info->dsp_mode        =  in->dsp_mode;
+	port_info->fe_unpacker_fmt =  in->format;
+	port_info->hbi_cnt         =  in->hbi_cnt;
+	port_info->cust_node       =  in->cust_node;
+	port_info->horizontal_bin  =  in->horizontal_bin;
+	port_info->qcfa_bin        =  in->qcfa_bin;
+	port_info->num_out_res     =  in->num_out_res;
 
 
 	port_info->data = kcalloc(in->num_out_res,
 	port_info->data = kcalloc(in->num_out_res,
 		sizeof(struct cam_isp_out_port_generic_info),
 		sizeof(struct cam_isp_out_port_generic_info),
@@ -2822,10 +2906,17 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 			goto free_mem;
 			goto free_mem;
 		}
 		}
 
 
-		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],
-			acquire_args->acquired_hw_path[i]);
+		if (ife_ctx->is_fe_enabled)
+			rc = cam_ife_mgr_acquire_hw_for_fe_ctx(
+				ife_ctx, in_port,
+				&num_pix_port_per_in,
+				&acquire_args->acquired_hw_id[i],
+				acquire_args->acquired_hw_path[i]);
+		else
+			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],
+				acquire_args->acquired_hw_path[i]);
 
 
 		total_pix_port += num_pix_port_per_in;
 		total_pix_port += num_pix_port_per_in;
 		total_rdi_port += num_rdi_port_per_in;
 		total_rdi_port += num_rdi_port_per_in;
@@ -2915,6 +3006,7 @@ void cam_ife_mgr_acquire_get_unified_dev_str(struct cam_isp_in_port_info *in,
 	gen_port_info->batch_size      =  in->batch_size;
 	gen_port_info->batch_size      =  in->batch_size;
 	gen_port_info->dsp_mode        =  in->dsp_mode;
 	gen_port_info->dsp_mode        =  in->dsp_mode;
 	gen_port_info->hbi_cnt         =  in->hbi_cnt;
 	gen_port_info->hbi_cnt         =  in->hbi_cnt;
+	gen_port_info->fe_unpacker_fmt =  in->format;
 	gen_port_info->cust_node       =  0;
 	gen_port_info->cust_node       =  0;
 	gen_port_info->num_out_res     =  in->num_out_res;
 	gen_port_info->num_out_res     =  in->num_out_res;
 
 
@@ -3788,11 +3880,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
 	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
 	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
 		cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]);
 		cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]);
 
 
-	/* IFE bus rd resources */
-	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) {
-		cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
-	}
-
 	CAM_DBG(CAM_ISP, "Going to stop IFE Mux");
 	CAM_DBG(CAM_ISP, "Going to stop IFE Mux");
 
 
 	/* IFE mux in resources */
 	/* IFE mux in resources */
@@ -3800,6 +3887,11 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
 		cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
 		cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
 	}
 	}
 
 
+	/* IFE bus rd resources */
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) {
+		cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
+	}
+
 	cam_tasklet_stop(ctx->common.tasklet_info);
 	cam_tasklet_stop(ctx->common.tasklet_info);
 
 
 	cam_ife_mgr_pause_hw(ctx);
 	cam_ife_mgr_pause_hw(ctx);
@@ -4090,18 +4182,6 @@ start_only:
 		}
 		}
 	}
 	}
 
 
-	CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d",
-		ctx->ctx_index);
-	/* Start the IFE mux in devices */
-	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) {
-		rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)",
-				 hw_mgr_res->res_id);
-			goto err;
-		}
-	}
-
 	if (primary_rdi_out_res < CAM_ISP_IFE_OUT_RES_MAX)
 	if (primary_rdi_out_res < CAM_ISP_IFE_OUT_RES_MAX)
 		primary_rdi_src_res =
 		primary_rdi_src_res =
 			cam_convert_rdi_out_res_id_to_src(primary_rdi_out_res);
 			cam_convert_rdi_out_res_id_to_src(primary_rdi_out_res);
@@ -4114,15 +4194,25 @@ start_only:
 			hw_mgr_res->hw_res[0]->rdi_only_ctx =
 			hw_mgr_res->hw_res[0]->rdi_only_ctx =
 				ctx->is_rdi_only_context;
 				ctx->is_rdi_only_context;
 		}
 		}
-
 		rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
 		rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
 		if (rc) {
 		if (rc) {
-			CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)",
+			CAM_ERR(CAM_ISP, "Can not start IFE Mux (%d)",
 				 hw_mgr_res->res_id);
 				 hw_mgr_res->res_id);
 			goto err;
 			goto err;
 		}
 		}
 	}
 	}
 
 
+	CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", ctx->ctx_index);
+	/* Start IFE Bus RD devices */
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) {
+		rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx);
+		if (rc) {
+			CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)",
+				hw_mgr_res->res_id);
+			goto err;
+		}
+	}
+
 	CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d",
 	CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d",
 		ctx->ctx_index);
 		ctx->ctx_index);
 	/* Start the IFE CSID HW devices */
 	/* Start the IFE CSID HW devices */
@@ -5838,6 +5928,18 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 		}
 		}
 	}
 	}
 
 
+
+	/* add go_cmd for offline context */
+	if (prepare->num_out_map_entries && prepare->num_in_map_entries &&
+		ctx->is_offline) {
+		rc = cam_isp_add_go_cmd(prepare, &ctx->res_list_ife_in_rd,
+			ctx->base[i].idx, &kmd_buf);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"Add GO_CMD faled i: %d, idx: %d, rc: %d",
+				i, ctx->base[i].idx, rc);
+	}
+
 	/*
 	/*
 	 * reg update will be done later for the initial configure.
 	 * reg update will be done later for the initial configure.
 	 * need to plus one to the op_code and only take the lower
 	 * need to plus one to the op_code and only take the lower
@@ -6075,7 +6177,10 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 				isp_hw_cmd_args->u.sof_irq_enable);
 				isp_hw_cmd_args->u.sof_irq_enable);
 			break;
 			break;
 		case CAM_ISP_HW_MGR_CMD_CTX_TYPE:
 		case CAM_ISP_HW_MGR_CMD_CTX_TYPE:
-			if (ctx->is_fe_enable)
+			if (ctx->is_fe_enabled && ctx->is_offline)
+				isp_hw_cmd_args->u.ctx_type =
+					CAM_ISP_CTX_OFFLINE;
+			else if (ctx->is_fe_enabled && !ctx->is_offline)
 				isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2;
 				isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2;
 			else if (ctx->is_rdi_only_context)
 			else if (ctx->is_rdi_only_context)
 				isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI;
 				isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI;
@@ -6309,6 +6414,17 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
+static inline void cam_ife_hw_mgr_get_offline_sof_timestamp(
+	uint64_t                             *timestamp,
+	uint64_t                             *boot_time)
+{
+	struct timespec64                     ts;
+
+	ktime_get_boottime_ts64(&ts);
+	*timestamp = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec);
+	*boot_time = *timestamp;
+}
+
 static int cam_ife_mgr_cmd_get_sof_timestamp(
 static int cam_ife_mgr_cmd_get_sof_timestamp(
 	struct cam_ife_hw_mgr_ctx            *ife_ctx,
 	struct cam_ife_hw_mgr_ctx            *ife_ctx,
 	uint64_t                             *time_stamp,
 	uint64_t                             *time_stamp,
@@ -6681,6 +6797,7 @@ static int cam_ife_hw_mgr_handle_hw_rup(
 
 
 	case CAM_ISP_HW_VFE_IN_PDLIB:
 	case CAM_ISP_HW_VFE_IN_PDLIB:
 	case CAM_ISP_HW_VFE_IN_LCR:
 	case CAM_ISP_HW_VFE_IN_LCR:
+	case CAM_ISP_HW_VFE_IN_RD:
 		break;
 		break;
 	default:
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d",
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d",
@@ -6810,6 +6927,8 @@ static int cam_ife_hw_mgr_handle_hw_sof(
 	struct cam_isp_hw_sof_event_data      sof_done_event_data;
 	struct cam_isp_hw_sof_event_data      sof_done_event_data;
 	int                                   rc = 0;
 	int                                   rc = 0;
 
 
+	memset(&sof_done_event_data, 0, sizeof(sof_done_event_data));
+
 	ife_hw_irq_sof_cb =
 	ife_hw_irq_sof_cb =
 		ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF];
 		ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF];
 
 
@@ -6820,10 +6939,15 @@ static int cam_ife_hw_mgr_handle_hw_sof(
 		rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx,
 		rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx,
 			CAM_ISP_HW_EVENT_SOF);
 			CAM_ISP_HW_EVENT_SOF);
 		if (!rc) {
 		if (!rc) {
-			cam_ife_mgr_cmd_get_sof_timestamp(
-				ife_hw_mgr_ctx,
-				&sof_done_event_data.timestamp,
-				&sof_done_event_data.boot_time);
+			if (ife_hw_mgr_ctx->is_offline)
+				cam_ife_hw_mgr_get_offline_sof_timestamp(
+					&sof_done_event_data.timestamp,
+					&sof_done_event_data.boot_time);
+			else
+				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 frame header is enabled reset qtimer ts */
 			if (ife_hw_mgr_ctx->use_frame_header_ts)
 			if (ife_hw_mgr_ctx->use_frame_header_ts)

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

@@ -82,12 +82,13 @@ struct cam_ife_hw_mgr_debug {
  * @last_dump_flush_req_id  Last req id for which reg dump on flush was called
  * @last_dump_flush_req_id  Last req id for which reg dump on flush was called
  * @last_dump_err_req_id    Last req id for which reg dump on error was called
  * @last_dump_err_req_id    Last req id for which reg dump on error was called
  * @init_done               indicate whether init hw is done
  * @init_done               indicate whether init hw is done
- * @is_fe_enable            indicate whether fetch engine\read path is enabled
+ * @is_fe_enabled           Indicate whether fetch engine\read path is enabled
  * @is_dual                 indicate whether context is in dual VFE mode
  * @is_dual                 indicate whether context is in dual VFE mode
  * @custom_enabled          update the flag if context is connected to custom HW
  * @custom_enabled          update the flag if context is connected to custom HW
  * @use_frame_header_ts     obtain qtimer ts using frame header
  * @use_frame_header_ts     obtain qtimer ts using frame header
  * @ts                      captured timestamp when the ctx is acquired
  * @ts                      captured timestamp when the ctx is acquired
  * @is_tpg                  indicate whether context is using PHY TPG
  * @is_tpg                  indicate whether context is using PHY TPG
+ * @is_offline              Indicate whether context is for offline IFE
  */
  */
 struct cam_ife_hw_mgr_ctx {
 struct cam_ife_hw_mgr_ctx {
 	struct list_head                list;
 	struct list_head                list;
@@ -133,12 +134,13 @@ struct cam_ife_hw_mgr_ctx {
 	uint64_t                        last_dump_flush_req_id;
 	uint64_t                        last_dump_flush_req_id;
 	uint64_t                        last_dump_err_req_id;
 	uint64_t                        last_dump_err_req_id;
 	bool                            init_done;
 	bool                            init_done;
-	bool                            is_fe_enable;
+	bool                            is_fe_enabled;
 	bool                            is_dual;
 	bool                            is_dual;
 	bool                            custom_enabled;
 	bool                            custom_enabled;
 	bool                            use_frame_header_ts;
 	bool                            use_frame_header_ts;
 	struct timespec64               ts;
 	struct timespec64               ts;
 	bool                            is_tpg;
 	bool                            is_tpg;
+	bool                            is_offline;
 };
 };
 
 
 /**
 /**

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

@@ -947,7 +947,7 @@ int cam_isp_add_reg_update(
 				return rc;
 				return rc;
 
 
 			CAM_DBG(CAM_ISP, "Reg update added for res %d hw_id %d",
 			CAM_DBG(CAM_ISP, "Reg update added for res %d hw_id %d",
-				res->res_id, res->hw_intf->hw_idx);
+				res->res_type, res->hw_intf->hw_idx);
 			reg_update_size += get_regup.cmd.used_bytes;
 			reg_update_size += get_regup.cmd.used_bytes;
 		}
 		}
 	}
 	}
@@ -981,3 +981,100 @@ int cam_isp_add_reg_update(
 
 
 	return rc;
 	return rc;
 }
 }
+
+int cam_isp_add_go_cmd(
+	struct cam_hw_prepare_update_args    *prepare,
+	struct list_head                     *res_list_isp_rd,
+	uint32_t                              base_idx,
+	struct cam_kmd_buf_info              *kmd_buf_info)
+{
+	int rc = -EINVAL;
+	struct cam_isp_resource_node         *res;
+	struct cam_isp_hw_mgr_res            *hw_mgr_res;
+	struct cam_hw_update_entry           *hw_entry;
+	struct cam_isp_hw_get_cmd_update      get_regup;
+	uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size;
+
+	hw_entry = prepare->hw_update_entries;
+	if (prepare->num_hw_update_entries + 1 >=
+		prepare->max_hw_update_entries) {
+		CAM_ERR(CAM_ISP, "Insufficient HW entries current: %d max: %d",
+			prepare->num_hw_update_entries,
+			prepare->max_hw_update_entries);
+		return -EINVAL;
+	}
+
+	reg_update_size = 0;
+	list_for_each_entry(hw_mgr_res, res_list_isp_rd, list) {
+		if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT)
+			continue;
+
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			res = hw_mgr_res->hw_res[i];
+			if (res->hw_intf->hw_idx != base_idx)
+				continue;
+
+			if (kmd_buf_info->size > (kmd_buf_info->used_bytes +
+				reg_update_size)) {
+				kmd_buf_remain_size =  kmd_buf_info->size -
+					(kmd_buf_info->used_bytes +
+					reg_update_size);
+			} else {
+				CAM_ERR(CAM_ISP, "no free mem %d %d %d",
+					base_idx, kmd_buf_info->size,
+					kmd_buf_info->used_bytes +
+					reg_update_size);
+				rc = -EINVAL;
+				return rc;
+			}
+
+			get_regup.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr +
+				kmd_buf_info->used_bytes/4 +
+				reg_update_size/4;
+			get_regup.cmd.size = kmd_buf_remain_size;
+			get_regup.cmd_type = CAM_ISP_HW_CMD_FE_TRIGGER_CMD;
+			get_regup.res = res;
+
+			rc = res->process_cmd(res->res_priv,
+				CAM_ISP_HW_CMD_FE_TRIGGER_CMD, &get_regup,
+				sizeof(struct cam_isp_hw_get_cmd_update));
+			if (rc)
+				return rc;
+
+			CAM_DBG(CAM_ISP, "GO_CMD added for RD res %d hw_id %d",
+				res->res_type, res->hw_intf->hw_idx);
+			reg_update_size += get_regup.cmd.used_bytes;
+		}
+	}
+
+	if (reg_update_size) {
+		/* Update the HW entries */
+		num_ent = prepare->num_hw_update_entries;
+		prepare->hw_update_entries[num_ent].handle =
+					kmd_buf_info->handle;
+		prepare->hw_update_entries[num_ent].len = reg_update_size;
+		prepare->hw_update_entries[num_ent].offset =
+			kmd_buf_info->offset;
+
+		prepare->hw_update_entries[num_ent].flags =
+			CAM_ISP_IOCFG_BL;
+		CAM_DBG(CAM_ISP,
+			"num_ent=%d handle=0x%x, len=%u, offset=%u",
+			num_ent,
+			prepare->hw_update_entries[num_ent].handle,
+			prepare->hw_update_entries[num_ent].len,
+			prepare->hw_update_entries[num_ent].offset);
+		num_ent++;
+
+		kmd_buf_info->used_bytes += reg_update_size;
+		kmd_buf_info->offset     += reg_update_size;
+		prepare->num_hw_update_entries = num_ent;
+		rc = 0;
+	}
+
+	return rc;
+}
+

+ 19 - 0
drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h

@@ -176,4 +176,23 @@ int cam_isp_add_reg_update(
 	uint32_t                              base_idx,
 	uint32_t                              base_idx,
 	struct cam_kmd_buf_info              *kmd_buf_info);
 	struct cam_kmd_buf_info              *kmd_buf_info);
 
 
+/*
+ * cam_isp_add_go_cmd()
+ *
+ * @brief                  Add go_cmd in the hw entries list for each rd source
+ *
+ * @prepare:               Contain the  packet and HW update variables
+ * @res_list_isp_rd:       Resource list for BUS RD ports
+ * @base_idx:              Base or dev index of the IFE/VFE HW instance
+ * @kmd_buf_info:          Kmd buffer to store the change base command
+ * @return:                0 for success
+ *                         -EINVAL for Fail
+ */
+int cam_isp_add_go_cmd(
+	struct cam_hw_prepare_update_args    *prepare,
+	struct list_head                     *res_list_isp_rd,
+	uint32_t                              base_idx,
+	struct cam_kmd_buf_info              *kmd_buf_info);
+
+
 #endif /*_CAM_ISP_HW_PARSER_H */
 #endif /*_CAM_ISP_HW_PARSER_H */

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

@@ -239,6 +239,7 @@ enum cam_isp_ctx_type {
 	CAM_ISP_CTX_FS2 = 1,
 	CAM_ISP_CTX_FS2 = 1,
 	CAM_ISP_CTX_RDI,
 	CAM_ISP_CTX_RDI,
 	CAM_ISP_CTX_PIX,
 	CAM_ISP_CTX_PIX,
+	CAM_ISP_CTX_OFFLINE,
 	CAM_ISP_CTX_MAX,
 	CAM_ISP_CTX_MAX,
 };
 };
 /**
 /**

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -97,6 +97,7 @@ struct cam_isp_in_port_generic_info {
 	uint32_t                        batch_size;
 	uint32_t                        batch_size;
 	uint32_t                        dsp_mode;
 	uint32_t                        dsp_mode;
 	uint32_t                        hbi_cnt;
 	uint32_t                        hbi_cnt;
+	uint32_t                        fe_unpacker_fmt;
 	uint32_t                        cust_node;
 	uint32_t                        cust_node;
 	uint32_t                        num_out_res;
 	uint32_t                        num_out_res;
 	uint32_t                        horizontal_bin;
 	uint32_t                        horizontal_bin;

+ 2 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -77,8 +77,8 @@ enum cam_isp_resource_type {
 	CAM_ISP_RESOURCE_CID,
 	CAM_ISP_RESOURCE_CID,
 	CAM_ISP_RESOURCE_PIX_PATH,
 	CAM_ISP_RESOURCE_PIX_PATH,
 	CAM_ISP_RESOURCE_VFE_IN,
 	CAM_ISP_RESOURCE_VFE_IN,
-	CAM_ISP_RESOURCE_VFE_OUT,
 	CAM_ISP_RESOURCE_VFE_BUS_RD,
 	CAM_ISP_RESOURCE_VFE_BUS_RD,
+	CAM_ISP_RESOURCE_VFE_OUT,
 	CAM_ISP_RESOURCE_TPG,
 	CAM_ISP_RESOURCE_TPG,
 	CAM_ISP_RESOURCE_TFE_IN,
 	CAM_ISP_RESOURCE_TFE_IN,
 	CAM_ISP_RESOURCE_TFE_OUT,
 	CAM_ISP_RESOURCE_TFE_OUT,
@@ -114,6 +114,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE,
 	CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE,
 	CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP,
 	CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP,
 	CAM_ISP_HW_CMD_DUMP_HW,
 	CAM_ISP_HW_CMD_DUMP_HW,
+	CAM_ISP_HW_CMD_FE_TRIGGER_CMD,
 	CAM_ISP_HW_CMD_MAX,
 	CAM_ISP_HW_CMD_MAX,
 };
 };
 
 

+ 28 - 3
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h

@@ -102,6 +102,27 @@ struct cam_vfe_hw_get_hw_cap {
 	uint32_t                max_rdi_num;
 	uint32_t                max_rdi_num;
 };
 };
 
 
+/*
+ * struct cam_vfe_hw_vfe_bus_rd_acquire_args:
+ *
+ * @rsrc_node:               Pointer to Resource Node object, filled if acquire
+ *                           is successful
+ * @res_id:                  Unique Identity of port to associate with this
+ *                           resource.
+ * @is_dual:                 Flag to indicate dual VFE usecase
+ * @cdm_ops:                 CDM operations
+ * @unpacket_fmt:            Unpacker format for read engine
+ * @is_offline:              Flag to indicate offline usecase
+ */
+struct cam_vfe_hw_vfe_bus_rd_acquire_args {
+	struct cam_isp_resource_node         *rsrc_node;
+	uint32_t                              res_id;
+	uint32_t                              is_dual;
+	struct cam_cdm_utils_ops             *cdm_ops;
+	uint32_t                              unpacker_fmt;
+	bool                                  is_offline;
+};
+
 /*
 /*
  * struct cam_vfe_hw_vfe_out_acquire_args:
  * struct cam_vfe_hw_vfe_out_acquire_args:
  *
  *
@@ -143,6 +164,8 @@ struct cam_vfe_hw_vfe_out_acquire_args {
  * @sync_mode:               In case of Dual VFE, this is Master or Slave.
  * @sync_mode:               In case of Dual VFE, this is Master or Slave.
  *                           (Default is Master in case of Single VFE)
  *                           (Default is Master in case of Single VFE)
  * @in_port:                 Input port details to acquire
  * @in_port:                 Input port details to acquire
+ * @is_fe_enabled:           Flag to indicate if FE is enabled
+ * @is_offline:              Flag to indicate Offline IFE
  */
  */
 struct cam_vfe_hw_vfe_in_acquire_args {
 struct cam_vfe_hw_vfe_in_acquire_args {
 	struct cam_isp_resource_node         *rsrc_node;
 	struct cam_isp_resource_node         *rsrc_node;
@@ -152,6 +175,8 @@ struct cam_vfe_hw_vfe_in_acquire_args {
 	void                                 *cdm_ops;
 	void                                 *cdm_ops;
 	enum cam_isp_hw_sync_mode             sync_mode;
 	enum cam_isp_hw_sync_mode             sync_mode;
 	struct cam_isp_in_port_generic_info  *in_port;
 	struct cam_isp_in_port_generic_info  *in_port;
+	bool                                  is_fe_enabled;
+	bool                                  is_offline;
 };
 };
 
 
 /*
 /*
@@ -173,9 +198,9 @@ struct cam_vfe_acquire_args {
 	void                                *priv;
 	void                                *priv;
 	cam_hw_mgr_event_cb_func             event_cb;
 	cam_hw_mgr_event_cb_func             event_cb;
 	union {
 	union {
-		struct cam_vfe_hw_vfe_out_acquire_args  vfe_out;
-		struct cam_vfe_hw_vfe_out_acquire_args  vfe_bus_rd;
-		struct cam_vfe_hw_vfe_in_acquire_args   vfe_in;
+		struct cam_vfe_hw_vfe_out_acquire_args     vfe_out;
+		struct cam_vfe_hw_vfe_bus_rd_acquire_args  vfe_bus_rd;
+		struct cam_vfe_hw_vfe_in_acquire_args      vfe_in;
 	};
 	};
 };
 };
 
 

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h

@@ -407,6 +407,7 @@ static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = {
 			.max_height    = -1,
 			.max_height    = -1,
 		},
 		},
 	},
 	},
+	.top_irq_shift = 23,
 };
 };
 
 
 static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = {
 static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = {

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h

@@ -1360,6 +1360,7 @@ static struct cam_vfe_bus_rd_ver1_hw_info vfe480_bus_rd_hw_info = {
 			.max_height    = -1,
 			.max_height    = -1,
 		},
 		},
 	},
 	},
+	.top_irq_shift = 8,
 };
 };
 
 
 struct cam_vfe_hw_info cam_vfe480_hw_info = {
 struct cam_vfe_hw_info cam_vfe480_hw_info = {

File diff suppressed because it is too large
+ 391 - 252
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c


+ 2 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_VFE_BUS_R_VER1_H_
 #ifndef _CAM_VFE_BUS_R_VER1_H_
@@ -88,6 +88,7 @@ struct cam_vfe_bus_rd_ver1_hw_info {
 	uint32_t num_bus_rd_resc;
 	uint32_t num_bus_rd_resc;
 	struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info
 	struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info
 		vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX];
 		vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX];
+	uint32_t top_irq_shift;
 };
 };
 
 
 /*
 /*

+ 42 - 16
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c

@@ -54,6 +54,8 @@ struct cam_vfe_mux_camif_ver3_data {
 	uint32_t                           qcfa_bin;
 	uint32_t                           qcfa_bin;
 	uint32_t                           dual_hw_idx;
 	uint32_t                           dual_hw_idx;
 	uint32_t                           is_dual;
 	uint32_t                           is_dual;
+	bool                               is_fe_enabled;
+	bool                               is_offline;
 };
 };
 
 
 static int cam_vfe_camif_ver3_get_evt_payload(
 static int cam_vfe_camif_ver3_get_evt_payload(
@@ -248,19 +250,20 @@ int cam_vfe_camif_ver3_acquire_resource(
 		return rc;
 		return rc;
 	}
 	}
 
 
-	camif_data->sync_mode   = acquire_data->vfe_in.sync_mode;
-	camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern;
-	camif_data->dsp_mode    = acquire_data->vfe_in.in_port->dsp_mode;
-	camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start;
-	camif_data->last_pixel  = acquire_data->vfe_in.in_port->left_stop;
-	camif_data->first_line  = acquire_data->vfe_in.in_port->line_start;
-	camif_data->last_line   = acquire_data->vfe_in.in_port->line_stop;
+	camif_data->sync_mode      = acquire_data->vfe_in.sync_mode;
+	camif_data->pix_pattern    = acquire_data->vfe_in.in_port->test_pattern;
+	camif_data->dsp_mode       = acquire_data->vfe_in.in_port->dsp_mode;
+	camif_data->first_pixel    = acquire_data->vfe_in.in_port->left_start;
+	camif_data->last_pixel     = acquire_data->vfe_in.in_port->left_stop;
+	camif_data->first_line     = acquire_data->vfe_in.in_port->line_start;
+	camif_data->last_line      = acquire_data->vfe_in.in_port->line_stop;
+	camif_data->is_fe_enabled  = acquire_data->vfe_in.is_fe_enabled;
+	camif_data->is_offline     = acquire_data->vfe_in.is_offline;
+	camif_data->event_cb       = acquire_data->event_cb;
+	camif_data->priv           = acquire_data->priv;
+	camif_data->qcfa_bin       = acquire_data->vfe_in.in_port->qcfa_bin;
 	camif_data->horizontal_bin =
 	camif_data->horizontal_bin =
 		acquire_data->vfe_in.in_port->horizontal_bin;
 		acquire_data->vfe_in.in_port->horizontal_bin;
-	camif_data->qcfa_bin    = acquire_data->vfe_in.in_port->qcfa_bin;
-	camif_data->event_cb    = acquire_data->event_cb;
-	camif_data->priv        = acquire_data->priv;
-	camif_data->is_dual     = acquire_data->vfe_in.is_dual;
 
 
 	if (acquire_data->vfe_in.is_dual)
 	if (acquire_data->vfe_in.is_dual)
 		camif_data->dual_hw_idx = acquire_data->vfe_in.dual_hw_idx;
 		camif_data->dual_hw_idx = acquire_data->vfe_in.dual_hw_idx;
@@ -417,12 +420,20 @@ static int cam_vfe_camif_ver3_resource_start(
 	val |= (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) <<
 	val |= (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) <<
 		CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP;
 		CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP;
 
 
+	if (rsrc_data->is_fe_enabled && !rsrc_data->is_offline)
+		val |= 0x2 << rsrc_data->reg_data->operating_mode_shift;
+	else
+		val |= 0x1 << rsrc_data->reg_data->operating_mode_shift;
+
 	if (rsrc_data->is_dual && rsrc_data->reg_data->dual_vfe_sync_mask) {
 	if (rsrc_data->is_dual && rsrc_data->reg_data->dual_vfe_sync_mask) {
 		val |= (((rsrc_data->dual_hw_idx &
 		val |= (((rsrc_data->dual_hw_idx &
 				rsrc_data->reg_data->dual_vfe_sync_mask) + 1) <<
 				rsrc_data->reg_data->dual_vfe_sync_mask) + 1) <<
 				rsrc_data->reg_data->dual_ife_sync_sel_shift);
 				rsrc_data->reg_data->dual_ife_sync_sel_shift);
 	}
 	}
 
 
+	CAM_DBG(CAM_ISP, "VFE:%d TOP core_cfg: 0x%X",
+		camif_res->hw_intf->hw_idx, val);
+
 	cam_io_w_mb(val, rsrc_data->mem_base +
 	cam_io_w_mb(val, rsrc_data->mem_base +
 		rsrc_data->common_reg->core_cfg_0);
 		rsrc_data->common_reg->core_cfg_0);
 
 
@@ -459,11 +470,14 @@ static int cam_vfe_camif_ver3_resource_start(
 	camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 	camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 
 
 	/* Reg Update */
 	/* Reg Update */
-	cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data,
-		rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd);
-	CAM_DBG(CAM_ISP, "VFE:%d CAMIF RUP val:0x%X",
-		camif_res->hw_intf->hw_idx,
-		rsrc_data->reg_data->reg_update_cmd_data);
+	if (!rsrc_data->is_offline) {
+		cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data,
+			rsrc_data->mem_base +
+			rsrc_data->camif_reg->reg_update_cmd);
+		CAM_DBG(CAM_ISP, "VFE:%d CAMIF RUP val:0x%X",
+			camif_res->hw_intf->hw_idx,
+			rsrc_data->reg_data->reg_update_cmd_data);
+	}
 
 
 	/* disable sof irq debug flag */
 	/* disable sof irq debug flag */
 	rsrc_data->enable_sof_irq_debug = false;
 	rsrc_data->enable_sof_irq_debug = false;
@@ -606,6 +620,18 @@ static int cam_vfe_camif_ver3_reg_dump(
 		CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val);
 		CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val);
 	}
 	}
 
 
+	CAM_INFO(CAM_ISP, "IFE:%d BUS RD", camif_res->hw_intf->hw_idx);
+	for (offset = 0xA800; offset <= 0xA89C; offset += 0x4) {
+		val = cam_soc_util_r(camif_priv->soc_info, 0, offset);
+		CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val);
+		if (offset == 0xA838)
+			offset = 0xA844;
+		if (offset == 0xA864)
+			offset = 0xA874;
+		if (offset == 0xA878)
+			offset = 0xA87C;
+	}
+
 	CAM_INFO(CAM_ISP, "IFE:%d BUS WR", camif_res->hw_intf->hw_idx);
 	CAM_INFO(CAM_ISP, "IFE:%d BUS WR", camif_res->hw_intf->hw_idx);
 	for (offset = 0xAA00; offset <= 0xAADC; offset += 0x4) {
 	for (offset = 0xAA00; offset <= 0xAADC; offset += 0x4) {
 		val = cam_soc_util_r(camif_priv->soc_info, 0, offset);
 		val = cam_soc_util_r(camif_priv->soc_info, 0, offset);

Some files were not shown because too many files changed in this diff