소스 검색

msm: camera: isp: Add support for RDI LCR

For spectra 780, one of the RDI inputs can serve
as an input to LCR in PDAF block inside IFE using
mux.
It  needs programming of top wrapper registers in CSID
and mux related registers in IFE.
At bus side, mipi packing needs to be used as the
output from CSID will be Plain16.
This commit adds support for the above requirements.

CRs-Fixed: 2948116
Change-Id: I425e4aa5ed58dd4214a1f11865359b3fc06d1b0d
Signed-off-by: Gaurav Jindal<[email protected]>
Gaurav Jindal 3 년 전
부모
커밋
f2cad8ef24
21개의 변경된 파일696개의 추가작업 그리고 57개의 파일을 삭제
  1. 237 0
      drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
  2. 2 0
      drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
  3. 2 0
      drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h
  4. 12 0
      drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
  5. 16 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid780.h
  6. 58 1
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.c
  7. 15 3
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.h
  8. 2 2
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c
  9. 123 10
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c
  10. 6 2
      drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h
  11. 6 2
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
  12. 1 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
  13. 2 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h
  14. 2 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
  15. 39 21
      drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c
  16. 1 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
  17. 19 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe780.h
  18. 37 16
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c
  19. 80 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c
  20. 9 0
      drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.h
  21. 27 0
      include/uapi/camera/media/cam_isp.h

+ 237 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -1847,6 +1847,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi(
 		vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler;
 		vfe_acquire.buf_done_controller = ife_ctx->buf_done_controller;
 		hw_intf = ife_src_res->hw_res[0]->hw_intf;
+		vfe_acquire.vfe_out.use_wm_pack = ife_src_res->use_wm_pack;
 		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
 			&vfe_acquire,
 			sizeof(struct cam_vfe_acquire_args));
@@ -1867,6 +1868,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi(
 
 	ife_out_res->hw_res[0] = vfe_acquire.vfe_out.rsrc_node;
 	ife_out_res->is_dual_isp = 0;
+	ife_out_res->use_wm_pack = ife_src_res->use_wm_pack;
 	ife_out_res->res_id = vfe_out_res_id;
 	ife_out_res->res_type = CAM_ISP_RESOURCE_VFE_OUT;
 	ife_src_res->num_children++;
@@ -2038,6 +2040,7 @@ static int cam_ife_hw_mgr_acquire_res_sfe_out_rdi(
 		sfe_acquire.sfe_out.is_dual = 0;
 		sfe_acquire.buf_done_controller = ife_ctx->buf_done_controller;
 		sfe_acquire.event_cb = cam_ife_hw_mgr_event_handler;
+		sfe_acquire.sfe_out.use_wm_pack = sfe_src_res->use_wm_pack;
 		hw_intf = sfe_src_res->hw_res[0]->hw_intf;
 		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
 			&sfe_acquire,
@@ -2060,6 +2063,7 @@ static int cam_ife_hw_mgr_acquire_res_sfe_out_rdi(
 
 	sfe_out_res->hw_res[0] = sfe_acquire.sfe_out.rsrc_node;
 	sfe_out_res->is_dual_isp = 0;
+	sfe_out_res->use_wm_pack = sfe_src_res->use_wm_pack;
 	sfe_out_res->res_id = sfe_out_res_id;
 	sfe_out_res->res_type = CAM_ISP_RESOURCE_SFE_OUT;
 	sfe_src_res->num_children++;
@@ -2468,6 +2472,7 @@ static int cam_ife_hw_mgr_acquire_res_sfe_src(
 		sfe_src_res->res_type = sfe_acquire.rsrc_type;
 		sfe_src_res->res_id = sfe_acquire.sfe_in.res_id;
 		sfe_src_res->is_dual_isp = csid_res->is_dual_isp;
+		sfe_src_res->use_wm_pack = csid_res->use_wm_pack;
 		for (i = sfe_src_res->is_dual_isp; i >= 0; i--) {
 			rc = cam_ife_hw_mgr_acquire_sfe_hw(
 				((is_rdi) && (!sfe_src_res->is_dual_isp) &&
@@ -3025,6 +3030,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_src(
 		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;
+		ife_src_res->use_wm_pack = csid_res->use_wm_pack;
 
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
 			if (!csid_res->hw_res[i])
@@ -3426,6 +3432,9 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
 		csid_acquire.tasklet = ife_ctx->common.tasklet_info;
 		csid_acquire.cb_priv = ife_ctx;
 		csid_acquire.cdm_ops = ife_ctx->cdm_ops;
+		if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE)
+			csid_acquire.sfe_en = true;
+
 		if (cam_ife_hw_mgr_is_shdr_fs_rdi_res(
 			out_port->res_type,
 			ife_ctx->flags.is_sfe_shdr, ife_ctx->flags.is_sfe_fs)) {
@@ -3499,6 +3508,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
 		csid_res->is_dual_isp = 0;
 		csid_res->hw_res[0] = csid_acquire.node_res;
 		csid_res->hw_res[1] = NULL;
+		csid_res->use_wm_pack = csid_acquire.use_wm_pack;
 		if ((ife_ctx->flags.is_rdi_only_context) ||
 			(ife_ctx->flags.is_sfe_fs) ||
 			(ife_ctx->flags.is_sfe_shdr)) {
@@ -8541,6 +8551,213 @@ static int cam_isp_blob_bw_limit_update(
 	return rc;
 }
 
+static int cam_isp_hw_mgr_add_cmd_buf_util(
+	struct cam_isp_hw_mgr_res         *hw_mgr_res,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_isp_generic_blob_info  *blob_info,
+	void                              *data,
+	uint32_t                           hw_cmd_type,
+	uint32_t                           blob_type)
+{
+	uint32_t                       total_used_bytes = 0;
+	uint32_t                       kmd_buf_remain_size;
+	struct cam_kmd_buf_info       *kmd_buf_info;
+	uint32_t                      *cmd_buf_addr;
+	int                            rc = 0;
+
+	kmd_buf_info = blob_info->kmd_buf_info;
+	if (kmd_buf_info->used_bytes < kmd_buf_info->size) {
+		kmd_buf_remain_size = kmd_buf_info->size - kmd_buf_info->used_bytes;
+	} else {
+		CAM_ERR(CAM_ISP, "No free kmd memory for base idx: %d used_bytes %u buf_size %u",
+			blob_info->base_info->idx, kmd_buf_info->used_bytes, kmd_buf_info->size);
+		return -ENOMEM;
+	}
+
+	cmd_buf_addr = kmd_buf_info->cpu_addr + (kmd_buf_info->used_bytes / 4);
+	rc = cam_isp_add_cmd_buf_update(hw_mgr_res, blob_type,
+		hw_cmd_type, blob_info->base_info->idx, (void *)cmd_buf_addr,
+		kmd_buf_remain_size, data, &total_used_bytes);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Add cmd buffer failed idx: %d",
+			blob_info->base_info->idx);
+		return -EINVAL;
+	}
+
+	if (total_used_bytes)
+		cam_ife_mgr_update_hw_entries_util(
+			CAM_ISP_IQ_BL, total_used_bytes, kmd_buf_info, prepare);
+	return rc;
+}
+
+static int cam_isp_update_ife_pdaf_cfg(
+	struct cam_ife_hw_mgr_ctx         *ctx,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_isp_generic_blob_info  *blob_info,
+	struct cam_isp_lcr_rdi_cfg_args   *isp_lcr_cfg,
+	uint32_t                           blob_type)
+{
+	struct cam_isp_hw_mgr_res     *hw_mgr_res;
+	uint32_t                       i;
+	uint32_t                       ife_res_id;
+	struct cam_isp_resource_node  *res;
+	int                            rc = -EINVAL;
+
+	ife_res_id = cam_convert_rdi_out_res_id_to_src(isp_lcr_cfg->rdi_lcr_cfg->res_id);
+	if (ife_res_id == CAM_ISP_HW_VFE_IN_MAX) {
+		CAM_ERR(CAM_ISP, "Invalid res_id %u", isp_lcr_cfg->rdi_lcr_cfg->res_id);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_ISP, "Ctx %d res: %u lcr %u id %u ctx_type %u", ctx->ctx_index, ife_res_id,
+		isp_lcr_cfg->rdi_lcr_cfg->res_id, blob_info->base_info->idx, ctx->ctx_type);
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, 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];
+			/*
+			 * for SFE cases, only CAMIF resource is
+			 * acquired. We need any res to go to vfe drivers
+			 * to update the buffer. For non-sfe case, we match
+			 * with the incoming res_id
+			 */
+			if ((ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE &&
+				res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) ||
+				res->res_id == ife_res_id) {
+
+				rc = cam_isp_hw_mgr_add_cmd_buf_util(hw_mgr_res, prepare,
+					blob_info, (void *)isp_lcr_cfg,
+					CAM_ISP_HW_CMD_RDI_LCR_CFG, blob_type);
+				if (rc)
+					CAM_ERR(CAM_ISP,
+						"Ctx %d res: %u lcr %u id %u ctx_type %u rc %u",
+						ctx->ctx_index, ife_res_id,
+						isp_lcr_cfg->rdi_lcr_cfg->res_id,
+						blob_info->base_info->idx, ctx->ctx_type, rc);
+				goto end;
+			}
+		}
+	}
+end:
+	return rc;
+}
+
+static int  cam_isp_config_rdi_lcr_csid_init_params(
+	struct cam_ife_hw_mgr_ctx         *ctx,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_isp_generic_blob_info  *blob_info,
+	struct cam_isp_lcr_rdi_config     *rdi_lcr_cfg,
+	uint32_t                           blob_type)
+{
+	struct cam_isp_hw_mgr_res         *hw_mgr_res;
+	struct cam_isp_resource_node      *res;
+	int                                rc = -EINVAL;
+	uint32_t                           csid_res_id = 0;
+	uint32_t                           acquired_res_id_mask = 0;
+
+	csid_res_id = cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
+			rdi_lcr_cfg->res_id);
+	CAM_DBG(CAM_ISP,
+		"Ctx: %d csid_res_id: %u rdi_lcr: %u sfe_shdr %u ctx_ctype %u", ctx->ctx_index,
+		csid_res_id, rdi_lcr_cfg->res_id, ctx->flags.is_sfe_shdr, ctx->ctx_type);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+		if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT)
+			continue;
+
+		if (!hw_mgr_res->hw_res[0])
+			continue;
+
+		if (hw_mgr_res->res_id < CAM_IFE_PIX_PATH_RES_RDI_0 ||
+			hw_mgr_res->res_id > CAM_IFE_PIX_PATH_RES_RDI_2)
+			continue;
+
+		if (!ctx->flags.is_sfe_shdr && hw_mgr_res->res_id != csid_res_id)
+			continue;
+
+		res = hw_mgr_res->hw_res[0];
+		rc = res->hw_intf->hw_ops.process_cmd(res->hw_intf->hw_priv,
+			CAM_ISP_HW_CMD_RDI_LCR_CFG, res, sizeof(*res));
+		acquired_res_id_mask |= BIT(res->res_id);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"Ctx: %d csid_res_id: %u rdi_lcr: %u sfe_shdr %u ctx_ctype %u",
+				ctx->ctx_index, csid_res_id, rdi_lcr_cfg->res_id,
+				ctx->flags.is_sfe_shdr, ctx->ctx_type);
+			break;
+		}
+	}
+
+	if (!(acquired_res_id_mask & BIT(csid_res_id))) {
+		CAM_ERR(CAM_ISP,
+			"Ctx: %d Unacquired csid_res_id: %u rdi_lcr: %u sfe_shdr %u ctx_ctype %u",
+			ctx->ctx_index, csid_res_id, rdi_lcr_cfg->res_id,
+			ctx->flags.is_sfe_shdr, ctx->ctx_type);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int cam_isp_blob_ife_rdi_lcr_config(
+	struct cam_ife_hw_mgr_ctx         *ctx,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_isp_generic_blob_info  *blob_info,
+	struct cam_isp_lcr_rdi_config     *rdi_lcr_cfg,
+	uint32_t                           blob_type)
+{
+	struct cam_isp_prepare_hw_update_data  *prepare_hw_data;
+	struct cam_isp_lcr_rdi_cfg_args         isp_cfg_args = {0};
+	int                                     rc = -EINVAL;
+
+	prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)prepare->priv;
+	CAM_DBG(CAM_ISP,
+		"Blob opcode %u res %u ctx_type %u shdr %u rdi_lcr %u",
+		prepare_hw_data->packet_opcode_type, rdi_lcr_cfg->res_id, ctx->ctx_type,
+		ctx->flags.is_sfe_shdr, ctx->flags.rdi_lcr_en);
+
+	if (prepare_hw_data->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV) {
+		rc = cam_isp_config_rdi_lcr_csid_init_params(ctx,
+			prepare, blob_info, rdi_lcr_cfg, blob_type);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"CSID param failed Ctx: %d rdi_lcr: %u ctx_type: %u",
+				ctx->ctx_index, rdi_lcr_cfg->res_id, ctx->ctx_type);
+			return rc;
+		}
+
+		isp_cfg_args.is_init = true;
+		ctx->flags.rdi_lcr_en = true;
+	} else if (!ctx->flags.rdi_lcr_en || !ctx->flags.is_sfe_shdr) {
+		/*
+		 * we don't expect blob for non-shdr cases other than Init Packet,
+		 * as the RDI input would remain same for the session.
+		 */
+		CAM_ERR(CAM_ISP,
+			"Unexpected Blob opcode %u res %u ctx_type %u shdr %u rdi_lcr %u",
+			prepare_hw_data->packet_opcode_type, rdi_lcr_cfg->res_id, ctx->ctx_type,
+			ctx->flags.is_sfe_shdr, ctx->flags.rdi_lcr_en);
+		return rc;
+	}
+
+	isp_cfg_args.rdi_lcr_cfg = rdi_lcr_cfg;
+	rc = cam_isp_update_ife_pdaf_cfg(ctx, prepare, blob_info,
+		&isp_cfg_args, blob_type);
+	if (rc) {
+		CAM_ERR(CAM_ISP,
+			"IFE param failed %u res %u ctx_type %u shdr %u rdi_lcr %u",
+			prepare_hw_data->packet_opcode_type, rdi_lcr_cfg->res_id, ctx->ctx_type,
+			ctx->flags.is_sfe_shdr, ctx->flags.rdi_lcr_en);
+		return rc;
+	}
+
+	return rc;
+}
+
 static inline int cam_isp_validate_bw_limiter_blob(
 	uint32_t blob_size,
 	struct cam_isp_out_rsrc_bw_limiter_config *bw_limit_config)
@@ -9218,6 +9435,25 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 			CAM_ERR(CAM_ISP,
 				"Init config failed for req: %llu rc: %d",
 				 prepare->packet->header.request_id, rc);
+	}
+		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_RDI_LCR_CONFIG: {
+		struct cam_isp_lcr_rdi_config *lcr_rdi_config;
+
+		if (blob_size < sizeof(struct cam_isp_lcr_rdi_config)) {
+			CAM_ERR(CAM_ISP, "Invalid lcr blob size %u expected %u",
+				blob_size, sizeof(struct cam_isp_lcr_rdi_config));
+			return -EINVAL;
+		}
+
+		lcr_rdi_config = (struct cam_isp_lcr_rdi_config *)blob_data;
+		rc = cam_isp_blob_ife_rdi_lcr_config(ife_mgr_ctx, prepare,
+			blob_info, lcr_rdi_config, blob_type);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"RDI LCR config failed for res %u",
+				 lcr_rdi_config->res_id);
+
 	}
 		break;
 	default:
@@ -9683,6 +9919,7 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 	case CAM_ISP_GENERIC_BLOB_TYPE_DISCARD_INITIAL_FRAMES:
 	case CAM_ISP_GENERIC_BLOB_TYPE_INIT_CONFIG:
 	case CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG:
+	case CAM_ISP_GENERIC_BLOB_TYPE_RDI_LCR_CONFIG:
 		break;
 	default:
 		CAM_WARN(CAM_ISP, "Invalid blob type: %u", blob_type);

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

@@ -153,6 +153,7 @@ struct cam_ife_hw_mgr_sfe_info {
  * @dump_on_flush:       Set if reg dump triggered on flush
  * @dump_on_error:       Set if reg dump triggered on error
  * @custom_aeb_mode:     Set if custom AEB stream
+ * @rdi_lcr_en:          To indicate if RDI LCR is enabled
  * @sys_cache_usage:     Per context sys cache usage
  *                       The corresponding index will be set
  *                       for the cache type
@@ -175,6 +176,7 @@ struct cam_ife_hw_mgr_ctx_flags {
 	bool   dump_on_flush;
 	bool   dump_on_error;
 	bool   is_aeb_mode;
+	bool   rdi_lcr_en;
 	bool   sys_cache_usage[CAM_LLCC_MAX];
 };
 

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

@@ -69,6 +69,7 @@ struct cam_isp_hw_mgr {
  *                       acquired
  * @is_secure            informs whether the resource is in secure mode or not
  * @num_children:        number of the child resource node.
+ * @use_wm_pack:         Flag to indicate if WM is to be used for packing
  *
  */
 struct cam_isp_hw_mgr_res {
@@ -79,6 +80,7 @@ struct cam_isp_hw_mgr_res {
 	struct cam_isp_resource_node    *hw_res[CAM_ISP_HW_SPLIT_MAX];
 	uint32_t                         is_secure;
 	uint32_t                         num_children;
+	bool                             use_wm_pack;
 };
 
 

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

@@ -370,6 +370,18 @@ struct cam_isp_start_args {
 	bool                      start_only;
 };
 
+/**
+ * struct cam_isp_lcr_rdi_cfg_args - isp hardware start arguments
+ *
+ * @rdi_lcr_cfg:            RDI LCR cfg received from User space.
+ * @is_init:                Flag to indicate if init packet.
+ *
+ */
+struct cam_isp_lcr_rdi_cfg_args {
+	struct cam_isp_lcr_rdi_config *rdi_lcr_cfg;
+	bool                           is_init;
+};
+
 /**
  * cam_isp_hw_mgr_init()
  *

+ 16 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid780.h

@@ -625,6 +625,10 @@ static struct cam_ife_csid_ver2_path_reg_info
 		/* configurations */
 		.resume_frame_boundary            = 1,
 		.overflow_ctrl_en                 = 1,
+		.capabilities                     = CAM_IFE_CSID_CAP_INPUT_LCR |
+							CAM_IFE_CSID_CAP_MIPI10_UNPACK |
+							CAM_IFE_CSID_CAP_MIPI12_UNPACK |
+							CAM_IFE_CSID_CAP_MIPI14_UNPACK,
 		.overflow_ctrl_mode_val           = 0x8,
 		.offline_mode_supported           = 1,
 		.mipi_pack_supported              = 1,
@@ -719,6 +723,10 @@ static struct cam_ife_csid_ver2_path_reg_info
 		/* configurations */
 		.resume_frame_boundary            = 1,
 		.overflow_ctrl_en                 = 1,
+		.capabilities                     = CAM_IFE_CSID_CAP_INPUT_LCR |
+							CAM_IFE_CSID_CAP_MIPI10_UNPACK |
+							CAM_IFE_CSID_CAP_MIPI12_UNPACK |
+							CAM_IFE_CSID_CAP_MIPI14_UNPACK,
 		.overflow_ctrl_mode_val           = 0x8,
 		.mipi_pack_supported              = 1,
 		.offline_mode_supported           = 1,
@@ -813,6 +821,10 @@ static struct cam_ife_csid_ver2_path_reg_info
 		/* configurations */
 		.resume_frame_boundary            = 1,
 		.overflow_ctrl_en                 = 1,
+		.capabilities                     = CAM_IFE_CSID_CAP_INPUT_LCR |
+							CAM_IFE_CSID_CAP_MIPI10_UNPACK |
+							CAM_IFE_CSID_CAP_MIPI12_UNPACK |
+							CAM_IFE_CSID_CAP_MIPI14_UNPACK,
 		.overflow_ctrl_mode_val           = 0x8,
 		.mipi_pack_supported              = 1,
 		.offline_mode_supported           = 1,
@@ -907,6 +919,7 @@ static struct cam_ife_csid_ver2_path_reg_info
 		/* configurations */
 		.resume_frame_boundary            = 1,
 		.overflow_ctrl_en                 = 1,
+		.capabilities                     = 0,
 		.overflow_ctrl_mode_val           = 0x8,
 		.offline_mode_supported           = 1,
 		.mipi_pack_supported              = 1,
@@ -1001,6 +1014,7 @@ static struct cam_ife_csid_ver2_path_reg_info
 		/* configurations */
 		.resume_frame_boundary           = 1,
 		.overflow_ctrl_en                = 1,
+		.capabilities                    = 0,
 		.overflow_ctrl_mode_val          = 0x8,
 		.offline_mode_supported          = 1,
 		.mipi_pack_supported             = 1,
@@ -1142,6 +1156,7 @@ static struct cam_ife_csid_ver2_common_reg_info
 	.timestamp_stb_sel_shift_val             = 8,
 	.vfr_en_shift_val                        = 0,
 	.mup_shift_val                           = 28,
+	.shdr_slave_ppp_shift                    = 20,
 	.shdr_slave_rdi2_shift                   = 22,
 	.shdr_slave_rdi1_shift                   = 21,
 	.shdr_master_rdi0_shift                  = 5,
@@ -1203,6 +1218,7 @@ static struct cam_ife_csid_ver2_top_reg_info
 	.dual_sync_sel_shift_val        = 8,
 	.dual_en_shift_val              = 0,
 	.master_slave_sel_shift_val     = 1,
+	.rdi_lcr_shift_val              = 16,
 	.master_sel_val                 = 0,
 	.slave_sel_val                  = 1,
 	.io_path_cfg_rst_val            = 1,

+ 58 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.c

@@ -96,7 +96,8 @@ int cam_ife_csid_is_pix_res_format_supported(
 
 int cam_ife_csid_get_format_rdi(
 	uint32_t in_format, uint32_t out_format,
-	struct cam_ife_csid_path_format *path_format, bool rpp)
+	struct cam_ife_csid_path_format *path_format, bool rpp,
+	bool mipi_unpacked)
 {
 	int rc = 0;
 
@@ -109,10 +110,17 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x0;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x0;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x0;
+			}
 			break;
 		case CAM_FORMAT_PLAIN8:
 			path_format->decode_fmt = 0x0;
 			path_format->plain_fmt = 0x0;
+			path_format->packing_fmt = 0;
 			break;
 		default:
 			rc = -EINVAL;
@@ -129,9 +137,16 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x1;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x1;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x0;
+			}
 			break;
 		case CAM_FORMAT_PLAIN8:
 			path_format->decode_fmt = 0x1;
+			path_format->packing_fmt = 0;
 			path_format->plain_fmt = 0x0;
 			break;
 		default:
@@ -149,10 +164,17 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x2;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x2;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x1;
+			}
 			break;
 		case CAM_FORMAT_PLAIN16_10:
 			path_format->decode_fmt = 0x2;
 			path_format->plain_fmt = 0x1;
+			path_format->packing_fmt = 0;
 			break;
 		default:
 			rc = -EINVAL;
@@ -168,10 +190,17 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x3;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x3;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x1;
+			}
 			break;
 		case CAM_FORMAT_PLAIN16_12:
 			path_format->decode_fmt = 0x3;
 			path_format->plain_fmt = 0x1;
+			path_format->packing_fmt = 0;
 			break;
 		default:
 			rc = -EINVAL;
@@ -187,10 +216,17 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x4;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x4;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x1;
+			}
 			break;
 		case CAM_FORMAT_PLAIN16_14:
 			path_format->decode_fmt = 0x4;
 			path_format->plain_fmt = 0x1;
+			path_format->packing_fmt = 0;
 			break;
 		default:
 			rc = -EINVAL;
@@ -206,10 +242,17 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x5;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x5;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x1;
+			}
 			break;
 		case CAM_FORMAT_PLAIN16_16:
 			path_format->decode_fmt = 0x5;
 			path_format->plain_fmt = 0x1;
+			path_format->packing_fmt = 0;
 			break;
 		default:
 			rc = -EINVAL;
@@ -225,10 +268,17 @@ int cam_ife_csid_get_format_rdi(
 				path_format->decode_fmt = 0x6;
 				path_format->packing_fmt = 0x1;
 			}
+
+			if (mipi_unpacked) {
+				path_format->decode_fmt = 0x6;
+				path_format->packing_fmt = 0x0;
+				path_format->plain_fmt = 0x2;
+			}
 			break;
 		case CAM_FORMAT_PLAIN32_20:
 			path_format->decode_fmt = 0x6;
 			path_format->plain_fmt = 0x2;
+			path_format->packing_fmt = 0;
 			break;
 		default:
 			rc = -EINVAL;
@@ -239,30 +289,37 @@ int cam_ife_csid_get_format_rdi(
 	case CAM_FORMAT_DPCM_10_6_10:
 		path_format->decode_fmt  = 0x7;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_DPCM_10_8_10:
 		path_format->decode_fmt  = 0x8;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_DPCM_12_6_12:
 		path_format->decode_fmt  = 0x9;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_DPCM_12_8_12:
 		path_format->decode_fmt  = 0xA;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_DPCM_14_8_14:
 		path_format->decode_fmt  = 0xB;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_DPCM_14_10_14:
 		path_format->decode_fmt  = 0xC;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_DPCM_12_10_12:
 		path_format->decode_fmt  = 0xD;
 		path_format->plain_fmt = 0x1;
+		path_format->packing_fmt = 0;
 		break;
 	case CAM_FORMAT_YUV422:
 		path_format->decode_fmt  = 0x1;

+ 15 - 3
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.h

@@ -33,6 +33,13 @@
 
 #define CAM_IFE_CSID_LOG_BUF_LEN                          512
 
+#define CAM_IFE_CSID_CAP_INPUT_LCR                        0x1
+#define CAM_IFE_CSID_CAP_MIPI8_UNPACK                     0x2
+#define CAM_IFE_CSID_CAP_MIPI10_UNPACK                    0x4
+#define CAM_IFE_CSID_CAP_MIPI12_UNPACK                    0x8
+#define CAM_IFE_CSID_CAP_MIPI14_UNPACK                    0x10
+#define CAM_IFE_CSID_CAP_MIPI16_UNPACK                    0x20
+#define CAM_IFE_CSID_CAP_MIPI20_UNPACK                    0x40
 /*
  * Debug values enable the corresponding interrupts and debug logs provide
  * necessary information
@@ -283,6 +290,8 @@ struct cam_ife_csid_debug_info {
  * @tpg_configured:         flag to indicate if internal_tpg is configured
  * @reset_awaited:          flag to indicate if reset is awaited
  * @offline_mode:           flag to indicate if csid in offline mode
+ * @rdi_lcr_en:             flag to indicate if RDI to lcr is enabled
+ * @sfe_en:                 flag to indicate if SFE is enabled
  */
 struct cam_ife_csid_hw_flags {
 	bool                  device_enabled;
@@ -295,10 +304,12 @@ struct cam_ife_csid_hw_flags {
 	bool                  tpg_configured;
 	bool                  reset_awaited;
 	bool                  offline_mode;
+	bool                  rdi_lcr_en;
+	bool                  sfe_en;
 };
 
 /*
- * struct cam_ife_csid_hw_flags: place holder for flags
+ * struct am_ife_csid_cid_data: place holder for cid data
  *
  * @vc_dt:        vc_dt structure
  * @cid_cnt:      count of cid acquired
@@ -311,7 +322,7 @@ struct cam_ife_csid_cid_data {
 };
 
 /*
- * struct cam_ife_csid_hw_flags: place holder for flags
+ * struct cam_ife_csid_rx_cfg: place holder for rx cfg
  *
  * @phy_sel:                  Selected phy
  * @lane_type:                type of lane selected
@@ -344,7 +355,8 @@ int cam_ife_csid_is_pix_res_format_supported(
 
 int cam_ife_csid_get_format_rdi(
 	uint32_t in_format, uint32_t out_format,
-	struct cam_ife_csid_path_format *path_format, bool rpp);
+	struct cam_ife_csid_path_format *path_format, bool rpp,
+	bool mipi_unpacked);
 
 int cam_ife_csid_get_format_ipp_ppp(
 	uint32_t in_format,

+ 2 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c

@@ -2172,7 +2172,7 @@ static int cam_ife_csid_ver1_init_config_rdi_path(
 	mem_base = soc_info->reg_map[0].mem_base;
 	is_rpp = path_cfg->crop_enable || path_cfg->drop_enable;
 	rc = cam_ife_csid_get_format_rdi(path_cfg->in_format,
-		path_cfg->out_format, &path_format, is_rpp);
+		path_cfg->out_format, &path_format, is_rpp, false);
 	if (rc)
 		return rc;
 
@@ -2330,7 +2330,7 @@ static int cam_ife_csid_ver1_init_config_udi_path(
 	mem_base = soc_info->reg_map[0].mem_base;
 	is_rpp = path_cfg->crop_enable || path_cfg->drop_enable;
 	rc = cam_ife_csid_get_format_rdi(path_cfg->in_format,
-		path_cfg->out_format, &path_format, is_rpp);
+		path_cfg->out_format, &path_format, is_rpp, false);
 	if (rc)
 		return rc;
 

+ 123 - 10
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c

@@ -2108,6 +2108,45 @@ err:
 	return rc;
 }
 
+static bool cam_ife_csid_hw_ver2_need_unpack_mipi(
+	struct cam_ife_csid_ver2_hw                  *csid_hw,
+	struct cam_csid_hw_reserve_resource_args     *reserve,
+	const struct cam_ife_csid_ver2_path_reg_info *path_reg,
+	uint32_t                                      format)
+{
+	bool  need_unpack = false;
+
+	switch(format) {
+	case CAM_FORMAT_MIPI_RAW_8:
+		need_unpack = (bool)(path_reg->capabilities & CAM_IFE_CSID_CAP_MIPI8_UNPACK);
+		break;
+	case CAM_FORMAT_MIPI_RAW_10:
+		need_unpack = (bool)(path_reg->capabilities & CAM_IFE_CSID_CAP_MIPI10_UNPACK);
+		break;
+	case CAM_FORMAT_MIPI_RAW_12:
+		need_unpack = (bool)(path_reg->capabilities & CAM_IFE_CSID_CAP_MIPI12_UNPACK);
+		break;
+	case CAM_FORMAT_MIPI_RAW_14:
+		need_unpack = (bool)(path_reg->capabilities & CAM_IFE_CSID_CAP_MIPI14_UNPACK);
+		break;
+	case CAM_FORMAT_MIPI_RAW_16:
+		need_unpack = (bool)(path_reg->capabilities & CAM_IFE_CSID_CAP_MIPI16_UNPACK);
+		break;
+	case CAM_FORMAT_MIPI_RAW_20:
+		need_unpack = (bool)(path_reg->capabilities & CAM_IFE_CSID_CAP_MIPI20_UNPACK);
+		break;
+	default:
+		need_unpack = false;
+		break;
+	}
+
+	CAM_DBG(CAM_ISP, "CSID[%u], RDI_%u format %u need_unpack %u sfe_shdr %u",
+		csid_hw->hw_intf->hw_idx, reserve->res_id, format, need_unpack,
+		reserve->sfe_inline_shdr);
+
+	return need_unpack;
+}
+
 static int cam_ife_csid_hw_ver2_config_path_data(
 	struct cam_ife_csid_ver2_hw *csid_hw,
 	struct cam_ife_csid_ver2_path_cfg *path_cfg,
@@ -2120,6 +2159,7 @@ static int cam_ife_csid_hw_ver2_config_path_data(
 		(struct cam_ife_csid_ver2_reg_info *)csid_hw->core_info->csid_reg;
 	struct cam_ife_csid_cid_data *cid_data = &csid_hw->cid_data[cid];
 	struct cam_isp_resource_node *res = &csid_hw->path_res[reserve->res_id];
+	const struct cam_ife_csid_ver2_path_reg_info  *path_reg = NULL;
 
 	for(i = 0; i < reserve->in_port->num_valid_vc_dt; i++)
 		path_cfg->in_format[i] = reserve->in_port->format[i];
@@ -2138,6 +2178,7 @@ static int cam_ife_csid_hw_ver2_config_path_data(
 	path_cfg->num_bytes_out = reserve->in_port->num_bytes_out;
 	path_cfg->sec_evt_config.en_secondary_evt = reserve->sec_evt_config.en_secondary_evt;
 	path_cfg->sec_evt_config.evt_type = reserve->sec_evt_config.evt_type;
+	path_reg = csid_reg->path_reg[res->res_id];
 
 	if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) {
 		path_cfg->start_pixel = reserve->in_port->left_start;
@@ -2191,11 +2232,18 @@ static int cam_ife_csid_hw_ver2_config_path_data(
 	case CAM_IFE_PIX_PATH_RES_RDI_3:
 	case CAM_IFE_PIX_PATH_RES_RDI_4:
 		is_rpp = path_cfg->crop_enable || path_cfg->drop_enable;
+		/*
+		 * if csid gives unpacked out, packing needs to be done at
+		 * WM side if needed, based on the format the decision is
+		 * taken at WM side
+		 */
+		reserve->use_wm_pack = cam_ife_csid_hw_ver2_need_unpack_mipi(csid_hw,
+			reserve, path_reg, path_cfg->out_format);
 		rc = cam_ife_csid_get_format_rdi(
 			path_cfg->in_format[CAM_IFE_CSID_MULTI_VC_DT_GRP_0],
 			path_cfg->out_format,
 			&path_cfg->path_format[CAM_IFE_CSID_MULTI_VC_DT_GRP_0],
-			is_rpp);
+			is_rpp, reserve->use_wm_pack);
 		if (rc)
 			goto end;
 
@@ -2206,7 +2254,7 @@ static int cam_ife_csid_hw_ver2_config_path_data(
 				path_cfg->in_format[CAM_IFE_CSID_MULTI_VC_DT_GRP_1],
 				path_cfg->out_format,
 				&path_cfg->path_format[CAM_IFE_CSID_MULTI_VC_DT_GRP_1],
-				is_rpp);
+				is_rpp, reserve->use_wm_pack);
 			if (rc)
 				goto end;
 		}
@@ -2516,9 +2564,9 @@ int cam_ife_csid_ver2_reserve(void *hw_priv,
 	csid_hw->token  = reserve->cb_priv;
 	reserve->buf_done_controller = csid_hw->buf_done_irq_controller;
 	res->cdm_ops = reserve->cdm_ops;
-	path_cfg->sfe_inline_shdr = reserve->sfe_inline_shdr;
+	csid_hw->flags.sfe_en = reserve->sfe_en;
+	path_cfg->sfe_shdr = reserve->sfe_inline_shdr;
 	csid_hw->flags.offline_mode = reserve->is_offline;
-
 	reserve->need_top_cfg = csid_reg->need_top_cfg;
 
 	CAM_DBG(CAM_ISP, "CSID[%u] Resource[id: %d name:%s] state %d cid %d",
@@ -2614,7 +2662,7 @@ end:
 	return rc;
 }
 
-static int cam_ife_csid_ver2_shdr_cfg(
+static int cam_ife_csid_ver2_res_master_slave_cfg(
 	struct cam_ife_csid_ver2_hw *csid_hw,
 	uint32_t res_id)
 {
@@ -2641,6 +2689,9 @@ static int cam_ife_csid_ver2_shdr_cfg(
 	case CAM_IFE_PIX_PATH_RES_RDI_2:
 		val |= BIT(csid_reg->cmn_reg->shdr_slave_rdi2_shift);
 		break;
+	case CAM_IFE_PIX_PATH_RES_PPP:
+		val |= BIT(csid_reg->cmn_reg->shdr_slave_ppp_shift);
+		break;
 	default:
 		break;
 	}
@@ -2803,8 +2854,10 @@ static int cam_ife_csid_ver2_init_config_rdi_path(
 			path_reg->err_recovery_cfg0_addr);
 	}
 
-	if (path_cfg->sfe_inline_shdr)
-		cam_ife_csid_ver2_shdr_cfg(csid_hw, res->res_id);
+	if (path_cfg->sfe_shdr ||
+		(csid_hw->flags.rdi_lcr_en &&
+		 res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0))
+		cam_ife_csid_ver2_res_master_slave_cfg(csid_hw, res->res_id);
 
 	if (csid_hw->debug_info.debug_val &
 		CAM_IFE_CSID_DEBUG_ENABLE_HBI_VBI_INFO) {
@@ -2990,6 +3043,9 @@ static int cam_ife_csid_ver2_init_config_pxl_path(
 			mem_base + path_reg->format_measure_cfg0_addr);
 	}
 
+	if (csid_hw->flags.rdi_lcr_en && res->res_id == CAM_IFE_PIX_PATH_RES_PPP)
+		cam_ife_csid_ver2_res_master_slave_cfg(csid_hw, res->res_id);
+
 	res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
 	return rc;
 }
@@ -3088,7 +3144,7 @@ static int cam_ife_csid_ver2_program_rdi_path(
 	}
 
 	if ((csid_hw->flags.offline_mode ||
-		path_cfg->sfe_inline_shdr) &&
+		path_cfg->sfe_shdr) &&
 		(res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0)) {
 		val |= path_reg->camif_irq_mask;
 		path_cfg->handle_camif_irq = true;
@@ -3693,7 +3749,6 @@ err:
 	return rc;
 }
 
-
 static int cam_ife_csid_ver2_program_top(
 	struct cam_ife_csid_ver2_hw *csid_hw)
 {
@@ -3735,6 +3790,8 @@ static int cam_ife_csid_ver2_program_top(
 	val |= csid_hw->top_cfg.out_ife_en <<
 			top_reg->out_ife_en_shift_val;
 
+	val |= csid_hw->top_cfg.rdi_lcr;
+
 	cam_io_w_mb(val,
 		soc_info->reg_map[CAM_IFE_CSID_TOP_MEM_BASE_ID].mem_base +
 		top_reg->io_path_cfg0_addr[csid_hw->hw_intf->hw_idx]);
@@ -4058,6 +4115,7 @@ static int cam_ife_csid_ver2_disable_core(
 	spin_lock_bh(&csid_hw->lock_state);
 	csid_hw->flags.device_enabled = false;
 	csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN;
+	csid_hw->flags.rdi_lcr_en = false;
 	spin_unlock_bh(&csid_hw->lock_state);
 	rc = cam_ife_csid_disable_soc_resources(soc_info);
 	if (rc)
@@ -4065,7 +4123,6 @@ static int cam_ife_csid_ver2_disable_core(
 			csid_hw->hw_intf->hw_idx);
 
 	csid_hw->counters.error_irq_count = 0;
-
 	return rc;
 }
 
@@ -4280,6 +4337,7 @@ int cam_ife_csid_ver2_stop(void *hw_priv,
 		csid_stop->num_res);
 
 	csid_hw->flags.device_enabled = false;
+	csid_hw->flags.rdi_lcr_en = false;
 
 	reset.reset_type = (csid_hw->flags.fatal_err_detected) ? CAM_IFE_CSID_RESET_GLOBAL :
 		CAM_IFE_CSID_RESET_PATH;
@@ -4906,6 +4964,58 @@ end:
 	return 0;
 }
 
+static int cam_ife_csid_ver2_rdi_lcr_cfg(
+	struct cam_ife_csid_ver2_hw  *csid_hw, void *cmd_args)
+{
+	const struct cam_ife_csid_ver2_path_reg_info *path_reg;
+	struct cam_ife_csid_ver2_reg_info            *csid_reg;
+	struct cam_ife_csid_ver2_path_cfg            *path_cfg = NULL;
+	struct cam_isp_resource_node                 *res = cmd_args;
+
+	if (!csid_hw || !cmd_args) {
+		CAM_ERR(CAM_ISP, "Invalid params");
+		return -EINVAL;
+	}
+
+	csid_reg = (struct cam_ife_csid_ver2_reg_info *)
+			csid_hw->core_info->csid_reg;
+
+	path_reg = csid_reg->path_reg[res->res_id];
+	path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
+	if (!path_cfg || !path_reg || !path_reg->capabilities ||
+		!(path_reg->capabilities & CAM_IFE_CSID_CAP_INPUT_LCR)) {
+		CAM_ERR(CAM_ISP, "Invalid res %s", res->res_name);
+		return -EINVAL;
+	}
+
+	if (!path_cfg->sfe_shdr && (res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0)) {
+		CAM_ERR(CAM_ISP, "Invalid res: %s, capabilities 0x%x sfe_shdr: %u",
+			res->res_name, path_reg->capabilities, path_cfg->sfe_shdr);
+		return -EINVAL;
+	}
+
+	/*
+	 * LCR should not be on for a resource if CSID is giving packed data
+	 * this case would come for formats which are not supported
+	 * */
+	if (path_cfg->path_format[CAM_IFE_CSID_MULTI_VC_DT_GRP_0].packing_fmt) {
+		CAM_ERR(CAM_ISP, "LCR enabled for %s, csid out packed not supported",
+			res->res_name);
+		return -EINVAL;
+	}
+
+	if (csid_hw->flags.sfe_en)
+		csid_hw->top_cfg.rdi_lcr |= BIT(res->res_id) <<
+			csid_reg->top_reg->rdi_lcr_shift_val;
+
+	csid_hw->flags.rdi_lcr_en = true;
+
+	CAM_DBG(CAM_ISP, "CSID[%u] %s top_cfg %u",
+		csid_hw->hw_intf->hw_idx, res->res_name, csid_hw->top_cfg.rdi_lcr);
+
+	return 0;
+}
+
 static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
 {
@@ -4983,6 +5093,9 @@ static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 	case CAM_ISP_HW_CMD_CSID_DISCARD_INIT_FRAMES:
 		rc = cam_ife_csid_ver2_set_discard_frame_cfg(csid_hw, cmd_args);
 		break;
+	case CAM_ISP_HW_CMD_RDI_LCR_CFG:
+		rc = cam_ife_csid_ver2_rdi_lcr_cfg(csid_hw, cmd_args);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);

+ 6 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h

@@ -108,6 +108,7 @@ struct cam_ife_csid_ver2_top_cfg {
 	bool          dual_en;
 	bool          offline_sfe_en;
 	bool          out_ife_en;
+	bool          rdi_lcr;
 };
 
 struct cam_ife_csid_ver2_evt_payload {
@@ -166,7 +167,7 @@ struct cam_ife_csid_ver2_camif_data {
  *                          If we know the number of paths to avoid configuring discard
  *                          for before processing discard config we can skip it for
  *                          the corresponding paths
- * @sfe_inline_shdr:        flag to indicate if sfe is inline shdr
+ * @sfe_shdr:               flag to indicate if sfe is inline shdr
  *
  */
 struct cam_ife_csid_ver2_path_cfg {
@@ -204,7 +205,7 @@ struct cam_ife_csid_ver2_path_cfg {
 	bool                                 handle_camif_irq;
 	bool                                 discard_init_frames;
 	bool                                 skip_discard_frame_cfg;
-	bool                                 sfe_inline_shdr;
+	bool                                 sfe_shdr;
 };
 
 struct cam_ife_csid_ver2_top_reg_info {
@@ -216,6 +217,7 @@ struct cam_ife_csid_ver2_top_reg_info {
 	uint32_t dual_sync_sel_shift_val;
 	uint32_t dual_en_shift_val;
 	uint32_t master_slave_sel_shift_val;
+	uint32_t rdi_lcr_shift_val;
 	uint32_t master_sel_val;
 	uint32_t slave_sel_val;
 	uint32_t io_path_cfg_rst_val;
@@ -349,6 +351,7 @@ struct cam_ife_csid_ver2_path_reg_info {
 	uint32_t epoch1_cfg_val;
 	uint32_t epoch0_shift_val;
 	uint32_t epoch1_shift_val;
+	uint32_t capabilities;
 };
 
 struct cam_ife_csid_ver2_common_reg_info {
@@ -422,6 +425,7 @@ struct cam_ife_csid_ver2_common_reg_info {
 	uint32_t multi_vcdt_ts_combo_en_shift_val;
 	uint32_t multi_vcdt_en_shift_val;
 	uint32_t mup_shift_val;
+	uint32_t shdr_slave_ppp_shift;
 	uint32_t shdr_slave_rdi2_shift;
 	uint32_t shdr_slave_rdi1_shift;
 	uint32_t shdr_master_rdi0_shift;

+ 6 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -192,10 +192,12 @@ struct cam_csid_secondary_evt_config {
  * @buf_done_controller: IRQ controller for buf done for version 680 hw
  * @cdm_ops:             CDM Ops
  * @event_cb:            Callback function to hw mgr in case of hw events
- * @cb_priv:             Private pointer to return to callback
  * @phy_sel:             Phy selection number if tpg is enabled from userspace
+ * @cb_priv:             Private pointer to return to callback
  * @can_use_lite:        Flag to indicate if current call qualifies for
  *                       acquire lite
+ * @sfe_en:              Flag to indicate if SFE is enabled
+ * @use_wm_pack:         [OUT]Flag to indicate if WM packing is to be used for packing
  *
  */
 struct cam_csid_hw_reserve_resource_args {
@@ -218,8 +220,10 @@ struct cam_csid_hw_reserve_resource_args {
 	void                                     *cdm_ops;
 	cam_hw_mgr_event_cb_func                  event_cb;
 	uint32_t                                  phy_sel;
-	bool                                      can_use_lite;
 	void                                     *cb_priv;
+	bool                                      can_use_lite;
+	bool                                      sfe_en;
+	bool                                      use_wm_pack;
 };
 
 /**

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

@@ -203,6 +203,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE,
 	CAM_ISP_HW_CSID_MINI_DUMP,
 	CAM_ISP_HW_BUS_MINI_DUMP,
+	CAM_ISP_HW_CMD_RDI_LCR_CFG,
 	CAM_ISP_HW_CMD_MAX,
 };
 

+ 2 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h

@@ -307,6 +307,7 @@ struct cam_sfe_hw_sfe_in_acquire_args {
  * @split_id:                In case of Dual SFE, this is Left or Right.
  * @is_master:               In case of Dual SFE, this is Master or Slave.
  * @cdm_ops:                 CDM operations
+ * @use_wm_pack:             Flag to indicalte packing at WM side
  */
 struct cam_sfe_hw_sfe_out_acquire_args {
 	struct cam_isp_resource_node         *rsrc_node;
@@ -316,6 +317,7 @@ struct cam_sfe_hw_sfe_out_acquire_args {
 	enum cam_isp_hw_split_id              split_id;
 	uint32_t                              is_master;
 	struct cam_cdm_utils_ops             *cdm_ops;
+	bool                                  use_wm_pack;
 };
 
 /*

+ 2 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h

@@ -142,6 +142,7 @@ struct cam_vfe_hw_vfe_bus_rd_acquire_args {
  * @dual_slave_core:         If Master and Slave exists, HW Index of Slave
  * @cdm_ops:                 CDM operations
  * @disable_ubwc_comp:       Disable UBWC compression
+ * @use_wm_pack:             Use WM Packing
  */
 struct cam_vfe_hw_vfe_out_acquire_args {
 	struct cam_isp_resource_node         *rsrc_node;
@@ -153,6 +154,7 @@ struct cam_vfe_hw_vfe_out_acquire_args {
 	uint32_t                              dual_slave_core;
 	struct cam_cdm_utils_ops             *cdm_ops;
 	bool                                  disable_ubwc_comp;
+	bool                                  use_wm_pack;
 };
 
 /*

+ 39 - 21
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c

@@ -113,8 +113,6 @@ struct cam_sfe_bus_wr_wm_resource_data {
 	struct cam_sfe_bus_reg_offset_bus_client  *hw_regs;
 	struct cam_sfe_wr_scratch_buf_info scratch_buf_info;
 
-	bool                 init_cfg_done;
-	bool                 hfr_cfg_done;
 
 	uint32_t             offset;
 	uint32_t             width;
@@ -137,9 +135,12 @@ struct cam_sfe_bus_wr_wm_resource_data {
 	uint32_t             acquired_width;
 	uint32_t             acquired_height;
 
-	bool                 enable_caching;
 	uint32_t             cache_cfg;
 	int32_t              current_scid;
+	bool                 enable_caching;
+	bool                 init_cfg_done;
+	bool                 hfr_cfg_done;
+	bool                 use_wm_pack;
 };
 
 struct cam_sfe_bus_wr_comp_grp_data {
@@ -501,7 +502,8 @@ static inline void cam_sfe_bus_config_rdi_wm_frame_based_mode(
 static int cam_sfe_bus_config_rdi_wm(
 	struct cam_sfe_bus_wr_wm_resource_data  *rsrc_data)
 {
-	rsrc_data->pack_fmt = 0x0;
+
+	rsrc_data->pack_fmt = PACKER_FMT_PLAIN_128;
 	switch (rsrc_data->format) {
 	case CAM_FORMAT_MIPI_RAW_10:
 		if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE) {
@@ -514,6 +516,12 @@ static int cam_sfe_bus_config_rdi_wm(
 			CAM_WARN(CAM_SFE, "No index mode support for SFE WM: %u",
 				rsrc_data->index);
 		}
+
+		if (rsrc_data->use_wm_pack) {
+			rsrc_data->pack_fmt = PACKER_FMT_MIPI10;
+			if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE)
+				rsrc_data->width = ALIGNUP((rsrc_data->acquired_width), 16);
+		}
 		break;
 	case CAM_FORMAT_MIPI_RAW_6:
 		if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE) {
@@ -550,6 +558,12 @@ static int cam_sfe_bus_config_rdi_wm(
 			CAM_WARN(CAM_SFE, "No index mode support for SFE WM: %u",
 				rsrc_data->index);
 		}
+
+		if (rsrc_data->use_wm_pack) {
+			rsrc_data->pack_fmt = PACKER_FMT_MIPI12;
+			if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE)
+				rsrc_data->width = ALIGNUP((rsrc_data->acquired_width), 16);
+		}
 		break;
 	case CAM_FORMAT_MIPI_RAW_14:
 		if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE) {
@@ -562,6 +576,11 @@ static int cam_sfe_bus_config_rdi_wm(
 			CAM_WARN(CAM_SFE, "No index mode support for SFE WM: %u",
 				rsrc_data->index);
 		}
+		if (rsrc_data->use_wm_pack) {
+			rsrc_data->pack_fmt = PACKER_FMT_MIPI14;
+			if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE)
+				rsrc_data->width = ALIGNUP((rsrc_data->acquired_width), 16);
+		}
 		break;
 	case CAM_FORMAT_MIPI_RAW_16:
 		if (rsrc_data->wm_mode == CAM_SFE_WM_LINE_BASED_MODE) {
@@ -659,15 +678,14 @@ static int cam_sfe_bus_config_rdi_wm(
 }
 
 static int cam_sfe_bus_acquire_wm(
-	struct cam_sfe_bus_wr_priv            *bus_priv,
-	struct cam_isp_out_port_generic_info  *out_port_info,
-	void                                  *tasklet,
-	enum cam_sfe_bus_sfe_out_type          sfe_out_res_id,
-	enum cam_sfe_bus_plane_type            plane,
-	struct cam_isp_resource_node          *wm_res,
-	uint32_t                              *comp_done_mask,
-	uint32_t                               is_dual,
-	enum cam_sfe_bus_wr_comp_grp_type     *comp_grp_id)
+	struct cam_sfe_bus_wr_priv             *bus_priv,
+	struct cam_sfe_hw_sfe_out_acquire_args *out_acq_args,
+	void                                   *tasklet,
+	enum cam_sfe_bus_sfe_out_type           sfe_out_res_id,
+	enum cam_sfe_bus_plane_type             plane,
+	struct cam_isp_resource_node           *wm_res,
+	uint32_t                               *comp_done_mask,
+	enum cam_sfe_bus_wr_comp_grp_type      *comp_grp_id)
 {
 	int32_t wm_idx = 0, rc;
 	struct cam_sfe_bus_wr_wm_resource_data  *rsrc_data = NULL;
@@ -681,15 +699,16 @@ static int cam_sfe_bus_acquire_wm(
 
 	rsrc_data = wm_res->res_priv;
 	wm_idx = rsrc_data->index;
-	rsrc_data->format = out_port_info->format;
+	rsrc_data->format = out_acq_args->out_port_info->format;
+	rsrc_data->use_wm_pack = out_acq_args->use_wm_pack;
 	rsrc_data->pack_fmt = cam_sfe_bus_get_packer_fmt(bus_priv,
 		rsrc_data->format, wm_idx);
 
-	rsrc_data->width = out_port_info->width;
-	rsrc_data->height = out_port_info->height;
-	rsrc_data->acquired_width = out_port_info->width;
-	rsrc_data->acquired_height = out_port_info->height;
-	rsrc_data->is_dual = is_dual;
+	rsrc_data->width = out_acq_args->out_port_info->width;
+	rsrc_data->height = out_acq_args->out_port_info->height;
+	rsrc_data->acquired_width = out_acq_args->out_port_info->width;
+	rsrc_data->acquired_height = out_acq_args->out_port_info->height;
+	rsrc_data->is_dual = out_acq_args->is_dual;
 	rsrc_data->enable_caching =  false;
 	rsrc_data->offset = 0;
 
@@ -1350,13 +1369,12 @@ static int cam_sfe_bus_acquire_sfe_out(void *priv, void *acquire_args,
 	/* Acquire WM and retrieve COMP GRP ID */
 	for (i = 0; i < rsrc_data->num_wm; i++) {
 		rc = cam_sfe_bus_acquire_wm(bus_priv,
-			out_acquire_args->out_port_info,
+			out_acquire_args,
 			acq_args->tasklet,
 			sfe_out_res_id,
 			i,
 			&rsrc_data->wm_res[i],
 			&client_done_mask,
-			out_acquire_args->is_dual,
 			&comp_grp_id);
 		if (rc) {
 			CAM_ERR(CAM_SFE,

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

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

+ 19 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe780.h

@@ -472,6 +472,21 @@ static struct cam_vfe_top_ver4_pdaf_violation_desc vfe780_pdaf_violation_desc[]
 	},
 };
 
+static struct cam_vfe_top_ver4_pdaf_lcr_res_info vfe780_pdaf_lcr_res_mask[] = {
+	{
+		.res_id = CAM_ISP_HW_VFE_IN_RDI0,
+		.val = 0,
+	},
+	{
+		.res_id = CAM_ISP_HW_VFE_IN_RDI1,
+		.val = 1,
+	},
+	{
+		.res_id = CAM_ISP_HW_VFE_IN_RDI2,
+		.val= 2,
+	},
+};
+
 static struct cam_irq_register_set vfe780_top_irq_reg_set[2] = {
 	{
 		.mask_reg_offset   = 0x00000034,
@@ -530,6 +545,8 @@ static struct cam_vfe_top_ver4_reg_offset_common vfe780_top_common_reg = {
 	.bus_overflow_status      = 0x00000C68,
 	.top_debug_cfg            = 0x000000FC,
 	.num_top_debug_reg        = CAM_VFE_780_NUM_DBG_REG,
+	.pdaf_input_cfg_0         = 0x00000130,
+	.pdaf_input_cfg_1         = 0x00000134,
 	.top_debug = {
 		0x000000A0,
 		0x000000A4,
@@ -818,6 +835,8 @@ static struct cam_vfe_top_ver4_hw_info vfe780_top_hw_info = {
 	.num_pdaf_violation_errors       = ARRAY_SIZE(vfe780_pdaf_violation_desc),
 	.pdaf_violation_desc             = vfe780_pdaf_violation_desc,
 	.debug_reg_info                  = &vfe780_dbg_reg_info,
+	.pdaf_lcr_res_mask               = vfe780_pdaf_lcr_res_mask,
+	.num_pdaf_lcr_res                = ARRAY_SIZE(vfe780_pdaf_lcr_res_mask),
 };
 
 static struct cam_irq_register_set vfe780_bus_irq_reg[2] = {

+ 37 - 16
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c

@@ -151,6 +151,7 @@ struct cam_vfe_bus_ver3_wm_resource_data {
 	uint32_t             acquired_width;
 	uint32_t             acquired_height;
 	uint32_t             default_line_based;
+	bool                 use_wm_pack;
 };
 
 struct cam_vfe_bus_ver3_comp_grp_data {
@@ -847,7 +848,7 @@ static int cam_vfe_bus_ver3_handle_rup_bottom_half(void *handler_priv,
 static int cam_vfe_bus_ver3_config_rdi_wm(
 	struct cam_vfe_bus_ver3_wm_resource_data  *rsrc_data)
 {
-	/* Force RDI to use PLAIN128 */
+
 	rsrc_data->pack_fmt = PACKER_FMT_VER3_PLAIN_128;
 	switch (rsrc_data->format) {
 	case CAM_FORMAT_MIPI_RAW_10:
@@ -861,6 +862,12 @@ static int cam_vfe_bus_ver3_config_rdi_wm(
 			rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE;
 			rsrc_data->en_cfg = (0x1 << 16) | 0x1;
 		}
+
+		if (rsrc_data->use_wm_pack) {
+			rsrc_data->pack_fmt = PACKER_FMT_VER3_MIPI10;
+			if (rsrc_data->default_line_based)
+				rsrc_data->width = ALIGNUP((rsrc_data->acquired_width), 16);
+		}
 		break;
 	case CAM_FORMAT_MIPI_RAW_6:
 		if (rsrc_data->default_line_based) {
@@ -898,6 +905,12 @@ static int cam_vfe_bus_ver3_config_rdi_wm(
 			rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE;
 			rsrc_data->en_cfg = (0x1 << 16) | 0x1;
 		}
+
+		if (rsrc_data->use_wm_pack) {
+			rsrc_data->pack_fmt = PACKER_FMT_VER3_MIPI12;
+			if (rsrc_data->default_line_based)
+				rsrc_data->width = ALIGNUP((rsrc_data->acquired_width), 16);
+		}
 		break;
 	case CAM_FORMAT_MIPI_RAW_14:
 		if (rsrc_data->default_line_based) {
@@ -910,6 +923,12 @@ static int cam_vfe_bus_ver3_config_rdi_wm(
 			rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE;
 			rsrc_data->en_cfg = (0x1 << 16) | 0x1;
 		}
+
+		if (rsrc_data->use_wm_pack) {
+			rsrc_data->pack_fmt = PACKER_FMT_VER3_MIPI14;
+			if (rsrc_data->default_line_based)
+				rsrc_data->width = ALIGNUP((rsrc_data->acquired_width), 16);
+		}
 		break;
 	case CAM_FORMAT_MIPI_RAW_16:
 		if (rsrc_data->default_line_based) {
@@ -934,6 +953,9 @@ static int cam_vfe_bus_ver3_config_rdi_wm(
 			rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE;
 			rsrc_data->en_cfg = (0x1 << 16) | 0x1;
 		}
+
+		if (rsrc_data->use_wm_pack)
+			rsrc_data->pack_fmt = PACKER_FMT_VER3_MIPI20;
 		break;
 	case CAM_FORMAT_PLAIN128:
 		if (rsrc_data->default_line_based) {
@@ -998,13 +1020,12 @@ static int cam_vfe_bus_ver3_config_rdi_wm(
 }
 
 static int cam_vfe_bus_ver3_acquire_wm(
-	struct cam_vfe_bus_ver3_priv          *ver3_bus_priv,
-	struct cam_isp_out_port_generic_info  *out_port_info,
-	void                                  *tasklet,
-	enum cam_vfe_bus_ver3_vfe_out_type     vfe_out_res_id,
-	enum cam_vfe_bus_plane_type            plane,
-	struct cam_isp_resource_node          *wm_res,
-	uint32_t                               is_dual,
+	struct cam_vfe_bus_ver3_priv           *ver3_bus_priv,
+	struct cam_vfe_hw_vfe_out_acquire_args *out_acq_args,
+	void                                   *tasklet,
+	enum cam_vfe_bus_ver3_vfe_out_type      vfe_out_res_id,
+	enum cam_vfe_bus_plane_type             plane,
+	struct cam_isp_resource_node           *wm_res,
 	enum cam_vfe_bus_ver3_comp_grp_type   *comp_grp_id)
 {
 	int32_t wm_idx = 0, rc;
@@ -1021,15 +1042,16 @@ static int cam_vfe_bus_ver3_acquire_wm(
 
 	rsrc_data = wm_res->res_priv;
 	wm_idx = rsrc_data->index;
-	rsrc_data->format = out_port_info->format;
+	rsrc_data->format = out_acq_args->out_port_info->format;
+	rsrc_data->use_wm_pack = out_acq_args->use_wm_pack;
 	rsrc_data->pack_fmt = cam_vfe_bus_ver3_get_packer_fmt(rsrc_data->format,
 		wm_idx);
 
-	rsrc_data->width = out_port_info->width;
-	rsrc_data->height = out_port_info->height;
-	rsrc_data->acquired_width = out_port_info->width;
-	rsrc_data->acquired_height = out_port_info->height;
-	rsrc_data->is_dual = is_dual;
+	rsrc_data->width = out_acq_args->out_port_info->width;
+	rsrc_data->height = out_acq_args->out_port_info->height;
+	rsrc_data->acquired_width = out_acq_args->out_port_info->width;
+	rsrc_data->acquired_height = out_acq_args->out_port_info->height;
+	rsrc_data->is_dual = out_acq_args->is_dual;
 	/* Set WM offset value to default */
 	rsrc_data->offset  = 0;
 	CAM_DBG(CAM_ISP, "WM:%d width %d height %d", rsrc_data->index,
@@ -2029,12 +2051,11 @@ static int cam_vfe_bus_ver3_acquire_vfe_out(void *bus_priv, void *acquire_args,
 	/* Acquire WM and retrieve COMP GRP ID */
 	for (i = 0; i < rsrc_data->num_wm; i++) {
 		rc = cam_vfe_bus_ver3_acquire_wm(ver3_bus_priv,
-			out_acquire_args->out_port_info,
+			out_acquire_args,
 			acq_args->tasklet,
 			vfe_out_res_id,
 			i,
 			&rsrc_data->wm_res[i],
-			out_acquire_args->is_dual,
 			&comp_acq_args.comp_grp_id);
 		if (rc) {
 			CAM_ERR(CAM_ISP,

+ 80 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c

@@ -99,6 +99,82 @@ static int cam_vfe_top_ver4_get_path_port_map(struct cam_vfe_top_ver4_priv *top_
 	return 0;
 }
 
+static int cam_vfe_top_ver4_pdaf_lcr_config(struct cam_vfe_top_ver4_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_vfe_top_ver4_hw_info  *hw_info;
+	struct cam_isp_hw_get_cmd_update *cdm_args = NULL;
+	struct cam_cdm_utils_ops         *cdm_util_ops = NULL;
+	uint32_t                          i;
+	uint32_t                          reg_val_idx = 0;
+	uint32_t                          num_reg_vals;
+	uint32_t                          reg_val_pair[4];
+	struct cam_isp_lcr_rdi_cfg_args  *cfg_args;
+	size_t                            size;
+
+	if (!cmd_args || !top_priv) {
+		CAM_ERR(CAM_ISP, "Error, Invalid args");
+		return -EINVAL;
+	}
+
+	cdm_args = (struct cam_isp_hw_get_cmd_update *)cmd_args;
+	if (!cdm_args->res) {
+		CAM_ERR(CAM_ISP, "Error, Invalid res");
+		return -EINVAL;
+	}
+
+	hw_info = top_priv->common_data.hw_info;
+	if (!hw_info->num_pdaf_lcr_res || !hw_info->pdaf_lcr_res_mask) {
+		CAM_DBG(CAM_ISP, "PDAF LCR is not supported");
+		return 0;
+	}
+
+	cfg_args = (struct cam_isp_lcr_rdi_cfg_args *)cdm_args->data;
+	cdm_util_ops =
+		(struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops;
+	if (!cdm_util_ops) {
+		CAM_ERR(CAM_ISP, "Invalid CDM ops");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < hw_info->num_pdaf_lcr_res; i++)
+		if (cdm_args->res->res_id ==
+			hw_info->pdaf_lcr_res_mask[i].res_id)
+			break;
+
+	if (i == hw_info->num_pdaf_lcr_res) {
+		CAM_ERR(CAM_ISP, "Res :%d is not supported for mux",
+			cfg_args->rdi_lcr_cfg->res_id);
+		return -EINVAL;
+	}
+
+	if (cfg_args->is_init)
+		num_reg_vals = 2;
+	else
+		num_reg_vals = 1;
+
+	size = cdm_util_ops->cdm_required_size_reg_random(num_reg_vals);
+	/* since cdm returns dwords, we need to convert it into bytes */
+	if ((size * 4) > cdm_args->cmd.size) {
+		CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d",
+			cdm_args->cmd.size, (size*4));
+		return -EINVAL;
+	}
+
+	if (cfg_args->is_init) {
+		reg_val_pair[reg_val_idx++] = hw_info->common_reg->pdaf_input_cfg_1;
+		reg_val_pair[reg_val_idx++] = 0;
+	}
+
+	reg_val_pair[reg_val_idx++] = hw_info->common_reg->pdaf_input_cfg_0;
+	reg_val_pair[reg_val_idx++] = hw_info->pdaf_lcr_res_mask[i].val;
+	cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr,
+		num_reg_vals, reg_val_pair);
+	cdm_args->cmd.used_bytes = size * 4;
+
+	return 0;
+}
+
 static int cam_vfe_top_ver4_mux_get_base(struct cam_vfe_top_ver4_priv *top_priv,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -887,6 +963,10 @@ int cam_vfe_top_ver4_process_cmd(void *device_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE:
 		rc = cam_vfe_init_config_update(cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_RDI_LCR_CFG:
+		rc = cam_vfe_top_ver4_pdaf_lcr_config(top_priv, cmd_args,
+			arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);

+ 9 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.h

@@ -57,6 +57,8 @@ struct cam_vfe_top_ver4_reg_offset_common {
 	uint32_t epoch1_pattern_cfg;
 	uint32_t epoch_height_cfg;
 	uint32_t top_debug_cfg;
+	uint32_t pdaf_input_cfg_0;
+	uint32_t pdaf_input_cfg_1;
 	uint32_t num_top_debug_reg;
 	uint32_t top_debug[CAM_VFE_TOP_DBG_REG_MAX];
 };
@@ -93,6 +95,11 @@ struct cam_vfe_top_ver4_pdaf_violation_desc {
 	char     *desc;
 };
 
+struct cam_vfe_top_ver4_pdaf_lcr_res_info {
+	uint32_t  res_id;
+	uint32_t  val;
+};
+
 struct cam_vfe_ver4_path_hw_info {
 	struct cam_vfe_top_ver4_reg_offset_common  *common_reg;
 	struct cam_vfe_ver4_path_reg_data          *reg_data;
@@ -121,6 +128,8 @@ struct cam_vfe_top_ver4_hw_info {
 	struct cam_vfe_top_ver4_top_err_irq_desc    *top_err_desc;
 	uint32_t                                     num_pdaf_violation_errors;
 	struct cam_vfe_top_ver4_pdaf_violation_desc *pdaf_violation_desc;
+	struct cam_vfe_top_ver4_pdaf_lcr_res_info   *pdaf_lcr_res_mask;
+	uint32_t                                     num_pdaf_lcr_res;
 };
 
 struct cam_vfe_ver4_path_reg_data {

+ 27 - 0
include/uapi/camera/media/cam_isp.h

@@ -124,6 +124,7 @@
 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_LIMITER_CFG            16
 #define CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG                17
 #define CAM_ISP_GENERIC_BLOB_TYPE_INIT_CONFIG               18
+#define CAM_ISP_GENERIC_BLOB_TYPE_RDI_LCR_CONFIG            19
 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_CLOCK_CONFIG          21
 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_CORE_CONFIG           22
 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_OUT_CONFIG            23
@@ -1002,6 +1003,32 @@ struct cam_isp_init_config {
 	__u32             additional_params[19];
 };
 
+/**
+ * struct cam_isp_lcr_rdi_config - RDI res id to be muxed to LCR
+ *
+ *    Configure RDI Res id for LCR
+ *
+ * @res_id                   : Out port Res id, it is same as the out port
+ *                             configured during acquire. It would vary
+ *                             as per SFE or IFE. Based on this res id,
+ *                             Mux register in IFE will be programmed.
+ *                             Examples:
+ *                             IFE:
+ *                             CAM_ISP_IFE_OUT_RES_RDI_0
+ *                             SFE:
+ *                             CAM_ISP_SFE_OUT_RES_RDI_0
+ *                             This blob is expected as a part of init packet for
+ *                             all LCR cases. For SHDR-LCR cases, this can be used
+ *                             per request. For non-shdr cases, this blob is not
+ *                             expected as the input to LCR will remain same throughout
+ *                             the session
+ * @reserved                 : Reserved field
+ */
+struct cam_isp_lcr_rdi_config {
+	__u32                                   res_id;
+	__u32                                   reserved[5];
+};
+
 #define CAM_ISP_ACQUIRE_COMMON_VER0         0x1000
 
 #define CAM_ISP_ACQUIRE_COMMON_SIZE_VER0    0x0