From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 08:20:59 +0000
Subject: [PATCH] kernel_5.10 no rt

---
 kernel/drivers/media/platform/rockchip/cif/capture.c | 7218 ++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 5,904 insertions(+), 1,314 deletions(-)

diff --git a/kernel/drivers/media/platform/rockchip/cif/capture.c b/kernel/drivers/media/platform/rockchip/cif/capture.c
index ac8b596..983d675 100644
--- a/kernel/drivers/media/platform/rockchip/cif/capture.c
+++ b/kernel/drivers/media/platform/rockchip/cif/capture.c
@@ -19,11 +19,14 @@
 #include <media/videobuf2-dma-sg.h>
 #include <soc/rockchip/rockchip-system-status.h>
 #include <dt-bindings/soc/rockchip-system-status.h>
+#include <soc/rockchip/rockchip_iommu.h>
 
 #include "dev.h"
 #include "mipi-csi2.h"
+#include "common.h"
+#include "rkcif-externel.h"
 
-#define CIF_REQ_BUFS_MIN	3
+#define CIF_REQ_BUFS_MIN	1
 #define CIF_MIN_WIDTH		64
 #define CIF_MIN_HEIGHT		64
 #define CIF_MAX_WIDTH		8192
@@ -33,6 +36,7 @@
 
 #define RKCIF_PLANE_Y		0
 #define RKCIF_PLANE_CBCR	1
+#define RKCIF_MAX_PLANE		3
 
 #define STREAM_PAD_SINK		0
 #define STREAM_PAD_SOURCE	1
@@ -146,10 +150,18 @@
 		.csi_fmt_val = CSI_WRDDR_TYPE_RGB888,
 		.fmt_type = CIF_FMT_TYPE_RAW,
 	}, {
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 24 },
+		.csi_fmt_val = CSI_WRDDR_TYPE_RGB888,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.cplanes = 1,
 		.mplanes = 1,
 		.bpp = { 16 },
+		.csi_fmt_val = CSI_WRDDR_TYPE_RGB565,
 		.fmt_type = CIF_FMT_TYPE_RAW,
 	}, {
 		.fourcc = V4L2_PIX_FMT_BGR666,
@@ -262,6 +274,30 @@
 		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
 		.fmt_type = CIF_FMT_TYPE_RAW,
 	}, {
+		.fourcc = V4L2_PIX_FMT_SGBRG16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SGRBG16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SRGGB16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
 		.fourcc = V4L2_PIX_FMT_Y16,
 		.cplanes = 1,
 		.mplanes = 1,
@@ -293,8 +329,51 @@
 		.raw_bpp = 16,
 		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
 		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_Y12,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 12,
+		.csi_fmt_val = CSI_WRDDR_TYPE_RAW12,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_Y10,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 10,
+		.csi_fmt_val = CSI_WRDDR_TYPE_RAW10,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SRGGB16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SGRBG16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SGBRG16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.fmt_type = CIF_FMT_TYPE_RAW,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SBGGR16,
+		.cplanes = 1,
+		.mplanes = 1,
+		.bpp = { 16 },
+		.raw_bpp = 16,
+		.fmt_type = CIF_FMT_TYPE_RAW,
 	}
-
 	/* TODO: We can support NV12M/NV21M/NV16M/NV61M too */
 };
 
@@ -432,6 +511,14 @@
 		.csi_fmt_val	= CSI_WRDDR_TYPE_RGB888,
 		.field		= V4L2_FIELD_NONE,
 	}, {
+		.mbus_code	= MEDIA_BUS_FMT_BGR888_1X24,
+		.csi_fmt_val	= CSI_WRDDR_TYPE_RGB888,
+		.field		= V4L2_FIELD_NONE,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_RGB565_1X16,
+		.csi_fmt_val	= CSI_WRDDR_TYPE_RGB565,
+		.field		= V4L2_FIELD_NONE,
+	}, {
 		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
 		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_8,
 		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
@@ -463,6 +550,143 @@
 		.field		= V4L2_FIELD_NONE,
 	}
 };
+
+static int rkcif_output_fmt_check(struct rkcif_stream *stream,
+				  const struct cif_output_fmt *output_fmt)
+{
+	const struct cif_input_fmt *input_fmt = stream->cif_fmt_in;
+	struct csi_channel_info *channel = &stream->cifdev->channels[stream->id];
+	int ret = -EINVAL;
+
+	switch (input_fmt->mbus_code) {
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+		if (output_fmt->fourcc == V4L2_PIX_FMT_NV16 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_NV61 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_NV12 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_NV21 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_YUYV ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_YVYU ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_UYVY ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_VYUY)
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_Y8_1X8:
+		if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_GREY)
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_Y10_1X10:
+		if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_Y10)
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_Y12_1X12:
+		if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_Y12)
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_BGR888_1X24:
+		if (output_fmt->fourcc == V4L2_PIX_FMT_RGB24 ||
+		    output_fmt->fourcc == V4L2_PIX_FMT_BGR24)
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		if (output_fmt->fourcc == V4L2_PIX_FMT_RGB565)
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_EBD_1X8:
+		if (output_fmt->fourcc == V4l2_PIX_FMT_EBD8 ||
+		    (channel->data_bit == 8 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) ||
+		    (channel->data_bit == 10 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) ||
+		    (channel->data_bit == 12 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) ||
+		    (channel->data_bit == 16 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16)))
+			ret = 0;
+		break;
+	case MEDIA_BUS_FMT_SPD_2X8:
+		if (output_fmt->fourcc == V4l2_PIX_FMT_SPD16 ||
+		    (channel->data_bit == 8 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) ||
+		    (channel->data_bit == 10 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) ||
+		    (channel->data_bit == 12 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) ||
+		    (channel->data_bit == 16 &&
+		     (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 ||
+		      output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16)))
+			ret = 0;
+		break;
+	default:
+		break;
+	}
+	if (ret)
+		v4l2_err(&stream->cifdev->v4l2_dev,
+			 "input mbus_code 0x%x, can't transform to %c%c%c%c\n",
+			 input_fmt->mbus_code,
+			 output_fmt->fourcc & 0xff,
+			 (output_fmt->fourcc >> 8) & 0xff,
+			 (output_fmt->fourcc >> 16) & 0xff,
+			 (output_fmt->fourcc >> 24) & 0xff);
+	return ret;
+}
+
+static int rkcif_stop_dma_capture(struct rkcif_stream *stream);
+
+struct rkcif_rx_buffer *to_cif_rx_buf(struct rkisp_rx_buf *dbufs)
+{
+	return container_of(dbufs, struct rkcif_rx_buffer, dbufs);
+}
 
 static struct v4l2_subdev *get_remote_sensor(struct rkcif_stream *stream, u16 *index)
 {
@@ -553,18 +777,21 @@
 	case MEDIA_BUS_FMT_SGBRG8_1X8:
 	case MEDIA_BUS_FMT_SGRBG8_1X8:
 	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_Y8_1X8:
 		return 0x2a;
 	/* csi raw10 */
 	case MEDIA_BUS_FMT_SBGGR10_1X10:
 	case MEDIA_BUS_FMT_SGBRG10_1X10:
 	case MEDIA_BUS_FMT_SGRBG10_1X10:
 	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_Y10_1X10:
 		return 0x2b;
 	/* csi raw12 */
 	case MEDIA_BUS_FMT_SBGGR12_1X12:
 	case MEDIA_BUS_FMT_SGBRG12_1X12:
 	case MEDIA_BUS_FMT_SGRBG12_1X12:
 	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_Y12_1X12:
 		return 0x2c;
 	/* csi uyvy 422 */
 	case MEDIA_BUS_FMT_UYVY8_2X8:
@@ -572,7 +799,8 @@
 	case MEDIA_BUS_FMT_YUYV8_2X8:
 	case MEDIA_BUS_FMT_YVYU8_2X8:
 		return 0x1e;
-	case MEDIA_BUS_FMT_RGB888_1X24: {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_BGR888_1X24:
 		if (dsi_input) {
 			if (cmd_mode_en) /* dsi command mode*/
 				return 0x39;
@@ -581,7 +809,15 @@
 		} else {
 			return 0x24;
 		}
-	}
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		if (dsi_input) {
+			if (cmd_mode_en) /* dsi command mode*/
+				return 0x39;
+			else /* dsi video mode */
+				return 0x0e;
+		} else {
+			return 0x22;
+		}
 	case MEDIA_BUS_FMT_EBD_1X8:
 		return 0x12;
 	case MEDIA_BUS_FMT_SPD_2X8:
@@ -597,6 +833,8 @@
 	switch (fmt_in->csi_fmt_val) {
 	case CSI_WRDDR_TYPE_RGB888:
 		return 24;
+	case CSI_WRDDR_TYPE_RGB565:
+		return 16;
 	case CSI_WRDDR_TYPE_RAW10:
 	case CSI_WRDDR_TYPE_RAW12:
 		return 4;
@@ -608,51 +846,61 @@
 	}
 }
 
-static const struct
-cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect,
-			     u32 pad, int *vc)
+const struct
+cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *rect,
+			     u32 pad_id, struct csi_channel_info *csi_info)
 {
 	struct v4l2_subdev_format fmt;
+	struct v4l2_subdev *sd = dev->terminal_sensor.sd;
+	struct rkmodule_channel_info ch_info = {0};
+	struct rkmodule_capture_info capture_info;
 	int ret;
 	u32 i;
-	struct rkmodule_vc_fmt_info vc_info = {0};
 
-	ret = v4l2_subdev_call(sd,
-			core, ioctl,
-			RKMODULE_GET_VC_FMT_INFO,
-			&vc_info);
-	if (ret < 0)
-		v4l2_warn(sd->v4l2_dev,
-			  "get sensor vc info failed, maybe not support\n");
-
-	fmt.pad = pad;
+	fmt.pad = 0;
 	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 	fmt.reserved[0] = 0;
+	fmt.format.field = V4L2_FIELD_NONE;
 	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
 	if (ret < 0) {
 		v4l2_warn(sd->v4l2_dev,
 			  "sensor fmt invalid, set to default size\n");
 		goto set_default;
 	}
-
-	/* v4l2_subdev_format reserved[0]
-	 * using as mipi virtual channel
-	 */
-	switch (fmt.reserved[0]) {
-	case V4L2_MBUS_CSI2_CHANNEL_3:
-		*vc = 3;
-		break;
-	case V4L2_MBUS_CSI2_CHANNEL_2:
-		*vc = 2;
-		break;
-	case V4L2_MBUS_CSI2_CHANNEL_1:
-		*vc = 1;
-		break;
-	case V4L2_MBUS_CSI2_CHANNEL_0:
-		*vc = 0;
-		break;
-	default:
-		*vc = -1;
+	ch_info.index = pad_id;
+	ret = v4l2_subdev_call(sd,
+			       core, ioctl,
+			       RKMODULE_GET_CHANNEL_INFO,
+			       &ch_info);
+	if (!ret) {
+		fmt.format.width = ch_info.width;
+		fmt.format.height = ch_info.height;
+		fmt.format.code = ch_info.bus_fmt;
+		switch (ch_info.vc) {
+		case V4L2_MBUS_CSI2_CHANNEL_3:
+			csi_info->vc = 3;
+			break;
+		case V4L2_MBUS_CSI2_CHANNEL_2:
+			csi_info->vc = 2;
+			break;
+		case V4L2_MBUS_CSI2_CHANNEL_1:
+			csi_info->vc = 1;
+			break;
+		case V4L2_MBUS_CSI2_CHANNEL_0:
+			csi_info->vc = 0;
+			break;
+		default:
+			csi_info->vc = 0xff;
+		}
+		if (ch_info.bus_fmt == MEDIA_BUS_FMT_SPD_2X8 ||
+		    ch_info.bus_fmt == MEDIA_BUS_FMT_EBD_1X8) {
+			if (ch_info.data_type > 0)
+				csi_info->data_type = ch_info.data_type;
+			if (ch_info.data_bit > 0)
+				csi_info->data_bit = ch_info.data_bit;
+		}
+	} else {
+		csi_info->vc = 0xff;
 	}
 
 	v4l2_dbg(1, rkcif_debug, sd->v4l2_dev,
@@ -663,7 +911,26 @@
 	rect->top = 0;
 	rect->width = fmt.format.width;
 	rect->height = fmt.format.height;
-
+	ret = v4l2_subdev_call(sd,
+			       core, ioctl,
+			       RKMODULE_GET_CAPTURE_MODE,
+			       &capture_info);
+	if (!ret) {
+		if (capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE &&
+		    dev->hw_dev->is_rk3588s2) {
+			for (i = 0; i < capture_info.multi_dev.dev_num; i++) {
+				if (capture_info.multi_dev.dev_idx[i] == 0)
+					capture_info.multi_dev.dev_idx[i] = 2;
+				else if (capture_info.multi_dev.dev_idx[i] == 2)
+					capture_info.multi_dev.dev_idx[i] = 4;
+				else if (capture_info.multi_dev.dev_idx[i] == 3)
+					capture_info.multi_dev.dev_idx[i] = 5;
+			}
+		}
+		csi_info->capture_info = capture_info;
+	} else {
+		csi_info->capture_info.mode = RKMODULE_CAPTURE_MODE_NONE;
+	}
 	for (i = 0; i < ARRAY_SIZE(in_fmts); i++)
 		if (fmt.format.code == in_fmts[i].mbus_code &&
 		    fmt.format.field == in_fmts[i].field)
@@ -680,8 +947,8 @@
 	return NULL;
 }
 
-static const struct
-cif_output_fmt *find_output_fmt(struct rkcif_stream *stream, u32 pixelfmt)
+const struct
+cif_output_fmt *rkcif_find_output_fmt(struct rkcif_stream *stream, u32 pixelfmt)
 {
 	const struct cif_output_fmt *fmt;
 	u32 i;
@@ -714,6 +981,31 @@
 		break;
 	default:
 		index = CIF_REG_MIPI_LVDS_ID0_CTRL0;
+		break;
+	}
+
+	return index;
+}
+
+static enum cif_reg_index get_reg_index_of_lvds_id_ctrl0(int channel_id)
+{
+	enum cif_reg_index index;
+
+	switch (channel_id) {
+	case 0:
+		index = CIF_REG_LVDS_ID0_CTRL0;
+		break;
+	case 1:
+		index = CIF_REG_LVDS_ID1_CTRL0;
+		break;
+	case 2:
+		index = CIF_REG_LVDS_ID2_CTRL0;
+		break;
+	case 3:
+		index = CIF_REG_LVDS_ID3_CTRL0;
+		break;
+	default:
+		index = CIF_REG_LVDS_ID0_CTRL0;
 		break;
 	}
 
@@ -1170,12 +1462,50 @@
 	return index;
 }
 
+int rkcif_get_linetime(struct rkcif_stream *stream)
+{
+	struct rkcif_device *cif_dev = stream->cifdev;
+	struct rkcif_sensor_info *sensor = &cif_dev->terminal_sensor;
+	u32 numerator, denominator;
+	u32 def_fps = 0;
+	int line_time = 0;
+	int vblank_def = 0;
+	int vblank_curr = 0;
+
+	numerator = sensor->fi.interval.numerator;
+	denominator = sensor->fi.interval.denominator;
+	if (!numerator || !denominator) {
+		v4l2_err(&cif_dev->v4l2_dev,
+			 "get frame interval fail, numerator %d, denominator %d\n",
+			 numerator, denominator);
+		return -EINVAL;
+	}
+	def_fps = denominator / numerator;
+	if (!def_fps) {
+		v4l2_err(&cif_dev->v4l2_dev,
+			 "get fps fail, numerator %d, denominator %d\n",
+			 numerator, denominator);
+		return -EINVAL;
+	}
+	vblank_def = rkcif_get_sensor_vblank_def(cif_dev);
+	vblank_curr = rkcif_get_sensor_vblank(cif_dev);
+	if (!vblank_def || !vblank_curr) {
+		v4l2_err(&cif_dev->v4l2_dev,
+			 "get vblank fail, vblank_def %d, vblank_curr %d\n",
+			 vblank_def, vblank_curr);
+		return -EINVAL;
+	}
+	line_time = div_u64(1000000000, def_fps);
+	line_time = div_u64(line_time, vblank_def + sensor->raw_rect.height);
+	return line_time;
+}
+
 /***************************** stream operations ******************************/
 static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
-					     enum rkcif_yuvaddr_state stat)
+					    enum rkcif_yuvaddr_state stat)
 {
 	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 	struct rkcif_buffer *buffer = NULL;
 	u32 frm_addr_y = CIF_REG_DVP_FRM0_ADDR_Y;
 	u32 frm_addr_uv = CIF_REG_DVP_FRM0_ADDR_UV;
@@ -1270,12 +1600,696 @@
 			} else {
 				ret = -EINVAL;
 			}
-			v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
-				 "not active buffer, frame Drop\n");
+			dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id);
+			dev->irq_stats.not_active_buf_cnt[stream->id]++;
 		}
 	}
 	spin_unlock_irqrestore(&stream->vbq_lock, flags);
 	return ret;
+}
+
+static void rkcif_rx_buffer_free(struct rkcif_stream *stream)
+{
+	struct media_pad *pad = NULL;
+	struct v4l2_subdev *sd;
+	struct rkisp_rx_buf *dbufs;
+	struct rkcif_device *dev = stream->cifdev;
+
+	if (dev->sditf[0] && dev->sditf[0]->sd.entity.num_links) {
+		if (dev->sditf[0]->is_combine_mode)
+			pad = media_entity_remote_pad(&dev->sditf[0]->pads[1]);
+		else
+			pad = media_entity_remote_pad(&dev->sditf[0]->pads[0]);
+	} else {
+		return;
+	}
+
+	if (pad)
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+	else
+		return;
+
+	while (!list_empty(&stream->rx_buf_head_vicap)) {
+		dbufs = list_first_entry(&stream->rx_buf_head_vicap, struct rkisp_rx_buf, list);
+		if (dbufs->is_init)
+			v4l2_subdev_call(sd, core, ioctl,
+					 RKISP_VICAP_CMD_RX_BUFFER_FREE, dbufs);
+		dma_buf_put(dbufs->dbuf);
+		list_del(&dbufs->list);
+		kfree(dbufs);
+	}
+}
+
+static void rkcif_s_rx_buffer(struct rkcif_device *dev, struct rkisp_rx_buf *dbufs)
+{
+	struct media_pad *pad = NULL;
+	struct v4l2_subdev *sd;
+	struct rkcif_rx_buffer *rx_buf = NULL;
+
+	if (dev->sditf[0]) {
+		if (dev->sditf[0]->is_combine_mode)
+			pad = media_entity_remote_pad(&dev->sditf[0]->pads[1]);
+		else
+			pad = media_entity_remote_pad(&dev->sditf[0]->pads[0]);
+	} else {
+		return;
+	}
+	if (pad)
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+	else
+		return;
+	if (dev->rdbk_debug &&
+	    dbufs->sequence < 15) {
+		rx_buf = to_cif_rx_buf(dbufs);
+		v4l2_info(&dev->v4l2_dev,
+			  "s_buf seq %d type %d, dma addr %x, %lld\n",
+			  dbufs->sequence, dbufs->type, (u32)rx_buf->dummy.dma_addr,
+			  ktime_get_ns());
+	}
+	v4l2_subdev_call(sd, video, s_rx_buffer, dbufs, NULL);
+}
+
+static void rkcif_enable_skip_frame(struct rkcif_stream *stream, int cap_m, int skip_n)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	u32 val = 0;
+
+	val = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_CTRL);
+	val &= 0xc00fffff;
+	val |= cap_m << RKCIF_CAP_SHIFT | skip_n << RKCIF_SKIP_SHIFT | RKCIF_SKIP_EN(stream->id);
+	rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val);
+	stream->skip_info.skip_en = true;
+}
+
+static void rkcif_disable_skip_frame(struct rkcif_stream *stream)
+{	struct rkcif_device *dev = stream->cifdev;
+	u32 val = 0;
+
+	val = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_CTRL);
+	val &= ~(RKCIF_SKIP_EN(stream->id));
+	rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val);
+	stream->skip_info.skip_en = false;
+}
+
+static void rkcif_rdbk_with_tools(struct rkcif_stream *stream,
+				      struct rkcif_rx_buffer *active_buf)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags);
+	if (stream->tools_vdev->state == RKCIF_STATE_STREAMING) {
+		list_add_tail(&active_buf->list, &stream->tools_vdev->buf_done_head);
+		if (!work_busy(&stream->tools_vdev->work))
+			schedule_work(&stream->tools_vdev->work);
+	}
+	spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags);
+}
+
+static void rkcif_rdbk_frame_end_toisp(struct rkcif_stream *stream,
+				       struct rkcif_rx_buffer *buffer)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct rkcif_sensor_info *sensor = &stream->cifdev->terminal_sensor;
+	u32 denominator, numerator;
+	u64 l_ts, m_ts, s_ts, time = 30000000LL;
+	int ret, fps = -1;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->hdr_lock, flags);
+	if (dev->rdbk_rx_buf[stream->id]) {
+		list_add_tail(&dev->rdbk_rx_buf[stream->id]->list, &stream->rx_buf_head);
+		dev->rdbk_rx_buf[stream->id] = buffer;
+	} else {
+		dev->rdbk_rx_buf[stream->id] = buffer;
+	}
+
+	numerator = sensor->fi.interval.numerator;
+	denominator = sensor->fi.interval.denominator;
+	if (denominator && numerator)
+		time = numerator * 1000 / denominator * 1000 * 1000;
+
+	if (dev->hdr.hdr_mode == HDR_X3 &&
+	    dev->rdbk_rx_buf[RDBK_L] &&
+	    dev->rdbk_rx_buf[RDBK_M] &&
+	    dev->rdbk_rx_buf[RDBK_S]) {
+		l_ts = dev->rdbk_rx_buf[RDBK_L]->fe_timestamp;
+		m_ts = dev->rdbk_rx_buf[RDBK_M]->fe_timestamp;
+		s_ts = dev->rdbk_rx_buf[RDBK_S]->fe_timestamp;
+
+		if (m_ts < l_ts || s_ts < m_ts) {
+			v4l2_err(&dev->v4l2_dev,
+				 "s/m/l frame err, timestamp s:%lld m:%lld l:%lld\n",
+				 s_ts, m_ts, l_ts);
+			goto RDBK_TOISP_UNMATCH;
+		}
+
+		if ((m_ts - l_ts) > time || (s_ts - m_ts) > time) {
+			ret = v4l2_subdev_call(sensor->sd,
+					       video,
+					       g_frame_interval,
+					       &sensor->fi);
+			if (!ret) {
+				denominator = sensor->fi.interval.denominator;
+				numerator = sensor->fi.interval.numerator;
+				if (denominator && numerator) {
+					time = numerator * 1000 / denominator * 1000 * 1000;
+					fps = denominator / numerator;
+				}
+			}
+
+			if ((m_ts - l_ts) > time || (s_ts - m_ts) > time) {
+				v4l2_err(&dev->v4l2_dev,
+					 "timestamp no match, s:%lld m:%lld l:%lld, fps:%d\n",
+					 s_ts, m_ts, l_ts, fps);
+				goto RDBK_TOISP_UNMATCH;
+			}
+		}
+		dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence;
+		dev->rdbk_rx_buf[RDBK_S]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence;
+		rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs);
+		rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs);
+		rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_S]->dbufs);
+		rkcif_rdbk_with_tools(&dev->stream[RDBK_L], dev->rdbk_rx_buf[RDBK_L]);
+		rkcif_rdbk_with_tools(&dev->stream[RDBK_M], dev->rdbk_rx_buf[RDBK_M]);
+		rkcif_rdbk_with_tools(&dev->stream[RDBK_S], dev->rdbk_rx_buf[RDBK_S]);
+		atomic_dec(&dev->stream[RDBK_L].buf_cnt);
+		atomic_dec(&dev->stream[RDBK_M].buf_cnt);
+		atomic_dec(&dev->stream[RDBK_S].buf_cnt);
+		dev->rdbk_rx_buf[RDBK_L] = NULL;
+		dev->rdbk_rx_buf[RDBK_M] = NULL;
+		dev->rdbk_rx_buf[RDBK_S] = NULL;
+	} else if (dev->hdr.hdr_mode == HDR_X2 &&
+		dev->rdbk_rx_buf[RDBK_L] && dev->rdbk_rx_buf[RDBK_M]) {
+		l_ts = dev->rdbk_rx_buf[RDBK_L]->fe_timestamp;
+		s_ts = dev->rdbk_rx_buf[RDBK_M]->fe_timestamp;
+
+		if (s_ts < l_ts) {
+			v4l2_err(&dev->v4l2_dev,
+				 "s/l frame err, timestamp s:%lld l:%lld\n",
+				 s_ts, l_ts);
+			goto RDBK_TOISP_UNMATCH;
+		}
+
+		if ((s_ts - l_ts) > time) {
+			ret = v4l2_subdev_call(sensor->sd,
+					       video,
+					       g_frame_interval,
+					       &sensor->fi);
+			if (!ret) {
+				denominator = sensor->fi.interval.denominator;
+				numerator = sensor->fi.interval.numerator;
+				if (denominator && numerator) {
+					time = numerator * 1000 / denominator * 1000 * 1000;
+					fps = denominator / numerator;
+				}
+			}
+			if ((s_ts - l_ts) > time) {
+				v4l2_err(&dev->v4l2_dev,
+					 "timestamp no match, s:%lld l:%lld, fps:%d\n",
+					 s_ts, l_ts, fps);
+				goto RDBK_TOISP_UNMATCH;
+			}
+		}
+		dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence;
+		rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs);
+		rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs);
+		rkcif_rdbk_with_tools(&dev->stream[RDBK_L], dev->rdbk_rx_buf[RDBK_L]);
+		rkcif_rdbk_with_tools(&dev->stream[RDBK_M], dev->rdbk_rx_buf[RDBK_M]);
+		atomic_dec(&dev->stream[RDBK_L].buf_cnt);
+		atomic_dec(&dev->stream[RDBK_M].buf_cnt);
+		dev->rdbk_rx_buf[RDBK_L] = NULL;
+		dev->rdbk_rx_buf[RDBK_M] = NULL;
+	}
+
+	spin_unlock_irqrestore(&dev->hdr_lock, flags);
+	return;
+
+RDBK_TOISP_UNMATCH:
+	spin_unlock_irqrestore(&dev->hdr_lock, flags);
+}
+
+static void rkcif_write_buff_addr_multi_dev_combine(struct rkcif_stream *stream,
+						    u32 frm_addr_y, u32 frm_addr_uv,
+						    u32 buff_addr_y, u32 buff_addr_cbcr,
+						    bool is_dummy_buf)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info;
+	u32 addr_y, addr_cbcr;
+	int addr_offset = 0;
+	int i = 0;
+	int tmp_host_index = dev->csi_host_idx;
+
+	for (i = 0; i < capture_info->multi_dev.dev_num; i++) {
+		if (is_dummy_buf) {
+			addr_y = buff_addr_y;
+		} else {
+			addr_offset = dev->channels[stream->id].left_virtual_width;
+			addr_y = buff_addr_y + addr_offset * i;
+		}
+		dev->csi_host_idx = capture_info->multi_dev.dev_idx[i];
+		rkcif_write_register(dev, frm_addr_y, addr_y);
+		if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW &&
+		    frm_addr_uv && buff_addr_cbcr) {
+			if (is_dummy_buf) {
+				addr_cbcr = buff_addr_cbcr;
+			} else {
+				addr_offset = dev->channels[stream->id].left_virtual_width;
+				addr_cbcr = buff_addr_cbcr + addr_offset * i;
+			}
+			rkcif_write_register(dev, frm_addr_uv, addr_cbcr);
+		}
+	}
+	dev->csi_host_idx = tmp_host_index;
+}
+
+static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream,
+					       int channel_id)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct rkcif_rx_buffer *rx_buf;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info;
+	u32 frm0_addr_y;
+	u32 frm1_addr_y;
+	u32 buff_addr_y;
+	unsigned long flags;
+
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CCP2) {
+		frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id);
+		frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id);
+	} else {
+		frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id);
+		frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id);
+	}
+
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+
+	if (!stream->curr_buf_toisp) {
+		if (!list_empty(&stream->rx_buf_head)) {
+			rx_buf = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer,
+						 list);
+			if (rx_buf) {
+				list_del(&rx_buf->list);
+				stream->curr_buf_toisp = rx_buf;
+			}
+		}
+	}
+
+	if (stream->curr_buf_toisp) {
+		buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr;
+		if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream, frm0_addr_y, 0,
+								buff_addr_y, 0, false);
+		} else {
+			rkcif_write_register(dev, frm0_addr_y, buff_addr_y);
+		}
+	}
+
+	if (!stream->next_buf_toisp) {
+		if (!list_empty(&stream->rx_buf_head)) {
+			rx_buf = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (rx_buf) {
+				list_del(&rx_buf->list);
+				stream->next_buf_toisp = rx_buf;
+			} else {
+				stream->next_buf_toisp = stream->curr_buf_toisp;
+			}
+		} else {
+			stream->next_buf_toisp = stream->curr_buf_toisp;
+		}
+	}
+
+	if (stream->next_buf_toisp) {
+		buff_addr_y = stream->next_buf_toisp->dummy.dma_addr;
+		if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream, frm1_addr_y, 0,
+								buff_addr_y, 0, false);
+		} else {
+			rkcif_write_register(dev, frm1_addr_y, buff_addr_y);
+		}
+	}
+
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+	stream->buf_owner = RKCIF_DMAEN_BY_ISP;
+}
+
+static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream,
+						int channel_id)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info;
+	struct rkcif_rx_buffer *buffer = NULL;
+	struct rkcif_rx_buffer *active_buf = NULL;
+	struct sditf_priv *priv = dev->sditf[0];
+	u32 frm_addr_y, buff_addr_y;
+	unsigned long flags;
+
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CCP2) {
+		frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			     get_reg_index_of_frm0_y_addr(channel_id) :
+			     get_reg_index_of_frm1_y_addr(channel_id);
+	} else {
+		frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			     get_dvp_reg_index_of_frm0_y_addr(channel_id) :
+			     get_dvp_reg_index_of_frm1_y_addr(channel_id);
+	}
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+	if (!list_empty(&stream->rx_buf_head)) {
+		if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+			if (stream->curr_buf_toisp == stream->next_buf_toisp)
+				active_buf = NULL;
+			else
+				active_buf = stream->curr_buf_toisp;
+
+			buffer = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (buffer) {
+				list_del(&buffer->list);
+				stream->curr_buf_toisp = buffer;
+			}
+			if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) {
+				if (!active_buf)
+					goto out_get_buf;
+				if (stream->frame_idx == 1)
+					active_buf->dbufs.is_first = true;
+				active_buf->dbufs.sequence = stream->frame_idx - 1;
+				active_buf->dbufs.timestamp = stream->readout.fs_timestamp;
+				active_buf->fe_timestamp = ktime_get_ns();
+				stream->last_frame_idx = stream->frame_idx;
+				if (dev->hdr.hdr_mode == NO_HDR) {
+					rkcif_s_rx_buffer(dev, &active_buf->dbufs);
+					if (dev->is_support_tools && stream->tools_vdev)
+						rkcif_rdbk_with_tools(stream, active_buf);
+					atomic_dec(&stream->buf_cnt);
+				} else {
+					rkcif_rdbk_frame_end_toisp(stream, active_buf);
+				}
+			} else {
+				rkcif_s_rx_buffer(dev, &active_buf->dbufs);
+				if (dev->is_support_tools && stream->tools_vdev)
+					rkcif_rdbk_with_tools(stream, active_buf);
+			}
+		} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
+			if (stream->curr_buf_toisp == stream->next_buf_toisp)
+				active_buf = NULL;
+			else
+				active_buf = stream->next_buf_toisp;
+			buffer = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (buffer) {
+				list_del(&buffer->list);
+				stream->next_buf_toisp = buffer;
+			}
+			if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) {
+				if (!active_buf)
+					goto out_get_buf;
+				if (stream->frame_idx == 1)
+					active_buf->dbufs.is_first = true;
+				active_buf->dbufs.sequence = stream->frame_idx - 1;
+				active_buf->dbufs.timestamp = stream->readout.fs_timestamp;
+				active_buf->fe_timestamp = ktime_get_ns();
+				stream->last_frame_idx = stream->frame_idx;
+				if (dev->hdr.hdr_mode == NO_HDR) {
+					rkcif_s_rx_buffer(dev, &active_buf->dbufs);
+					if (dev->is_support_tools && stream->tools_vdev)
+						rkcif_rdbk_with_tools(stream, active_buf);
+					atomic_dec(&stream->buf_cnt);
+				} else {
+					rkcif_rdbk_frame_end_toisp(stream, active_buf);
+				}
+			} else {
+				rkcif_s_rx_buffer(dev, &active_buf->dbufs);
+				if (dev->is_support_tools && stream->tools_vdev)
+					rkcif_rdbk_with_tools(stream, active_buf);
+			}
+		}
+		if (stream->lack_buf_cnt)
+			stream->lack_buf_cnt--;
+	} else {
+		if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE)
+			goto out_get_buf;
+		if (stream->lack_buf_cnt < 2)
+			stream->lack_buf_cnt++;
+		if (dev->hw_dev->dummy_buf.vaddr) {
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+				active_buf = stream->curr_buf_toisp;
+				stream->curr_buf_toisp = NULL;
+			} else {
+				active_buf = stream->next_buf_toisp;
+				stream->next_buf_toisp = NULL;
+			}
+		} else if (stream->curr_buf_toisp && stream->next_buf_toisp &&
+			   stream->curr_buf_toisp != stream->next_buf_toisp) {
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+				active_buf = stream->curr_buf_toisp;
+				stream->curr_buf_toisp = stream->next_buf_toisp;
+				buffer = stream->next_buf_toisp;
+			} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
+				active_buf = stream->next_buf_toisp;
+				stream->next_buf_toisp = stream->curr_buf_toisp;
+				buffer = stream->curr_buf_toisp;
+			}
+			if (stream->cifdev->rdbk_debug)
+				v4l2_info(&stream->cifdev->v4l2_dev,
+					  "stream[%d] hold buf %x\n",
+					  stream->id,
+					  (u32)stream->next_buf_toisp->dummy.dma_addr);
+		}
+		if (active_buf) {
+			if (stream->frame_idx == 1)
+				active_buf->dbufs.is_first = true;
+			active_buf->dbufs.sequence = stream->frame_idx - 1;
+			active_buf->dbufs.timestamp = stream->readout.fs_timestamp;
+			active_buf->fe_timestamp = ktime_get_ns();
+			stream->last_frame_idx = stream->frame_idx;
+			if (dev->hdr.hdr_mode == NO_HDR) {
+				rkcif_s_rx_buffer(dev, &active_buf->dbufs);
+				if (dev->is_support_tools && stream->tools_vdev)
+					rkcif_rdbk_with_tools(stream, active_buf);
+				atomic_dec(&stream->buf_cnt);
+			} else {
+				rkcif_rdbk_frame_end_toisp(stream, active_buf);
+			}
+		} else {
+			if (stream->cifdev->rdbk_debug && dev->hw_dev->dummy_buf.vaddr)
+				v4l2_info(&stream->cifdev->v4l2_dev,
+					  "stream[%d] loss frame %d\n",
+					  stream->id,
+					  stream->frame_idx - 1);
+		}
+		if (dev->is_support_tools && stream->tools_vdev && stream->curr_buf_toisp)
+			rkcif_rdbk_with_tools(stream, stream->curr_buf_toisp);
+	}
+
+out_get_buf:
+	stream->frame_phase_cache = stream->frame_phase;
+	if (buffer) {
+		buff_addr_y = buffer->dummy.dma_addr;
+		if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0,
+								buff_addr_y, 0, false);
+		} else {
+			rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+		}
+		if (dev->rdbk_debug > 1 &&
+		    stream->frame_idx < 15)
+			v4l2_info(&dev->v4l2_dev,
+				  "stream[%d] update, seq %d, reg %x, buf %x\n",
+				  stream->id,
+				  stream->frame_idx - 1,
+				  frm_addr_y, (u32)buffer->dummy.dma_addr);
+	} else if (dev->hw_dev->dummy_buf.vaddr && priv &&
+		   priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) {
+		buff_addr_y = dev->hw_dev->dummy_buf.dma_addr;
+		if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0,
+								buff_addr_y, 0, true);
+		} else {
+			rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+		}
+	}
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+	return 0;
+}
+
+static int rkcif_assign_new_buffer_pingpong_toisp(struct rkcif_stream *stream,
+						  int init, int channel_id)
+{
+	int ret = 0;
+
+	if (init)
+		rkcif_assign_new_buffer_init_toisp(stream, channel_id);
+	else
+		ret = rkcif_assign_new_buffer_update_toisp(stream, channel_id);
+	return ret;
+}
+
+void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	struct rkcif_rx_buffer *buffer = NULL;
+	struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info;
+	struct rkcif_rx_buffer *active_buf = NULL;
+	u32 frm_addr_y, buff_addr_y;
+	u32 vblank = 0;
+	u32 vblank_ns = 0;
+	u64 cur_time = 0;
+	int frame_phase = 0;
+	int frame_phase_next = 0;
+	bool is_early_update = false;
+
+	if (stream->curr_buf_toisp != stream->next_buf_toisp) {
+		if (dev->rdbk_debug > 2 &&
+		    stream->frame_idx < 15)
+			v4l2_info(&dev->v4l2_dev,
+				  "stream[%d] addr check not equal 0x%x 0x%x\n",
+				  stream->id,
+				  (u32)stream->curr_buf_toisp->dummy.dma_addr,
+				  (u32)stream->next_buf_toisp->dummy.dma_addr);
+		return;
+	}
+	if (!dev->sensor_linetime)
+		dev->sensor_linetime = rkcif_get_linetime(stream);
+	vblank = rkcif_get_sensor_vblank(dev);
+	vblank_ns = vblank * dev->sensor_linetime;
+	cur_time = ktime_get_ns();
+
+	if (dev->chip_id > CHIP_RK3568_CIF &&
+	    dev->hdr.hdr_mode == NO_HDR &&
+	    cur_time - stream->readout.fe_timestamp < (vblank_ns - 500000) &&
+	    stream->lack_buf_cnt == 2 &&
+	    stream->frame_idx > stream->last_frame_idx) {
+		is_early_update = true;
+		frame_phase = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			CIF_CSI_FRAME1_READY : CIF_CSI_FRAME0_READY;
+		frame_phase_next = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			CIF_CSI_FRAME0_READY : CIF_CSI_FRAME1_READY;
+	} else {
+		frame_phase = stream->frame_phase;
+	}
+	if (dev->rdbk_debug > 2 &&
+	    stream->frame_idx < 15)
+		v4l2_info(&dev->v4l2_dev,
+			  "stream[%d] check update, cur %lld, fe %lld, vb %u lack_buf %d\n",
+			  stream->id,
+			  cur_time, stream->readout.fe_timestamp,
+			  vblank_ns, stream->lack_buf_cnt);
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CCP2) {
+		frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ?
+			     get_reg_index_of_frm0_y_addr(stream->id) :
+			     get_reg_index_of_frm1_y_addr(stream->id);
+	} else {
+		frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ?
+			     get_dvp_reg_index_of_frm0_y_addr(stream->id) :
+			     get_dvp_reg_index_of_frm1_y_addr(stream->id);
+	}
+	if (!list_empty(&stream->rx_buf_head)) {
+		if (frame_phase == CIF_CSI_FRAME0_READY) {
+			active_buf = stream->curr_buf_toisp;
+			buffer = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (buffer) {
+				list_del(&buffer->list);
+				stream->curr_buf_toisp = buffer;
+				buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr;
+				if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+					rkcif_write_buff_addr_multi_dev_combine(stream,
+										frm_addr_y, 0,
+										buff_addr_y, 0,
+										false);
+				} else {
+					rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+				}
+				if (dev->rdbk_debug > 1 &&
+				    stream->frame_idx < 15)
+					v4l2_info(&dev->v4l2_dev,
+						  "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n",
+						  stream->id,
+						  stream->frame_idx - 1, frm_addr_y,
+						  (u32)stream->curr_buf_toisp->dummy.dma_addr);
+			}
+		} else if (frame_phase == CIF_CSI_FRAME1_READY) {
+			active_buf = stream->next_buf_toisp;
+			buffer = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (buffer) {
+				list_del(&buffer->list);
+				stream->next_buf_toisp = buffer;
+				buff_addr_y = stream->next_buf_toisp->dummy.dma_addr;
+				if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+					rkcif_write_buff_addr_multi_dev_combine(stream,
+										frm_addr_y, 0,
+										buff_addr_y, 0,
+										false);
+				} else {
+					rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+				}
+				if (dev->rdbk_debug > 1 &&
+				    stream->frame_idx < 15)
+					v4l2_info(&dev->v4l2_dev,
+						  "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n",
+						  stream->id,
+						  stream->frame_idx - 1, frm_addr_y,
+						  (u32)stream->next_buf_toisp->dummy.dma_addr);
+			}
+		}
+		if (stream->lack_buf_cnt)
+			stream->lack_buf_cnt--;
+	}
+	if (is_early_update) {
+		if (dev->rdbk_debug > 1 &&
+		    stream->frame_idx < 15)
+			v4l2_info(&dev->v4l2_dev,
+				  "stream[%d] early update, seq %d\n",
+				  stream->id,
+				  stream->frame_idx - 1);
+		if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+		    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY)
+			rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_CTRL, 0x00010000);
+		else
+			rkcif_write_register_or(dev, CIF_REG_DVP_CTRL, 0x00010000);
+		if (active_buf) {
+			active_buf->dbufs.sequence = stream->frame_idx - 1;
+			active_buf->dbufs.timestamp = stream->readout.fs_timestamp;
+			stream->last_frame_idx = stream->frame_idx;
+			rkcif_s_rx_buffer(dev, &active_buf->dbufs);
+		}
+		if (dev->hw_dev->dummy_buf.vaddr)
+			return;
+		if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+		    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+		    mbus_cfg->type == V4L2_MBUS_CCP2) {
+			frm_addr_y = frame_phase_next & CIF_CSI_FRAME0_READY ?
+			     get_reg_index_of_frm0_y_addr(stream->id) :
+			     get_reg_index_of_frm1_y_addr(stream->id);
+		} else {
+			frm_addr_y = frame_phase_next & CIF_CSI_FRAME0_READY ?
+				     get_dvp_reg_index_of_frm0_y_addr(stream->id) :
+				     get_dvp_reg_index_of_frm1_y_addr(stream->id);
+		}
+		if (frame_phase == CIF_CSI_FRAME0_READY)
+			stream->next_buf_toisp = stream->curr_buf_toisp;
+		else
+			stream->curr_buf_toisp = stream->next_buf_toisp;
+		buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr;
+		if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0,
+								buff_addr_y, 0, false);
+		} else {
+			rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+		}
+	}
 }
 
 static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream,
@@ -1285,11 +2299,13 @@
 	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
 	u32 frm0_addr_y, frm0_addr_uv;
 	u32 frm1_addr_y, frm1_addr_uv;
+	u32 buff_addr_y, buff_addr_cbcr;
 	unsigned long flags;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 	struct csi_channel_info *channel = &dev->channels[channel_id];
 
-	if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
 	    mbus_cfg->type == V4L2_MBUS_CCP2) {
 		frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id);
 		frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id);
@@ -1309,53 +2325,117 @@
 			stream->curr_buf = list_first_entry(&stream->buf_head,
 							    struct rkcif_buffer,
 							    queue);
+			v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "%s %d, stream[%d] buf idx %d\n",
+				 __func__, __LINE__, stream->id, stream->curr_buf->vb.vb2_buf.index);
 			list_del(&stream->curr_buf->queue);
 		}
 	}
 
 	if (stream->curr_buf) {
-		rkcif_write_register(dev, frm0_addr_y,
-				     stream->curr_buf->buff_addr[RKCIF_PLANE_Y]);
-		if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-			rkcif_write_register(dev, frm0_addr_uv,
-					     stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]);
+		buff_addr_y = stream->curr_buf->buff_addr[RKCIF_PLANE_Y];
+		buff_addr_cbcr = stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR];
+		if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream,
+								frm0_addr_y,
+								frm0_addr_uv,
+								buff_addr_y,
+								buff_addr_cbcr,
+								false);
+		} else {
+			rkcif_write_register(dev, frm0_addr_y,
+					     stream->curr_buf->buff_addr[RKCIF_PLANE_Y]);
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm0_addr_uv,
+						     stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]);
+		}
 	} else {
 		if (dummy_buf->vaddr) {
-			rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr);
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr);
+			buff_addr_y = dummy_buf->dma_addr;
+			buff_addr_cbcr = dummy_buf->dma_addr;
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm0_addr_y,
+									frm0_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									true);
+			} else {
+				rkcif_write_register(dev, frm0_addr_y, buff_addr_y);
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm0_addr_uv, buff_addr_cbcr);
+			}
+		} else {
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
 		}
 	}
 
 	if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
 		stream->next_buf = stream->curr_buf;
 		if (stream->next_buf) {
-			rkcif_write_register(dev, frm1_addr_y,
-					     stream->next_buf->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2));
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm1_addr_uv,
-						     stream->next_buf->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2));
+			buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y];
+			buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR];
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm1_addr_y,
+									frm1_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									false);
+			} else {
+				rkcif_write_register(dev, frm1_addr_y,
+						     buff_addr_y + (channel->virtual_width / 2));
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm1_addr_uv,
+							     buff_addr_cbcr + (channel->virtual_width / 2));
+			}
 		}
 	} else {
 		if (!stream->next_buf) {
 			if (!list_empty(&stream->buf_head)) {
 				stream->next_buf = list_first_entry(&stream->buf_head,
 								    struct rkcif_buffer, queue);
+				v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "%s %d, stream[%d] buf idx %d\n",
+					 __func__, __LINE__, stream->id, stream->next_buf->vb.vb2_buf.index);
 				list_del(&stream->next_buf->queue);
 			}
 		}
 
-		if (stream->next_buf) {
-			rkcif_write_register(dev, frm1_addr_y,
-					     stream->next_buf->buff_addr[RKCIF_PLANE_Y]);
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm1_addr_uv,
-						     stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]);
-		} else {
-			if (dummy_buf->vaddr) {
+		if (!stream->next_buf && dummy_buf->vaddr) {
+			buff_addr_y = dummy_buf->dma_addr;
+			buff_addr_cbcr = dummy_buf->dma_addr;
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm1_addr_y,
+									frm1_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									true);
+			} else {
 				rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr);
 				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
 					rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr);
+			}
+
+		} else if (!stream->next_buf && stream->curr_buf) {
+			stream->next_buf = stream->curr_buf;
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
+		}
+		if (stream->next_buf) {
+			buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y];
+			buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR];
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm1_addr_y,
+									frm1_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									false);
+			} else {
+				rkcif_write_register(dev, frm1_addr_y, buff_addr_y);
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm1_addr_uv, buff_addr_cbcr);
 			}
 		}
 	}
@@ -1388,22 +2468,26 @@
 			}
 		}
 	}
-
+	stream->buf_owner = RKCIF_DMAEN_BY_VICAP;
 }
 
 static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
-					   int channel_id)
+					  int channel_id)
 {
 	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
 	struct rkcif_buffer *buffer = NULL;
 	u32 frm_addr_y, frm_addr_uv;
 	struct csi_channel_info *channel = &dev->channels[channel_id];
+	struct rkisp_rx_buf *dbufs = NULL;
+	struct dma_buf *dbuf = NULL;
 	int ret = 0;
+	u32 buff_addr_y, buff_addr_cbcr;
 	unsigned long flags;
 
-	if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
 	    mbus_cfg->type == V4L2_MBUS_CCP2) {
 		frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
 			     get_reg_index_of_frm0_y_addr(channel_id) :
@@ -1420,20 +2504,43 @@
 			      get_dvp_reg_index_of_frm1_uv_addr(channel_id);
 	}
 
+	if (stream->to_stop_dma) {
+		if (stream->dma_en & RKCIF_DMAEN_BY_ISP) {
+			v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s %d\n", __func__, __LINE__);
+			goto stop_dma;
+		} else {
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY)
+				stream->curr_buf = NULL;
+			else
+				stream->next_buf = NULL;
+			v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s %d\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+	}
+
 	spin_lock_irqsave(&stream->vbq_lock, flags);
 	if (!list_empty(&stream->buf_head)) {
+
 		if (!dummy_buf->vaddr &&
 		    stream->curr_buf == stream->next_buf &&
 		    stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED)
 			ret = -EINVAL;
+
 		if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+			if (!stream->curr_buf)
+				ret = -EINVAL;
 			stream->curr_buf = list_first_entry(&stream->buf_head,
 							    struct rkcif_buffer, queue);
 			if (stream->curr_buf) {
 				list_del(&stream->curr_buf->queue);
 				buffer = stream->curr_buf;
+				v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+					 "stream[%d] update curr_buf 0x%x, buf idx %d\n",
+					 stream->id, buffer->buff_addr[0], stream->curr_buf->vb.vb2_buf.index);
 			}
 		} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
+			if (!stream->next_buf)
+				ret = -EINVAL;
 			if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
 				if (stream->next_buf != stream->curr_buf) {
 					stream->next_buf = stream->curr_buf;
@@ -1448,14 +2555,17 @@
 				if (stream->next_buf) {
 					list_del(&stream->next_buf->queue);
 					buffer = stream->next_buf;
+					v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+						 "stream[%d] update next_buf 0x%x, buf idx %d\n",
+						 stream->id, buffer->buff_addr[0], stream->next_buf->vb.vb2_buf.index);
 				}
 			}
 		}
-	} else {
+	} else if (!(stream->dma_en & RKCIF_DMAEN_BY_ISP)) {
 		buffer = NULL;
 		if (dummy_buf->vaddr) {
 			if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
-				stream->curr_buf = NULL;
+				stream->curr_buf  = NULL;
 			} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
 				if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
 					stream->next_buf = stream->curr_buf;
@@ -1464,7 +2574,8 @@
 					stream->next_buf = NULL;
 				}
 			}
-		} else if (stream->curr_buf != stream->next_buf) {
+		} else if (stream->curr_buf && stream->next_buf &&
+			   stream->curr_buf != stream->next_buf) {
 			if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
 				stream->curr_buf = stream->next_buf;
 				buffer = stream->next_buf;
@@ -1472,49 +2583,175 @@
 				stream->next_buf = stream->curr_buf;
 				buffer = stream->curr_buf;
 			}
-
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
+		} else {
+			stream->curr_buf = NULL;
+			stream->next_buf = NULL;
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
 		}
-
 	}
 	stream->frame_phase_cache = stream->frame_phase;
-	spin_unlock_irqrestore(&stream->vbq_lock, flags);
 
 	if (buffer) {
+		buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y];
+		buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR];
 		if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED &&
 		    stream->frame_phase == CIF_CSI_FRAME1_READY) {
-			rkcif_write_register(dev, frm_addr_y,
-					     buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2));
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm_addr_uv,
-						     buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2));
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm_addr_y,
+									frm_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									false);
+			} else {
+				rkcif_write_register(dev, frm_addr_y,
+						     buff_addr_y + (channel->virtual_width / 2));
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm_addr_uv,
+							     buff_addr_cbcr + (channel->virtual_width / 2));
+			}
 		} else {
-			rkcif_write_register(dev, frm_addr_y,
-					     buffer->buff_addr[RKCIF_PLANE_Y]);
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm_addr_uv,
-						     buffer->buff_addr[RKCIF_PLANE_CBCR]);
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm_addr_y,
+									frm_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									false);
+			} else {
+				rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr);
+			}
+		}
+		if (stream->dma_en & RKCIF_DMAEN_BY_ISP) {
+			if (stream->buf_replace_cnt < 2)
+				stream->buf_replace_cnt++;
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY &&
+			    stream->next_buf)
+				dbuf = stream->next_buf->dbuf;
+			else if (stream->frame_phase == CIF_CSI_FRAME1_READY &&
+				 stream->curr_buf)
+				dbuf = stream->curr_buf->dbuf;
+
+			if (dbuf) {
+				list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) {
+					if (dbufs->dbuf == dbuf)
+						break;
+				}
+			}
+			if (dbufs)
+				rkcif_s_rx_buffer(dev, dbufs);
 		}
 	} else {
-		if (dummy_buf->vaddr) {
-			rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr);
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr);
+		if (stream->dma_en & RKCIF_DMAEN_BY_ISP) {
+			buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr;
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE)
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm_addr_y, 0,
+									buff_addr_y, 0, false);
+			else
+				rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY &&
+			    stream->next_buf)
+				dbuf = stream->next_buf->dbuf;
+			else if (stream->frame_phase == CIF_CSI_FRAME1_READY &&
+				 stream->curr_buf)
+				dbuf = stream->curr_buf->dbuf;
+
+			if (dbuf) {
+				list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list)
+					if (dbufs->dbuf == dbuf)
+						break;
+			} else {
+				dbufs = &stream->curr_buf_toisp->dbufs;
+			}
+			rkcif_s_rx_buffer(dev, dbufs);
+			if (stream->curr_buf && stream->frame_phase == CIF_CSI_FRAME0_READY) {
+				stream->curr_buf = NULL;
+				if (stream->buf_replace_cnt)
+					stream->buf_replace_cnt--;
+			} else if (stream->next_buf && stream->frame_phase == CIF_CSI_FRAME1_READY) {
+				stream->next_buf = NULL;
+				if (stream->buf_replace_cnt)
+					stream->buf_replace_cnt--;
+			}
+		} else if (dummy_buf->vaddr) {
+
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				buff_addr_y = dummy_buf->dma_addr;
+				buff_addr_cbcr = dummy_buf->dma_addr;
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm_addr_y,
+									frm_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									true);
+			} else {
+				rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr);
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr);
+			}
+			dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id);
+			dev->irq_stats.not_active_buf_cnt[stream->id]++;
+
 		} else {
 			ret = -EINVAL;
+			stream->curr_buf = NULL;
+			stream->next_buf = NULL;
+			dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id);
+			dev->irq_stats.not_active_buf_cnt[stream->id]++;
 		}
-		v4l2_info(&dev->v4l2_dev,
-			 "not active buffer, skip current frame, %s stream[%d]\n",
-			 (mbus_cfg->type == V4L2_MBUS_CSI2 ||
-			  mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp",
-			  stream->id);
 	}
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
 	return ret;
+stop_dma:
+	if (stream->buf_replace_cnt) {
+		spin_lock_irqsave(&stream->vbq_lock, flags);
+		buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr;
+		if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE)
+			rkcif_write_buff_addr_multi_dev_combine(stream,
+								frm_addr_y, 0,
+								buff_addr_y, 0, false);
+		else
+			rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+		if (stream->frame_phase == CIF_CSI_FRAME0_READY &&
+		    stream->next_buf)
+			dbuf = stream->next_buf->dbuf;
+		else if (stream->frame_phase == CIF_CSI_FRAME1_READY &&
+			 stream->curr_buf)
+			dbuf = stream->curr_buf->dbuf;
+
+		if (dbuf) {
+			list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list)
+				if (dbufs->dbuf == dbuf)
+					break;
+		} else {
+			dbufs = &stream->curr_buf_toisp->dbufs;
+		}
+		if (dbufs)
+			rkcif_s_rx_buffer(dev, dbufs);
+
+		if (stream->frame_phase == CIF_CSI_FRAME0_READY &&
+		    stream->curr_buf) {
+			stream->curr_buf = NULL;
+		} else if (stream->frame_phase == CIF_CSI_FRAME1_READY &&
+			   stream->next_buf) {
+			stream->next_buf = NULL;
+		}
+		stream->buf_replace_cnt--;
+		spin_unlock_irqrestore(&stream->vbq_lock, flags);
+	}
+	return -EINVAL;
 }
 
 static int rkcif_get_new_buffer_wake_up_mode(struct rkcif_stream *stream)
 {
 	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 	int ret = 0;
 	unsigned long flags;
 
@@ -1535,6 +2772,8 @@
 				list_del(&stream->next_buf->queue);
 		}
 		stream->is_buf_active = true;
+		if (stream->lack_buf_cnt)
+			stream->lack_buf_cnt--;
 	} else {
 		stream->is_buf_active = false;
 		if (dummy_buf->vaddr) {
@@ -1551,8 +2790,15 @@
 				stream->frame_phase_cache = CIF_CSI_FRAME1_READY;
 			}
 			stream->is_buf_active = true;
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
 		} else {
-			ret = -EINVAL;
+			if (dev->chip_id < CHIP_RK3588_CIF)
+				ret = -EINVAL;
+			else
+				ret = 0;
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
 		}
 	}
 	spin_unlock_irqrestore(&stream->vbq_lock, flags);
@@ -1563,15 +2809,18 @@
 static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream)
 {
 	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info;
 	struct rkcif_buffer *buffer = NULL;
 	u32 frm_addr_y, frm_addr_uv;
+	u32 buff_addr_y, buff_addr_cbcr;
 	int channel_id = stream->id;
 	int ret = 0;
 	unsigned long flags;
 
-	if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
 	    mbus_cfg->type == V4L2_MBUS_CCP2) {
 		frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
 			     get_reg_index_of_frm0_y_addr(channel_id) :
@@ -1596,25 +2845,122 @@
 	}
 	spin_unlock_irqrestore(&stream->vbq_lock, flags);
 	if (buffer) {
-		rkcif_write_register(dev, frm_addr_y,
-				     buffer->buff_addr[RKCIF_PLANE_Y]);
-		if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-			rkcif_write_register(dev, frm_addr_uv,
-					     buffer->buff_addr[RKCIF_PLANE_CBCR]);
+		buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y];
+		buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR];
+		if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y,
+								frm_addr_uv,
+								buff_addr_y,
+								buff_addr_cbcr,
+								false);
+		} else {
+			rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr);
+		}
 	} else {
 		if (dummy_buf->vaddr) {
-			rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr);
-			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-				rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr);
+			buff_addr_y = dummy_buf->dma_addr;
+			buff_addr_cbcr = dummy_buf->dma_addr;
+			if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				rkcif_write_buff_addr_multi_dev_combine(stream,
+									frm_addr_y,
+									frm_addr_uv,
+									buff_addr_y,
+									buff_addr_cbcr,
+									true);
+			} else {
+				rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr);
+			}
+		} else {
+			if (dev->chip_id < CHIP_RK3588_CIF)
+				ret = -EINVAL;
+			else
+				ret = 0;
+		}
+		dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id);
+		dev->irq_stats.not_active_buf_cnt[stream->id]++;
+	}
+
+	return ret;
+}
+
+static int rkcif_get_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream)
+{
+	struct rkcif_rx_buffer *buffer = NULL;
+	struct rkcif_device *dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	int ret = 0;
+	unsigned long flags;
+	u32 frm_addr_y;
+	int frame_phase = 0;
+
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+	if (!list_empty(&stream->rx_buf_head)) {
+		if (stream->line_int_cnt % 2) {
+			buffer = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (buffer) {
+				list_del(&buffer->list);
+				stream->curr_buf_toisp = buffer;
+			}
+			frame_phase = CIF_CSI_FRAME0_READY;
+		} else {
+			buffer = list_first_entry(&stream->rx_buf_head,
+						 struct rkcif_rx_buffer, list);
+			if (buffer) {
+				list_del(&buffer->list);
+				stream->next_buf_toisp = buffer;
+			}
+			frame_phase = CIF_CSI_FRAME1_READY;
+		}
+		if (stream->lack_buf_cnt)
+			stream->lack_buf_cnt--;
+	} else {
+		if (stream->lack_buf_cnt < 2)
+			stream->lack_buf_cnt++;
+		if (stream->curr_buf_toisp && stream->next_buf_toisp &&
+		    stream->curr_buf_toisp != stream->next_buf_toisp) {
+			if (stream->line_int_cnt % 2)
+				stream->curr_buf_toisp = stream->next_buf_toisp;
+			else
+				stream->next_buf_toisp = stream->curr_buf_toisp;
+			buffer = stream->curr_buf_toisp;
+			ret = 0;
+			if (stream->cifdev->rdbk_debug)
+				v4l2_info(&stream->cifdev->v4l2_dev,
+					  "stream[%d] hold buf %x\n",
+					  stream->id,
+					  (u32)stream->next_buf_toisp->dummy.dma_addr);
 		} else {
 			ret = -EINVAL;
 		}
-		v4l2_info(&dev->v4l2_dev,
-			 "not active buffer, skip current frame, %s stream[%d]\n",
-			 (mbus_cfg->type == V4L2_MBUS_CSI2 ||
-			  mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp",
-			  stream->id);
 	}
+	if (buffer) {
+		if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+		    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+		    mbus_cfg->type == V4L2_MBUS_CCP2) {
+			frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ?
+				     get_reg_index_of_frm0_y_addr(stream->id) :
+				     get_reg_index_of_frm1_y_addr(stream->id);
+		} else {
+			frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ?
+				     get_dvp_reg_index_of_frm0_y_addr(stream->id) :
+				     get_dvp_reg_index_of_frm1_y_addr(stream->id);
+		}
+		rkcif_write_register(dev, frm_addr_y,
+				     buffer->dummy.dma_addr);
+		if (dev->rdbk_debug > 1 &&
+		    stream->frame_idx < 15)
+			v4l2_info(&dev->v4l2_dev,
+				  "stream[%d] rdbk update, seq %d, reg %x, buf %x\n",
+				  stream->id,
+				  stream->frame_idx - 1,
+				  frm_addr_y, (u32)buffer->dummy.dma_addr);
+	}
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
 
 	return ret;
 }
@@ -1623,7 +2969,7 @@
 {
 	struct rkcif_device *dev = stream->cifdev;
 	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 	unsigned long flags;
 
 	spin_lock_irqsave(&stream->vbq_lock, flags);
@@ -1658,6 +3004,276 @@
 		rkcif_assign_new_buffer_init(stream, channel_id);
 	else
 		ret = rkcif_assign_new_buffer_update(stream, channel_id);
+	return ret;
+}
+
+static void rkcif_assign_new_buffer_init_rockit(struct rkcif_stream *stream,
+							  int channel_id)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	u32 frm0_addr_y, frm0_addr_uv;
+	u32 frm1_addr_y, frm1_addr_uv;
+	unsigned long flags;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
+	struct csi_channel_info *channel = &dev->channels[channel_id];
+
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CCP2) {
+		frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id);
+		frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id);
+		frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id);
+		frm1_addr_uv = get_reg_index_of_frm1_uv_addr(channel_id);
+	} else {
+		frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id);
+		frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(channel_id);
+		frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id);
+		frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id);
+	}
+
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+
+	if (!stream->curr_buf_rockit) {
+		if (!list_empty(&stream->rockit_buf_head)) {
+			stream->curr_buf_rockit = list_first_entry(&stream->rockit_buf_head,
+							    struct rkcif_buffer,
+							    queue);
+			list_del(&stream->curr_buf_rockit->queue);
+		}
+	}
+
+	if (stream->curr_buf_rockit) {
+		rkcif_write_register(dev, frm0_addr_y,
+				     stream->curr_buf_rockit->buff_addr[RKCIF_PLANE_Y]);
+		if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+			rkcif_write_register(dev, frm0_addr_uv,
+					     stream->curr_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]);
+	} else {
+		if (dummy_buf->vaddr) {
+			rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr);
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr);
+		} else {
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
+		}
+	}
+
+	if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
+		stream->next_buf_rockit = stream->curr_buf_rockit;
+		if (stream->next_buf_rockit) {
+			rkcif_write_register(dev, frm1_addr_y,
+					     stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2));
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm1_addr_uv,
+						     stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2));
+		}
+	} else {
+		if (!stream->next_buf_rockit) {
+			if (!list_empty(&stream->rockit_buf_head)) {
+				stream->next_buf_rockit = list_first_entry(&stream->rockit_buf_head,
+								    struct rkcif_buffer, queue);
+				list_del(&stream->next_buf_rockit->queue);
+			}
+		}
+
+		if (stream->next_buf_rockit) {
+			rkcif_write_register(dev, frm1_addr_y,
+					     stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y]);
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm1_addr_uv,
+						     stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]);
+		} else {
+			if (dummy_buf->vaddr) {
+				rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr);
+				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+					rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr);
+			} else {
+				if (stream->curr_buf_rockit) {
+					stream->next_buf_rockit = stream->curr_buf_rockit;
+					rkcif_write_register(dev, frm1_addr_y,
+							     stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y]);
+					if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+						rkcif_write_register(dev, frm1_addr_uv,
+								     stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]);
+				}
+				if (stream->lack_buf_cnt < 2)
+					stream->lack_buf_cnt++;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+
+	stream->is_dvp_yuv_addr_init = true;
+
+	/* for BT.656/BT.1120 multi channels function,
+	 * yuv addr of unused channel must be set
+	 */
+	if (mbus_cfg->type == V4L2_MBUS_BT656) {
+		int ch_id;
+
+		for (ch_id = 0; ch_id < RKCIF_MAX_STREAM_DVP; ch_id++) {
+			if (dev->stream[ch_id].is_dvp_yuv_addr_init)
+				continue;
+			if (dummy_buf->dma_addr) {
+				rkcif_write_register(dev,
+						     get_dvp_reg_index_of_frm0_y_addr(ch_id),
+						     dummy_buf->dma_addr);
+				rkcif_write_register(dev,
+						     get_dvp_reg_index_of_frm0_uv_addr(ch_id),
+						     dummy_buf->dma_addr);
+				rkcif_write_register(dev,
+						     get_dvp_reg_index_of_frm1_y_addr(ch_id),
+						     dummy_buf->dma_addr);
+				rkcif_write_register(dev,
+						     get_dvp_reg_index_of_frm1_uv_addr(ch_id),
+						     dummy_buf->dma_addr);
+			}
+		}
+	}
+	stream->buf_owner = RKCIF_DMAEN_BY_ROCKIT;
+}
+
+static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream,
+							    int channel_id)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	struct rkcif_buffer *buffer = NULL;
+	u32 frm_addr_y, frm_addr_uv;
+	struct csi_channel_info *channel = &dev->channels[channel_id];
+	int ret = 0;
+	unsigned long flags;
+
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CCP2) {
+		frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			     get_reg_index_of_frm0_y_addr(channel_id) :
+			     get_reg_index_of_frm1_y_addr(channel_id);
+		frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			      get_reg_index_of_frm0_uv_addr(channel_id) :
+			      get_reg_index_of_frm1_uv_addr(channel_id);
+	} else {
+		frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			     get_dvp_reg_index_of_frm0_y_addr(channel_id) :
+			     get_dvp_reg_index_of_frm1_y_addr(channel_id);
+		frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ?
+			      get_dvp_reg_index_of_frm0_uv_addr(channel_id) :
+			      get_dvp_reg_index_of_frm1_uv_addr(channel_id);
+	}
+
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+	if (!list_empty(&stream->rockit_buf_head)) {
+
+		if (!dummy_buf->vaddr &&
+		    stream->curr_buf_rockit == stream->next_buf_rockit &&
+		    stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED)
+			ret = -EINVAL;
+
+		if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+			if (!stream->curr_buf_rockit)
+				ret = -EINVAL;
+			stream->curr_buf_rockit = list_first_entry(&stream->rockit_buf_head,
+							    struct rkcif_buffer, queue);
+			if (stream->curr_buf_rockit) {
+				list_del(&stream->curr_buf_rockit->queue);
+				buffer = stream->curr_buf_rockit;
+			}
+		} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
+			if (!stream->next_buf_rockit)
+				ret = -EINVAL;
+			if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
+				if (stream->next_buf_rockit != stream->curr_buf_rockit) {
+					stream->next_buf_rockit = stream->curr_buf_rockit;
+					buffer = stream->next_buf_rockit;
+				} else {
+					buffer = NULL;
+				}
+
+			} else {
+				stream->next_buf_rockit = list_first_entry(&stream->rockit_buf_head,
+								    struct rkcif_buffer, queue);
+				if (stream->next_buf_rockit) {
+					list_del(&stream->next_buf_rockit->queue);
+					buffer = stream->next_buf_rockit;
+				}
+			}
+		}
+	} else {
+		buffer = NULL;
+		if (dummy_buf->vaddr) {
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+				stream->curr_buf_rockit  = NULL;
+			} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
+				if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
+					stream->next_buf_rockit = stream->curr_buf_rockit;
+					buffer = stream->next_buf_rockit;
+				} else {
+					stream->next_buf_rockit = NULL;
+				}
+			}
+		} else if (stream->curr_buf_rockit && stream->next_buf_rockit &&
+			   stream->curr_buf_rockit != stream->next_buf_rockit) {
+			if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
+				stream->curr_buf_rockit = stream->next_buf_rockit;
+				buffer = stream->next_buf_rockit;
+			} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
+				stream->next_buf_rockit = stream->curr_buf_rockit;
+				buffer = stream->curr_buf_rockit;
+			}
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
+		} else {
+			if (stream->lack_buf_cnt < 2)
+				stream->lack_buf_cnt++;
+		}
+	}
+	stream->frame_phase_cache = stream->frame_phase;
+
+	if (buffer) {
+		if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED &&
+		    stream->frame_phase == CIF_CSI_FRAME1_READY) {
+			rkcif_write_register(dev, frm_addr_y,
+					     buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2));
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm_addr_uv,
+						     buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2));
+		} else {
+			rkcif_write_register(dev, frm_addr_y,
+					     buffer->buff_addr[RKCIF_PLANE_Y]);
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm_addr_uv,
+						     buffer->buff_addr[RKCIF_PLANE_CBCR]);
+		}
+	} else {
+		if (dummy_buf->vaddr) {
+			rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr);
+			if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+				rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr);
+			dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id);
+			dev->irq_stats.not_active_buf_cnt[stream->id]++;
+		} else {
+			ret = -EINVAL;
+			dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id);
+			dev->irq_stats.not_active_buf_cnt[stream->id]++;
+		}
+	}
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+	return ret;
+}
+
+static int rkcif_assign_new_buffer_pingpong_rockit(struct rkcif_stream *stream,
+					     int init, int channel_id)
+{
+	int ret = 0;
+
+	if (init)
+		rkcif_assign_new_buffer_init_rockit(stream, channel_id);
+	else
+		ret = rkcif_assign_new_buffer_update_rockit(stream, channel_id);
 	return ret;
 }
 
@@ -1709,7 +3325,7 @@
 	struct rkmodule_lvds_frm_sync_code *odd_sync_code = NULL;
 	struct rkmodule_lvds_frm_sync_code *even_sync_code = NULL;
 
-	if (dev->hdr.mode == NO_HDR) {
+	if (dev->hdr.hdr_mode == NO_HDR || dev->hdr.hdr_mode == HDR_COMPR) {
 		frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LINEAR];
 		odd_sync_code = &frm_sync_code->odd_sync_code;
 		even_sync_code = odd_sync_code;
@@ -1717,12 +3333,12 @@
 		if (channel->id == RKCIF_STREAM_MIPI_ID0)
 			frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LONG];
 
-		if (dev->hdr.mode == HDR_X2) {
+		if (dev->hdr.hdr_mode == HDR_X2) {
 			if (channel->id == RKCIF_STREAM_MIPI_ID1)
 				frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_SHORT];
 			else
 				frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LONG];
-		} else if (dev->hdr.mode == HDR_X3) {
+		} else if (dev->hdr.hdr_mode == HDR_X3) {
 			if (channel->id == RKCIF_STREAM_MIPI_ID1)
 				frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_MEDIUM];
 			else if (channel->id == RKCIF_STREAM_MIPI_ID2)
@@ -1758,12 +3374,44 @@
 	}
 }
 
+static unsigned char get_csi_fmt_val(const struct cif_input_fmt	*cif_fmt_in,
+				     struct csi_channel_info *csi_info)
+{
+	unsigned char csi_fmt_val = 0;
+
+	if (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 ||
+	    cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8) {
+		switch (csi_info->data_bit) {
+		case 8:
+			csi_fmt_val = CSI_WRDDR_TYPE_RAW8;
+			break;
+		case 10:
+			csi_fmt_val = CSI_WRDDR_TYPE_RAW10;
+			break;
+		case 12:
+			csi_fmt_val = CSI_WRDDR_TYPE_RAW12;
+			break;
+		default:
+			csi_fmt_val = CSI_WRDDR_TYPE_RAW12;
+			break;
+		}
+	} else if (cif_fmt_in->csi_fmt_val == CSI_WRDDR_TYPE_RGB888 ||
+		   cif_fmt_in->csi_fmt_val == CSI_WRDDR_TYPE_RGB565) {
+		csi_fmt_val = CSI_WRDDR_TYPE_RAW8;
+	} else {
+		csi_fmt_val = cif_fmt_in->csi_fmt_val;
+	}
+	return csi_fmt_val;
+}
+
 static int rkcif_csi_channel_init(struct rkcif_stream *stream,
 				  struct csi_channel_info *channel)
 {
 	struct rkcif_device *dev = stream->cifdev;
+	struct sditf_priv *priv = dev->sditf[0];
 	const struct cif_output_fmt *fmt;
 	u32 fourcc;
+	int vc = dev->channels[stream->id].vc;
 
 	channel->enable = 1;
 	channel->width = stream->pixm.width;
@@ -1779,10 +3427,14 @@
 
 		if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888)
 			channel->crop_st_x = 3 * stream->crop[CROP_SRC_ACT].left;
+		else if (channel->fmt_val == CSI_WRDDR_TYPE_RGB565)
+			channel->crop_st_x = 2 * stream->crop[CROP_SRC_ACT].left;
 		else
 			channel->crop_st_x = stream->crop[CROP_SRC_ACT].left;
 
 		channel->crop_st_y = stream->crop[CROP_SRC_ACT].top;
+		if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF)
+			channel->crop_st_y *= dev->sditf_cnt;
 		channel->width = stream->crop[CROP_SRC_ACT].width;
 		channel->height = stream->crop[CROP_SRC_ACT].height;
 	} else {
@@ -1791,13 +3443,18 @@
 		channel->crop_en = 0;
 	}
 
-	fmt = find_output_fmt(stream, stream->pixm.pixelformat);
+	if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF)
+		channel->height *= dev->sditf_cnt;
+
+	fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat);
 	if (!fmt) {
 		v4l2_err(&dev->v4l2_dev, "can not find output format: 0x%x",
 			 stream->pixm.pixelformat);
 		return -EINVAL;
 	}
 
+	if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE)
+		channel->width /=  channel->capture_info.multi_dev.dev_num;
 	/*
 	 * for mipi or lvds, when enable compact, the virtual width of raw10/raw12
 	 * needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode
@@ -1805,13 +3462,24 @@
 	 * writing of ddr, aliged with 256
 	 */
 	if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact &&
-	    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888) {
-		channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256);
+	    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 &&
+	    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) {
+		if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			channel->virtual_width = ALIGN(channel->width * 2 * fmt->raw_bpp / 8, 256);
+			channel->left_virtual_width = channel->width * fmt->raw_bpp / 8;
+		} else {
+			channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256);
+		}
 	} else {
-		channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8);
+		if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			channel->virtual_width = ALIGN(channel->width * 2 * fmt->bpp[0] / 8, 8);
+			channel->left_virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8);
+		} else {
+			channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8);
+		}
 	}
 
-	if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888)
+	if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565)
 		channel->width = channel->width * fmt->bpp[0] / 8;
 	/*
 	 * rk cif don't support output yuyv fmt data
@@ -1819,36 +3487,53 @@
 	 * and the width is double Because the real input fmt is
 	 * yuyv
 	 */
-	fourcc  = stream->cif_fmt_out->fourcc;
+	fourcc = stream->cif_fmt_out->fourcc;
 	if (fourcc == V4L2_PIX_FMT_YUYV || fourcc == V4L2_PIX_FMT_YVYU ||
 	    fourcc == V4L2_PIX_FMT_UYVY || fourcc == V4L2_PIX_FMT_VYUY) {
-		channel->fmt_val = CSI_WRDDR_TYPE_RAW8;
-		channel->width *= 2;
+		if (dev->chip_id < CHIP_RK3588_CIF) {
+			channel->fmt_val = CSI_WRDDR_TYPE_RAW8;
+			channel->width *= 2;
+		}
 		channel->virtual_width *= 2;
+		if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE)
+			channel->left_virtual_width *= 2;
 	}
 	if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
 		channel->virtual_width *= 2;
 		channel->height /= 2;
 	}
+	if (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 ||
+	    stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8) {
+		if (dev->channels[stream->id].data_type)
+			channel->data_type = dev->channels[stream->id].data_type;
+		else
+			channel->data_type = get_data_type(stream->cif_fmt_in->mbus_code,
+							   channel->cmd_mode_en,
+							   channel->dsi_input);
+	} else {
+		channel->data_type = get_data_type(stream->cif_fmt_in->mbus_code,
+						   channel->cmd_mode_en,
+						   channel->dsi_input);
+	}
+	channel->csi_fmt_val = get_csi_fmt_val(stream->cif_fmt_in,
+					       &dev->channels[stream->id]);
 
-	channel->data_type = get_data_type(stream->cif_fmt_in->mbus_code,
-					   channel->cmd_mode_en, channel->dsi_input);
-
-	if ((dev->hdr.mode == NO_HDR && stream->vc >= 0) ||
-	    (dev->hdr.mode == HDR_X2 && stream->vc > 1) ||
-	    (dev->hdr.mode == HDR_X3 && stream->vc > 2))
-		channel->vc = stream->vc;
+	if (dev->hdr.hdr_mode == NO_HDR ||
+	    dev->hdr.hdr_mode == HDR_COMPR ||
+	    (dev->hdr.hdr_mode == HDR_X2 && stream->id > 1) ||
+	    (dev->hdr.hdr_mode == HDR_X3 && stream->id > 2))
+		channel->vc = vc < 4 ? vc : channel->id;
 	else
 		channel->vc = channel->id;
-	v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+	v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
 		 "%s: channel width %d, height %d, virtual_width %d, vc %d\n", __func__,
 		 channel->width, channel->height, channel->virtual_width, channel->vc);
 	return 0;
 }
 
 static int rkcif_csi_channel_set(struct rkcif_stream *stream,
-				       struct csi_channel_info *channel,
-				       enum v4l2_mbus_type mbus_type)
+				 struct csi_channel_info *channel,
+				 enum v4l2_mbus_type mbus_type)
 {
 	unsigned int val = 0x0;
 	struct rkcif_device *dev = stream->cifdev;
@@ -1869,10 +3554,9 @@
 				 CSI_DMA_END_INTSTAT(channel->id) |
 				 CSI_LINE_INTSTAT(channel->id)));
 
-	/* enable id0 frame start int for sof(long frame, for hdr) */
-	if (channel->id == RKCIF_STREAM_MIPI_ID0)
-		rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
-					CSI_START_INTEN(channel->id));
+	rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
+				CSI_START_INTEN(channel->id));
+
 	if (detect_stream->is_line_wake_up) {
 		rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
 					CSI_LINE_INTEN(channel->id));
@@ -1891,15 +3575,15 @@
 			     CIF_MIPI_LVDS_SW_HURRY_VALUE_RK1808(0x3) |
 			     CIF_MIPI_LVDS_SW_HURRY_ENABLE_RK1808);
 
-	val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x7) |
+	val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x3) |
 		CIF_MIPI_LVDS_SW_PRESS_ENABLE |
-		CIF_MIPI_LVDS_SW_HURRY_VALUE(0x7) |
+		CIF_MIPI_LVDS_SW_HURRY_VALUE(0x3) |
 		CIF_MIPI_LVDS_SW_HURRY_ENABLE |
 		CIF_MIPI_LVDS_SW_WATER_LINE_25 |
 		CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE;
-	if (mbus_type  == V4L2_MBUS_CSI2) {
+	if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
 		val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS;
-	} else if (mbus_type  == V4L2_MBUS_CCP2) {
+	} else if (mbus_type == V4L2_MBUS_CCP2) {
 		if (channel->fmt_val == CSI_WRDDR_TYPE_RAW12)
 			val |= CIF_MIPI_LVDS_SW_LVDS_WIDTH_12BITS;
 		else if (channel->fmt_val == CSI_WRDDR_TYPE_RAW10)
@@ -1934,7 +3618,7 @@
 					 RKCIF_YUV_ADDR_STATE_INIT,
 					 channel->id);
 
-	if (mbus_type  == V4L2_MBUS_CSI2) {
+	if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
 		//need always enable crop
 		val = CSI_ENABLE_CAPTURE | channel->fmt_val |
 		      channel->cmd_mode_en << 4 | CSI_ENABLE_CROP |
@@ -1946,7 +3630,7 @@
 
 		if (stream->cifdev->chip_id >= CHIP_RK3568_CIF)
 			val |= stream->cif_fmt_in->csi_yuv_order;
-	} else if (mbus_type  == V4L2_MBUS_CCP2) {
+	} else if (mbus_type == V4L2_MBUS_CCP2) {
 		rkcif_csi_set_lvds_sav_eav(stream, channel);
 		val = LVDS_ENABLE_CAPTURE | LVDS_MODE(channel->lvds_cfg.mode) |
 		      LVDS_MAIN_LANE(0) | LVDS_FID(0) |
@@ -1958,15 +3642,403 @@
 			val &= ~LVDS_COMPACT;
 	}
 	if (stream->is_high_align)
-		val |= CSI_ENABLE_MIPI_HIGH_ALIGN;
+		val |= CSI_HIGH_ALIGN;
 	else
-		val &= ~CSI_ENABLE_MIPI_HIGH_ALIGN;
+		val &= ~CSI_HIGH_ALIGN;
 	rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val);
 
 	return 0;
 }
 
-static int rkcif_csi_stream_start(struct rkcif_stream *stream)
+static int rkcif_dvp_get_input_yuv_order(struct rkcif_stream *stream)
+{
+	unsigned int mask;
+	const struct cif_input_fmt *fmt = stream->cif_fmt_in;
+
+	switch (fmt->mbus_code) {
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+		mask = CSI_YUV_INPUT_ORDER_UYVY >> 11;
+		break;
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+		mask = CSI_YUV_INPUT_ORDER_VYUY >> 11;
+		break;
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+		mask = CSI_YUV_INPUT_ORDER_YUYV >> 11;
+		break;
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+		mask = CSI_YUV_INPUT_ORDER_YVYU >> 11;
+		break;
+	default:
+		mask = CSI_YUV_INPUT_ORDER_UYVY >> 11;
+		break;
+	}
+	return mask;
+}
+
+static int rkcif_csi_get_output_type_mask(struct rkcif_stream *stream)
+{
+	unsigned int mask;
+	const struct cif_output_fmt *fmt = stream->cif_fmt_out;
+
+	switch (fmt->fourcc) {
+	case V4L2_PIX_FMT_NV16:
+		mask = CSI_WRDDR_TYPE_YUV422SP_RK3588 | CSI_YUV_OUTPUT_ORDER_UYVY;
+		break;
+	case V4L2_PIX_FMT_NV61:
+		mask = CSI_WRDDR_TYPE_YUV422SP_RK3588 | CSI_YUV_OUTPUT_ORDER_VYUY;
+		break;
+	case V4L2_PIX_FMT_NV12:
+		mask = CSI_WRDDR_TYPE_YUV420SP_RK3588 | CSI_YUV_OUTPUT_ORDER_UYVY;
+		break;
+	case V4L2_PIX_FMT_NV21:
+		mask = CSI_WRDDR_TYPE_YUV420SP_RK3588 | CSI_YUV_OUTPUT_ORDER_VYUY;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_YUYV;
+		break;
+	case V4L2_PIX_FMT_YVYU:
+		mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_YVYU;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_UYVY;
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_VYUY;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_BGR666:
+		mask = CSI_WRDDR_TYPE_RAW_COMPACT;
+		break;
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_Y10:
+	case V4L2_PIX_FMT_Y12:
+		if (stream->is_compact)
+			mask = CSI_WRDDR_TYPE_RAW_COMPACT;
+		else
+			mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT;
+		break;
+	case V4L2_PIX_FMT_SBGGR16:
+	case V4L2_PIX_FMT_SGBRG16:
+	case V4L2_PIX_FMT_SGRBG16:
+	case V4L2_PIX_FMT_SRGGB16:
+	case V4L2_PIX_FMT_Y16:
+		mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT;
+		break;
+	default:
+		mask = CSI_WRDDR_TYPE_RAW_COMPACT;
+		break;
+	}
+	return mask;
+}
+
+static int rkcif_lvds_get_output_type_mask(struct rkcif_stream *stream)
+{
+	unsigned int mask;
+	const struct cif_output_fmt *fmt = stream->cif_fmt_out;
+	int wr_type_offset = 0;
+	int yuvout_offset = 0;
+
+	if (stream->cifdev->chip_id == CHIP_RV1106_CIF) {
+		wr_type_offset = 17;
+		yuvout_offset = 9;
+	}
+
+	switch (fmt->fourcc) {
+	case V4L2_PIX_FMT_NV16:
+		mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_UYVY << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_NV61:
+		mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_VYUY << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_NV12:
+		mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_UYVY << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_NV21:
+		mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_VYUY << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_YUYV << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_YVYU:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_YVYU << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_UYVY << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) |
+			(CSI_YUV_OUTPUT_ORDER_VYUY << yuvout_offset);
+		break;
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_BGR666:
+		mask = CSI_WRDDR_TYPE_RAW_COMPACT << wr_type_offset;
+		break;
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_Y10:
+	case V4L2_PIX_FMT_Y12:
+		if (stream->is_compact)
+			mask = CSI_WRDDR_TYPE_RAW_COMPACT << wr_type_offset;
+		else
+			mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << wr_type_offset;
+		break;
+	case V4L2_PIX_FMT_SBGGR16:
+	case V4L2_PIX_FMT_SGBRG16:
+	case V4L2_PIX_FMT_SGRBG16:
+	case V4L2_PIX_FMT_SRGGB16:
+	case V4L2_PIX_FMT_Y16:
+		mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << wr_type_offset;
+		break;
+	default:
+		mask = CSI_WRDDR_TYPE_RAW_COMPACT << wr_type_offset;
+		break;
+	}
+	return mask;
+}
+
+static void rkcif_modify_frame_skip_config(struct rkcif_stream *stream)
+{
+	if (stream->skip_info.skip_to_en) {
+		rkcif_disable_skip_frame(stream);
+		rkcif_enable_skip_frame(stream,
+					stream->skip_info.cap_m,
+					stream->skip_info.skip_n);
+		stream->skip_info.skip_to_en = false;
+	} else if (stream->skip_info.skip_to_dis) {
+		rkcif_disable_skip_frame(stream);
+	}
+}
+
+/*config reg for rk3588*/
+static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream,
+				       struct csi_channel_info *channel,
+				       enum v4l2_mbus_type mbus_type, unsigned int mode,
+				       int index)
+{
+	unsigned int val = 0x0;
+	struct rkcif_device *dev = stream->cifdev;
+	struct rkcif_stream *detect_stream = &dev->stream[0];
+	struct sditf_priv *priv = dev->sditf[0];
+	struct rkmodule_capture_info *capture_info = &channel->capture_info;
+	unsigned int wait_line = 0x3fff;
+	unsigned int dma_en = 0;
+	int offset = 0;
+
+	if (channel->id >= 4)
+		return -EINVAL;
+
+	if (!channel->enable) {
+		rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id),
+				     CSI_DISABLE_CAPTURE);
+		return 0;
+	}
+
+	rkcif_write_register_and(dev, CIF_REG_MIPI_LVDS_INTSTAT,
+				 ~(CSI_START_INTSTAT(channel->id) |
+				 CSI_DMA_END_INTSTAT(channel->id) |
+				 CSI_LINE_INTSTAT_V1(channel->id)));
+
+	if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE &&
+	      index < capture_info->multi_dev.dev_num - 1)) {
+
+		rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
+					CSI_START_INTEN(channel->id));
+
+		if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) {
+			rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
+						CSI_LINE_INTEN_RK3588(channel->id));
+			wait_line = dev->wait_line;
+		}
+		rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1,
+				     wait_line << 16 | wait_line);
+		rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3,
+				     wait_line << 16 | wait_line);
+
+		rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
+					CSI_DMA_END_INTEN(channel->id));
+
+		rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
+					CSI_ALL_ERROR_INTEN_V1);
+	}
+	if (stream->cifdev->id_use_cnt == 0) {
+		val = CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(0x3) |
+			CIF_MIPI_LVDS_SW_PRESS_ENABLE |
+			CIF_MIPI_LVDS_SW_HURRY_VALUE_RK3588(0x3) |
+			CIF_MIPI_LVDS_SW_HURRY_ENABLE |
+			CIF_MIPI_LVDS_SW_WATER_LINE_25 |
+			CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE;
+		if (mbus_type == V4L2_MBUS_CSI2_DPHY ||
+		    mbus_type == V4L2_MBUS_CSI2_CPHY)
+			val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS_RV1106;
+		else
+			val |= CIF_MIPI_LVDS_SW_SEL_LVDS_RV1106;
+		rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val);
+	}
+#if IS_ENABLED(CONFIG_CPU_RV1106)
+	if (channel->id == 1)
+		rv1106_sdmmc_get_lock();
+#endif
+	if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE &&
+	    priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE &&
+	    (dev->hdr.hdr_mode == NO_HDR ||
+	     (dev->hdr.hdr_mode == HDR_X2 && stream->id == 1) ||
+	     (dev->hdr.hdr_mode == HDR_X3 && stream->id == 2)))
+		offset = channel->capture_info.multi_dev.pixel_offset;
+
+	rkcif_write_register(dev, get_reg_index_of_id_ctrl1(channel->id),
+			     (channel->width + offset) | (channel->height << 16));
+
+#if IS_ENABLED(CONFIG_CPU_RV1106)
+	if (channel->id == 1)
+		rv1106_sdmmc_put_lock();
+#endif
+
+	if (channel->crop_en)
+		rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id),
+				     channel->crop_st_y << 16 | channel->crop_st_x);
+
+	if (mode == RKCIF_STREAM_MODE_CAPTURE)
+		rkcif_assign_new_buffer_pingpong(stream,
+						 RKCIF_YUV_ADDR_STATE_INIT,
+						 channel->id);
+	else if (mode == RKCIF_STREAM_MODE_TOISP ||
+		 mode == RKCIF_STREAM_MODE_TOISP_RDBK)
+		rkcif_assign_new_buffer_pingpong_toisp(stream,
+						       RKCIF_YUV_ADDR_STATE_INIT,
+						       channel->id);
+	else if (mode == RKCIF_STREAM_MODE_ROCKIT)
+		rkcif_assign_new_buffer_pingpong_rockit(stream,
+							RKCIF_YUV_ADDR_STATE_INIT,
+							channel->id);
+
+	if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE &&
+	    index == (capture_info->multi_dev.dev_num - 1) &&
+	    priv && priv->mode.rdbk_mode != RKISP_VICAP_ONLINE)
+		rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id),
+				     channel->crop_st_y << 16 |
+				     (channel->crop_st_x + capture_info->multi_dev.pixel_offset));
+
+	rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id),
+			     channel->virtual_width);
+
+	if (stream->lack_buf_cnt == 2)
+		stream->dma_en = 0;
+
+	if (stream->dma_en) {
+		if (mbus_type == V4L2_MBUS_CSI2_DPHY ||
+		    mbus_type == V4L2_MBUS_CSI2_CPHY)
+			dma_en = CSI_DMA_ENABLE;
+		else
+			dma_en = LVDS_DMAEN_RV1106;
+	}
+	if (mbus_type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_type == V4L2_MBUS_CSI2_CPHY) {
+
+		if (stream->cifdev->hdr.esp.mode == HDR_LINE_CNT ||
+		    stream->cifdev->hdr.esp.mode == HDR_ID_CODE)
+			channel->vc = 0;
+
+		val = CSI_ENABLE_CAPTURE | dma_en |
+		      channel->cmd_mode_en << 26 | CSI_ENABLE_CROP_V1 |
+		      channel->vc << 8 | channel->data_type << 10 |
+		      channel->csi_fmt_val;
+
+		val |= stream->cif_fmt_in->csi_yuv_order;
+		val |= rkcif_csi_get_output_type_mask(stream);
+		if (stream->cifdev->hdr.hdr_mode == NO_HDR ||
+		    stream->cifdev->hdr.hdr_mode == HDR_COMPR)
+			val |= CSI_NO_HDR;
+		else if (stream->cifdev->hdr.hdr_mode == HDR_X2)
+			val |= CSI_HDR2;
+		else if (stream->cifdev->hdr.hdr_mode == HDR_X3)
+			val |= CSI_HDR3;
+		if (stream->cifdev->hdr.esp.mode == HDR_NORMAL_VC)
+			val |= CSI_HDR_MODE_VC;
+		else if (stream->cifdev->hdr.esp.mode == HDR_LINE_CNT)
+			val |= CSI_HDR_MODE_LINE_CNT;
+		else if (stream->cifdev->hdr.esp.mode == HDR_ID_CODE)
+			val |= CSI_HDR_MODE_LINE_INFO;
+		if (stream->cifdev->hdr.hdr_mode != NO_HDR &&
+		    stream->cifdev->hdr.esp.mode == HDR_NORMAL_VC)
+			val |= CSI_HDR_VC_MODE_PROTECT;
+		if (stream->is_high_align)
+			val |= CSI_HIGH_ALIGN_RK3588;
+		else
+			val &= ~CSI_HIGH_ALIGN_RK3588;
+		rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val);
+		rkcif_write_register(dev, CIF_REG_MIPI_EFFECT_CODE_ID0, 0x02410251);
+		rkcif_write_register(dev, CIF_REG_MIPI_EFFECT_CODE_ID1, 0x02420252);
+	} else if (mbus_type == V4L2_MBUS_CCP2) {
+		rkcif_csi_set_lvds_sav_eav(stream, channel);
+		val = LVDS_ENABLE_CAPTURE_RV1106 | LVDS_MODE_RV1106(channel->lvds_cfg.mode) |
+		      LVDS_MAIN_LANE_RV1106(0) | LVDS_FID_RV1106(0) |
+		      LVDS_LANES_ENABLED_RV1106(dev->active_sensor->lanes) |
+		      (channel->csi_fmt_val << 18) |
+		      rkcif_lvds_get_output_type_mask(stream) |
+		      (stream->cif_fmt_in->csi_yuv_order << 9) |
+		      dma_en;
+		if (stream->cifdev->hdr.hdr_mode == HDR_X3)
+			val |= BIT(12);
+		rkcif_write_register(dev, get_reg_index_of_lvds_id_ctrl0(channel->id), val);
+	}
+	if (dev->chip_id >= CHIP_RV1106_CIF)
+		rkcif_modify_frame_skip_config(stream);
+	if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+		if (index == (capture_info->multi_dev.dev_num - 1))
+			stream->cifdev->id_use_cnt++;
+	} else {
+		stream->cifdev->id_use_cnt++;
+	}
+	if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE &&
+	      index < capture_info->multi_dev.dev_num - 1)) {
+		if (mode == RKCIF_STREAM_MODE_CAPTURE)
+			rkcif_assign_new_buffer_pingpong(stream,
+						 RKCIF_YUV_ADDR_STATE_INIT,
+						 channel->id);
+		else if (mode == RKCIF_STREAM_MODE_TOISP ||
+			 mode == RKCIF_STREAM_MODE_TOISP_RDBK)
+			rkcif_assign_new_buffer_pingpong_toisp(stream,
+						       RKCIF_YUV_ADDR_STATE_INIT,
+						       channel->id);
+	}
+	return 0;
+}
+
+static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode)
 {
 	struct rkcif_device *dev = stream->cifdev;
 	struct rkcif_sensor_info *active_sensor = dev->active_sensor;
@@ -1974,23 +4046,22 @@
 	enum v4l2_mbus_type mbus_type = active_sensor->mbus.type;
 	struct csi_channel_info *channel;
 	u32 ret = 0;
+	int i;
 
-	if (stream->state != RKCIF_STATE_RESET_IN_STREAMING)
+	if (stream->state < RKCIF_STATE_STREAMING) {
 		stream->frame_idx = 0;
+		stream->buf_wake_up_cnt = 0;
+		stream->frame_phase = 0;
+		stream->lack_buf_cnt = 0;
+		stream->is_in_vblank = false;
+		stream->is_change_toisp = false;
+	}
 
-	if (mbus_type == V4L2_MBUS_CSI2) {
-		rkcif_csi_get_vc_num(dev, flags);
+	rkcif_csi_get_vc_num(dev, flags);
 
-		channel = &dev->channels[stream->id];
-		channel->id = stream->id;
-		rkcif_csi_channel_init(stream, channel);
-		rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CSI2);
-	} else if (mbus_type == V4L2_MBUS_CCP2) {
-		rkcif_csi_get_vc_num(dev, flags);
-
-		channel = &dev->channels[stream->id];
-		channel->id = stream->id;
-
+	channel = &dev->channels[stream->id];
+	channel->id = stream->id;
+	if (mbus_type == V4L2_MBUS_CCP2) {
 		ret = v4l2_subdev_call(dev->terminal_sensor.sd, core,
 				       ioctl, RKMODULE_GET_LVDS_CFG,
 				       &channel->lvds_cfg);
@@ -1998,18 +4069,63 @@
 			v4l2_err(&dev->v4l2_dev, "Err: get lvds config failed!!\n");
 			return ret;
 		}
-
-		rkcif_csi_channel_init(stream, channel);
-		rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CCP2);
 	}
-
-	stream->line_int_cnt = 0;
-	if (stream->is_line_wake_up)
-		stream->is_can_stop = false;
-	else
-		stream->is_can_stop = true;
-	stream->state = RKCIF_STATE_STREAMING;
-	dev->workmode = RKCIF_WORKMODE_PINGPONG;
+	rkcif_csi_channel_init(stream, channel);
+	if (stream->state != RKCIF_STATE_STREAMING) {
+		if (mode  == RKCIF_STREAM_MODE_CAPTURE) {
+			stream->dma_en |= RKCIF_DMAEN_BY_VICAP;
+		} else if (mode == RKCIF_STREAM_MODE_TOISP_RDBK) {
+			stream->dma_en |= RKCIF_DMAEN_BY_ISP;
+		} else if (mode == RKCIF_STREAM_MODE_TOISP) {
+			if (dev->hdr.hdr_mode == HDR_X2 &&
+			    stream->id == 0)
+				stream->dma_en |= RKCIF_DMAEN_BY_ISP;
+			else if (dev->hdr.hdr_mode == HDR_X3 && (stream->id == 0 || stream->id == 1))
+				stream->dma_en |= RKCIF_DMAEN_BY_ISP;
+		} else if (mode == RKCIF_STREAM_MODE_ROCKIT) {
+			stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT;
+		}
+		if (stream->cifdev->chip_id < CHIP_RK3588_CIF) {
+			rkcif_csi_channel_set(stream, channel, mbus_type);
+		} else {
+			if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+				for (i = 0; i < channel->capture_info.multi_dev.dev_num; i++) {
+					dev->csi_host_idx = channel->capture_info.multi_dev.dev_idx[i];
+					rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i);
+				}
+			} else {
+				rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0);
+			}
+		}
+	} else {
+		if (stream->cifdev->chip_id >= CHIP_RK3588_CIF) {
+			if (mode == RKCIF_STREAM_MODE_CAPTURE) {
+				stream->to_en_dma = RKCIF_DMAEN_BY_VICAP;
+			} else if (mode == RKCIF_STREAM_MODE_TOISP_RDBK) {
+				stream->to_en_dma = RKCIF_DMAEN_BY_ISP;
+			} else if (mode == RKCIF_STREAM_MODE_TOISP) {
+				if (dev->hdr.hdr_mode == HDR_X2 &&
+				    stream->id == 0 &&
+				    (!stream->dma_en))
+					stream->to_en_dma = RKCIF_DMAEN_BY_ISP;
+				else if (dev->hdr.hdr_mode == HDR_X3 &&
+					 (stream->id == 0 || stream->id == 1) &&
+					 (!stream->dma_en))
+					stream->to_en_dma = RKCIF_DMAEN_BY_ISP;
+			} else if (mode == RKCIF_STREAM_MODE_ROCKIT) {
+				stream->to_en_dma = RKCIF_DMAEN_BY_ROCKIT;
+			}
+		}
+	}
+	if (stream->state != RKCIF_STATE_STREAMING) {
+		stream->line_int_cnt = 0;
+		if (stream->is_line_wake_up)
+			stream->is_can_stop = false;
+		else
+			stream->is_can_stop = true;
+		stream->state = RKCIF_STATE_STREAMING;
+		dev->workmode = RKCIF_WORKMODE_PINGPONG;
+	}
 
 	return 0;
 }
@@ -2020,17 +4136,28 @@
 	struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus;
 	u32 val;
 	int id;
+	int i = 0;
 
-	if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
+	stream->cifdev->id_use_cnt--;
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
 	    mbus_cfg->type == V4L2_MBUS_CCP2) {
 		id = stream->id;
 		val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(id));
-		if (mbus_cfg->type == V4L2_MBUS_CSI2)
-			val &= ~CSI_ENABLE_CAPTURE;
+		if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+		    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY)
+			val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE);
 		else
 			val &= ~LVDS_ENABLE_CAPTURE;
 
-		rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val);
+		if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) {
+				cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i];
+				rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val);
+			}
+		} else {
+			rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val);
+		}
 
 		rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT,
 					CSI_START_INTSTAT(id) |
@@ -2042,8 +4169,25 @@
 					   CSI_DMA_END_INTEN(id) |
 					   CSI_LINE_INTEN(id)));
 
-		rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
-					~CSI_ALL_ERROR_INTEN);
+		if (stream->cifdev->chip_id < CHIP_RK3588_CIF) {
+			rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
+						 ~CSI_ALL_ERROR_INTEN);
+		} else {
+			if (stream->cifdev->id_use_cnt == 0) {
+				rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
+						~CSI_ALL_ERROR_INTEN_V1);
+				if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+					for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) {
+						cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i];
+						rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL,
+									 ~CSI_ENABLE_CAPTURE);
+					}
+				} else {
+					rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL,
+								 ~CSI_ENABLE_CAPTURE);
+				}
+			}
+		}
 
 	} else {
 		if (atomic_read(&cif_dev->pipe.stream_cnt) == 1) {
@@ -2053,16 +4197,17 @@
 			rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, 0x0);
 			rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, 0x3ff);
 			rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, 0x0);
+			if (IS_ENABLED(CONFIG_CPU_RV1106))
+				rkcif_config_dvp_pin(cif_dev, false);
 		}
-		stream->is_dvp_yuv_addr_init = false;
 	}
-
 	stream->state = RKCIF_STATE_READY;
+	stream->dma_en = 0;
 }
 
 static bool rkcif_is_extending_line_for_height(struct rkcif_device *dev,
-							 struct rkcif_stream *stream,
-							 const struct cif_input_fmt *fmt)
+					       struct rkcif_stream *stream,
+					       const struct cif_input_fmt *fmt)
 {
 	bool is_extended = false;
 	struct rkmodule_hdr_cfg hdr_cfg;
@@ -2076,17 +4221,17 @@
 					       RKMODULE_GET_HDR_CFG,
 					       &hdr_cfg);
 			if (!ret)
-				dev->hdr.mode = hdr_cfg.hdr_mode;
+				dev->hdr = hdr_cfg;
 			else
-				dev->hdr.mode = NO_HDR;
+				dev->hdr.hdr_mode = NO_HDR;
 		}
 
 		if (fmt && fmt->fmt_type == CIF_FMT_TYPE_RAW) {
-			if ((dev->hdr.mode == HDR_X2 &&
+			if ((dev->hdr.hdr_mode == HDR_X2 &&
 			    stream->id == RKCIF_STREAM_MIPI_ID1) ||
-			    (dev->hdr.mode == HDR_X3 &&
+			    (dev->hdr.hdr_mode == HDR_X3 &&
 			     stream->id == RKCIF_STREAM_MIPI_ID2) ||
-			     (dev->hdr.mode == NO_HDR)) {
+			     (dev->hdr.hdr_mode == NO_HDR)) {
 				is_extended = true;
 			}
 		}
@@ -2134,7 +4279,7 @@
 		plane_fmt = &pixm->plane_fmt[i];
 		sizes[i] = plane_fmt->sizeimage / height * h;
 	}
-
+	stream->total_buf_num = *num_buffers;
 	v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s count %d, size %d, extended(%d, %d)\n",
 		 v4l2_type_names[queue->type], *num_buffers, sizes[0],
 		 is_extended, extend_line->is_extended);
@@ -2143,91 +4288,192 @@
 }
 
 static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream,
-					   int channel_id)
+					       int channel_id)
 {
 	struct rkcif_device *dev = stream->cifdev;
 	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
 	struct rkcif_buffer *buffer = NULL;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
-	u32 frm_addr_y, frm_addr_uv;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
+	u32 frm_addr_y = 0, frm_addr_uv = 0;
+	u32 frm0_addr_y = 0, frm0_addr_uv = 0;
+	u32 frm1_addr_y = 0, frm1_addr_uv = 0;
+	u32 buff_addr_y = 0, buff_addr_cbcr = 0;
+	struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info;
 	unsigned long flags;
+	int frame_phase = 0;
+	bool is_dual_update_buf = false;
 
+	spin_lock_irqsave(&stream->vbq_lock, flags);
 	if (stream->state == RKCIF_STATE_STREAMING &&
-	    stream->curr_buf == stream->next_buf &&
-	    stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED  &&
-	    (!dummy_buf->vaddr)) {
-		if (!stream->is_line_wake_up) {
-			if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
+	    ((stream->curr_buf == stream->next_buf &&
+	      stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED  &&
+	      (!dummy_buf->vaddr)) ||
+	     stream->curr_buf == NULL ||
+	     stream->next_buf == NULL)) {
+		frame_phase = stream->frame_phase_cache;
+		if (!stream->is_line_wake_up ||
+		    (stream->is_line_wake_up && stream->frame_idx < 2)) {
+			if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+			    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
 			    mbus_cfg->type == V4L2_MBUS_CCP2) {
-				frm_addr_y = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ?
-					     get_reg_index_of_frm0_y_addr(channel_id) :
-					     get_reg_index_of_frm1_y_addr(channel_id);
-				frm_addr_uv = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ?
-					      get_reg_index_of_frm0_uv_addr(channel_id) :
-					      get_reg_index_of_frm1_uv_addr(channel_id);
+				frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id);
+				frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id);
+				frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id);
+				frm1_addr_uv = get_reg_index_of_frm1_uv_addr(channel_id);
 			} else {
-				frm_addr_y = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ?
-					     get_dvp_reg_index_of_frm0_y_addr(channel_id) :
-					     get_dvp_reg_index_of_frm1_y_addr(channel_id);
-				frm_addr_uv = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ?
-					      get_dvp_reg_index_of_frm0_uv_addr(channel_id) :
-					      get_dvp_reg_index_of_frm1_uv_addr(channel_id);
+				frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id);
+				frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id);
+				frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(channel_id);
+				frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id);
 			}
-			v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
-				"stream[%d] update buf in %s, stream->frame_phase_cache %d\n",
-				stream->id, __func__, stream->frame_phase_cache);
-			spin_lock_irqsave(&stream->vbq_lock, flags);
+			if (frame_phase & CIF_CSI_FRAME0_READY) {
+				frm_addr_y = frm0_addr_y;
+				frm_addr_uv = frm0_addr_uv;
+			} else {
+				frm_addr_y = frm1_addr_y;
+				frm_addr_uv = frm1_addr_uv;
+			}
+			if (!stream->dma_en && stream->curr_buf == NULL && stream->next_buf == NULL)
+				is_dual_update_buf = true;
 			if (!list_empty(&stream->buf_head)) {
-				if (stream->frame_phase_cache == CIF_CSI_FRAME0_READY) {
+				if (frame_phase == CIF_CSI_FRAME0_READY) {
 					stream->curr_buf = list_first_entry(&stream->buf_head,
 									    struct rkcif_buffer, queue);
 					if (stream->curr_buf) {
 						list_del(&stream->curr_buf->queue);
 						buffer = stream->curr_buf;
 					}
-				} else if (stream->frame_phase_cache == CIF_CSI_FRAME1_READY) {
-					stream->next_buf = list_first_entry(&stream->buf_head,
+					if (buffer && is_dual_update_buf)
+						stream->next_buf = buffer;
+				} else if (frame_phase == CIF_CSI_FRAME1_READY) {
+					if (stream->next_buf == NULL &&
+					    stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
+						stream->next_buf = stream->curr_buf;
+					} else {
+						stream->next_buf = list_first_entry(&stream->buf_head,
 									    struct rkcif_buffer, queue);
-					if (stream->next_buf) {
-						list_del(&stream->next_buf->queue);
-						buffer = stream->next_buf;
+						if (stream->next_buf) {
+							list_del(&stream->next_buf->queue);
+							buffer = stream->next_buf;
+						}
+						if (buffer && is_dual_update_buf)
+							stream->curr_buf = buffer;
+					}
+				}
+			} else {
+				v4l2_info(&dev->v4l2_dev, "%s %d\n", __func__, __LINE__);
+			}
+			if (buffer) {
+				if (is_dual_update_buf) {
+					buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y];
+					buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR];
+					if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+						rkcif_write_buff_addr_multi_dev_combine(stream,
+											frm0_addr_y,
+											frm0_addr_uv,
+											buff_addr_y,
+											buff_addr_cbcr,
+											false);
+						rkcif_write_buff_addr_multi_dev_combine(stream,
+											frm1_addr_y,
+											frm1_addr_uv,
+											buff_addr_y,
+											buff_addr_cbcr,
+											false);
+					} else {
+						rkcif_write_register(dev, frm0_addr_y, buff_addr_y);
+						if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+							rkcif_write_register(dev,
+									     frm0_addr_uv,
+									     buff_addr_cbcr);
+						rkcif_write_register(dev, frm1_addr_y, buff_addr_y);
+						if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+							rkcif_write_register(dev,
+									     frm1_addr_uv,
+									     buff_addr_cbcr);
+					}
+				} else {
+
+					buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y];
+					buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR];
+					if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+						rkcif_write_buff_addr_multi_dev_combine(stream,
+											frm_addr_y,
+											frm_addr_uv,
+											buff_addr_y,
+											buff_addr_cbcr,
+											false);
+					} else {
+						rkcif_write_register(dev, frm_addr_y, buff_addr_y);
+						if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
+							rkcif_write_register(dev,
+									     frm_addr_uv,
+									     buff_addr_cbcr);
 					}
 				}
 			}
-			spin_unlock_irqrestore(&stream->vbq_lock, flags);
-			if (buffer) {
-				rkcif_write_register(dev, frm_addr_y,
-						     buffer->buff_addr[RKCIF_PLANE_Y]);
-				if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
-					rkcif_write_register(dev, frm_addr_uv,
-							     buffer->buff_addr[RKCIF_PLANE_CBCR]);
-			}
 		} else {
-			spin_lock_irqsave(&stream->vbq_lock, flags);
+			v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
+				 "%s %d, is_wake_up %d, frame_idx %d\n",
+				 __func__, __LINE__, stream->is_line_wake_up, stream->frame_idx);
 			if (stream->curr_buf == stream->next_buf) {
 				if (stream->frame_phase_cache == CIF_CSI_FRAME0_READY) {
 					stream->curr_buf = list_first_entry(&stream->buf_head,
 									    struct rkcif_buffer, queue);
+					v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+						 "%s %d, stream[%d] buf idx %d\n",
+						 __func__, __LINE__, stream->id, stream->curr_buf->vb.vb2_buf.index);
 					if (stream->curr_buf)
 						list_del(&stream->curr_buf->queue);
 				} else if (stream->frame_phase_cache == CIF_CSI_FRAME1_READY) {
 					stream->next_buf = list_first_entry(&stream->buf_head,
 									    struct rkcif_buffer, queue);
+					v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev,
+						 "%s %d, stream[%d] buf idx %d\n",
+						 __func__, __LINE__, stream->id, stream->next_buf->vb.vb2_buf.index);
 					if (stream->next_buf)
 						list_del(&stream->next_buf->queue);
 				}
 				stream->is_buf_active = true;
 			}
-			spin_unlock_irqrestore(&stream->vbq_lock, flags);
 		}
+		v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
+			 "%s, stream[%d] update buffer, frame_phase %d, is_stop %s, lack_buf_cnt %d\n",
+			 __func__, stream->id, frame_phase,
+			 (stream->dma_en ? "false" : "true"),
+			 stream->lack_buf_cnt);
+		if (!stream->dma_en) {
+			if (stream->to_stop_dma) {
+				stream->to_stop_dma = 0;
+				wake_up(&stream->wq_stopped);
+			} else {
+				stream->to_en_dma = RKCIF_DMAEN_BY_VICAP;
+				v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
+					 "%s stream[%d] start dma capture, frame cnt %d\n",
+					 __func__, stream->id, stream->frame_idx);
+			}
+		} else {
+			v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
+				 "%s %d, dma_en 0x%x, frame cnt %d\n",
+				 __func__, __LINE__, stream->dma_en, stream->frame_idx);
+		}
+		if (stream->lack_buf_cnt)
+			stream->lack_buf_cnt--;
+
+	} else {
+		v4l2_info(&dev->v4l2_dev, "%s %d, state %d, curr_buf %p, next_buf %p\n",
+			  __func__, __LINE__, stream->state, stream->curr_buf, stream->next_buf);
 	}
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+	if (stream->to_en_dma)
+		rkcif_enable_dma_capture(stream, true);
 }
 
 /*
  * The vb2_buffer are stored in rkcif_buffer, in order to unify
  * mplane buffer and none-mplane buffer.
  */
-static void rkcif_buf_queue(struct vb2_buffer *vb)
+void rkcif_buf_queue(struct vb2_buffer *vb)
 {
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct rkcif_buffer *cifbuf = to_rkcif_buffer(vbuf);
@@ -2236,8 +4482,32 @@
 	struct v4l2_pix_format_mplane *pixm = &stream->pixm;
 	const struct cif_output_fmt *fmt = stream->cif_fmt_out;
 	struct rkcif_hw *hw_dev = stream->cifdev->hw_dev;
+	struct rkcif_tools_buffer *tools_buf;
+	struct rkcif_tools_vdev *tools_vdev = stream->tools_vdev;
 	unsigned long flags;
 	int i;
+	bool is_find_tools_buf = false;
+
+	if (tools_vdev) {
+		spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags);
+		if (!list_empty(&tools_vdev->src_buf_head)) {
+			list_for_each_entry(tools_buf, &tools_vdev->src_buf_head, list) {
+				if (tools_buf->vb == vbuf) {
+					is_find_tools_buf = true;
+					break;
+				}
+			}
+			if (is_find_tools_buf) {
+				if (tools_buf->use_cnt)
+					tools_buf->use_cnt--;
+				if (tools_buf->use_cnt) {
+					spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags);
+					return;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags);
+	}
 
 	memset(cifbuf->buff_addr, 0, sizeof(cifbuf->buff_addr));
 	/* If mplanes > 1, every c-plane has its own m-plane,
@@ -2246,7 +4516,7 @@
 	for (i = 0; i < fmt->mplanes; i++) {
 		void *addr = vb2_plane_vaddr(vb, i);
 
-		if (hw_dev->iommu_en) {
+		if (hw_dev->is_dma_sg_ops) {
 			struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, i);
 
 			cifbuf->buff_addr[i] = sg_dma_address(sgt->sgl);
@@ -2255,7 +4525,7 @@
 		}
 		if (rkcif_debug && addr && !hw_dev->iommu_en) {
 			memset(addr, 0, pixm->plane_fmt[i].sizeimage);
-			v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
+			v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
 				 "Clear buffer, size: 0x%08x\n",
 				 pixm->plane_fmt[i].sizeimage);
 		}
@@ -2269,40 +4539,240 @@
 	spin_lock_irqsave(&stream->vbq_lock, flags);
 	list_add_tail(&cifbuf->queue, &stream->buf_head);
 	spin_unlock_irqrestore(&stream->vbq_lock, flags);
-	if (stream->cifdev->workmode == RKCIF_WORKMODE_PINGPONG)
+	if (stream->dma_en & RKCIF_DMAEN_BY_ISP && (!cifbuf->dbuf)) {
+		struct rkisp_rx_buf *dbufs = NULL;
+
+		dbufs = kzalloc(sizeof(struct rkisp_rx_buf), GFP_KERNEL);
+
+		memset(dbufs, 0, sizeof(struct rkisp_rx_buf));
+		if (stream->cifdev->hdr.hdr_mode == HDR_X2 && stream->id == 0)
+			dbufs->type = BUF_MIDDLE;
+		else if (stream->cifdev->hdr.hdr_mode == HDR_X3 && stream->id == 0)
+			dbufs->type = BUF_LONG;
+		else if (stream->cifdev->hdr.hdr_mode == HDR_X3 && stream->id == 1)
+			dbufs->type = BUF_MIDDLE;
+		cifbuf->dbuf = hw_dev->mem_ops->get_dmabuf(vb->planes[0].mem_priv, O_RDWR);
+		if (cifbuf->dbuf)
+			dbufs->dbuf = cifbuf->dbuf;
+		list_add_tail(&dbufs->list, &stream->rx_buf_head_vicap);
+	}
+	if (stream->cifdev->workmode == RKCIF_WORKMODE_PINGPONG &&
+	    stream->lack_buf_cnt)
 		rkcif_check_buffer_update_pingpong(stream, stream->id);
+	v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
+		 "stream[%d] buf queue, index: %d, dma_addr 0x%x\n",
+		 stream->id, vb->index, cifbuf->buff_addr[0]);
+	atomic_inc(&stream->buf_cnt);
+}
+
+void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num)
+{
+	struct rkcif_rx_buffer *buf;
+	struct rkcif_device *dev = stream->cifdev;
+	struct sditf_priv *priv = dev->sditf[0];
+	int i = 0;
+	unsigned long flags;
+
+	if (!priv)
+		return;
+
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+	stream->curr_buf_toisp = NULL;
+	stream->next_buf_toisp = NULL;
+	INIT_LIST_HEAD(&stream->rx_buf_head);
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+
+	if (dev->is_thunderboot)
+		spin_lock_irqsave(&dev->buffree_lock, flags);
+	for (i = 0; i < buf_num; i++) {
+		buf = &stream->rx_buf[i];
+		if (buf->dummy.is_free)
+			continue;
+		if (!dev->is_thunderboot)
+			rkcif_free_buffer(dev, &buf->dummy);
+		else
+			list_add_tail(&buf->list_free, &priv->buf_free_list);
+		atomic_dec(&stream->buf_cnt);
+		stream->total_buf_num--;
+	}
+
+	if (dev->is_thunderboot) {
+		spin_unlock_irqrestore(&dev->buffree_lock, flags);
+		schedule_work(&priv->buffree_work.work);
+	}
+	stream->dma_en &= ~RKCIF_DMAEN_BY_ISP;
 	v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
-		 "stream[%d] buf queue, index: %d\n",
-		 stream->id, vb->index);
+		 "free rx_buf, buf_num %d\n", buf_num);
+}
+
+int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct v4l2_pix_format_mplane *pixm = &stream->pixm;
+	struct rkcif_dummy_buffer *dummy;
+	struct rkcif_rx_buffer *buf;
+	struct sditf_priv *priv = dev->sditf[0];
+	int frm_type = 0;
+	int i = 0;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	if (buf_num > RKISP_VICAP_BUF_CNT_MAX)
+		return -EINVAL;
+
+	if (dev->hdr.hdr_mode == NO_HDR) {
+		if (stream->id == 0)
+			frm_type = BUF_SHORT;
+		else
+			return -EINVAL;
+	} else if (dev->hdr.hdr_mode == HDR_X2) {
+		if (stream->id == 0)
+			frm_type = BUF_MIDDLE;
+		else if (stream->id == 1)
+			frm_type = BUF_SHORT;
+		else
+			return -EINVAL;
+	} else if (dev->hdr.hdr_mode == HDR_X3) {
+		if (stream->id == 0)
+			frm_type = BUF_LONG;
+		else if (stream->id == 1)
+			frm_type = BUF_MIDDLE;
+		else if (stream->id == 2)
+			frm_type = BUF_SHORT;
+		else
+			return -EINVAL;
+	}
+	while (true) {
+		buf = &stream->rx_buf[i];
+		memset(buf, 0, sizeof(*buf));
+		dummy = &buf->dummy;
+		dummy->size = pixm->plane_fmt[0].sizeimage;
+		dummy->is_need_vaddr = true;
+		dummy->is_need_dbuf = true;
+		if (dev->is_thunderboot) {
+			buf->buf_idx = i;
+			ret = rkcif_alloc_reserved_mem_buf(dev, buf);
+			if (ret) {
+				priv->buf_num = i;
+				v4l2_info(&dev->v4l2_dev,
+					 "reserved mem support alloc buf num %d, require buf num %d\n",
+					 i, buf_num);
+				break;
+			}
+			if (dev->rdbk_debug)
+				v4l2_info(&dev->v4l2_dev,
+					  "stream[%d] buf addr 0x%llx\n",
+					  stream->id, (u64)dummy->dma_addr);
+		} else {
+			ret = rkcif_alloc_buffer(dev, dummy);
+			if (ret) {
+				priv->buf_num = i;
+				v4l2_info(&dev->v4l2_dev,
+					 "alloc buf num %d, require buf num %d\n",
+					 i, buf_num);
+				break;
+			}
+			buf->dbufs.dbuf = dummy->dbuf;
+		}
+		buf->dbufs.is_init = false;
+		buf->dbufs.type = frm_type;
+		list_add_tail(&buf->list, &stream->rx_buf_head);
+		dummy->is_free = false;
+		if (stream->is_compact)
+			buf->dbufs.is_uncompact = false;
+		else
+			buf->dbufs.is_uncompact = true;
+		if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && i == 0) {
+			buf->dbufs.is_first = true;
+			rkcif_s_rx_buffer(dev, &buf->dbufs);
+		}
+		i++;
+		if (!dev->is_thunderboot && i >= buf_num) {
+			break;
+		} else if (i >= RKISP_VICAP_BUF_CNT_MAX) {
+			priv->buf_num = i;
+			v4l2_info(&dev->v4l2_dev,
+				  "reserved mem alloc buf num %d\n", i);
+			break;
+		}
+		v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
+			"init rx_buf,dma_addr 0x%llx size: 0x%x\n",
+			(u64)dummy->dma_addr, pixm->plane_fmt[0].sizeimage);
+	}
+	if (priv->buf_num) {
+		stream->total_buf_num = priv->buf_num;
+		atomic_set(&stream->buf_cnt, priv->buf_num);
+		return 0;
+	} else {
+		return -EINVAL;
+	}
 }
 
 static int rkcif_create_dummy_buf(struct rkcif_stream *stream)
 {
-	u32 fourcc;
 	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
-	struct rkcif_hw *hw_dev = dev->hw_dev;
+	struct rkcif_hw *hw = dev->hw_dev;
+	struct rkcif_dummy_buffer *dummy_buf = &hw->dummy_buf;
+	struct rkcif_device *tmp_dev = NULL;
+	struct v4l2_subdev_frame_interval_enum fie;
+	struct v4l2_subdev_format fmt;
+	u32 max_size = 0;
+	u32 size = 0;
+	int ret = 0;
+	int i, j;
 
-	/* get a maximum plane size */
-	dummy_buf->size = max3(stream->pixm.plane_fmt[0].bytesperline *
-		stream->pixm.height,
-		stream->pixm.plane_fmt[1].sizeimage,
-		stream->pixm.plane_fmt[2].sizeimage);
-	/*
-	 * rk cif don't support output yuyv fmt data
-	 * if user request yuyv fmt, the input mode must be RAW8
-	 * and the width is double Because the real input fmt is
-	 * yuyv
-	 */
-	fourcc  = stream->cif_fmt_out->fourcc;
-	if (fourcc == V4L2_PIX_FMT_YUYV || fourcc == V4L2_PIX_FMT_YVYU ||
-	    fourcc == V4L2_PIX_FMT_UYVY || fourcc == V4L2_PIX_FMT_VYUY)
-		dummy_buf->size *= 2;
+	for (i = 0; i < hw->dev_num; i++) {
+		tmp_dev = hw->cif_dev[i];
+		if (tmp_dev->terminal_sensor.sd) {
+			for (j = 0; j < 32; j++) {
+				memset(&fie, 0, sizeof(fie));
+				fie.index = j;
+				fie.pad = 0;
+				fie.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+				ret = v4l2_subdev_call(tmp_dev->terminal_sensor.sd,
+						       pad, enum_frame_interval,
+						       NULL, &fie);
+				if (!ret) {
+					if (fie.code == MEDIA_BUS_FMT_RGB888_1X24)
+						size = fie.width * fie.height * 3;
+					else
+						size = fie.width * fie.height * 2;
+					v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
+						 "%s enum fmt, width %d, height %d\n",
+						 __func__, fie.width, fie.height);
+				} else {
+					break;
+				}
+				if (size > max_size)
+					max_size = size;
+			}
+		} else {
+			continue;
+		}
+	}
 
-	dummy_buf->vaddr = dma_alloc_coherent(hw_dev->dev, dummy_buf->size,
-					      &dummy_buf->dma_addr,
-					      GFP_KERNEL);
-	if (!dummy_buf->vaddr) {
+	if (max_size == 0 && dev->terminal_sensor.sd) {
+		fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		ret = v4l2_subdev_call(dev->terminal_sensor.sd,
+				       pad, get_fmt, NULL, &fmt);
+		if (!ret) {
+			if (fmt.format.code == MEDIA_BUS_FMT_RGB888_1X24)
+				size = fmt.format.width  * fmt.format.height * 3;
+			else
+				size = fmt.format.width * fmt.format.height * 2;
+			if (size > max_size)
+				max_size = size;
+		}
+	}
+
+	dummy_buf->size = max_size;
+
+	dummy_buf->is_need_vaddr = true;
+	dummy_buf->is_need_dbuf = true;
+	ret = rkcif_alloc_buffer(dev, dummy_buf);
+	if (ret) {
 		v4l2_err(&dev->v4l2_dev,
 			 "Failed to allocate the memory for dummy buffer\n");
 		return -ENOMEM;
@@ -2311,18 +4781,16 @@
 	v4l2_info(&dev->v4l2_dev, "Allocate dummy buffer, size: 0x%08x\n",
 		  dummy_buf->size);
 
-	return 0;
+	return ret;
 }
 
 static void rkcif_destroy_dummy_buf(struct rkcif_stream *stream)
 {
 	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf;
-	struct rkcif_hw *hw_dev = dev->hw_dev;
+	struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
 
 	if (dummy_buf->vaddr)
-		dma_free_coherent(hw_dev->dev, dummy_buf->size,
-				  dummy_buf->vaddr, dummy_buf->dma_addr);
+		rkcif_free_buffer(dev, dummy_buf);
 	dummy_buf->dma_addr = 0;
 	dummy_buf->vaddr = NULL;
 }
@@ -2336,7 +4804,7 @@
 	if (dev->luma_vdev.enable)
 		rkcif_stop_luma(&dev->luma_vdev);
 
-	if (dev->hdr.mode != NO_HDR) {
+	if (dev->hdr.hdr_mode != NO_HDR) {
 		if (dev->chip_id == CHIP_RK1808_CIF) {
 			val = rkcif_read_register(dev, CIF_REG_MIPI_WATER_LINE);
 			val |= CIF_MIPI_LVDS_SW_DMA_IDLE_RK1808;
@@ -2360,14 +4828,22 @@
 			reset_control_deassert(cif_hw->cif_rst[i]);
 
 	if (cif_hw->iommu_en) {
-		struct iommu_domain *domain;
-
-		domain = iommu_get_domain_for_dev(cif_hw->dev);
-		if (domain) {
-			iommu_detach_device(domain, cif_hw->dev);
-			iommu_attach_device(domain, cif_hw->dev);
-		}
+		rockchip_iommu_disable(cif_hw->dev);
+		rockchip_iommu_enable(cif_hw->dev);
 	}
+}
+
+void rkcif_do_soft_reset(struct rkcif_device *dev)
+{
+	if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	    dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ||
+	    dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)
+		rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000);
+	else
+		rkcif_write_register_or(dev, CIF_REG_DVP_CTRL, 0x000A0000);
+	usleep_range(10, 20);
+	v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
+		"vicap do soft reset 0x%x\n", 0x000A0000);
 }
 
 static void rkcif_release_rdbk_buf(struct rkcif_stream *stream)
@@ -2412,9 +4888,52 @@
 
 }
 
-static void rkcif_stop_streaming(struct vb2_queue *queue)
+static void rkcif_detach_sync_mode(struct rkcif_device *cif_dev)
 {
-	struct rkcif_stream *stream = queue->drv_priv;
+	int i = 0;
+	struct rkcif_hw *hw = cif_dev->hw_dev;
+	struct rkcif_device *tmp_dev;
+	struct rkcif_multi_sync_config *sync_config;
+
+	if ((!cif_dev->sync_cfg.type) ||
+	    (atomic_read(&cif_dev->pipe.stream_cnt) != 0))
+		return;
+	mutex_lock(&hw->dev_lock);
+	memset(&cif_dev->sync_cfg, 0, sizeof(cif_dev->sync_cfg));
+	sync_config = &hw->sync_config[cif_dev->sync_cfg.group];
+	sync_config->streaming_cnt--;
+	if (cif_dev->sync_cfg.type == EXTERNAL_MASTER_MODE) {
+		for (i = 0; i < sync_config->ext_master.count; i++) {
+			tmp_dev = sync_config->ext_master.cif_dev[i];
+			if (tmp_dev == cif_dev) {
+				sync_config->ext_master.is_streaming[i] = false;
+				break;
+			}
+		}
+	}
+	if (cif_dev->sync_cfg.type == INTERNAL_MASTER_MODE)
+		sync_config->int_master.is_streaming[0] = false;
+	if (cif_dev->sync_cfg.type == SLAVE_MODE) {
+		for (i = 0; i < sync_config->slave.count; i++) {
+			tmp_dev = sync_config->slave.cif_dev[i];
+			if (tmp_dev == cif_dev) {
+				sync_config->slave.is_streaming[i] = false;
+				break;
+			}
+		}
+	}
+
+	if (!sync_config->streaming_cnt && sync_config->is_attach) {
+		sync_config->is_attach = false;
+		sync_config->mode = RKCIF_NOSYNC_MODE;
+		sync_config->dev_cnt = 0;
+	}
+	mutex_unlock(&hw->dev_lock);
+}
+
+void rkcif_do_stop_stream(struct rkcif_stream *stream,
+			  unsigned int mode)
+{
 	struct rkcif_vdev_node *node = &stream->vnode;
 	struct rkcif_device *dev = stream->cifdev;
 	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
@@ -2424,95 +4943,170 @@
 	bool can_reset = true;
 	int i;
 	unsigned long flags;
+	u32 vblank = 0;
+	u32 frame_time_ns = 0;
+	u64 cur_time = 0;
+	u64 fs_time = 0;
 
 	mutex_lock(&dev->stream_lock);
 
-	v4l2_info(&dev->v4l2_dev, "stream[%d] start stopping\n", stream->id);
+	v4l2_info(&dev->v4l2_dev, "stream[%d] start stopping, total mode 0x%x, cur 0x%x\n",
+		stream->id, stream->cur_stream_mode, mode);
 
-	stream->stopping = true;
+	if (mode == stream->cur_stream_mode) {
+		if (stream->dma_en) {
+			if (!dev->sensor_linetime)
+				dev->sensor_linetime = rkcif_get_linetime(stream);
+			vblank = rkcif_get_sensor_vblank(dev);
+			if (vblank) {
+				frame_time_ns = (vblank + dev->terminal_sensor.raw_rect.height) *
+						dev->sensor_linetime;
+				spin_lock_irqsave(&stream->fps_lock, flags);
+				fs_time = stream->readout.fs_timestamp;
+				spin_unlock_irqrestore(&stream->fps_lock, flags);
+				cur_time = ktime_get_ns();
+				if (cur_time > fs_time &&
+				    cur_time - fs_time < (frame_time_ns - 10000000)) {
+					spin_lock_irqsave(&stream->vbq_lock, flags);
+					if (stream->dma_en & RKCIF_DMAEN_BY_VICAP)
+						stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP;
+					else if (stream->dma_en & RKCIF_DMAEN_BY_ISP)
+						stream->to_stop_dma = RKCIF_DMAEN_BY_ISP;
+					stream->is_stop_capture = true;
+					rkcif_stop_dma_capture(stream);
+					spin_unlock_irqrestore(&stream->vbq_lock, flags);
+				}
+			}
+		}
+		stream->stopping = true;
+		ret = wait_event_timeout(stream->wq_stopped,
+					 stream->state != RKCIF_STATE_STREAMING,
+					 msecs_to_jiffies(500));
+		if (!ret) {
+			rkcif_stream_stop(stream);
+			stream->stopping = false;
+		}
 
-	ret = wait_event_timeout(stream->wq_stopped,
-				 stream->state != RKCIF_STATE_STREAMING,
-				 msecs_to_jiffies(1000));
-	if (!ret) {
-		rkcif_stream_stop(stream);
-		stream->stopping = false;
+		media_pipeline_stop(&node->vdev.entity);
+		ret = dev->pipe.set_stream(&dev->pipe, false);
+		if (ret < 0)
+			v4l2_err(v4l2_dev, "pipeline stream-off failed error:%d\n",
+				 ret);
+
+		dev->is_start_hdr = false;
+		stream->is_dvp_yuv_addr_init = false;
+		if (stream->skip_info.skip_en) {
+			stream->skip_info.skip_en = false;
+			stream->skip_info.skip_to_en = true;
+		}
+	} else if (mode == RKCIF_STREAM_MODE_CAPTURE && stream->dma_en & RKCIF_DMAEN_BY_VICAP) {
+		//only stop dma
+		stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP;
+		stream->is_wait_dma_stop = true;
+		wait_event_timeout(stream->wq_stopped,
+				   !stream->is_wait_dma_stop,
+				   msecs_to_jiffies(1000));
+	} else if (mode == RKCIF_STREAM_MODE_TOISP && stream->dma_en & RKCIF_DMAEN_BY_VICAP) {
+		//only stop dma
+		stream->to_stop_dma = RKCIF_DMAEN_BY_ISP;
+		stream->is_wait_dma_stop = true;
+		wait_event_timeout(stream->wq_stopped,
+				   !stream->is_wait_dma_stop,
+				   msecs_to_jiffies(1000));
+	}
+	if ((mode & RKCIF_STREAM_MODE_CAPTURE) == RKCIF_STREAM_MODE_CAPTURE) {
+		/* release buffers */
+		spin_lock_irqsave(&stream->vbq_lock, flags);
+		if (stream->curr_buf)
+			list_add_tail(&stream->curr_buf->queue, &stream->buf_head);
+		if (stream->next_buf &&
+		    stream->next_buf != stream->curr_buf)
+			list_add_tail(&stream->next_buf->queue, &stream->buf_head);
+		spin_unlock_irqrestore(&stream->vbq_lock, flags);
+
+		stream->curr_buf = NULL;
+		stream->next_buf = NULL;
+
+		if (dev->hdr.hdr_mode == HDR_X2 ||
+		    dev->hdr.hdr_mode == HDR_X3)
+			rkcif_release_rdbk_buf(stream);
+
+		rkcif_rx_buffer_free(stream);
+		list_for_each_entry(buf, &stream->buf_head, queue) {
+			v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+				 "stream[%d] buf return addr 0x%x\n",
+				 stream->id, buf->buff_addr[0]);
+			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+		}
+		INIT_LIST_HEAD(&stream->buf_head);
+		while (!list_empty(&stream->vb_done_list)) {
+			buf = list_first_entry(&stream->vb_done_list,
+					       struct rkcif_buffer, queue);
+			if (buf) {
+				list_del(&buf->queue);
+				vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+			}
+		}
+		stream->total_buf_num = 0;
+		atomic_set(&stream->buf_cnt, 0);
+		stream->lack_buf_cnt = 0;
+		stream->dma_en &= ~RKCIF_DMAEN_BY_VICAP;
 	}
 
-	media_pipeline_stop(&node->vdev.entity);
-	ret = dev->pipe.set_stream(&dev->pipe, false);
-	if (ret < 0)
-		v4l2_err(v4l2_dev, "pipeline stream-off failed error:%d\n",
-			 ret);
-
-	dev->is_start_hdr = false;
-	stream->is_dvp_yuv_addr_init = false;
-
-	/* release buffers */
-	if (stream->curr_buf)
-		list_add_tail(&stream->curr_buf->queue, &stream->buf_head);
-
-	if (stream->next_buf &&
-	    stream->next_buf != stream->curr_buf)
-		list_add_tail(&stream->next_buf->queue, &stream->buf_head);
-
-	if (dev->hdr.mode != NO_HDR)
-		rkcif_release_rdbk_buf(stream);
-
-	stream->curr_buf = NULL;
-	stream->next_buf = NULL;
-
-	while (!list_empty(&stream->buf_head)) {
-		buf = list_first_entry(&stream->buf_head,
-				       struct rkcif_buffer, queue);
-		list_del(&buf->queue);
-		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-	}
-
-	ret = dev->pipe.close(&dev->pipe);
-	if (ret < 0)
-		v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret);
-
-	if (dev->hdr.mode == HDR_X2) {
-		if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY &&
-		    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) {
+	if (mode == stream->cur_stream_mode) {
+		ret = dev->pipe.close(&dev->pipe);
+		if (ret < 0)
+			v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret);
+		if (dev->hdr.hdr_mode == HDR_X2) {
+			if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) {
+				dev->can_be_reset = true;
+			}
+		} else if (dev->hdr.hdr_mode == HDR_X3) {
+			if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_READY) {
+				dev->can_be_reset = true;
+			}
+		} else {
 			dev->can_be_reset = true;
 		}
-	} else if (dev->hdr.mode == HDR_X3) {
-		if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY &&
-		    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY &&
-		    dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_READY) {
-			dev->can_be_reset = true;
+		mutex_lock(&hw_dev->dev_lock);
+		for (i = 0; i < hw_dev->dev_num; i++) {
+			if (atomic_read(&hw_dev->cif_dev[i]->pipe.stream_cnt) != 0) {
+				can_reset = false;
+				break;
+			}
 		}
-	} else {
-		dev->can_be_reset = true;
-	}
-
-	spin_lock_irqsave(&hw_dev->hw_timer.timer_lock, flags);
-	for (i = 0; i < hw_dev->dev_num; i++) {
-		if (atomic_read(&hw_dev->cif_dev[i]->pipe.stream_cnt) != 0) {
-			can_reset = false;
-			break;
+		mutex_unlock(&hw_dev->dev_lock);
+		if (dev->can_be_reset && dev->chip_id >= CHIP_RK3588_CIF)
+			rkcif_do_soft_reset(dev);
+		if (dev->can_be_reset && can_reset) {
+			dev->can_be_reset = false;
+			dev->reset_work_cancel = true;
+			dev->early_line = 0;
+			dev->sensor_linetime = 0;
+			dev->wait_line = 0;
+			stream->is_line_wake_up = false;
 		}
+		if (can_reset && hw_dev->dummy_buf.vaddr)
+			rkcif_destroy_dummy_buf(stream);
 	}
+	if (mode == RKCIF_STREAM_MODE_CAPTURE)
+		tasklet_disable(&stream->vb_done_tasklet);
 
-	if (dev->can_be_reset && can_reset) {
-		rkcif_do_cru_reset(dev);
-		dev->can_be_reset = false;
-		dev->reset_work_cancel = true;
-		hw_dev->hw_timer.is_running = false;
-		hw_dev->reset_info.is_need_reset = 0;
-	}
-	spin_unlock_irqrestore(&hw_dev->hw_timer.timer_lock, flags);
-
-	pm_runtime_put_sync(dev->dev);
-
-	if (!atomic_read(&dev->pipe.stream_cnt) && dev->dummy_buf.vaddr)
-		rkcif_destroy_dummy_buf(stream);
-
-	v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished\n", stream->id);
-
+	stream->cur_stream_mode &= ~mode;
+	INIT_LIST_HEAD(&stream->vb_done_list);
+	v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished, dma_en 0x%x\n", stream->id, stream->dma_en);
 	mutex_unlock(&dev->stream_lock);
+	rkcif_detach_sync_mode(dev);
+}
+
+static void rkcif_stop_streaming(struct vb2_queue *queue)
+{
+	struct rkcif_stream *stream = queue->drv_priv;
+
+	rkcif_do_stop_stream(stream, RKCIF_STREAM_MODE_CAPTURE);
 }
 
 /*
@@ -2588,6 +5182,70 @@
 	return mode;
 }
 
+static u32 rkcif_determine_input_mode_rk3588(struct rkcif_stream *stream)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct rkcif_sensor_info *sensor_info = dev->active_sensor;
+	struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor;
+	__u32 intf = BT656_STD_RAW;
+	u32 mode = INPUT_MODE_YUV;
+	v4l2_std_id std;
+	int ret;
+
+	ret = v4l2_subdev_call(sensor_info->sd, video, querystd, &std);
+	if (ret == 0) {
+		/* retrieve std from sensor if exist */
+		switch (std) {
+		case V4L2_STD_NTSC:
+		case V4L2_STD_PAL:
+			mode = INPUT_BT656_YUV422;
+			break;
+		case V4L2_STD_ATSC:
+			mode = INPUT_BT1120_YUV422;
+			break;
+		default:
+			v4l2_err(&dev->v4l2_dev,
+				 "std: %lld is not supported", std);
+		}
+		mode |= CSI_WRDDR_TYPE_RAW8 << 6;
+	} else {
+		/* determine input mode by mbus_code (fmt_type) */
+		switch (stream->cif_fmt_in->fmt_type) {
+		case CIF_FMT_TYPE_YUV:
+			if (sensor_info->mbus.type == V4L2_MBUS_BT656) {
+				if ((sensor_info->mbus.flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE)
+					mode = INPUT_BT1120_YUV422;
+				else
+					mode = INPUT_BT656_YUV422;
+			} else {
+				mode = INPUT_BT601_YUV422;
+			}
+			mode |= CSI_WRDDR_TYPE_RAW8 << 6;
+			break;
+		case CIF_FMT_TYPE_RAW:
+			ret = v4l2_subdev_call(terminal_sensor->sd,
+					       core, ioctl,
+					       RKMODULE_GET_BT656_INTF_TYPE,
+					       &intf);
+			if (!ret) {
+				if (intf == BT656_SONY_RAW)
+					mode = INPUT_SONY_RAW;
+				else
+					mode = INPUT_BT601_RAW;
+			} else {
+				mode = INPUT_BT601_RAW;
+			}
+			mode |= stream->cif_fmt_in->csi_fmt_val << 6;
+			break;
+		}
+	}
+	if (stream->cif_fmt_in->field == V4L2_FIELD_NONE)
+		mode |= TRANSMIT_PROGRESS_RK3588;
+	else
+		mode |= TRANSMIT_INTERFACE_RK3588;
+	return mode;
+}
+
 static inline u32 rkcif_scl_ctl(struct rkcif_stream *stream)
 {
 	u32 fmt_type = stream->cif_fmt_in->fmt_type;
@@ -2612,15 +5270,21 @@
 		case V4L2_PIX_FMT_NV61:
 		case V4L2_PIX_FMT_NV12:
 		case V4L2_PIX_FMT_NV21:
-		case V4L2_PIX_FMT_YUYV:
-		case V4L2_PIX_FMT_YVYU:
-		case V4L2_PIX_FMT_UYVY:
-		case V4L2_PIX_FMT_VYUY:
 		case V4L2_PIX_FMT_GREY:
 		case V4L2_PIX_FMT_Y16:
 			bpp = fmt->bpp[plane_index];
 			break;
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_YVYU:
+		case V4L2_PIX_FMT_UYVY:
+		case V4L2_PIX_FMT_VYUY:
+			if (stream->cifdev->chip_id < CHIP_RK3588_CIF)
+				bpp = fmt->bpp[plane_index];
+			else
+				bpp = fmt->bpp[plane_index + 1];
+			break;
 		case V4L2_PIX_FMT_RGB24:
+		case V4L2_PIX_FMT_BGR24:
 		case V4L2_PIX_FMT_RGB565:
 		case V4L2_PIX_FMT_BGR666:
 		case V4L2_PIX_FMT_SRGGB8:
@@ -2636,8 +5300,13 @@
 		case V4L2_PIX_FMT_SGBRG12:
 		case V4L2_PIX_FMT_SBGGR12:
 		case V4L2_PIX_FMT_SBGGR16:
+		case V4L2_PIX_FMT_SGBRG16:
+		case V4L2_PIX_FMT_SGRBG16:
+		case V4L2_PIX_FMT_SRGGB16:
 		case V4l2_PIX_FMT_SPD16:
 		case V4l2_PIX_FMT_EBD8:
+		case V4L2_PIX_FMT_Y10:
+		case V4L2_PIX_FMT_Y12:
 			if (stream->cifdev->chip_id < CHIP_RV1126_CIF) {
 				bpp = max(fmt->bpp[plane_index], (u8)CIF_RAW_STORED_BIT_WIDTH);
 				cal = CIF_RAW_STORED_BIT_WIDTH;
@@ -2653,7 +5322,8 @@
 			}
 			break;
 		default:
-			pr_err("fourcc: %d is not supported!\n", fmt->fourcc);
+			v4l2_err(&stream->cifdev->v4l2_dev, "fourcc: %d is not supported!\n",
+				 fmt->fourcc);
 			break;
 		}
 	}
@@ -2687,7 +5357,8 @@
 
 	if (dev->terminal_sensor.sd) {
 		input_sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
-
+		input_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		input_sel.pad = 0;
 		ret = v4l2_subdev_call(dev->terminal_sensor.sd,
 				       pad, get_selection, NULL,
 				       &input_sel);
@@ -2697,6 +5368,7 @@
 			stream->crop_mask |= CROP_SRC_SENSOR_MASK;
 			dev->terminal_sensor.selection = input_sel;
 		} else {
+			stream->crop_mask &= ~CROP_SRC_SENSOR_MASK;
 			dev->terminal_sensor.selection.r = dev->terminal_sensor.raw_rect;
 		}
 	}
@@ -2717,8 +5389,10 @@
 			stream->crop[CROP_SRC_ACT].top = stream->crop[CROP_SRC_USR].top +
 							  stream->crop[CROP_SRC_SENSOR].top;
 		}
-	} else {
+	} else if (stream->crop_mask & CROP_SRC_SENSOR_MASK) {
 		stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_SENSOR];
+	} else {
+		stream->crop[CROP_SRC_ACT] = dev->terminal_sensor.raw_rect;
 	}
 }
 
@@ -2732,11 +5406,11 @@
 	struct rkcif_device *dev = stream->cifdev;
 	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
 	struct v4l2_rect input, *crop;
-	int vc;
 
 	if (dev->terminal_sensor.sd) {
-		stream->cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd,
-						   &input, stream->id, &vc);
+		stream->cif_fmt_in = rkcif_get_input_fmt(dev,
+							 &input, stream->id,
+							 &dev->channels[stream->id]);
 		if (!stream->cif_fmt_in) {
 			v4l2_err(v4l2_dev, "Input fmt is invalid\n");
 			return -EINVAL;
@@ -2746,7 +5420,6 @@
 		return -EINVAL;
 	}
 
-	stream->vc = vc;
 	if (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 ||
 		stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8) {
 		stream->crop_enable = false;
@@ -2764,7 +5437,9 @@
 		return -EINVAL;
 	}
 
-	if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
+	if (dev->active_sensor &&
+	    (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	    dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY)) {
 		if (crop->left > 0) {
 			int align_x = get_csi_crop_align(stream->cif_fmt_in);
 
@@ -2775,7 +5450,7 @@
 				return -EINVAL;
 			}
 		}
-	} else if (dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) {
+	} else if (dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) {
 		if (crop->left % 4 != 0 && crop->width % 4 != 0) {
 			v4l2_err(v4l2_dev,
 				 "ERROR: lvds crop left and width must align %d\n", 4);
@@ -2807,8 +5482,8 @@
 			 __func__, stream->id);
 		return -ENODEV;
 	}
-	ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config,
-			       &sensor->mbus);
+	ret = v4l2_subdev_call(sensor->sd, pad, get_mbus_config,
+			       0, &sensor->mbus);
 	if (ret && ret != -ENOIOCTLCMD) {
 		v4l2_err(&stream->cifdev->v4l2_dev,
 			 "%s: get remote %s mbus failed!\n", __func__, sensor->sd->name);
@@ -2820,24 +5495,38 @@
 	terminal_sensor = &stream->cifdev->terminal_sensor;
 	get_remote_terminal_sensor(stream, &terminal_sensor->sd);
 	if (terminal_sensor->sd) {
-		ret = v4l2_subdev_call(terminal_sensor->sd, video, g_mbus_config,
-				       &terminal_sensor->mbus);
+		ret = v4l2_subdev_call(terminal_sensor->sd, pad, get_mbus_config,
+				       0, &terminal_sensor->mbus);
 		if (ret && ret != -ENOIOCTLCMD) {
 			v4l2_err(&stream->cifdev->v4l2_dev,
 				 "%s: get terminal %s mbus failed!\n",
 				 __func__, terminal_sensor->sd->name);
 			return ret;
 		}
-		if (v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_GET_CSI_DSI_INFO,
-		    &terminal_sensor->dsi_input_en)) {
-			v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
-				 "%s: get terminal %s CSI/DSI sel failed, default csi input!\n",
+		ret = v4l2_subdev_call(terminal_sensor->sd, video,
+				       g_frame_interval, &terminal_sensor->fi);
+		if (ret) {
+			v4l2_err(&stream->cifdev->v4l2_dev,
+				 "%s: get terminal %s g_frame_interval failed!\n",
 				 __func__, terminal_sensor->sd->name);
+			return ret;
+		}
+		if (v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_GET_CSI_DSI_INFO,
+					&terminal_sensor->dsi_input_en)) {
+			v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
+				"%s: get terminal %s CSI/DSI sel failed, default csi input!\n",
+				__func__, terminal_sensor->sd->name);
 			terminal_sensor->dsi_input_en = 0;
 		}
+	} else {
+		v4l2_err(&stream->cifdev->v4l2_dev,
+			 "%s: stream[%d] get remote terminal sensor failed!\n",
+			 __func__, stream->id);
+		return -ENODEV;
 	}
 
-	if (terminal_sensor->mbus.type == V4L2_MBUS_CSI2 ||
+	if (terminal_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	    terminal_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ||
 	    terminal_sensor->mbus.type == V4L2_MBUS_CCP2) {
 		switch (terminal_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
 		case V4L2_MBUS_CSI2_1_LANE:
@@ -2864,7 +5553,85 @@
 	return ret;
 }
 
-static int rkcif_stream_start(struct rkcif_stream *stream)
+static int rkcif_dvp_get_output_type_mask(struct rkcif_stream *stream)
+{
+	unsigned int mask;
+	const struct cif_output_fmt *fmt = stream->cif_fmt_out;
+
+	switch (fmt->fourcc) {
+	case V4L2_PIX_FMT_NV16:
+		mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_UYVY << 1);
+		break;
+	case V4L2_PIX_FMT_NV61:
+		mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_VYUY << 1);
+		break;
+	case V4L2_PIX_FMT_NV12:
+		mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_UYVY << 1);
+		break;
+	case V4L2_PIX_FMT_NV21:
+		mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_VYUY << 1);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_YUYV << 1);
+		break;
+	case V4L2_PIX_FMT_YVYU:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_YVYU << 1);
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_UYVY << 1);
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) |
+		       (CSI_YUV_OUTPUT_ORDER_VYUY << 1);
+		break;
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_BGR666:
+		mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11;
+		break;
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_Y10:
+	case V4L2_PIX_FMT_Y12:
+		if (stream->is_compact)
+			mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11;
+		else
+			mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11;
+		break;
+	case V4L2_PIX_FMT_SBGGR16:
+	case V4L2_PIX_FMT_SGBRG16:
+	case V4L2_PIX_FMT_SGRBG16:
+	case V4L2_PIX_FMT_SRGGB16:
+	case V4L2_PIX_FMT_Y16:
+		mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11;
+		break;
+	default:
+		mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11;
+		break;
+	}
+	return mask;
+}
+
+static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode)
 {
 	u32 val, mbus_flags, href_pol, vsync_pol,
 	    xfer_mode = 0, yc_swap = 0, inputmode = 0,
@@ -2873,20 +5640,66 @@
 	    multi_id_mode = BT656_1120_MULTI_ID_MODE_1,
 	    multi_id_sel = BT656_1120_MULTI_ID_SEL_LSB,
 	    bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES,
-	    bt1120_flags = 0;
+	    bt1120_flags = 0,
+	    out_fmt_mask = 0,
+	    in_fmt_yuv_order = 0;
 	struct rkmodule_bt656_mbus_info bt1120_info;
 	struct rkcif_device *dev = stream->cifdev;
 	struct rkcif_sensor_info *sensor_info;
 	struct v4l2_mbus_config *mbus;
 	struct rkcif_dvp_sof_subdev *sof_sd = &dev->dvp_sof_subdev;
 	const struct cif_output_fmt *fmt;
+	unsigned int dma_en = 0;
+	unsigned int dma_state = 0;
+	int i = 0;
+	u32 sav_detect = BT656_DETECT_SAV;
+	u32 reserved = 0;
 
-	if (stream->state != RKCIF_STATE_RESET_IN_STREAMING)
+	if (stream->state < RKCIF_STATE_STREAMING) {
 		stream->frame_idx = 0;
+		stream->buf_wake_up_cnt = 0;
+		stream->lack_buf_cnt = 0;
+		stream->frame_phase = 0;
+		stream->is_in_vblank = false;
+		stream->is_change_toisp = false;
+	}
 
 	sensor_info = dev->active_sensor;
 	mbus = &sensor_info->mbus;
 
+	dma_state = stream->dma_en;
+	if ((mode & RKCIF_STREAM_MODE_CAPTURE) == RKCIF_STREAM_MODE_CAPTURE)
+		stream->dma_en |= RKCIF_DMAEN_BY_VICAP;
+	else if ((mode & RKCIF_STREAM_MODE_TOISP_RDBK) == RKCIF_STREAM_MODE_TOISP_RDBK)
+		stream->dma_en |= RKCIF_DMAEN_BY_ISP;
+	else if ((mode & RKCIF_STREAM_MODE_ROCKIT) == RKCIF_STREAM_MODE_ROCKIT)
+		stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT;
+
+	if (dma_state)
+		return 0;
+
+	mbus_flags = mbus->flags;
+	if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) {
+		bt1120_edge_mode = (dev->chip_id < CHIP_RK3588_CIF ?
+			BT1120_CLOCK_DOUBLE_EDGES : BT1120_CLOCK_DOUBLE_EDGES_RK3588);
+		rkcif_enable_dvp_clk_dual_edge(dev, true);
+	} else {
+		bt1120_edge_mode = dev->chip_id < CHIP_RK3588_CIF ?
+			BT1120_CLOCK_SINGLE_EDGES : BT1120_CLOCK_SINGLE_EDGES_RK3588;
+		rkcif_enable_dvp_clk_dual_edge(dev, false);
+	}
+
+	if (IS_ENABLED(CONFIG_CPU_RV1106))
+		rkcif_config_dvp_pin(dev, true);
+
+	if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_RISING);
+	else
+		rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_FALLING);
+
+#if IS_ENABLED(CONFIG_CPU_RV1106)
+	rv1106_sdmmc_get_lock();
+#endif
 	if (sensor_info->sd && mbus->type == V4L2_MBUS_BT656) {
 		int ret;
 
@@ -2910,32 +5723,21 @@
 				multi_id_mode = BT656_1120_MULTI_ID_MODE_4;
 			else if (((bt1120_flags & RKMODULE_CAMERA_BT656_CHANNELS) >> 2) > 1)
 				multi_id_mode = BT656_1120_MULTI_ID_MODE_2;
-
-			multi_id = DVP_SW_MULTI_ID(stream->id, stream->id, bt1120_info.id_en_bits);
+			for (i = 0; i < 4; i++)
+				multi_id |= DVP_SW_MULTI_ID(i, i, bt1120_info.id_en_bits);
 			rkcif_write_register_or(dev, CIF_REG_DVP_MULTI_ID, multi_id);
 		}
 	}
-
-	mbus_flags = mbus->flags;
-	if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) {
-		bt1120_edge_mode = BT1120_CLOCK_DOUBLE_EDGES;
-		rkcif_enable_dvp_clk_dual_edge(dev, true);
-	} else {
-		bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES;
-		rkcif_enable_dvp_clk_dual_edge(dev, false);
-	}
-
-	if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
-		rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_RISING);
-	else
-		rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_FALLING);
 
 	href_pol = (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) ?
 		    HSY_HIGH_ACTIVE : HSY_LOW_ACTIVE;
 	vsync_pol = (mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) ?
 		     VSY_HIGH_ACTIVE : VSY_LOW_ACTIVE;
 
-	inputmode = rkcif_determine_input_mode(stream);
+	if (dev->chip_id < CHIP_RK3588_CIF)
+		inputmode = rkcif_determine_input_mode(stream);
+	else
+		inputmode = rkcif_determine_input_mode_rk3588(stream);
 	if (dev->chip_id <= CHIP_RK1808_CIF) {
 		if (inputmode == INPUT_MODE_BT1120) {
 			if (stream->cif_fmt_in->field == V4L2_FIELD_NONE)
@@ -2945,7 +5747,7 @@
 			if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val))
 				yc_swap = BT1120_YC_SWAP;
 		}
-	} else {
+	} else if (dev->chip_id < CHIP_RK3588_CIF) {
 		if (sensor_info->mbus.type == V4L2_MBUS_BT656) {
 			if (stream->cif_fmt_in->field == V4L2_FIELD_NONE)
 				xfer_mode = BT1120_TRANSMIT_PROGRESS;
@@ -2957,9 +5759,14 @@
 			if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val))
 				yc_swap = BT1120_YC_SWAP;
 		}
+	} else {
+		if ((inputmode & INPUT_BT1120_YUV422) == INPUT_BT1120_YUV422)
+			if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val))
+				yc_swap = BT1120_YC_SWAP_RK3588;
 	}
 
-	if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
+	if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	    dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) {
 		inputmode = INPUT_MODE_MIPI;
 
 		/* if cif is linked with mipi,
@@ -2977,33 +5784,43 @@
 			mipimode = MIPI_MODE_32BITS_BYPASS;
 	}
 
-	val = vsync_pol | href_pol | inputmode | mipimode
-	      | stream->cif_fmt_out->fmt_val
-	      | stream->cif_fmt_in->dvp_fmt_val
-	      | xfer_mode | yc_swap | multi_id_en
-	      | multi_id_sel | multi_id_mode | bt1120_edge_mode;
-
-	if (stream->is_high_align)
-		val |= CIF_HIGH_ALIGN;
-	else
-		val &= ~CIF_HIGH_ALIGN;
+	if (dev->chip_id < CHIP_RK3588_CIF) {
+		val = vsync_pol | href_pol | inputmode | mipimode
+			| stream->cif_fmt_out->fmt_val
+			| stream->cif_fmt_in->dvp_fmt_val
+			| xfer_mode | yc_swap | multi_id_en
+			| multi_id_sel | multi_id_mode | bt1120_edge_mode;
+		if (stream->is_high_align)
+			val |= CIF_HIGH_ALIGN;
+		else
+			val &= ~CIF_HIGH_ALIGN;
+	} else {
+		out_fmt_mask = rkcif_dvp_get_output_type_mask(stream);
+		in_fmt_yuv_order = rkcif_dvp_get_input_yuv_order(stream);
+		val = vsync_pol | href_pol | inputmode
+			| yc_swap
+			| out_fmt_mask
+			| in_fmt_yuv_order
+			| multi_id_en
+			| sav_detect
+			| multi_id_sel | multi_id_mode | bt1120_edge_mode;
+		if (stream->is_high_align)
+			val |= CIF_HIGH_ALIGN_RK3588;
+		else
+			val &= ~CIF_HIGH_ALIGN_RK3588;
+	}
 	rkcif_write_register(dev, CIF_REG_DVP_FOR, val);
 
-	val = stream->pixm.width;
-	if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) {
-		fmt = find_output_fmt(stream, stream->pixm.pixelformat);
-		if (fmt->fourcc == V4L2_PIX_FMT_GREY ||
-		    fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
-		    fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
-		    fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
-		    fmt->fourcc == V4L2_PIX_FMT_SBGGR8)
+	if (dev->chip_id >= CHIP_RK3588_CIF) {
+		val = stream->pixm.plane_fmt[0].bytesperline;
+	} else {
+		fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat);
+		if (fmt->fmt_type == CIF_FMT_TYPE_RAW &&
+		    fmt->csi_fmt_val == CSI_WRDDR_TYPE_RAW8)
 			val = ALIGN(stream->pixm.width * fmt->raw_bpp / 8, 256);
 		else
 			val = stream->pixm.width * rkcif_cal_raw_vir_line_ratio(stream, fmt);
 	}
-	rkcif_write_register(dev, CIF_REG_DVP_VIR_LINE_WIDTH, val);
-	rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE,
-			     stream->pixm.width | (stream->pixm.height << 16));
 
 	if (stream->crop_enable) {
 		dev->channels[stream->id].crop_en = 1;
@@ -3019,6 +5836,10 @@
 		dev->channels[stream->id].crop_en = 0;
 	}
 
+	rkcif_write_register(dev, CIF_REG_DVP_VIR_LINE_WIDTH, val);
+	rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE,
+			     dev->channels[stream->id].width |
+			     (dev->channels[stream->id].height << 16));
 	rkcif_write_register(dev, CIF_REG_DVP_CROP,
 			     dev->channels[stream->id].crop_st_y << CIF_CROP_Y_SHIFT |
 			     dev->channels[stream->id].crop_st_x);
@@ -3026,17 +5847,44 @@
 	if (atomic_read(&dev->pipe.stream_cnt) <= 1)
 		rkcif_write_register(dev, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS);
 
-	rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, INTSTAT_CLS);
-	rkcif_write_register(dev, CIF_REG_DVP_SCL_CTRL, rkcif_scl_ctl(stream));
+	if (dev->chip_id < CHIP_RK3588_CIF) {
+		rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, INTSTAT_CLS);
+		rkcif_write_register(dev, CIF_REG_DVP_SCL_CTRL, rkcif_scl_ctl(stream));
+		rkcif_write_register_or(dev, CIF_REG_DVP_INTEN,
+				DVP_DMA_END_INTSTAT(stream->id) |
+				INTSTAT_ERR | PST_INF_FRAME_END);
+		/* enable line int for sof */
+		rkcif_write_register(dev, CIF_REG_DVP_LINE_INT_NUM, 0x1);
+		rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, LINE_INT_EN);
+	} else {
+		if (dev->chip_id == CHIP_RV1106_CIF)
+			reserved = 0xfc3c0000;
+		else
+			reserved = 0;
+		rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, 0x3c3ffff | reserved);
+		rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, 0x033ffff);//0x3c3ffff
+	}
 
-	if (dev->chip_id < CHIP_RK1808_CIF)
-		rkcif_assign_new_buffer_oneframe(stream,
-						 RKCIF_YUV_ADDR_STATE_INIT);
-	else
-		rkcif_assign_new_buffer_pingpong(stream,
+	if (stream->dma_en) {
+		if (dev->chip_id < CHIP_RK1808_CIF) {
+			rkcif_assign_new_buffer_oneframe(stream,
+							 RKCIF_YUV_ADDR_STATE_INIT);
+		} else {
+			if (mode == RKCIF_STREAM_MODE_CAPTURE)
+				rkcif_assign_new_buffer_pingpong(stream,
 						 RKCIF_YUV_ADDR_STATE_INIT,
 						 stream->id);
-
+			else if (mode == RKCIF_STREAM_MODE_TOISP ||
+				 mode == RKCIF_STREAM_MODE_TOISP_RDBK)
+				rkcif_assign_new_buffer_pingpong_toisp(stream,
+						       RKCIF_YUV_ADDR_STATE_INIT,
+						       stream->id);
+			else if (mode == RKCIF_STREAM_MODE_ROCKIT)
+				rkcif_assign_new_buffer_pingpong_rockit(stream,
+							RKCIF_YUV_ADDR_STATE_INIT,
+							stream->id);
+		}
+	}
 	rkcif_write_register_or(dev, CIF_REG_DVP_INTEN,
 				DVP_DMA_END_INTSTAT(stream->id) |
 				INTSTAT_ERR | PST_INF_FRAME_END);
@@ -3052,14 +5900,47 @@
 	else
 		workmode = MODE_LINELOOP;
 
-	if (inputmode == INPUT_MODE_BT1120) {
+	if ((inputmode & INPUT_MODE_BT1120) == INPUT_MODE_BT1120) {
 		workmode = MODE_PINGPONG;
 		dev->workmode = RKCIF_WORKMODE_PINGPONG;
 	}
 
-	rkcif_write_register(dev, CIF_REG_DVP_CTRL,
-			     AXI_BURST_16 | workmode | ENABLE_CAPTURE);
-
+	if (dev->chip_id == CHIP_RK3588_CIF) {
+		if (stream->dma_en)
+			dma_en = DVP_DMA_EN;
+		if (stream->lack_buf_cnt == 2)
+			dma_en = 0;
+		rkcif_write_register(dev, CIF_REG_DVP_CTRL,
+			     DVP_SW_WATER_LINE_25
+			     | dma_en
+			     | DVP_PRESS_EN
+			     | DVP_HURRY_EN
+			     | DVP_SW_WATER_LINE_25
+			     | DVP_SW_PRESS_VALUE(3)
+			     | DVP_SW_HURRY_VALUE(3)
+			     | ENABLE_CAPTURE);
+	} else if (dev->chip_id == CHIP_RV1106_CIF) {
+		if (stream->dma_en)
+			dma_en = DVP_SW_DMA_EN(stream->id);
+		if (stream->lack_buf_cnt == 2)
+			dma_en = 0;
+		rkcif_write_register(dev, CIF_REG_DVP_CTRL,
+			     DVP_SW_WATER_LINE_25
+			     | DVP_PRESS_EN
+			     | DVP_HURRY_EN
+			     | DVP_SW_WATER_LINE_25
+			     | DVP_SW_PRESS_VALUE(3)
+			     | DVP_SW_HURRY_VALUE(3)
+			     | DVP_SW_CAP_EN(stream->id)
+			     | dma_en
+			     | ENABLE_CAPTURE);
+	} else {
+		rkcif_write_register(dev, CIF_REG_DVP_CTRL,
+				     AXI_BURST_16 | workmode | ENABLE_CAPTURE);
+	}
+#if IS_ENABLED(CONFIG_CPU_RV1106)
+	rv1106_sdmmc_put_lock();
+#endif
 	atomic_set(&sof_sd->frm_sync_seq, 0);
 	stream->state = RKCIF_STATE_STREAMING;
 	stream->cifdev->dvp_sof_in_oneframe = 0;
@@ -3067,34 +5948,198 @@
 	return 0;
 }
 
-static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
+static void rkcif_attach_sync_mode(struct rkcif_device *cifdev)
 {
-	struct rkcif_stream *stream = queue->drv_priv;
+	struct rkcif_hw *hw = cifdev->hw_dev;
+	struct rkcif_device *dev;
+	struct sditf_priv *priv;
+	int i = 0, j = 0;
+	int ret = 0;
+	int count = 0;
+	int sync_type = NO_SYNC_MODE;
+	int sync_group = 0;
+	struct rkcif_sync_cfg sync_cfg;
+	struct rkcif_multi_sync_config *sync_config;
+
+	mutex_lock(&hw->dev_lock);
+	if (cifdev->sditf_cnt <= 1) {
+		ret = v4l2_subdev_call(cifdev->terminal_sensor.sd,
+				       core, ioctl,
+				       RKMODULE_GET_SYNC_MODE,
+				       &sync_type);
+		if (!ret)
+			sync_cfg.type = sync_type;
+		else
+			sync_cfg.type = NO_SYNC_MODE;
+		ret = v4l2_subdev_call(cifdev->terminal_sensor.sd,
+				       core, ioctl,
+				       RKMODULE_GET_GROUP_ID,
+				       &sync_group);
+		if (!ret && sync_group < RKCIF_MAX_GROUP)
+			sync_cfg.group = sync_group;
+		else
+			sync_cfg.group = 0;
+	} else {
+		for (j = 0; j < cifdev->sditf_cnt; j++) {
+			ret |= v4l2_subdev_call(cifdev->sditf[j]->sensor_sd,
+					core, ioctl,
+					RKMODULE_GET_SYNC_MODE,
+					&sync_type);
+			if (!ret && sync_type)
+				break;
+		}
+		if (!ret)
+			sync_cfg.type = sync_type;
+		else
+			sync_cfg.type = NO_SYNC_MODE;
+		ret = v4l2_subdev_call(cifdev->sditf[j]->sensor_sd,
+				       core, ioctl,
+				       RKMODULE_GET_GROUP_ID,
+				       &sync_group);
+		if (!ret && sync_group < RKCIF_MAX_GROUP)
+			sync_cfg.group = sync_group;
+		else
+			sync_cfg.group = 0;
+	}
+	cifdev->sync_cfg = sync_cfg;
+	if (sync_cfg.type == NO_SYNC_MODE ||
+	    hw->sync_config[sync_cfg.group].is_attach) {
+		mutex_unlock(&hw->dev_lock);
+		return;
+	}
+
+	sync_config = &hw->sync_config[sync_cfg.group];
+	memset(sync_config, 0, sizeof(struct rkcif_multi_sync_config));
+	for (i = 0; i < hw->dev_num; i++) {
+		dev = hw->cif_dev[i];
+		if (dev->sditf_cnt <= 1) {
+			ret = v4l2_subdev_call(dev->terminal_sensor.sd,
+					       core, ioctl,
+					       RKMODULE_GET_SYNC_MODE,
+					       &sync_type);
+			if (!ret)
+				sync_cfg.type = sync_type;
+			else
+				sync_cfg.type = NO_SYNC_MODE;
+			ret = v4l2_subdev_call(dev->terminal_sensor.sd,
+					       core, ioctl,
+					       RKMODULE_GET_GROUP_ID,
+					       &sync_group);
+			if (!ret && sync_group < RKCIF_MAX_GROUP)
+				sync_cfg.group = sync_group;
+			else
+				sync_cfg.group = 0;
+		} else {
+			priv = dev->sditf[0];
+			if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) {
+				for (j = 0; j < dev->sditf_cnt; j++) {
+					ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd,
+							core, ioctl,
+							RKMODULE_GET_SYNC_MODE,
+							&sync_type);
+					if (!ret && sync_type) {
+						priv = dev->sditf[j];
+						break;
+					}
+				}
+				if (!ret)
+					sync_cfg.type = sync_type;
+				else
+					sync_cfg.type = NO_SYNC_MODE;
+				ret = v4l2_subdev_call(priv->sensor_sd,
+						       core, ioctl,
+						       RKMODULE_GET_GROUP_ID,
+						       &sync_group);
+				if (!ret && sync_group < RKCIF_MAX_GROUP)
+					sync_cfg.group = sync_group;
+				else
+					sync_cfg.group = 0;
+			}
+		}
+		if (sync_cfg.group == cifdev->sync_cfg.group) {
+			if (sync_cfg.type == EXTERNAL_MASTER_MODE) {
+				count = sync_config->ext_master.count;
+				sync_config->ext_master.cif_dev[count] = dev;
+				sync_config->ext_master.count++;
+				sync_config->dev_cnt++;
+				sync_config->sync_mask |= BIT(dev->csi_host_idx);
+			} else if (sync_cfg.type == INTERNAL_MASTER_MODE) {
+				count = sync_config->int_master.count;
+				sync_config->int_master.cif_dev[count] = dev;
+				sync_config->int_master.count++;
+				sync_config->dev_cnt++;
+				sync_config->sync_mask |= BIT(dev->csi_host_idx);
+			} else if (sync_cfg.type == SLAVE_MODE) {
+				count = sync_config->slave.count;
+				sync_config->slave.cif_dev[count] = dev;
+				sync_config->slave.count++;
+				sync_config->dev_cnt++;
+				sync_config->sync_mask |= BIT(dev->csi_host_idx);
+			}
+			dev->sync_cfg = sync_cfg;
+		} else {
+			ret = v4l2_subdev_call(dev->terminal_sensor.sd,
+					       core, ioctl,
+					       RKMODULE_GET_SYNC_MODE,
+					       &sync_type);
+		}
+	}
+	if (sync_config->int_master.count == 1) {
+		if (sync_config->ext_master.count) {
+			sync_config->mode = RKCIF_MASTER_MASTER;
+			sync_config->is_attach = true;
+		} else if (sync_config->slave.count) {
+			sync_config->mode = RKCIF_MASTER_SLAVE;
+			sync_config->is_attach = true;
+		} else {
+			dev_info(hw->dev,
+				 "Missing slave device, do not use sync mode\n");
+		}
+		if (sync_config->is_attach)
+			dev_info(hw->dev,
+				 "group %d, int_master %d, ext_master %d, slave %d\n",
+				 i,
+				 sync_config->int_master.count,
+				 sync_config->ext_master.count,
+				 sync_config->slave.count);
+	}
+	mutex_unlock(&hw->dev_lock);
+}
+
+static void rkcif_monitor_reset_event(struct rkcif_device *dev);
+
+int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
+{
 	struct rkcif_vdev_node *node = &stream->vnode;
 	struct rkcif_device *dev = stream->cifdev;
+	struct rkcif_hw *hw_dev = dev->hw_dev;
 	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
 	struct rkcif_sensor_info *sensor_info = dev->active_sensor;
-	struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor;
+	struct rkcif_sensor_info *terminal_sensor = NULL;
 	struct rkmodule_hdr_cfg hdr_cfg;
+	struct rkcif_csi_info csi_info = {0};
 	int rkmodule_stream_seq = RKMODULE_START_STREAM_DEFAULT;
 	int ret;
+	int i = 0;
 
 	v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id);
 
+	rkcif_attach_sync_mode(dev);
 	mutex_lock(&dev->stream_lock);
 
-	if (WARN_ON(stream->state != RKCIF_STATE_READY)) {
+	if ((stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE) == mode) {
 		ret = -EBUSY;
 		v4l2_err(v4l2_dev, "stream in busy state\n");
 		goto destroy_buf;
 	}
+	if (stream->dma_en == 0)
+		stream->fs_cnt_in_single_frame = 0;
 	if (stream->is_line_wake_up)
 		stream->is_line_inten = true;
 	else
 		stream->is_line_inten = false;
-	stream->fs_cnt_in_single_frame = 0;
 
-	if (dev->active_sensor) {
+	if (!dev->active_sensor) {
 		ret = rkcif_update_sensor_info(stream);
 		if (ret < 0) {
 			v4l2_err(v4l2_dev,
@@ -3103,16 +6148,16 @@
 			goto out;
 		}
 	}
-
+	terminal_sensor = &dev->terminal_sensor;
 	if (terminal_sensor->sd) {
 		ret = v4l2_subdev_call(terminal_sensor->sd,
 				       core, ioctl,
 				       RKMODULE_GET_HDR_CFG,
 				       &hdr_cfg);
 		if (!ret)
-			dev->hdr.mode = hdr_cfg.hdr_mode;
+			dev->hdr = hdr_cfg;
 		else
-			dev->hdr.mode = NO_HDR;
+			dev->hdr.hdr_mode = NO_HDR;
 
 		ret = v4l2_subdev_call(terminal_sensor->sd,
 				       video, g_frame_interval, &terminal_sensor->fi);
@@ -3133,109 +6178,149 @@
 	if (ret < 0)
 		goto destroy_buf;
 
+	mutex_lock(&hw_dev->dev_lock);
+	if (atomic_read(&dev->pipe.stream_cnt) == 0 &&
+	    dev->active_sensor &&
+	    (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	     dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ||
+	     dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) {
+		if (dev->channels[0].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
+			csi_info.csi_num = dev->channels[0].capture_info.multi_dev.dev_num;
+			if (csi_info.csi_num > RKCIF_MAX_CSI_NUM) {
+				v4l2_err(v4l2_dev,
+					 "csi num %d, max %d\n",
+					 csi_info.csi_num, RKCIF_MAX_CSI_NUM);
+				goto out;
+			}
+			for (i = 0; i < csi_info.csi_num; i++) {
+				csi_info.csi_idx[i] = dev->channels[0].capture_info.multi_dev.dev_idx[i];
+				if (dev->hw_dev->is_rk3588s2)
+					v4l2_info(v4l2_dev, "rk3588s2 combine mode attach to mipi%d\n",
+						  csi_info.csi_idx[i]);
+			}
+		} else {
+			csi_info.csi_num = 1;
+			dev->csi_host_idx = dev->csi_host_idx_def;
+			csi_info.csi_idx[0] = dev->csi_host_idx;
+		}
+		ret = v4l2_subdev_call(dev->active_sensor->sd,
+				       core, ioctl,
+				       RKCIF_CMD_SET_CSI_IDX,
+				       &csi_info);
+		if (ret)
+			v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx);
+
+	}
+
 	if (((dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_BT656) ||
 	     dev->is_use_dummybuf) &&
-	    (!dev->dummy_buf.vaddr)) {
+	    (!dev->hw_dev->dummy_buf.vaddr) &&
+	    mode == RKCIF_STREAM_MODE_CAPTURE) {
 		ret = rkcif_create_dummy_buf(stream);
 		if (ret < 0) {
+			mutex_unlock(&hw_dev->dev_lock);
 			v4l2_err(v4l2_dev, "Failed to create dummy_buf, %d\n", ret);
 			goto destroy_buf;
 		}
 	}
+	mutex_unlock(&hw_dev->dev_lock);
 
-	/* enable clocks/power-domains */
-	ret = pm_runtime_get_sync(dev->dev);
-	if (ret < 0) {
-		v4l2_err(v4l2_dev, "Failed to get runtime pm, %d\n",
-			 ret);
-		goto  destroy_buf;
+	if (mode == RKCIF_STREAM_MODE_CAPTURE)
+		tasklet_enable(&stream->vb_done_tasklet);
+
+	if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) {
+		ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true);
+		if (ret < 0) {
+			v4l2_err(v4l2_dev, "open cif pipeline failed %d\n",
+				 ret);
+			goto destroy_buf;
+		}
+
+		/*
+		 * start sub-devices
+		 * When use bt601, the sampling edge of cif is random,
+		 * can be rising or fallling after powering on cif.
+		 * To keep the coherence of edge, open sensor in advance.
+		 */
+		if (sensor_info->mbus.type == V4L2_MBUS_PARALLEL ||
+		    rkmodule_stream_seq == RKMODULE_START_STREAM_FRONT) {
+			ret = dev->pipe.set_stream(&dev->pipe, true);
+			if (ret < 0)
+				goto destroy_buf;
+		}
 	}
-
-	ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true);
-	if (ret < 0) {
-		v4l2_err(v4l2_dev, "open cif pipeline failed %d\n",
-			 ret);
-		goto destroy_buf;
-	}
-
-	/*
-	 * start sub-devices
-	 * When use bt601, the sampling edge of cif is random,
-	 * can be rising or fallling after powering on cif.
-	 * To keep the coherence of edge, open sensor in advance.
-	 */
-	if (sensor_info->mbus.type == V4L2_MBUS_PARALLEL ||
-	    rkmodule_stream_seq == RKMODULE_START_STREAM_FRONT) {
-		ret = dev->pipe.set_stream(&dev->pipe, true);
-		if (ret < 0)
-			goto runtime_put;
-	}
-
 	if (dev->chip_id >= CHIP_RK1808_CIF) {
-		if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 ||
-		    dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)
-			ret = rkcif_csi_stream_start(stream);
+		if (dev->active_sensor  &&
+		    (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+		    dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ||
+		    dev->active_sensor->mbus.type == V4L2_MBUS_CCP2))
+			ret = rkcif_csi_stream_start(stream, mode);
 		else
-			ret = rkcif_stream_start(stream);
+			ret = rkcif_stream_start(stream, mode);
 	} else {
-		ret = rkcif_stream_start(stream);
+		ret = rkcif_stream_start(stream, mode);
 	}
 
 	if (ret < 0)
-		goto runtime_put;
+		goto destroy_buf;
 
-	ret = media_pipeline_start(&node->vdev.entity, &dev->pipe.pipe);
-	if (ret < 0) {
-		v4l2_err(&dev->v4l2_dev, "start pipeline failed %d\n",
-			 ret);
-		goto pipe_stream_off;
+	if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) {
+		ret = media_pipeline_start(&node->vdev.entity, &dev->pipe.pipe);
+		if (ret < 0) {
+			v4l2_err(&dev->v4l2_dev, "start pipeline failed %d\n",
+				 ret);
+			goto pipe_stream_off;
+		}
+
+		if (sensor_info->mbus.type != V4L2_MBUS_PARALLEL &&
+		    rkmodule_stream_seq != RKMODULE_START_STREAM_FRONT) {
+			ret = dev->pipe.set_stream(&dev->pipe, true);
+			if (ret < 0)
+				goto stop_stream;
+		}
 	}
-
-	if (sensor_info->mbus.type != V4L2_MBUS_PARALLEL &&
-	    rkmodule_stream_seq != RKMODULE_START_STREAM_FRONT) {
-		ret = dev->pipe.set_stream(&dev->pipe, true);
-		if (ret < 0)
-			goto stop_stream;
-	}
-
-	if (dev->hdr.mode == NO_HDR) {
-		if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING) {
-			rkcif_start_luma(&dev->luma_vdev,
+	if (dev->chip_id == CHIP_RV1126_CIF ||
+	    dev->chip_id == CHIP_RV1126_CIF_LITE ||
+	    dev->chip_id == CHIP_RK3568_CIF) {
+		if (dev->hdr.hdr_mode == NO_HDR) {
+			if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING)
+				rkcif_start_luma(&dev->luma_vdev,
+						dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in);
+		} else if (dev->hdr.hdr_mode == HDR_X2) {
+			if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING)
+				rkcif_start_luma(&dev->luma_vdev,
+					dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in);
+		} else if (dev->hdr.hdr_mode == HDR_X3) {
+			if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_STREAMING)
+				rkcif_start_luma(&dev->luma_vdev,
 					dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in);
 		}
-	} else if (dev->hdr.mode == HDR_X2) {
-		if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING &&
-		    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING) {
-			rkcif_start_luma(&dev->luma_vdev,
-				dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in);
-		}
-	} else if (dev->hdr.mode == HDR_X3) {
-		if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING &&
-		    dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING &&
-		    dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_STREAMING) {
-			rkcif_start_luma(&dev->luma_vdev,
-				dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in);
-		}
 	}
-
 	dev->reset_work_cancel = false;
-	if (dev->hdr.mode == NO_HDR)
-		stream->streamon_timestamp = ktime_get_ns();
+	stream->cur_stream_mode |= mode;
+	rkcif_monitor_reset_event(dev);
 	goto out;
 
 stop_stream:
 	rkcif_stream_stop(stream);
 pipe_stream_off:
 	dev->pipe.set_stream(&dev->pipe, false);
-runtime_put:
-	pm_runtime_put_sync(dev->dev);
+
 destroy_buf:
-	if (stream->next_buf)
-		vb2_buffer_done(&stream->next_buf->vb.vb2_buf,
-				VB2_BUF_STATE_QUEUED);
+	if (mode == RKCIF_STREAM_MODE_CAPTURE)
+		tasklet_disable(&stream->vb_done_tasklet);
 	if (stream->curr_buf)
-		vb2_buffer_done(&stream->curr_buf->vb.vb2_buf,
-				VB2_BUF_STATE_QUEUED);
+		list_add_tail(&stream->curr_buf->queue, &stream->buf_head);
+	if (stream->next_buf &&
+	    stream->next_buf != stream->curr_buf)
+		list_add_tail(&stream->next_buf->queue, &stream->buf_head);
+
+	stream->curr_buf = NULL;
+	stream->next_buf = NULL;
+	atomic_set(&stream->buf_cnt, 0);
 	while (!list_empty(&stream->buf_head)) {
 		struct rkcif_buffer *buf;
 
@@ -3247,6 +6332,15 @@
 
 out:
 	mutex_unlock(&dev->stream_lock);
+	return ret;
+}
+
+static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
+{
+	struct rkcif_stream *stream = queue->drv_priv;
+	int ret = 0;
+
+	ret = rkcif_do_start_stream(stream, RKCIF_STREAM_MODE_CAPTURE);
 	return ret;
 }
 
@@ -3269,10 +6363,7 @@
 	q->io_modes = VB2_MMAP | VB2_DMABUF;
 	q->drv_priv = stream;
 	q->ops = &rkcif_vb2_ops;
-	if (hw_dev->iommu_en)
-		q->mem_ops = &vb2_dma_sg_memops;
-	else
-		q->mem_ops = &vb2_dma_contig_memops;
+	q->mem_ops = hw_dev->mem_ops;
 	q->buf_struct_size = sizeof(struct rkcif_buffer);
 	if (stream->cifdev->is_use_dummybuf)
 		q->min_buffers_needed = 1;
@@ -3284,14 +6375,17 @@
 	q->allow_cache_hints = 1;
 	q->bidirectional = 1;
 	q->gfp_flags = GFP_DMA32;
+	if (hw_dev->is_dma_contig)
+		q->dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
 	return vb2_queue_init(q);
 }
 
-static void rkcif_set_fmt(struct rkcif_stream *stream,
-			  struct v4l2_pix_format_mplane *pixm,
-			  bool try)
+int rkcif_set_fmt(struct rkcif_stream *stream,
+		  struct v4l2_pix_format_mplane *pixm,
+		  bool try)
 {
 	struct rkcif_device *dev = stream->cifdev;
+	struct sditf_priv *priv = dev->sditf[0];
 	const struct cif_output_fmt *fmt;
 	const struct cif_input_fmt *cif_fmt_in = NULL;
 	struct v4l2_rect input_rect;
@@ -3299,9 +6393,13 @@
 	u32 xsubs = 1, ysubs = 1, i;
 	struct rkmodule_hdr_cfg hdr_cfg;
 	struct rkcif_extend_info *extend_line = &stream->extend_line;
-	int ret, vc;
+	struct csi_channel_info *channel_info = &dev->channels[stream->id];
+	int ret;
 
-	fmt = find_output_fmt(stream, pixm->pixelformat);
+	for (i = 0; i < RKCIF_MAX_PLANE; i++)
+		memset(&pixm->plane_fmt[i], 0, sizeof(struct v4l2_plane_pix_format));
+
+	fmt = rkcif_find_output_fmt(stream, pixm->pixelformat);
 	if (!fmt)
 		fmt = &out_fmts[0];
 
@@ -3309,10 +6407,19 @@
 	input_rect.height = RKCIF_DEFAULT_HEIGHT;
 
 	if (dev->terminal_sensor.sd) {
-		cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd,
-			      &input_rect, stream->id, &vc);
+		cif_fmt_in = rkcif_get_input_fmt(dev,
+						 &input_rect, stream->id,
+						 channel_info);
 		stream->cif_fmt_in = cif_fmt_in;
+	} else {
+		v4l2_err(&stream->cifdev->v4l2_dev,
+			 "terminal subdev does not exist\n");
+		return -EINVAL;
 	}
+
+	ret = rkcif_output_fmt_check(stream, fmt);
+	if (ret)
+		return -EINVAL;
 
 	if (dev->terminal_sensor.sd) {
 		ret = v4l2_subdev_call(dev->terminal_sensor.sd,
@@ -3320,9 +6427,9 @@
 				       RKMODULE_GET_HDR_CFG,
 				       &hdr_cfg);
 		if (!ret)
-			dev->hdr.mode = hdr_cfg.hdr_mode;
+			dev->hdr = hdr_cfg;
 		else
-			dev->hdr.mode = NO_HDR;
+			dev->hdr.hdr_mode = NO_HDR;
 
 		dev->terminal_sensor.raw_rect = input_rect;
 	}
@@ -3343,6 +6450,11 @@
 	fcc_xysubs(fmt->fourcc, &xsubs, &ysubs);
 
 	planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes;
+
+	if (cif_fmt_in &&
+	    (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 ||
+	     cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8))
+		stream->crop_enable = false;
 
 	for (i = 0; i < planes; i++) {
 		struct v4l2_plane_pix_format *plane_fmt;
@@ -3366,6 +6478,9 @@
 			}
 		}
 
+		if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF)
+			height *= dev->sditf_cnt;
+
 		extend_line->pixm.height = height + RKMODULE_EXTEND_LINE;
 
 		/* compact mode need bytesperline 4bytes align,
@@ -3373,25 +6488,29 @@
 		 * to optimize reading and writing of ddr, aliged with 256.
 		 */
 		if (fmt->fmt_type == CIF_FMT_TYPE_RAW &&
-			(stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 ||
-			stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) {
+		    cif_fmt_in &&
+		    (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 ||
+		     cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) {
 			stream->is_compact = false;
 		}
 
 		if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact &&
-		    (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 ||
+		    (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+		     dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ||
 		     dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) &&
-		     fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888) {
-			bpl = ALIGN(width * fmt->raw_bpp / 8, 256);
-		} else if (fmt->fourcc == V4L2_PIX_FMT_GREY ||
-			   fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
-			   fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
-			   fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
-			   fmt->fourcc == V4L2_PIX_FMT_SBGGR8) {
+		     fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 &&
+		     fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) {
 			bpl = ALIGN(width * fmt->raw_bpp / 8, 256);
 		} else {
-			bpp = rkcif_align_bits_per_pixel(stream, fmt, i);
-			bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH;
+			if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact &&
+			    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 &&
+			    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565 &&
+			    dev->chip_id >= CHIP_RK3588_CIF) {
+				bpl = ALIGN(width * fmt->raw_bpp / 8, 256);
+			} else {
+				bpp = rkcif_align_bits_per_pixel(stream, fmt, i);
+				bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH;
+			}
 		}
 		size = bpl * height;
 		imagesize += size;
@@ -3431,6 +6550,7 @@
 			 pixm->width, pixm->height,
 			 stream->pixm.width, stream->pixm.height);
 	}
+	return 0;
 }
 
 void rkcif_stream_init(struct rkcif_device *dev, u32 id)
@@ -3445,6 +6565,9 @@
 	stream->cifdev = dev;
 
 	INIT_LIST_HEAD(&stream->buf_head);
+	INIT_LIST_HEAD(&stream->rx_buf_head);
+	INIT_LIST_HEAD(&stream->rx_buf_head_vicap);
+	INIT_LIST_HEAD(&stream->rockit_buf_head);
 	spin_lock_init(&stream->vbq_lock);
 	spin_lock_init(&stream->fps_lock);
 	stream->state = RKCIF_STATE_READY;
@@ -3480,6 +6603,8 @@
 	}
 
 	stream->is_high_align = false;
+	stream->is_finish_stop_dma = false;
+	stream->is_wait_dma_stop = false;
 
 	if (dev->chip_id == CHIP_RV1126_CIF ||
 	    dev->chip_id == CHIP_RV1126_CIF_LITE)
@@ -3499,7 +6624,15 @@
 		dev->wait_line_cache = 0;
 		dev->wait_line_bak = 0;
 	}
-
+	stream->cur_stream_mode = 0;
+	stream->dma_en = 0;
+	stream->to_en_dma = 0;
+	stream->to_stop_dma = 0;
+	stream->to_en_scale = false;
+	stream->buf_owner = 0;
+	stream->buf_replace_cnt = 0;
+	stream->is_stop_capture = false;
+	atomic_set(&stream->buf_cnt, 0);
 }
 
 static int rkcif_fh_open(struct file *filp)
@@ -3509,6 +6642,7 @@
 	struct rkcif_stream *stream = to_rkcif_stream(vnode);
 	struct rkcif_device *cifdev = stream->cifdev;
 	int ret;
+	int i = 0;
 
 	ret = rkcif_attach_hw(cifdev);
 	if (ret)
@@ -3524,31 +6658,35 @@
 		return ret;
 	}
 
-	/*
-	 * Soft reset via CRU.
-	 * Because CRU would reset iommu too, so there's not chance
-	 * to reset cif once we hold buffers after buf queued
-	 */
-	if (cifdev->chip_id == CHIP_RK1808_CIF ||
-	    cifdev->chip_id == CHIP_RV1126_CIF ||
-	    cifdev->chip_id == CHIP_RV1126_CIF_LITE ||
-	    cifdev->chip_id == CHIP_RK3568_CIF) {
-		mutex_lock(&cifdev->stream_lock);
-		if (!atomic_read(&cifdev->fh_cnt))
-			rkcif_soft_reset(cifdev, true);
-		atomic_inc(&cifdev->fh_cnt);
-		mutex_unlock(&cifdev->stream_lock);
-	} else {
-		rkcif_soft_reset(cifdev, true);
+	ret = pm_runtime_resume_and_get(cifdev->dev);
+	if (ret < 0) {
+		v4l2_err(vdev, "Failed to get runtime pm, %d\n",
+			 ret);
+		return ret;
 	}
 
 	ret = v4l2_fh_open(filp);
 	if (!ret) {
-		ret = v4l2_pipeline_pm_use(&vnode->vdev.entity, 1);
+		mutex_lock(&cifdev->stream_lock);
+		ret = v4l2_pipeline_pm_get(&vnode->vdev.entity);
+		v4l2_info(vdev, "open video, entity use_countt %d\n",
+			  vnode->vdev.entity.use_count);
+		mutex_unlock(&cifdev->stream_lock);
 		if (ret < 0)
 			vb2_fop_release(filp);
 	}
-
+	if (cifdev->sditf_cnt > 1) {
+		for (i = 0; i < cifdev->sditf_cnt; i++) {
+			if (cifdev->sditf[i]->sensor_sd)
+				ret |= v4l2_subdev_call(cifdev->sditf[i]->sensor_sd,
+							core,
+							s_power,
+							1);
+		}
+		if (ret < 0)
+			v4l2_err(vdev, "set sensor power on fail, ret %d\n",
+				 ret);
+	}
 	return ret;
 }
 
@@ -3559,22 +6697,30 @@
 	struct rkcif_stream *stream = to_rkcif_stream(vnode);
 	struct rkcif_device *cifdev = stream->cifdev;
 	int ret = 0;
+	int i = 0;
 
 	ret = vb2_fop_release(filp);
 	if (!ret) {
-		ret = v4l2_pipeline_pm_use(&vnode->vdev.entity, 0);
-		if (ret < 0)
-			v4l2_err(&cifdev->v4l2_dev,
-				 "set pipeline power failed %d\n", ret);
+		mutex_lock(&cifdev->stream_lock);
+		v4l2_pipeline_pm_put(&vnode->vdev.entity);
+		v4l2_info(vdev, "close video, entity use_count %d\n",
+			  vnode->vdev.entity.use_count);
+		mutex_unlock(&cifdev->stream_lock);
 	}
 
-	mutex_lock(&cifdev->stream_lock);
-	if (!atomic_dec_return(&cifdev->fh_cnt))
-		rkcif_soft_reset(cifdev, true);
-	else if (atomic_read(&cifdev->fh_cnt) < 0)
-		atomic_set(&cifdev->fh_cnt, 0);
-	mutex_unlock(&cifdev->stream_lock);
-
+	pm_runtime_put_sync(cifdev->dev);
+	if (cifdev->sditf_cnt > 1) {
+		for (i = 0; i < cifdev->sditf_cnt; i++) {
+			if (cifdev->sditf[i]->sensor_sd)
+				ret |= v4l2_subdev_call(cifdev->sditf[i]->sensor_sd,
+							core,
+							s_power,
+							0);
+		}
+		if (ret < 0)
+			v4l2_err(vdev, "set sensor power on fail, ret %d\n",
+				 ret);
+	}
 	return ret;
 }
 
@@ -3584,6 +6730,9 @@
 	.unlocked_ioctl = video_ioctl2,
 	.poll = vb2_fop_poll,
 	.mmap = vb2_fop_mmap,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = video_ioctl2,
+#endif
 };
 
 static int rkcif_enum_input(struct file *file, void *priv,
@@ -3602,41 +6751,50 @@
 					struct v4l2_format *f)
 {
 	struct rkcif_stream *stream = video_drvdata(file);
+	int ret = 0;
 
-	rkcif_set_fmt(stream, &f->fmt.pix_mp, true);
+	ret = rkcif_set_fmt(stream, &f->fmt.pix_mp, true);
 
-	return 0;
+	return ret;
 }
 
 static int rkcif_enum_framesizes(struct file *file, void *prov,
 				 struct v4l2_frmsizeenum *fsize)
 {
+	struct v4l2_frmsize_discrete *d = &fsize->discrete;
 	struct v4l2_frmsize_stepwise *s = &fsize->stepwise;
 	struct rkcif_stream *stream = video_drvdata(file);
 	struct rkcif_device *dev = stream->cifdev;
 	struct v4l2_rect input_rect;
-	int vc;
+	struct csi_channel_info csi_info;
 
 	if (fsize->index != 0)
 		return -EINVAL;
 
-	if (!find_output_fmt(stream, fsize->pixel_format))
+	if (!rkcif_find_output_fmt(stream, fsize->pixel_format))
 		return -EINVAL;
 
 	input_rect.width = RKCIF_DEFAULT_WIDTH;
 	input_rect.height = RKCIF_DEFAULT_HEIGHT;
 
 	if (dev->terminal_sensor.sd)
-		get_input_fmt(dev->terminal_sensor.sd,
-			      &input_rect, stream->id, &vc);
+		rkcif_get_input_fmt(dev,
+				    &input_rect, stream->id,
+				    &csi_info);
 
-	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-	s->min_width = CIF_MIN_WIDTH;
-	s->min_height = CIF_MIN_HEIGHT;
-	s->max_width = input_rect.width;
-	s->max_height = input_rect.height;
-	s->step_width = OUTPUT_STEP_WISE;
-	s->step_height = OUTPUT_STEP_WISE;
+	if (dev->hw_dev->adapt_to_usbcamerahal) {
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		d->width = input_rect.width;
+		d->height = input_rect.height;
+	} else {
+		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+		s->min_width = CIF_MIN_WIDTH;
+		s->min_height = CIF_MIN_HEIGHT;
+		s->max_width = input_rect.width;
+		s->max_height = input_rect.height;
+		s->step_width = OUTPUT_STEP_WISE;
+		s->step_height = OUTPUT_STEP_WISE;
+	}
 
 	return 0;
 }
@@ -3668,13 +6826,19 @@
 		fi.interval.denominator = 30;
 	}
 
-	fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
-	fival->stepwise.step.numerator = 1;
-	fival->stepwise.step.denominator = 1;
-	fival->stepwise.max.numerator = 1;
-	fival->stepwise.max.denominator = 1;
-	fival->stepwise.min.numerator = fi.interval.numerator;
-	fival->stepwise.min.denominator = fi.interval.denominator;
+	if (dev->hw_dev->adapt_to_usbcamerahal) {
+		fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+		fival->discrete.numerator = fi.interval.numerator;
+		fival->discrete.denominator = fi.interval.denominator;
+	} else {
+		fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+		fival->stepwise.step.numerator = 1;
+		fival->stepwise.step.denominator = 1;
+		fival->stepwise.max.numerator = 1;
+		fival->stepwise.max.denominator = 1;
+		fival->stepwise.min.numerator = fi.interval.numerator;
+		fival->stepwise.min.denominator = fi.interval.denominator;
+	}
 
 	return 0;
 }
@@ -3683,13 +6847,57 @@
 					 struct v4l2_fmtdesc *f)
 {
 	const struct cif_output_fmt *fmt = NULL;
+	struct rkcif_stream *stream = video_drvdata(file);
+	struct rkcif_device *dev = stream->cifdev;
+	const struct cif_input_fmt *cif_fmt_in = NULL;
+	struct v4l2_rect input_rect;
+	int i = 0;
+	int ret = 0;
+	int fource_idx = 0;
 
 	if (f->index >= ARRAY_SIZE(out_fmts))
 		return -EINVAL;
 
-	fmt = &out_fmts[f->index];
-	f->pixelformat = fmt->fourcc;
+	if (dev->terminal_sensor.sd) {
+		cif_fmt_in = rkcif_get_input_fmt(dev,
+					   &input_rect, stream->id,
+					   &dev->channels[stream->id]);
+		stream->cif_fmt_in = cif_fmt_in;
+	} else {
+		v4l2_err(&stream->cifdev->v4l2_dev,
+			 "terminal subdev does not exist\n");
+		return -EINVAL;
+	}
 
+	if (f->index != 0)
+		fource_idx = stream->new_fource_idx;
+
+	for (i = fource_idx; i < ARRAY_SIZE(out_fmts); i++) {
+		fmt = &out_fmts[i];
+		ret = rkcif_output_fmt_check(stream, fmt);
+		if (!ret) {
+			f->pixelformat = fmt->fourcc;
+			stream->new_fource_idx = i + 1;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(out_fmts))
+		return -EINVAL;
+
+	switch (f->pixelformat) {
+	case V4l2_PIX_FMT_EBD8:
+		strscpy(f->description,
+			"Embedded data 8-bit",
+			sizeof(f->description));
+		break;
+	case V4l2_PIX_FMT_SPD16:
+		strscpy(f->description,
+			"Shield pix data 16-bit",
+			sizeof(f->description));
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
@@ -3698,15 +6906,16 @@
 {
 	struct rkcif_stream *stream = video_drvdata(file);
 	struct rkcif_device *dev = stream->cifdev;
+	int ret = 0;
 
 	if (vb2_is_busy(&stream->vnode.buf_queue)) {
 		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
 		return -EBUSY;
 	}
 
-	rkcif_set_fmt(stream, &f->fmt.pix_mp, false);
+	ret = rkcif_set_fmt(stream, &f->fmt.pix_mp, false);
 
-	return 0;
+	return ret;
 }
 
 static int rkcif_g_fmt_vid_cap_mplane(struct file *file, void *fh,
@@ -3733,8 +6942,8 @@
 	return 0;
 }
 
-static int rkcif_cropcap(struct file *file, void *fh,
-			 struct v4l2_cropcap *cap)
+static __maybe_unused int rkcif_cropcap(struct file *file, void *fh,
+					struct v4l2_cropcap *cap)
 {
 	struct rkcif_stream *stream = video_drvdata(file);
 	struct rkcif_device *dev = stream->cifdev;
@@ -3760,78 +6969,16 @@
 	return ret;
 }
 
-static int rkcif_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
-{
-	struct rkcif_stream *stream = video_drvdata(file);
-	struct rkcif_device *dev = stream->cifdev;
-	const struct v4l2_rect *rect = &a->c;
-	struct v4l2_rect sensor_crop;
-	struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect;
-	int ret;
-
-	ret = rkcif_sanity_check_fmt(stream, rect);
-	if (ret) {
-		v4l2_err(&dev->v4l2_dev, "set crop failed\n");
-		return ret;
-	}
-
-	if (stream->crop_mask & CROP_SRC_SENSOR) {
-		sensor_crop = stream->crop[CROP_SRC_SENSOR];
-		if (rect->left + rect->width > sensor_crop.width ||
-		    rect->top + rect->height > sensor_crop.height) {
-			v4l2_err(&dev->v4l2_dev,
-				 "crop size is bigger than sensor input:left:%d, top:%d, width:%d, height:%d\n",
-				 sensor_crop.left, sensor_crop.top, sensor_crop.width, sensor_crop.height);
-			return -EINVAL;
-		}
-	} else {
-		if (rect->left + rect->width > raw_rect->width ||
-		    rect->top + rect->height > raw_rect->height) {
-			v4l2_err(&dev->v4l2_dev,
-				 "crop size is bigger than sensor raw input:left:%d, top:%d, width:%d, height:%d\n",
-				 raw_rect->left, raw_rect->top, raw_rect->width, raw_rect->height);
-			return -EINVAL;
-		}
-	}
-
-	stream->crop[CROP_SRC_USR] = *rect;
-	stream->crop_enable = true;
-	stream->crop_mask |= CROP_SRC_USR_MASK;
-	stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_USR];
-	if (stream->crop_mask & CROP_SRC_SENSOR) {
-		stream->crop[CROP_SRC_ACT].left = sensor_crop.left + stream->crop[CROP_SRC_USR].left;
-		stream->crop[CROP_SRC_ACT].top = sensor_crop.top + stream->crop[CROP_SRC_USR].top;
-	}
-
-	if (stream->state == RKCIF_STATE_STREAMING) {
-		stream->crop_dyn_en = true;
-
-		v4l2_info(&dev->v4l2_dev, "enable dynamic crop, S_CROP(%ux%u@%u:%u) type: %d\n",
-			  rect->width, rect->height, rect->left, rect->top, a->type);
-	} else {
-		v4l2_info(&dev->v4l2_dev, "static crop, S_CROP(%ux%u@%u:%u) type: %d\n",
-			  rect->width, rect->height, rect->left, rect->top, a->type);
-	}
-
-	return ret;
-}
-
-static int rkcif_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
-{
-	struct rkcif_stream *stream = video_drvdata(file);
-
-	a->c = stream->crop[CROP_SRC_ACT];
-
-	return 0;
-}
-
 static int rkcif_s_selection(struct file *file, void *fh,
-				  struct v4l2_selection *s)
+			     struct v4l2_selection *s)
 {
 	struct rkcif_stream *stream = video_drvdata(file);
 	struct rkcif_device *dev = stream->cifdev;
 	struct v4l2_subdev *sensor_sd;
 	struct v4l2_subdev_selection sd_sel;
+	const struct v4l2_rect *rect = &s->r;
+	struct v4l2_rect sensor_crop;
+	struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect;
 	u16 pad = 0;
 	int ret = 0;
 
@@ -3840,18 +6987,69 @@
 		goto err;
 	}
 
-	sensor_sd = get_remote_sensor(stream, &pad);
+	if (s->target == V4L2_SEL_TGT_CROP_BOUNDS) {
+		sensor_sd = get_remote_sensor(stream, &pad);
 
-	sd_sel.r = s->r;
-	sd_sel.pad = pad;
-	sd_sel.target = s->target;
-	sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		sd_sel.r = s->r;
+		sd_sel.pad = pad;
+		sd_sel.target = s->target;
+		sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 
-	ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel);
-	if (!ret) {
-		s->r = sd_sel.r;
-		v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n",
-			 __func__, pad, sd_sel.which, sd_sel.target);
+		ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel);
+		if (!ret) {
+			s->r = sd_sel.r;
+			v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n",
+				 __func__, pad, sd_sel.which, sd_sel.target);
+		}
+	} else if (s->target == V4L2_SEL_TGT_CROP) {
+		ret = rkcif_sanity_check_fmt(stream, rect);
+		if (ret) {
+			v4l2_err(&dev->v4l2_dev, "set crop failed\n");
+			return ret;
+		}
+
+		if (stream->crop_mask & CROP_SRC_SENSOR) {
+			sensor_crop = stream->crop[CROP_SRC_SENSOR];
+			if (rect->left + rect->width > sensor_crop.width ||
+			    rect->top + rect->height > sensor_crop.height) {
+				v4l2_err(&dev->v4l2_dev,
+					 "crop size is bigger than sensor input:left:%d, top:%d, width:%d, height:%d\n",
+					 sensor_crop.left, sensor_crop.top,
+					 sensor_crop.width, sensor_crop.height);
+				return -EINVAL;
+			}
+		} else {
+			if (rect->left + rect->width > raw_rect->width ||
+			    rect->top + rect->height > raw_rect->height) {
+				v4l2_err(&dev->v4l2_dev,
+					 "crop size is bigger than sensor raw input:left:%d, top:%d, width:%d, height:%d\n",
+					 raw_rect->left, raw_rect->top,
+					 raw_rect->width, raw_rect->height);
+				return -EINVAL;
+			}
+		}
+
+		stream->crop[CROP_SRC_USR] = *rect;
+		stream->crop_enable = true;
+		stream->crop_mask |= CROP_SRC_USR_MASK;
+		stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_USR];
+		if (stream->crop_mask & CROP_SRC_SENSOR) {
+			sensor_crop = stream->crop[CROP_SRC_SENSOR];
+			stream->crop[CROP_SRC_ACT].left = sensor_crop.left + stream->crop[CROP_SRC_USR].left;
+			stream->crop[CROP_SRC_ACT].top = sensor_crop.top + stream->crop[CROP_SRC_USR].top;
+		}
+
+		if (stream->state == RKCIF_STATE_STREAMING) {
+			stream->crop_dyn_en = true;
+
+			v4l2_info(&dev->v4l2_dev, "enable dynamic crop, S_SELECTION(%ux%u@%u:%u) target: %d\n",
+				  rect->width, rect->height, rect->left, rect->top, s->target);
+		} else {
+			v4l2_info(&dev->v4l2_dev, "static crop, S_SELECTION(%ux%u@%u:%u) target: %d\n",
+				  rect->width, rect->height, rect->left, rect->top, s->target);
+		}
+	} else {
+		goto err;
 	}
 
 	return ret;
@@ -3861,7 +7059,7 @@
 }
 
 static int rkcif_g_selection(struct file *file, void *fh,
-				  struct v4l2_selection *s)
+			     struct v4l2_selection *s)
 {
 	struct rkcif_stream *stream = video_drvdata(file);
 	struct rkcif_device *dev = stream->cifdev;
@@ -3912,19 +7110,127 @@
 	return -EINVAL;
 }
 
+static int rkcif_get_max_common_div(int a, int b)
+{
+	int remainder = a % b;
+
+	while (remainder != 0) {
+		a = b;
+		b = remainder;
+		remainder = a % b;
+	}
+	return b;
+}
+
+void rkcif_set_fps(struct rkcif_stream *stream, struct rkcif_fps *fps)
+{
+	struct rkcif_sensor_info *sensor = &stream->cifdev->terminal_sensor;
+	struct rkcif_device *cif_dev = stream->cifdev;
+	struct rkcif_stream *tmp_stream = NULL;
+	u32 numerator, denominator;
+	u32 def_fps = 0;
+	u32 cur_fps = 0;
+	int cap_m, skip_n;
+	int i = 0;
+	int max_common_div;
+	bool skip_en = false;
+	s32 vblank_def = 0;
+	s32 vblank_curr = 0;
+	int ret = 0;
+
+	if (!stream->cifdev->terminal_sensor.sd) {
+		ret = rkcif_update_sensor_info(stream);
+		if (ret) {
+			v4l2_err(&stream->cifdev->v4l2_dev,
+				 "%s update sensor info fail\n",
+				 __func__);
+			return;
+		}
+
+	}
+	if (!stream->cifdev->terminal_sensor.sd)
+		return;
+	numerator = sensor->fi.interval.numerator;
+	denominator = sensor->fi.interval.denominator;
+	def_fps = denominator / numerator;
+
+	vblank_def = rkcif_get_sensor_vblank_def(cif_dev);
+	vblank_curr = rkcif_get_sensor_vblank(cif_dev);
+	if (vblank_def)
+		cur_fps = def_fps * (u32)(vblank_def + sensor->raw_rect.height) /
+			  (u32)(vblank_curr + sensor->raw_rect.height);
+	else
+		cur_fps = def_fps;
+
+	if (fps->fps == 0 || fps->fps > cur_fps) {
+		v4l2_err(&stream->cifdev->v4l2_dev,
+			"set fps %d fps failed, current fps %d fps\n",
+			fps->fps, cur_fps);
+		return;
+	}
+	cap_m = fps->fps;
+	skip_n = cur_fps - fps->fps;
+	max_common_div = rkcif_get_max_common_div(cap_m, skip_n);
+	cap_m /= max_common_div;
+	skip_n /= max_common_div;
+	if (cap_m > 64) {
+		skip_n = skip_n / (cap_m / 64);
+		if (skip_n == 0)
+			skip_n = 1;
+		cap_m = 64;
+	}
+	if (skip_n > 7) {
+		cap_m = cap_m / (skip_n / 7);
+		if (cap_m == 0)
+			cap_m = 1;
+		skip_n = 7;
+	}
+
+	if (fps->fps == cur_fps)
+		skip_en = false;
+	else
+		skip_en = true;
+
+	if (fps->ch_num > 1 && fps->ch_num < 4) {
+		for (i = 0; i < fps->ch_num; i++) {
+			tmp_stream = &cif_dev->stream[i];
+			if (skip_en) {
+				tmp_stream->skip_info.skip_to_en = true;
+				tmp_stream->skip_info.cap_m = cap_m;
+				tmp_stream->skip_info.skip_n = skip_n;
+			} else {
+				tmp_stream->skip_info.skip_to_dis = true;
+			}
+		}
+	} else {
+		if (skip_en) {
+			stream->skip_info.skip_to_en = true;
+			stream->skip_info.cap_m = cap_m;
+			stream->skip_info.skip_n = skip_n;
+		} else {
+			stream->skip_info.skip_to_dis = true;
+		}
+	}
+	v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
+		    "skip_to_en %d, cap_m %d, skip_n %d\n",
+			stream->skip_info.skip_to_en,
+			cap_m,
+			skip_n);
+}
+
 static int rkcif_do_reset_work(struct rkcif_device *cif_dev,
 			       enum rkmodule_reset_src reset_src);
 
 static long rkcif_ioctl_default(struct file *file, void *fh,
-				    bool valid_prio, unsigned int cmd, void *arg)
+				bool valid_prio, unsigned int cmd, void *arg)
 {
 	struct rkcif_stream *stream = video_drvdata(file);
 	struct rkcif_device *dev = stream->cifdev;
 	const struct cif_input_fmt *in_fmt;
 	struct v4l2_rect rect;
-	int vc = 0;
-	struct rkcif_reset_info *reset_info;
-	int reset_src = 0;
+	struct csi_channel_info csi_info;
+	struct rkcif_fps fps;
+	int reset_src;
 
 	switch (cmd) {
 	case RKCIF_CMD_GET_CSI_MEMORY_MODE:
@@ -3939,7 +7245,8 @@
 		break;
 	case RKCIF_CMD_SET_CSI_MEMORY_MODE:
 		if (dev->terminal_sensor.sd) {
-			in_fmt = get_input_fmt(dev->terminal_sensor.sd, &rect, 0, &vc);
+			in_fmt = rkcif_get_input_fmt(dev,
+						     &rect, 0, &csi_info);
 			if (in_fmt == NULL) {
 				v4l2_err(&dev->v4l2_dev, "can't get sensor input format\n");
 				return -EINVAL;
@@ -3965,11 +7272,9 @@
 			stream->is_high_align = false;
 		}
 		break;
-	case RKCIF_CMD_GET_RESET_INFO:
-		reset_info = (struct rkcif_reset_info *)arg;
-		*reset_info = dev->hw_dev->reset_info;
-		if (dev->hw_dev->reset_info.is_need_reset)
-			dev->hw_dev->reset_info.is_need_reset = 0;
+	case RKCIF_CMD_SET_FPS:
+		fps = *(struct rkcif_fps *)arg;
+		rkcif_set_fps(stream, &fps);
 		break;
 	case RKCIF_CMD_SET_RESET:
 		reset_src = *(int *)arg;
@@ -3993,13 +7298,10 @@
 	.vidioc_streamoff = vb2_ioctl_streamoff,
 	.vidioc_enum_input = rkcif_enum_input,
 	.vidioc_try_fmt_vid_cap_mplane = rkcif_try_fmt_vid_cap_mplane,
-	.vidioc_enum_fmt_vid_cap_mplane = rkcif_enum_fmt_vid_cap_mplane,
+	.vidioc_enum_fmt_vid_cap = rkcif_enum_fmt_vid_cap_mplane,
 	.vidioc_s_fmt_vid_cap_mplane = rkcif_s_fmt_vid_cap_mplane,
 	.vidioc_g_fmt_vid_cap_mplane = rkcif_g_fmt_vid_cap_mplane,
 	.vidioc_querycap = rkcif_querycap,
-	.vidioc_cropcap = rkcif_cropcap,
-	.vidioc_s_crop = rkcif_s_crop,
-	.vidioc_g_crop = rkcif_g_crop,
 	.vidioc_s_selection = rkcif_s_selection,
 	.vidioc_g_selection = rkcif_g_selection,
 	.vidioc_enum_frameintervals = rkcif_enum_frameintervals,
@@ -4007,8 +7309,59 @@
 	.vidioc_default = rkcif_ioctl_default,
 };
 
+void rkcif_vb_done_oneframe(struct rkcif_stream *stream,
+			    struct vb2_v4l2_buffer *vb_done)
+{
+	const struct cif_output_fmt *fmt = stream->cif_fmt_out;
+	u32 i;
+
+	/* Dequeue a filled buffer */
+	for (i = 0; i < fmt->mplanes; i++) {
+		vb2_set_plane_payload(&vb_done->vb2_buf, i,
+				      stream->pixm.plane_fmt[i].sizeimage);
+	}
+
+	vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE);
+	v4l2_dbg(2, rkcif_debug, &stream->cifdev->v4l2_dev,
+		 "stream[%d] vb done, index: %d, sequence %d\n", stream->id,
+		 vb_done->vb2_buf.index, vb_done->sequence);
+	atomic_dec(&stream->buf_cnt);
+}
+
+static void rkcif_tasklet_handle(unsigned long data)
+{
+	struct rkcif_stream *stream = (struct rkcif_stream *)data;
+	struct rkcif_buffer *buf = NULL;
+	unsigned long flags = 0;
+	LIST_HEAD(local_list);
+
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+	list_replace_init(&stream->vb_done_list, &local_list);
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+
+	while (!list_empty(&local_list)) {
+		buf = list_first_entry(&local_list,
+				       struct rkcif_buffer, queue);
+		list_del(&buf->queue);
+		rkcif_vb_done_oneframe(stream, &buf->vb);
+	}
+}
+
+void rkcif_vb_done_tasklet(struct rkcif_stream *stream, struct rkcif_buffer *buf)
+{
+	unsigned long flags = 0;
+
+	if (!stream || !buf)
+		return;
+	spin_lock_irqsave(&stream->vbq_lock, flags);
+	list_add_tail(&buf->queue, &stream->vb_done_list);
+	spin_unlock_irqrestore(&stream->vbq_lock, flags);
+	tasklet_schedule(&stream->vb_done_tasklet);
+}
+
 static void rkcif_unregister_stream_vdev(struct rkcif_stream *stream)
 {
+	tasklet_kill(&stream->vb_done_tasklet);
 	media_entity_cleanup(&stream->vnode.vdev.entity);
 	video_unregister_device(&stream->vnode.vdev);
 }
@@ -4042,6 +7395,7 @@
 				vdev_name = CIF_DVP_VDEV_NAME;
 				break;
 			default:
+				ret = -EINVAL;
 				v4l2_err(v4l2_dev, "Invalid stream\n");
 				goto unreg;
 			}
@@ -4064,6 +7418,7 @@
 				vdev_name = CIF_MIPI_ID3_VDEV_NAME;
 				break;
 			default:
+				ret = -EINVAL;
 				v4l2_err(v4l2_dev, "Invalid stream\n");
 				goto unreg;
 			}
@@ -4082,6 +7437,7 @@
 				vdev_name = CIF_DVP_ID3_VDEV_NAME;
 				break;
 			default:
+				ret = -EINVAL;
 				v4l2_err(v4l2_dev, "Invalid stream\n");
 				goto unreg;
 			}
@@ -4108,7 +7464,7 @@
 			     V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	vdev->queue = &node->buf_queue;
 
-	ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
 	if (ret < 0) {
 		v4l2_err(v4l2_dev,
 			 "video_register_device failed with error %d\n", ret);
@@ -4119,6 +7475,11 @@
 	if (ret < 0)
 		goto unreg;
 
+	INIT_LIST_HEAD(&stream->vb_done_list);
+	tasklet_init(&stream->vb_done_tasklet,
+		     rkcif_tasklet_handle,
+		     (unsigned long)stream);
+	tasklet_disable(&stream->vb_done_tasklet);
 	return 0;
 unreg:
 	video_unregister_device(vdev);
@@ -4151,7 +7512,7 @@
 		if (ret < 0)
 			goto err;
 	}
-
+	dev->num_channels = stream_num;
 	return 0;
 err:
 	for (j = 0; j < i; j++) {
@@ -4219,8 +7580,8 @@
 }
 
 static struct v4l2_rect *rkcif_lvds_sd_get_crop(struct rkcif_lvds_subdev *subdev,
-						      struct v4l2_subdev_pad_config *cfg,
-						      enum v4l2_subdev_format_whence which)
+						struct v4l2_subdev_pad_config *cfg,
+						enum v4l2_subdev_format_whence which)
 {
 	if (which == V4L2_SUBDEV_FORMAT_TRY)
 		return v4l2_subdev_get_try_crop(&subdev->sd, cfg, RKCIF_LVDS_PAD_SINK);
@@ -4229,8 +7590,8 @@
 }
 
 static int rkcif_lvds_sd_set_selection(struct v4l2_subdev *sd,
-					       struct v4l2_subdev_pad_config *cfg,
-					       struct v4l2_subdev_selection *sel)
+				       struct v4l2_subdev_pad_config *cfg,
+				       struct v4l2_subdev_selection *sel)
 {
 	struct rkcif_lvds_subdev *subdev = container_of(sd, struct rkcif_lvds_subdev, sd);
 	struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd);
@@ -4245,8 +7606,8 @@
 }
 
 static int rkcif_lvds_sd_get_selection(struct v4l2_subdev *sd,
-					       struct v4l2_subdev_pad_config *cfg,
-					       struct v4l2_subdev_selection *sel)
+				       struct v4l2_subdev_pad_config *cfg,
+				       struct v4l2_subdev_selection *sel)
 {
 	struct rkcif_lvds_subdev *subdev = container_of(sd, struct rkcif_lvds_subdev, sd);
 	struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd);
@@ -4302,13 +7663,13 @@
 	return -EINVAL;
 }
 
-static int rkcif_lvds_g_mbus_config(struct v4l2_subdev *sd,
+static int rkcif_lvds_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
 				    struct v4l2_mbus_config *mbus)
 {
 	struct v4l2_subdev *sensor_sd = get_lvds_remote_sensor(sd);
 	int ret;
 
-	ret = v4l2_subdev_call(sensor_sd, video, g_mbus_config, mbus);
+	ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, mbus);
 	if (ret)
 		return ret;
 
@@ -4331,12 +7692,13 @@
 }
 
 static int rkcif_sof_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
-				      struct v4l2_event_subscription *sub)
+				     struct v4l2_event_subscription *sub)
 {
-	if (sub->type != V4L2_EVENT_FRAME_SYNC)
+	if (sub->type == V4L2_EVENT_FRAME_SYNC ||
+	    sub->type == V4L2_EVENT_RESET_DEV)
+		return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL);
+	else
 		return -EINVAL;
-
-	return v4l2_event_subscribe(fh, sub, 0, NULL);
 }
 
 static const struct media_entity_operations rkcif_lvds_sd_media_ops = {
@@ -4349,10 +7711,10 @@
 	.get_fmt = rkcif_lvds_sd_get_fmt,
 	.set_selection = rkcif_lvds_sd_set_selection,
 	.get_selection = rkcif_lvds_sd_get_selection,
+	.get_mbus_config = rkcif_lvds_g_mbus_config,
 };
 
 static const struct v4l2_subdev_video_ops rkcif_lvds_sd_video_ops = {
-	.g_mbus_config = rkcif_lvds_g_mbus_config,
 	.s_stream = rkcif_lvds_sd_s_stream,
 };
 
@@ -4390,10 +7752,12 @@
 	return 0;
 }
 
-static void rkcif_lvds_set_sof(struct rkcif_device *dev, u32 seq)
+static u32 rkcif_lvds_set_sof(struct rkcif_device *dev, u32 seq)
 {
 	if (dev)
 		atomic_set(&dev->lvds_subdev.frm_sync_seq, seq);
+
+	return 0;
 }
 
 int rkcif_register_lvds_subdev(struct rkcif_device *dev)
@@ -4402,6 +7766,7 @@
 	struct rkcif_lvds_subdev *lvds_subdev = &dev->lvds_subdev;
 	struct v4l2_subdev *sd;
 	int ret;
+	int pad_num = 4;
 
 	memset(lvds_subdev, 0, sizeof(*lvds_subdev));
 	lvds_subdev->cifdev = dev;
@@ -4410,7 +7775,7 @@
 	v4l2_subdev_init(sd, &rkcif_lvds_sd_ops);
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 	sd->entity.ops = &rkcif_lvds_sd_media_ops;
-	if (dev->chip_id == CHIP_RV1126_CIF)
+	if (dev->chip_id != CHIP_RV1126_CIF_LITE)
 		snprintf(sd->name, sizeof(sd->name), "rkcif-lvds-subdev");
 	else
 		snprintf(sd->name, sizeof(sd->name), "rkcif-lite-lvds-subdev");
@@ -4421,6 +7786,13 @@
 	lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID1].flags = MEDIA_PAD_FL_SOURCE;
 	lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID2].flags = MEDIA_PAD_FL_SOURCE;
 	lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID3].flags = MEDIA_PAD_FL_SOURCE;
+	if (dev->chip_id == CHIP_RV1106_CIF) {
+		lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID0].flags = MEDIA_PAD_FL_SOURCE;
+		lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID1].flags = MEDIA_PAD_FL_SOURCE;
+		lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID2].flags = MEDIA_PAD_FL_SOURCE;
+		lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID3].flags = MEDIA_PAD_FL_SOURCE;
+		pad_num = RKCIF_LVDS_PAD_MAX;
+	}
 
 	lvds_subdev->in_fmt.width = RKCIF_DEFAULT_WIDTH;
 	lvds_subdev->in_fmt.height = RKCIF_DEFAULT_HEIGHT;
@@ -4429,7 +7801,7 @@
 	lvds_subdev->crop.width = RKCIF_DEFAULT_WIDTH;
 	lvds_subdev->crop.height = RKCIF_DEFAULT_HEIGHT;
 
-	ret = media_entity_pads_init(&sd->entity, RKCIF_LVDS_PAD_MAX,
+	ret = media_entity_pads_init(&sd->entity, pad_num,
 				     lvds_subdev->pads);
 	if (ret < 0)
 		return ret;
@@ -4481,10 +7853,12 @@
 	return 0;
 }
 
-static void rkcif_dvp_set_sof(struct rkcif_device *dev, u32 seq)
+static u32 rkcif_dvp_set_sof(struct rkcif_device *dev, u32 seq)
 {
 	if (dev)
 		atomic_set(&dev->dvp_sof_subdev.frm_sync_seq, seq);
+
+	return 0;
 }
 
 static const struct v4l2_subdev_core_ops rkcif_dvp_sof_sd_core_ops = {
@@ -4537,28 +7911,6 @@
 	v4l2_device_unregister_subdev(sd);
 }
 
-
-static void rkcif_vb_done_oneframe(struct rkcif_stream *stream,
-				   struct vb2_v4l2_buffer *vb_done)
-{
-	const struct cif_output_fmt *fmt = stream->cif_fmt_out;
-	u32 i;
-
-	/* Dequeue a filled buffer */
-	for (i = 0; i < fmt->mplanes; i++) {
-		vb2_set_plane_payload(&vb_done->vb2_buf, i,
-				      stream->pixm.plane_fmt[i].sizeimage);
-	}
-
-	if (stream->cifdev->hdr.mode == NO_HDR)
-		vb_done->vb2_buf.timestamp = ktime_get_ns();
-
-	vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE);
-	v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
-		 "stream[%d] vb done, index: %d, sequence %d\n", stream->id,
-		 vb_done->vb2_buf.index, vb_done->sequence);
-}
-
 void rkcif_irq_oneframe(struct rkcif_device *cif_dev)
 {
 	/* TODO: xuhf-debug: add stream type */
@@ -4590,7 +7942,7 @@
 	}
 
 	if ((intstat & FRAME_END)) {
-		struct vb2_v4l2_buffer *vb_done = NULL;
+		struct rkcif_buffer *active_buf = NULL;
 
 		rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT,
 				     FRAME_END_CLR);
@@ -4623,11 +7975,11 @@
 		if (frmid % 2 != 0) {
 			stream->frame_phase = CIF_CSI_FRAME0_READY;
 			if (stream->curr_buf)
-				vb_done = &stream->curr_buf->vb;
+				active_buf = stream->curr_buf;
 		} else {
 			stream->frame_phase = CIF_CSI_FRAME1_READY;
 			if (stream->next_buf)
-				vb_done = &stream->next_buf->vb;
+				active_buf = stream->next_buf;
 		}
 
 		/* In one-frame mode:
@@ -4640,46 +7992,28 @@
 		ret = rkcif_assign_new_buffer_oneframe(stream,
 						 RKCIF_YUV_ADDR_STATE_UPDATE);
 
-		if (vb_done && (!ret)) {
-			vb_done->sequence = stream->frame_idx;
-			rkcif_vb_done_oneframe(stream, vb_done);
+		if (active_buf && (!ret)) {
+			active_buf->vb.sequence = stream->frame_idx - 1;
+			rkcif_vb_done_tasklet(stream, active_buf);
 		}
 
-		stream->frame_idx++;
-		cif_dev->irq_stats.all_frm_end_cnt++;
+		cif_dev->irq_stats.frm_end_cnt[stream->id]++;
 	}
 }
 
 static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev,
-				    unsigned int intstat)
+			       unsigned int intstat)
 {
-	if (intstat & CSI_FRAME_END_ID0) {
-		if ((intstat & CSI_FRAME_END_ID0) ==
-		    CSI_FRAME_END_ID0)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID0\n");
+	if (intstat & CSI_FRAME_END_ID0)
 		return RKCIF_STREAM_MIPI_ID0;
-	}
 
-	if (intstat & CSI_FRAME_END_ID1) {
-		if ((intstat & CSI_FRAME_END_ID1) ==
-		    CSI_FRAME_END_ID1)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID1\n");
+	if (intstat & CSI_FRAME_END_ID1)
 		return RKCIF_STREAM_MIPI_ID1;
-	}
 
-	if (intstat & CSI_FRAME_END_ID2) {
-		if ((intstat & CSI_FRAME_END_ID2) ==
-		    CSI_FRAME_END_ID2)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID2\n");
+	if (intstat & CSI_FRAME_END_ID2)
 		return RKCIF_STREAM_MIPI_ID2;
-	}
-
-	if (intstat & CSI_FRAME_END_ID3) {
-		if ((intstat & CSI_FRAME_END_ID3) ==
-		    CSI_FRAME_END_ID3)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID3\n");
+	if (intstat & CSI_FRAME_END_ID3)
 		return RKCIF_STREAM_MIPI_ID3;
-	}
 
 	return -EINVAL;
 }
@@ -4688,38 +8022,42 @@
 			     u32 *intstat, u32 frm_stat)
 {
 	if (*intstat & DVP_FRAME_END_ID0) {
-		if ((frm_stat & DVP_CHANNEL0_FRM_READ) ==
-		    DVP_CHANNEL0_FRM_READ)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID0\n");
-
 		*intstat &= ~DVP_FRAME_END_ID0;
 		return RKCIF_STREAM_MIPI_ID0;
 	}
 
 	if (*intstat & DVP_FRAME_END_ID1) {
-		if ((frm_stat & DVP_CHANNEL1_FRM_READ) ==
-		    DVP_CHANNEL1_FRM_READ)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID1\n");
-
 		*intstat &= ~DVP_FRAME_END_ID1;
 		return RKCIF_STREAM_MIPI_ID1;
 	}
 
 	if (*intstat & DVP_FRAME_END_ID2) {
-		if ((frm_stat & DVP_CHANNEL2_FRM_READ) ==
-		    DVP_CHANNEL2_FRM_READ)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID2\n");
 		*intstat &= ~DVP_FRAME_END_ID2;
 		return RKCIF_STREAM_MIPI_ID2;
 	}
 
 	if (*intstat & DVP_FRAME_END_ID3) {
-		if ((frm_stat & DVP_CHANNEL3_FRM_READ) ==
-		    DVP_CHANNEL3_FRM_READ)
-			v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID3\n");
 		*intstat &= ~DVP_FRAME_END_ID3;
 		return RKCIF_STREAM_MIPI_ID3;
 	}
+
+	return -EINVAL;
+}
+
+static int rkcif_dvp_g_ch_id_by_fe(struct v4l2_device *v4l2_dev,
+				   u32 intstat)
+{
+	if (intstat & DVP_ALL_END_ID0)
+		return RKCIF_STREAM_MIPI_ID0;
+
+	if (intstat & DVP_ALL_END_ID1)
+		return RKCIF_STREAM_MIPI_ID1;
+
+	if (intstat & DVP_ALL_END_ID2)
+		return RKCIF_STREAM_MIPI_ID2;
+
+	if (intstat & DVP_ALL_END_ID3)
+		return RKCIF_STREAM_MIPI_ID3;
 
 	return -EINVAL;
 }
@@ -4730,7 +8068,6 @@
 						struct rkcif_device,
 						reset_watchdog_timer);
 	struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0];
-	struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer;
 	bool is_triggered = false, is_assign_triggered = false, is_first_err = false;
 	unsigned long flags;
 	u64 cur_time, diff_time;
@@ -4741,7 +8078,7 @@
 	    timer->csi2_err_cnt_odd != 0) {
 		timer->csi2_err_cnt_odd = 0;
 		timer->csi2_err_cnt_even = 0;
-		hw_timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2;
+		timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2;
 		timer->csi2_err_triggered_cnt++;
 		if (timer->csi2_err_triggered_cnt == 1) {
 			is_first_err = true;
@@ -4760,7 +8097,7 @@
 			cur_time = ktime_get_ns();
 			diff_time = cur_time - timer->csi2_first_err_timestamp;
 			diff_time = div_u64(diff_time, 1000000);
-			if (diff_time >= hw_timer->err_time_interval) {
+			if (diff_time >= timer->err_time_interval) {
 				is_triggered = true;
 				v4l2_info(&dev->v4l2_dev, "trigger reset for time out of csi err\n");
 				goto end_judge;
@@ -4780,19 +8117,10 @@
 	 * when fs cnt is beyond 2, it indicates that frame end is not coming,
 	 * or fs and fe had been not paired.
 	 */
-	if (hw_timer->monitor_mode != RKCIF_MONITOR_MODE_HOTPLUG &&
-	    (stream->is_fs_fe_not_paired ||
-	     stream->fs_cnt_in_single_frame > RKCIF_FS_DETECTED_NUM)) {
+	if (stream->is_fs_fe_not_paired ||
+	    stream->fs_cnt_in_single_frame > RKCIF_FS_DETECTED_NUM) {
 		is_triggered = true;
 		v4l2_info(&dev->v4l2_dev, "reset for fs & fe not paired\n");
-	}
-	if (dev->irq_stats.csi_bwidth_lack_cnt) {
-		is_triggered = true;
-		dev->irq_stats.csi_bwidth_lack_cnt = 0;
-	}
-	if (dev->irq_stats.csi_overflow_cnt) {
-		is_triggered = true;
-		dev->irq_stats.csi_overflow_cnt = 0;
 	}
 end_judge:
 	spin_unlock_irqrestore(&timer->csi2_err_lock, flags);
@@ -4800,7 +8128,30 @@
 	return is_triggered;
 }
 
-static s32 rkcif_get_sensor_vblank(struct rkcif_device *dev)
+static bool rkcif_is_triggered_monitoring(struct rkcif_device *dev)
+{
+	struct rkcif_timer *timer = &dev->reset_watchdog_timer;
+	struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0];
+	bool ret = false;
+
+	if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE)
+		ret = false;
+
+	if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE ||
+	    timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) {
+		if (stream->frame_idx >= timer->triggered_frame_num)
+			ret = true;
+	}
+
+	if (timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) {
+		timer->is_csi2_err_occurred = rkcif_is_csi2_err_trigger_reset(timer);
+		ret = timer->is_csi2_err_occurred;
+	}
+
+	return ret;
+}
+
+s32 rkcif_get_sensor_vblank(struct rkcif_device *dev)
 {
 	struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor;
 	struct v4l2_subdev *sd = terminal_sensor->sd;
@@ -4817,7 +8168,7 @@
 	return 0;
 }
 
-static s32 rkcif_get_sensor_vblank_def(struct rkcif_device *dev)
+s32 rkcif_get_sensor_vblank_def(struct rkcif_device *dev)
 {
 	struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor;
 	struct v4l2_subdev *sd = terminal_sensor->sd;
@@ -4843,7 +8194,7 @@
 	const struct cif_output_fmt *fmt;
 	u32 fourcc;
 
-	fmt = find_output_fmt(stream, stream->pixm.pixelformat);
+	fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat);
 	if (!fmt) {
 		v4l2_err(&dev->v4l2_dev, "can not find output format: 0x%x",
 			 stream->pixm.pixelformat);
@@ -4859,13 +8210,14 @@
 	 * writing of ddr, aliged with 256
 	 */
 	if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact &&
-	    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888) {
+	    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 &&
+	    fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) {
 		*crop_vwidth = ALIGN(raw_width * fmt->raw_bpp / 8, 256);
 	} else {
 		*crop_vwidth = ALIGN(raw_width * fmt->bpp[0] / 8, 8);
 	}
 
-	if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888)
+	if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565)
 		*crop_width = raw_width * fmt->bpp[0] / 8;
 	/*
 	 * rk cif don't support output yuyv fmt data
@@ -4893,12 +8245,15 @@
 		return;
 
 	mbus = &cif_dev->active_sensor->mbus;
-	if (mbus->type == V4L2_MBUS_CSI2 ||
+	if (mbus->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus->type == V4L2_MBUS_CSI2_CPHY ||
 	    mbus->type == V4L2_MBUS_CCP2) {
 		struct csi_channel_info *channel = &cif_dev->channels[stream->id];
 
 		if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888)
 			crop_x = 3 * stream->crop[CROP_SRC_ACT].left;
+		else if (channel->fmt_val == CSI_WRDDR_TYPE_RGB565)
+			crop_x = 2 * stream->crop[CROP_SRC_ACT].left;
 		else
 			crop_x = stream->crop[CROP_SRC_ACT].left;
 
@@ -4940,15 +8295,8 @@
 				     crop_y << CIF_CROP_Y_SHIFT | crop_x);
 
 		if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) {
-			fmt = find_output_fmt(stream, stream->pixm.pixelformat);
-			if (fmt->fourcc == V4L2_PIX_FMT_GREY ||
-			    fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
-			    fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
-			    fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
-			    fmt->fourcc == V4L2_PIX_FMT_SBGGR8)
-				crop_vwidth = ALIGN(raw_width * fmt->raw_bpp / 8, 256);
-			else
-				crop_vwidth = raw_width * rkcif_cal_raw_vir_line_ratio(stream, fmt);
+			fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat);
+			crop_vwidth = raw_width * rkcif_cal_raw_vir_line_ratio(stream, fmt);
 		}
 		rkcif_write_register(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, crop_vwidth);
 
@@ -4959,41 +8307,94 @@
 	stream->crop_dyn_en = false;
 }
 
-void rkcif_monitor_reset_event(struct rkcif_hw *hw)
+static void rkcif_monitor_reset_event(struct rkcif_device *dev)
 {
-	struct rkcif_hw_timer *hw_timer = &hw->hw_timer;
-	struct rkcif_timer *timer = NULL;
-	struct rkcif_device *cif_dev = NULL;
 	struct rkcif_stream *stream = NULL;
-	unsigned long flags;
-	int i = 0, j = 0;
+	struct rkcif_timer *timer = &dev->reset_watchdog_timer;
+	unsigned int cycle = 0;
+	u64 fps, timestamp0, timestamp1;
+	unsigned long flags, fps_flags;
+	int i = 0;
 
-	if (hw_timer->is_running)
+	if (timer->is_running)
 		return;
 
-	if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE)
+	if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE)
 		return;
 
-	spin_lock_irqsave(&hw_timer->timer_lock, flags);
-	hw_timer->is_running = true;
-	for (j = 0; i < hw->dev_num; j++) {
-		cif_dev = hw->cif_dev[i];
-		timer = &cif_dev->reset_watchdog_timer;
-		for (i = 0; i < cif_dev->num_channels; i++) {
-			stream = &cif_dev->stream[i];
-			if (stream->state == RKCIF_STATE_STREAMING)
-				timer->last_buf_wakeup_cnt[i] = stream->frame_idx;
-		}
+	for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
+		stream = &dev->stream[i];
+		if (stream->state == RKCIF_STATE_STREAMING)
+			break;
 	}
-	hw_timer->cycle_jif = msecs_to_jiffies(hw_timer->monitor_cycle);
-	hw_timer->timer.expires = jiffies + hw_timer->cycle_jif;
-	mod_timer(&hw_timer->timer, hw_timer->timer.expires);
 
-	spin_unlock_irqrestore(&hw_timer->timer_lock, flags);
+	if (i >= RKCIF_MAX_STREAM_MIPI)
+		return;
 
-	v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
-		 "start monitor timer, monitor cycle %d\n",
-		 hw_timer->monitor_cycle);
+	timer->is_triggered = rkcif_is_triggered_monitoring(dev);
+
+	if (timer->is_triggered) {
+		struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect;
+		enum rkcif_monitor_mode mode;
+		s32 vblank = 0;
+		u32 vts = 0;
+		u64 numerator = 0;
+		u64 denominator = 0;
+
+		if (stream->frame_idx  > 2) {
+			spin_lock_irqsave(&stream->fps_lock, fps_flags);
+			timestamp0 = stream->fps_stats.frm0_timestamp;
+			timestamp1 = stream->fps_stats.frm1_timestamp;
+			spin_unlock_irqrestore(&stream->fps_lock, fps_flags);
+
+			fps = timestamp0 > timestamp1 ?
+			      timestamp0 - timestamp1 : timestamp1 - timestamp0;
+			fps = div_u64(fps, 1000);
+		} else {
+			numerator = dev->terminal_sensor.fi.interval.numerator;
+			denominator = dev->terminal_sensor.fi.interval.denominator;
+			fps = div_u64(1000000 * numerator, denominator);
+		}
+		spin_lock_irqsave(&timer->timer_lock, flags);
+
+		timer->frame_end_cycle_us = fps;
+
+		vblank = rkcif_get_sensor_vblank(dev);
+		timer->raw_height = raw_rect->height;
+		vts = timer->raw_height + vblank;
+		timer->vts = vts;
+
+		timer->line_end_cycle = div_u64(timer->frame_end_cycle_us, timer->vts);
+		fps = div_u64(timer->frame_end_cycle_us, 1000);
+		cycle = fps * timer->frm_num_of_monitor_cycle;
+		timer->cycle = msecs_to_jiffies(cycle);
+
+		timer->run_cnt = 0;
+		timer->is_running = true;
+		timer->is_buf_stop_update = false;
+		for (i = 0; i < dev->num_channels; i++) {
+			stream = &dev->stream[i];
+			if (stream->state == RKCIF_STATE_STREAMING)
+				timer->last_buf_wakeup_cnt[i] = stream->buf_wake_up_cnt;
+		}
+		/* in trigger mode, monitoring count is fps */
+		mode = timer->monitor_mode;
+		if (mode == RKCIF_MONITOR_MODE_CONTINUE ||
+		    mode == RKCIF_MONITOR_MODE_HOTPLUG)
+			timer->max_run_cnt = 0xffffffff - CIF_TIMEOUT_FRAME_NUM;
+		else
+			timer->max_run_cnt = div_u64(1000, fps) * 1;
+
+		timer->timer.expires = jiffies + timer->cycle;
+		mod_timer(&timer->timer, timer->timer.expires);
+
+		spin_unlock_irqrestore(&timer->timer_lock, flags);
+
+		v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+			 "%s:mode:%d, raw height:%d,vblank:%d, cycle:%ld, fps:%llu\n",
+			  __func__, timer->monitor_mode, raw_rect->height,
+			  vblank, timer->cycle, div_u64(1000, fps));
+	}
 }
 
 static void rkcif_rdbk_frame_end(struct rkcif_stream *stream)
@@ -5003,13 +8404,15 @@
 	u32 denominator, numerator;
 	u64 l_ts, m_ts, s_ts, time = 30000000LL;
 	int ret, fps = -1;
+	int i = 0;
+	unsigned long flags;
 
-	if (dev->hdr.mode == HDR_X2) {
+	if (dev->hdr.hdr_mode == HDR_X2) {
 		if (stream->id != RKCIF_STREAM_MIPI_ID1 ||
 		    dev->stream[RKCIF_STREAM_MIPI_ID0].state != RKCIF_STATE_STREAMING ||
 		    dev->stream[RKCIF_STREAM_MIPI_ID1].state != RKCIF_STATE_STREAMING)
 			return;
-	} else if (dev->hdr.mode == HDR_X3) {
+	} else if (dev->hdr.hdr_mode == HDR_X3) {
 		if (stream->id != RKCIF_STREAM_MIPI_ID2 ||
 		    dev->stream[RKCIF_STREAM_MIPI_ID0].state != RKCIF_STATE_STREAMING ||
 		    dev->stream[RKCIF_STREAM_MIPI_ID1].state != RKCIF_STATE_STREAMING ||
@@ -5022,13 +8425,13 @@
 	if (denominator && numerator)
 		time = numerator * 1000 / denominator * 1000 * 1000;
 
-	if (dev->hdr.mode == HDR_X3) {
+	if (dev->hdr.hdr_mode == HDR_X3) {
 		if (dev->rdbk_buf[RDBK_L] &&
 		    dev->rdbk_buf[RDBK_M] &&
 		    dev->rdbk_buf[RDBK_S]) {
-			l_ts = dev->rdbk_buf[RDBK_L]->vb.vb2_buf.timestamp;
-			m_ts = dev->rdbk_buf[RDBK_M]->vb.vb2_buf.timestamp;
-			s_ts = dev->rdbk_buf[RDBK_S]->vb.vb2_buf.timestamp;
+			l_ts = dev->rdbk_buf[RDBK_L]->fe_timestamp;
+			m_ts = dev->rdbk_buf[RDBK_M]->fe_timestamp;
+			s_ts = dev->rdbk_buf[RDBK_S]->fe_timestamp;
 
 			if (m_ts < l_ts || s_ts < m_ts) {
 				v4l2_err(&dev->v4l2_dev,
@@ -5058,14 +8461,25 @@
 					goto RDBK_FRM_UNMATCH;
 				}
 			}
-			dev->rdbk_buf[RDBK_L]->vb.sequence = dev->rdbk_buf[RDBK_S]->vb.sequence;
-			dev->rdbk_buf[RDBK_M]->vb.sequence = dev->rdbk_buf[RDBK_S]->vb.sequence;
-			rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID0],
-					       &dev->rdbk_buf[RDBK_L]->vb);
-			rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID1],
-					       &dev->rdbk_buf[RDBK_M]->vb);
-			rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID2],
-					       &dev->rdbk_buf[RDBK_S]->vb);
+			dev->rdbk_buf[RDBK_M]->vb.sequence = dev->rdbk_buf[RDBK_L]->vb.sequence;
+			dev->rdbk_buf[RDBK_S]->vb.sequence = dev->rdbk_buf[RDBK_L]->vb.sequence;
+			if (dev->is_support_tools &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID0].tools_vdev->state == RKCIF_STATE_STREAMING &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID1].tools_vdev->state == RKCIF_STATE_STREAMING &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID2].tools_vdev->state == RKCIF_STATE_STREAMING) {
+				for (i = 0; i < 3; i++) {
+					spin_lock_irqsave(&dev->stream[i].tools_vdev->vbq_lock, flags);
+					list_add_tail(&dev->rdbk_buf[i]->queue,
+						      &dev->stream[i].tools_vdev->buf_done_head);
+					if (!work_busy(&dev->stream[i].tools_vdev->work))
+						schedule_work(&dev->stream[i].tools_vdev->work);
+					spin_unlock_irqrestore(&dev->stream[i].tools_vdev->vbq_lock, flags);
+				}
+			} else {
+				rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID0], dev->rdbk_buf[RDBK_L]);
+				rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID1], dev->rdbk_buf[RDBK_M]);
+				rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID2], dev->rdbk_buf[RDBK_S]);
+			}
 		} else {
 			if (!dev->rdbk_buf[RDBK_L])
 				v4l2_err(&dev->v4l2_dev, "lost long frames\n");
@@ -5075,10 +8489,10 @@
 				v4l2_err(&dev->v4l2_dev, "lost short frames\n");
 			goto RDBK_FRM_UNMATCH;
 		}
-	} else if (dev->hdr.mode == HDR_X2) {
+	} else if (dev->hdr.hdr_mode == HDR_X2) {
 		if (dev->rdbk_buf[RDBK_L] && dev->rdbk_buf[RDBK_M]) {
-			l_ts = dev->rdbk_buf[RDBK_L]->vb.vb2_buf.timestamp;
-			s_ts = dev->rdbk_buf[RDBK_M]->vb.vb2_buf.timestamp;
+			l_ts = dev->rdbk_buf[RDBK_L]->fe_timestamp;
+			s_ts = dev->rdbk_buf[RDBK_M]->fe_timestamp;
 
 			if (s_ts < l_ts) {
 				v4l2_err(&dev->v4l2_dev,
@@ -5107,11 +8521,22 @@
 					goto RDBK_FRM_UNMATCH;
 				}
 			}
-			dev->rdbk_buf[RDBK_L]->vb.sequence = dev->rdbk_buf[RDBK_M]->vb.sequence;
-			rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID0],
-					       &dev->rdbk_buf[RDBK_L]->vb);
-			rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID1],
-					       &dev->rdbk_buf[RDBK_M]->vb);
+			dev->rdbk_buf[RDBK_M]->vb.sequence = dev->rdbk_buf[RDBK_L]->vb.sequence;
+			if (dev->is_support_tools &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID0].tools_vdev->state == RKCIF_STATE_STREAMING &&
+			    dev->stream[RKCIF_STREAM_MIPI_ID1].tools_vdev->state == RKCIF_STATE_STREAMING) {
+				for (i = 0; i < 2; i++) {
+					spin_lock_irqsave(&dev->stream[i].tools_vdev->vbq_lock, flags);
+					list_add_tail(&dev->rdbk_buf[i]->queue,
+						      &dev->stream[i].tools_vdev->buf_done_head);
+					if (!work_busy(&dev->stream[i].tools_vdev->work))
+						schedule_work(&dev->stream[i].tools_vdev->work);
+					spin_unlock_irqrestore(&dev->stream[i].tools_vdev->vbq_lock, flags);
+				}
+			} else {
+				rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID0], dev->rdbk_buf[RDBK_L]);
+				rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID1], dev->rdbk_buf[RDBK_M]);
+			}
 		} else {
 			if (!dev->rdbk_buf[RDBK_L])
 				v4l2_err(&dev->v4l2_dev, "lost long frames\n");
@@ -5119,8 +8544,6 @@
 				v4l2_err(&dev->v4l2_dev, "lost short frames\n");
 			goto RDBK_FRM_UNMATCH;
 		}
-	} else {
-		rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_S]->vb);
 	}
 
 	dev->rdbk_buf[RDBK_L] = NULL;
@@ -5147,10 +8570,26 @@
 	dev->rdbk_buf[RDBK_S] = NULL;
 }
 
+static void rkcif_buf_done_with_tools(struct rkcif_stream *stream,
+				      struct rkcif_buffer *active_buf)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags);
+	if (stream->tools_vdev->state == RKCIF_STATE_STREAMING) {
+		list_add_tail(&active_buf->queue, &stream->tools_vdev->buf_done_head);
+		if (!work_busy(&stream->tools_vdev->work))
+			schedule_work(&stream->tools_vdev->work);
+	} else {
+		rkcif_vb_done_tasklet(stream, active_buf);
+	}
+	spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags);
+}
+
 static void rkcif_buf_done_prepare(struct rkcif_stream *stream,
-					 struct rkcif_buffer *active_buf,
-					 int mipi_id,
-					 u32 mode)
+				   struct rkcif_buffer *active_buf,
+				   int mipi_id,
+				   u32 mode)
 {
 	unsigned long flags;
 	struct vb2_v4l2_buffer *vb_done = NULL;
@@ -5158,8 +8597,13 @@
 
 	if (active_buf) {
 		vb_done = &active_buf->vb;
-		vb_done->vb2_buf.timestamp = ktime_get_ns();
-		vb_done->sequence = stream->frame_idx;
+		if (cif_dev->chip_id < CHIP_RK3588_CIF &&
+		    cif_dev->active_sensor->mbus.type == V4L2_MBUS_BT656)
+			vb_done->vb2_buf.timestamp = stream->readout.fe_timestamp;
+		else
+			vb_done->vb2_buf.timestamp = stream->readout.fs_timestamp;
+		vb_done->sequence = stream->frame_idx - 1;
+		active_buf->fe_timestamp = ktime_get_ns();
 		if (stream->is_line_wake_up) {
 			spin_lock_irqsave(&stream->fps_lock, flags);
 			if (mode)
@@ -5173,13 +8617,22 @@
 			vb_done->sequence /= 2;
 	}
 
-	if (cif_dev->hdr.mode == NO_HDR) {
+	if (cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) {
 		if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
-			if (stream->frame_phase == CIF_CSI_FRAME1_READY && active_buf)
-				rkcif_vb_done_oneframe(stream, vb_done);
+			if (stream->frame_phase == CIF_CSI_FRAME1_READY && active_buf) {
+
+				if (cif_dev->is_support_tools && stream->tools_vdev)
+					rkcif_buf_done_with_tools(stream, active_buf);
+				else
+					rkcif_vb_done_tasklet(stream, active_buf);
+			}
 		} else {
-			if (active_buf)
-				rkcif_vb_done_oneframe(stream, vb_done);
+			if (active_buf) {
+				if (cif_dev->is_support_tools && stream->tools_vdev)
+					rkcif_buf_done_with_tools(stream, active_buf);
+				else
+					rkcif_vb_done_tasklet(stream, active_buf);
+			}
 		}
 	} else {
 		if (cif_dev->is_start_hdr) {
@@ -5188,11 +8641,12 @@
 				if (cif_dev->rdbk_buf[RDBK_L]) {
 					v4l2_err(&cif_dev->v4l2_dev,
 						 "multiple long data in %s frame,frm_idx:%d,state:0x%x\n",
-						 cif_dev->hdr.mode == HDR_X2 ? "hdr_x2" : "hdr_x3",
+						 cif_dev->hdr.hdr_mode == HDR_X2 ? "hdr_x2" : "hdr_x3",
 						 stream->frame_idx,
 						 cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state);
 					cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
 					rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf);
+					cif_dev->rdbk_buf[RDBK_L] = NULL;
 				}
 				if (active_buf)
 					cif_dev->rdbk_buf[RDBK_L] = active_buf;
@@ -5200,29 +8654,31 @@
 				if (cif_dev->rdbk_buf[RDBK_M]) {
 					v4l2_err(&cif_dev->v4l2_dev,
 						 "multiple %s frame,frm_idx:%d,state:0x%x\n",
-						 cif_dev->hdr.mode == HDR_X2 ? "short data in hdr_x2" : "medium data in hdr_x3",
+						 cif_dev->hdr.hdr_mode == HDR_X2 ? "short data in hdr_x2" : "medium data in hdr_x3",
 						 stream->frame_idx,
 						 cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf.state);
 					cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
 					rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf);
+					cif_dev->rdbk_buf[RDBK_M] = NULL;
 				}
 				if (active_buf)
 					cif_dev->rdbk_buf[RDBK_M] = active_buf;
-				if (cif_dev->hdr.mode == HDR_X2)
+				if (cif_dev->hdr.hdr_mode == HDR_X2)
 					rkcif_rdbk_frame_end(stream);
 			} else if (mipi_id == RKCIF_STREAM_MIPI_ID2) {
 				if (cif_dev->rdbk_buf[RDBK_S]) {
 					v4l2_err(&cif_dev->v4l2_dev,
 						 "multiple %s frame, frm_idx:%d,state:0x%x\n",
-						 cif_dev->hdr.mode == HDR_X2 ? "err short data in hdr_x3" : "short data in hdr_x3",
+						 cif_dev->hdr.hdr_mode == HDR_X2 ? "err short data in hdr_x3" : "short data in hdr_x3",
 						 stream->frame_idx,
 						 cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state);
 					cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
 					rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf);
+					cif_dev->rdbk_buf[RDBK_S] = NULL;
 				}
 				if (active_buf)
 					cif_dev->rdbk_buf[RDBK_S] = active_buf;
-				if (cif_dev->hdr.mode == HDR_X3)
+				if (cif_dev->hdr.hdr_mode == HDR_X3)
 					rkcif_rdbk_frame_end(stream);
 			}
 			spin_unlock_irqrestore(&cif_dev->hdr_lock, flags);
@@ -5265,12 +8721,129 @@
 	}
 	ret = rkcif_get_new_buffer_wake_up_mode(stream);
 	if (ret)
-		goto end_wake_up;
-
+		return;
 	rkcif_buf_done_prepare(stream, active_buf, mipi_id, mode);
-end_wake_up:
-	stream->frame_idx++;
+}
 
+static void rkcif_store_last_buf_for_online(struct rkcif_stream *stream,
+					    struct rkcif_rx_buffer *buf)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
+	u32 frm0_addr_y, frm1_addr_y;
+
+	INIT_LIST_HEAD(&stream->rx_buf_head);
+	stream->curr_buf_toisp = buf;
+	stream->next_buf_toisp = buf;
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CCP2) {
+		frm0_addr_y = get_reg_index_of_frm0_y_addr(stream->id);
+		frm1_addr_y = get_reg_index_of_frm1_y_addr(stream->id);
+	} else {
+		frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(stream->id);
+		frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(stream->id);
+	}
+	rkcif_write_register(dev, frm0_addr_y,
+			     buf->dummy.dma_addr);
+	rkcif_write_register(dev, frm1_addr_y,
+			     buf->dummy.dma_addr);
+}
+
+static void rkcif_release_unnecessary_buf_for_online(struct rkcif_stream *stream,
+						     struct rkcif_rx_buffer *buf)
+{
+	struct rkcif_device *dev = stream->cifdev;
+	struct sditf_priv *priv = dev->sditf[0];
+	struct rkcif_rx_buffer *rx_buf = NULL;
+	unsigned long flags;
+	int i = 0;
+
+	spin_lock_irqsave(&priv->cif_dev->buffree_lock, flags);
+	for (i = 0; i < priv->buf_num; i++) {
+		rx_buf = &stream->rx_buf[i];
+		if (rx_buf && (!rx_buf->dummy.is_free) && rx_buf != buf) {
+			list_add_tail(&rx_buf->list_free, &priv->buf_free_list);
+			stream->total_buf_num--;
+		}
+	}
+	spin_unlock_irqrestore(&priv->cif_dev->buffree_lock, flags);
+	schedule_work(&priv->buffree_work.work);
+}
+
+static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id)
+{
+	u32 mode;
+	struct rkcif_rx_buffer *active_buf = NULL;
+	struct sditf_priv *priv = NULL;
+	unsigned long flags;
+	int ret = 0;
+
+	mode = stream->line_int_cnt % 2;
+	if (mode) {
+		if (stream->curr_buf_toisp)
+			active_buf = stream->curr_buf_toisp;
+		stream->frame_phase = CIF_CSI_FRAME0_READY;
+	} else {
+		if (stream->next_buf_toisp)
+			active_buf = stream->next_buf_toisp;
+		stream->frame_phase = CIF_CSI_FRAME1_READY;
+	}
+
+	if (!active_buf) {
+		v4l2_err(&stream->cifdev->v4l2_dev,
+			 "err buffer state in %s\n",
+			 __func__);
+		return;
+	}
+
+	if (stream->stopping) {
+		stream->is_can_stop = true;
+		return;
+	}
+	ret = rkcif_get_new_buffer_wake_up_mode_rdbk(stream);
+	v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
+		 "%d frame_idx %d, last_rx_buf_idx %d cur dma buf %x\n",
+		 __LINE__, stream->frame_idx, stream->last_rx_buf_idx,
+		 (u32)active_buf->dummy.dma_addr);
+	if (!ret) {
+		priv = stream->cifdev->sditf[0];
+		if (stream->cur_stream_mode & RKCIF_STREAM_MODE_TOISP_RDBK) {
+			spin_lock_irqsave(&stream->vbq_lock, flags);
+			if (stream->cifdev->is_thunderboot &&
+			    (stream->frame_idx - 1) == stream->last_rx_buf_idx &&
+			     stream->cifdev->is_rdbk_to_online) {
+				stream->cur_stream_mode &= ~RKCIF_STREAM_MODE_TOISP_RDBK;
+				stream->cur_stream_mode |= RKCIF_STREAM_MODE_TOISP;
+				stream->cifdev->wait_line = 0;
+				stream->is_line_wake_up = false;
+				if (stream->cifdev->hdr.hdr_mode == NO_HDR ||
+				    (priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id == 1) ||
+				    (priv->hdr_cfg.hdr_mode == HDR_X3 && stream->id == 2)) {
+					stream->to_stop_dma = RKCIF_DMAEN_BY_ISP;
+					rkcif_stop_dma_capture(stream);
+				}
+				active_buf->dbufs.is_switch = true;
+				if ((priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id != 1) ||
+				    (priv->hdr_cfg.hdr_mode == HDR_X3 && stream->id != 2)) {
+					rkcif_store_last_buf_for_online(stream, active_buf);
+					stream->is_change_toisp = true;
+				}
+			}
+			spin_unlock_irqrestore(&stream->vbq_lock, flags);
+			active_buf->dbufs.sequence = stream->frame_idx - 1;
+			active_buf->dbufs.timestamp = stream->readout.fs_timestamp;
+			active_buf->fe_timestamp = ktime_get_ns();
+			stream->last_frame_idx = stream->frame_idx;
+			if (stream->cifdev->hdr.hdr_mode == NO_HDR) {
+				rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs);
+				if (stream->cifdev->is_support_tools && stream->tools_vdev)
+					rkcif_rdbk_with_tools(stream, active_buf);
+			} else {
+				rkcif_rdbk_frame_end_toisp(stream, active_buf);
+			}
+		}
+	}
 }
 
 static void rkcif_deal_readout_time(struct rkcif_stream *stream)
@@ -5281,17 +8854,24 @@
 
 	spin_lock_irqsave(&stream->fps_lock, flags);
 	stream->readout.fe_timestamp = ktime_get_ns();
+
+	if (cif_dev->inf_id == RKCIF_DVP) {
+		spin_unlock_irqrestore(&stream->fps_lock, flags);
+		return;
+	}
+
 	if (stream->id == RKCIF_STREAM_MIPI_ID0)
 		detect_stream->readout.readout_time = stream->readout.fe_timestamp - stream->readout.fs_timestamp;
 
-	if ((cif_dev->hdr.mode == NO_HDR) && (stream->id == RKCIF_STREAM_MIPI_ID0)) {
+	if ((cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) &&
+	    (stream->id == RKCIF_STREAM_MIPI_ID0)) {
 		detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp;
 
-	} else if ((cif_dev->hdr.mode == HDR_X2) && (stream->id == RKCIF_STREAM_MIPI_ID1)) {
+	} else if ((cif_dev->hdr.hdr_mode == HDR_X2) && (stream->id == RKCIF_STREAM_MIPI_ID1)) {
 		detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp;
 		detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fe_timestamp;
 		detect_stream->readout.total_time += detect_stream->readout.readout_time;
-	} else if ((cif_dev->hdr.mode == HDR_X3) && (stream->id == RKCIF_STREAM_MIPI_ID2)) {
+	} else if ((cif_dev->hdr.hdr_mode == HDR_X3) && (stream->id == RKCIF_STREAM_MIPI_ID2)) {
 		detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp;
 		detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fe_timestamp;
 		detect_stream->readout.total_time += detect_stream->readout.readout_time;
@@ -5310,11 +8890,8 @@
 	int ret = 0;
 
 	if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) {
-
-		v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n",
-			 stream->id, stream->frame_idx);
-
-		stream->frame_idx++;
+		cif_dev->err_state |= (RKCIF_ERR_ID0_TRIG_SIMULT << stream->id);
+		cif_dev->irq_stats.trig_simult_cnt[stream->id]++;
 		return;
 	}
 	if (!stream->is_line_wake_up) {
@@ -5332,99 +8909,181 @@
 		spin_unlock_irqrestore(&stream->fps_lock, flags);
 	}
 
-	if (cif_dev->inf_id == RKCIF_MIPI_LVDS)
-		rkcif_deal_readout_time(stream);
+	rkcif_deal_readout_time(stream);
+
+	if (!stream->is_line_wake_up) {
+		ret = rkcif_assign_new_buffer_pingpong(stream,
+						       RKCIF_YUV_ADDR_STATE_UPDATE,
+						       mipi_id);
+		if (ret && cif_dev->chip_id < CHIP_RK3588_CIF)
+			return;
+	} else {
+		ret = rkcif_update_new_buffer_wake_up_mode(stream);
+		if (ret && cif_dev->chip_id < CHIP_RK3588_CIF)
+			return;
+	}
+	if (cif_dev->chip_id < CHIP_RK3588_CIF &&
+	    cif_dev->active_sensor->mbus.type == V4L2_MBUS_BT656 &&
+	    stream->id != 0)
+		stream->frame_idx++;
+	if (!stream->is_line_wake_up && stream->dma_en & RKCIF_DMAEN_BY_VICAP)
+		rkcif_buf_done_prepare(stream, active_buf, mipi_id, 0);
 
 	if (cif_dev->chip_id == CHIP_RV1126_CIF ||
 	    cif_dev->chip_id == CHIP_RV1126_CIF_LITE ||
 	    cif_dev->chip_id == CHIP_RK3568_CIF)
-		rkcif_luma_isr(&cif_dev->luma_vdev, mipi_id, stream->frame_idx);
-
-	if (!stream->is_line_wake_up) {
-		ret = rkcif_assign_new_buffer_pingpong(stream,
-					 RKCIF_YUV_ADDR_STATE_UPDATE,
-					 mipi_id);
-		if (ret)
-			goto end;
-	} else {
-		ret = rkcif_update_new_buffer_wake_up_mode(stream);
-		if (ret)
-			return;
-	}
-	if (!stream->is_line_wake_up)
-		rkcif_buf_done_prepare(stream, active_buf, mipi_id, 0);
-
-end:
-	if (!stream->is_line_wake_up)
-		stream->frame_idx++;
+		rkcif_luma_isr(&cif_dev->luma_vdev, mipi_id, cif_dev->stream[0].frame_idx - 1);
 }
 
-u32 rkcif_get_sof(struct rkcif_device *cif_dev)
+static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev,
+				      struct rkcif_stream *stream,
+				      int mipi_id)
+{
+	if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) {
+
+		v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n",
+			 stream->id, stream->frame_idx);
+		return;
+	}
+
+	spin_lock(&stream->fps_lock);
+	if (stream->frame_phase & CIF_CSI_FRAME0_READY)
+		stream->fps_stats.frm0_timestamp = ktime_get_ns();
+	else if (stream->frame_phase & CIF_CSI_FRAME1_READY)
+		stream->fps_stats.frm1_timestamp = ktime_get_ns();
+	spin_unlock(&stream->fps_lock);
+
+	if (cif_dev->inf_id == RKCIF_MIPI_LVDS)
+		rkcif_deal_readout_time(stream);
+
+	if (!stream->is_line_wake_up)
+		rkcif_assign_new_buffer_pingpong_toisp(stream,
+						       RKCIF_YUV_ADDR_STATE_UPDATE,
+						       mipi_id);
+}
+
+static void rkcif_update_stream_rockit(struct rkcif_device *cif_dev,
+				struct rkcif_stream *stream,
+				int mipi_id)
+{
+	struct rkcif_buffer *active_buf = NULL;
+	unsigned long flags;
+	int ret = 0;
+
+	if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) {
+
+		v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n",
+			 stream->id, stream->frame_idx);
+		return;
+	}
+	if (!stream->is_line_wake_up) {
+
+		spin_lock_irqsave(&stream->fps_lock, flags);
+		if (stream->frame_phase & CIF_CSI_FRAME0_READY) {
+			if (stream->curr_buf_rockit)
+				active_buf = stream->curr_buf_rockit;
+			stream->fps_stats.frm0_timestamp = ktime_get_ns();
+		} else if (stream->frame_phase & CIF_CSI_FRAME1_READY) {
+			if (stream->next_buf_rockit)
+				active_buf = stream->next_buf_rockit;
+			stream->fps_stats.frm1_timestamp = ktime_get_ns();
+		}
+		spin_unlock_irqrestore(&stream->fps_lock, flags);
+	}
+
+	if (cif_dev->inf_id == RKCIF_MIPI_LVDS)
+		rkcif_deal_readout_time(stream);
+
+	ret = rkcif_assign_new_buffer_pingpong_rockit(stream,
+						      RKCIF_YUV_ADDR_STATE_UPDATE,
+						      mipi_id);
+	if (ret)
+		return;
+
+	if (active_buf) {
+		active_buf->vb.vb2_buf.timestamp = stream->readout.fs_timestamp;
+		active_buf->vb.sequence = stream->frame_idx - 1;
+		rkcif_rockit_buf_done(stream, active_buf);
+	}
+}
+
+static u32 rkcif_get_sof(struct rkcif_device *cif_dev)
 {
 	u32 val = 0x0;
 	struct rkcif_sensor_info *sensor = cif_dev->active_sensor;
+	struct csi2_dev *csi;
 
-	if (sensor->mbus.type == V4L2_MBUS_CSI2)
-		val = rkcif_csi2_get_sof();
-	else if (sensor->mbus.type == V4L2_MBUS_CCP2)
+	if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	    sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) {
+		csi = container_of(sensor->sd, struct csi2_dev, sd);
+		val = rkcif_csi2_get_sof(csi);
+	} else if (sensor->mbus.type == V4L2_MBUS_CCP2) {
 		val = rkcif_lvds_get_sof(cif_dev);
-	else if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
-		 sensor->mbus.type == V4L2_MBUS_BT656)
+	} else if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
+		 sensor->mbus.type == V4L2_MBUS_BT656) {
 		val = rkcif_dvp_get_sof(cif_dev);
-
+	}
 	return val;
 }
 
 static void rkcif_set_sof(struct rkcif_device *cif_dev, u32 seq)
 {
 	struct rkcif_sensor_info *sensor = cif_dev->active_sensor;
+	struct csi2_dev *csi;
 
-	if (sensor->mbus.type == V4L2_MBUS_CSI2)
-		rkcif_csi2_set_sof(seq);
-	else if (sensor->mbus.type == V4L2_MBUS_CCP2)
+	if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+	    sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) {
+		csi = container_of(sensor->sd, struct csi2_dev, sd);
+		rkcif_csi2_set_sof(csi, seq);
+	} else if (sensor->mbus.type == V4L2_MBUS_CCP2) {
 		rkcif_lvds_set_sof(cif_dev, seq);
-	else if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
-		 sensor->mbus.type == V4L2_MBUS_BT656)
+	} else if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
+		   sensor->mbus.type == V4L2_MBUS_BT656) {
 		rkcif_dvp_set_sof(cif_dev, seq);
+	}
 }
 
-static int rkcif_streamoff_in_reset(struct rkcif_device *cif_dev,
-				 struct rkcif_stream *resume_stream[],
-				 struct rkcif_resume_info *resume_info,
-				 enum rkmodule_reset_src reset_src)
+static int rkcif_do_reset_work(struct rkcif_device *cif_dev,
+			       enum rkmodule_reset_src reset_src)
 {
-	struct rkcif_stream *stream = NULL;
 	struct rkcif_pipeline *p = &cif_dev->pipe;
+	struct rkcif_stream *stream = NULL;
+	struct rkcif_stream *resume_stream[RKCIF_MAX_STREAM_MIPI] = { NULL };
 	struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor;
-	u32 on, sof_cnt;
+	struct rkcif_resume_info *resume_info = &cif_dev->reset_work.resume_info;
+	struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer;
+	struct sditf_priv *priv = cif_dev->sditf[0];
 	int i, j, ret = 0;
-	int stream_off_cnt = 0;
+	u32 on, sof_cnt;
+	int capture_mode = 0;
+
+	mutex_lock(&cif_dev->stream_lock);
+	if (cif_dev->reset_work_cancel) {
+		ret = 0;
+		goto unlock_stream;
+	}
+	v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset\n");
 
 	for (i = 0, j = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
 		stream = &cif_dev->stream[i];
-		mutex_lock(&cif_dev->stream_lock);
+
 		if (stream->state == RKCIF_STATE_STREAMING) {
-			stream_off_cnt++;
 
 			v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
 				 "stream[%d] stopping\n", stream->id);
 
 			rkcif_stream_stop(stream);
 
-			atomic_dec(&p->stream_cnt);
-
 			if (stream->id == RKCIF_STREAM_MIPI_ID0) {
 				sof_cnt = rkcif_get_sof(cif_dev);
-				v4l2_err(&cif_dev->v4l2_dev,
+				v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
 					 "%s: stream[%d] sync frmid & csi_sof, frm_id:%d, csi_sof:%d\n",
 					 __func__,
 					 stream->id,
 					 stream->frame_idx,
 					 sof_cnt);
 
-				resume_info->frm_sync_seq = sof_cnt;
-				if (stream->frame_idx != sof_cnt)
-					stream->frame_idx = sof_cnt;
+				resume_info->frm_sync_seq = stream->frame_idx;
 			}
 
 			stream->state = RKCIF_STATE_RESET_IN_STREAMING;
@@ -5435,59 +9094,63 @@
 
 			v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
 				 "%s stop stream[%d] in streaming, frm_id:%d, csi_sof:%d\n",
-				 __func__, stream->id, stream->frame_idx, rkcif_csi2_get_sof());
+				 __func__, stream->id, stream->frame_idx, rkcif_get_sof(cif_dev));
 
 		}
-		mutex_unlock(&cif_dev->stream_lock);
 	}
-	if (!stream_off_cnt)
-		return 0;
 
 	on = 0;
 	for (i = 0; i < p->num_subdevs; i++) {
 
 		if (p->subdevs[i] == terminal_sensor->sd) {
 
-			if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 ||
-			    reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG ||
-			    reset_src == RKICF_RESET_SRC_ERR_CUTOFF) {
-
+			if (reset_src != RKCIF_RESET_SRC_ERR_APP) {
 				ret = v4l2_subdev_call(p->subdevs[i], core, ioctl,
 						       RKMODULE_SET_QUICK_STREAM, &on);
 				if (ret)
-					v4l2_err(&cif_dev->v4l2_dev, "quick stream off subdev:%s failed\n",
+					v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
+						 "quick stream off subdev:%s failed\n",
 						 p->subdevs[i]->name);
 			}
+		} else {
+			ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
 		}
-
 		if (ret)
-			v4l2_err(&cif_dev->v4l2_dev, "%s:stream %s subdev:%s failed\n",
+			v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
+				 "%s:stream %s subdev:%s failed\n",
 				 __func__, on ? "on" : "off", p->subdevs[i]->name);
-
 	}
-	return ret;
-}
 
-static int rkcif_streamon_in_reset(struct rkcif_device *cif_dev,
-				 struct rkcif_stream *resume_stream[],
-				 struct rkcif_resume_info *resume_info,
-				 enum rkmodule_reset_src reset_src)
-{
-	struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer;
-	struct rkcif_stream *stream = NULL;
-	struct rkcif_pipeline *p = &cif_dev->pipe;
-	struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor;
-	int i = 0;
-	int ret = 0;
-	int on = 0;
-	int stream_on_cnt = 0;
+	if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) {
+		for (i = 0; i < cif_dev->sditf_cnt; i++) {
+			if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd)
+				ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl,
+						       RKMODULE_SET_QUICK_STREAM, &on);
+		}
+	}
 
-	for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
+	rockchip_clear_system_status(SYS_STATUS_CIF0);
+
+	if (cif_dev->chip_id >= CHIP_RK3588_CIF) {
+		rkcif_do_soft_reset(cif_dev);
+	} else {
+
+		rkcif_do_cru_reset(cif_dev);
+
+		rkcif_disable_sys_clk(cif_dev->hw_dev);
+
+		udelay(5);
+
+		ret = rkcif_enable_sys_clk(cif_dev->hw_dev);
+
+		if (ret < 0) {
+			v4l2_err(&cif_dev->v4l2_dev, "%s:resume cif clk failed\n", __func__);
+			goto unlock_stream;
+		}
+	}
+
+	for (i = 0; i < j; i++) {
 		stream = resume_stream[i];
-		if (stream == NULL || stream->state != RKCIF_STATE_RESET_IN_STREAMING)
-			break;
-		mutex_lock(&cif_dev->stream_lock);
-		stream_on_cnt++;
 		stream->fs_cnt_in_single_frame = 0;
 		if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
 			if (stream->curr_buf == stream->next_buf) {
@@ -5502,26 +9165,35 @@
 			stream->curr_buf = NULL;
 			stream->next_buf = NULL;
 		}
-		if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 ||
-		    cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)
-			ret = rkcif_csi_stream_start(stream);
+		if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AIQ)
+			capture_mode = RKCIF_STREAM_MODE_CAPTURE;
+		else {
+			if (cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_ONLINE)
+				capture_mode = RKCIF_STREAM_MODE_TOISP;
+			else
+				capture_mode = RKCIF_STREAM_MODE_TOISP_RDBK;
+		}
+		if (cif_dev->active_sensor  &&
+		    (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
+		    cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ||
+		    cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2))
+			ret = rkcif_csi_stream_start(stream, capture_mode);
 		else
-			ret = rkcif_stream_start(stream);
+			ret = rkcif_stream_start(stream, capture_mode);
 		if (ret) {
 			v4l2_err(&cif_dev->v4l2_dev, "%s:resume stream[%d] failed\n",
 				 __func__, stream->id);
 			goto unlock_stream;
 		}
-		atomic_inc(&p->stream_cnt);
-		stream->streamon_timestamp = ktime_get_ns();
-		mutex_unlock(&cif_dev->stream_lock);
+
 		v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
 			 "resume stream[%d], frm_idx:%d, csi_sof:%d\n",
 			 stream->id, stream->frame_idx,
 			 rkcif_get_sof(cif_dev));
 	}
-	if (!stream_on_cnt)
-		return 0;
+
+	rockchip_set_system_status(SYS_STATUS_CIF0);
+
 	on = 1;
 	for (i = 0; i < p->num_subdevs; i++) {
 
@@ -5529,9 +9201,7 @@
 
 			rkcif_set_sof(cif_dev, resume_info->frm_sync_seq);
 
-			if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 ||
-			    reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG ||
-			    reset_src == RKICF_RESET_SRC_ERR_CUTOFF) {
+			if (reset_src != RKCIF_RESET_SRC_ERR_APP) {
 				ret = v4l2_subdev_call(p->subdevs[i], core, ioctl,
 						       RKMODULE_SET_QUICK_STREAM, &on);
 				if (ret)
@@ -5539,6 +9209,11 @@
 						 "quick stream on subdev:%s failed\n",
 						 p->subdevs[i]->name);
 			}
+		} else {
+			if (p->subdevs[i] == terminal_sensor->sd)
+				rkcif_set_sof(cif_dev, resume_info->frm_sync_seq);
+
+			ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
 		}
 
 		if (ret)
@@ -5546,71 +9221,28 @@
 				 p->subdevs[i]->name);
 	}
 
-	rkcif_start_luma(&cif_dev->luma_vdev, resume_stream[0]->cif_fmt_in);
+	if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) {
+		for (i = 0; i < cif_dev->sditf_cnt; i++) {
+			if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd)
+				v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl,
+						 RKMODULE_SET_QUICK_STREAM, &on);
+		}
+	}
+
+	if (cif_dev->chip_id < CHIP_RK3588_CIF)
+		rkcif_start_luma(&cif_dev->luma_vdev,
+				 cif_dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in);
 
 	timer->csi2_err_triggered_cnt = 0;
+	rkcif_monitor_reset_event(cif_dev);
 
 	v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset successfully!\n");
-
 	mutex_unlock(&cif_dev->stream_lock);
 	return 0;
 
 unlock_stream:
 	mutex_unlock(&cif_dev->stream_lock);
 	return ret;
-}
-
-static int rkcif_do_reset_work(struct rkcif_device *cif_dev,
-				    enum rkmodule_reset_src reset_src)
-{
-	struct rkcif_stream *resume_stream[RKCIF_MAX_DEV][RKCIF_MAX_STREAM_MIPI] = {0};
-	struct rkcif_resume_info *resume_info[RKCIF_MAX_DEV];
-	struct rkcif_hw *hw = cif_dev->hw_dev;
-	struct rkcif_device *cifdev = NULL;
-	int i = 0;
-	int ret = 0;
-
-	v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset\n");
-
-	for (i = 0; i < hw->dev_num; i++) {
-		cifdev = hw->cif_dev[i];
-		resume_info[i] = &cifdev->reset_work.resume_info;
-		ret |= rkcif_streamoff_in_reset(cifdev,
-						resume_stream[i],
-						resume_info[i],
-						reset_src);
-	}
-
-	rockchip_clear_system_status(SYS_STATUS_CIF0);
-
-	rkcif_do_cru_reset(cif_dev);
-
-	rkcif_disable_sys_clk(cif_dev->hw_dev);
-
-	udelay(5);
-
-	ret |= rkcif_enable_sys_clk(cif_dev->hw_dev);
-	if (ret < 0)
-		v4l2_err(&cif_dev->v4l2_dev, "%s:resume cif clk failed\n", __func__);
-
-	for (i = 0; i < hw->dev_num; i++) {
-		cifdev = hw->cif_dev[i];
-		resume_info[i] = &cifdev->reset_work.resume_info;
-		ret |= rkcif_streamon_in_reset(cifdev,
-					       resume_stream[i],
-					       resume_info[i],
-					       reset_src);
-	}
-
-	rockchip_set_system_status(SYS_STATUS_CIF0);
-
-	hw->hw_timer.is_running = false;
-	rkcif_monitor_reset_event(cif_dev->hw_dev);
-
-	v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset successfully!\n");
-
-	return ret;
-
 }
 
 void rkcif_reset_work(struct work_struct *work)
@@ -5628,128 +9260,183 @@
 		v4l2_info(&dev->v4l2_dev, "do reset work failed!\n");
 }
 
-static bool rkcif_is_stream_stop_output(struct rkcif_stream *stream)
+static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev)
 {
-	struct rkcif_device *dev = stream->cifdev;
-	struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer;
-	struct rkcif_stream *tmp_stream = NULL;
+	struct rkcif_timer *timer = &dev->reset_watchdog_timer;
+	struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0];
 	struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect;
-	u64 fps, diff_time;
-	unsigned int i;
-	s64 vblank_def = 0;
-	s32 vblank = 0;
-	u64 numerator = 0;
-	u64 denominator = 0;
-	u64 cur_timestamp = 0;
+	u64 fps, timestamp0, timestamp1, diff_time;
+	unsigned long fps_flags;
+	unsigned int deviation = 1;
+	bool is_reduced = false;
+	u64 cur_time = 0;
+	u64 time_distance = 0;
 
-	if (dev->hdr.mode == HDR_X3) {
-		for (i = 0; i < 3; i++) {
-			tmp_stream = &dev->stream[i];
-			if (tmp_stream->state != RKCIF_STATE_STREAMING)
-				return false;
-		}
-	} else if (dev->hdr.mode == HDR_X2) {
-		for (i = 0; i < 2; i++) {
-			tmp_stream = &dev->stream[i];
-			if (tmp_stream->state != RKCIF_STATE_STREAMING)
-				return false;
-		}
-	}
+	spin_lock_irqsave(&stream->fps_lock, fps_flags);
+	timestamp0 = stream->fps_stats.frm0_timestamp;
+	timestamp1 = stream->fps_stats.frm1_timestamp;
+	spin_unlock_irqrestore(&stream->fps_lock, fps_flags);
 
-	vblank_def = rkcif_get_sensor_vblank_def(dev);
-	vblank = rkcif_get_sensor_vblank(dev);
-	numerator = dev->terminal_sensor.fi.interval.numerator;
-	denominator = dev->terminal_sensor.fi.interval.denominator;
-	fps = div_u64(1000 * numerator, denominator);
-	fps *= (raw_rect->height + vblank);
-	fps = div_u64((raw_rect->height + vblank_def), fps);
+	fps = timestamp0 > timestamp1 ?
+	      timestamp0 - timestamp1 : timestamp1 - timestamp0;
+	fps =  div_u64(fps, 1000);
+	diff_time = fps > timer->frame_end_cycle_us ?
+		    fps - timer->frame_end_cycle_us : 0;
+	deviation = DIV_ROUND_UP(timer->vts, 100);
 
-	if (fps > hw_timer->monitor_cycle) {
-		v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "camera work in long expsure, not to check stream loss\n");
+	v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "diff_time:%lld,devi_t:%ld,devi_h:%d\n",
+		  diff_time, timer->line_end_cycle * deviation, deviation);
+
+	cur_time = ktime_get_ns();
+	time_distance = timestamp0 > timestamp1 ?
+			cur_time - timestamp0 : cur_time - timestamp1;
+	time_distance = div_u64(time_distance, 1000);
+	if (time_distance > fps * 2)
 		return false;
+
+	if (diff_time > timer->line_end_cycle * deviation) {
+		s32 vblank = 0;
+		unsigned int vts;
+
+		is_reduced = true;
+		vblank = rkcif_get_sensor_vblank(dev);
+		vts = vblank + timer->raw_height;
+
+		v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "old vts:%d,new vts:%d\n", timer->vts, vts);
+
+		v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
+			  "reduce frame rate,vblank:%d, height(raw output):%d, fps:%lld, frm_end_t:%ld, line_t:%ld, diff:%lld\n",
+			  rkcif_get_sensor_vblank(dev),
+			  raw_rect->height,
+			  fps,
+			  timer->frame_end_cycle_us,
+			  timer->line_end_cycle,
+			  diff_time);
+
+		timer->vts = vts;
+		timer->frame_end_cycle_us = fps;
+		timer->line_end_cycle = div_u64(timer->frame_end_cycle_us, timer->vts);
+	} else {
+		is_reduced = false;
 	}
 
-	cur_timestamp = ktime_get_ns();
-	diff_time = cur_timestamp - stream->streamon_timestamp;
-	diff_time = div_u64(diff_time, 1000000);
-	if (diff_time > hw_timer->monitor_cycle + 10)
-		return true;
+	timer->frame_end_cycle_us = fps;
 
-	return false;
+	fps = div_u64(fps, 1000);
+	fps = fps * timer->frm_num_of_monitor_cycle;
+	timer->cycle = msecs_to_jiffies(fps);
+	timer->timer.expires = jiffies + timer->cycle;
+
+	return is_reduced;
+
 }
 
-static void rkcif_init_reset_work(struct rkcif_hw_timer *hw_timer)
+static void rkcif_dvp_event_reset_pipe(struct rkcif_device *dev, int reset_src)
 {
-	struct rkcif_hw *hw = container_of(hw_timer,
-					  struct rkcif_hw,
-					  hw_timer);
-	struct rkcif_device *dev = NULL;
+	struct rkcif_dvp_sof_subdev *subdev = &dev->dvp_sof_subdev;
+
+	if (subdev) {
+		struct v4l2_event event = {
+			.type = V4L2_EVENT_RESET_DEV,
+			.reserved[0] = reset_src,
+		};
+		v4l2_event_queue(subdev->sd.devnode, &event);
+	}
+}
+
+static void rkcif_lvds_event_reset_pipe(struct rkcif_device *dev, int reset_src)
+{
+	struct rkcif_lvds_subdev *subdev = &dev->lvds_subdev;
+
+	if (subdev) {
+		struct v4l2_event event = {
+			.type = V4L2_EVENT_RESET_DEV,
+			.reserved[0] = reset_src,
+		};
+		v4l2_event_queue(subdev->sd.devnode, &event);
+	}
+}
+
+static void rkcif_send_reset_event(struct rkcif_device *cif_dev, int reset_src)
+{
+	struct v4l2_mbus_config *mbus = &cif_dev->active_sensor->mbus;
+	struct csi2_dev *csi;
+
+	if (mbus->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus->type == V4L2_MBUS_CSI2_CPHY) {
+		csi = container_of(cif_dev->active_sensor->sd, struct csi2_dev, sd);
+		rkcif_csi2_event_reset_pipe(csi, reset_src);
+	} else if (mbus->type == V4L2_MBUS_CCP2) {
+		rkcif_lvds_event_reset_pipe(cif_dev, reset_src);
+	} else {
+		rkcif_dvp_event_reset_pipe(cif_dev, reset_src);
+	}
+	v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev,
+		 "send reset event,bus type 0x%x\n",
+		 mbus->type);
+}
+
+static void rkcif_init_reset_work(struct rkcif_timer *timer)
+{
+	struct rkcif_device *dev = container_of(timer,
+						struct rkcif_device,
+						reset_watchdog_timer);
 	struct rkcif_stream *stream = NULL;
-	struct rkcif_timer *timer;
 	unsigned long flags;
-	int i = 0, j = 0;
+	int i = 0;
 
 	v4l2_info(&dev->v4l2_dev,
 		  "do reset work schedule, run_cnt:%d, reset source:%d\n",
-		  hw_timer->run_cnt, hw_timer->reset_src);
+		  timer->run_cnt, timer->reset_src);
 
-	for (j = 0; j < hw->dev_num; j++) {
-		dev = hw->cif_dev[j];
-		timer = &dev->reset_watchdog_timer;
-		spin_lock_irqsave(&timer->csi2_err_lock, flags);
-		timer->is_triggered = false;
-		timer->csi2_err_cnt_odd = 0;
-		timer->csi2_err_cnt_even = 0;
-		timer->csi2_err_fs_fe_cnt = 0;
-		timer->notifer_called_cnt = 0;
-		for (i = 0; i < dev->num_channels; i++) {
-			stream = &dev->stream[i];
-			if (stream->state == RKCIF_STATE_STREAMING)
-				timer->last_buf_wakeup_cnt[stream->id] = stream->frame_idx;
-		}
-		spin_unlock_irqrestore(&timer->csi2_err_lock, flags);
+	spin_lock_irqsave(&timer->timer_lock, flags);
+	timer->is_running = false;
+	timer->is_triggered = false;
+	timer->csi2_err_cnt_odd = 0;
+	timer->csi2_err_cnt_even = 0;
+	timer->csi2_err_fs_fe_cnt = 0;
+	timer->notifer_called_cnt = 0;
+	for (i = 0; i < dev->num_channels; i++) {
+		stream = &dev->stream[i];
+		if (stream->state == RKCIF_STATE_STREAMING)
+			timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt;
 	}
-	if (hw_timer->is_reset_by_user) {
-		hw->reset_info.is_need_reset = 1;
-		hw->reset_info.reset_src = hw_timer->reset_src;
+	spin_unlock_irqrestore(&timer->timer_lock, flags);
+	if (timer->is_ctrl_by_user) {
+		rkcif_send_reset_event(dev, timer->reset_src);
 	} else {
-		dev->reset_work.reset_src = hw_timer->reset_src;
-		if (schedule_work(&dev->reset_work.work)) {
+		if (!schedule_work(&dev->reset_work.work))
 			v4l2_info(&dev->v4l2_dev,
-				 "schedule reset work successfully\n");
-		} else {
-			v4l2_info(&dev->v4l2_dev,
-				 "schedule reset work failed\n");
-		}
+				  "schedule reset work failed\n");
+		dev->reset_work.reset_src = timer->reset_src;
 	}
 }
 
 static int rkcif_detect_reset_event(struct rkcif_stream *stream,
 				    struct rkcif_timer *timer,
-				    int *check_cnt,
+				    int check_cnt,
 				    bool *is_mod_timer)
 {
 	struct rkcif_device *dev = stream->cifdev;
 	struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor;
-	struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer;
+	unsigned long flags;
 	int ret, is_reset = 0;
 	struct rkmodule_vicap_reset_info rst_info;
 
-	v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
-		 "info: frame end still update(%d, %d), detect cnt: %d, mode:%d check_cnt:%d\n",
-		 timer->last_buf_wakeup_cnt[stream->id], stream->frame_idx,
-		 hw_timer->run_cnt, hw_timer->monitor_mode, *check_cnt);
+	if (timer->last_buf_wakeup_cnt[stream->id] < stream->buf_wake_up_cnt &&
+	    check_cnt == 0) {
 
-	if (timer->last_buf_wakeup_cnt[stream->id] < stream->frame_idx) {
-		*check_cnt += 1;
 		v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
-			 "info: frame end still update(%d, %d), detect cnt: %d, mode:%d\n",
+			 "info: frame end still update(%d, %d) in detecting cnt:%d, mode:%d\n",
 			  timer->last_buf_wakeup_cnt[stream->id], stream->frame_idx,
-			  hw_timer->run_cnt, hw_timer->monitor_mode);
+			  timer->run_cnt, timer->monitor_mode);
 
-		timer->last_buf_wakeup_cnt[stream->id] = stream->frame_idx;
+		timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt;
 
-		if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) {
+		if (stream->frame_idx > 2)
+			rkcif_is_reduced_frame_rate(dev);
+
+		if (timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) {
 			ret = v4l2_subdev_call(terminal_sensor->sd,
 					       core, ioctl,
 					       RKMODULE_GET_VICAP_RST_INFO,
@@ -5759,144 +9446,139 @@
 			else
 				is_reset = rst_info.is_reset;
 			rst_info.is_reset = 0;
-			hw_timer->reset_src = RKCIF_RESET_SRC_ERR_HOTPLUG;
+			if (is_reset)
+				timer->reset_src = RKCIF_RESET_SRC_ERR_HOTPLUG;
 			v4l2_subdev_call(terminal_sensor->sd, core, ioctl,
 					 RKMODULE_SET_VICAP_RST_INFO, &rst_info);
-			if (!is_reset && stream->cifdev->inf_id == RKCIF_MIPI_LVDS)
+			if (!is_reset) {
 				is_reset = rkcif_is_csi2_err_trigger_reset(timer);
-		} else if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE) {
-			if (stream->cifdev->inf_id == RKCIF_MIPI_LVDS)
-				is_reset = rkcif_is_csi2_err_trigger_reset(timer);
-		} else if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) {
-			if (stream->cifdev->inf_id == RKCIF_MIPI_LVDS) {
-				is_reset = timer->is_csi2_err_occurred;
 				if (is_reset)
-					hw_timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2;
-				timer->is_csi2_err_occurred = false;
+					timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2;
 			}
+		} else if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE) {
+			is_reset = rkcif_is_csi2_err_trigger_reset(timer);
+		} else if (timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) {
+			is_reset = timer->is_csi2_err_occurred;
+			if (is_reset)
+				timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2;
+			timer->is_csi2_err_occurred = false;
 		}
 
 		if (is_reset) {
-			rkcif_init_reset_work(hw_timer);
+			rkcif_init_reset_work(timer);
 			return is_reset;
 		}
-		*is_mod_timer = true;
-	} else if (timer->last_buf_wakeup_cnt[stream->id] == stream->frame_idx) {
-		bool is_loss_stream = false;
 
-		*check_cnt += 1;
-		if (hw_timer->run_cnt > 4)
-			is_loss_stream = rkcif_is_stream_stop_output(stream);
-
-		if (is_loss_stream) {
-			v4l2_info(&dev->v4l2_dev,
-				  "do reset work due to frame end is stopped, run_cnt:%d\n",
-				  hw_timer->run_cnt);
-
-			hw_timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF;
-			is_reset = true;
-			rkcif_init_reset_work(hw_timer);
+		if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE ||
+		    timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) {
+			if (timer->run_cnt == timer->max_run_cnt)
+				timer->run_cnt = 0x0;
+			*is_mod_timer = true;
 		} else {
+			if (timer->run_cnt <= timer->max_run_cnt) {
+				*is_mod_timer = true;
+			} else {
+				spin_lock_irqsave(&timer->timer_lock, flags);
+				timer->is_triggered = false;
+				timer->is_running = false;
+				spin_unlock_irqrestore(&timer->timer_lock, flags);
+				v4l2_info(&dev->v4l2_dev, "stop reset detecting!\n");
+			}
+		}
+	} else if (timer->last_buf_wakeup_cnt[stream->id] == stream->buf_wake_up_cnt) {
+
+		bool is_reduced = false;
+
+		if (stream->frame_idx > 2)
+			is_reduced = rkcif_is_reduced_frame_rate(dev);
+		else if (timer->run_cnt < 20)
+			is_reduced = true;
+
+		if (is_reduced) {
 			*is_mod_timer = true;
 			v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s fps is reduced\n", __func__);
+		} else {
+
+			v4l2_info(&dev->v4l2_dev,
+				  "do reset work due to frame end is stopped, run_cnt:%d\n",
+				  timer->run_cnt);
+
+			timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF;
+			rkcif_init_reset_work(timer);
+			is_reset = true;
 		}
 	}
 
-	return is_reset;
-
-}
-
-static int rkcif_dvp_err_trigger_reset(struct rkcif_device *dev)
-{
-	int is_reset = 0;
-
-	if (dev->irq_stats.dvp_overflow_cnt) {
-		dev->irq_stats.dvp_overflow_cnt = 0;
-		is_reset = 1;
-	}
-	return is_reset;
-}
-
-static int rkcif_detect_reset_event_all_dev(struct rkcif_device *dev,
-						     int *check_cnt,
-						     bool *is_mod_timer)
-{
-	struct rkcif_timer *timer = &dev->reset_watchdog_timer;
-	struct rkcif_stream *stream = NULL;
-	int i = 0;
-	int is_reset = 0;
-	int check_cnt_local = 0;
-
-	for (i = 0; i < dev->num_channels; i++) {
-		stream = &dev->stream[i];
-		if (stream->state == RKCIF_STATE_STREAMING) {
-			is_reset = rkcif_detect_reset_event(stream,
-							    timer,
-							    &check_cnt_local,
-							    is_mod_timer);
-			if (is_reset)
-				break;
-		}
-	}
-	if (!is_reset && dev->inf_id == RKCIF_DVP)
-		is_reset = rkcif_dvp_err_trigger_reset(dev);
-
-	if (check_cnt_local)
-		*check_cnt += 1;
 	return is_reset;
 
 }
 
 void rkcif_reset_watchdog_timer_handler(struct timer_list *t)
 {
-	struct rkcif_hw_timer *hw_timer = container_of(t, struct rkcif_hw_timer, timer);
-	struct rkcif_hw *hw = container_of(hw_timer,
-					   struct rkcif_hw,
-					   hw_timer);
-	struct rkcif_device *dev = NULL;
+	struct rkcif_timer *timer = container_of(t, struct rkcif_timer, timer);
+	struct rkcif_device *dev = container_of(timer,
+						struct rkcif_device,
+						reset_watchdog_timer);
+	struct rkcif_stream *stream = NULL;
 	unsigned long flags;
 	unsigned int i;
 	int is_reset = 0;
 	int check_cnt = 0;
 	bool is_mod_timer = false;
 
-	for (i = 0; i < hw->dev_num; i++) {
-		dev = hw->cif_dev[i];
-		is_reset = rkcif_detect_reset_event_all_dev(dev,
-							    &check_cnt,
+	for (i = 0; i < dev->num_channels; i++) {
+		stream = &dev->stream[i];
+		if (stream->state == RKCIF_STATE_STREAMING) {
+			is_reset = rkcif_detect_reset_event(stream,
+							    timer,
+							    check_cnt,
 							    &is_mod_timer);
-		if (is_reset)
-			break;
-
+			check_cnt++;
+			if (is_reset)
+				break;
+		}
 	}
-
 	if (!is_reset && is_mod_timer)
-		mod_timer(&hw_timer->timer, jiffies + hw_timer->cycle_jif);
+		mod_timer(&timer->timer, jiffies + timer->cycle);
 
-	hw_timer->run_cnt += 1;
+	timer->run_cnt += 1;
 
-	if (!check_cnt && !is_reset) {
-		spin_lock_irqsave(&hw_timer->timer_lock, flags);
-		hw_timer->is_running = false;
-		spin_unlock_irqrestore(&hw_timer->timer_lock, flags);
+	if (!check_cnt) {
+		spin_lock_irqsave(&timer->timer_lock, flags);
+		timer->is_triggered = false;
+		timer->is_running = false;
+		spin_unlock_irqrestore(&timer->timer_lock, flags);
 
-		dev_info(hw->dev,
-			 "all stream is stopped, stop reset detect!\n");
+		v4l2_info(&dev->v4l2_dev,
+			  "all stream is stopped, stop reset detect!\n");
 	}
 }
 
 int rkcif_reset_notifier(struct notifier_block *nb,
 			 unsigned long action, void *data)
 {
-	struct rkcif_device *dev = container_of(nb, struct rkcif_device, reset_notifier);
-	struct rkcif_timer *timer = &dev->reset_watchdog_timer;
-	struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer;
+	struct rkcif_hw *hw = container_of(nb, struct rkcif_hw, reset_notifier);
+	struct rkcif_device *dev = NULL;
+	struct rkcif_timer *timer = NULL;
 	unsigned long flags, val;
+	u32 *csi_idx = data;
+	int i = 0;
+	bool is_match_dev = false;
 
-	if (hw_timer->is_running) {
+	for (i = 0; i < hw->dev_num; i++) {
+		dev = hw->cif_dev[i];
+		if (*csi_idx == dev->csi_host_idx) {
+			is_match_dev = true;
+			break;
+		}
+	}
+	if (!is_match_dev)
+		return -EINVAL;
+	timer = &dev->reset_watchdog_timer;
+	if (timer->is_running) {
 		val = action & CSI2_ERR_COUNT_ALL_MASK;
 		spin_lock_irqsave(&timer->csi2_err_lock, flags);
-		if ((val % hw_timer->err_ref_cnt) == 0) {
+		if ((val % timer->csi2_err_ref_cnt) == 0) {
 			timer->notifer_called_cnt++;
 			if ((timer->notifer_called_cnt % 2) == 0)
 				timer->csi2_err_cnt_even = val;
@@ -5914,7 +9596,12 @@
 static void rkcif_modify_line_int(struct rkcif_stream *stream, bool en)
 {
 	struct rkcif_device *cif_dev = stream->cifdev;
+	u32 line_intr_en = 0;
 
+	if (cif_dev->chip_id >= CHIP_RK3588_CIF)
+		line_intr_en = CSI_LINE_INTEN_RK3588(stream->id);
+	else
+		line_intr_en = CSI_LINE_INTEN(stream->id);
 	if (en) {
 		if (cif_dev->wait_line_bak != cif_dev->wait_line) {
 			cif_dev->wait_line_bak = cif_dev->wait_line;
@@ -5924,44 +9611,73 @@
 					     cif_dev->wait_line << 16 | cif_dev->wait_line);
 		}
 		rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
-					CSI_LINE_INTEN(stream->id));
+					line_intr_en);
+		stream->is_line_inten = true;
 	} else {
 		rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
-					 ~(CSI_LINE_INTEN(stream->id)));
+					 ~line_intr_en);
 	}
 }
 
 static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream)
 {
 	struct rkcif_device *cif_dev = stream->cifdev;
+	struct sditf_priv *priv = cif_dev->sditf[0];
+	bool is_change = false;
+	int ch = 0;
+	int i = 0;
+
+	if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_ONLINE)
+		return;
+
+	if ((cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) &&
+	    stream->id == RKCIF_STREAM_MIPI_ID0) {
+		if (cif_dev->wait_line != cif_dev->wait_line_cache)
+			cif_dev->wait_line = cif_dev->wait_line_cache;
+	} else if (cif_dev->hdr.hdr_mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) {
+		if (cif_dev->wait_line != cif_dev->wait_line_cache)
+			cif_dev->wait_line = cif_dev->wait_line_cache;
+	} else if (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) {
+		if (cif_dev->wait_line != cif_dev->wait_line_cache)
+			cif_dev->wait_line = cif_dev->wait_line_cache;
+	}
 
 	if (cif_dev->wait_line && (!stream->is_line_wake_up)) {
+		is_change = true;
 		stream->is_line_wake_up = true;
 		if (stream->frame_phase == CIF_CSI_FRAME0_READY)
 			stream->line_int_cnt = 1;
 		else if (stream->frame_phase == CIF_CSI_FRAME1_READY)
 			stream->line_int_cnt = 0;
+		if (cif_dev->hdr.hdr_mode == HDR_X2) {
+			cif_dev->stream[0].is_line_wake_up = true;
+			cif_dev->stream[0].line_int_cnt = stream->line_int_cnt;
+		} else if (cif_dev->hdr.hdr_mode == HDR_X3) {
+			cif_dev->stream[0].is_line_wake_up = true;
+			cif_dev->stream[1].is_line_wake_up = true;
+			cif_dev->stream[0].line_int_cnt = stream->line_int_cnt;
+			cif_dev->stream[1].line_int_cnt = stream->line_int_cnt;
+		}
 	} else if ((cif_dev->wait_line == 0) && stream->is_line_wake_up) {
 		stream->is_line_wake_up = false;
 	}
 	if (stream->is_line_wake_up) {
-		rkcif_modify_line_int(stream, true);
-		stream->is_line_inten = true;
-	}
-
-	if (cif_dev->hdr.mode == NO_HDR && stream->id == RKCIF_STREAM_MIPI_ID0) {
-		if (cif_dev->wait_line != cif_dev->wait_line_cache)
-			cif_dev->wait_line = cif_dev->wait_line_cache;
-	} else if (cif_dev->hdr.mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) {
-		if (cif_dev->wait_line != cif_dev->wait_line_cache)
-			cif_dev->wait_line = cif_dev->wait_line_cache;
-	} else if (cif_dev->hdr.mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) {
-		if (cif_dev->wait_line != cif_dev->wait_line_cache)
-			cif_dev->wait_line = cif_dev->wait_line_cache;
+		if (is_change) {
+			if (cif_dev->hdr.hdr_mode == HDR_X2)
+				ch = 2;
+			else if (cif_dev->hdr.hdr_mode == HDR_X3)
+				ch = 3;
+			else
+				ch = 1;
+			for (i = 0; i < ch; i++)
+				rkcif_modify_line_int(&cif_dev->stream[i], true);
+		} else {
+			rkcif_modify_line_int(stream, true);
+		}
 	}
 }
 
-static u32 rkisp_mbus_pixelcode_to_v4l2(u32 pixelcode)
+u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode)
 {
 	u32 pixelformat;
 
@@ -6050,13 +9766,14 @@
 			v4l2_subdev_call(cif_dev->terminal_sensor.sd, pad, get_fmt, NULL, &fmt);
 
 			memset(&pixm, 0, sizeof(pixm));
-			pixm.pixelformat = rkisp_mbus_pixelcode_to_v4l2(fmt.format.code);
+			pixm.pixelformat = rkcif_mbus_pixelcode_to_v4l2(fmt.format.code);
 			pixm.width = fmt.format.width;
 			pixm.height = fmt.format.height;
 
 			memset(&input_sel, 0, sizeof(input_sel));
 			input_sel.pad = i;
 			input_sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
+			input_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 			ret = v4l2_subdev_call(cif_dev->terminal_sensor.sd,
 					       pad, get_selection, NULL,
 					       &input_sel);
@@ -6069,12 +9786,899 @@
 	}
 }
 
+void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable)
+{
+	struct rkcif_device *cif_dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus;
+	struct csi_channel_info *channel = &cif_dev->channels[stream->id];
+	u32 val = 0;
+
+	if (stream->buf_owner == RKCIF_DMAEN_BY_ISP)
+		stream->buf_owner = RKCIF_DMAEN_BY_ISP_TO_VICAP;
+
+	if (stream->dma_en) {
+		stream->dma_en |= stream->to_en_dma;
+		stream->to_en_dma = 0;
+		return;
+	}
+
+	stream->dma_en |= stream->to_en_dma;
+	if (!is_only_enable) {
+		if (stream->to_en_dma == RKCIF_DMAEN_BY_VICAP) {
+			rkcif_assign_new_buffer_pingpong(stream,
+							 RKCIF_YUV_ADDR_STATE_INIT,
+							 stream->id);
+			rkcif_write_register(cif_dev, get_reg_index_of_frm0_y_vlw(stream->id),
+					     channel->virtual_width);
+		} else if (stream->to_en_dma == RKCIF_DMAEN_BY_ISP) {
+			rkcif_assign_new_buffer_pingpong_toisp(stream,
+							       RKCIF_YUV_ADDR_STATE_INIT,
+							       stream->id);
+		}
+	}
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY)
+		rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_CTRL, 0x00010000);
+	else
+		rkcif_write_register_or(cif_dev, CIF_REG_DVP_CTRL, 0x00010000);
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) {
+		val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id));
+		if (!stream->is_compact)
+			val |= CSI_WRDDR_TYPE_RAW_UNCOMPACT;
+		else
+			val &= ~CSI_WRDDR_TYPE_RAW_UNCOMPACT;
+		val |= CSI_DMA_ENABLE;
+		rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id), val);
+	} else if (mbus_cfg->type == V4L2_MBUS_CCP2) {
+		val = rkcif_read_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id));
+		if (!stream->is_compact)
+			val |= CSI_WRDDR_TYPE_RAW_UNCOMPACT << 17;
+		else
+			val &= ~(CSI_WRDDR_TYPE_RAW_UNCOMPACT << 17);
+		val |= LVDS_DMAEN_RV1106;
+		rkcif_write_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id), val);
+	} else {
+		val = rkcif_read_register(cif_dev, CIF_REG_DVP_FOR);
+		if (!stream->is_compact)
+			val |= CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11;
+		else
+			val &= ~(CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11);
+		rkcif_write_register(cif_dev, CIF_REG_DVP_FOR, val);
+		val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL);
+		if (cif_dev->chip_id == CHIP_RK3588_CIF)
+			val |= DVP_DMA_EN;
+		else if (cif_dev->chip_id == CHIP_RV1106_CIF)
+			val |= DVP_SW_DMA_EN(stream->id);
+		rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val);
+	}
+
+	stream->to_en_dma = 0;
+}
+
+static int rkcif_stop_dma_capture(struct rkcif_stream *stream)
+{
+	struct rkcif_device *cif_dev = stream->cifdev;
+	struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus;
+	u32 val = 0;
+
+	if (stream->buf_replace_cnt)
+		return -EINVAL;
+
+	stream->dma_en &= ~stream->to_stop_dma;
+
+	if (stream->dma_en != 0) {
+		if (stream->dma_en & RKCIF_DMAEN_BY_ISP)
+			stream->buf_owner = RKCIF_DMAEN_BY_ISP;
+		stream->to_stop_dma = 0;
+		return 0;
+	}
+
+	if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) {
+		val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id));
+		val &= ~CSI_DMA_ENABLE;
+		if (stream->is_stop_capture) {
+			val &= ~CSI_ENABLE_CAPTURE;
+			stream->is_stop_capture = false;
+		}
+		rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id), val);
+	} else if (mbus_cfg->type == V4L2_MBUS_CCP2) {
+		val = rkcif_read_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id));
+		val &= ~LVDS_DMAEN_RV1106;
+		if (stream->is_stop_capture) {
+			val &= ~ENABLE_CAPTURE;
+			stream->is_stop_capture = false;
+		}
+		rkcif_write_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id), val);
+	}  else {
+		val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL);
+		if (cif_dev->chip_id == CHIP_RK3588_CIF)
+			val &= ~DVP_DMA_EN;
+		else if (cif_dev->chip_id == CHIP_RV1106_CIF)
+			val &= ~(DVP_SW_DMA_EN(stream->id));
+		if (stream->is_stop_capture) {
+			val &= ~ENABLE_CAPTURE;
+			stream->is_stop_capture = false;
+		}
+		rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val);
+	}
+	stream->to_stop_dma = 0;
+	v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev,
+		 "stream[%d] replace_cnt %d, y_addr 0x%x, 0x%x\n",
+		 stream->id, stream->buf_replace_cnt,
+		 rkcif_read_register(cif_dev, get_reg_index_of_frm0_y_addr(stream->id)),
+		 rkcif_read_register(cif_dev, get_reg_index_of_frm1_y_addr(stream->id)));
+	return 0;
+}
+
+static void rkcif_send_sof(struct rkcif_device *cif_dev)
+{
+	struct v4l2_mbus_config *mbus = &cif_dev->active_sensor->mbus;
+	struct csi2_dev *csi;
+
+	if (mbus->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus->type == V4L2_MBUS_CSI2_CPHY) {
+		csi = container_of(cif_dev->active_sensor->sd, struct csi2_dev, sd);
+		rkcif_csi2_event_inc_sof(csi);
+	} else if (mbus->type == V4L2_MBUS_CCP2) {
+		rkcif_lvds_event_inc_sof(cif_dev);
+	} else {
+		rkcif_dvp_event_inc_sof(cif_dev);
+	}
+}
+
+static int rkcif_g_toisp_ch(unsigned int intstat_glb, int index)
+{
+	if (intstat_glb & TOISP_END_CH0(index))
+		return RKCIF_TOISP_CH0;
+	if (intstat_glb & TOISP_END_CH1(index))
+		return RKCIF_TOISP_CH1;
+	if (intstat_glb & TOISP_END_CH2(index))
+		return RKCIF_TOISP_CH2;
+
+	return -EINVAL;
+}
+
+static int rkcif_g_toisp_fs(unsigned int intstat_glb, int index)
+{
+	if (intstat_glb & TOISP_FS_CH0(index))
+		return RKCIF_TOISP_CH0;
+	if (intstat_glb & TOISP_FS_CH1(index))
+		return RKCIF_TOISP_CH1;
+	if (intstat_glb & TOISP_FS_CH2(index))
+		return RKCIF_TOISP_CH2;
+
+	return -EINVAL;
+}
+
+static void rkcif_toisp_check_stop_status(struct sditf_priv *priv,
+					  unsigned int intstat_glb,
+					  int index)
+{
+	int ch = 0;
+	struct rkcif_stream *stream;
+	int src_id = 0;
+	int i = 0;
+	u32 val = 0;
+	u64 cur_time = 0;
+
+	for (i = 0; i < TOISP_CH_MAX; i++) {
+		ch = rkcif_g_toisp_ch(intstat_glb, index);
+		if (ch >= 0) {
+			src_id = priv->toisp_inf.ch_info[ch].id;
+			if (src_id == 24)
+				stream = &priv->cif_dev->stream[0];
+			else
+				stream = &priv->cif_dev->stream[src_id % 4];
+			if (stream->stopping) {
+				v4l2_dbg(3, rkcif_debug, &priv->cif_dev->v4l2_dev,
+					 "stream[%d] stop\n",
+					 stream->id);
+				rkcif_stream_stop(stream);
+				stream->stopping = false;
+				wake_up(&stream->wq_stopped);
+			}
+
+			if (stream->cifdev->chip_id >= CHIP_RV1106_CIF)
+				rkcif_modify_frame_skip_config(stream);
+			if (stream->cifdev->rdbk_debug &&
+			    stream->frame_idx < 15)
+				v4l2_info(&priv->cif_dev->v4l2_dev,
+					  "stream[%d] toisp fe %d\n",
+					  stream->id,
+					  stream->frame_idx - 1);
+
+			switch (ch) {
+			case RKCIF_TOISP_CH0:
+				val = TOISP_END_CH0(index);
+				intstat_glb = intstat_glb & (~val);
+				break;
+			case RKCIF_TOISP_CH1:
+				val = TOISP_END_CH1(index);
+				intstat_glb = intstat_glb & (~val);
+				break;
+			case RKCIF_TOISP_CH2:
+				val = TOISP_END_CH2(index);
+				intstat_glb = intstat_glb & (~val);
+				break;
+			default:
+				break;
+			}
+		}
+		ch = rkcif_g_toisp_fs(intstat_glb, index);
+		if (ch >= 0) {
+			src_id = priv->toisp_inf.ch_info[ch].id;
+			if (src_id == 24)
+				stream = &priv->cif_dev->stream[0];
+			else
+				stream = &priv->cif_dev->stream[src_id % 4];
+			if (stream->id == 0)
+				rkcif_send_sof(stream->cifdev);
+			stream->frame_idx++;
+			cur_time = ktime_get_ns();
+			stream->readout.readout_time = cur_time - stream->readout.fs_timestamp;
+			stream->readout.fs_timestamp = cur_time;
+			if (stream->cifdev->rdbk_debug &&
+			    stream->frame_idx < 15)
+				v4l2_info(&priv->cif_dev->v4l2_dev,
+					  "stream[%d] toisp sof seq %d\n",
+					  stream->id,
+					  stream->frame_idx - 1);
+			if (stream->to_en_dma)
+				rkcif_enable_dma_capture(stream, false);
+			if (stream->to_en_scale) {
+				stream->to_en_scale = false;
+				rkcif_scale_start(stream->scale_vdev);
+			}
+			switch (ch) {
+			case RKCIF_TOISP_CH0:
+				val = TOISP_FS_CH0(index);
+				intstat_glb = intstat_glb & (~val);
+				break;
+			case RKCIF_TOISP_CH1:
+				val = TOISP_FS_CH1(index);
+				intstat_glb = intstat_glb & (~val);
+				break;
+			case RKCIF_TOISP_CH2:
+				val = TOISP_FS_CH2(index);
+				intstat_glb = intstat_glb & (~val);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+}
+
+void rkcif_irq_handle_toisp(struct rkcif_device *cif_dev, unsigned int intstat_glb)
+{
+	int i = 0;
+	bool to_check = false;
+	struct sditf_priv *priv = cif_dev->sditf[0];
+
+	if (!priv || priv->mode.rdbk_mode != RKISP_VICAP_ONLINE)
+		return;
+
+	for (i = 0; i < 2; i++) {
+		if (priv->toisp_inf.link_mode == TOISP0 &&
+		    i == 0) {
+			to_check = true;
+		} else if (priv->toisp_inf.link_mode == TOISP1 &&
+			   i == 1) {
+			to_check = true;
+		} else if (priv->toisp_inf.link_mode == TOISP_UNITE &&
+			   i == 1) {
+			to_check = true;
+		}
+		if (to_check)
+			rkcif_toisp_check_stop_status(priv, intstat_glb, i);
+	}
+}
+
+static int rkcif_check_group_sync_state(struct rkcif_device *cif_dev)
+{
+	struct rkcif_stream *detect_stream = &cif_dev->stream[0];
+	struct rkcif_stream *next_stream = NULL;
+	struct rkcif_hw *hw = cif_dev->hw_dev;
+	u64 fs_interval = 0;
+	int i = 0;
+	int ret = 0;
+	struct rkcif_multi_sync_config *sync_config;
+
+	sync_config = &hw->sync_config[cif_dev->sync_cfg.group];
+	sync_config->sync_code |= BIT(cif_dev->csi_host_idx);
+	v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev,
+		 "sync code 0x%x, mask 0x%x, update 0x%x, cache 0x%x, timestamp %llu\n",
+		 sync_config->sync_code,
+		 sync_config->sync_mask,
+		 sync_config->update_code,
+		 sync_config->update_cache,
+		 detect_stream->readout.fs_timestamp);
+
+	if (sync_config->sync_code != sync_config->sync_mask)
+		return -EINVAL;
+
+	for (i = 0; i < sync_config->dev_cnt; i++) {
+		if (sync_config->mode == RKCIF_MASTER_MASTER) {
+			if (i < sync_config->ext_master.count)
+				next_stream = &sync_config->ext_master.cif_dev[i]->stream
+					[0];
+			else
+				next_stream = &sync_config->int_master.cif_dev[0]->stream
+					[0];
+		} else if (sync_config->mode == RKCIF_MASTER_SLAVE) {
+			if (i < sync_config->slave.count)
+				next_stream = &sync_config->slave.cif_dev[i]->stream
+					[0];
+			else
+				next_stream = &sync_config->int_master.cif_dev[0]->stream
+					[0];
+		} else {
+			v4l2_err(&cif_dev->v4l2_dev,
+				 "ERROR: invalid group sync mode\n");
+			ret = -EINVAL;
+			break;
+		}
+		if (detect_stream == next_stream)
+			continue;
+		fs_interval = abs(detect_stream->readout.fs_timestamp - next_stream->readout.fs_timestamp);
+		if (fs_interval > RKCIF_MAX_INTERVAL_NS) {
+			ret = -EINVAL;
+			break;
+		}
+	}
+	return ret;
+}
+
+static void rkcif_deal_sof(struct rkcif_device *cif_dev)
+{
+	struct rkcif_stream *detect_stream = &cif_dev->stream[0];
+	struct rkcif_hw *hw = cif_dev->hw_dev;
+	struct rkcif_device *tmp_dev = NULL;
+	unsigned long flags;
+	int i = 0;
+	int ret = 0;
+
+	if (cif_dev->chip_id < CHIP_RK3588_CIF)
+		detect_stream->fs_cnt_in_single_frame++;
+	spin_lock_irqsave(&detect_stream->fps_lock, flags);
+	detect_stream->readout.fs_timestamp = ktime_get_ns();
+	spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
+
+	if (cif_dev->sync_cfg.type != RKCIF_NOSYNC_MODE) {
+		struct rkcif_multi_sync_config *sync_config;
+
+		sync_config = &hw->sync_config[cif_dev->sync_cfg.group];
+		ret = rkcif_check_group_sync_state(cif_dev);
+		if (!ret) {
+			sync_config->sync_code = 0;
+			sync_config->frame_idx++;
+			spin_lock_irqsave(&hw->group_lock, flags);
+			sync_config->update_cache = sync_config->sync_mask;
+			if (!sync_config->update_code) {
+				sync_config->update_code = sync_config->update_cache;
+				sync_config->update_cache = 0;
+			}
+			spin_unlock_irqrestore(&hw->group_lock, flags);
+			for (i = 0; i < sync_config->dev_cnt; i++) {
+				if (sync_config->mode == RKCIF_MASTER_MASTER) {
+					if (i < sync_config->ext_master.count)
+						tmp_dev = sync_config->ext_master.cif_dev[i];
+					else
+						tmp_dev = sync_config->int_master.cif_dev[0];
+				} else if (sync_config->mode == RKCIF_MASTER_SLAVE) {
+					if (i < sync_config->slave.count)
+						tmp_dev = sync_config->slave.cif_dev[i];
+					else
+						tmp_dev = sync_config->int_master.cif_dev[0];
+				} else {
+					v4l2_err(&cif_dev->v4l2_dev,
+						 "ERROR: invalid group sync mode\n");
+				}
+				if (tmp_dev) {
+					rkcif_send_sof(tmp_dev);
+					tmp_dev->stream[0].frame_idx = sync_config->frame_idx;
+				}
+			}
+		}
+	} else {
+		if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode) {
+			rkcif_send_sof(cif_dev);
+			detect_stream->frame_idx++;
+		}
+		if (detect_stream->cifdev->rdbk_debug &&
+		    detect_stream->frame_idx < 15 &&
+		    (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode))
+			v4l2_info(&cif_dev->v4l2_dev,
+				  "stream[%d] sof %d %lld\n",
+				  detect_stream->id,
+				  detect_stream->frame_idx - 1,
+				  ktime_get_ns());
+	}
+}
+
+unsigned int rkcif_irq_global(struct rkcif_device *cif_dev)
+{
+	unsigned int intstat_glb = 0;
+
+	intstat_glb = rkcif_read_register(cif_dev, CIF_REG_GLB_INTST);
+	if (intstat_glb)
+		v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev,
+			 "intstat_glb 0x%x\n",
+			 intstat_glb);
+	else
+		return intstat_glb;
+
+	if (intstat_glb & SCALE_TOISP_AXI0_ERR) {
+		v4l2_err(&cif_dev->v4l2_dev,
+			"ERROR: scale channel, AXI0 bus err intstat_glb:0x%x !!\n",
+			intstat_glb);
+		return 0;
+	}
+	if (intstat_glb & SCALE_TOISP_AXI1_ERR) {
+		v4l2_err(&cif_dev->v4l2_dev,
+			"ERROR: scale channel, AXI1 bus err intstat_glb:0x%x !!\n",
+			intstat_glb);
+		return 0;
+	}
+	rkcif_irq_handle_scale(cif_dev, intstat_glb);
+	return intstat_glb;
+}
+
+static bool rkcif_check_buffer_prepare(struct rkcif_stream *stream)
+{
+	struct rkcif_device *cif_dev = stream->cifdev;
+	unsigned long flags;
+	bool is_update = false;
+	struct rkcif_multi_sync_config *sync_config;
+
+	spin_lock_irqsave(&cif_dev->hw_dev->group_lock, flags);
+	sync_config = &cif_dev->hw_dev->sync_config[cif_dev->sync_cfg.group];
+	if (stream->id == 0 &&
+	    sync_config->update_code & BIT(cif_dev->csi_host_idx)) {
+		is_update = true;
+		sync_config->update_code &= ~(BIT(cif_dev->csi_host_idx));
+		if (!sync_config->update_code &&
+		    sync_config->update_cache) {
+			sync_config->update_code = sync_config->update_cache;
+			sync_config->update_cache = 0;
+		}
+	} else {
+		if (cif_dev->rdbk_buf[RDBK_L])
+			is_update = true;
+	}
+
+	spin_unlock_irqrestore(&cif_dev->hw_dev->group_lock, flags);
+	return is_update;
+}
+
+void rkcif_err_print_work(struct work_struct *work)
+{
+	struct rkcif_err_state_work *err_state_work = container_of(work,
+							      struct rkcif_err_state_work,
+							      work);
+	struct rkcif_device *dev = container_of(err_state_work,
+						struct rkcif_device,
+						err_state_work);
+	u32 err_state = 0;
+	int intstat = 0;
+	int lastline = 0;
+	int lastpixel = 0;
+	u64 cur_time = 0;
+	bool is_print = false;
+
+	cur_time = ktime_get_ns();
+	if (err_state_work->last_timestamp == 0) {
+		is_print = true;
+	} else {
+		if (cur_time - err_state_work->last_timestamp > 500000000)
+			is_print = true;
+	}
+	err_state_work->last_timestamp = cur_time;
+	err_state = err_state_work->err_state;
+	intstat = err_state_work->intstat;
+	lastline = err_state_work->lastline;
+	lastpixel = err_state_work->lastpixel;
+	if (err_state & RKCIF_ERR_ID0_NOT_BUF && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[0] not active buffer, frame num %d, cnt %llu\n",
+			 dev->stream[0].frame_idx, dev->irq_stats.not_active_buf_cnt[0]);
+	if (err_state & RKCIF_ERR_ID1_NOT_BUF && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[1] not active buffer, frame num %d, cnt %llu\n",
+			 dev->stream[1].frame_idx, dev->irq_stats.not_active_buf_cnt[1]);
+	if (err_state & RKCIF_ERR_ID2_NOT_BUF && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[2] not active buffer, frame num %d, cnt %llu\n",
+			 dev->stream[2].frame_idx, dev->irq_stats.not_active_buf_cnt[2]);
+	if (err_state & RKCIF_ERR_ID3_NOT_BUF && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[3] not active buffer, frame num %d, cnt %llu\n",
+			 dev->stream[3].frame_idx, dev->irq_stats.not_active_buf_cnt[3]);
+	if (err_state & RKCIF_ERR_ID0_TRIG_SIMULT && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[0], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n",
+			 dev->stream[0].frame_idx, dev->irq_stats.trig_simult_cnt[0]);
+	if (err_state & RKCIF_ERR_ID1_TRIG_SIMULT && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[1], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n",
+			 dev->stream[1].frame_idx, dev->irq_stats.trig_simult_cnt[1]);
+	if (err_state & RKCIF_ERR_ID2_TRIG_SIMULT && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[2], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n",
+			 dev->stream[2].frame_idx, dev->irq_stats.trig_simult_cnt[2]);
+	if (err_state & RKCIF_ERR_ID3_TRIG_SIMULT && is_print)
+		v4l2_err(&dev->v4l2_dev,
+			 "stream[3], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n",
+			 dev->stream[3].frame_idx, dev->irq_stats.trig_simult_cnt[3]);
+	if (err_state & RKCIF_ERR_SIZE)
+		v4l2_err(&dev->v4l2_dev,
+			 "ERROR: csi size err, intstat:0x%x, lastline:0x%x, cnt %llu\n",
+			 intstat, lastline, dev->irq_stats.csi_size_err_cnt);
+	if (err_state & RKCIF_ERR_OVERFLOW)
+		v4l2_err(&dev->v4l2_dev,
+			 "ERROR: csi fifo overflow, intstat:0x%x, lastline:0x%x, cnt %llu\n",
+			 intstat, lastline, dev->irq_stats.csi_overflow_cnt);
+	if (err_state & RKCIF_ERR_BANDWIDTH_LACK)
+		v4l2_err(&dev->v4l2_dev,
+			 "ERROR: csi bandwidth lack, intstat:0x%x, lastline:0x%x, cnt %llu\n",
+			 intstat, lastline, dev->irq_stats.csi_bwidth_lack_cnt);
+	if (err_state & RKCIF_ERR_ID0_MULTI_FS)
+		v4l2_err(&dev->v4l2_dev,
+			 "ERR: multi fs in oneframe in id0, fs_num:%u\n",
+			 dev->stream[0].fs_cnt_in_single_frame);
+	if (err_state & RKCIF_ERR_BUS)
+		v4l2_err(&dev->v4l2_dev, "dvp bus err, intstat 0x%x, last line 0x%x\n",
+			 intstat, lastline);
+	if (err_state & RKCIF_ERR_PIXEL)
+		v4l2_err(&dev->v4l2_dev, "dvp pix err, intstat 0x%x, last pixel 0x%x\n",
+			 intstat, lastpixel);
+	if (err_state & RKCIF_ERR_LINE)
+		v4l2_err(&dev->v4l2_dev, "dvp line err, intstat 0x%x, last line 0x%x\n",
+			 intstat, lastline);
+}
+
+/* pingpong irq for rk3588 and next */
+void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev)
+{
+	struct rkcif_stream *stream;
+	struct rkcif_stream *detect_stream = &cif_dev->stream[0];
+	struct v4l2_mbus_config *mbus;
+	unsigned int intstat, i = 0xff;
+	unsigned long flags;
+	bool is_update = false;
+	int ret = 0;
+
+	if (!cif_dev->active_sensor)
+		return;
+
+	mbus = &cif_dev->active_sensor->mbus;
+	if (mbus->type == V4L2_MBUS_CSI2_DPHY ||
+	    mbus->type == V4L2_MBUS_CSI2_CPHY ||
+	    mbus->type == V4L2_MBUS_CCP2) {
+		int mipi_id;
+		u32 lastline = 0;
+
+		intstat = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT);
+		lastline = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1);
+		cif_dev->err_state_work.lastline = lastline;
+		cif_dev->err_state_work.intstat = intstat;
+
+		/* clear all interrupts that has been triggered */
+		if (intstat) {
+			rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat);
+			v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev,
+				 "intstat 0x%x\n",
+				 intstat);
+		} else {
+			return;
+		}
+
+		if (intstat & CSI_SIZE_ERR) {
+			cif_dev->irq_stats.csi_size_err_cnt++;
+			cif_dev->err_state |= RKCIF_ERR_SIZE;
+			rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000);
+			return;
+		}
+
+		if (intstat & CSI_FIFO_OVERFLOW_V1) {
+			cif_dev->irq_stats.csi_overflow_cnt++;
+			cif_dev->err_state |= RKCIF_ERR_OVERFLOW;
+			return;
+		}
+
+		if (intstat & CSI_BANDWIDTH_LACK_V1) {
+			cif_dev->irq_stats.csi_bwidth_lack_cnt++;
+			cif_dev->err_state |= RKCIF_ERR_BANDWIDTH_LACK;
+		}
+
+		if (intstat & CSI_ALL_ERROR_INTEN_V1) {
+			cif_dev->irq_stats.all_err_cnt++;
+			return;
+		}
+
+		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
+			mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev,
+						      intstat);
+			if (mipi_id < 0)
+				continue;
+
+			stream = &cif_dev->stream[mipi_id];
+			if (!cif_dev->sditf[0] ||
+			    cif_dev->sditf[0]->mode.rdbk_mode)
+				stream->buf_wake_up_cnt++;
+
+			if (stream->stopping && (!stream->dma_en)) {
+				rkcif_stream_stop(stream);
+				stream->stopping = false;
+				wake_up(&stream->wq_stopped);
+				continue;
+			}
+
+			if (stream->state != RKCIF_STATE_STREAMING)
+				continue;
+			stream->is_in_vblank = true;
+			switch (mipi_id) {
+			case RKCIF_STREAM_MIPI_ID0:
+				stream->frame_phase = SW_FRM_END_ID0(intstat);
+				intstat &= ~CSI_FRAME_END_ID0;
+				break;
+			case RKCIF_STREAM_MIPI_ID1:
+				stream->frame_phase = SW_FRM_END_ID1(intstat);
+				intstat &= ~CSI_FRAME_END_ID1;
+				break;
+			case RKCIF_STREAM_MIPI_ID2:
+				stream->frame_phase = SW_FRM_END_ID2(intstat);
+				intstat &= ~CSI_FRAME_END_ID2;
+				break;
+			case RKCIF_STREAM_MIPI_ID3:
+				stream->frame_phase = SW_FRM_END_ID3(intstat);
+				intstat &= ~CSI_FRAME_END_ID3;
+				break;
+			}
+			if (stream->cifdev->rdbk_debug &&
+			    stream->frame_idx < 15 &&
+			    (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode))
+				v4l2_info(&cif_dev->v4l2_dev,
+					  "stream[%d] fe %d, phase %d, %lld\n",
+					  stream->id,
+					  stream->frame_idx - 1,
+					  stream->frame_phase,
+					  ktime_get_ns());
+			if (stream->is_finish_stop_dma && stream->is_wait_dma_stop) {
+				stream->is_wait_dma_stop = false;
+				wake_up(&stream->wq_stopped);
+				stream->is_finish_stop_dma = false;
+				continue;
+			}
+			if (stream->crop_dyn_en)
+				rkcif_dynamic_crop(stream);
+
+			if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) {
+				if (cif_dev->sync_cfg.type == RKCIF_NOSYNC_MODE)
+					is_update = true;
+				else
+					is_update = rkcif_check_buffer_prepare(stream);
+				v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev,
+					 "dma capture by vicap, is_updata %d, group mode %d, dma_en %d\n",
+					 is_update, cif_dev->sync_cfg.type, stream->dma_en);
+				if (is_update)
+					rkcif_update_stream(cif_dev, stream, mipi_id);
+			} else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) {
+				v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev,
+					 "dma capture by isp, dma_en 0x%x\n",
+					 stream->dma_en);
+				rkcif_update_stream_toisp(cif_dev, stream, mipi_id);
+			} else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) {
+				v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev,
+					 "dma capture by rockit, dma_en 0x%x\n",
+					 stream->dma_en);
+				rkcif_update_stream_rockit(cif_dev, stream, mipi_id);
+			}
+
+			if (cif_dev->chip_id >= CHIP_RV1106_CIF)
+				rkcif_modify_frame_skip_config(stream);
+			if (stream->is_change_toisp) {
+				stream->is_change_toisp = false;
+				if ((cif_dev->hdr.hdr_mode == HDR_X2 && stream->id != 1) ||
+				    (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id != 2))
+					rkcif_release_unnecessary_buf_for_online(stream,
+										 stream->curr_buf_toisp);
+				else
+					sditf_change_to_online(cif_dev->sditf[0]);
+			}
+
+			spin_lock_irqsave(&stream->vbq_lock, flags);
+			if (!(stream->dma_en & RKCIF_DMAEN_BY_ISP) && stream->lack_buf_cnt == 2) {
+				v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev,
+					 "stream[%d] to stop dma, lack_buf_cnt %d\n",
+					 stream->id, stream->lack_buf_cnt);
+				stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP;
+				rkcif_stop_dma_capture(stream);
+			}
+			spin_unlock_irqrestore(&stream->vbq_lock, flags);
+			if (stream->to_en_scale) {
+				stream->to_en_scale = false;
+				rkcif_scale_start(stream->scale_vdev);
+			}
+			rkcif_detect_wake_up_mode_change(stream);
+			if (cif_dev->chip_id < CHIP_RK3588_CIF &&
+			    mipi_id == RKCIF_STREAM_MIPI_ID0) {
+				if ((intstat & (CSI_FRAME1_START_ID0 | CSI_FRAME0_START_ID0)) == 0 &&
+				    detect_stream->fs_cnt_in_single_frame > 1) {
+					cif_dev->err_state |= RKCIF_ERR_ID0_MULTI_FS;
+					detect_stream->is_fs_fe_not_paired = true;
+					detect_stream->fs_cnt_in_single_frame = 0;
+				} else {
+					detect_stream->fs_cnt_in_single_frame--;
+				}
+			}
+			rkcif_monitor_reset_event(cif_dev);
+			cif_dev->irq_stats.frm_end_cnt[stream->id]++;
+		}
+
+		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
+			if (intstat & CSI_START_INTSTAT(i)) {
+				stream = &cif_dev->stream[i];
+				if (i == 0) {
+					rkcif_deal_sof(cif_dev);
+				} else {
+					spin_lock_irqsave(&stream->fps_lock, flags);
+					stream->readout.fs_timestamp = ktime_get_ns();
+					stream->frame_idx++;
+					spin_unlock_irqrestore(&stream->fps_lock, flags);
+				}
+				stream->is_in_vblank = false;
+				spin_lock_irqsave(&stream->vbq_lock, flags);
+				if (stream->stopping && stream->dma_en) {
+					if (stream->dma_en & RKCIF_DMAEN_BY_VICAP)
+						stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP;
+					else if (stream->dma_en & RKCIF_DMAEN_BY_ISP)
+						stream->to_stop_dma = RKCIF_DMAEN_BY_ISP;
+					stream->is_stop_capture = true;
+				}
+				if (stream->to_stop_dma) {
+					ret = rkcif_stop_dma_capture(stream);
+					if (!ret)
+						stream->is_finish_stop_dma = true;
+				}
+				if (stream->to_en_dma)
+					rkcif_enable_dma_capture(stream, false);
+				spin_unlock_irqrestore(&stream->vbq_lock, flags);
+			}
+			if (intstat & CSI_LINE_INTSTAT_V1(i)) {
+				stream = &cif_dev->stream[i];
+				if (stream->is_line_inten) {
+					stream->line_int_cnt++;
+					if (cif_dev->rdbk_debug > 1 &&
+					    stream->frame_idx < 15)
+						v4l2_info(&cif_dev->v4l2_dev,
+							  "line int %lld\n",
+							  stream->line_int_cnt);
+					if (cif_dev->sditf[0] && cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO)
+						rkcif_line_wake_up_rdbk(stream, stream->id);
+					else
+						rkcif_line_wake_up(stream, stream->id);
+					rkcif_modify_line_int(stream, false);
+					stream->is_line_inten = false;
+				}
+				v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev,
+					 "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff);
+			}
+		}
+	} else {
+		struct rkcif_stream *stream;
+		int ch_id;
+		int lastline;
+
+		intstat = rkcif_read_register(cif_dev, CIF_REG_DVP_INTSTAT);
+		if (intstat)
+			rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat);
+		else
+			return;
+		lastline = rkcif_read_register(cif_dev, CIF_REG_DVP_LINE_CNT);
+		cif_dev->err_state_work.lastline = lastline;
+		cif_dev->err_state_work.intstat = intstat;
+		stream = &cif_dev->stream[RKCIF_STREAM_CIF];
+
+		if (intstat & DVP_SIZE_ERR) {
+			cif_dev->irq_stats.dvp_size_err_cnt++;
+			rkcif_write_register_or(cif_dev, CIF_REG_DVP_CTRL, 0x000A0000);
+			cif_dev->err_state |= RKCIF_ERR_SIZE;
+		}
+
+		if (intstat & DVP_FIFO_OVERFLOW) {
+			cif_dev->irq_stats.dvp_overflow_cnt++;
+			cif_dev->err_state |= RKCIF_ERR_OVERFLOW;
+		}
+
+		if (intstat & DVP_BANDWIDTH_LACK) {
+			cif_dev->irq_stats.dvp_bwidth_lack_cnt++;
+			cif_dev->err_state |= RKCIF_ERR_BANDWIDTH_LACK;
+		}
+
+		if (intstat & INTSTAT_ERR_RK3588) {
+			cif_dev->irq_stats.all_err_cnt++;
+		}
+
+		for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) {
+			ch_id = rkcif_dvp_g_ch_id_by_fe(&cif_dev->v4l2_dev, intstat);
+
+			if (ch_id < 0)
+				continue;
+
+			stream = &cif_dev->stream[ch_id];
+			if (!cif_dev->sditf[0] ||
+			    cif_dev->sditf[0]->mode.rdbk_mode)
+				stream->buf_wake_up_cnt++;
+
+			if (stream->stopping) {
+				rkcif_stream_stop(stream);
+				stream->stopping = false;
+				wake_up(&stream->wq_stopped);
+				continue;
+			}
+
+			if (stream->state != RKCIF_STATE_STREAMING)
+				continue;
+			stream->is_in_vblank = true;
+			switch (ch_id) {
+			case RKCIF_STREAM_MIPI_ID0:
+				stream->frame_phase = SW_FRM_END_ID0(intstat);
+				intstat &= ~DVP_ALL_END_ID0;
+				break;
+			case RKCIF_STREAM_MIPI_ID1:
+				stream->frame_phase = SW_FRM_END_ID1(intstat);
+				intstat &= ~DVP_ALL_END_ID1;
+				break;
+			case RKCIF_STREAM_MIPI_ID2:
+				stream->frame_phase = SW_FRM_END_ID2(intstat);
+				intstat &= ~DVP_ALL_END_ID2;
+				break;
+			case RKCIF_STREAM_MIPI_ID3:
+				stream->frame_phase = SW_FRM_END_ID3(intstat);
+				intstat &= ~DVP_ALL_END_ID3;
+				break;
+			}
+			if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) {
+				if (cif_dev->sync_cfg.type == RKCIF_NOSYNC_MODE)
+					is_update = true;
+				else
+					is_update = rkcif_check_buffer_prepare(stream);
+				if (is_update)
+					rkcif_update_stream(cif_dev, stream, ch_id);
+			} else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) {
+				rkcif_update_stream_toisp(cif_dev, stream, ch_id);
+			} else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) {
+				rkcif_update_stream_rockit(cif_dev, stream, ch_id);
+			}
+
+			if (stream->to_en_dma)
+				rkcif_enable_dma_capture(stream, false);
+			if (stream->to_stop_dma) {
+				rkcif_stop_dma_capture(stream);
+				wake_up(&stream->wq_stopped);
+			}
+			cif_dev->irq_stats.frm_end_cnt[stream->id]++;
+		}
+
+		if (intstat & DVP_FRAME0_START_ID0 || intstat & DVP_FRAME1_START_ID0) {
+			stream->is_in_vblank = false;
+			rkcif_deal_sof(cif_dev);
+		}
+
+		if (stream->crop_dyn_en)
+			rkcif_dynamic_crop(stream);
+	}
+}
+
 void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
 {
 	struct rkcif_stream *stream;
 	struct rkcif_stream *detect_stream = &cif_dev->stream[0];
 	struct v4l2_mbus_config *mbus;
-	unsigned int intstat = 0x0, i = 0xff, bak_intstat = 0x0;
+	unsigned int intstat = 0x0, i = 0xff;
 	unsigned long flags;
 	int ret = 0;
 
@@ -6082,7 +10686,8 @@
 		return;
 
 	mbus = &cif_dev->active_sensor->mbus;
-	if ((mbus->type == V4L2_MBUS_CSI2 ||
+	if ((mbus->type == V4L2_MBUS_CSI2_DPHY ||
+	     mbus->type == V4L2_MBUS_CSI2_CPHY ||
 	     mbus->type == V4L2_MBUS_CCP2) &&
 	    (cif_dev->chip_id == CHIP_RK1808_CIF ||
 	     cif_dev->chip_id == CHIP_RV1126_CIF ||
@@ -6092,78 +10697,27 @@
 
 		intstat = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT);
 		lastline = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1);
+		cif_dev->err_state_work.lastline = lastline;
+		cif_dev->err_state_work.intstat = intstat;
 
 		/* clear all interrupts that has been triggered */
 		rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat);
 
 		if (intstat & CSI_FIFO_OVERFLOW) {
 			cif_dev->irq_stats.csi_overflow_cnt++;
-			v4l2_err(&cif_dev->v4l2_dev,
-				 "ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n",
-				  intstat, lastline);
-			return;
+			cif_dev->err_state |= RKCIF_ERR_OVERFLOW;
 		}
 
 		if (intstat & CSI_BANDWIDTH_LACK) {
 			cif_dev->irq_stats.csi_bwidth_lack_cnt++;
-			v4l2_err(&cif_dev->v4l2_dev,
-				 "ERROR: csi bandwidth lack, intstat:0x%x!!\n",
-				 intstat);
+			cif_dev->err_state |= RKCIF_ERR_BANDWIDTH_LACK;
 			return;
 		}
 
 		if (intstat & CSI_ALL_ERROR_INTEN) {
 			cif_dev->irq_stats.all_err_cnt++;
-			v4l2_err(&cif_dev->v4l2_dev,
-				 "ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat);
 			return;
 		}
-
-		if ((intstat & (CSI_FRAME0_START_ID0 | CSI_FRAME1_START_ID0)) ==
-			(CSI_FRAME0_START_ID0 | CSI_FRAME1_START_ID0)) {
-			v4l2_err(&cif_dev->v4l2_dev, "%s:ERR: double fs in one fs int\n",
-				 __func__);
-		}
-
-		if (intstat & CSI_FRAME0_START_ID0) {
-			if (mbus->type == V4L2_MBUS_CSI2)
-				rkcif_csi2_event_inc_sof();
-			else if (mbus->type == V4L2_MBUS_CCP2)
-				rkcif_lvds_event_inc_sof(cif_dev);
-			detect_stream->fs_cnt_in_single_frame++;
-			spin_lock_irqsave(&detect_stream->fps_lock, flags);
-			detect_stream->readout.fs_timestamp = ktime_get_ns();
-			spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
-		}
-
-		if (intstat & CSI_FRAME1_START_ID0) {
-			if (mbus->type == V4L2_MBUS_CSI2)
-				rkcif_csi2_event_inc_sof();
-			else if (mbus->type == V4L2_MBUS_CCP2)
-				rkcif_lvds_event_inc_sof(cif_dev);
-			detect_stream->fs_cnt_in_single_frame++;
-			spin_lock_irqsave(&detect_stream->fps_lock, flags);
-			detect_stream->readout.fs_timestamp = ktime_get_ns();
-			spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
-		}
-		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
-			if (intstat & CSI_LINE_INTSTAT(i)) {
-				stream = &cif_dev->stream[i];
-				if (stream->is_line_inten) {
-					stream->line_int_cnt++;
-					rkcif_line_wake_up(stream, stream->id);
-					rkcif_modify_line_int(stream, false);
-					stream->is_line_inten = false;
-				}
-				v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
-					 "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff);
-			}
-		}
-
-		/* if do not reach frame dma end, return irq */
-		mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat);
-		if (mipi_id < 0)
-			return;
 
 		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
 			mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev,
@@ -6206,22 +10760,44 @@
 
 			rkcif_update_stream(cif_dev, stream, mipi_id);
 			rkcif_detect_wake_up_mode_change(stream);
+			rkcif_monitor_reset_event(cif_dev);
 			if (mipi_id == RKCIF_STREAM_MIPI_ID0) {
 				if ((intstat & (CSI_FRAME1_START_ID0 | CSI_FRAME0_START_ID0)) == 0 &&
 				    detect_stream->fs_cnt_in_single_frame > 1) {
-					v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev,
-						 "%s ERR: multi fs in oneframe, bak_int:0x%x, fs_num:%u\n",
-						 __func__,
-						 bak_intstat,
-						 detect_stream->fs_cnt_in_single_frame);
+					cif_dev->err_state |= RKCIF_ERR_ID0_MULTI_FS;
 					detect_stream->is_fs_fe_not_paired = true;
 					detect_stream->fs_cnt_in_single_frame = 0;
 				} else {
 					detect_stream->fs_cnt_in_single_frame--;
 				}
 			}
+			cif_dev->irq_stats.frm_end_cnt[stream->id]++;
 		}
-		cif_dev->irq_stats.all_frm_end_cnt++;
+		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
+			if (intstat & CSI_START_INTSTAT(i)) {
+				stream = &cif_dev->stream[i];
+				if (i == 0) {
+					rkcif_deal_sof(cif_dev);
+				} else {
+					spin_lock_irqsave(&stream->fps_lock, flags);
+					stream->readout.fs_timestamp = ktime_get_ns();
+					stream->frame_idx++;
+					spin_unlock_irqrestore(&stream->fps_lock, flags);
+				}
+				stream->is_in_vblank = false;
+			}
+			if (intstat & CSI_LINE_INTSTAT(i)) {
+				stream = &cif_dev->stream[i];
+				if (stream->is_line_inten) {
+					stream->line_int_cnt++;
+					rkcif_line_wake_up(stream, stream->id);
+					rkcif_modify_line_int(stream, false);
+					stream->is_line_inten = false;
+				}
+				v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev,
+					 "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff);
+			}
+		}
 	} else {
 		u32 lastline, lastpix, ctl;
 		u32 cif_frmst, frmid, int_en;
@@ -6235,49 +10811,36 @@
 		lastpix = rkcif_read_register(cif_dev, CIF_REG_DVP_LAST_PIX);
 		lastpix =  CIF_FETCH_Y_LAST_LINE(lastpix);
 		ctl = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL);
+		cif_dev->err_state_work.lastline = lastline;
+		cif_dev->err_state_work.lastpixel = lastpix;
+		cif_dev->err_state_work.intstat = intstat;
 
 		rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat);
 
 		stream = &cif_dev->stream[RKCIF_STREAM_CIF];
 
-		if ((intstat & LINE_INT_END) && !(intstat & FRAME_END) &&
-		    (cif_dev->dvp_sof_in_oneframe == 0)) {
-			if ((intstat & (PRE_INF_FRAME_END | PST_INF_FRAME_END)) == 0x0) {
-				if ((intstat & INTSTAT_ERR) == 0x0) {
-					rkcif_dvp_event_inc_sof(cif_dev);
-					int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN);
-					int_en &= ~LINE_INT_EN;
-					rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en);
-					cif_dev->dvp_sof_in_oneframe = 1;
-				}
-			}
-		}
-
 		if (intstat & BUS_ERR) {
 			cif_dev->irq_stats.dvp_bus_err_cnt++;
-			v4l2_info(&cif_dev->v4l2_dev, "dvp bus err\n");
+			cif_dev->err_state |= RKCIF_ERR_BUS;
 		}
 
 		if (intstat & DVP_ALL_OVERFLOW) {
 			cif_dev->irq_stats.dvp_overflow_cnt++;
-			v4l2_info(&cif_dev->v4l2_dev, "dvp overflow err\n");
+			cif_dev->err_state |= RKCIF_ERR_OVERFLOW;
 		}
 
 		if (intstat & LINE_ERR) {
 			cif_dev->irq_stats.dvp_line_err_cnt++;
-			v4l2_info(&cif_dev->v4l2_dev, "dvp line err\n");
+			cif_dev->err_state |= RKCIF_ERR_LINE;
 		}
 
 		if (intstat & PIX_ERR) {
 			cif_dev->irq_stats.dvp_pix_err_cnt++;
-			v4l2_info(&cif_dev->v4l2_dev, "dvp pix err\n");
+			cif_dev->err_state |= RKCIF_ERR_PIXEL;
 		}
 
-		if (intstat & INTSTAT_ERR) {
+		if (intstat & INTSTAT_ERR)
 			cif_dev->irq_stats.all_err_cnt++;
-			v4l2_err(&cif_dev->v4l2_dev,
-				 "ERROR: DVP_ALL_ERROR_INTEN:0x%x!!\n", intstat);
-		}
 
 		/* There are two irqs enabled:
 		 *  - PST_INF_FRAME_END: cif FIFO is ready,
@@ -6298,7 +10861,7 @@
 			stream = &cif_dev->stream[RKCIF_STREAM_CIF];
 
 			if ((intstat & FRAME_END)) {
-				struct vb2_v4l2_buffer *vb_done = NULL;
+				struct rkcif_buffer *active_buf = NULL;
 
 				int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN);
 				int_en |= LINE_INT_EN;
@@ -6318,7 +10881,7 @@
 					v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n",
 						  frmid, cif_frmst);
 					rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS,
-							     cif_frmst & 0x3);
+							     FRAME_STAT_CLS);
 				}
 
 				if (lastline != stream->pixm.height ||
@@ -6334,11 +10897,11 @@
 
 				if (cif_frmst & CIF_F0_READY) {
 					if (stream->curr_buf)
-						vb_done = &stream->curr_buf->vb;
+						active_buf = stream->curr_buf;
 					stream->frame_phase = CIF_CSI_FRAME0_READY;
 				} else if (cif_frmst & CIF_F1_READY) {
 					if (stream->next_buf)
-						vb_done = &stream->next_buf->vb;
+						active_buf = stream->next_buf;
 					stream->frame_phase = CIF_CSI_FRAME1_READY;
 				}
 
@@ -6352,12 +10915,12 @@
 				ret = rkcif_assign_new_buffer_oneframe(stream,
 								 RKCIF_YUV_ADDR_STATE_UPDATE);
 
-				if (vb_done && (!ret)) {
-					vb_done->sequence = stream->frame_idx;
-					rkcif_vb_done_oneframe(stream, vb_done);
+				if (active_buf && (!ret)) {
+					active_buf->vb.sequence = stream->frame_idx;
+					rkcif_vb_done_tasklet(stream, active_buf);
 				}
 				stream->frame_idx++;
-				cif_dev->irq_stats.all_frm_end_cnt++;
+				cif_dev->irq_stats.frm_end_cnt[stream->id]++;
 			}
 		} else {
 			for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) {
@@ -6406,10 +10969,23 @@
 					v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n",
 						  frmid, cif_frmst);
 					rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS,
-							     cif_frmst & 0xffff);
+							     FRAME_STAT_CLS);
 				}
 				rkcif_update_stream(cif_dev, stream, ch_id);
-				cif_dev->irq_stats.all_frm_end_cnt++;
+				cif_dev->irq_stats.frm_end_cnt[stream->id]++;
+			}
+		}
+
+		if ((intstat & LINE_INT_END) && !(intstat & FRAME_END) &&
+		    (cif_dev->dvp_sof_in_oneframe == 0)) {
+			if ((intstat & (PRE_INF_FRAME_END | PST_INF_FRAME_END)) == 0x0) {
+				if ((intstat & INTSTAT_ERR) == 0x0) {
+					rkcif_deal_sof(cif_dev);
+					int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN);
+					int_en &= ~LINE_INT_EN;
+					rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en);
+					cif_dev->dvp_sof_in_oneframe = 1;
+				}
 			}
 		}
 
@@ -6431,6 +11007,8 @@
 
 		intstat = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT);
 		lastline = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1);
+		cif_dev->err_state_work.lastline = lastline;
+		cif_dev->err_state_work.intstat = intstat;
 
 		/* clear all interrupts that has been triggered */
 		rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat);
@@ -6454,18 +11032,6 @@
 				 "ERROR: cif lite lvds all err:0x%x!!\n", intstat);
 			return;
 		}
-
-		if (intstat & CSI_FRAME0_START_ID0)
-			rkcif_lvds_event_inc_sof(cif_dev);
-
-
-		if (intstat & CSI_FRAME1_START_ID0)
-			rkcif_lvds_event_inc_sof(cif_dev);
-
-		/* if do not reach frame dma end, return irq */
-		mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat);
-		if (mipi_id < 0)
-			return;
 
 		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
 			mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev,
@@ -6505,7 +11071,31 @@
 			}
 
 			rkcif_update_stream(cif_dev, stream, mipi_id);
+			rkcif_monitor_reset_event(cif_dev);
+			cif_dev->irq_stats.frm_end_cnt[stream->id]++;
 		}
-		cif_dev->irq_stats.all_frm_end_cnt++;
+
+		if (intstat & CSI_FRAME0_START_ID0)
+			rkcif_lvds_event_inc_sof(cif_dev);
+
+		if (intstat & CSI_FRAME1_START_ID0)
+			rkcif_lvds_event_inc_sof(cif_dev);
 	}
 }
+
+int rkcif_sditf_disconnect(struct video_device *vdev)
+{
+	struct rkcif_vdev_node *vnode = vdev_to_node(vdev);
+	struct rkcif_stream *stream = to_rkcif_stream(vnode);
+	struct rkcif_device *cifdev = stream->cifdev;
+	struct media_link *link;
+	int ret;
+
+	link = list_first_entry(&cifdev->sditf[0]->sd.entity.links, struct media_link, list);
+	ret = media_entity_setup_link(link, 0);
+	if (ret)
+		dev_err(cifdev->dev, "failed to disable link of sditf with isp");
+
+	return ret;
+}
+EXPORT_SYMBOL(rkcif_sditf_disconnect);

--
Gitblit v1.6.2