Browse Source

msm: camera: isp: Add support for PDAF HW

This change add support for:
 - PDAF HW support handling in CSID and TFE driver
 - CSID PPP halt mode handling
 - Add support for new TFE PD ports (LCR, PD_PREPROCESSED
   PD_PARSED).

CRs-Fixed: 3387396
Change-Id: I56dc109138607fe7b342760a5c977e4126fe1676
Signed-off-by: Alok Chauhan <[email protected]>
Alok Chauhan 2 years ago
parent
commit
b5d8386049

+ 3 - 0
drivers/cam_isp/cam_isp_context.c

@@ -1324,6 +1324,9 @@ static const char *__cam_isp_tfe_resource_handle_id_to_type(
 	case CAM_ISP_TFE_OUT_RES_DS4:                   return "TFE_DS_4";
 	case CAM_ISP_TFE_OUT_RES_DS16:                  return "TFE_DS_16";
 	case CAM_ISP_TFE_OUT_RES_AI:                    return "TFE_AI";
+	case CAM_ISP_TFE_OUT_RES_PD_LCR_STATS:          return "TFE_LCR_STATS";
+	case CAM_ISP_TFE_OUT_RES_PD_PREPROCESSED:       return "TFE_PD_PREPROCESSED";
+	case CAM_ISP_TFE_OUT_RES_PD_PARSED:             return "TFE_PD_PARSED";
 	/* Handle invalid type */
 	default:                                        return "Invalid_Resource_Type";
 	}

+ 143 - 33
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -239,6 +239,20 @@ static int cam_tfe_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args)
 	return rc;
 }
 
+static inline bool cam_tfe_hw_mgr_check_path_port_compat(
+	uint32_t in_type, uint32_t out_type)
+{
+	int i;
+	const struct cam_isp_hw_path_port_map *map = &g_tfe_hw_mgr.path_port_map;
+
+	for (i = 0; i < map->num_entries; i++) {
+		if (map->entry[i][1] == out_type)
+			return (map->entry[i][0] == in_type);
+	}
+
+	return (in_type == CAM_ISP_HW_TFE_IN_CAMIF);
+}
+
 static int cam_tfe_hw_mgr_is_rdi_res(uint32_t res_id)
 {
 	int rc = 0;
@@ -1019,6 +1033,7 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_out(
 
 		switch (tfe_in_res->res_id) {
 		case CAM_ISP_HW_TFE_IN_CAMIF:
+		case CAM_ISP_HW_TFE_IN_PDLIB:
 			rc = cam_tfe_hw_mgr_acquire_res_tfe_out_pixel(tfe_ctx,
 				tfe_in_res, in_port);
 			break;
@@ -1046,7 +1061,8 @@ err:
 static int cam_tfe_hw_mgr_acquire_res_tfe_in(
 	struct cam_tfe_hw_mgr_ctx               *tfe_ctx,
 	struct cam_isp_tfe_in_port_generic_info *in_port,
-	uint32_t                          *pdaf_enable)
+	uint32_t                          *pdaf_enable,
+	bool                              lcr_enable)
 {
 	int rc                = -EINVAL;
 	int i;
@@ -1080,6 +1096,7 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_in(
 		tfe_acquire.tfe_in.camif_pd_enable = *pdaf_enable;
 		tfe_acquire.priv = tfe_ctx;
 		tfe_acquire.event_cb = cam_tfe_hw_mgr_event_handler;
+		tfe_acquire.tfe_in.lcr_enable = lcr_enable;
 
 		switch (csid_res->res_id) {
 		case CAM_TFE_CSID_PATH_RES_IPP:
@@ -1094,6 +1111,17 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_in(
 				CAM_ISP_HW_SYNC_NONE;
 
 			break;
+		case CAM_TFE_CSID_PATH_RES_PPP:
+			tfe_acquire.tfe_in.res_id =
+				CAM_ISP_HW_TFE_IN_PDLIB;
+
+			if (csid_res->is_dual_isp)
+				tfe_acquire.tfe_in.sync_mode =
+					CAM_ISP_HW_SYNC_MASTER;
+			else
+				tfe_acquire.tfe_in.sync_mode =
+					CAM_ISP_HW_SYNC_NONE;
+			break;
 		case CAM_TFE_CSID_PATH_RES_RDI_0:
 			tfe_acquire.tfe_in.res_id = CAM_ISP_HW_TFE_IN_RDI0;
 			tfe_acquire.tfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
@@ -1162,7 +1190,9 @@ err:
 
 static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(
 	struct cam_tfe_hw_mgr_ctx               *tfe_ctx,
-	struct cam_isp_tfe_in_port_generic_info *in_port)
+	struct cam_isp_tfe_in_port_generic_info *in_port,
+	bool                                is_ipp,
+	bool                                crop_enable)
 {
 	int rc = -EINVAL;
 	int i, j;
@@ -1170,14 +1200,17 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(
 	struct cam_tfe_hw_mgr                        *tfe_hw_mgr;
 	struct cam_isp_hw_mgr_res                    *csid_res;
 	struct cam_hw_intf                           *hw_intf;
-	struct cam_tfe_csid_hw_reserve_resource_args  csid_acquire;
+	struct cam_tfe_csid_hw_reserve_resource_args  csid_acquire = {0};
 	enum cam_tfe_csid_path_res_id                 path_res_id;
 	struct cam_isp_hw_mgr_res        *csid_res_temp, *csid_res_iterator;
 	struct cam_isp_tfe_out_port_generic_info     *out_port = NULL;
 
 	tfe_hw_mgr = tfe_ctx->hw_mgr;
 	/* get csid resource */
-	path_res_id = CAM_TFE_CSID_PATH_RES_IPP;
+	if (is_ipp)
+		path_res_id = CAM_TFE_CSID_PATH_RES_IPP;
+	else
+		path_res_id = CAM_TFE_CSID_PATH_RES_PPP;
 
 	rc = cam_tfe_hw_mgr_get_res(&tfe_ctx->free_res_list, &csid_res);
 	if (rc) {
@@ -1194,6 +1227,7 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(
 	csid_acquire.node_res = NULL;
 	csid_acquire.event_cb_prv = tfe_ctx;
 	csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler;
+	csid_acquire.crop_enable = crop_enable;
 	if (in_port->num_out_res)
 		out_port = &(in_port->data[0]);
 
@@ -1232,12 +1266,14 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(
 				csid_acquire.node_res;
 
 			CAM_DBG(CAM_ISP,
-				"acquired from old csid(%s)=%d CSID rsrc successfully",
+				"acquired from old csid(%s)=%d CSID rsrc %s successfully",
 				(i == 0) ? "left" : "right",
-				hw_intf->hw_idx);
+				hw_intf->hw_idx,
+				(is_ipp) ? "IPP" : "PPP");
 
 			if (in_port->usage_type && acquired_cnt == 1 &&
-				path_res_id == CAM_TFE_CSID_PATH_RES_IPP)
+				((path_res_id == CAM_TFE_CSID_PATH_RES_IPP) ||
+				(path_res_id == CAM_TFE_CSID_PATH_RES_PPP)))
 				/*
 				 * Continue to acquire Right for IPP.
 				 * Dual TFE for RDI is not currently
@@ -1284,8 +1320,9 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(
 
 		if (i == CAM_TFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
 			CAM_ERR(CAM_ISP,
-				"Can not acquire left tfe csid path resource %d",
-				path_res_id);
+				"Can not acquire left tfe csid path resource %d (%s)",
+				path_res_id,
+				(is_ipp) ? "IPP" : "PPP");
 			goto put_res;
 		}
 	} else {
@@ -1308,14 +1345,16 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(
 
 		if (i == -1 || !csid_acquire.node_res) {
 			CAM_ERR(CAM_ISP,
-				"Can not acquire tfe csid path resource %d",
-				path_res_id);
+				"Can not acquire tfe csid path resource %d(%s)",
+				path_res_id,
+				(is_ipp) ? "IPP" : "PPP");
 			goto put_res;
 		}
 	}
 acquire_successful:
-	CAM_DBG(CAM_ISP, "CSID path left acquired success. is_dual %d",
-		in_port->usage_type);
+	CAM_DBG(CAM_ISP, "CSID path left acquired success. is_dual %d res %s",
+		in_port->usage_type,
+		(is_ipp) ? "IPP" : "PPP");
 
 	csid_res_temp->res_type = CAM_ISP_RESOURCE_PIX_PATH;
 	csid_res_temp->res_id = path_res_id;
@@ -1337,7 +1376,8 @@ acquire_successful:
 	 * Acquire Right if not already acquired.
 	 * Dual TFE for RDI is not currently supported.
 	 */
-	if (in_port->usage_type && (path_res_id == CAM_TFE_CSID_PATH_RES_IPP)
+	if (in_port->usage_type && ((path_res_id == CAM_TFE_CSID_PATH_RES_IPP)
+		|| (path_res_id == CAM_TFE_CSID_PATH_RES_PPP))
 		&& (acquired_cnt == 1)) {
 		memset(&csid_acquire, 0, sizeof(csid_acquire));
 		csid_acquire.node_res = NULL;
@@ -1349,6 +1389,7 @@ acquire_successful:
 		csid_acquire.sync_mode = CAM_ISP_HW_SYNC_SLAVE;
 		csid_acquire.node_res = NULL;
 		csid_acquire.out_port = in_port->data;
+		csid_acquire.crop_enable = crop_enable;
 		csid_acquire.event_cb_prv = tfe_ctx;
 		csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler;
 
@@ -1370,14 +1411,16 @@ acquire_successful:
 
 		if (j == CAM_TFE_CSID_HW_NUM_MAX) {
 			CAM_ERR(CAM_ISP,
-				"Can not acquire tfe csid pixel resource");
+				"Can not acquire tfe csid pixel resource %s",
+				(is_ipp) ? "IPP" : "PPP");
 			goto end;
 		}
 		csid_res_temp->hw_res[1] = csid_acquire.node_res;
 		tfe_ctx->slave_hw_idx =
 			csid_res_temp->hw_res[1]->hw_intf->hw_idx;
-		CAM_DBG(CAM_ISP, "CSID right acquired success is_dual %d",
-			in_port->usage_type);
+		CAM_DBG(CAM_ISP, "CSID right acquired success is_dual %d res %s",
+			in_port->usage_type,
+			(is_ipp) ? "IPP" : "PPP");
 	}
 
 	return 0;
@@ -1427,7 +1470,7 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi(
 	struct cam_isp_hw_mgr_res                   *csid_res;
 	struct cam_hw_intf                          *hw_intf;
 	struct cam_isp_tfe_out_port_generic_info    *out_port;
-	struct cam_tfe_csid_hw_reserve_resource_args csid_acquire;
+	struct cam_tfe_csid_hw_reserve_resource_args csid_acquire = {0};
 	struct cam_isp_hw_mgr_res                   *csid_res_iterator;
 	enum cam_tfe_csid_path_res_id                path_res_id;
 
@@ -1606,10 +1649,13 @@ static int cam_tfe_hw_mgr_preprocess_port(
 	struct cam_isp_tfe_in_port_generic_info *in_port,
 	int                             *ipp_count,
 	int                             *rdi_count,
-	int                             *pdaf_enable)
+	int                             *ppp_count,
+	int                             *pdaf_enable,
+	bool                            *lcr_enable)
 {
 	int ipp_num        = 0;
 	int rdi_num        = 0;
+	int pd_num         = 0;
 	bool rdi2_enable   = false;
 	uint32_t i;
 	struct cam_isp_tfe_out_port_generic_info *out_port;
@@ -1633,6 +1679,12 @@ static int cam_tfe_hw_mgr_preprocess_port(
 			rdi_num++;
 			if (out_port->res_id == CAM_ISP_TFE_OUT_RES_RDI_2)
 				rdi2_enable = true;
+		} else if (cam_tfe_hw_mgr_check_path_port_compat(CAM_ISP_HW_TFE_IN_PDLIB,
+					out_port->res_id)) {
+			pd_num++;
+
+			if (out_port->res_id == CAM_ISP_TFE_OUT_RES_PD_LCR_STATS)
+				*lcr_enable = true;
 		} else {
 			ipp_num++;
 			if (out_port->res_id == CAM_ISP_TFE_OUT_RES_PDAF)
@@ -1648,9 +1700,10 @@ static int cam_tfe_hw_mgr_preprocess_port(
 
 	*ipp_count = ipp_num;
 	*rdi_count = rdi_num;
+	*ppp_count = pd_num;
 
-	CAM_DBG(CAM_ISP, "rdi: %d ipp: %d pdaf:%d", rdi_num, ipp_num,
-		*pdaf_enable);
+	CAM_DBG(CAM_ISP, "rdi: %d ipp: %d ppp: %d pdaf:%d", rdi_num, ipp_num,
+		*ppp_count, *pdaf_enable);
 
 	return 0;
 }
@@ -1659,28 +1712,51 @@ static int cam_tfe_mgr_acquire_hw_for_ctx(
 	struct cam_tfe_hw_mgr_ctx               *tfe_ctx,
 	struct cam_isp_tfe_in_port_generic_info *in_port,
 	uint32_t *num_pix_port, uint32_t  *num_rdi_port,
-	uint32_t *pdaf_enable)
+	uint32_t  *num_pd_port, uint32_t *pdaf_enable)
 {
 	int rc                                    = -EINVAL;
 	int is_dual_isp                           = 0;
 	int ipp_count                             = 0;
 	int rdi_count                             = 0;
+	int ppp_count                             = 0;
+	bool lcr_enable                           = false;
+	bool crop_enable                          = true;
 
 	is_dual_isp = in_port->usage_type;
 
 	cam_tfe_hw_mgr_preprocess_port(tfe_ctx, in_port, &ipp_count,
-		&rdi_count, pdaf_enable);
+		&rdi_count, &ppp_count, pdaf_enable, &lcr_enable);
 
-	if (!ipp_count && !rdi_count) {
+	if (!ipp_count && !rdi_count && !ppp_count) {
 		CAM_ERR(CAM_ISP,
 			"No PIX or RDI");
 		return -EINVAL;
 	}
 
-	if (ipp_count) {
+	if (ipp_count || lcr_enable) {
 		/* get tfe csid IPP resource */
 		rc = cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(tfe_ctx,
-			in_port);
+			in_port, true, crop_enable);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"Acquire TFE CSID IPP resource Failed dual:%d",
+				in_port->usage_type);
+			goto err;
+		}
+	}
+
+	if (ppp_count) {
+		/* get ife csid PPP resource */
+		/* If both IPP and PPP paths are requested with the same vc dt
+		 * it is implied that the sensor is a type 3 PD sensor. Crop
+		 * must be enabled for this sensor on PPP path as well.
+		 */
+		if (!ipp_count)
+			crop_enable = false;
+
+		/* get tfe csid IPP resource */
+		rc = cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(tfe_ctx,
+				in_port, false, crop_enable);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Acquire TFE CSID IPP resource Failed dual:%d",
@@ -1700,7 +1776,7 @@ static int cam_tfe_mgr_acquire_hw_for_ctx(
 		}
 	}
 
-	rc = cam_tfe_hw_mgr_acquire_res_tfe_in(tfe_ctx, in_port, pdaf_enable);
+	rc = cam_tfe_hw_mgr_acquire_res_tfe_in(tfe_ctx, in_port, pdaf_enable, lcr_enable);
 	if (rc) {
 		CAM_ERR(CAM_ISP,
 		"Acquire TFE IN resource Failed dual:%d", in_port->usage_type);
@@ -1717,6 +1793,7 @@ static int cam_tfe_mgr_acquire_hw_for_ctx(
 
 	*num_pix_port += ipp_count;
 	*num_rdi_port += rdi_count;
+	*num_pd_port  += ppp_count;
 
 	return 0;
 err:
@@ -2094,11 +2171,13 @@ static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	struct cam_cdm_acquire_data         cdm_acquire;
 	uint32_t                            num_pix_port_per_in = 0;
 	uint32_t                            num_rdi_port_per_in = 0;
+	uint32_t                            num_pd_port_per_in = 0;
 	uint32_t                            pdaf_enable = 0;
 	uint32_t                            total_pix_port = 0;
 	uint32_t                            total_rdi_port = 0;
 	struct cam_isp_tfe_acquire_hw_info *acquire_hw_info = NULL;
 	uint32_t                            input_size = 0;
+	bool                                lcr_enable = false;
 
 	CAM_DBG(CAM_ISP, "Enter...");
 
@@ -2186,7 +2265,7 @@ static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 
 	for (i = 0; i < acquire_hw_info->num_inputs; i++) {
 		cam_tfe_hw_mgr_preprocess_port(tfe_ctx, &in_port[i], &num_pix_port_per_in,
-			&num_rdi_port_per_in, &pdaf_enable);
+			&num_rdi_port_per_in, &num_pd_port_per_in, &pdaf_enable, &lcr_enable);
 		total_pix_port += num_pix_port_per_in;
 		total_rdi_port += num_rdi_port_per_in;
 	}
@@ -2214,7 +2293,7 @@ static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 
 		CAM_DBG(CAM_ISP, "in_res_id %x", in_port[i].res_id);
 		rc = cam_tfe_mgr_acquire_hw_for_ctx(tfe_ctx, &in_port[i],
-			&num_pix_port_per_in, &num_rdi_port_per_in,
+			&num_pix_port_per_in, &num_rdi_port_per_in, &num_pd_port_per_in,
 			&pdaf_enable);
 
 		if (rc) {
@@ -2359,6 +2438,7 @@ static int cam_tfe_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
 	struct cam_cdm_acquire_data        cdm_acquire;
 	uint32_t                           num_pix_port_per_in = 0;
 	uint32_t                           num_rdi_port_per_in = 0;
+	uint32_t                           num_pd_port_per_in = 0;
 	uint32_t                           pdad_enable         = 0;
 	uint32_t                           total_pix_port = 0;
 	uint32_t                           total_rdi_port = 0;
@@ -2478,7 +2558,7 @@ static int cam_tfe_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
 
 			rc = cam_tfe_mgr_acquire_hw_for_ctx(tfe_ctx,
 				&gen_in_port[i],
-				&num_pix_port_per_in, &num_rdi_port_per_in,
+				&num_pix_port_per_in, &num_rdi_port_per_in, &num_pd_port_per_in,
 				&pdad_enable);
 			total_pix_port += num_pix_port_per_in;
 			total_rdi_port += num_rdi_port_per_in;
@@ -2593,7 +2673,8 @@ static int cam_tfe_classify_vote_info(
 {
 	int                                   rc = 0, i, j = 0;
 
-	if (hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) {
+	if ((hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) ||
+		(hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_PDLIB)) {
 		if (split_idx == CAM_ISP_HW_SPLIT_LEFT) {
 			if (*camif_l_bw_updated)
 				return rc;
@@ -3648,6 +3729,7 @@ static int cam_tfe_mgr_dump(void *hw_mgr_priv, void *args)
 				break;
 
 			case CAM_TFE_CSID_PATH_RES_IPP:
+			case CAM_TFE_CSID_PATH_RES_PPP:
 				if (hw_intf->hw_ops.process_cmd) {
 					rc = hw_intf->hw_ops.process_cmd(
 						hw_intf->hw_priv,
@@ -3686,6 +3768,7 @@ static int cam_tfe_mgr_dump(void *hw_mgr_priv, void *args)
 				break;
 
 			case CAM_ISP_HW_TFE_IN_CAMIF:
+			case CAM_ISP_HW_TFE_IN_PDLIB:
 				if (hw_intf->hw_ops.process_cmd) {
 					rc = hw_intf->hw_ops.process_cmd(
 						hw_intf->hw_priv,
@@ -3995,7 +4078,8 @@ static int cam_isp_tfe_blob_clock_update(
 			if (!hw_mgr_res->hw_res[i])
 				continue;
 
-			if (hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) {
+			if ((hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) ||
+				(hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_PDLIB)) {
 				if (i == CAM_ISP_HW_SPLIT_LEFT) {
 					if (camif_l_clk_updated)
 						continue;
@@ -5934,6 +6018,8 @@ static int cam_tfe_hw_mgr_handle_hw_rup(
 			CAM_ISP_HW_EVENT_REG_UPDATE, (void *)&rup_event_data);
 		break;
 
+	case CAM_ISP_HW_TFE_IN_PDLIB:
+		break;
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d",
 			event_info->res_id);
@@ -5969,6 +6055,7 @@ static int cam_tfe_hw_mgr_handle_hw_epoch(
 	case CAM_ISP_HW_TFE_IN_RDI0:
 	case CAM_ISP_HW_TFE_IN_RDI1:
 	case CAM_ISP_HW_TFE_IN_RDI2:
+	case CAM_ISP_HW_TFE_IN_PDLIB:
 		break;
 
 	default:
@@ -6021,6 +6108,8 @@ static int cam_tfe_hw_mgr_handle_hw_sof(
 			CAM_ISP_HW_EVENT_SOF, (void *)&sof_done_event_data);
 		break;
 
+	case CAM_ISP_HW_TFE_IN_PDLIB:
+		break;
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d",
 			event_info->res_id);
@@ -6063,6 +6152,9 @@ static int cam_tfe_hw_mgr_handle_hw_eof(
 			CAM_ISP_HW_EVENT_EOF, (void *)&eof_done_event_data);
 		break;
 
+	case CAM_ISP_HW_TFE_IN_PDLIB:
+		break;
+
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d",
 			event_info->res_id);
@@ -6305,11 +6397,13 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 	struct cam_iommu_handle cdm_handles;
 	struct cam_tfe_hw_mgr_ctx *ctx_pool;
 	struct cam_isp_hw_mgr_res *res_list_tfe_out;
+	struct cam_isp_hw_path_port_map path_port_map;
 	bool support_consumed_addr = false;
 
 	CAM_DBG(CAM_ISP, "Enter");
 
 	memset(&g_tfe_hw_mgr, 0, sizeof(g_tfe_hw_mgr));
+	memset(&path_port_map, 0, sizeof(path_port_map));
 
 	mutex_init(&g_tfe_hw_mgr.ctx_mutex);
 	spin_lock_init(&g_tfe_hw_mgr.ctx_lock);
@@ -6329,13 +6423,22 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 				g_tfe_hw_mgr.tfe_devices[i]->hw_intf->hw_priv;
 			struct cam_hw_soc_info *soc_info = &tfe_hw->soc_info;
 
-			if (j == 0)
+			if (j == 0) {
 				tfe_device->hw_ops.process_cmd(
 					tfe_hw,
 					CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT,
 					&support_consumed_addr,
 					sizeof(support_consumed_addr));
 
+				tfe_device->hw_ops.process_cmd(
+					tfe_hw,
+					CAM_ISP_HW_CMD_GET_PATH_PORT_MAP,
+					&path_port_map,
+					sizeof(struct cam_isp_hw_path_port_map));
+				CAM_DBG(CAM_ISP, "received %d path-port mappings",
+					path_port_map.num_entries);
+			}
+
 			j++;
 
 			g_tfe_hw_mgr.cdm_reg_map[i] = &soc_info->reg_map[0];
@@ -6353,6 +6456,13 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 	}
 
 	g_tfe_hw_mgr.support_consumed_addr = support_consumed_addr;
+
+	for (i = 0; i < path_port_map.num_entries; i++) {
+		g_tfe_hw_mgr.path_port_map.entry[i][0] = path_port_map.entry[i][0];
+		g_tfe_hw_mgr.path_port_map.entry[i][1] = path_port_map.entry[i][1];
+	}
+	g_tfe_hw_mgr.path_port_map.num_entries = path_port_map.num_entries;
+
 	/* fill csid hw intf information */
 	for (i = 0, j = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) {
 		rc = cam_tfe_csid_hw_init(&g_tfe_hw_mgr.csid_devices[i], i);

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

@@ -190,6 +190,7 @@ struct cam_tfe_hw_mgr_ctx {
  * @tfe_dev_caps           tfe device capability per core
  * @work q                 work queue for TFE hw manager
  * @debug_cfg              debug configuration
+ * @path_port_map          Mapping of outport to TFE mux
  * @support_consumed_addr  indicate whether hw supports last consumed address
  * @ctx_lock               Spinlock for HW manager
  */
@@ -209,6 +210,7 @@ struct cam_tfe_hw_mgr {
 	struct cam_tfe_hw_get_hw_cap   tfe_dev_caps[CAM_TFE_HW_NUM_MAX];
 	struct cam_req_mgr_core_workq *workq;
 	struct cam_tfe_hw_mgr_debug    debug_cfg;
+	struct cam_isp_hw_path_port_map  path_port_map;
 	bool                           support_consumed_addr;
 	spinlock_t                     ctx_lock;
 };

+ 6 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h

@@ -23,6 +23,7 @@ enum cam_tfe_csid_path_res_id {
 	CAM_TFE_CSID_PATH_RES_RDI_1,
 	CAM_TFE_CSID_PATH_RES_RDI_2,
 	CAM_TFE_CSID_PATH_RES_IPP,
+	CAM_TFE_CSID_PATH_RES_PPP,
 	CAM_TFE_CSID_PATH_RES_MAX,
 };
 
@@ -36,6 +37,7 @@ enum cam_tfe_csid_irq_reg {
 	TFE_CSID_IRQ_REG_TOP,
 	TFE_CSID_IRQ_REG_RX,
 	TFE_CSID_IRQ_REG_IPP,
+	TFE_CSID_IRQ_REG_PPP,
 	TFE_CSID_IRQ_REG_MAX,
 };
 
@@ -96,6 +98,7 @@ struct cam_isp_tfe_in_port_generic_info {
  * struct cam_tfe_csid_hw_caps- get the CSID hw capability
  * @num_rdis:       number of rdis supported by CSID HW device
  * @num_pix:        number of pxl paths supported by CSID HW device
+ * @num_ppp:        number of ppp paths supported by CSID HW device
  * @major_version : major version
  * @minor_version:  minor version
  * @version_incr:   version increment
@@ -106,6 +109,7 @@ struct cam_isp_tfe_in_port_generic_info {
 struct cam_tfe_csid_hw_caps {
 	uint32_t      num_rdis;
 	uint32_t      num_pix;
+	uint32_t      num_ppp;
 	uint32_t      major_version;
 	uint32_t      minor_version;
 	uint32_t      version_incr;
@@ -128,6 +132,7 @@ struct cam_tfe_csid_hw_caps {
  * @event_cb_prv: Context data
  * @event_cb:     Callback function to hw mgr in case of hw events
  * @node_res :    Reserved resource structure pointer
+ * @crop_enable : Flag to indicate CSID crop enable
  *
  */
 struct cam_tfe_csid_hw_reserve_resource_args {
@@ -141,6 +146,7 @@ struct cam_tfe_csid_hw_reserve_resource_args {
 	void                                     *event_cb_prv;
 	cam_hw_mgr_event_cb_func                  event_cb;
 	struct cam_isp_resource_node             *node_res;
+	bool                                      crop_enable;
 };
 
 /**

+ 3 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_hw_intf.h

@@ -19,6 +19,7 @@ enum cam_isp_hw_tfe_in {
 	CAM_ISP_HW_TFE_IN_RDI0        = 1,
 	CAM_ISP_HW_TFE_IN_RDI1        = 2,
 	CAM_ISP_HW_TFE_IN_RDI2        = 3,
+	CAM_ISP_HW_TFE_IN_PDLIB       = 4,
 	CAM_ISP_HW_TFE_IN_MAX,
 };
 
@@ -120,6 +121,7 @@ struct cam_tfe_hw_tfe_out_acquire_args {
  * @in_port:                 Input port details to acquire
  * @camif_pd_enable          Camif pd enable or disable
  * @dual_tfe_sync_sel_idx    Dual tfe master hardware index
+ * @lcr_enable               LCR enable field
  */
 struct cam_tfe_hw_tfe_in_acquire_args {
 	struct cam_isp_resource_node            *rsrc_node;
@@ -129,6 +131,7 @@ struct cam_tfe_hw_tfe_in_acquire_args {
 	enum cam_isp_hw_sync_mode                sync_mode;
 	bool                                     camif_pd_enable;
 	uint32_t                                 dual_tfe_sync_sel_idx;
+	bool                                     lcr_enable;
 };
 
 /*

+ 479 - 24
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c

@@ -47,7 +47,7 @@
 /* Max CSI Rx irq error count threshold value */
 #define CAM_TFE_CSID_MAX_IRQ_ERROR_COUNT               5
 
-static int cam_tfe_csid_is_ipp_format_supported(
+static int cam_tfe_csid_is_ipp_ppp_format_supported(
 	uint32_t in_format)
 {
 	int rc = -EINVAL;
@@ -170,7 +170,7 @@ static int cam_tfe_csid_get_format_rdi(
 	return rc;
 }
 
-static int cam_tfe_csid_get_format_ipp(
+static int cam_tfe_csid_get_format_ipp_ppp(
 	uint32_t in_format,
 	uint32_t *decode_fmt, uint32_t *plain_fmt)
 {
@@ -341,6 +341,17 @@ static bool cam_tfe_csid_check_path_active(struct cam_tfe_csid_hw   *csid_hw)
 			goto end;
 	}
 
+	/* check the PPP path status */
+	if (csid_reg->cmn_reg->num_ppp) {
+		path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_status_addr);
+		CAM_DBG(CAM_ISP, "CSID:%d PPP path status:%d",
+			csid_hw->hw_intf->hw_idx, path_status);
+		/* if status is 0 then it is active */
+		if (!path_status)
+			goto end;
+	}
+
 	/* Check the RDI path status */
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 		path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base +
@@ -461,6 +472,10 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw)
 		cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
 			csid_reg->ipp_reg->csid_pxl_irq_mask_addr);
 
+	if (csid_reg->cmn_reg->num_ppp)
+		cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_irq_mask_addr);
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++)
 		cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
 			csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr);
@@ -478,6 +493,11 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw)
 			soc_info->reg_map[0].mem_base +
 			csid_reg->ipp_reg->csid_pxl_irq_clear_addr);
 
+	if (csid_reg->cmn_reg->num_ppp)
+		cam_io_w_mb(csid_reg->cmn_reg->ppp_irq_mask_all,
+			soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_irq_clear_addr);
+
 	for (i = 0 ; i < csid_reg->cmn_reg->num_rdis; i++)
 		cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all,
 			soc_info->reg_map[0].mem_base +
@@ -541,6 +561,12 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw)
 		path_data->res_sof_cnt = 0;
 	}
 
+	if (csid_reg->cmn_reg->num_ppp) {
+		path_data = (struct cam_tfe_csid_path_cfg *)
+			csid_hw->ppp_res.res_priv;
+		path_data->res_sof_cnt = 0;
+	}
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 		path_data = (struct cam_tfe_csid_path_cfg  *)
 			csid_hw->rdi_res[i].res_priv;
@@ -599,6 +625,24 @@ static int cam_tfe_csid_path_reset(struct cam_tfe_csid_hw *csid_hw,
 		val |= TFE_CSID_PATH_INFO_RST_DONE;
 		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
 			 csid_reg->ipp_reg->csid_pxl_irq_mask_addr);
+	} else if (res->res_id == CAM_TFE_CSID_PATH_RES_PPP) {
+		if (!csid_reg->ppp_reg) {
+			CAM_ERR(CAM_ISP, "CSID:%d PPP not supported :%d",
+				 csid_hw->hw_intf->hw_idx,
+				res->res_id);
+			return -EINVAL;
+		}
+
+		reset_strb_addr = csid_reg->ppp_reg->csid_pxl_rst_strobes_addr;
+		complete = &csid_hw->csid_ppp_complete;
+		reset_strb_val = csid_reg->cmn_reg->ppp_path_rst_stb_all;
+
+		/* Enable path reset done interrupt */
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_irq_mask_addr);
+		val |= TFE_CSID_PATH_INFO_RST_DONE;
+		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			 csid_reg->ppp_reg->csid_pxl_irq_mask_addr);
 	} else {
 		id = res->res_id;
 		if (!csid_reg->rdi_reg[id]) {
@@ -820,7 +864,7 @@ static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw,
 			goto end;
 		}
 
-		if (cam_tfe_csid_is_ipp_format_supported(
+		if (cam_tfe_csid_is_ipp_ppp_format_supported(
 				reserve->in_port->format)) {
 			CAM_ERR(CAM_ISP,
 				"CSID:%d res id:%d un support format %d",
@@ -841,6 +885,43 @@ static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw,
 
 		break;
 
+	case CAM_TFE_CSID_PATH_RES_PPP:
+		if (csid_hw->ppp_res.res_state !=
+			CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+			CAM_DBG(CAM_ISP,
+				"CSID:%d PPP resource not available %d",
+				csid_hw->hw_intf->hw_idx,
+				csid_hw->ppp_res.res_state);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		if (cam_tfe_csid_is_ipp_ppp_format_supported(
+				reserve->in_port->format)) {
+			CAM_ERR(CAM_ISP,
+				"CSID:%d res id:%d un support format %d",
+				csid_hw->hw_intf->hw_idx, reserve->res_id,
+				reserve->in_port->format);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		rc = cam_tfe_csid_cid_reserve(csid_hw, reserve, &cid_value);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"CSID:%d res id:%d invalid cid %d",
+			       csid_hw->hw_intf->hw_idx, reserve->res_id, cid_value);
+			goto end;
+		}
+
+		/* assign the PPP resource */
+		res = &csid_hw->ppp_res;
+		CAM_DBG(CAM_ISP,
+			"CSID:%d PPP resource:%d acquired successfully",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+
+		break;
+
 	case CAM_TFE_CSID_PATH_RES_RDI_0:
 	case CAM_TFE_CSID_PATH_RES_RDI_1:
 	case CAM_TFE_CSID_PATH_RES_RDI_2:
@@ -899,6 +980,7 @@ static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw,
 
 	path_data->bayer_bin = reserve->in_port->bayer_bin;
 	path_data->qcfa_bin = reserve->in_port->qcfa_bin;
+	path_data->crop_enable = reserve->crop_enable;
 
 	csid_hw->event_cb = reserve->event_cb;
 	csid_hw->event_cb_priv = reserve->event_cb_prv;
@@ -912,10 +994,6 @@ static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw,
 		}
 	}
 
-	/* Enable crop only for ipp */
-	if (reserve->res_id == CAM_TFE_CSID_PATH_RES_IPP)
-		path_data->crop_enable = true;
-
 	CAM_DBG(CAM_ISP,
 		"Res id: %d height:%d line_start %d line_end %d crop_en %d",
 		reserve->res_id, reserve->in_port->height,
@@ -1177,6 +1255,11 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw  *csid_hw)
 			soc_info->reg_map[0].mem_base +
 			csid_reg->ipp_reg->csid_pxl_irq_clear_addr);
 
+	if (csid_reg->cmn_reg->num_ppp)
+		cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all,
+			soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_irq_clear_addr);
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++)
 		cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all,
 			soc_info->reg_map[0].mem_base +
@@ -1207,6 +1290,12 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw  *csid_hw)
 		path_data->res_sof_cnt = 0;
 	}
 
+	if (csid_reg->cmn_reg->num_ppp) {
+		path_data = (struct cam_tfe_csid_path_cfg  *)
+			csid_hw->ppp_res.res_priv;
+		path_data->res_sof_cnt = 0;
+	}
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 		path_data = (struct cam_tfe_csid_path_cfg *)
 			csid_hw->rdi_res[i].res_priv;
@@ -1294,15 +1383,22 @@ static int cam_tfe_csid_init_config_pxl_path(
 	csid_reg = csid_hw->csid_info->csid_reg;
 	soc_info = &csid_hw->hw_info->soc_info;
 
-	pxl_reg = csid_reg->ipp_reg;
+	if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
+		pxl_reg = csid_reg->ipp_reg;
+	else
+		pxl_reg = csid_reg->ppp_reg;
+
 	if (!pxl_reg) {
-		CAM_ERR(CAM_ISP, "CSID:%d IPP :%d is not supported on HW",
-			csid_hw->hw_intf->hw_idx, res->res_id);
+		CAM_ERR(CAM_ISP, "CSID:%d %s :%d is not supported on HW",
+			csid_hw->hw_intf->hw_idx,
+			(res->res_id == CAM_TFE_CSID_PATH_RES_IPP) ? "IPP" : "PPP",
+			res->res_id);
 		return -EINVAL;
 	}
 
-	CAM_DBG(CAM_ISP, "Config IPP Path");
-	rc = cam_tfe_csid_get_format_ipp(path_data->in_format,
+	CAM_DBG(CAM_ISP, "Config %s Path",
+			(res->res_id == CAM_TFE_CSID_PATH_RES_IPP) ? "IPP" : "PPP");
+	rc = cam_tfe_csid_get_format_ipp_ppp(path_data->in_format,
 		&decode_format, &plain_format);
 	if (rc)
 		return rc;
@@ -1481,18 +1577,25 @@ static int cam_tfe_csid_deinit_pxl_path(
 	csid_reg = csid_hw->csid_info->csid_reg;
 	soc_info = &csid_hw->hw_info->soc_info;
 
-	pxl_reg = csid_reg->ipp_reg;
+	if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
+		pxl_reg = csid_reg->ipp_reg;
+	else
+		pxl_reg = csid_reg->ppp_reg;
+
 	if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) {
 		CAM_ERR(CAM_ISP,
-			"CSID:%d IPP Res type %d res_id:%d in wrong state %d",
+			"CSID:%d %s Res type %d res_id:%d in wrong state %d",
 			csid_hw->hw_intf->hw_idx,
+			(res->res_id == CAM_TFE_CSID_PATH_RES_IPP) ? "IPP" : "PPP",
 			res->res_type, res->res_id, res->res_state);
 		rc = -EINVAL;
 	}
 
 	if (!pxl_reg) {
-		CAM_ERR(CAM_ISP, "CSID:%d IPP %d is not supported on HW",
-			csid_hw->hw_intf->hw_idx, res->res_id);
+		CAM_ERR(CAM_ISP, "CSID:%d %s %d is not supported on HW",
+			csid_hw->hw_intf->hw_idx,
+			(res->res_id == CAM_TFE_CSID_PATH_RES_IPP) ? "IPP" : "PPP",
+			res->res_id);
 		rc = -EINVAL;
 		goto end;
 	}
@@ -1666,6 +1769,7 @@ static int cam_tfe_csid_disable_pxl_path(
 	}
 
 	pxl_reg = csid_reg->ipp_reg;
+
 	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
 		CAM_DBG(CAM_ISP, "CSID:%d IPP path Res:%d Invalid state%d",
 			csid_hw->hw_intf->hw_idx, res->res_id, res->res_state);
@@ -1718,6 +1822,164 @@ static int cam_tfe_csid_disable_pxl_path(
 	return rc;
 }
 
+static int cam_tfe_csid_enable_ppp_path(
+	struct cam_tfe_csid_hw          *csid_hw,
+	struct cam_isp_resource_node    *res)
+{
+	const struct cam_tfe_csid_reg_offset     *csid_reg;
+	struct cam_hw_soc_info                   *soc_info;
+	struct cam_tfe_csid_path_cfg             *path_data;
+	const struct cam_tfe_csid_pxl_reg_offset *ppp_reg = NULL;
+	uint32_t                                  val = 0;
+
+	path_data = (struct cam_tfe_csid_path_cfg   *) res->res_priv;
+	csid_reg = csid_hw->csid_info->csid_reg;
+	soc_info = &csid_hw->hw_info->soc_info;
+	ppp_reg = csid_reg->ppp_reg;
+
+	if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) {
+		CAM_ERR(CAM_ISP,
+			"CSID:%d PPP path res type:%d res_id:%d Invalid state%d",
+			csid_hw->hw_intf->hw_idx,
+			res->res_type, res->res_id, res->res_state);
+		return -EINVAL;
+	}
+
+	if (!ppp_reg) {
+		CAM_ERR(CAM_ISP, "CSID:%d PPP resid: %d not supported on HW",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_ISP, "CSID:%d Enable PPP path", csid_hw->hw_intf->hw_idx);
+
+	/* Set master or slave path */
+	if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER)
+		/* Set halt mode as master */
+		val = (TFE_CSID_HALT_MODE_SLAVE  << ppp_reg->halt_mode_shift) |
+			(ppp_reg->halt_master_sel_master_val <<
+			ppp_reg->halt_master_sel_shift);
+	else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE)
+		/* Set halt mode as slave and set master idx */
+		val = (TFE_CSID_HALT_MODE_SLAVE  << ppp_reg->halt_mode_shift) |
+			(ppp_reg->halt_master_sel_slave_val <<
+			ppp_reg->halt_master_sel_shift);
+	else
+		/* Default is internal halt mode */
+		val = 0;
+
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base + ppp_reg->csid_pxl_ctrl_addr);
+
+	CAM_DBG(CAM_ISP, "CSID:%d PPP Ctrl val: 0x%x", csid_hw->hw_intf->hw_idx, val);
+
+	/* Enable the required ppp path interrupts */
+	val = TFE_CSID_PATH_INFO_RST_DONE | TFE_CSID_PATH_ERROR_FIFO_OVERFLOW |
+		TFE_CSID_PATH_PPP_ERROR_CCIF_VIOLATION | TFE_CSID_PATH_PPP_OVERFLOW_IRQ;
+
+	if (csid_reg->cmn_reg->format_measure_support)
+		val |= TFE_CSID_PATH_ERROR_PIX_COUNT | TFE_CSID_PATH_ERROR_LINE_COUNT;
+
+	if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)
+		val |= TFE_CSID_PATH_INFO_INPUT_SOF;
+	if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ)
+		val |= TFE_CSID_PATH_INFO_INPUT_EOF;
+
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base + ppp_reg->csid_pxl_irq_mask_addr);
+
+	CAM_DBG(CAM_ISP, "CSID:%d Enable PPP IRQ mask 0x%x", csid_hw->hw_intf->hw_idx, val);
+
+	res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
+	return 0;
+}
+
+static int cam_tfe_csid_disable_ppp_path(
+	struct cam_tfe_csid_hw          *csid_hw,
+	struct cam_isp_resource_node    *res,
+	enum cam_tfe_csid_halt_cmd       stop_cmd)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	const struct cam_tfe_csid_reg_offset       *csid_reg;
+	struct cam_hw_soc_info                     *soc_info;
+	struct cam_tfe_csid_path_cfg               *path_data;
+	const struct cam_tfe_csid_pxl_reg_offset   *ppp_reg;
+
+	path_data = (struct cam_tfe_csid_path_cfg   *) res->res_priv;
+	csid_reg = csid_hw->csid_info->csid_reg;
+	soc_info = &csid_hw->hw_info->soc_info;
+
+	if (res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) {
+		CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+		return -EINVAL;
+	}
+
+	if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
+		res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
+		CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
+			csid_hw->hw_intf->hw_idx, res->res_id, res->res_state);
+		return rc;
+	}
+
+	ppp_reg = csid_reg->ppp_reg;
+	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
+		CAM_DBG(CAM_ISP, "CSID:%d IPP path Res:%d Invalid state%d",
+			csid_hw->hw_intf->hw_idx, res->res_id, res->res_state);
+		return -EINVAL;
+	}
+
+	if (!ppp_reg) {
+		CAM_ERR(CAM_ISP, "CSID:%d PPP %d is not supported on HW",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+		return -EINVAL;
+	}
+
+	if (stop_cmd != CAM_TFE_CSID_HALT_AT_FRAME_BOUNDARY &&
+		stop_cmd != CAM_TFE_CSID_HALT_IMMEDIATELY) {
+		CAM_ERR(CAM_ISP,
+			"CSID:%d PPP path un supported stop command:%d",
+			csid_hw->hw_intf->hw_idx, stop_cmd);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_ISP, "CSID:%d res_id:%d PPP path",
+		csid_hw->hw_intf->hw_idx, res->res_id);
+
+	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+		ppp_reg->csid_pxl_irq_mask_addr);
+
+	if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
+		path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) {
+		/* configure Halt */
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		ppp_reg->csid_pxl_ctrl_addr);
+		val &= ~0x3F;
+		val |= (TFE_CSID_HALT_MODE_SLAVE << ppp_reg->halt_mode_shift);
+		val |= (ppp_reg->halt_master_sel_master_val <<
+			ppp_reg->halt_master_sel_shift);
+		val |= stop_cmd;
+		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			ppp_reg->csid_pxl_ctrl_addr);
+	}
+
+	if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE &&
+		stop_cmd == CAM_TFE_CSID_HALT_IMMEDIATELY) {
+		/* configure Halt for slave */
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			ppp_reg->csid_pxl_ctrl_addr);
+		val &= ~0x3F;
+		val |= (TFE_CSID_HALT_MODE_SLAVE << ppp_reg->halt_mode_shift);
+		val |= (ppp_reg->halt_master_sel_slave_val <<
+			ppp_reg->halt_master_sel_shift);
+		val |= stop_cmd;
+		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			ppp_reg->csid_pxl_ctrl_addr);
+	}
+
+	return rc;
+}
+
 static int cam_tfe_csid_init_config_rdi_path(
 	struct cam_tfe_csid_hw          *csid_hw,
 	struct cam_isp_resource_node    *res)
@@ -2032,6 +2294,14 @@ static int cam_tfe_csid_poll_stop_status(
 				CAM_ISP_RESOURCE_STATE_STREAMING)
 				continue;
 
+		} else if (res_id == CAM_TFE_CSID_PATH_RES_PPP) {
+			csid_status_addr =
+			csid_reg->ppp_reg->csid_pxl_status_addr;
+
+			if (csid_hw->ppp_res.res_state !=
+				CAM_ISP_RESOURCE_STATE_STREAMING)
+				continue;
+
 		} else {
 			csid_status_addr =
 				csid_reg->rdi_reg[res_id]->csid_rdi_status_addr;
@@ -2129,6 +2399,19 @@ static int cam_tfe_csid_get_time_stamp(
 				csid_reg->ipp_reg->csid_pxl_timestamp_perv0_sof_addr,
 				&time_stamp->prev_time_stamp_val);
 		}
+	} else if (res->res_id == CAM_TFE_CSID_PATH_RES_PPP) {
+		torn = __cam_tfe_csid_read_timestamp(
+			soc_info->reg_map[0].mem_base,
+			csid_reg->ppp_reg->csid_pxl_timestamp_curr1_sof_addr,
+			csid_reg->ppp_reg->csid_pxl_timestamp_curr0_sof_addr,
+			&time_stamp->time_stamp_val);
+		if (time_stamp->get_prev_timestamp) {
+			prev_torn = __cam_tfe_csid_read_timestamp(
+				soc_info->reg_map[0].mem_base,
+				csid_reg->ppp_reg->csid_pxl_timestamp_perv1_sof_addr,
+				csid_reg->ppp_reg->csid_pxl_timestamp_perv0_sof_addr,
+				&time_stamp->prev_time_stamp_val);
+		}
 	} else {
 		id = res->res_id;
 		rdi_reg = csid_reg->rdi_reg[id];
@@ -2229,6 +2512,11 @@ static int cam_tfe_csid_print_hbi_vbi(
 			csid_reg->ipp_reg->csid_pxl_format_measure1_addr);
 		vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base +
 			csid_reg->ipp_reg->csid_pxl_format_measure2_addr);
+	} else if (res->res_id == CAM_TFE_CSID_PATH_RES_PPP) {
+		hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_format_measure1_addr);
+		vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_format_measure2_addr);
 	} else if ((res->res_id >= CAM_TFE_CSID_PATH_RES_RDI_0) &&
 		(res->res_id <= CAM_TFE_CSID_PATH_RES_RDI_2)) {
 		rdi_reg = csid_reg->rdi_reg[res->res_id];
@@ -2286,6 +2574,7 @@ static int cam_tfe_csid_get_hw_caps(void *hw_priv,
 
 	hw_caps->num_rdis = csid_reg->cmn_reg->num_rdis;
 	hw_caps->num_pix = csid_hw->pxl_pipe_enable;
+	hw_caps->num_ppp = csid_reg->cmn_reg->num_ppp;
 	hw_caps->major_version = csid_reg->cmn_reg->major_version;
 	hw_caps->minor_version = csid_reg->cmn_reg->minor_version;
 	hw_caps->version_incr = csid_reg->cmn_reg->version_incr;
@@ -2551,7 +2840,8 @@ static int cam_tfe_csid_init_hw(void *hw_priv,
 	if (rc)
 		goto end;
 
-	if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
+	if ((res->res_id == CAM_TFE_CSID_PATH_RES_IPP) ||
+		(res->res_id == CAM_TFE_CSID_PATH_RES_PPP))
 		rc = cam_tfe_csid_init_config_pxl_path(csid_hw, res);
 	else
 		rc = cam_tfe_csid_init_config_rdi_path(csid_hw, res);
@@ -2607,7 +2897,8 @@ static int cam_tfe_csid_deinit_hw(void *hw_priv,
 
 	CAM_DBG(CAM_ISP, "De-Init IPP Path: %d", res->res_id);
 
-	if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
+	if ((res->res_id == CAM_TFE_CSID_PATH_RES_IPP) ||
+		(res->res_id == CAM_TFE_CSID_PATH_RES_PPP))
 		rc = cam_tfe_csid_deinit_pxl_path(csid_hw, res);
 	else
 		rc = cam_tfe_csid_deinit_rdi_path(csid_hw, res);
@@ -2662,6 +2953,8 @@ static int cam_tfe_csid_start(void *hw_priv, void *start_args,
 	case CAM_ISP_RESOURCE_PIX_PATH:
 		if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
 			rc = cam_tfe_csid_enable_pxl_path(csid_hw, res);
+		else if (res->res_id == CAM_TFE_CSID_PATH_RES_PPP)
+			rc = cam_tfe_csid_enable_ppp_path(csid_hw, res);
 		else
 			rc = cam_tfe_csid_enable_rdi_path(csid_hw, res);
 		break;
@@ -2756,6 +3049,9 @@ static int cam_tfe_csid_stop(void *hw_priv,
 			if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
 				rc = cam_tfe_csid_disable_pxl_path(csid_hw,
 					res, csid_stop->stop_cmd);
+			else if (res->res_id == CAM_TFE_CSID_PATH_RES_PPP)
+				rc = cam_tfe_csid_disable_ppp_path(csid_hw,
+					res, csid_stop->stop_cmd);
 			else
 				rc = cam_tfe_csid_disable_rdi_path(csid_hw,
 					res, csid_stop->stop_cmd);
@@ -2835,6 +3131,22 @@ static int cam_tfe_csid_sof_irq_debug(
 		}
 	}
 
+	if (csid_reg->ppp_reg) {
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_irq_mask_addr);
+
+		if (val) {
+			if (sof_irq_enable)
+				val |= TFE_CSID_PATH_INFO_INPUT_SOF;
+			else
+				val &= ~TFE_CSID_PATH_INFO_INPUT_SOF;
+
+			cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+				csid_reg->ppp_reg->csid_pxl_irq_mask_addr);
+			val = 0;
+		}
+	}
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
 			csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr);
@@ -2984,6 +3296,29 @@ static int cam_tfe_csid_get_regdump(struct cam_tfe_csid_hw *csid_hw,
 			csid_reg->ipp_reg->csid_pxl_vcrop_addr);
 		CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x",
 			csid_reg->ipp_reg->csid_pxl_vcrop_addr, val);
+	} else if (res->res_id == CAM_TFE_CSID_PATH_RES_PPP) {
+		CAM_INFO(CAM_ISP, "Dumping CSID:%d PPP registers ",
+			csid_hw->hw_intf->hw_idx);
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_cfg0_addr);
+		CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x",
+			csid_reg->ppp_reg->csid_pxl_cfg0_addr, val);
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_cfg1_addr);
+		CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x",
+			csid_reg->ppp_reg->csid_pxl_cfg1_addr, val);
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_ctrl_addr);
+		CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x",
+			csid_reg->ppp_reg->csid_pxl_ctrl_addr, val);
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_hcrop_addr);
+		CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x",
+			csid_reg->ppp_reg->csid_pxl_hcrop_addr, val);
+		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_vcrop_addr);
+		CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x",
+			csid_reg->ppp_reg->csid_pxl_vcrop_addr, val);
 	} else {
 		id = res->res_id;
 		CAM_INFO(CAM_ISP, "Dumping CSID:%d RDI:%d registers ",
@@ -3321,6 +3656,13 @@ static int cam_tfe_csid_evt_bottom_half_handler(
 				csid_hw->hw_intf->hw_idx);
 		}
 
+		if (evt_payload->irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_INFO_INPUT_SOF) {
+			CAM_INFO_RATE_LIMIT(CAM_ISP,
+				"CSID:%d PPP SOF received",
+				csid_hw->hw_intf->hw_idx);
+		}
+
 		for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 			if (evt_payload->irq_status[i] &
 				TFE_CSID_PATH_INFO_INPUT_SOF)
@@ -3330,13 +3672,14 @@ static int cam_tfe_csid_evt_bottom_half_handler(
 		}
 	} else {
 		CAM_ERR_RATE_LIMIT(CAM_ISP,
-			"CSID %d err %d phy %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x",
+			"CSID %d err %d phy %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x PPP: 0x%x RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x",
 			csid_hw->hw_intf->hw_idx,
 			evt_payload->evt_type,
 			csid_hw->csi2_rx_cfg.phy_sel,
 			evt_payload->irq_status[TFE_CSID_IRQ_REG_TOP],
 			evt_payload->irq_status[TFE_CSID_IRQ_REG_RX],
 			evt_payload->irq_status[TFE_CSID_IRQ_REG_IPP],
+			evt_payload->irq_status[TFE_CSID_IRQ_REG_PPP],
 			evt_payload->irq_status[TFE_CSID_IRQ_REG_RDI0],
 			evt_payload->irq_status[TFE_CSID_IRQ_REG_RDI1],
 			evt_payload->irq_status[TFE_CSID_IRQ_REG_RDI2]);
@@ -3421,10 +3764,11 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data)
 	struct cam_hw_soc_info                         *soc_info;
 	const struct cam_tfe_csid_reg_offset           *csid_reg;
 	const struct cam_tfe_csid_pxl_reg_offset       *ipp_reg;
+	const struct cam_tfe_csid_pxl_reg_offset       *ppp_reg;
 	const struct cam_tfe_csid_rdi_reg_offset       *rdi_reg;
 	const struct cam_tfe_csid_common_reg_offset    *cmn_reg;
 	const struct cam_tfe_csid_csi2_rx_reg_offset   *csi2_reg;
-	uint32_t                   irq_status[TFE_CSID_IRQ_REG_MAX];
+	uint32_t                   irq_status[TFE_CSID_IRQ_REG_MAX] = {0};
 	bool fatal_err_detected = false, is_error_irq = false;
 	uint32_t sof_irq_debug_en = 0, log_en = 0;
 	unsigned long flags;
@@ -3458,6 +3802,11 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data)
 			cam_io_r_mb(soc_info->reg_map[0].mem_base +
 				csid_reg->ipp_reg->csid_pxl_irq_status_addr);
 
+	if (csid_reg->cmn_reg->num_ppp)
+		irq_status[TFE_CSID_IRQ_REG_PPP] =
+			cam_io_r_mb(soc_info->reg_map[0].mem_base +
+				csid_reg->ppp_reg->csid_pxl_irq_status_addr);
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++)
 		irq_status[i] =
 		cam_io_r_mb(soc_info->reg_map[0].mem_base +
@@ -3477,6 +3826,11 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data)
 			soc_info->reg_map[0].mem_base +
 			csid_reg->ipp_reg->csid_pxl_irq_clear_addr);
 
+	if (csid_reg->cmn_reg->num_ppp)
+		cam_io_w_mb(irq_status[TFE_CSID_IRQ_REG_PPP],
+			soc_info->reg_map[0].mem_base +
+			csid_reg->ppp_reg->csid_pxl_irq_clear_addr);
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 		cam_io_w_mb(irq_status[i],
 			soc_info->reg_map[0].mem_base +
@@ -3700,6 +4054,11 @@ handle_fatal_error:
 			CAM_INFO_RATE_LIMIT(CAM_ISP,
 				"CSID IPP reset complete");
 
+		if (irq_status[TFE_CSID_IRQ_REG_PPP] &
+			BIT(csid_reg->cmn_reg->path_rst_done_shift_val))
+			CAM_INFO_RATE_LIMIT(CAM_ISP,
+				"CSID PPP reset complete");
+
 		if (irq_status[TFE_CSID_IRQ_REG_TOP])
 			CAM_INFO_RATE_LIMIT(CAM_ISP,
 				"CSID TOP reset complete");
@@ -3781,6 +4140,77 @@ handle_fatal_error:
 
 	}
 
+	/* read the PPP errors */
+	if (csid_reg->cmn_reg->num_ppp) {
+		/* PPP reset done bit */
+		if (irq_status[TFE_CSID_IRQ_REG_PPP] &
+			BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) {
+			CAM_DBG(CAM_ISP, "CSID PPP reset complete");
+			complete(&csid_hw->csid_ppp_complete);
+		}
+
+		if ((irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_INFO_INPUT_SOF) &&
+			(csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) {
+			if (!csid_hw->sof_irq_triggered)
+				CAM_INFO_RATE_LIMIT(CAM_ISP,
+				"CSID:%d PPP SOF received",
+					csid_hw->hw_intf->hw_idx);
+			else
+				log_en = 1;
+
+			if (csid_hw->sof_irq_triggered)
+				csid_hw->irq_debug_cnt++;
+		}
+
+		if ((irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_INFO_INPUT_EOF) &&
+			(csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ)) {
+			CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received",
+				csid_hw->hw_intf->hw_idx);
+		}
+
+		if (irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_ERROR_FIFO_OVERFLOW) {
+			/* Stop PPP path immediately */
+			cam_io_w_mb(CAM_TFE_CSID_HALT_IMMEDIATELY,
+				soc_info->reg_map[0].mem_base +
+				csid_reg->ppp_reg->csid_pxl_ctrl_addr);
+			is_error_irq = true;
+		}
+
+		if (irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_PPP_ERROR_CCIF_VIOLATION)
+			is_error_irq = true;
+
+		if ((irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_ERROR_PIX_COUNT) ||
+			(irq_status[TFE_CSID_IRQ_REG_PPP] &
+			TFE_CSID_PATH_ERROR_LINE_COUNT)) {
+			ppp_reg = csid_reg->ppp_reg;
+			cmn_reg = csid_reg->cmn_reg;
+			val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+				ppp_reg->csid_pxl_format_measure0_addr);
+			val1 = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+				ppp_reg->csid_pxl_format_measure_cfg1_addr);
+
+			CAM_ERR(CAM_ISP,
+				"Pix/Line count error for CSID: %d PPP path, Expected:: height: %d, width: %d and  Actual:: height: %d width %d",
+				csid_hw->hw_intf->hw_idx,
+				((val1 >>
+				cmn_reg->format_measure_height_shift_val) &
+				cmn_reg->format_measure_height_mask_val),
+				val1 &
+				cmn_reg->format_measure_width_mask_val,
+				((val >>
+				cmn_reg->format_measure_height_shift_val) &
+				cmn_reg->format_measure_height_mask_val),
+				val &
+				cmn_reg->format_measure_width_mask_val);
+		}
+
+	}
+
 	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
 
 		if ((irq_status[i] &
@@ -3860,13 +4290,14 @@ handle_fatal_error:
 	}
 
 	if (is_error_irq || log_en) {
-		CAM_ERR_RATE_LIMIT(CAM_ISP,
-			"CSID %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x",
+		CAM_ERR(CAM_ISP,
+			"CSID %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x PPP: 0x%x",
 			csid_hw->hw_intf->hw_idx,
 			irq_status[TFE_CSID_IRQ_REG_TOP],
 			irq_status[TFE_CSID_IRQ_REG_RX],
-			irq_status[TFE_CSID_IRQ_REG_IPP]);
-		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			irq_status[TFE_CSID_IRQ_REG_IPP],
+			irq_status[TFE_CSID_IRQ_REG_PPP]);
+		CAM_ERR(CAM_ISP,
 			"RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x CSID clk:%d",
 			irq_status[TFE_CSID_IRQ_REG_RDI0],
 			irq_status[TFE_CSID_IRQ_REG_RDI1],
@@ -3922,6 +4353,7 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
 	init_completion(&tfe_csid_hw->csid_top_complete);
 	init_completion(&tfe_csid_hw->csid_csi2_complete);
 	init_completion(&tfe_csid_hw->csid_ipp_complete);
+	init_completion(&tfe_csid_hw->csid_ppp_complete);
 	for (i = 0; i < CAM_TFE_CSID_RDI_MAX; i++)
 		init_completion(&tfe_csid_hw->csid_rdin_complete[i]);
 
@@ -4010,6 +4442,24 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
 		tfe_csid_hw->pxl_pipe_enable = 1;
 	}
 
+	/* Initialize the PPP resources */
+	if (tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_ppp) {
+		CAM_DBG(CAM_ISP, "initializing the ppp path");
+
+		tfe_csid_hw->ppp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH;
+		tfe_csid_hw->ppp_res.res_id = CAM_TFE_CSID_PATH_RES_PPP;
+		tfe_csid_hw->ppp_res.res_state =
+			CAM_ISP_RESOURCE_STATE_AVAILABLE;
+		tfe_csid_hw->ppp_res.hw_intf = tfe_csid_hw->hw_intf;
+		path_data = kzalloc(sizeof(*path_data),
+					GFP_KERNEL);
+		if (!path_data) {
+			rc = -ENOMEM;
+			goto err;
+		}
+		tfe_csid_hw->ppp_res.res_priv = path_data;
+	}
+
 	/* Initialize the RDI resource */
 	for (i = 0; i < tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis;
 			i++) {
@@ -4077,6 +4527,8 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
 err:
 	if (rc) {
 		kfree(tfe_csid_hw->ipp_res.res_priv);
+		if (tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_ppp)
+			kfree(tfe_csid_hw->ppp_res.res_priv);
 		for (i = 0; i <
 			tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis;
 			i++)
@@ -4100,6 +4552,9 @@ int cam_tfe_csid_hw_deinit(struct cam_tfe_csid_hw *tfe_csid_hw)
 	/* release the privdate data memory from resources */
 	kfree(tfe_csid_hw->ipp_res.res_priv);
 
+	if (tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_ppp)
+		kfree(tfe_csid_hw->ppp_res.res_priv);
+
 	for (i = 0; i <
 		tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis;
 		i++) {

+ 15 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h

@@ -58,9 +58,12 @@
 #define TFE_CSID_PATH_IPP_ERROR_CCIF_VIOLATION        BIT(15)
 #define TFE_CSID_PATH_IPP_FRAME_DROP                  BIT(16)
 #define TFE_CSID_PATH_IPP_OVERFLOW_IRQ                BIT(17)
+#define TFE_CSID_PATH_PPP_ERROR_CCIF_VIOLATION        BIT(15)
+#define TFE_CSID_PATH_PPP_FRAME_DROP                  BIT(16)
+#define TFE_CSID_PATH_PPP_OVERFLOW_IRQ                BIT(17)
+#define TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION        BIT(15)
 #define TFE_CSID_PATH_RDI_FRAME_DROP                  BIT(16)
 #define TFE_CSID_PATH_RDI_OVERFLOW_IRQ                BIT(17)
-#define TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION        BIT(18)
 
 /*
  * Debug values enable the corresponding interrupts and debug logs provide
@@ -95,6 +98,14 @@ enum cam_tfe_csid_path_halt_mode {
 	TFE_CSID_HALT_MODE_SLAVE,
 };
 
+/* enum cam_csid_path_halt_master select the path halt master control */
+enum cam_tfe_csid_path_halt_master_sel {
+	TFE_CSID_HALT_CMD_SOURCE_EXTERNAL,
+	TFE_CSID_HALT_CMD_SOURCE_NONE,
+	TFE_CSID_HALT_CMD_SOURCE_INTERNAL2,
+	TFE_CSID_HALT_CMD_SOURCE_INTERNAL1,
+};
+
 /**
  *enum cam_csid_path_timestamp_stb_sel - select the sof/eof strobes used to
  *        capture the timestamp
@@ -470,6 +481,7 @@ struct cam_csid_evt_payload {
  * @csi2_rx_reserve_cnt:      csi2 reservations count value
  * pxl_pipe_enable:           flag to specify if the hardware has IPP
  * @ipp_res:                  image pixel path resource
+ * @ppp_res:                  PD pixel path resource
  * @rdi_res:                  raw dump image path resources
  * @cid_res:                  cid resources values
  * @csid_top_reset_complete:  csid top reset completion
@@ -510,11 +522,13 @@ struct cam_tfe_csid_hw {
 	uint32_t                            csi2_reserve_cnt;
 	uint32_t                            pxl_pipe_enable;
 	struct cam_isp_resource_node        ipp_res;
+	struct cam_isp_resource_node        ppp_res;
 	struct cam_isp_resource_node        rdi_res[CAM_TFE_CSID_RDI_MAX];
 	struct cam_tfe_csid_cid_data        cid_res[CAM_TFE_CSID_CID_MAX];
 	struct completion                   csid_top_complete;
 	struct completion                   csid_csi2_complete;
 	struct completion                   csid_ipp_complete;
+	struct completion                   csid_ppp_complete;
 	struct completion     csid_rdin_complete[CAM_TFE_CSID_RDI_MAX];
 	uint64_t                            csid_debug;
 	uint64_t                            clk_rate;

+ 93 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c

@@ -81,6 +81,7 @@ struct cam_tfe_bus_common_data {
 	uint32_t                                    max_bw_counter_limit;
 	uint32_t                                    counter_limit_shift;
 	uint32_t                                    counter_limit_mask;
+	uint32_t                                    pack_align_shift;
 };
 
 struct cam_tfe_bus_wm_resource_data {
@@ -188,6 +189,9 @@ static bool cam_tfe_bus_can_be_secure(uint32_t out_id)
 	case CAM_TFE_BUS_TFE_OUT_DS4:
 	case CAM_TFE_BUS_TFE_OUT_DS16:
 	case CAM_TFE_BUS_TFE_OUT_AI:
+	case CAM_TFE_BUS_TFE_OUT_PD_LCR_STATS:
+	case CAM_TFE_BUS_TFE_OUT_PD_PREPROCESSED:
+	case CAM_TFE_BUS_TFE_OUT_PD_PARSED:
 		return true;
 
 	case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE:
@@ -235,6 +239,12 @@ static enum cam_tfe_bus_tfe_out_id
 		return CAM_TFE_BUS_TFE_OUT_DS16;
 	case CAM_ISP_TFE_OUT_RES_AI:
 		return CAM_TFE_BUS_TFE_OUT_AI;
+	case CAM_ISP_TFE_OUT_RES_PD_LCR_STATS:
+		return CAM_TFE_BUS_TFE_OUT_PD_LCR_STATS;
+	case CAM_ISP_TFE_OUT_RES_PD_PREPROCESSED:
+		return CAM_TFE_BUS_TFE_OUT_PD_PREPROCESSED;
+	case CAM_ISP_TFE_OUT_RES_PD_PARSED:
+		return CAM_TFE_BUS_TFE_OUT_PD_PARSED;
 	default:
 		return CAM_TFE_BUS_TFE_OUT_MAX;
 	}
@@ -352,6 +362,17 @@ static int cam_tfe_bus_get_num_wm(
 			break;
 		}
 		break;
+	case CAM_TFE_BUS_TFE_OUT_PD_LCR_STATS:
+	case CAM_TFE_BUS_TFE_OUT_PD_PREPROCESSED:
+	case CAM_TFE_BUS_TFE_OUT_PD_PARSED:
+		switch (format) {
+		case CAM_FORMAT_PLAIN16_16:
+		case CAM_FORMAT_PLAIN64:
+			return 1;
+		default:
+			break;
+		}
+		break;
 	default:
 		break;
 	}
@@ -553,6 +574,33 @@ static int cam_tfe_bus_get_wm_idx(
 			break;
 		}
 		break;
+	case CAM_TFE_BUS_TFE_OUT_PD_LCR_STATS:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 16;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_TFE_BUS_TFE_OUT_PD_PREPROCESSED:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 17;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_TFE_BUS_TFE_OUT_PD_PARSED:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 18;
+			break;
+		default:
+			break;
+		}
+		break;
 	default:
 		break;
 	}
@@ -868,6 +916,48 @@ static int cam_tfe_bus_acquire_wm(
 		/*RS state packet format*/
 		if (rsrc_data->index == 15)
 			rsrc_data->pack_fmt = 0x9;
+	} else if (rsrc_data->index == 16) {
+		/* LCR */
+		switch (rsrc_data->format) {
+		case CAM_FORMAT_PLAIN16_16:
+			rsrc_data->stride = ALIGNUP(rsrc_data->width * 2, 8);
+			rsrc_data->en_cfg = 0x1;
+			/* LSB aligned */
+			rsrc_data->pack_fmt |= (1 <<
+				bus_priv->common_data.pack_align_shift);
+			break;
+		default:
+			CAM_ERR(CAM_ISP, "Invalid format %d out_type:%d index: %d",
+				rsrc_data->format, tfe_out_res_id, rsrc_data->index);
+			return -EINVAL;
+		}
+	} else if (rsrc_data->index == 17) {
+		/* PD_PREPROCESSED */
+		switch (rsrc_data->format) {
+		case CAM_FORMAT_PLAIN16_16:
+			rsrc_data->stride = ALIGNUP(rsrc_data->width * 2, 8);
+			rsrc_data->en_cfg = 0x1;
+			break;
+		default:
+			CAM_ERR(CAM_ISP, "Invalid format %d out_type:%d index: %d",
+				rsrc_data->format, tfe_out_res_id, rsrc_data->index);
+			return -EINVAL;
+		}
+	} else if (rsrc_data->index == 18) {
+		/* PD PARSED */
+		switch (rsrc_data->format) {
+		case CAM_FORMAT_PLAIN16_16:
+			rsrc_data->stride = ALIGNUP(rsrc_data->width * 2, 8);
+			rsrc_data->en_cfg = 0x1;
+			/* LSB aligned */
+			rsrc_data->pack_fmt |= (1 <<
+				bus_priv->common_data.pack_align_shift);
+			break;
+		default:
+			CAM_ERR(CAM_ISP, "Invalid format %d out_type:%d index: %d",
+				rsrc_data->format, tfe_out_res_id, rsrc_data->index);
+			return -EINVAL;
+		}
 	} else {
 		CAM_ERR(CAM_ISP, "Invalid WM:%d requested", rsrc_data->index);
 		return -EINVAL;
@@ -1792,6 +1882,8 @@ static const char *cam_tfe_bus_rup_type(
 		return "RDI1 RUP";
 	case CAM_ISP_HW_TFE_IN_RDI2:
 		return "RDI2 RUP";
+	case CAM_ISP_HW_TFE_IN_PDLIB:
+		return "PDLIB RUP";
 	default:
 		return "invalid rup group";
 	}
@@ -2734,6 +2826,7 @@ int cam_tfe_bus_init(
 	bus_priv->common_data.counter_limit_mask = hw_info->counter_limit_mask;
 	bus_priv->common_data.en_cfg_shift = hw_info->en_cfg_shift;
 	bus_priv->common_data.height_shift = hw_info->height_shift;
+	bus_priv->common_data.pack_align_shift = hw_info->pack_align_shift;
 
 	for (i = 0; i < CAM_TFE_BUS_IRQ_REGISTERS_MAX; i++)
 		bus_priv->bus_irq_error_mask[i] =

+ 6 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h

@@ -70,6 +70,7 @@ enum cam_tfe_bus_rup_grp_id {
 	CAM_TFE_BUS_RUP_GRP_1,
 	CAM_TFE_BUS_RUP_GRP_2,
 	CAM_TFE_BUS_RUP_GRP_3,
+	CAM_TFE_BUS_RUP_GRP_4,
 	CAM_TFE_BUS_RUP_GRP_MAX,
 };
 
@@ -89,6 +90,9 @@ enum cam_tfe_bus_tfe_out_id {
 	CAM_TFE_BUS_TFE_OUT_DS4,
 	CAM_TFE_BUS_TFE_OUT_DS16,
 	CAM_TFE_BUS_TFE_OUT_AI,
+	CAM_TFE_BUS_TFE_OUT_PD_LCR_STATS,
+	CAM_TFE_BUS_TFE_OUT_PD_PREPROCESSED,
+	CAM_TFE_BUS_TFE_OUT_PD_PARSED,
 	CAM_TFE_BUS_TFE_OUT_MAX,
 };
 
@@ -202,6 +206,7 @@ struct cam_tfe_bus_tfe_out_hw_info {
  * @counter_limit_shift:   Mask shift for BW counter limit
  * @counter_limit_mask:    Default Mask of BW limit counter
  * @en_cfg_shift:          bus client frame based enable bit
+ * @pack_align_shift:      pack alignment shift
  */
 struct cam_tfe_bus_hw_info {
 	struct cam_tfe_bus_reg_offset_common common_reg;
@@ -226,6 +231,7 @@ struct cam_tfe_bus_hw_info {
 	uint32_t max_bw_counter_limit;
 	uint32_t counter_limit_shift;
 	uint32_t counter_limit_mask;
+	uint32_t pack_align_shift;
 };
 
 /*

+ 275 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c

@@ -109,6 +109,23 @@ struct cam_tfe_rdi_data {
 	uint32_t                                     last_line;
 };
 
+struct cam_tfe_ppp_data {
+	void __iomem                                *mem_base;
+	struct cam_hw_intf                          *hw_intf;
+	struct cam_tfe_top_reg_offset_common        *common_reg;
+	struct cam_tfe_ppp_reg                      *ppp_reg;
+	struct cam_tfe_ppp_reg_data                 *reg_data;
+	cam_hw_mgr_event_cb_func                     event_cb;
+	void                                        *priv;
+	enum cam_isp_hw_sync_mode                    sync_mode;
+	uint32_t                                     pix_pattern;
+	uint32_t                                     left_first_pixel;
+	uint32_t                                     left_last_pixel;
+	uint32_t                                     first_line;
+	uint32_t                                     last_line;
+	bool                                         lcr_enable;
+};
+
 static int cam_tfe_validate_pix_pattern(uint32_t pattern)
 {
 	int rc;
@@ -240,6 +257,7 @@ static void cam_tfe_log_tfe_in_debug_status(
 	struct cam_tfe_camif_data            *camif_data;
 	struct cam_tfe_rdi_data              *rdi_data;
 	struct cam_tfe_top_reg_offset_common *common_reg;
+	struct cam_tfe_ppp_data              *ppp_data;
 	uint32_t  i, val_0, val_1;
 
 	mem_base = top_priv->common_data.soc_info->reg_map[0].mem_base;
@@ -283,6 +301,28 @@ static void cam_tfe_log_tfe_in_debug_status(
 				camif_data->vbi_value,
 				camif_data->hbi_value);
 
+		} else if (top_priv->in_rsrc[i].res_id == CAM_ISP_HW_TFE_IN_PDLIB) {
+			ppp_data = (struct cam_tfe_ppp_data  *)
+				top_priv->in_rsrc[i].res_priv;
+			val_0 = cam_io_r(mem_base  +
+				ppp_data->ppp_reg->ppp_debug_0);
+			val_1 = cam_io_r(mem_base  +
+				ppp_data->ppp_reg->ppp_debug_1);
+			CAM_INFO(CAM_ISP,
+				"PDLIB res id:%d debug1:0x%x Height:0x%x, width:0x%x",
+				top_priv->in_rsrc[i].res_id,
+				val_1, ((val_0 >> 16) & 0x1FFF),
+				(val_0 & 0x1FFF));
+			CAM_INFO(CAM_ISP,
+				"sync mode:%d left start pxl:0x%x end_pixel:0x%x",
+				ppp_data->sync_mode,
+				ppp_data->left_first_pixel,
+				ppp_data->left_last_pixel);
+			CAM_INFO(CAM_ISP,
+				"sync mode:%d line start:0x%x line end:0x%x",
+				ppp_data->sync_mode,
+				ppp_data->first_line,
+				ppp_data->last_line);
 		} else if ((top_priv->in_rsrc[i].res_id >=
 			CAM_ISP_HW_TFE_IN_RDI0) ||
 			(top_priv->in_rsrc[i].res_id <=
@@ -401,6 +441,9 @@ static void cam_tfe_log_error_irq_status(
 		if (evt_payload->irq_reg_val[0] & common_reg->rdi2_frame_drop_bit)
 			CAM_INFO(CAM_ISP, "TFE %d RDI2_FRAME_DROP", core_info->core_index);
 
+		if (evt_payload->irq_reg_val[0] & common_reg->ppp_frame_drop_bit)
+			CAM_INFO(CAM_ISP, "TFE %d PDAF_FRAME_DROP", core_info->core_index);
+
 		if (evt_payload->irq_reg_val[0] & common_reg->pp_overflow_bit)
 			CAM_INFO(CAM_ISP, "TFE %d PP_OVERFLOW", core_info->core_index);
 
@@ -413,6 +456,9 @@ static void cam_tfe_log_error_irq_status(
 		if (evt_payload->irq_reg_val[0] & common_reg->rdi2_overflow_bit)
 			CAM_INFO(CAM_ISP, "TFE %d RDI2_OVERFLOW", core_info->core_index);
 
+		if (evt_payload->irq_reg_val[0] & common_reg->ppp_overflow_bit)
+			CAM_INFO(CAM_ISP, "TFE %d PDAF_OVERFLOW", core_info->core_index);
+
 		if (evt_payload->irq_reg_val[0] & common_reg->out_of_sync_frame_drop_bit) {
 			CAM_INFO(CAM_ISP,
 				"TFE %d SENSOR_SWITCH_OUT_OF_SYNC_FRAME_DROP mup: last %d curr %d",
@@ -442,6 +488,12 @@ static void cam_tfe_log_error_irq_status(
 		if (evt_payload->irq_reg_val[2] & common_reg->diag_violation_bit)
 			CAM_INFO(CAM_ISP, "TFE %d DIAG_VIOLATION", core_info->core_index);
 
+		if (evt_payload->irq_reg_val[2] & common_reg->ppp_camif_violation_bit)
+			CAM_INFO(CAM_ISP, "TFE %d PDAF_CAMIF_VIOLATION", core_info->core_index);
+
+		if (evt_payload->irq_reg_val[2] & common_reg->ppp_violation_bit)
+			CAM_INFO(CAM_ISP, "TFE %d PDAF_VIOLATION", core_info->core_index);
+
 		if (evt_payload->irq_reg_val[2] & common_reg->dyamanic_switch_violation_bit)
 			CAM_INFO(CAM_ISP,
 				"TFE %d DYNAMIC_SHDR_MODE_SWITCH_VIOLATION mup val %d",
@@ -586,6 +638,84 @@ static int cam_tfe_rdi_irq_bottom_half(
 	return 0;
 }
 
+static int cam_tfe_ppp_irq_bottom_half(
+	struct cam_tfe_top_priv              *top_priv,
+	struct cam_isp_resource_node         *ppp_node,
+	bool                                  epoch_process,
+	struct cam_tfe_irq_evt_payload       *evt_payload)
+{
+	struct cam_tfe_ppp_data               *ppp_priv;
+	struct cam_isp_hw_event_info           evt_info;
+	struct cam_hw_info                    *hw_info;
+	struct cam_tfe_top_reg_offset_common  *common_reg;
+	uint32_t                               val, val2;
+
+	ppp_priv = (struct cam_tfe_ppp_data    *)ppp_node->res_priv;
+	hw_info = ppp_node->hw_intf->hw_priv;
+
+	evt_info.hw_idx   = ppp_node->hw_intf->hw_idx;
+	evt_info.res_id   = ppp_node->res_id;
+	evt_info.res_type = ppp_node->res_type;
+
+	if ((!epoch_process) && (evt_payload->irq_reg_val[1] &
+		ppp_priv->reg_data->eof_irq_mask)) {
+		CAM_DBG(CAM_ISP, "Received EOF");
+		top_priv->eof_ts.tv_sec =
+			evt_payload->ts.mono_time.tv_sec;
+		top_priv->eof_ts.tv_nsec =
+			evt_payload->ts.mono_time.tv_nsec;
+
+		if (ppp_priv->event_cb)
+			ppp_priv->event_cb(ppp_priv->priv,
+				CAM_ISP_HW_EVENT_EOF, (void *)&evt_info);
+	}
+
+	if ((!epoch_process) && (evt_payload->irq_reg_val[1] &
+		ppp_priv->reg_data->sof_irq_mask)) {
+		CAM_DBG(CAM_ISP, "Received SOF");
+		top_priv->sof_ts.tv_sec =
+			evt_payload->ts.mono_time.tv_sec;
+		top_priv->sof_ts.tv_nsec =
+			evt_payload->ts.mono_time.tv_nsec;
+
+		if (ppp_priv->event_cb)
+			ppp_priv->event_cb(ppp_priv->priv,
+				CAM_ISP_HW_EVENT_SOF, (void *)&evt_info);
+
+		if (top_priv->top_debug &
+			CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) {
+			common_reg  = ppp_priv->common_reg;
+			val = cam_io_r(ppp_priv->mem_base +
+				common_reg->diag_sensor_status_0);
+			val2 =  cam_io_r(ppp_priv->mem_base +
+				common_reg->diag_sensor_status_1);
+			CAM_INFO(CAM_ISP,
+				"TFE:%d diag sensor hbi min error:%d neq hbi:%d HBI:%d VBI:%d",
+				ppp_node->hw_intf->hw_idx,
+				((val >> common_reg->diag_min_hbi_error_shift)
+					& 0x1),
+				((val >> common_reg->diag_neq_hbi_shift) & 0x1),
+				(val & common_reg->diag_sensor_hbi_mask),
+				val2);
+		}
+	}
+
+	if (epoch_process && (evt_payload->irq_reg_val[1] &
+		ppp_priv->reg_data->epoch0_irq_mask)) {
+		CAM_DBG(CAM_ISP, "Received EPOCH0");
+		top_priv->epoch_ts.tv_sec =
+			evt_payload->ts.mono_time.tv_sec;
+		top_priv->epoch_ts.tv_nsec =
+			evt_payload->ts.mono_time.tv_nsec;
+
+		if (ppp_priv->event_cb)
+			ppp_priv->event_cb(ppp_priv->priv,
+				CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info);
+	}
+
+	return 0;
+}
+
 static int cam_tfe_camif_irq_bottom_half(
 	struct cam_tfe_top_priv              *top_priv,
 	struct cam_isp_resource_node         *camif_node,
@@ -687,6 +817,7 @@ static int cam_tfe_irq_bottom_half(void *handler_priv,
 	struct cam_tfe_irq_evt_payload      *evt_payload;
 	struct cam_tfe_camif_data           *camif_priv;
 	struct cam_tfe_rdi_data             *rdi_priv;
+	struct cam_tfe_ppp_data             *ppp_priv;
 	cam_hw_mgr_event_cb_func             event_cb = NULL;
 	void                                *event_cb_priv = NULL;
 	uint32_t i;
@@ -719,6 +850,20 @@ static int cam_tfe_irq_bottom_half(void *handler_priv,
 					&top_priv->in_rsrc[i], false,
 					evt_payload);
 
+		} else if ((top_priv->in_rsrc[i].res_id ==
+			CAM_ISP_HW_TFE_IN_PDLIB) &&
+			(top_priv->in_rsrc[i].res_state ==
+			CAM_ISP_RESOURCE_STATE_STREAMING)) {
+			ppp_priv = (struct cam_tfe_ppp_data *)
+				top_priv->in_rsrc[i].res_priv;
+			event_cb = ppp_priv->event_cb;
+			event_cb_priv = ppp_priv->priv;
+
+			if (ppp_priv->reg_data->subscribe_irq_mask[1] &
+				evt_payload->irq_reg_val[1])
+				cam_tfe_ppp_irq_bottom_half(top_priv,
+					&top_priv->in_rsrc[i], false,
+					evt_payload);
 		} else if ((top_priv->in_rsrc[i].res_id >=
 			CAM_ISP_HW_TFE_IN_RDI0) &&
 			(top_priv->in_rsrc[i].res_id <=
@@ -763,6 +908,17 @@ static int cam_tfe_irq_bottom_half(void *handler_priv,
 				cam_tfe_camif_irq_bottom_half(top_priv,
 					&top_priv->in_rsrc[i], true,
 					evt_payload);
+		} else if ((top_priv->in_rsrc[i].res_id ==
+			CAM_ISP_HW_TFE_IN_PDLIB) &&
+			(top_priv->in_rsrc[i].res_state ==
+			CAM_ISP_RESOURCE_STATE_STREAMING)) {
+			ppp_priv = (struct cam_tfe_ppp_data *)
+				top_priv->in_rsrc[i].res_priv;
+			if (ppp_priv->reg_data->subscribe_irq_mask[1] &
+				evt_payload->irq_reg_val[1])
+				cam_tfe_ppp_irq_bottom_half(top_priv,
+					&top_priv->in_rsrc[i], true,
+					evt_payload);
 		} else if ((top_priv->in_rsrc[i].res_id >=
 			CAM_ISP_HW_TFE_IN_RDI0) &&
 			(top_priv->in_rsrc[i].res_id <=
@@ -1339,6 +1495,11 @@ static int cam_tfe_top_get_reg_update(
 		rdi_rsrc_data =  in_res->res_priv;
 		reg_val_pair[0] = rdi_rsrc_data->rdi_reg->reg_update_cmd;
 		reg_val_pair[1] = rdi_rsrc_data->reg_data->reg_update_cmd_data;
+	} else if (in_res->res_id == CAM_ISP_HW_TFE_IN_PDLIB) {
+		/*REG CMD is not supported in PDLIB. PD CAMIF takes RUP from IPP CAMIF */
+		CAM_DBG(CAM_ISP, "Reg update not supported for res %d",
+			in_res->res_id);
+		return 0;
 	}
 
 	common_reg = top_priv->common_data.common_reg;
@@ -1908,6 +2069,22 @@ int cam_tfe_set_top_debug(struct cam_tfe_hw_core_info    *core_info,
 	return 0;
 }
 
+static int cam_tfe_bus_get_path_port_map(void *top_hw_info,
+		void *cmd_args, uint32_t arg_size)
+{
+	struct cam_isp_hw_path_port_map *arg = cmd_args;
+	struct cam_tfe_top_hw_info *hw_info =
+		(struct cam_tfe_top_hw_info  *)top_hw_info;
+	int i;
+
+	for (i = 0; i < hw_info->num_path_port_map; i++) {
+		arg->entry[i][0] = hw_info->path_port_map[i][0];
+		arg->entry[i][1] = hw_info->path_port_map[i][1];
+	}
+	arg->num_entries = hw_info->num_path_port_map;
+
+	return 0;
+}
 
 int cam_tfe_top_reserve(void *device_priv,
 	void *reserve_args, uint32_t arg_size)
@@ -1916,6 +2093,7 @@ int cam_tfe_top_reserve(void *device_priv,
 	struct cam_tfe_acquire_args             *args;
 	struct cam_tfe_hw_tfe_in_acquire_args   *acquire_args;
 	struct cam_tfe_camif_data               *camif_data;
+	struct cam_tfe_ppp_data                 *ppp_data;
 	struct cam_tfe_rdi_data                 *rdi_data;
 	uint32_t i;
 	int rc = -EINVAL;
@@ -1986,6 +2164,24 @@ int cam_tfe_top_reserve(void *device_priv,
 					top_priv->in_rsrc[i].hw_intf->hw_idx,
 					camif_data->pix_pattern,
 					camif_data->dsp_mode);
+			} else if (acquire_args->res_id == CAM_ISP_HW_TFE_IN_PDLIB) {
+				ppp_data = (struct cam_tfe_ppp_data	*)
+					top_priv->in_rsrc[i].res_priv;
+				ppp_data->pix_pattern =
+					acquire_args->in_port->pix_pattern;
+				ppp_data->sync_mode = acquire_args->sync_mode;
+				ppp_data->event_cb = args->event_cb;
+				ppp_data->priv = args->priv;
+				ppp_data->left_first_pixel =
+					acquire_args->in_port->left_start;
+				ppp_data->left_last_pixel =
+					acquire_args->in_port->left_end;
+				ppp_data->first_line =
+					acquire_args->in_port->line_start;
+				ppp_data->last_line =
+					acquire_args->in_port->line_end;
+				ppp_data->lcr_enable =
+					acquire_args->lcr_enable;
 			} else {
 				rdi_data = (struct cam_tfe_rdi_data      *)
 					top_priv->in_rsrc[i].res_priv;
@@ -2212,6 +2408,45 @@ static int cam_tfe_camif_resource_start(
 	return 0;
 }
 
+static int cam_tfe_ppp_resource_start(
+	struct cam_tfe_hw_core_info         *core_info,
+	struct cam_isp_resource_node        *ppp_res)
+{
+	struct cam_tfe_ppp_data             *rsrc_data;
+	uint32_t                             val = 0;
+
+	if (!ppp_res || !core_info) {
+		CAM_ERR(CAM_ISP, "Error Invalid input arguments");
+		return -EINVAL;
+	}
+
+	if (ppp_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
+		CAM_ERR(CAM_ISP, "TFE:%d Error Invalid camif res res_state:%d",
+			core_info->core_index, ppp_res->res_state);
+		return -EINVAL;
+	}
+
+	rsrc_data = (struct cam_tfe_ppp_data  *)ppp_res->res_priv;
+
+	/* Config tfe core */
+	val = (1 << rsrc_data->reg_data->pdaf_path_en_shift);
+
+	if (!rsrc_data->lcr_enable)
+		val = (1 << rsrc_data->reg_data->lcr_dis_en_shift);
+
+	if (rsrc_data->sync_mode != CAM_ISP_HW_SYNC_NONE)
+		val = (1 << rsrc_data->reg_data->lcr_dis_en_shift);
+
+	cam_io_w_mb(val, rsrc_data->mem_base +
+		rsrc_data->common_reg->core_cfg_0);
+
+	ppp_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
+	CAM_DBG(CAM_ISP, "TFE: %d Start PPP Done, core_cfg 0 val:0x%x",
+		core_info->core_index, val);
+	return 0;
+}
+
 int cam_tfe_top_start(struct cam_tfe_hw_core_info *core_info,
 	void *start_args, uint32_t arg_size)
 {
@@ -2256,6 +2491,8 @@ int cam_tfe_top_start(struct cam_tfe_hw_core_info *core_info,
 
 	if (in_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) {
 		cam_tfe_camif_resource_start(core_info, in_res);
+	} else if (in_res->res_id == CAM_ISP_HW_TFE_IN_PDLIB) {
+		cam_tfe_ppp_resource_start(core_info, in_res);
 	} else if (in_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0 &&
 		in_res->res_id <= CAM_ISP_HW_TFE_IN_RDI2) {
 		rsrc_rdi_data = (struct cam_tfe_rdi_data *) in_res->res_priv;
@@ -2325,6 +2562,7 @@ int cam_tfe_top_stop(struct cam_tfe_hw_core_info *core_info,
 	struct cam_hw_info                      *hw_info = NULL;
 	struct cam_tfe_camif_data               *camif_data;
 	struct cam_tfe_rdi_data                 *rsrc_rdi_data;
+	struct cam_tfe_ppp_data                 *ppp_data;
 	uint32_t val = 0;
 	int i, rc = 0;
 
@@ -2362,7 +2600,15 @@ int cam_tfe_top_stop(struct cam_tfe_hw_core_info *core_info,
 			cam_io_w_mb(val, camif_data->mem_base +
 				camif_data->common_reg->diag_config);
 		}
-	}  else if ((in_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0) &&
+	}  else if (in_res->res_id == CAM_ISP_HW_TFE_IN_PDLIB) {
+		ppp_data = (struct cam_tfe_ppp_data *)in_res->res_priv;
+
+		cam_io_w_mb(0, ppp_data->mem_base +
+			ppp_data->ppp_reg->ppp_module_config);
+
+		if (in_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING)
+			in_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+	} else if ((in_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0) &&
 		(in_res->res_id <= CAM_ISP_HW_TFE_IN_RDI2)) {
 		rsrc_rdi_data = (struct cam_tfe_rdi_data *) in_res->res_priv;
 		cam_io_w_mb(0x0, rsrc_rdi_data->mem_base +
@@ -2415,6 +2661,7 @@ int cam_tfe_top_init(
 	struct cam_tfe_soc_private        *soc_private = NULL;
 	struct cam_tfe_camif_data         *camif_priv = NULL;
 	struct cam_tfe_rdi_data           *rdi_priv = NULL;
+	struct cam_tfe_ppp_data           *ppp_priv = NULL;
 	int i, j, rc = 0;
 
 	top_priv = kzalloc(sizeof(struct cam_tfe_top_priv),
@@ -2477,6 +2724,29 @@ int cam_tfe_top_init(
 			camif_priv->hw_intf     = hw_intf;
 			camif_priv->soc_info    = soc_info;
 
+		} else if (hw_info->in_port[i] == CAM_TFE_PDLIB_VER_1_0) {
+			top_priv->in_rsrc[i].res_id =
+				CAM_ISP_HW_TFE_IN_PDLIB;
+
+			ppp_priv = kzalloc(sizeof(struct cam_tfe_ppp_data),
+					GFP_KERNEL);
+			if (!ppp_priv) {
+				CAM_DBG(CAM_ISP,
+					"TFE:%d Error Failed to alloc for ppp_priv",
+					core_info->core_index);
+				goto deinit_resources;
+			}
+
+			top_priv->in_rsrc[i].res_priv = ppp_priv;
+
+			ppp_priv->mem_base    =
+				soc_info->reg_map[TFE_CORE_BASE_IDX].mem_base;
+			ppp_priv->hw_intf     = hw_intf;
+			ppp_priv->common_reg  = hw_info->common_reg;
+			ppp_priv->ppp_reg     =
+				hw_info->ppp_hw_info.ppp_reg;
+			ppp_priv->reg_data    =
+				hw_info->ppp_hw_info.reg_data;
 		} else if (hw_info->in_port[i] ==
 			CAM_TFE_RDI_VER_1_0) {
 			top_priv->in_rsrc[i].res_id =
@@ -3025,6 +3295,10 @@ int cam_tfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 			core_info->tfe_bus->bus_priv, cmd_type, cmd_args,
 			arg_size);
 		break;
+	case CAM_ISP_HW_CMD_GET_PATH_PORT_MAP:
+		rc = cam_tfe_bus_get_path_port_map(hw_info->top_hw_info, cmd_args,
+					arg_size);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "TFE:%d Invalid cmd type:%d",
 			core_info->core_index, cmd_type);

+ 42 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h

@@ -16,8 +16,9 @@
 
 #define CAM_TFE_CAMIF_VER_1_0        0x10
 #define CAM_TFE_RDI_VER_1_0          0x1000
+#define CAM_TFE_PDLIB_VER_1_0        0x10000
 #define CAM_TFE_TOP_1_0              0x1000
-#define CAM_TFE_TOP_IN_PORT_MAX      4
+#define CAM_TFE_TOP_IN_PORT_MAX      5
 #define CAM_TFE_RDI_MAX              4
 
 #define CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS      BIT(0)
@@ -116,16 +117,20 @@ struct cam_tfe_top_reg_offset_common {
 	/* error bit data */
 	uint32_t pp_camif_violation_bit;
 	uint32_t pp_violation_bit;
+	uint32_t ppp_camif_violation_bit;
+	uint32_t ppp_violation_bit;
 	uint32_t rdi0_camif_violation_bit;
 	uint32_t rdi1_camif_violation_bit;
 	uint32_t rdi2_camif_violation_bit;
 	uint32_t diag_violation_bit;
 	uint32_t dyamanic_switch_violation_bit;
 	uint32_t pp_frame_drop_bit;
+	uint32_t ppp_frame_drop_bit;
 	uint32_t rdi0_frame_drop_bit;
 	uint32_t rdi1_frame_drop_bit;
 	uint32_t rdi2_frame_drop_bit;
 	uint32_t pp_overflow_bit;
+	uint32_t ppp_overflow_bit;
 	uint32_t rdi0_overflow_bit;
 	uint32_t rdi1_overflow_bit;
 	uint32_t rdi2_overflow_bit;
@@ -237,6 +242,34 @@ struct cam_tfe_rdi_reg_data {
 	uint32_t     diag_sensor_shift;
 };
 
+struct cam_tfe_ppp_reg {
+	uint32_t     ppp_hw_version;
+	uint32_t     ppp_hw_status;
+	uint32_t     ppp_module_config;
+	uint32_t     ppp_skip_period;
+	uint32_t     ppp_irq_subsample_pattern;
+	uint32_t     ppp_epoch_irq;
+	uint32_t     ppp_debug_1;
+	uint32_t     ppp_debug_0;
+	uint32_t     ppp_test_bus_ctrl;
+	uint32_t     ppp_spare;
+	uint32_t     reg_update_cmd;
+};
+
+struct cam_tfe_ppp_reg_data {
+	uint32_t     sof_irq_mask;
+	uint32_t     epoch0_irq_mask;
+	uint32_t     epoch1_irq_mask;
+	uint32_t     eof_irq_mask;
+	uint32_t     subscribe_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM];
+	uint32_t     enable_diagnostic_hw;
+	uint32_t     diag_sensor_sel;
+	uint32_t     diag_sensor_shift;
+
+	uint32_t     pdaf_path_en_shift;
+	uint32_t     lcr_dis_en_shift;
+};
+
 struct cam_tfe_clc_hw_status {
 	uint8_t     name[CAM_TFE_CLC_NAME_LENGTH_MAX];
 	uint32_t    hw_status_reg;
@@ -247,12 +280,20 @@ struct cam_tfe_rdi_hw_info {
 	struct cam_tfe_rdi_reg_data         *reg_data;
 };
 
+struct cam_tfe_ppp_hw_info {
+	struct cam_tfe_ppp_reg              *ppp_reg;
+	struct cam_tfe_ppp_reg_data         *reg_data;
+};
+
 struct cam_tfe_top_hw_info {
 	struct cam_tfe_top_reg_offset_common  *common_reg;
 	struct cam_tfe_camif_hw_info           camif_hw_info;
 	struct cam_tfe_rdi_hw_info             rdi_hw_info[CAM_TFE_RDI_MAX];
+	struct cam_tfe_ppp_hw_info             ppp_hw_info;
 	uint32_t in_port[CAM_TFE_TOP_IN_PORT_MAX];
 	struct cam_tfe_reg_dump_data           reg_dump_data;
+	uint32_t                               num_path_port_map;
+	uint32_t path_port_map[CAM_ISP_HW_PATH_PORT_MAP_MAX][2];
 };
 
 struct cam_tfe_hw_info {