From 9999e48639b3cecb08ffb37358bcba3b48161b29 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 08:50:17 +0000
Subject: [PATCH] add ax88772_rst

---
 kernel/drivers/media/platform/rockchip/isp/capture.c | 1130 +++++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 709 insertions(+), 421 deletions(-)

diff --git a/kernel/drivers/media/platform/rockchip/isp/capture.c b/kernel/drivers/media/platform/rockchip/isp/capture.c
index 670acc1..a43e6e4 100644
--- a/kernel/drivers/media/platform/rockchip/isp/capture.c
+++ b/kernel/drivers/media/platform/rockchip/isp/capture.c
@@ -11,17 +11,18 @@
 #include <media/videobuf2-dma-contig.h>
 #include "dev.h"
 #include "regs.h"
+#include "rkisp_tb_helper.h"
 
 #define STREAM_MAX_MP_RSZ_OUTPUT_WIDTH		4416
 #define STREAM_MAX_MP_RSZ_OUTPUT_HEIGHT		3312
 #define STREAM_MAX_SP_RSZ_OUTPUT_WIDTH		1920
 #define STREAM_MAX_SP_RSZ_OUTPUT_HEIGHT		1080
 #define STREAM_MIN_RSZ_OUTPUT_WIDTH		32
-#define STREAM_MIN_RSZ_OUTPUT_HEIGHT		16
+#define STREAM_MIN_RSZ_OUTPUT_HEIGHT		32
 #define STREAM_OUTPUT_STEP_WISE			8
 
-#define STREAM_MIN_MP_SP_INPUT_WIDTH		32
-#define STREAM_MIN_MP_SP_INPUT_HEIGHT		32
+#define STREAM_MIN_MP_SP_INPUT_WIDTH		STREAM_MIN_RSZ_OUTPUT_WIDTH
+#define STREAM_MIN_MP_SP_INPUT_HEIGHT		STREAM_MIN_RSZ_OUTPUT_HEIGHT
 
 static int hdr_dma_frame(struct rkisp_device *dev)
 {
@@ -124,7 +125,7 @@
 	if (atomic_read(&dev->cap_dev.refcnt) > 1 ||
 	    !dev->active_sensor ||
 	    (dev->active_sensor &&
-	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) ||
+	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY) ||
 	    (dev->isp_inp & INP_CIF) ||
 	    (dev->isp_ver != ISP_V20 && dev->isp_ver != ISP_V21))
 		return;
@@ -157,7 +158,7 @@
 
 	if (!dev->active_sensor ||
 	    (dev->active_sensor &&
-	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) ||
+	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY) ||
 	    (dev->isp_inp & INP_CIF) ||
 	    (dev->isp_ver != ISP_V20 && dev->isp_ver != ISP_V21))
 		return 0;
@@ -165,7 +166,7 @@
 	for (i = RKISP_STREAM_DMATX0; i <= RKISP_STREAM_DMATX2; i++) {
 		dmatx = &dev->cap_dev.stream[i];
 		if (dmatx->ops && dmatx->ops->frame_end)
-			dmatx->ops->frame_end(dmatx);
+			dmatx->ops->frame_end(dmatx, FRAME_INIT);
 	}
 
 	if (dev->dmarx_dev.trigger)
@@ -225,7 +226,7 @@
 	if (atomic_inc_return(&dev->hdr.refcnt) > 1 ||
 	    !dev->active_sensor ||
 	    (dev->active_sensor &&
-	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) ||
+	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY) ||
 	    (dev->isp_inp & INP_CIF) ||
 	    (dev->isp_ver != ISP_V20 && dev->isp_ver != ISP_V21))
 		return 0;
@@ -294,7 +295,7 @@
 	if (atomic_dec_return(&dev->hdr.refcnt) ||
 	    !dev->active_sensor ||
 	    (dev->active_sensor &&
-	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) ||
+	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY) ||
 	    (dev->isp_inp & INP_CIF) ||
 	    (dev->isp_ver != ISP_V20 && dev->isp_ver != ISP_V21))
 		return;
@@ -351,7 +352,7 @@
 	if (!hw->dummy_buf.mem_priv ||
 	    !dev->active_sensor ||
 	    (dev->active_sensor &&
-	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) ||
+	     dev->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY) ||
 	    (dev->isp_inp & INP_CIF) ||
 	    (dev->isp_ver != ISP_V20 && dev->isp_ver != ISP_V21))
 		return;
@@ -360,14 +361,14 @@
 	 */
 	for (i = 0; i < hw->dev_num; i++) {
 		isp = hw->isp[i];
-		if (!(isp->isp_inp & INP_CSI))
+		if (!isp ||
+		    (isp && !(isp->isp_inp & INP_CSI)))
 			continue;
 		for (j = RKISP_STREAM_DMATX0; j < RKISP_MAX_STREAM; j++) {
 			stream = &isp->cap_dev.stream[j];
 			if (!stream->linked || stream->curr_buf || stream->next_buf)
 				continue;
-			if (!rkisp_read(dev, stream->config->mi.y_base_ad_init, true))
-				mi_set_y_addr(stream, hw->dummy_buf.dma_addr);
+			mi_set_y_addr(stream, hw->dummy_buf.dma_addr);
 		}
 	}
 }
@@ -393,6 +394,7 @@
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
 	case V4L2_PIX_FMT_YVU422M:
+	case V4L2_PIX_FMT_FBC2:
 		*xsubs = 2;
 		*ysubs = 1;
 		break;
@@ -403,6 +405,7 @@
 	case V4L2_PIX_FMT_YUV420:
 	case V4L2_PIX_FMT_YVU420:
 	case V4L2_PIX_FMT_FBCG:
+	case V4L2_PIX_FMT_FBC0:
 		*xsubs = 2;
 		*ysubs = 2;
 		break;
@@ -431,326 +434,48 @@
 	return 0;
 }
 
-static const struct capture_fmt mp_fmts[] = {
-	/* yuv422 */
-	{
-		.fourcc = V4L2_PIX_FMT_UYVY,
-		.fmt_type = FMT_YUV,
-		.bpp = { 16 },
-		.cplanes = 1,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUVINT,
-	}, {
-		.fourcc = V4L2_PIX_FMT_YUV422P,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 4, 4 },
-		.cplanes = 3,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV16,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_SPLA,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV61,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_SPLA,
-	}, {
-		.fourcc = V4L2_PIX_FMT_YUV422M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 3,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	},
-	/* yuv420 */
-	{
-		.fourcc = V4L2_PIX_FMT_NV21,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_SPLA,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV12,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_SPLA,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV21M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 2,
-		.uv_swap = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_SPLA,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV12M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 2,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_SPLA,
-	}, {
-		.fourcc = V4L2_PIX_FMT_YUV420,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	},
-	/* yuv444 */
-	{
-		.fourcc = V4L2_PIX_FMT_YUV444M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 3,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	},
-	/* raw */
-	{
-		.fourcc = V4L2_PIX_FMT_SRGGB8,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 8 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SGRBG8,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 8 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SGBRG8,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 8 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SBGGR8,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 8 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SRGGB10,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 10 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SGRBG10,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 10 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SGBRG10,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 10 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SBGGR10,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 10 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SRGGB12,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 12 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SGRBG12,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 12 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SGBRG12,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 12 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	}, {
-		.fourcc = V4L2_PIX_FMT_SBGGR12,
-		.fmt_type = FMT_BAYER,
-		.bpp = { 12 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_MP_WRITE_RAW12,
-	},
-};
+int rkisp_stream_frame_start(struct rkisp_device *dev, u32 isp_mis)
+{
+	struct rkisp_stream *stream;
+	int i;
 
-static const struct capture_fmt sp_fmts[] = {
-	/* yuv422 */
-	{
-		.fourcc = V4L2_PIX_FMT_UYVY,
-		.fmt_type = FMT_YUV,
-		.bpp = { 16 },
-		.cplanes = 1,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_INT,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV422,
-	}, {
-		.fourcc = V4L2_PIX_FMT_YUV422P,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV422,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV16,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV422,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV61,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 1,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV422,
-	}, {
-		.fourcc = V4L2_PIX_FMT_YUV422M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 3,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV422,
-	},
-	/* yuv420 */
-	{
-		.fourcc = V4L2_PIX_FMT_NV21,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 1,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV420,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV12,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV420,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV21M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 2,
-		.uv_swap = 1,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV420,
-	}, {
-		.fourcc = V4L2_PIX_FMT_NV12M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 2,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV420,
-	}, {
-		.fourcc = V4L2_PIX_FMT_YUV420,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV420,
-	},
-	/* yuv444 */
-	{
-		.fourcc = V4L2_PIX_FMT_YUV444M,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8, 8, 8 },
-		.cplanes = 3,
-		.mplanes = 3,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV444,
-	},
-	/* yuv400 */
-	{
-		.fourcc = V4L2_PIX_FMT_GREY,
-		.fmt_type = FMT_YUV,
-		.bpp = { 8 },
-		.cplanes = 1,
-		.mplanes = 1,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV400,
-	},
-	/* rgb */
-	{
-		.fourcc = V4L2_PIX_FMT_XBGR32,
-		.fmt_type = FMT_RGB,
-		.bpp = { 32 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_RGB888,
-	}, {
-		.fourcc = V4L2_PIX_FMT_RGB565,
-		.fmt_type = FMT_RGB,
-		.bpp = { 16 },
-		.mplanes = 1,
-		.write_format = MI_CTRL_SP_WRITE_PLA,
-		.output_format = MI_CTRL_SP_OUTPUT_RGB565,
-	},
-	/* fbcg */
-	{
-		.fourcc = V4L2_PIX_FMT_FBCG,
-		.fmt_type = FMT_FBCGAIN,
-		.bpp = { 8, 16 },
-		.cplanes = 2,
-		.mplanes = 2,
-		.uv_swap = 0,
-		.write_format = MI_CTRL_SP_WRITE_SPLA,
-		.output_format = MI_CTRL_SP_OUTPUT_YUV420,
+	if (isp_mis)
+		rkisp_dvbm_event(dev, CIF_ISP_V_START);
+	rkisp_bridge_update_mi(dev, isp_mis);
+
+	for (i = 0; i < RKISP_MAX_STREAM; i++) {
+		if (i == RKISP_STREAM_VIR || i == RKISP_STREAM_LUMA)
+			continue;
+		stream = &dev->cap_dev.stream[i];
+		if (stream->streaming &&
+		    stream->ops && stream->ops->frame_start)
+			stream->ops->frame_start(stream, isp_mis);
 	}
-};
+
+	return 0;
+}
+
+void rkisp_stream_buf_done_early(struct rkisp_device *dev)
+{
+	struct rkisp_stream *stream;
+	int i;
+
+	if (!dev->cap_dev.is_done_early)
+		return;
+
+	for (i = 0; i < RKISP_MAX_STREAM; i++) {
+		if (i == RKISP_STREAM_VIR || i == RKISP_STREAM_LUMA ||
+		    i == RKISP_STREAM_DMATX0 || i == RKISP_STREAM_DMATX1 ||
+		    i == RKISP_STREAM_DMATX2 || i == RKISP_STREAM_DMATX3)
+			continue;
+		stream = &dev->cap_dev.stream[i];
+		if (stream->streaming && !stream->stopping &&
+		    stream->ops && stream->ops->frame_end)
+			stream->ops->frame_end(stream, FRAME_WORK);
+	}
+}
 
 struct stream_config rkisp_mp_stream_config = {
-	.fmts = mp_fmts,
-	.fmt_size = ARRAY_SIZE(mp_fmts),
 	/* constraints */
 	.max_rsz_width = STREAM_MAX_MP_RSZ_OUTPUT_WIDTH,
 	.max_rsz_height = STREAM_MAX_MP_RSZ_OUTPUT_HEIGHT,
@@ -802,12 +527,11 @@
 		.cb_offs_cnt_init = CIF_MI_MP_CB_OFFS_CNT_INIT,
 		.cr_offs_cnt_init = CIF_MI_MP_CR_OFFS_CNT_INIT,
 		.y_base_ad_shd = CIF_MI_MP_Y_BASE_AD_SHD,
+		.y_pic_size = ISP3X_MI_MP_WR_Y_PIC_SIZE,
 	},
 };
 
 struct stream_config rkisp_sp_stream_config = {
-	.fmts = sp_fmts,
-	.fmt_size = ARRAY_SIZE(sp_fmts),
 	/* constraints */
 	.max_rsz_width = STREAM_MAX_SP_RSZ_OUTPUT_WIDTH,
 	.max_rsz_height = STREAM_MAX_SP_RSZ_OUTPUT_HEIGHT,
@@ -859,6 +583,7 @@
 		.cb_offs_cnt_init = CIF_MI_SP_CB_OFFS_CNT_INIT,
 		.cr_offs_cnt_init = CIF_MI_SP_CR_OFFS_CNT_INIT,
 		.y_base_ad_shd = CIF_MI_SP_Y_BASE_AD_SHD,
+		.y_pic_size = ISP3X_MI_SP_WR_Y_PIC_SIZE,
 	},
 };
 
@@ -876,21 +601,40 @@
 	return NULL;
 }
 
-/*
- * Make sure max resize/output resolution is smaller than
- * isp sub device output size. This assumes it's not
- * recommended to use ISP scale-up function to get output size
- * that exceeds sensor max resolution.
- */
-static void restrict_rsz_resolution(struct rkisp_device *dev,
-				    const struct stream_config *config,
+static void restrict_rsz_resolution(struct rkisp_stream *stream,
+				    const struct stream_config *cfg,
 				    struct v4l2_rect *max_rsz)
 {
-	struct v4l2_rect *input_win;
+	struct rkisp_device *dev = stream->ispdev;
+	struct v4l2_rect *input_win = rkisp_get_isp_sd_win(&dev->isp_sdev);
 
-	input_win = rkisp_get_isp_sd_win(&dev->isp_sdev);
-	max_rsz->width = min_t(int, input_win->width, config->max_rsz_width);
-	max_rsz->height = min_t(int, input_win->height, config->max_rsz_height);
+	if (stream->id == RKISP_STREAM_VIR ||
+	    (dev->isp_ver == ISP_V30 && stream->id == RKISP_STREAM_BP)) {
+		max_rsz->width = input_win->width;
+		max_rsz->height = input_win->height;
+	} else if (stream->id == RKISP_STREAM_FBC) {
+		max_rsz->width = stream->dcrop.width;
+		max_rsz->height = stream->dcrop.height;
+	} else if (stream->id == RKISP_STREAM_MPDS ||
+		   stream->id == RKISP_STREAM_BPDS) {
+		struct rkisp_stream *t = &dev->cap_dev.stream[stream->conn_id];
+
+		max_rsz->width = t->out_fmt.width / 4;
+		max_rsz->height = t->out_fmt.height / 4;
+	} else if (stream->id == RKISP_STREAM_LUMA) {
+		u32 div = dev->is_bigmode ? 32 : 16;
+
+		max_rsz->width = ALIGN(DIV_ROUND_UP(input_win->width, div), 4);
+		max_rsz->height = DIV_ROUND_UP(input_win->height, div);
+	} else if (dev->hw_dev->unite) {
+		/* scale down only for unite mode */
+		max_rsz->width = min_t(int, input_win->width, cfg->max_rsz_width);
+		max_rsz->height = min_t(int, input_win->height, cfg->max_rsz_height);
+	} else {
+		/* scale up/down */
+		max_rsz->width = cfg->max_rsz_width;
+		max_rsz->height = cfg->max_rsz_height;
+	}
 }
 
 static int rkisp_set_fmt(struct rkisp_stream *stream,
@@ -898,18 +642,17 @@
 			   bool try)
 {
 	const struct capture_fmt *fmt;
+	struct rkisp_vdev_node *node = &stream->vnode;
 	const struct stream_config *config = stream->config;
 	struct rkisp_device *dev = stream->ispdev;
-	struct rkisp_stream *other_stream;
-	unsigned int imagsize = 0;
-	unsigned int planes;
-	u32 xsubs = 1, ysubs = 1;
-	unsigned int i;
+	struct v4l2_rect max_rsz;
+	u32 i, planes, imagsize = 0, xsubs = 1, ysubs = 1;
 
 	fmt = find_fmt(stream, pixm->pixelformat);
 	if (!fmt) {
-		v4l2_err(&stream->ispdev->v4l2_dev,
-			 "nonsupport pixelformat:%c%c%c%c\n",
+		v4l2_err(&dev->v4l2_dev,
+			 "%s nonsupport pixelformat:%c%c%c%c\n",
+			 node->vdev.name,
 			 pixm->pixelformat,
 			 pixm->pixelformat >> 8,
 			 pixm->pixelformat >> 16,
@@ -917,51 +660,89 @@
 		return -EINVAL;
 	}
 
+	/* do checks on resolution */
+	restrict_rsz_resolution(stream, config, &max_rsz);
 	if (stream->id == RKISP_STREAM_MP ||
-	    stream->id == RKISP_STREAM_SP) {
-		struct v4l2_rect max_rsz;
+	    stream->id == RKISP_STREAM_SP ||
+	    (stream->id == RKISP_STREAM_BP && dev->isp_ver != ISP_V30)) {
+		pixm->width = clamp_t(u32, pixm->width, config->min_rsz_width, max_rsz.width);
+	} else if (pixm->width != max_rsz.width &&
+		   pixm->height != max_rsz.height &&
+		   (stream->id == RKISP_STREAM_LUMA ||
+		    (dev->isp_ver == ISP_V30 &&
+		     (stream->id == RKISP_STREAM_BP || stream->id == RKISP_STREAM_FBC)))) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "%s no scale %dx%d should equal to %dx%d\n",
+			  node->vdev.name,
+			  pixm->width, pixm->height,
+			  max_rsz.width, max_rsz.height);
+		pixm->width = max_rsz.width;
+		pixm->height = max_rsz.height;
+	} else if (stream->id == RKISP_STREAM_MPDS || stream->id == RKISP_STREAM_BPDS) {
+		struct rkisp_stream *t = &dev->cap_dev.stream[stream->conn_id];
 
-		other_stream = (stream->id == RKISP_STREAM_MP) ?
-			&dev->cap_dev.stream[RKISP_STREAM_SP] :
-			&dev->cap_dev.stream[RKISP_STREAM_MP];
-		/* do checks on resolution */
-		restrict_rsz_resolution(stream->ispdev, config, &max_rsz);
-		pixm->width = clamp_t(u32, pixm->width,
-				      config->min_rsz_width, max_rsz.width);
-		pixm->height = clamp_t(u32, pixm->height,
-				       config->min_rsz_height, max_rsz.height);
-	} else {
-		other_stream =
-			&stream->ispdev->cap_dev.stream[RKISP_STREAM_MP];
+		if (pixm->pixelformat != t->out_fmt.pixelformat ||
+		    pixm->width != max_rsz.width || pixm->height != max_rsz.height) {
+			v4l2_warn(&dev->v4l2_dev,
+				  "%s from %s, force to %dx%d %c%c%c%c\n",
+				  node->vdev.name, t->vnode.vdev.name,
+				  max_rsz.width, max_rsz.height,
+				  t->out_fmt.pixelformat,
+				  t->out_fmt.pixelformat >> 8,
+				  t->out_fmt.pixelformat >> 16,
+				  t->out_fmt.pixelformat >> 24);
+			pixm->pixelformat = t->out_fmt.pixelformat;
+			pixm->width = max_rsz.width;
+			pixm->height = max_rsz.height;
+		}
+	} else if (stream->id == RKISP_STREAM_VIR) {
+		struct rkisp_stream *t;
+
+		if (stream->conn_id != -1) {
+			t = &dev->cap_dev.stream[stream->conn_id];
+			*pixm = t->out_fmt;
+		} else {
+			for (i = RKISP_STREAM_MP; i < RKISP_STREAM_VIR; i++) {
+				t = &dev->cap_dev.stream[i];
+				if (t->out_isp_fmt.fmt_type != FMT_YUV || !t->streaming)
+					continue;
+				if (t->out_fmt.plane_fmt[0].sizeimage > imagsize) {
+					imagsize = t->out_fmt.plane_fmt[0].sizeimage;
+					*pixm = t->out_fmt;
+					stream->conn_id = t->id;
+				}
+			}
+		}
+		if (stream->conn_id == -1) {
+			v4l2_err(&dev->v4l2_dev, "no output stream for iqtool\n");
+			return -EINVAL;
+		}
+		imagsize = 0;
 	}
+
 	pixm->num_planes = fmt->mplanes;
 	pixm->field = V4L2_FIELD_NONE;
 	/* get quantization from ispsd */
 	pixm->quantization = stream->ispdev->isp_sdev.quantization;
-
-	/* output full range by default, take effect in isp_params */
-	if (!pixm->quantization)
-		pixm->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-	/* can not change quantization when stream-on */
-	if (other_stream->streaming)
-		pixm->quantization = other_stream->out_fmt.quantization;
 
 	/* calculate size */
 	rkisp_fcc_xysubs(fmt->fourcc, &xsubs, &ysubs);
 	planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes;
 	for (i = 0; i < planes; i++) {
 		struct v4l2_plane_pix_format *plane_fmt;
-		unsigned int width, height, bytesperline;
+		unsigned int width, height, bytesperline, w, h;
 
 		plane_fmt = pixm->plane_fmt + i;
 
-		if (i == 0) {
-			width = pixm->width;
-			height = pixm->height;
-		} else {
-			width = pixm->width / xsubs;
-			height = pixm->height / ysubs;
-		}
+		w = (fmt->fmt_type == FMT_FBC) ?
+			ALIGN(pixm->width, 16) : pixm->width;
+		h = (fmt->fmt_type == FMT_FBC) ?
+			ALIGN(pixm->height, 16) : pixm->height;
+		/* mainpath for warp default */
+		if (dev->cap_dev.wrap_line && stream->id == RKISP_STREAM_MP)
+			h = dev->cap_dev.wrap_line;
+		width = i ? w / xsubs : w;
+		height = i ? h / ysubs : h;
 
 		if (dev->isp_ver == ISP_V20 &&
 		    fmt->fmt_type == FMT_BAYER &&
@@ -978,20 +759,28 @@
 			bytesperline = ALIGN(width * fmt->bpp[i] / 8, 256);
 		else
 			bytesperline = width * DIV_ROUND_UP(fmt->bpp[i], 8);
-		/* 128bit AXI, 16byte align for bytesperline */
-		if (dev->isp_ver >= ISP_V20 && stream->id == RKISP_STREAM_SP)
-			bytesperline = ALIGN(bytesperline, 16);
-		/* stride is only available for sp stream and y plane */
-		if (stream->id != RKISP_STREAM_SP || i != 0 ||
-		    plane_fmt->bytesperline < bytesperline)
+
+		if (i != 0 || plane_fmt->bytesperline < bytesperline)
 			plane_fmt->bytesperline = bytesperline;
+
+		/* 128bit AXI, 16byte align for bytesperline */
+		if ((dev->isp_ver == ISP_V20 && stream->id == RKISP_STREAM_SP) ||
+		    dev->isp_ver >= ISP_V30)
+			plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline, 16);
 
 		plane_fmt->sizeimage = plane_fmt->bytesperline * height;
 
-		/* uv address is y size offset need 64 align */
+		/* FMT_FBCGAIN: uv address is y size offset need 64 align
+		 * FMT_FBC: width and height need 16 align
+		 *          header: width * height / 16, and 4096 align for mpp
+		 *          payload: yuv420 or yuv422 size
+		 */
 		if (fmt->fmt_type == FMT_FBCGAIN && i == 0)
 			plane_fmt->sizeimage = ALIGN(plane_fmt->sizeimage, 64);
-
+		else if (fmt->fmt_type == FMT_FBC && i == 0)
+			plane_fmt->sizeimage = ALIGN(plane_fmt->sizeimage >> 4, RK_MPP_ALIGN);
+		else if (fmt->fmt_type == FMT_FBC)
+			plane_fmt->sizeimage += w * h;
 		imagsize += plane_fmt->sizeimage;
 	}
 
@@ -1015,22 +804,29 @@
 		}
 
 		v4l2_dbg(1, rkisp_debug, &stream->ispdev->v4l2_dev,
-			 "%s: stream: %d req(%d, %d) out(%d, %d)\n", __func__,
-			 stream->id, pixm->width, pixm->height,
+			 "%s: %s req(%d, %d) out(%d, %d)\n", __func__,
+			 node->vdev.name, pixm->width, pixm->height,
 			 stream->out_fmt.width, stream->out_fmt.height);
 	}
 
 	return 0;
 }
 
+struct rockit_isp_ops rockit_isp_ops = {
+	.rkisp_set_fmt = rkisp_set_fmt,
+};
+
 int rkisp_fh_open(struct file *filp)
 {
 	struct rkisp_stream *stream = video_drvdata(filp);
 	int ret;
 
+	if (!stream->ispdev->is_probe_end)
+		return -EINVAL;
+
 	ret = v4l2_fh_open(filp);
 	if (!ret) {
-		ret = v4l2_pipeline_pm_use(&stream->vnode.vdev.entity, 1);
+		ret = v4l2_pipeline_pm_get(&stream->vnode.vdev.entity);
 		if (ret < 0)
 			vb2_fop_release(filp);
 	}
@@ -1044,12 +840,8 @@
 	int ret;
 
 	ret = vb2_fop_release(file);
-	if (!ret) {
-		ret = v4l2_pipeline_pm_use(&stream->vnode.vdev.entity, 0);
-		if (ret < 0)
-			v4l2_err(&stream->ispdev->v4l2_dev,
-				 "set pipeline power failed %d\n", ret);
-	}
+	if (!ret)
+		v4l2_pipeline_pm_put(&stream->vnode.vdev.entity);
 	return ret;
 }
 
@@ -1066,14 +858,15 @@
 		pixm.pixelformat = stream->out_isp_fmt.fourcc;
 	if (!pixm.pixelformat)
 		return;
-	pixm.width = width;
-	pixm.height = height;
-	rkisp_set_fmt(stream, &pixm, false);
 
 	stream->dcrop.left = 0;
 	stream->dcrop.top = 0;
 	stream->dcrop.width = width;
 	stream->dcrop.height = height;
+
+	pixm.width = width;
+	pixm.height = height;
+	rkisp_set_fmt(stream, &pixm, false);
 }
 
 /************************* v4l2_file_operations***************************/
@@ -1119,8 +912,9 @@
 	const struct stream_config *config = stream->config;
 	struct v4l2_frmsize_stepwise *s = &fsize->stepwise;
 	struct v4l2_frmsize_discrete *d = &fsize->discrete;
-	const struct ispsd_out_fmt *input_isp_fmt;
+	struct rkisp_device *dev = stream->ispdev;
 	struct v4l2_rect max_rsz;
+	struct v4l2_rect *input_win = rkisp_get_isp_sd_win(&dev->isp_sdev);
 
 	if (fsize->index != 0)
 		return -EINVAL;
@@ -1128,10 +922,15 @@
 	if (!find_fmt(stream, fsize->pixel_format))
 		return -EINVAL;
 
-	restrict_rsz_resolution(stream->ispdev, config, &max_rsz);
+	restrict_rsz_resolution(stream, config, &max_rsz);
 
-	input_isp_fmt = rkisp_get_ispsd_out_fmt(&stream->ispdev->isp_sdev);
-	if (input_isp_fmt->fmt_type == FMT_BAYER) {
+	if (stream->out_isp_fmt.fmt_type == FMT_BAYER ||
+	    stream->id == RKISP_STREAM_FBC ||
+	    stream->id == RKISP_STREAM_BPDS ||
+	    stream->id == RKISP_STREAM_MPDS ||
+	    stream->id == RKISP_STREAM_LUMA ||
+	    stream->id == RKISP_STREAM_VIR ||
+	    (stream->id == RKISP_STREAM_BP && dev->hw_dev->isp_ver == ISP_V30)) {
 		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
 		d->width = max_rsz.width;
 		d->height = max_rsz.height;
@@ -1139,13 +938,286 @@
 		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
 		s->min_width = STREAM_MIN_RSZ_OUTPUT_WIDTH;
 		s->min_height = STREAM_MIN_RSZ_OUTPUT_HEIGHT;
-		s->max_width = max_rsz.width;
-		s->max_height = max_rsz.height;
+		s->max_width = min_t(u32, max_rsz.width, input_win->width);
+		s->max_height = input_win->height;
 		s->step_width = STREAM_OUTPUT_STEP_WISE;
 		s->step_height = STREAM_OUTPUT_STEP_WISE;
 	}
 
 	return 0;
+}
+
+static int rkisp_get_cmsk(struct rkisp_stream *stream, struct rkisp_cmsk_cfg *cfg)
+{
+	struct rkisp_device *dev = stream->ispdev;
+	unsigned long lock_flags = 0;
+	u32 i, win_en, mode;
+
+	if ((dev->isp_ver != ISP_V30 && dev->isp_ver != ISP_V32) ||
+	    stream->id == RKISP_STREAM_FBC ||
+	    stream->id == RKISP_STREAM_MPDS ||
+	    stream->id == RKISP_STREAM_BPDS) {
+		v4l2_err(&dev->v4l2_dev, "%s not support\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&dev->cmsk_lock, lock_flags);
+	*cfg = dev->cmsk_cfg;
+	spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags);
+
+	switch (stream->id) {
+	case RKISP_STREAM_MP:
+		win_en = cfg->win[0].win_en;
+		mode = cfg->win[0].mode;
+		break;
+	case RKISP_STREAM_SP:
+		win_en = cfg->win[1].win_en;
+		mode = cfg->win[1].mode;
+		break;
+	case RKISP_STREAM_BP:
+	default:
+		win_en = cfg->win[2].win_en;
+		mode = cfg->win[2].mode;
+		break;
+	}
+
+	cfg->width_ro = dev->isp_sdev.out_crop.width;
+	cfg->height_ro = dev->isp_sdev.out_crop.height;
+	for (i = 0; i < RKISP_CMSK_WIN_MAX; i++) {
+		cfg->win[i].win_en = !!(win_en & BIT(i));
+		cfg->win[i].mode = !!(mode & BIT(i));
+	}
+
+	return 0;
+}
+
+static int rkisp_set_cmsk(struct rkisp_stream *stream, struct rkisp_cmsk_cfg *cfg)
+{
+	struct rkisp_device *dev = stream->ispdev;
+	unsigned long lock_flags = 0;
+	u16 i, win_en = 0, mode = 0;
+	u16 h_offs, v_offs, h_size, v_size;
+	u32 width = dev->isp_sdev.out_crop.width;
+	u32 height = dev->isp_sdev.out_crop.height;
+	u32 align = (dev->isp_ver == ISP_V30) ? 8 : 2;
+	bool warn = false;
+
+	if ((dev->isp_ver != ISP_V30 && dev->isp_ver != ISP_V32) ||
+	    stream->id == RKISP_STREAM_FBC ||
+	    stream->id == RKISP_STREAM_MPDS ||
+	    stream->id == RKISP_STREAM_BPDS) {
+		v4l2_err(&dev->v4l2_dev, "%s not support\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&dev->cmsk_lock, lock_flags);
+	dev->is_cmsk_upd = true;
+	for (i = 0; i < RKISP_CMSK_WIN_MAX; i++) {
+		win_en |= cfg->win[i].win_en ? BIT(i) : 0;
+		mode |= cfg->win[i].mode ? BIT(i) : 0;
+
+		if (cfg->win[i].win_en) {
+			if (cfg->win[i].mode) {
+				dev->cmsk_cfg.win[i].cover_color_y = cfg->win[i].cover_color_y;
+				dev->cmsk_cfg.win[i].cover_color_u = cfg->win[i].cover_color_u;
+				dev->cmsk_cfg.win[i].cover_color_v = cfg->win[i].cover_color_v;
+			}
+			h_offs = cfg->win[i].h_offs & ~0x1;
+			v_offs = cfg->win[i].v_offs & ~0x1;
+			h_size = ALIGN_DOWN(cfg->win[i].h_size, align);
+			v_size = ALIGN_DOWN(cfg->win[i].v_size, align);
+			if (h_offs != cfg->win[i].h_offs ||
+			    v_offs != cfg->win[i].v_offs ||
+			    h_size != cfg->win[i].h_size ||
+			    v_size != cfg->win[i].v_size)
+				warn = true;
+			if (h_offs + h_size > width) {
+				h_size = ALIGN_DOWN(width - h_offs, align);
+				warn = true;
+			}
+			if (v_offs + v_size > height) {
+				v_size = ALIGN_DOWN(height - v_offs, align);
+				warn = true;
+			}
+			if (warn) {
+				warn = false;
+				v4l2_warn(&dev->v4l2_dev,
+					  "%s cmsk offs 2 align, size %d align and offs + size < resolution\n"
+					  "\t cmsk win%d result to offs:%d %d, size:%d %d\n",
+					  stream->vnode.vdev.name, i, align, h_offs, v_offs, h_size, v_size);
+			}
+			dev->cmsk_cfg.win[i].h_offs = h_offs;
+			dev->cmsk_cfg.win[i].v_offs = v_offs;
+			dev->cmsk_cfg.win[i].h_size = h_size;
+			dev->cmsk_cfg.win[i].v_size = v_size;
+		}
+	}
+
+	switch (stream->id) {
+	case RKISP_STREAM_MP:
+		dev->cmsk_cfg.win[0].win_en = win_en;
+		dev->cmsk_cfg.win[0].mode = mode;
+		break;
+	case RKISP_STREAM_SP:
+		dev->cmsk_cfg.win[1].win_en = win_en;
+		dev->cmsk_cfg.win[1].mode = mode;
+		break;
+	case RKISP_STREAM_BP:
+	default:
+		dev->cmsk_cfg.win[2].win_en = win_en;
+		dev->cmsk_cfg.win[2].mode = mode;
+		break;
+	}
+	dev->cmsk_cfg.mosaic_block = cfg->mosaic_block;
+	spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags);
+	return 0;
+
+}
+
+static int rkisp_get_stream_info(struct rkisp_stream *stream,
+				 struct rkisp_stream_info *info)
+{
+	struct rkisp_device *dev = stream->ispdev;
+	u32 id = 0;
+
+	rkisp_dmarx_get_frame(stream->ispdev, &id, NULL, NULL, true);
+	info->cur_frame_id = stream->dbg.id;
+	info->input_frame_loss = dev->isp_sdev.dbg.frameloss;
+	info->output_frame_loss = stream->dbg.frameloss;
+	info->stream_on = stream->streaming;
+	info->stream_id = stream->id;
+	return 0;
+}
+
+static int rkisp_get_mirror_flip(struct rkisp_stream *stream,
+				 struct rkisp_mirror_flip *cfg)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (dev->isp_ver != ISP_V32)
+		return -EINVAL;
+
+	cfg->mirror = dev->cap_dev.is_mirror;
+	cfg->flip = stream->is_flip;
+	return 0;
+}
+
+static int rkisp_set_mirror_flip(struct rkisp_stream *stream,
+				 struct rkisp_mirror_flip *cfg)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (dev->isp_ver != ISP_V32)
+		return -EINVAL;
+
+	if (dev->cap_dev.wrap_line) {
+		v4l2_warn(&dev->v4l2_dev, "wrap_line mode can not set the mirror");
+		dev->cap_dev.is_mirror = 0;
+	} else {
+		dev->cap_dev.is_mirror = cfg->mirror;
+	}
+
+	stream->is_flip = cfg->flip;
+	stream->is_mf_upd = true;
+	return 0;
+}
+
+static int rkisp_get_wrap_line(struct rkisp_stream *stream, struct rkisp_wrap_info *arg)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (dev->isp_ver != ISP_V32 && stream->id != RKISP_STREAM_MP)
+		return -EINVAL;
+
+	arg->width = dev->cap_dev.wrap_width;
+	arg->height = dev->cap_dev.wrap_line;
+	return 0;
+}
+
+static int rkisp_set_wrap_line(struct rkisp_stream *stream, struct rkisp_wrap_info *arg)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (dev->isp_ver != ISP_V32 ||
+	    dev->hw_dev->dev_link_num > 1 ||
+	    !stream->ops->set_wrap ||
+	    dev->hw_dev->unite) {
+		v4l2_err(&dev->v4l2_dev,
+			 "wrap only support for single sensor and mainpath\n");
+		return -EINVAL;
+	}
+	dev->cap_dev.wrap_width = arg->width;
+	return stream->ops->set_wrap(stream, arg->height);
+}
+
+static int rkisp_set_fps(struct rkisp_stream *stream, int *fps)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (dev->isp_ver != ISP_V32)
+		return -EINVAL;
+
+	return rkisp_rockit_fps_set(fps, stream);
+}
+
+static int rkisp_get_fps(struct rkisp_stream *stream, int *fps)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (dev->isp_ver != ISP_V32)
+		return -EINVAL;
+
+	return rkisp_rockit_fps_get(fps, stream);
+}
+
+int rkisp_get_tb_stream_info(struct rkisp_stream *stream,
+			     struct rkisp_tb_stream_info *info)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (stream->id != RKISP_STREAM_MP) {
+		v4l2_err(&dev->v4l2_dev, "fast only support for MP\n");
+		return -EINVAL;
+	}
+
+	if (!dev->tb_stream_info.buf_max) {
+		v4l2_err(&dev->v4l2_dev, "thunderboot no enough memory for image\n");
+		return -EINVAL;
+	}
+
+	memcpy(info, &dev->tb_stream_info, sizeof(*info));
+	return 0;
+}
+
+int rkisp_free_tb_stream_buf(struct rkisp_stream *stream)
+{
+	struct rkisp_device *dev = stream->ispdev;
+	struct rkisp_isp_subdev *sdev = &dev->isp_sdev;
+	struct v4l2_subdev *sd = &sdev->sd;
+
+	return sd->ops->core->ioctl(sd, RKISP_CMD_FREE_SHARED_BUF, NULL);
+}
+
+static int rkisp_set_iqtool_connect_id(struct rkisp_stream *stream, int stream_id)
+{
+	struct rkisp_device *dev = stream->ispdev;
+
+	if (stream->id != RKISP_STREAM_VIR) {
+		v4l2_err(&dev->v4l2_dev, "only support for iqtool video\n");
+		goto err;
+	}
+
+	if (stream_id != RKISP_STREAM_MP &&
+	    stream_id != RKISP_STREAM_SP &&
+	    stream_id != RKISP_STREAM_BP) {
+		v4l2_err(&dev->v4l2_dev, "invalid connect stream id\n");
+		goto err;
+	}
+
+	stream->conn_id = stream_id;
+	return 0;
+err:
+	return -EINVAL;
 }
 
 static long rkisp_ioctl_default(struct file *file, void *fh,
@@ -1154,7 +1226,7 @@
 	struct rkisp_stream *stream = video_drvdata(file);
 	long ret = 0;
 
-	if (!arg)
+	if (!arg && cmd != RKISP_CMD_FREE_TB_STREAM_BUF)
 		return -EINVAL;
 
 	switch (cmd) {
@@ -1184,6 +1256,42 @@
 		else
 			stream->memory =
 				SW_CSI_RWA_WR_SIMG_SWP | SW_CSI_RAW_WR_SIMG_MODE;
+		break;
+	case RKISP_CMD_GET_CMSK:
+		ret = rkisp_get_cmsk(stream, arg);
+		break;
+	case RKISP_CMD_SET_CMSK:
+		ret = rkisp_set_cmsk(stream, arg);
+		break;
+	case RKISP_CMD_GET_STREAM_INFO:
+		ret = rkisp_get_stream_info(stream, arg);
+		break;
+	case RKISP_CMD_GET_MIRROR_FLIP:
+		ret = rkisp_get_mirror_flip(stream, arg);
+		break;
+	case RKISP_CMD_SET_MIRROR_FLIP:
+		ret = rkisp_set_mirror_flip(stream, arg);
+		break;
+	case RKISP_CMD_GET_WRAP_LINE:
+		ret = rkisp_get_wrap_line(stream, arg);
+		break;
+	case RKISP_CMD_SET_WRAP_LINE:
+		ret = rkisp_set_wrap_line(stream, arg);
+		break;
+	case RKISP_CMD_SET_FPS:
+		ret = rkisp_set_fps(stream, arg);
+		break;
+	case RKISP_CMD_GET_FPS:
+		ret = rkisp_get_fps(stream, arg);
+		break;
+	case RKISP_CMD_GET_TB_STREAM_INFO:
+		ret = rkisp_get_tb_stream_info(stream, arg);
+		break;
+	case RKISP_CMD_FREE_TB_STREAM_BUF:
+		ret = rkisp_free_tb_stream_buf(stream);
+		break;
+	case RKISP_CMD_SET_IQTOOL_CONN_ID:
+		ret = rkisp_set_iqtool_connect_id(stream, *(int *)arg);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1235,12 +1343,67 @@
 {
 	struct rkisp_stream *stream = video_drvdata(file);
 	const struct capture_fmt *fmt = NULL;
+	struct rkisp_device *dev = stream->ispdev;
+	struct ispsd_in_fmt *isp_in_fmt = &dev->isp_sdev.in_fmt;
+	struct ispsd_out_fmt *isp_out_fmt = &dev->isp_sdev.out_fmt;
+	int ret = -EINVAL;
+
+	/* only one output format for raw */
+	if (isp_out_fmt->fmt_type == FMT_BAYER ||
+	    stream->id == RKISP_STREAM_DMATX0 ||
+	    stream->id == RKISP_STREAM_DMATX1 ||
+	    stream->id == RKISP_STREAM_DMATX2 ||
+	    stream->id == RKISP_STREAM_DMATX3) {
+		u32 pixelformat = rkisp_mbus_pixelcode_to_v4l2(isp_in_fmt->mbus_code);
+
+		if (f->index == 0) {
+			fmt = find_fmt(stream, pixelformat);
+			if (fmt) {
+				f->pixelformat = pixelformat;
+				ret = 0;
+			}
+		}
+		return ret;
+	}
 
 	if (f->index >= stream->config->fmt_size)
 		return -EINVAL;
 
 	fmt = &stream->config->fmts[f->index];
+	/* only output yuv format */
+	if (isp_out_fmt->fmt_type == FMT_YUV && fmt->fmt_type == FMT_BAYER)
+		return -EINVAL;
+
 	f->pixelformat = fmt->fourcc;
+	switch (f->pixelformat) {
+	case V4L2_PIX_FMT_FBC2:
+		strscpy(f->description,
+			"Rockchip yuv422sp fbc encoder",
+			sizeof(f->description));
+		break;
+	case V4L2_PIX_FMT_FBC0:
+		strscpy(f->description,
+			"Rockchip yuv420sp fbc encoder",
+			sizeof(f->description));
+		break;
+	case V4L2_PIX_FMT_FBCG:
+		strscpy(f->description,
+			"Rockchip fbc gain",
+			sizeof(f->description));
+		break;
+	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;
 }
@@ -1302,13 +1465,19 @@
 					    struct v4l2_rect *sel,
 					    const struct v4l2_rect *in)
 {
+	struct rkisp_device *dev = stream->ispdev;
+	bool is_unite = !!dev->hw_dev->unite;
+	u32 align = is_unite ? 4 : 2;
+
 	/* Not crop for MP bayer raw data and dmatx path */
 	if ((stream->id == RKISP_STREAM_MP &&
 	     stream->out_isp_fmt.fmt_type == FMT_BAYER) ||
 	    stream->id == RKISP_STREAM_DMATX0 ||
 	    stream->id == RKISP_STREAM_DMATX1 ||
 	    stream->id == RKISP_STREAM_DMATX2 ||
-	    stream->id == RKISP_STREAM_DMATX3) {
+	    stream->id == RKISP_STREAM_DMATX3 ||
+	    stream->id == RKISP_STREAM_MPDS ||
+	    stream->id == RKISP_STREAM_BPDS) {
 		sel->left = 0;
 		sel->top = 0;
 		sel->width = in->width;
@@ -1317,7 +1486,7 @@
 	}
 
 	sel->left = ALIGN(sel->left, 2);
-	sel->width = ALIGN(sel->width, 2);
+	sel->width = ALIGN(sel->width, align);
 	sel->left = clamp_t(u32, sel->left, 0,
 			    in->width - STREAM_MIN_MP_SP_INPUT_WIDTH);
 	sel->top = clamp_t(u32, sel->top, 0,
@@ -1326,6 +1495,13 @@
 			     in->width - sel->left);
 	sel->height = clamp_t(u32, sel->height, STREAM_MIN_MP_SP_INPUT_HEIGHT,
 			      in->height - sel->top);
+	if (is_unite && (sel->width + 2 * sel->left) != in->width) {
+		sel->left = ALIGN_DOWN((in->width - sel->width) / 2, 2);
+		v4l2_warn(&dev->v4l2_dev,
+			  "try horizontal center crop(%d,%d)/%dx%d for dual isp\n",
+			  sel->left, sel->top, sel->width, sel->height);
+	}
+	stream->is_crop_upd = true;
 	return sel;
 }
 
@@ -1333,18 +1509,9 @@
 			      struct v4l2_selection *sel)
 {
 	struct rkisp_stream *stream = video_drvdata(file);
-	struct video_device *vdev = &stream->vnode.vdev;
-	struct rkisp_vdev_node *node = vdev_to_node(vdev);
 	struct rkisp_device *dev = stream->ispdev;
 	struct v4l2_rect *dcrop = &stream->dcrop;
 	const struct v4l2_rect *input_win;
-
-	if (vb2_is_busy(&node->buf_queue)) {
-		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
-		return -EBUSY;
-	}
-
-	input_win = rkisp_get_isp_sd_win(&dev->isp_sdev);
 
 	if (sel->target != V4L2_SEL_TGT_CROP)
 		return -EINVAL;
@@ -1352,6 +1519,7 @@
 	if (sel->flags != 0)
 		return -EINVAL;
 
+	input_win = rkisp_get_isp_sd_win(&dev->isp_sdev);
 	*dcrop = *rkisp_update_crop(stream, &sel->r, input_win);
 	v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
 		 "stream %d crop(%d,%d)/%dx%d\n", stream->id,
@@ -1389,7 +1557,7 @@
 	.vidioc_streamoff = vb2_ioctl_streamoff,
 	.vidioc_enum_input = rkisp_enum_input,
 	.vidioc_try_fmt_vid_cap_mplane = rkisp_try_fmt_vid_cap_mplane,
-	.vidioc_enum_fmt_vid_cap_mplane = rkisp_enum_fmt_vid_cap_mplane,
+	.vidioc_enum_fmt_vid_cap = rkisp_enum_fmt_vid_cap_mplane,
 	.vidioc_s_fmt_vid_cap_mplane = rkisp_s_fmt_vid_cap_mplane,
 	.vidioc_g_fmt_vid_cap_mplane = rkisp_g_fmt_vid_cap_mplane,
 	.vidioc_s_selection = rkisp_s_selection,
@@ -1400,8 +1568,78 @@
 	.vidioc_default = rkisp_ioctl_default,
 };
 
+static void rkisp_buf_done_task(unsigned long arg)
+{
+	struct rkisp_stream *stream = (struct rkisp_stream *)arg;
+	struct rkisp_buffer *buf = NULL;
+	unsigned long lock_flags = 0;
+	LIST_HEAD(local_list);
+
+	spin_lock_irqsave(&stream->vbq_lock, lock_flags);
+	list_replace_init(&stream->buf_done_list, &local_list);
+	spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
+
+	while (!list_empty(&local_list)) {
+		buf = list_first_entry(&local_list,
+				       struct rkisp_buffer, queue);
+		list_del(&buf->queue);
+
+		v4l2_dbg(2, rkisp_debug, &stream->ispdev->v4l2_dev,
+			 "stream:%d seq:%d buf:0x%x done\n",
+			 stream->id, buf->vb.sequence, buf->buff_addr[0]);
+		vb2_buffer_done(&buf->vb.vb2_buf,
+				stream->streaming ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR);
+	}
+}
+
+void rkisp_stream_buf_done(struct rkisp_stream *stream,
+			   struct rkisp_buffer *buf)
+{
+	unsigned long lock_flags = 0;
+
+	if (!stream || !buf)
+		return;
+	spin_lock_irqsave(&stream->vbq_lock, lock_flags);
+	list_add_tail(&buf->queue, &stream->buf_done_list);
+	spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
+	tasklet_schedule(&stream->buf_done_tasklet);
+}
+
+static void rkisp_stream_fast(struct work_struct *work)
+{
+	struct rkisp_capture_device *cap_dev =
+		container_of(work, struct rkisp_capture_device, fast_work);
+	struct rkisp_stream *stream = &cap_dev->stream[0];
+	struct rkisp_device *ispdev = cap_dev->ispdev;
+	struct v4l2_subdev *sd = ispdev->active_sensor->sd;
+	int ret;
+
+	if (ispdev->isp_ver != ISP_V32)
+		return;
+
+	mutex_lock(&ispdev->hw_dev->dev_lock);
+	rkisp_chk_tb_over(ispdev);
+	mutex_unlock(&ispdev->hw_dev->dev_lock);
+	if (ispdev->tb_head.complete != RKISP_TB_OK)
+		return;
+	ret = v4l2_pipeline_pm_get(&stream->vnode.vdev.entity);
+	if (ret < 0) {
+		dev_err(ispdev->dev, "%s PM get fail:%d\n", __func__, ret);
+		ispdev->is_thunderboot = false;
+		return;
+	}
+
+	if (ispdev->hw_dev->dev_num > 1)
+		ispdev->hw_dev->is_single = false;
+	ispdev->is_pre_on = true;
+	ispdev->is_rdbk_auto = true;
+	ispdev->pipe.open(&ispdev->pipe, &stream->vnode.vdev.entity, true);
+	v4l2_subdev_call(sd, video, s_stream, true);
+}
+
 void rkisp_unregister_stream_vdev(struct rkisp_stream *stream)
 {
+	tasklet_kill(&stream->buf_done_tasklet);
 	media_entity_cleanup(&stream->vnode.vdev.entity);
 	video_unregister_device(&stream->vnode.vdev);
 }
@@ -1431,7 +1669,7 @@
 	node->pad.flags = MEDIA_PAD_FL_SINK;
 	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);
@@ -1461,6 +1699,11 @@
 		sink, 0, stream->linked);
 	if (ret < 0)
 		goto unreg;
+	INIT_LIST_HEAD(&stream->buf_done_list);
+	tasklet_init(&stream->buf_done_tasklet,
+		     rkisp_buf_done_task,
+		     (unsigned long)stream);
+	tasklet_disable(&stream->buf_done_tasklet);
 	return 0;
 unreg:
 	video_unregister_device(vdev);
@@ -1470,18 +1713,55 @@
 int rkisp_register_stream_vdevs(struct rkisp_device *dev)
 {
 	struct rkisp_capture_device *cap_dev = &dev->cap_dev;
+	struct stream_config *st_cfg = &rkisp_mp_stream_config;
 	int ret = 0;
 
 	memset(cap_dev, 0, sizeof(*cap_dev));
 	cap_dev->ispdev = dev;
 	atomic_set(&cap_dev->refcnt, 0);
 
-	if (dev->isp_ver <= ISP_V13)
+	if (dev->isp_ver <= ISP_V13) {
+		if (dev->isp_ver == ISP_V12) {
+			st_cfg->max_rsz_width = CIF_ISP_INPUT_W_MAX_V12;
+			st_cfg->max_rsz_height = CIF_ISP_INPUT_H_MAX_V12;
+		} else if (dev->isp_ver == ISP_V13) {
+			st_cfg->max_rsz_width = CIF_ISP_INPUT_W_MAX_V13;
+			st_cfg->max_rsz_height = CIF_ISP_INPUT_H_MAX_V13;
+		}
 		ret = rkisp_register_stream_v1x(dev);
-	else if (dev->isp_ver == ISP_V20)
+	} else if (dev->isp_ver == ISP_V20) {
 		ret = rkisp_register_stream_v20(dev);
-	else if (dev->isp_ver == ISP_V21)
+	} else if (dev->isp_ver == ISP_V21) {
+		st_cfg->max_rsz_width = CIF_ISP_INPUT_W_MAX_V21;
+		st_cfg->max_rsz_height = CIF_ISP_INPUT_H_MAX_V21;
 		ret = rkisp_register_stream_v21(dev);
+	} else if (dev->isp_ver == ISP_V30) {
+		st_cfg->max_rsz_width = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_W_MAX_V30_UNITE : CIF_ISP_INPUT_W_MAX_V30;
+		st_cfg->max_rsz_height = dev->hw_dev->unite ?
+					 CIF_ISP_INPUT_H_MAX_V30_UNITE : CIF_ISP_INPUT_H_MAX_V30;
+		ret = rkisp_register_stream_v30(dev);
+	} else if (dev->isp_ver == ISP_V32) {
+		st_cfg->max_rsz_width = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_W_MAX_V32_UNITE : CIF_ISP_INPUT_W_MAX_V32;
+		st_cfg->max_rsz_height = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_H_MAX_V32_UNITE : CIF_ISP_INPUT_H_MAX_V32;
+		st_cfg = &rkisp_sp_stream_config;
+		st_cfg->max_rsz_width = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_W_MAX_V32_UNITE : CIF_ISP_INPUT_W_MAX_V32;
+		st_cfg->max_rsz_height = dev->hw_dev->unite ?
+					 CIF_ISP_INPUT_H_MAX_V32_UNITE : CIF_ISP_INPUT_H_MAX_V32;
+		ret = rkisp_register_stream_v32(dev);
+	} else if (dev->isp_ver == ISP_V32_L) {
+		st_cfg->max_rsz_width = CIF_ISP_INPUT_W_MAX_V32_L;
+		st_cfg->max_rsz_height = CIF_ISP_INPUT_H_MAX_V32_L;
+		st_cfg = &rkisp_sp_stream_config;
+		st_cfg->max_rsz_width = CIF_ISP_INPUT_W_MAX_V32_L;
+		st_cfg->max_rsz_height = CIF_ISP_INPUT_H_MAX_V32_L;
+		ret = rkisp_register_stream_v32(dev);
+	}
+
+	INIT_WORK(&cap_dev->fast_work, rkisp_stream_fast);
 	return ret;
 }
 
@@ -1493,6 +1773,10 @@
 		rkisp_unregister_stream_v20(dev);
 	else if (dev->isp_ver == ISP_V21)
 		rkisp_unregister_stream_v21(dev);
+	else if (dev->isp_ver == ISP_V30)
+		rkisp_unregister_stream_v30(dev);
+	else if (dev->isp_ver == ISP_V32 || dev->isp_ver == ISP_V32_L)
+		rkisp_unregister_stream_v32(dev);
 }
 
 void rkisp_mi_isr(u32 mis_val, struct rkisp_device *dev)
@@ -1503,4 +1787,8 @@
 		rkisp_mi_v20_isr(mis_val, dev);
 	else if (dev->isp_ver == ISP_V21)
 		rkisp_mi_v21_isr(mis_val, dev);
+	else if (dev->isp_ver == ISP_V30)
+		rkisp_mi_v30_isr(mis_val, dev);
+	else if (dev->isp_ver == ISP_V32 || dev->isp_ver == ISP_V32_L)
+		rkisp_mi_v32_isr(mis_val, dev);
 }

--
Gitblit v1.6.2