From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB

---
 kernel/drivers/media/platform/rockchip/isp/rkisp.c | 2021 +++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 1,612 insertions(+), 409 deletions(-)

diff --git a/kernel/drivers/media/platform/rockchip/isp/rkisp.c b/kernel/drivers/media/platform/rockchip/isp/rkisp.c
index f65e7e7..ac40adf 100644
--- a/kernel/drivers/media/platform/rockchip/isp/rkisp.c
+++ b/kernel/drivers/media/platform/rockchip/isp/rkisp.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/compat.h>
 #include <linux/iopoll.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
@@ -42,12 +43,13 @@
 #include <linux/kfifo.h>
 #include <linux/interrupt.h>
 #include <linux/rk-preisp.h>
-#include <linux/rkisp21-config.h>
+#include <linux/rk-isp21-config.h>
 #include <linux/iommu.h>
 #include <media/v4l2-event.h>
 #include <media/media-entity.h>
 
 #include "common.h"
+#include "isp_external.h"
 #include "regs.h"
 #include "rkisp_tb_helper.h"
 
@@ -83,11 +85,7 @@
  * +---------------------------------------------------------+
  */
 
-struct backup_reg {
-	const u32 base;
-	const u32 shd;
-	u32 val;
-};
+static void rkisp_config_cmsk(struct rkisp_device *dev);
 
 static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd)
 {
@@ -188,41 +186,50 @@
 	u32 code = dev->isp_sdev.in_frm.code;
 	u32 src_w = dev->isp_sdev.in_frm.width;
 	u32 src_h = dev->isp_sdev.in_frm.height;
-	u32 dest_w, dest_h, w, h;
+	u32 dest_w, dest_h, w, h, max_size, max_h, max_w;
 	int ret = 0;
 
 	if (!crop)
 		return -EINVAL;
 
-	if (dev->isp_ver == ISP_V12) {
-		w = clamp_t(u32, src_w,
-			    CIF_ISP_INPUT_W_MIN,
-			    CIF_ISP_INPUT_W_MAX_V12);
-		h = clamp_t(u32, src_h,
-			    CIF_ISP_INPUT_H_MIN,
-			    CIF_ISP_INPUT_H_MAX_V12);
-	} else if (dev->isp_ver == ISP_V13) {
-		w = clamp_t(u32, src_w,
-			    CIF_ISP_INPUT_W_MIN,
-			    CIF_ISP_INPUT_W_MAX_V13);
-		h = clamp_t(u32, src_h,
-			    CIF_ISP_INPUT_H_MIN,
-			    CIF_ISP_INPUT_H_MAX_V13);
-	} else if (dev->isp_ver == ISP_V21) {
-		w = clamp_t(u32, src_w,
-			    CIF_ISP_INPUT_W_MIN,
-			    CIF_ISP_INPUT_W_MAX_V21);
-		h = clamp_t(u32, src_h,
-			    CIF_ISP_INPUT_H_MIN,
-			    CIF_ISP_INPUT_H_MAX_V21);
-	} else {
-		w  = clamp_t(u32, src_w,
-			     CIF_ISP_INPUT_W_MIN,
-			     CIF_ISP_INPUT_W_MAX);
-		h = clamp_t(u32, src_h,
-			    CIF_ISP_INPUT_H_MIN,
-			    CIF_ISP_INPUT_H_MAX);
+	memset(&sel, 0, sizeof(sel));
+	switch (dev->isp_ver) {
+	case ISP_V12:
+		max_w = CIF_ISP_INPUT_W_MAX_V12;
+		max_h = CIF_ISP_INPUT_H_MAX_V12;
+		break;
+	case ISP_V13:
+		max_w = CIF_ISP_INPUT_W_MAX_V13;
+		max_h = CIF_ISP_INPUT_H_MAX_V13;
+		break;
+	case ISP_V21:
+		max_w = CIF_ISP_INPUT_W_MAX_V21;
+		max_h = CIF_ISP_INPUT_H_MAX_V21;
+		break;
+	case ISP_V30:
+		max_w = dev->hw_dev->unite ?
+			CIF_ISP_INPUT_W_MAX_V30_UNITE : CIF_ISP_INPUT_W_MAX_V30;
+		max_h = dev->hw_dev->unite ?
+			CIF_ISP_INPUT_H_MAX_V30_UNITE : CIF_ISP_INPUT_H_MAX_V30;
+		break;
+	case ISP_V32:
+		max_w = dev->hw_dev->unite ?
+			CIF_ISP_INPUT_W_MAX_V32_UNITE : CIF_ISP_INPUT_W_MAX_V32;
+		max_h = dev->hw_dev->unite ?
+			CIF_ISP_INPUT_H_MAX_V32_UNITE : CIF_ISP_INPUT_H_MAX_V32;
+		break;
+	case ISP_V32_L:
+		max_w = CIF_ISP_INPUT_W_MAX_V32_L;
+		max_h = CIF_ISP_INPUT_H_MAX_V32_L;
+		break;
+	default:
+		max_w = CIF_ISP_INPUT_W_MAX;
+		max_h = CIF_ISP_INPUT_H_MAX;
 	}
+	max_size = max_w * max_h;
+	w = clamp_t(u32, src_w, CIF_ISP_INPUT_W_MIN, max_w);
+	max_h = max_size / w;
+	h = clamp_t(u32, src_h, CIF_ISP_INPUT_H_MIN, max_h);
 
 	if (dev->active_sensor)
 		sensor = dev->active_sensor->sd;
@@ -343,35 +350,51 @@
 		return -ENODEV;
 
 	sensor = sd_to_sensor(dev, sensor_sd);
-	ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config,
-			       &sensor->mbus);
+	if (!sensor)
+		return -ENODEV;
+	ret = v4l2_subdev_call(sensor->sd, pad, get_mbus_config,
+			       0, &sensor->mbus);
 	if (ret && ret != -ENOIOCTLCMD)
 		return ret;
 
-	if (sensor->mbus.type == V4L2_MBUS_CSI2) {
+	sensor->fmt[0].pad = 0;
+	sensor->fmt[0].which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(sensor->sd, pad, get_fmt,
+			       &sensor->cfg, &sensor->fmt[0]);
+	if (ret && ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY &&
+	    dev->isp_ver < ISP_V30) {
 		u8 vc = 0;
 
-		memset(dev->csi_dev.mipi_di, 0,
-		       sizeof(dev->csi_dev.mipi_di));
-		memset(sensor->fmt, 0, sizeof(sensor->fmt));
+		sensor_sd = get_remote_sensor(sensor->sd);
+		if (!sensor_sd)
+			return -ENODEV;
+		memset(dev->csi_dev.mipi_di, 0, sizeof(dev->csi_dev.mipi_di));
 		for (i = 0; i < dev->csi_dev.max_pad - 1; i++) {
+			struct rkmodule_channel_info ch = { 0 };
+
 			fmt = &sensor->fmt[i];
-			fmt->pad = i;
-			fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
-			ret = v4l2_subdev_call(sensor->sd, pad, get_fmt,
-					       &sensor->cfg, fmt);
-			if (ret && ret != -ENOIOCTLCMD)
-				return ret;
+			ch.index = i;
+			ret = v4l2_subdev_call(sensor_sd, core, ioctl,
+					       RKMODULE_GET_CHANNEL_INFO, &ch);
+			if (ret) {
+				if (i)
+					*fmt = sensor->fmt[0];
+			} else {
+				fmt->format.width = ch.width;
+				fmt->format.height = ch.height;
+				fmt->format.code = ch.bus_fmt;
+			}
 			ret = mbus_pixelcode_to_mipi_dt(fmt->format.code);
 			if (ret < 0) {
 				v4l2_err(&dev->v4l2_dev,
 					 "Invalid mipi data type\n");
 				return ret;
 			}
-			/* v4l2_subdev_format reserved[0]
-			 * using as mipi virtual channel
-			 */
-			switch (fmt->reserved[0]) {
+
+			switch (ch.vc) {
 			case V4L2_MBUS_CSI2_CHANNEL_3:
 				vc = 3;
 				break;
@@ -393,18 +416,14 @@
 				  fmt->format.width,
 				  fmt->format.height);
 		}
-	} else {
-		sensor->fmt[0].pad = 0;
-		sensor->fmt[0].which = V4L2_SUBDEV_FORMAT_ACTIVE;
-		ret = v4l2_subdev_call(sensor->sd, pad, get_fmt,
-				       &sensor->cfg, &sensor->fmt[0]);
-		if (ret && ret != -ENOIOCTLCMD)
-			return ret;
 	}
 
 	v4l2_subdev_call(sensor->sd, video, g_frame_interval, &sensor->fi);
 	dev->active_sensor = sensor;
-
+	i = dev->dev_id;
+	if (sensor->fi.interval.numerator)
+		dev->hw_dev->isp_size[i].fps =
+			sensor->fi.interval.denominator / sensor->fi.interval.numerator;
 	return ret;
 }
 
@@ -471,6 +490,86 @@
 	return pixelformat;
 }
 
+static void rkisp_dvfs(struct rkisp_device *dev)
+{
+	struct rkisp_hw_dev *hw = dev->hw_dev;
+	u64 data_rate = 0;
+	int i, fps, num = 0;
+
+	if (!hw->is_dvfs)
+		return;
+	hw->is_dvfs = false;
+	for (i = 0; i < hw->dev_num; i++) {
+		if (!hw->isp_size[i].is_on)
+			continue;
+		fps = hw->isp_size[i].fps;
+		if (!fps)
+			fps = 30;
+		data_rate += (fps * hw->isp_size[i].size);
+		num++;
+	}
+	do_div(data_rate, 1000 * 1000);
+	/* increase margin: 25% * num */
+	data_rate += (data_rate >> 2) * num;
+	/* one frame two-run, data double */
+	if (hw->is_multi_overflow && num > 1)
+		data_rate *= 2;
+	/* compare with isp clock adjustment table */
+	for (i = 0; i < hw->num_clk_rate_tbl; i++)
+		if (data_rate <= hw->clk_rate_tbl[i].clk_rate)
+			break;
+	if (i == hw->num_clk_rate_tbl)
+		i--;
+
+	/* set isp clock rate */
+	rkisp_set_clk_rate(hw->clks[0], hw->clk_rate_tbl[i].clk_rate * 1000000UL);
+	if (hw->unite == ISP_UNITE_TWO)
+		rkisp_set_clk_rate(hw->clks[5], hw->clk_rate_tbl[i].clk_rate * 1000000UL);
+	/* aclk equal to core clk */
+	if (dev->isp_ver == ISP_V32)
+		rkisp_set_clk_rate(hw->clks[1], hw->clk_rate_tbl[i].clk_rate * 1000000UL);
+	dev_info(hw->dev, "set isp clk = %luHz\n", clk_get_rate(hw->clks[0]));
+}
+
+static void rkisp_multi_overflow_hdl(struct rkisp_device *dev, bool on)
+{
+	struct rkisp_hw_dev *hw = dev->hw_dev;
+
+	if (on) {
+		/* enable mi */
+		rkisp_update_regs(dev, ISP3X_MI_WR_CTRL, ISP3X_MI_WR_CTRL);
+		rkisp_update_regs(dev, ISP3X_ISP_CTRL1, ISP3X_ISP_CTRL1);
+		if (dev->isp_ver == ISP_V30) {
+			rkisp_update_regs(dev, ISP3X_MPFBC_CTRL, ISP3X_MPFBC_CTRL);
+			rkisp_update_regs(dev, ISP3X_MI_BP_WR_CTRL, ISP3X_MI_BP_WR_CTRL);
+			rkisp_update_regs(dev, ISP3X_SWS_CFG, ISP3X_SWS_CFG);
+		} else if (dev->isp_ver == ISP_V32) {
+			rkisp_update_regs(dev, ISP3X_MI_BP_WR_CTRL, ISP3X_MI_BP_WR_CTRL);
+			rkisp_update_regs(dev, ISP32_MI_BPDS_WR_CTRL, ISP32_MI_BPDS_WR_CTRL);
+			rkisp_update_regs(dev, ISP32_MI_MPDS_WR_CTRL, ISP32_MI_MPDS_WR_CTRL);
+		}
+	} else {
+		/* disabled mi. rv1106 sdmmc workaround, 3a_wr no close */
+		writel(CIF_MI_CTRL_INIT_OFFSET_EN | CIF_MI_CTRL_INIT_BASE_EN,
+		       hw->base_addr + ISP3X_MI_WR_CTRL);
+		if (dev->isp_ver == ISP_V30) {
+			writel(0, hw->base_addr + ISP3X_MPFBC_CTRL);
+			writel(0, hw->base_addr + ISP3X_MI_BP_WR_CTRL);
+			writel(0xc, hw->base_addr + ISP3X_SWS_CFG);
+			if (hw->unite == ISP_UNITE_TWO) {
+				writel(0, hw->base_next_addr + ISP3X_MI_WR_CTRL);
+				writel(0, hw->base_next_addr + ISP3X_MPFBC_CTRL);
+				writel(0, hw->base_next_addr + ISP3X_MI_BP_WR_CTRL);
+				writel(0xc, hw->base_next_addr + ISP3X_SWS_CFG);
+			}
+		} else if (dev->isp_ver == ISP_V32) {
+			writel(0, hw->base_addr + ISP3X_MI_BP_WR_CTRL);
+			writel(0, hw->base_addr + ISP32_MI_BPDS_WR_CTRL);
+			writel(0, hw->base_addr + ISP32_MI_MPDS_WR_CTRL);
+		}
+	}
+	rkisp_unite_write(dev, ISP3X_MI_WR_INIT, CIF_MI_INIT_SOFT_UPD, true);
+}
 
 /*
  * for hdr read back mode, rawrd read back data
@@ -479,6 +578,7 @@
 void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, bool is_try)
 {
 	struct rkisp_isp_params_vdev *params_vdev = &dev->params_vdev;
+	struct rkisp_isp_stats_vdev *stats_vdev = &dev->stats_vdev;
 	struct rkisp_hw_dev *hw = dev->hw_dev;
 	u32 val, cur_frame_id, tmp, rd_mode;
 	u64 iq_feature = hw->iq_feature;
@@ -488,8 +588,12 @@
 	hw->cur_dev_id = dev->dev_id;
 	rkisp_dmarx_get_frame(dev, &cur_frame_id, NULL, NULL, true);
 
+	/* isp process the same frame */
+	if (is_try)
+		goto run_next;
+
 	val = 0;
-	if (mode & T_START_X1) {
+	if (mode & (T_START_X1 | T_START_C)) {
 		rd_mode = HDR_RDBK_FRAME1;
 	} else if (mode & T_START_X2) {
 		rd_mode = HDR_RDBK_FRAME2;
@@ -502,6 +606,11 @@
 		val = rkisp_read(dev, ISP_HDRMGE_BASE, false) & 0xf;
 	}
 
+	if (mode & T_START_C)
+		rkisp_expander_config(dev, NULL, true);
+	else
+		rkisp_expander_config(dev, NULL, false);
+
 	if (is_feature_on) {
 		if ((ISP2X_MODULE_HDRMGE & ~iq_feature) && (val & SW_HDRMGE_EN)) {
 			v4l2_err(&dev->v4l2_dev, "hdrmge is not supported\n");
@@ -509,24 +618,22 @@
 		}
 	}
 
-	tmp = rkisp_read(dev, ISP_HDRMGE_BASE, false) & 0xf;
-	if (val != tmp) {
-		rkisp_write(dev, ISP_HDRMGE_BASE, val, false);
+	if (rd_mode != dev->rd_mode) {
+		rkisp_unite_set_bits(dev, ISP_HDRMGE_BASE, ISP_HDRMGE_MODE_MASK, val, false);
 		dev->skip_frame = 2;
 		is_upd = true;
 	}
 
-	if (dev->isp_ver == ISP_V20 && dev->dmarx_dev.trigger == T_MANUAL && !is_try) {
-		if (dev->rd_mode != rd_mode && RKMODULE_EXTEND_LINE != 0) {
+	if (dev->isp_ver == ISP_V20 && dev->dmarx_dev.trigger == T_MANUAL) {
+		if (dev->rd_mode != rd_mode && dev->br_dev.en) {
 			tmp = dev->isp_sdev.in_crop.height;
 			val = rkisp_read(dev, CIF_DUAL_CROP_CTRL, false);
 			if (rd_mode == HDR_RDBK_FRAME1) {
-				val |= CIF_DUAL_CROP_MP_MODE_YUV | CIF_DUAL_CROP_SP_MODE_YUV;
+				val |= CIF_DUAL_CROP_MP_MODE_YUV;
 				tmp += RKMODULE_EXTEND_LINE;
 			} else {
-				val &= ~(CIF_DUAL_CROP_MP_MODE_YUV | CIF_DUAL_CROP_SP_MODE_YUV);
+				val &= ~CIF_DUAL_CROP_MP_MODE_YUV;
 			}
-			val |= CIF_DUAL_CROP_CFG_UPD;
 			rkisp_write(dev, CIF_DUAL_CROP_CTRL, val, false);
 			rkisp_write(dev, CIF_ISP_ACQ_V_SIZE, tmp, false);
 			rkisp_write(dev, CIF_ISP_OUT_V_SIZE, tmp, false);
@@ -538,19 +645,38 @@
 	}
 	dev->rd_mode = rd_mode;
 
-	rkisp_params_first_cfg(&dev->params_vdev, &dev->isp_sdev.in_fmt,
-			       dev->isp_sdev.quantization);
-	rkisp_params_cfg(params_vdev, cur_frame_id);
+	if (hw->unite != ISP_UNITE_ONE || dev->unite_index == ISP_UNITE_LEFT) {
+		rkisp_params_first_cfg(&dev->params_vdev, &dev->isp_sdev.in_fmt,
+				       dev->isp_sdev.quantization);
+		rkisp_params_cfg(params_vdev, cur_frame_id);
+		rkisp_config_cmsk(dev);
+		rkisp_stream_frame_start(dev, 0);
+	}
 
-	if (!hw->is_single && !is_try) {
+	if (!hw->is_single) {
+		/* multi sensor need to reset isp resize mode if scale up */
+		val = 0;
+		if (rkisp_read(dev, ISP3X_MAIN_RESIZE_CTRL, true) & 0xf0)
+			val |= BIT(3);
+		if (dev->isp_ver != ISP_V32_L &&
+		    rkisp_read(dev, ISP3X_SELF_RESIZE_CTRL, true) & 0xf0)
+			val |= BIT(4);
+		if (rkisp_read(dev, ISP32_BP_RESIZE_CTRL, true) & 0xf0)
+			val |= BIT(12);
+		if (val) {
+			writel(val, hw->base_addr + CIF_IRCL);
+			writel(0, hw->base_addr + CIF_IRCL);
+		}
+
 		rkisp_update_regs(dev, CTRL_VI_ISP_PATH, SUPER_IMP_COLOR_CR);
-		rkisp_update_regs(dev, DUAL_CROP_M_H_OFFS, DUAL_CROP_S_V_SIZE);
-		rkisp_update_regs(dev, ISP_ACQ_PROP, DUAL_CROP_CTRL);
-		rkisp_update_regs(dev, MAIN_RESIZE_SCALE_HY, MI_WR_CTRL);
-		rkisp_update_regs(dev, SELF_RESIZE_SCALE_HY, MAIN_RESIZE_CTRL);
-		rkisp_update_regs(dev, ISP_GAMMA_OUT_CTRL, SELF_RESIZE_CTRL);
+		rkisp_update_regs(dev, DUAL_CROP_M_H_OFFS, ISP3X_DUAL_CROP_FBC_V_SIZE);
+		rkisp_update_regs(dev, ISP_ACQ_H_OFFS, DUAL_CROP_CTRL);
+		rkisp_update_regs(dev, SELF_RESIZE_SCALE_HY, MI_WR_CTRL);
+		rkisp_update_regs(dev, ISP32_BP_RESIZE_SCALE_HY, SELF_RESIZE_CTRL);
+		rkisp_update_regs(dev, MAIN_RESIZE_SCALE_HY, ISP32_BP_RESIZE_CTRL);
+		rkisp_update_regs(dev, ISP_GAMMA_OUT_CTRL, MAIN_RESIZE_CTRL);
 		rkisp_update_regs(dev, MI_RD_CTRL2, ISP_LSC_CTRL);
-		rkisp_update_regs(dev, MI_MP_WR_Y_BASE, MI_MP_WR_Y_LLENGTH);
+		rkisp_update_regs(dev, MI_MP_WR_Y_BASE, MI_WR_CTRL2 - 4);
 		rkisp_update_regs(dev, ISP_LSC_XGRAD_01, ISP_RAWAWB_RAM_DATA);
 		if (dev->isp_ver == ISP_V20 &&
 		    (rkisp_read(dev, ISP_DHAZ_CTRL, false) & ISP_DHAZ_ENMUX ||
@@ -560,53 +686,148 @@
 			val = rkisp_read(dev, MI_WR_CTRL2, false);
 			rkisp_set_bits(dev, MI_WR_CTRL2, 0, val, true);
 			rkisp_write(dev, MI_WR_INIT, ISP21_SP_FORCE_UPD | ISP21_MP_FORCE_UPD, true);
-			/* sensor mode & index */
+		} else {
+			if (dev->isp_ver == ISP_V32_L)
+				rkisp_write(dev, ISP32_SELF_SCALE_UPDATE, ISP32_SCALE_FORCE_UPD, true);
+			rkisp_unite_write(dev, ISP3X_MI_WR_INIT, CIF_MI_INIT_SOFT_UPD, true);
+		}
+		/* sensor mode & index */
+		if (dev->isp_ver >= ISP_V21) {
 			val = rkisp_read_reg_cache(dev, ISP_ACQ_H_OFFS);
-			val |= ISP21_SENSOR_MODE(hw->dev_num >= 3 ? 2 : hw->dev_num - 1) |
-			       ISP21_SENSOR_INDEX(dev->dev_id);
+			val |= ISP21_SENSOR_INDEX(dev->multi_index);
+			if (dev->isp_ver == ISP_V32_L)
+				val |= ISP32L_SENSOR_MODE(dev->multi_mode);
+			else
+				val |= ISP21_SENSOR_MODE(dev->multi_mode);
 			writel(val, hw->base_addr + ISP_ACQ_H_OFFS);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP_ACQ_H_OFFS);
+			v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
+				 "sensor mode:%d index:%d | 0x%x\n",
+				 dev->multi_mode, dev->multi_index, val);
 		}
 		is_upd = true;
 	}
 
-	if (dev->isp_ver == ISP_V21)
+	if (dev->isp_ver > ISP_V20)
 		dma2frm = 0;
 	if (dma2frm > 2)
 		dma2frm = 2;
 	if (dma2frm == 2)
 		dev->rdbk_cnt_x3++;
-	else if (dma2frm == 1)
+	else if (dma2frm == 1 || dev->sw_rd_cnt)
 		dev->rdbk_cnt_x2++;
 	else
 		dev->rdbk_cnt_x1++;
 	dev->rdbk_cnt++;
+	if (dev->isp_ver == ISP_V20)
+		params_vdev->rdbk_times = dma2frm + 1;
 
-	rkisp_params_cfgsram(params_vdev);
-	params_vdev->rdbk_times = dma2frm + 1;
+run_next:
+	rkisp_params_cfgsram(params_vdev, true);
+	stats_vdev->rdbk_drop = false;
+	if (dev->is_frame_double) {
+		is_upd = true;
+		if (is_try) {
+			/* the frame second running to on mi */
+			rkisp_multi_overflow_hdl(dev, true);
+			rkisp_update_regs(dev, ISP_LDCH_BASE, ISP_LDCH_BASE);
 
-	/* read 3d lut at frame end */
+			val = ISP3X_YNR_FST_FRAME | ISP3X_DHAZ_FST_FRAME | ISP3X_CNR_FST_FRAME;
+			if (dev->isp_ver == ISP_V32)
+				val |= ISP32_SHP_FST_FRAME;
+			else
+				val |= ISP3X_CNR_FST_FRAME;
+			rkisp_unite_clear_bits(dev, ISP3X_ISP_CTRL1, val, false);
+			val = rkisp_read_reg_cache(dev, ISP3X_DRC_IIRWG_GAIN);
+			writel(val, hw->base_addr + ISP3X_DRC_IIRWG_GAIN);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP3X_DRC_IIRWG_GAIN);
+			val = rkisp_read_reg_cache(dev, ISP3X_DRC_EXPLRATIO);
+			writel(val, hw->base_addr + ISP3X_DRC_EXPLRATIO);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP3X_DRC_EXPLRATIO);
+			val = rkisp_read_reg_cache(dev, ISP3X_YNR_GLOBAL_CTRL);
+			writel(val, hw->base_addr + ISP3X_YNR_GLOBAL_CTRL);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP3X_YNR_GLOBAL_CTRL);
+			if (dev->isp_ver == ISP_V21 || dev->isp_ver == ISP_V30) {
+				val = rkisp_read_reg_cache(dev, ISP3X_CNR_CTRL);
+				writel(val, hw->base_addr + ISP3X_CNR_CTRL);
+				if (hw->unite == ISP_UNITE_TWO)
+					writel(val, hw->base_next_addr + ISP3X_CNR_CTRL);
+			}
+		} else {
+			/* the frame first running to off mi to save bandwidth */
+			rkisp_multi_overflow_hdl(dev, false);
+
+			/* FST_FRAME no to read sram thumb */
+			val = ISP3X_YNR_FST_FRAME | ISP3X_DHAZ_FST_FRAME;
+			if (dev->isp_ver == ISP_V32)
+				val |= ISP32_SHP_FST_FRAME;
+			else
+				val |= ISP3X_CNR_FST_FRAME;
+			rkisp_unite_set_bits(dev, ISP3X_ISP_CTRL1, 0, val, false);
+			/* ADRC low iir thumb weight for first sensor switch */
+			val = rkisp_read_reg_cache(dev, ISP3X_DRC_IIRWG_GAIN);
+			val &= ~ISP3X_DRC_IIR_WEIGHT_MASK;
+			writel(val, hw->base_addr + ISP3X_DRC_IIRWG_GAIN);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP3X_DRC_IIRWG_GAIN);
+			/* ADRC iir5x5 and cur3x3 weight */
+			val = rkisp_read_reg_cache(dev, ISP3X_DRC_EXPLRATIO);
+			val &= ~ISP3X_DRC_WEIPRE_FRAME_MASK;
+			writel(val, hw->base_addr + ISP3X_DRC_EXPLRATIO);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP3X_DRC_EXPLRATIO);
+			/* YNR_THUMB_MIX_CUR_EN for thumb read addr to 0 */
+			val = rkisp_read_reg_cache(dev, ISP3X_YNR_GLOBAL_CTRL);
+			val |= ISP3X_YNR_THUMB_MIX_CUR_EN;
+			writel(val, hw->base_addr + ISP3X_YNR_GLOBAL_CTRL);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP3X_YNR_GLOBAL_CTRL);
+			if (dev->isp_ver == ISP_V21 || dev->isp_ver == ISP_V30) {
+				/* CNR_THUMB_MIX_CUR_EN for thumb read addr to 0 */
+				val = rkisp_read_reg_cache(dev, ISP3X_CNR_CTRL);
+				val |= ISP3X_CNR_THUMB_MIX_CUR_EN;
+				writel(val, hw->base_addr + ISP3X_CNR_CTRL);
+				if (hw->unite == ISP_UNITE_TWO)
+					writel(val, hw->base_next_addr + ISP3X_CNR_CTRL);
+			}
+			stats_vdev->rdbk_drop = true;
+		}
+	}
+
+	/* disable isp force update to read 3dlut
+	 * 3dlut auto update at frame end for single sensor
+	 */
 	if (hw->is_single && is_upd &&
 	    rkisp_read_reg_cache(dev, ISP_3DLUT_UPDATE) & 0x1) {
-		rkisp_write(dev, ISP_3DLUT_UPDATE, 0, true);
+		rkisp_unite_write(dev, ISP_3DLUT_UPDATE, 0, true);
 		is_3dlut_upd = true;
 	}
 	if (is_upd) {
 		val = rkisp_read(dev, ISP_CTRL, false);
 		val |= CIF_ISP_CTRL_ISP_CFG_UPD;
-		rkisp_write(dev, ISP_CTRL, val, true);
+		rkisp_unite_write(dev, ISP_CTRL, val, true);
+		/* bayer pat after ISP_CFG_UPD for multi sensor to read lsc r/g/b table */
+		rkisp_update_regs(dev, ISP3X_ISP_CTRL1, ISP3X_ISP_CTRL1);
 		/* fix ldch multi sensor case:
 		 * ldch will pre-read data when en and isp force upd or frame end,
 		 * udelay for ldch pre-read data.
 		 * ldch en=0 before start for frame end to stop ldch read data.
 		 */
-		if (!hw->is_single &&
-		    (rkisp_read(dev, ISP_LDCH_BASE, true) & 0x1)) {
+		val = rkisp_read(dev, ISP_LDCH_BASE, true);
+		if (!hw->is_single && val & BIT(0)) {
 			udelay(50);
-			writel(0, hw->base_addr + ISP_LDCH_BASE);
+			val &= ~(BIT(0) | BIT(31));
+			writel(val, hw->base_addr + ISP_LDCH_BASE);
+			if (hw->unite == ISP_UNITE_TWO)
+				writel(val, hw->base_next_addr + ISP_LDCH_BASE);
 		}
 	}
 	if (is_3dlut_upd)
-		rkisp_write(dev, ISP_3DLUT_UPDATE, 1, true);
+		rkisp_unite_write(dev, ISP_3DLUT_UPDATE, 1, true);
 
 	/* if output stream enable, wait it end */
 	val = rkisp_read(dev, CIF_MI_CTRL_SHD, true);
@@ -618,21 +839,68 @@
 		dev->irq_ends_mask |= ISP_FRAME_SP;
 	else
 		dev->irq_ends_mask &= ~ISP_FRAME_SP;
-
-	memset(dev->filt_state, 0, sizeof(dev->filt_state));
-	dev->filt_state[RDBK_F_VS] = dma2frm;
+	if ((dev->isp_ver == ISP_V20 &&
+	     rkisp_read(dev, ISP_MPFBC_CTRL, true) & SW_MPFBC_EN) ||
+	    (dev->isp_ver == ISP_V30 &&
+	     rkisp_read(dev, ISP3X_MPFBC_CTRL, true) & ISP3X_MPFBC_EN_SHD))
+		dev->irq_ends_mask |= ISP_FRAME_MPFBC;
+	else
+		dev->irq_ends_mask &= ~ISP_FRAME_MPFBC;
+	if ((dev->isp_ver == ISP_V30 &&
+	     rkisp_read(dev, ISP3X_MI_BP_WR_CTRL, true) & ISP3X_BP_ENABLE) ||
+	    (dev->isp_ver == ISP_V32 &&
+	     rkisp_read(dev, ISP32_MI_WR_CTRL2_SHD, true) & ISP32_BP_EN_OUT_SHD))
+		dev->irq_ends_mask |= ISP_FRAME_BP;
+	else
+		dev->irq_ends_mask &= ~ISP_FRAME_BP;
 
 	val = rkisp_read(dev, CSI2RX_CTRL0, true);
 	val &= ~SW_IBUF_OP_MODE(0xf);
 	tmp = SW_IBUF_OP_MODE(dev->rd_mode);
 	val |= tmp | SW_CSI2RX_EN | SW_DMA_2FRM_MODE(dma2frm);
+	if (dev->isp_ver > ISP_V20)
+		dma2frm = dev->sw_rd_cnt;
 	v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
-		 "readback frame:%d time:%d 0x%x\n",
-		 cur_frame_id, dma2frm + 1, val);
-	if (!dma2frm)
-		rkisp_bridge_update_mi(dev, 0);
+		 "readback frame:%d time:%d 0x%x try:%d\n",
+		 cur_frame_id, dma2frm + 1, val, is_try);
 	if (!hw->is_shutdown)
-		rkisp_write(dev, CSI2RX_CTRL0, val, true);
+		rkisp_unite_write(dev, CSI2RX_CTRL0, val, true);
+}
+
+static void rkisp_fast_switch_rx_buf(struct rkisp_device *dev, bool is_current)
+{
+	struct rkisp_stream *stream;
+	struct rkisp_buffer *buf;
+	u32 i, val;
+
+	if (!dev->is_rtt_first)
+		return;
+
+	for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) {
+		stream = &dev->dmarx_dev.stream[i];
+		if (!stream->ops)
+			continue;
+		buf = NULL;
+		if (is_current)
+			buf = stream->curr_buf;
+		else if (!list_empty(&stream->buf_queue))
+			buf = list_first_entry(&stream->buf_queue,
+					       struct rkisp_buffer, queue);
+		if (!buf)
+			continue;
+		val = buf->buff_addr[RKISP_PLANE_Y];
+		/* f1 -> f0 -> f1 for normal
+		 * L:f1 L:f1 -> L:f0 S:f0 -> L:f1 S:f1 for hdr2
+		 */
+		if (dev->rd_mode == HDR_RDBK_FRAME2 && !is_current &&
+		    rkisp_read_reg_cache(dev, ISP3X_HDRMGE_GAIN0) == 0xfff0040) {
+			if (i == RKISP_STREAM_RAWRD2)
+				continue;
+			else
+				rkisp_write(dev, ISP3X_MI_RAWS_RD_BASE, val, false);
+		}
+		rkisp_write(dev, stream->config->mi.y_base_ad_init, val, false);
+	}
 }
 
 static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
@@ -644,20 +912,44 @@
 	int i, times = -1, max = 0, id = 0;
 	int len[DEV_MAX] = { 0 };
 	u32 mode = 0;
+	bool is_try = false;
 
 	spin_lock_irqsave(&hw->rdbk_lock, lock_flags);
-	if (cmd == T_CMD_END)
+	if (cmd == T_CMD_END) {
+		if (dev->sw_rd_cnt) {
+			dev->sw_rd_cnt--;
+			isp = dev;
+			is_try = true;
+			times = 0;
+			if (hw->unite == ISP_UNITE_ONE) {
+				if (dev->sw_rd_cnt < 2)
+					isp->unite_index = ISP_UNITE_RIGHT;
+				if (!hw->is_multi_overflow || (dev->sw_rd_cnt & 0x1))
+					is_try = false;
+			}
+			goto end;
+		}
 		hw->is_idle = true;
+		hw->pre_dev_id = dev->dev_id;
+	}
 	if (hw->is_shutdown)
 		hw->is_idle = false;
 	if (!hw->is_idle)
 		goto end;
 	if (hw->monitor.state & ISP_MIPI_ERROR && hw->monitor.is_en)
 		goto end;
+	if (!IS_HDR_RDBK(dev->rd_mode))
+		goto end;
+	if (dev->is_suspend) {
+		if (dev->suspend_sync)
+			complete(&dev->pm_cmpl);
+		goto end;
+	}
 
 	for (i = 0; i < hw->dev_num; i++) {
 		isp = hw->isp[i];
-		if (!(isp->isp_state & ISP_START))
+		if (!isp ||
+		    (isp && (!(isp->isp_state & ISP_START) || isp->is_suspend)))
 			continue;
 		rkisp_rdbk_trigger_event(isp, T_CMD_LEN, &len[i]);
 		if (max < len[i]) {
@@ -666,10 +958,14 @@
 		}
 	}
 
+	/* wait 2 frame to start isp for fast */
+	if (dev->is_rtt_first && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq))
+		goto end;
+
 	if (max) {
-		v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
-			 "trigger fifo len:%d\n", max);
 		isp = hw->isp[id];
+		v4l2_dbg(2, rkisp_debug, &isp->v4l2_dev,
+			 "trigger fifo len:%d\n", max);
 		rkisp_rdbk_trigger_event(isp, T_CMD_DEQUEUE, &t);
 		isp->dmarx_dev.pre_frame = isp->dmarx_dev.cur_frame;
 		if (t.frame_id > isp->dmarx_dev.pre_frame.id &&
@@ -680,15 +976,52 @@
 		isp->dmarx_dev.cur_frame.sof_timestamp = t.sof_timestamp;
 		isp->dmarx_dev.cur_frame.timestamp = t.frame_timestamp;
 		isp->isp_sdev.frm_timestamp = t.sof_timestamp;
+		atomic_set(&isp->isp_sdev.frm_sync_seq, t.frame_id + 1);
 		mode = t.mode;
 		times = t.times;
 		hw->cur_dev_id = id;
 		hw->is_idle = false;
+		/* this frame will read count by isp */
+		isp->sw_rd_cnt = 0;
+		/* frame double for multi camera resolution out of hardware limit
+		 * first for HW save this camera information, and second to output image
+		 */
+		isp->is_frame_double = false;
+		if (hw->is_multi_overflow &&
+		    (hw->unite == ISP_UNITE_ONE ||
+		     (hw->pre_dev_id != -1 && hw->pre_dev_id != id))) {
+			isp->is_frame_double = true;
+			isp->sw_rd_cnt = 1;
+			times = 0;
+		}
+		/* resolution out of hardware limit
+		 * frame is vertically divided into left and right
+		 */
+		isp->unite_index = ISP_UNITE_LEFT;
+		if (hw->unite == ISP_UNITE_ONE) {
+			isp->sw_rd_cnt *= 2;
+			isp->sw_rd_cnt += 1;
+		}
+		/* first frame handle twice for thunderboot
+		 * first output stats to AIQ and wait new params to run second
+		 */
+		if (isp->is_rtt_first && t.frame_id == 0) {
+			isp->is_first_double = true;
+			isp->skip_frame = 1;
+			if (hw->unite != ISP_UNITE_ONE) {
+				isp->sw_rd_cnt = 0;
+				isp->is_frame_double = false;
+			}
+			rkisp_fast_switch_rx_buf(isp, false);
+		} else {
+			isp->is_rtt_first = false;
+		}
+		isp->params_vdev.rdbk_times = isp->sw_rd_cnt + 1;
 	}
 end:
 	spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags);
 	if (times >= 0)
-		rkisp_trigger_read_back(isp, times, mode, false);
+		rkisp_trigger_read_back(isp, times, mode, is_try);
 }
 
 int rkisp_rdbk_trigger_event(struct rkisp_device *dev, u32 cmd, void *arg)
@@ -697,9 +1030,6 @@
 	struct isp2x_csi_trigger *trigger = NULL;
 	unsigned long lock_flags = 0;
 	int val, ret = 0;
-
-	if (dev->dmarx_dev.trigger != T_MANUAL)
-		return 0;
 
 	spin_lock_irqsave(&dev->rdbk_lock, lock_flags);
 	switch (cmd) {
@@ -732,6 +1062,14 @@
 	return ret;
 }
 
+static void rkisp_rdbk_work(struct work_struct *work)
+{
+	struct rkisp_device *dev = container_of(work, struct rkisp_device, rdbk_work);
+
+	rkisp_dvfs(dev);
+	rkisp_rdbk_trigger_event(dev, T_CMD_END, NULL);
+}
+
 void rkisp_check_idle(struct rkisp_device *dev, u32 irq)
 {
 	u32 val = 0;
@@ -750,13 +1088,24 @@
 	    !IS_HDR_RDBK(dev->rd_mode))
 		return;
 
+	if (dev->sw_rd_cnt)
+		goto end;
+
+	if (dev->is_first_double) {
+		rkisp_fast_switch_rx_buf(dev, true);
+		dev->is_rtt_first = false;
+		dev->skip_frame = 0;
+		dev->irq_ends = 0;
+		return;
+	}
+
 	/* check output stream is off */
-	val = ISP_FRAME_MP | ISP_FRAME_SP | ISP_FRAME_MPFBC;
+	val = ISP_FRAME_MP | ISP_FRAME_SP | ISP_FRAME_MPFBC | ISP_FRAME_BP;
 	if (!(dev->irq_ends_mask & val)) {
 		u32 state = dev->isp_state;
 		struct rkisp_stream *s;
 
-		for (val = 0; val <= RKISP_STREAM_SP; val++) {
+		for (val = 0; val < RKISP_STREAM_VIR; val++) {
 			s = &dev->cap_dev.stream[val];
 			dev->isp_state = ISP_STOP;
 			if (s->streaming) {
@@ -767,7 +1116,6 @@
 	}
 
 	val = 0;
-	dev->irq_ends = 0;
 	switch (dev->rd_mode) {
 	case HDR_RDBK_FRAME3://for rd1 rd0 rd2
 		val |= RAW1_RD_FRAME;
@@ -780,7 +1128,12 @@
 		/* FALLTHROUGH */
 	}
 	rkisp2_rawrd_isr(val, dev);
-	if (dev->dmarx_dev.trigger == T_MANUAL)
+
+end:
+	dev->irq_ends = 0;
+	if (dev->hw_dev->is_dvfs)
+		schedule_work(&dev->rdbk_work);
+	else
 		rkisp_rdbk_trigger_event(dev, T_CMD_END, NULL);
 	if (dev->isp_state == ISP_STOP)
 		wake_up(&dev->sync_onoff);
@@ -803,113 +1156,48 @@
  */
 static void rkisp_config_ism(struct rkisp_device *dev)
 {
-	void __iomem *base = dev->base_addr;
 	struct v4l2_rect *out_crop = &dev->isp_sdev.out_crop;
-	u32 val;
+	u32 width = out_crop->width, mult = 1;
+	u32 unite = dev->hw_dev->unite;
 
 	/* isp2.0 no ism */
-	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
+	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21 ||
+	    dev->isp_ver == ISP_V32_L)
 		return;
 
-	writel(0, base + CIF_ISP_IS_RECENTER);
-	writel(0, base + CIF_ISP_IS_MAX_DX);
-	writel(0, base + CIF_ISP_IS_MAX_DY);
-	writel(0, base + CIF_ISP_IS_DISPLACE);
-	writel(out_crop->left, base + CIF_ISP_IS_H_OFFS);
-	writel(out_crop->top, base + CIF_ISP_IS_V_OFFS);
-	writel(out_crop->width, base + CIF_ISP_IS_H_SIZE);
+	if (unite)
+		width = width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL;
+	rkisp_unite_write(dev, CIF_ISP_IS_RECENTER, 0, false);
+	rkisp_unite_write(dev, CIF_ISP_IS_MAX_DX, 0, false);
+	rkisp_unite_write(dev, CIF_ISP_IS_MAX_DY, 0, false);
+	rkisp_unite_write(dev, CIF_ISP_IS_DISPLACE, 0, false);
+	rkisp_unite_write(dev, CIF_ISP_IS_H_OFFS, out_crop->left, false);
+	rkisp_unite_write(dev, CIF_ISP_IS_V_OFFS, out_crop->top, false);
+	rkisp_unite_write(dev, CIF_ISP_IS_H_SIZE, width, false);
 	if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced)
-		writel(out_crop->height / 2, base + CIF_ISP_IS_V_SIZE);
-	else
-		writel(out_crop->height, base + CIF_ISP_IS_V_SIZE);
+		mult = 2;
+	rkisp_unite_write(dev, CIF_ISP_IS_V_SIZE, out_crop->height / mult, false);
+
+	if (dev->isp_ver == ISP_V30 || dev->isp_ver == ISP_V32)
+		return;
 
 	/* IS(Image Stabilization) is always on, working as output crop */
-	writel(1, base + CIF_ISP_IS_CTRL);
-	val = readl(base + CIF_ISP_CTRL);
-	val |= CIF_ISP_CTRL_ISP_CFG_UPD;
-	writel(val, base + CIF_ISP_CTRL);
+	rkisp_write(dev, CIF_ISP_IS_CTRL, 1, false);
 }
 
-static int rkisp_reset_handle_v2x(struct rkisp_device *dev)
+static int rkisp_reset_handle(struct rkisp_device *dev)
 {
-	void __iomem *base = dev->base_addr;
-	void *reg_buf = NULL;
-	u32 *reg, *reg1, i;
-	struct backup_reg backup[] = {
-		{
-			.base = MI_MP_WR_Y_BASE,
-			.shd = MI_MP_WR_Y_BASE_SHD,
-		}, {
-			.base = MI_MP_WR_CB_BASE,
-			.shd = MI_MP_WR_CB_BASE_SHD,
-		}, {
-			.base = MI_MP_WR_CR_BASE,
-			.shd = MI_MP_WR_CR_BASE_SHD,
-		}, {
-			.base = MI_SP_WR_Y_BASE,
-			.shd = MI_SP_WR_Y_BASE_SHD,
-		}, {
-			.base = MI_SP_WR_CB_BASE,
-			.shd = MI_SP_WR_CB_BASE_AD_SHD,
-		}, {
-			.base = MI_SP_WR_CR_BASE,
-			.shd = MI_SP_WR_CR_BASE_AD_SHD,
-		}, {
-			.base = MI_RAW0_WR_BASE,
-			.shd = MI_RAW0_WR_BASE_SHD,
-		}, {
-			.base = MI_RAW1_WR_BASE,
-			.shd = MI_RAW1_WR_BASE_SHD,
-		}, {
-			.base = MI_RAW2_WR_BASE,
-			.shd = MI_RAW2_WR_BASE_SHD,
-		}, {
-			.base = MI_RAW3_WR_BASE,
-			.shd = MI_RAW3_WR_BASE_SHD,
-		}, {
-			.base = MI_RAW0_RD_BASE,
-			.shd = MI_RAW0_RD_BASE_SHD,
-		}, {
-			.base = MI_RAW1_RD_BASE,
-			.shd = MI_RAW1_RD_BASE_SHD,
-		}, {
-			.base = MI_RAW2_RD_BASE,
-			.shd = MI_RAW2_RD_BASE_SHD,
-		}, {
-			.base = MI_GAIN_WR_BASE,
-			.shd = MI_GAIN_WR_BASE_SHD,
-		}
-	};
-
-	reg_buf = kzalloc(RKISP_ISP_SW_REG_SIZE, GFP_KERNEL);
-	if (!reg_buf)
-		return -ENOMEM;
+	u32 val;
 
 	dev_info(dev->dev, "%s enter\n", __func__);
+	rkisp_hw_reg_save(dev->hw_dev);
 
-	memcpy_fromio(reg_buf, base, RKISP_ISP_SW_REG_SIZE);
 	rkisp_soft_reset(dev->hw_dev, true);
 
-	/* process special reg */
-	reg = reg_buf + ISP_CTRL;
-	*reg &= ~(CIF_ISP_CTRL_ISP_ENABLE |
-		  CIF_ISP_CTRL_ISP_INFORM_ENABLE |
-		  CIF_ISP_CTRL_ISP_CFG_UPD);
-	reg = reg_buf + MI_WR_INIT;
-	*reg = 0;
-	reg = reg_buf + CSI2RX_CTRL0;
-	*reg &= ~SW_CSI2RX_EN;
-	/* skip mmu range */
-	memcpy_toio(base, reg_buf, ISP21_MI_BAY3D_RD_BASE_SHD);
-	memcpy_toio(base + CSI2RX_CTRL0, reg_buf + CSI2RX_CTRL0,
-		    RKISP_ISP_SW_REG_SIZE - CSI2RX_CTRL0);
-	/* config shd_reg to base_reg */
-	for (i = 0; i < ARRAY_SIZE(backup); i++) {
-		reg = reg_buf + backup[i].base;
-		reg1 = reg_buf + backup[i].shd;
-		backup[i].val = *reg;
-		writel(*reg1, base + backup[i].base);
-	}
+	rkisp_hw_reg_restore(dev->hw_dev);
+
+	val = CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR;
+	rkisp_unite_set_bits(dev, CIF_ISP_IMSC, 0, val, true);
 
 	/* clear state */
 	dev->isp_err_cnt = 0;
@@ -917,40 +1205,12 @@
 	rkisp_set_state(&dev->isp_state, ISP_FRAME_END);
 	dev->hw_dev->monitor.state = ISP_FRAME_END;
 
-	/* update module */
-	reg = reg_buf + DUAL_CROP_CTRL;
-	if (*reg & 0xf)
-		writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL);
-	reg = reg_buf + SELF_RESIZE_CTRL;
-	if (*reg & 0xf)
-		writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL);
-	reg = reg_buf + MAIN_RESIZE_CTRL;
-	if (*reg & 0xf)
-		writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL);
-
-	/* update mi and isp, base_reg will update to shd_reg */
-	force_cfg_update(dev);
-	reg = reg_buf + ISP_CTRL;
-	*reg |= CIF_ISP_CTRL_ISP_ENABLE |
-		CIF_ISP_CTRL_ISP_INFORM_ENABLE |
-		CIF_ISP_CTRL_ISP_CFG_UPD;
-	writel(*reg, base + ISP_CTRL);
-	udelay(50);
-	/* config base_reg */
-	for (i = 0; i < ARRAY_SIZE(backup); i++)
-		writel(backup[i].val, base + backup[i].base);
-	/* mpfbc base_reg = shd_reg, write is base but read is shd */
-	if (dev->isp_ver == ISP_V20)
-		writel(rkisp_read_reg_cache(dev, ISP_MPFBC_HEAD_PTR),
-		       base + ISP_MPFBC_HEAD_PTR);
-	rkisp_set_bits(dev, CIF_ISP_IMSC, 0, CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR, true);
 	if (IS_HDR_RDBK(dev->hdr.op_mode)) {
 		if (!dev->hw_dev->is_idle)
 			rkisp_trigger_read_back(dev, 1, 0, true);
 		else
 			rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, NULL);
 	}
-	kfree(reg_buf);
 	dev_info(dev->dev, "%s exit\n", __func__);
 	return 0;
 }
@@ -964,11 +1224,6 @@
 	struct rkisp_pipeline *p;
 	int ret, i, j, timeout = 5, mipi_irq_cnt = 0;
 
-	if (!monitor->reset_handle) {
-		monitor->is_en = false;
-		return;
-	}
-
 	dev_info(hw->dev, "%s enter\n", __func__);
 	while (!(monitor->state & ISP_STOP) && monitor->is_en) {
 		ret = wait_for_completion_timeout(&monitor->cmpl,
@@ -976,15 +1231,18 @@
 		/* isp stop to exit
 		 * isp err to reset
 		 * mipi err wait isp idle, then reset
+		 * online vicap if isp err, notify vicap reset, then vicap notify isp reset
+		 * by ioctl RKISP_VICAP_CMD_SET_STREAM
 		 */
 		if (monitor->state & ISP_STOP ||
+		    monitor->state & ISP_CIF_RESET ||
 		    (ret && !(monitor->state & ISP_ERROR)) ||
 		    (!ret &&
 		     monitor->state & ISP_FRAME_END &&
 		     !(monitor->state & ISP_MIPI_ERROR))) {
 			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;
 				if (!(isp->isp_state & ISP_START))
 					break;
@@ -1006,6 +1264,8 @@
 		}
 		for (i = 0; i < hw->dev_num; i++) {
 			isp = hw->isp[i];
+			if (!isp)
+				continue;
 			if (isp->isp_inp & INP_CSI ||
 			    isp->isp_inp & INP_DVP ||
 			    isp->isp_inp & INP_LVDS) {
@@ -1024,14 +1284,28 @@
 
 		/* restart isp */
 		isp = hw->isp[hw->cur_dev_id];
-		ret = monitor->reset_handle(isp);
-		if (ret) {
-			monitor->is_en = false;
-			break;
+		if (!IS_HDR_RDBK(isp->hdr.op_mode) && isp->isp_ver >= ISP_V30) {
+			struct v4l2_subdev *remote = NULL;
+			struct v4l2_subdev *isp_subdev = NULL;
+
+			isp_subdev = &(isp->isp_sdev.sd);
+			remote = get_remote_sensor(isp_subdev);
+			v4l2_subdev_call(remote, core, ioctl,
+				RKISP_VICAP_CMD_SET_RESET, NULL);
+			monitor->state |= ISP_CIF_RESET;
+			continue;
+		} else {
+			ret = rkisp_reset_handle(isp);
+			if (ret) {
+				monitor->is_en = false;
+				break;
+			}
 		}
 
 		for (i = 0; i < hw->dev_num; i++) {
 			isp = hw->isp[i];
+			if (!isp)
+				continue;
 			if (isp->isp_inp & INP_CSI ||
 			    isp->isp_inp & INP_DVP ||
 			    isp->isp_inp & INP_LVDS) {
@@ -1059,9 +1333,6 @@
 	struct rkisp_monitor *monitor = &dev->hw_dev->monitor;
 
 	monitor->dev = dev->hw_dev;
-	monitor->reset_handle = NULL;
-	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
-		monitor->reset_handle = rkisp_reset_handle_v2x;
 
 	init_completion(&monitor->cmpl);
 	INIT_WORK(&monitor->work, rkisp_restart_monitor);
@@ -1085,6 +1356,8 @@
  */
 static void rkisp_config_color_space(struct rkisp_device *dev)
 {
+	u32 val = 0;
+
 	u16 bt601_coeff[] = {
 		0x0026, 0x004b, 0x000f,
 		0x01ea, 0x01d6, 0x0040,
@@ -1116,16 +1389,222 @@
 	}
 
 	for (i = 0; i < 9; i++)
-		rkisp_write(dev, CIF_ISP_CC_COEFF_0 + i * 4, *(coeff + i), false);
+		rkisp_unite_write(dev, CIF_ISP_CC_COEFF_0 + i * 4,
+				  *(coeff + i), false);
+
+	val = rkisp_read_reg_cache(dev, CIF_ISP_CTRL);
 
 	if (dev->isp_sdev.quantization == V4L2_QUANTIZATION_FULL_RANGE)
-		rkisp_set_bits(dev, CIF_ISP_CTRL, 0,
-			       CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA |
-			       CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA, false);
+		rkisp_unite_write(dev, CIF_ISP_CTRL, val |
+				  CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA |
+				  CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA, false);
 	else
-		rkisp_clear_bits(dev, CIF_ISP_CTRL,
-				 CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA |
-				 CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA, false);
+		rkisp_unite_write(dev, CIF_ISP_CTRL, val &
+				  ~(CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA |
+				  CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA), false);
+}
+
+static void rkisp_config_cmsk_single(struct rkisp_device *dev,
+				     struct rkisp_cmsk_cfg *cfg)
+{
+	u32 i, val, ctrl = 0;
+	u32 mp_en = cfg->win[0].win_en;
+	u32 sp_en = cfg->win[1].win_en;
+	u32 bp_en = cfg->win[2].win_en;
+	u32 win_max = (dev->isp_ver == ISP_V30) ?
+		RKISP_CMSK_WIN_MAX_V30 : RKISP_CMSK_WIN_MAX;
+
+	if (mp_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_MP;
+		rkisp_write(dev, ISP3X_CMSK_CTRL1, mp_en, false);
+		val = cfg->win[0].mode;
+		rkisp_write(dev, ISP3X_CMSK_CTRL4, val, false);
+	}
+
+	if (sp_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_SP;
+		rkisp_write(dev, ISP3X_CMSK_CTRL2, sp_en, false);
+		val = cfg->win[1].mode;
+		rkisp_write(dev, ISP3X_CMSK_CTRL5, val, false);
+	}
+
+	if (bp_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_BP;
+		rkisp_write(dev, ISP3X_CMSK_CTRL3, bp_en, false);
+		val = cfg->win[2].mode;
+		rkisp_write(dev, ISP3X_CMSK_CTRL6, val, false);
+	}
+
+	for (i = 0; i < win_max; i++) {
+		if (!(mp_en & BIT(i)) && !(sp_en & BIT(i)) && !(bp_en & BIT(i)))
+			continue;
+
+		val = ISP3X_SW_CMSK_YUV(cfg->win[i].cover_color_y,
+					cfg->win[i].cover_color_u,
+					cfg->win[i].cover_color_v);
+		rkisp_write(dev, ISP3X_CMSK_YUV0 + i * 4, val, false);
+
+		val = ISP_PACK_2SHORT(cfg->win[i].h_offs, cfg->win[i].v_offs);
+		rkisp_write(dev, ISP3X_CMSK_OFFS0 + i * 8, val, false);
+
+		val = ISP_PACK_2SHORT(cfg->win[i].h_size, cfg->win[i].v_size);
+		rkisp_write(dev, ISP3X_CMSK_SIZE0 + i * 8, val, false);
+	}
+
+	if (ctrl) {
+		val = ISP_PACK_2SHORT(dev->isp_sdev.out_crop.width,
+				      dev->isp_sdev.out_crop.height);
+		rkisp_write(dev, ISP3X_CMSK_PIC_SIZE, val, false);
+		ctrl |= ISP3X_SW_CMSK_EN | ISP3X_SW_CMSK_ORDER_MODE;
+		ctrl |= ISP3X_SW_CMSK_BLKSIZE(cfg->mosaic_block);
+	}
+	rkisp_write(dev, ISP3X_CMSK_CTRL0, ctrl, false);
+
+	val = rkisp_read(dev, ISP3X_CMSK_CTRL0, true);
+	if (dev->hw_dev->is_single &&
+	    ((val & ISP32_SW_CMSK_EN_PATH) != (val & ISP32_SW_CMSK_EN_PATH_SHD)))
+		rkisp_write(dev, ISP3X_CMSK_CTRL0, val | ISP3X_SW_CMSK_FORCE_UPD, true);
+}
+
+static void rkisp_config_cmsk_dual(struct rkisp_device *dev,
+				   struct rkisp_cmsk_cfg *cfg)
+{
+	struct rkisp_cmsk_cfg left = *cfg;
+	struct rkisp_cmsk_cfg right = *cfg;
+	u32 width = dev->isp_sdev.out_crop.width;
+	u32 height = dev->isp_sdev.out_crop.height;
+	u32 w = width / 2;
+	u32 i, val, h_offs, h_size, ctrl;
+	u8 mp_en = cfg->win[0].win_en;
+	u8 sp_en = cfg->win[1].win_en;
+	u8 bp_en = cfg->win[2].win_en;
+	u32 win_max = (dev->isp_ver == ISP_V30) ?
+		RKISP_CMSK_WIN_MAX_V30 : RKISP_CMSK_WIN_MAX;
+
+	for (i = 0; i < win_max; i++) {
+		if (!(mp_en & BIT(i)) && !(sp_en & BIT(i)) && !(bp_en & BIT(i)))
+			continue;
+
+		h_offs = cfg->win[i].h_offs;
+		h_size = cfg->win[i].h_size;
+		if (h_offs + h_size <= w) {
+			/* cmsk window at left isp */
+			right.win[0].win_en &= ~BIT(i);
+			right.win[1].win_en &= ~BIT(i);
+			right.win[2].win_en &= ~BIT(i);
+		} else if (h_offs >= w) {
+			/* cmsk window at right isp */
+			left.win[0].win_en &= ~BIT(i);
+			left.win[1].win_en &= ~BIT(i);
+			left.win[2].win_en &= ~BIT(i);
+			right.win[i].h_offs = h_offs - w + RKMOUDLE_UNITE_EXTEND_PIXEL;
+		} else {
+			/* cmsk window at dual isp */
+			left.win[i].h_size = ALIGN(w - h_offs, 8);
+
+			right.win[i].h_offs = RKMOUDLE_UNITE_EXTEND_PIXEL;
+			val = h_offs + h_size - w;
+			right.win[i].h_size = ALIGN(val, 8);
+			right.win[i].h_offs -= right.win[i].h_size - val;
+		}
+
+		val = ISP3X_SW_CMSK_YUV(left.win[i].cover_color_y,
+					left.win[i].cover_color_u,
+					left.win[i].cover_color_v);
+		rkisp_write(dev, ISP3X_CMSK_YUV0 + i * 4, val, false);
+		rkisp_next_write(dev, ISP3X_CMSK_YUV0 + i * 4, val, false);
+
+		val = ISP_PACK_2SHORT(left.win[i].h_offs, left.win[i].v_offs);
+		rkisp_write(dev, ISP3X_CMSK_OFFS0 + i * 8, val, false);
+		val = ISP_PACK_2SHORT(left.win[i].h_size, left.win[i].v_size);
+		rkisp_write(dev, ISP3X_CMSK_SIZE0 + i * 8, val, false);
+
+		val = ISP_PACK_2SHORT(right.win[i].h_offs, right.win[i].v_offs);
+		rkisp_next_write(dev, ISP3X_CMSK_OFFS0 + i * 8, val, false);
+		val = ISP_PACK_2SHORT(right.win[i].h_size, right.win[i].v_size);
+		rkisp_next_write(dev, ISP3X_CMSK_SIZE0 + i * 8, val, false);
+	}
+
+	w += RKMOUDLE_UNITE_EXTEND_PIXEL;
+	ctrl = 0;
+	if (left.win[0].win_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_MP;
+		rkisp_write(dev, ISP3X_CMSK_CTRL1, left.win[0].win_en, false);
+		val = left.win[0].mode;
+		rkisp_write(dev, ISP3X_CMSK_CTRL4, val, false);
+	}
+	if (left.win[1].win_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_SP;
+		rkisp_write(dev, ISP3X_CMSK_CTRL2, left.win[1].win_en, false);
+		val = left.win[1].mode;
+		rkisp_write(dev, ISP3X_CMSK_CTRL5, val, false);
+	}
+	if (left.win[2].win_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_BP;
+		rkisp_write(dev, ISP3X_CMSK_CTRL3, left.win[2].win_en, false);
+		val = left.win[2].mode;
+		rkisp_write(dev, ISP3X_CMSK_CTRL6, val, false);
+	}
+	if (ctrl) {
+		val = ISP_PACK_2SHORT(w, height);
+		rkisp_write(dev, ISP3X_CMSK_PIC_SIZE, val, false);
+		ctrl |= ISP3X_SW_CMSK_EN | ISP3X_SW_CMSK_ORDER_MODE;
+	}
+	rkisp_write(dev, ISP3X_CMSK_CTRL0, ctrl, false);
+
+	ctrl = 0;
+	if (right.win[0].win_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_MP;
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL1, right.win[0].win_en, false);
+		val = right.win[0].mode;
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL4, val, false);
+	}
+	if (right.win[1].win_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_SP;
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL2, right.win[1].win_en, false);
+		val = right.win[1].mode;
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL5, val, false);
+	}
+	if (right.win[2].win_en) {
+		ctrl |= ISP3X_SW_CMSK_EN_BP;
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL3, right.win[2].win_en, false);
+		val = right.win[2].mode;
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL6, val, false);
+	}
+	if (ctrl) {
+		val = ISP_PACK_2SHORT(w, height);
+		rkisp_next_write(dev, ISP3X_CMSK_PIC_SIZE, val, false);
+		ctrl |= ISP3X_SW_CMSK_EN | ISP3X_SW_CMSK_ORDER_MODE;
+	}
+	rkisp_next_write(dev, ISP3X_CMSK_CTRL0, ctrl, false);
+
+	val = rkisp_next_read(dev, ISP3X_CMSK_CTRL0, true);
+	if (dev->hw_dev->is_single &&
+	    ((val & ISP32_SW_CMSK_EN_PATH) != (val & ISP32_SW_CMSK_EN_PATH_SHD)))
+		rkisp_next_write(dev, ISP3X_CMSK_CTRL0, val | ISP3X_SW_CMSK_FORCE_UPD, false);
+}
+
+static void rkisp_config_cmsk(struct rkisp_device *dev)
+{
+	unsigned long lock_flags = 0;
+	struct rkisp_cmsk_cfg cfg;
+
+	if (dev->isp_ver != ISP_V30 && dev->isp_ver != ISP_V32)
+		return;
+
+	spin_lock_irqsave(&dev->cmsk_lock, lock_flags);
+	if (!dev->is_cmsk_upd) {
+		spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags);
+		return;
+	}
+	dev->is_cmsk_upd = false;
+	cfg = dev->cmsk_cfg;
+	spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags);
+
+	if (!dev->hw_dev->unite)
+		rkisp_config_cmsk_single(dev, &cfg);
+	else
+		rkisp_config_cmsk_dual(dev, &cfg);
 }
 
 /*
@@ -1137,17 +1616,20 @@
 	struct ispsd_out_fmt *out_fmt;
 	struct v4l2_rect *in_crop;
 	struct rkisp_sensor_info *sensor;
+	bool is_unite = !!dev->hw_dev->unite;
 	u32 isp_ctrl = 0;
 	u32 irq_mask = 0;
 	u32 signal = 0;
 	u32 acq_mult = 0;
 	u32 acq_prop = 0;
 	u32 extend_line = 0;
+	u32 width;
 
 	sensor = dev->active_sensor;
 	in_fmt = &dev->isp_sdev.in_fmt;
 	out_fmt = &dev->isp_sdev.out_fmt;
 	in_crop = &dev->isp_sdev.in_crop;
+	width = in_crop->width;
 
 	if (in_fmt->fmt_type == FMT_BAYER) {
 		acq_mult = 1;
@@ -1163,21 +1645,21 @@
 			if (in_fmt->mbus_code == MEDIA_BUS_FMT_Y8_1X8 ||
 			    in_fmt->mbus_code == MEDIA_BUS_FMT_Y10_1X10 ||
 			    in_fmt->mbus_code == MEDIA_BUS_FMT_Y12_1X12) {
-				if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
-					rkisp_write(dev, ISP_DEBAYER_CONTROL, 0, false);
+				if (dev->isp_ver >= ISP_V20)
+					rkisp_unite_write(dev, ISP_DEBAYER_CONTROL, 0, false);
 				else
 					rkisp_write(dev, CIF_ISP_DEMOSAIC,
-						CIF_ISP_DEMOSAIC_BYPASS |
-						CIF_ISP_DEMOSAIC_TH(0xc), false);
+						    CIF_ISP_DEMOSAIC_BYPASS |
+						    CIF_ISP_DEMOSAIC_TH(0xc), false);
 			} else {
-				if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
-					rkisp_write(dev, ISP_DEBAYER_CONTROL,
-						SW_DEBAYER_EN |
-						SW_DEBAYER_FILTER_G_EN |
-						SW_DEBAYER_FILTER_C_EN, false);
+				if (dev->isp_ver >= ISP_V20)
+					rkisp_unite_write(dev, ISP_DEBAYER_CONTROL,
+							  SW_DEBAYER_EN |
+							  SW_DEBAYER_FILTER_G_EN |
+							  SW_DEBAYER_FILTER_C_EN, false);
 				else
 					rkisp_write(dev, CIF_ISP_DEMOSAIC,
-						CIF_ISP_DEMOSAIC_TH(0xc), false);
+						    CIF_ISP_DEMOSAIC_TH(0xc), false);
 			}
 
 			if (sensor && sensor->mbus.type == V4L2_MBUS_BT656)
@@ -1195,7 +1677,7 @@
 	} else if (in_fmt->fmt_type == FMT_YUV) {
 		acq_mult = 2;
 		if (sensor &&
-		    (sensor->mbus.type == V4L2_MBUS_CSI2 ||
+		    (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
 		     sensor->mbus.type == V4L2_MBUS_CCP2)) {
 			isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU601;
 		} else {
@@ -1227,39 +1709,46 @@
 			signal |= CIF_ISP_ACQ_PROP_HSYNC_LOW;
 	}
 
-	rkisp_write(dev, CIF_ISP_CTRL, isp_ctrl, false);
+	if (rkisp_read_reg_cache(dev, CIF_ISP_CTRL) & ISP32_MIR_ENABLE)
+		isp_ctrl |= ISP32_MIR_ENABLE;
+
+	rkisp_unite_write(dev, CIF_ISP_CTRL, isp_ctrl, false);
 	acq_prop |= signal | in_fmt->yuv_seq |
 		CIF_ISP_ACQ_PROP_BAYER_PAT(in_fmt->bayer_pat) |
 		CIF_ISP_ACQ_PROP_FIELD_SEL_ALL;
-	rkisp_write(dev, CIF_ISP_ACQ_PROP, acq_prop, false);
-	rkisp_write(dev, CIF_ISP_ACQ_NR_FRAMES, 0, true);
+	rkisp_unite_write(dev, CIF_ISP_ACQ_PROP, acq_prop, false);
+	rkisp_unite_write(dev, CIF_ISP_ACQ_NR_FRAMES, 0, true);
 
+	if (is_unite)
+		width = width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL;
 	/* Acquisition Size */
-	rkisp_write(dev, CIF_ISP_ACQ_H_OFFS, acq_mult * in_crop->left, false);
-	rkisp_write(dev, CIF_ISP_ACQ_V_OFFS, in_crop->top, false);
-	rkisp_write(dev, CIF_ISP_ACQ_H_SIZE, acq_mult * in_crop->width, false);
+	rkisp_unite_write(dev, CIF_ISP_ACQ_H_OFFS, acq_mult * in_crop->left, false);
+	rkisp_unite_write(dev, CIF_ISP_ACQ_V_OFFS, in_crop->top, false);
+	rkisp_unite_write(dev, CIF_ISP_ACQ_H_SIZE, acq_mult * width, false);
 
 	/* ISP Out Area differ with ACQ is only FIFO, so don't crop in this */
-	rkisp_write(dev, CIF_ISP_OUT_H_OFFS, 0, true);
-	rkisp_write(dev, CIF_ISP_OUT_V_OFFS, 0, true);
-	rkisp_write(dev, CIF_ISP_OUT_H_SIZE, in_crop->width, false);
+	rkisp_unite_write(dev, CIF_ISP_OUT_H_OFFS, 0, true);
+	rkisp_unite_write(dev, CIF_ISP_OUT_V_OFFS, 0, true);
+	rkisp_unite_write(dev, CIF_ISP_OUT_H_SIZE, width, false);
 
 	if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced) {
-		rkisp_write(dev, CIF_ISP_ACQ_V_SIZE, in_crop->height / 2, false);
-		rkisp_write(dev, CIF_ISP_OUT_V_SIZE, in_crop->height / 2, false);
+		rkisp_unite_write(dev, CIF_ISP_ACQ_V_SIZE, in_crop->height / 2, false);
+		rkisp_unite_write(dev, CIF_ISP_OUT_V_SIZE, in_crop->height / 2, false);
 	} else {
-		rkisp_write(dev, CIF_ISP_ACQ_V_SIZE, in_crop->height + extend_line, false);
-		rkisp_write(dev, CIF_ISP_OUT_V_SIZE, in_crop->height + extend_line, false);
+		rkisp_unite_write(dev, CIF_ISP_ACQ_V_SIZE, in_crop->height + extend_line, false);
+		rkisp_unite_write(dev, CIF_ISP_OUT_V_SIZE, in_crop->height + extend_line, false);
 	}
 
 	/* interrupt mask */
-	irq_mask |= CIF_ISP_FRAME | CIF_ISP_V_START | CIF_ISP_PIC_SIZE_ERROR |
-		    CIF_ISP_FRAME_IN;
-	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
+	irq_mask |= CIF_ISP_FRAME | CIF_ISP_V_START | CIF_ISP_PIC_SIZE_ERROR;
+	if (dev->isp_ver >= ISP_V20)
 		irq_mask |= ISP2X_LSC_LUT_ERR;
-	rkisp_write(dev, CIF_ISP_IMSC, irq_mask, true);
+	if (dev->is_pre_on)
+		irq_mask |= CIF_ISP_FRAME_IN;
+	rkisp_unite_write(dev, CIF_ISP_IMSC, irq_mask, true);
 
-	if ((dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) &&
+	if ((dev->isp_ver == ISP_V20 ||
+	     dev->isp_ver == ISP_V21) &&
 	    IS_HDR_RDBK(dev->hdr.op_mode)) {
 		irq_mask = ISP2X_3A_RAWAE_BIG;
 		rkisp_write(dev, ISP_ISP3A_IMSC, irq_mask, true);
@@ -1276,6 +1765,8 @@
 		rkisp_update_regs(dev, CIF_ISP_ACQ_H_OFFS, CIF_ISP_ACQ_V_SIZE);
 		rkisp_update_regs(dev, CIF_ISP_OUT_H_SIZE, CIF_ISP_OUT_V_SIZE);
 	}
+
+	rkisp_config_cmsk(dev);
 	return 0;
 }
 
@@ -1379,12 +1870,12 @@
 /* Configure MUX */
 static int rkisp_config_path(struct rkisp_device *dev)
 {
-	int ret = 0;
 	struct rkisp_sensor_info *sensor = dev->active_sensor;
-	u32 dpcl = readl(dev->base_addr + CIF_VI_DPCL);
+	int ret = 0;
+	u32 dpcl = 0;
 
 	/* isp input interface selects */
-	if ((sensor && sensor->mbus.type == V4L2_MBUS_CSI2) ||
+	if ((sensor && sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) ||
 	    dev->isp_inp & (INP_RAWRD0 | INP_RAWRD1 | INP_RAWRD2 | INP_CIF)) {
 		/* mipi sensor->isp or isp read from ddr */
 		dpcl |= CIF_VI_DPCL_IF_SEL_MIPI;
@@ -1406,12 +1897,10 @@
 		ret = -EINVAL;
 	}
 
-	/* fix 3a_wr no output with selfpath */
-	if (dev->isp_ver == ISP_V21)
-		dpcl |= CIF_VI_DPCL_CHAN_MODE_MP | CIF_VI_DPCL_MP_MUX_MRSZ_MI;
+	if (dev->isp_ver == ISP_V32)
+		dpcl |= BIT(0);
 
-	writel(dpcl, dev->base_addr + CIF_VI_DPCL);
-
+	rkisp_unite_set_bits(dev, CIF_VI_DPCL, 0, dpcl, true);
 	return ret;
 }
 
@@ -1483,7 +1972,7 @@
 	int ret = 1000;
 
 	if (!rkisp_is_need_3a(dev) || dev->isp_ver == ISP_V20 ||
-	    !params_vdev->is_subs_evt)
+	    !params_vdev->is_subs_evt || dev->hw_dev->is_shutdown)
 		return;
 
 	v4l2_event_queue(vdev, &ev);
@@ -1500,6 +1989,7 @@
 /* Mess register operations to stop isp */
 static int rkisp_isp_stop(struct rkisp_device *dev)
 {
+	struct rkisp_hw_dev *hw = dev->hw_dev;
 	void __iomem *base = dev->base_addr;
 	unsigned long old_rate, safe_rate;
 	u32 val;
@@ -1507,9 +1997,9 @@
 
 	v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
 		 "%s refcnt:%d\n", __func__,
-		 atomic_read(&dev->hw_dev->refcnt));
+		 atomic_read(&hw->refcnt));
 
-	if (atomic_read(&dev->hw_dev->refcnt) > 1)
+	if (atomic_read(&hw->refcnt) > 1)
 		goto end;
 	/*
 	 * ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
@@ -1523,7 +2013,7 @@
 		readl(base + CIF_ISP_CSI0_ERR1);
 		readl(base + CIF_ISP_CSI0_ERR2);
 		readl(base + CIF_ISP_CSI0_ERR3);
-	} else if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) {
+	} else if (dev->isp_ver >= ISP_V20) {
 		writel(0, base + CSI2RX_MASK_PHY);
 		writel(0, base + CSI2RX_MASK_PACKET);
 		writel(0, base + CSI2RX_MASK_OVERFLOW);
@@ -1540,7 +2030,7 @@
 	writel(0, base + CIF_ISP_IMSC);
 	writel(~0, base + CIF_ISP_ICR);
 
-	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) {
+	if (dev->isp_ver >= ISP_V20) {
 		writel(0, base + ISP_ISP3A_IMSC);
 		writel(~0, base + ISP_ISP3A_ICR);
 	}
@@ -1556,7 +2046,7 @@
 		udelay(20);
 	}
 	/* stop lsc to avoid lsclut error */
-	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
+	if (dev->isp_ver >= ISP_V20)
 		writel(0, base + ISP_LSC_CTRL);
 	/* stop ISP */
 	val = readl(base + CIF_ISP_CTRL);
@@ -1565,6 +2055,9 @@
 
 	val = readl(base + CIF_ISP_CTRL);
 	writel(val | CIF_ISP_CTRL_ISP_CFG_UPD, base + CIF_ISP_CTRL);
+	if (hw->unite == ISP_UNITE_TWO)
+		rkisp_next_write(dev, CIF_ISP_CTRL,
+				 val | CIF_ISP_CTRL_ISP_CFG_UPD, true);
 
 	readx_poll_timeout_atomic(readl, base + CIF_ISP_RIS,
 				  val, val & CIF_ISP_OFF, 20, 100);
@@ -1572,19 +2065,19 @@
 		 "MI_CTRL:%x, ISP_CTRL:%x\n",
 		 readl(base + CIF_MI_CTRL), readl(base + CIF_ISP_CTRL));
 
-	val = rkisp_read(dev, CTRL_VI_ISP_CLK_CTRL, true);
 	if (!in_interrupt()) {
 		/* normal case */
 		/* check the isp_clk before isp reset operation */
-		old_rate = clk_get_rate(dev->hw_dev->clks[0]);
-		safe_rate = dev->hw_dev->clk_rate_tbl[0].clk_rate * 1000000UL;
+		old_rate = clk_get_rate(hw->clks[0]);
+		safe_rate = hw->clk_rate_tbl[0].clk_rate * 1000000UL;
 		if (old_rate > safe_rate) {
-			rkisp_set_clk_rate(dev->hw_dev->clks[0], safe_rate);
+			rkisp_set_clk_rate(hw->clks[0], safe_rate);
+			if (hw->unite == ISP_UNITE_TWO)
+				rkisp_set_clk_rate(hw->clks[5], safe_rate);
 			udelay(100);
 		}
-		rkisp_soft_reset(dev->hw_dev, false);
+		rkisp_soft_reset(hw, false);
 	}
-	rkisp_write(dev, CTRL_VI_ISP_CLK_CTRL, val, true);
 
 	if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) {
 		writel(0, base + CIF_ISP_CSI0_CSI2_RESETN);
@@ -1592,19 +2085,28 @@
 		writel(0, base + CIF_ISP_CSI0_MASK1);
 		writel(0, base + CIF_ISP_CSI0_MASK2);
 		writel(0, base + CIF_ISP_CSI0_MASK3);
-	} else if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) {
+	} else if (dev->isp_ver >= ISP_V20) {
 		writel(0, base + CSI2RX_CSI2_RESETN);
+		if (hw->unite == ISP_UNITE_TWO)
+			rkisp_next_write(dev, CSI2RX_CSI2_RESETN, 0, true);
 	}
 
-	dev->hw_dev->is_idle = true;
-	dev->hw_dev->is_mi_update = false;
+	hw->is_dvfs = false;
+	hw->is_runing = false;
+	hw->is_idle = true;
+	hw->is_mi_update = false;
+	hw->pre_dev_id = -1;
 end:
 	dev->irq_ends_mask = 0;
 	dev->hdr.op_mode = 0;
+	dev->sw_rd_cnt = 0;
+	dev->stats_vdev.rdbk_drop = false;
 	rkisp_set_state(&dev->isp_state, ISP_STOP);
 
-	if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
+	if (dev->isp_ver >= ISP_V20)
 		kfifo_reset(&dev->rdbk_kfifo);
+	if (dev->isp_ver == ISP_V30 || dev->isp_ver == ISP_V32)
+		memset(&dev->cmsk_cfg, 0, sizeof(dev->cmsk_cfg));
 	if (dev->emd_vc <= CIF_ISP_ADD_DATA_VC_MAX) {
 		for (i = 0; i < RKISP_EMDDATA_FIFO_MAX; i++)
 			kfifo_free(&dev->emd_data_fifo[i].mipi_kfifo);
@@ -1622,15 +2124,37 @@
 {
 	struct rkisp_sensor_info *sensor = dev->active_sensor;
 	void __iomem *base = dev->base_addr;
-	u32 val;
 	bool is_direct = true;
+	u32 val;
 
 	v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
-		 "%s refcnt:%d\n", __func__,
-		 atomic_read(&dev->hw_dev->refcnt));
+		 "%s refcnt:%d link_num:%d\n", __func__,
+		 atomic_read(&dev->hw_dev->refcnt),
+		 dev->hw_dev->dev_link_num);
+
+	dev->cap_dev.is_done_early = false;
+	if (dev->cap_dev.wait_line >= dev->isp_sdev.out_crop.height)
+		dev->cap_dev.wait_line = 0;
+	if (dev->cap_dev.wait_line) {
+		dev->cap_dev.is_done_early = true;
+		if (dev->isp_ver >= ISP_V32) {
+			val = dev->cap_dev.wait_line;
+			rkisp_write(dev, ISP32_ISP_IRQ_CFG0, val << 16, false);
+			rkisp_set_bits(dev, CIF_ISP_IMSC, 0, ISP3X_OUT_FRM_HALF, false);
+		} else {
+			/* using AF 15x15 block */
+			val = dev->isp_sdev.out_crop.height / 15;
+			val = dev->cap_dev.wait_line / val;
+			val = ISP3X_RAWAF_INELINE0(val) | ISP3X_RAWAF_INTLINE0_EN;
+			rkisp_unite_write(dev, ISP3X_RAWAF_INT_LINE, val, false);
+			rkisp_unite_set_bits(dev, ISP_ISP3A_IMSC, 0, ISP2X_3A_RAWAF, false);
+			rkisp_unite_clear_bits(dev, CIF_ISP_IMSC, ISP2X_LSC_LUT_ERR, false);
+			dev->rawaf_irq_cnt = 0;
+		}
+	}
 
 	/* Activate MIPI */
-	if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
+	if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) {
 		if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) {
 			/* clear interrupts state */
 			readl(base + CIF_ISP_CSI0_ERR1);
@@ -1645,19 +2169,19 @@
 		}
 	}
 	/* Activate ISP */
-	val = rkisp_read(dev, CIF_ISP_CTRL, false);
+	val = rkisp_read_reg_cache(dev, CIF_ISP_CTRL);
 	val |= CIF_ISP_CTRL_ISP_CFG_UPD | CIF_ISP_CTRL_ISP_ENABLE |
 	       CIF_ISP_CTRL_ISP_INFORM_ENABLE | CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT;
 	if (dev->isp_ver == ISP_V20)
 		val |= NOC_HURRY_PRIORITY(2) | NOC_HURRY_W_MODE(2) | NOC_HURRY_R_MODE(1);
 	if (atomic_read(&dev->hw_dev->refcnt) > 1)
 		is_direct = false;
-	rkisp_write(dev, CIF_ISP_CTRL, val, is_direct);
+	rkisp_unite_write(dev, CIF_ISP_CTRL, val, is_direct);
+	rkisp_clear_reg_cache_bits(dev, CIF_ISP_CTRL, CIF_ISP_CTRL_ISP_CFG_UPD);
 
 	dev->isp_err_cnt = 0;
 	dev->isp_isr_cnt = 0;
-	dev->isp_state = ISP_START | ISP_FRAME_END;
-	dev->irq_ends_mask |= ISP_FRAME_END | ISP_FRAME_IN;
+	dev->irq_ends_mask |= ISP_FRAME_END;
 	dev->irq_ends = 0;
 
 	/* XXX: Is the 1000us too long?
@@ -2097,7 +2621,7 @@
 	struct rkisp_isp_subdev *isp_sd = sd_to_isp_sd(sd);
 	struct rkisp_device *dev = sd_to_isp_dev(sd);
 	struct v4l2_rect *crop;
-	u32 max_w, max_h;
+	u32 max_w, max_h, max_size;
 
 	if (!sel)
 		goto err;
@@ -2118,19 +2642,42 @@
 		crop->left = 0;
 		crop->top = 0;
 		if (sel->pad == RKISP_ISP_PAD_SINK) {
-			if (dev->isp_ver == ISP_V12) {
+			switch (dev->isp_ver) {
+			case ISP_V12:
 				max_w = CIF_ISP_INPUT_W_MAX_V12;
 				max_h = CIF_ISP_INPUT_H_MAX_V12;
-			} else if (dev->isp_ver == ISP_V13) {
+				break;
+			case ISP_V13:
 				max_w = CIF_ISP_INPUT_W_MAX_V13;
 				max_h = CIF_ISP_INPUT_H_MAX_V13;
-			} else if (dev->isp_ver == ISP_V21) {
+				break;
+			case ISP_V21:
 				max_w = CIF_ISP_INPUT_W_MAX_V21;
 				max_h = CIF_ISP_INPUT_H_MAX_V21;
-			} else {
+				break;
+			case ISP_V30:
+				max_w = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_W_MAX_V30_UNITE : CIF_ISP_INPUT_W_MAX_V30;
+				max_h = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_H_MAX_V30_UNITE : CIF_ISP_INPUT_H_MAX_V30;
+				break;
+			case ISP_V32:
+				max_w = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_W_MAX_V32_UNITE : CIF_ISP_INPUT_W_MAX_V32;
+				max_h = dev->hw_dev->unite ?
+					CIF_ISP_INPUT_H_MAX_V32_UNITE : CIF_ISP_INPUT_H_MAX_V32;
+				break;
+			case ISP_V32_L:
+				max_w = CIF_ISP_INPUT_W_MAX_V32_L;
+				max_h = CIF_ISP_INPUT_H_MAX_V32_L;
+				break;
+			default:
 				max_w = CIF_ISP_INPUT_W_MAX;
 				max_h = CIF_ISP_INPUT_H_MAX;
 			}
+			max_size = max_w * max_h;
+			max_h = max_size / isp_sd->in_frm.width;
+
 			crop->width = min_t(u32, isp_sd->in_frm.width, max_w);
 			crop->height = min_t(u32, isp_sd->in_frm.height, max_h);
 		}
@@ -2146,6 +2693,40 @@
 	return 0;
 err:
 	return -EINVAL;
+}
+
+static void rkisp_check_stream_dcrop(struct rkisp_device *dev,
+				     struct v4l2_rect *crop)
+{
+	struct rkisp_stream *stream;
+	struct v4l2_rect *dcrop;
+	u32 i;
+
+	for (i = 0; i < RKISP_MAX_STREAM; i++) {
+		if (i != RKISP_STREAM_MP && i != RKISP_STREAM_SP &&
+		    i != RKISP_STREAM_FBC && i != RKISP_STREAM_BP)
+			continue;
+		stream = &dev->cap_dev.stream[i];
+		dcrop = &stream->dcrop;
+		v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
+			 "%s id:%d %dx%d(%d %d) from %dx%d(%d %d)\n",
+			__func__, i,
+			dcrop->width, dcrop->height, dcrop->left, dcrop->top,
+			crop->width, crop->height, crop->left, crop->top);
+		/* make sure dcrop window in isp output window */
+		if (dcrop->width > crop->width) {
+			dcrop->width = crop->width;
+			dcrop->left = 0;
+		} else if ((dcrop->left + dcrop->width) > crop->width) {
+			dcrop->left = crop->width - dcrop->width;
+		}
+		if (dcrop->height > crop->height) {
+			dcrop->height = crop->height;
+			dcrop->top = 0;
+		} else if ((dcrop->top + dcrop->height) > crop->height) {
+			dcrop->top = crop->height - dcrop->height;
+		}
+	}
 }
 
 static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd,
@@ -2179,18 +2760,20 @@
 
 	if (sel->pad == RKISP_ISP_PAD_SINK) {
 		isp_sd->in_crop = *crop;
-		/* ISP20 don't have out crop */
-		if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) {
+		/* don't have out crop */
+		if (dev->isp_ver >= ISP_V20) {
 			isp_sd->out_crop = *crop;
 			isp_sd->out_crop.left = 0;
 			isp_sd->out_crop.top = 0;
 			dev->br_dev.crop = isp_sd->out_crop;
 		}
 	} else {
-		if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
+		if (dev->isp_ver >= ISP_V20)
 			*crop = isp_sd->out_crop;
 		isp_sd->out_crop = *crop;
 	}
+
+	rkisp_check_stream_dcrop(dev, crop);
 
 	return 0;
 err:
@@ -2246,53 +2829,301 @@
 	struct rkisp_stream *stream;
 	int i;
 
+	rkisp_stats_first_ddr_config(&dev->stats_vdev);
 	if (dev->hw_dev->is_mi_update)
 		return;
 
-	rkisp_stats_first_ddr_config(&dev->stats_vdev);
 	rkisp_config_dmatx_valid_buf(dev);
 
 	force_cfg_update(dev);
 
 	hdr_update_dmatx_buf(dev);
-	if (dev->br_dev.en && dev->isp_ver == ISP_V20) {
-		stream = &dev->cap_dev.stream[RKISP_STREAM_SP];
-		rkisp_update_spstream_buf(stream);
-	}
 	if (dev->hw_dev->is_single) {
 		for (i = 0; i < RKISP_MAX_STREAM; i++) {
 			stream = &dev->cap_dev.stream[i];
-			if (stream->streaming && !stream->next_buf)
-				stream->ops->frame_end(stream);
+			if (stream->id == RKISP_STREAM_VIR ||
+			    stream->id == RKISP_STREAM_LUMA)
+				continue;
+			if (stream->streaming && !stream->curr_buf)
+				stream->ops->frame_end(stream, FRAME_INIT);
 		}
 	}
+	rkisp_stats_next_ddr_config(&dev->stats_vdev);
 }
 
 static int rkisp_isp_sd_s_stream(struct v4l2_subdev *sd, int on)
 {
 	struct rkisp_device *isp_dev = sd_to_isp_dev(sd);
+	struct rkisp_hw_dev *hw_dev = isp_dev->hw_dev;
+	int ret;
 
 	if (!on) {
-		wait_event_timeout(isp_dev->sync_onoff,
-			isp_dev->irq_ends_mask == (ISP_FRAME_END | ISP_FRAME_IN) &&
-			(!IS_HDR_RDBK(isp_dev->rd_mode) ||
-			 isp_dev->isp_state & ISP_STOP), msecs_to_jiffies(5));
+		if (IS_HDR_RDBK(isp_dev->rd_mode)) {
+			struct rkisp_stream *s;
+			int i;
+
+			for (i = RKISP_STREAM_RAWRD0; i <= RKISP_STREAM_RAWRD2; i++) {
+				s = &isp_dev->dmarx_dev.stream[i];
+				if (s->stopping)
+					wake_up(&s->done);
+			}
+		}
+		ret = wait_event_timeout(isp_dev->sync_onoff,
+					 isp_dev->isp_state & ISP_STOP ||
+					 !IS_HDR_RDBK(isp_dev->rd_mode),
+					 msecs_to_jiffies(500));
+		if (!ret)
+			v4l2_warn(&isp_dev->v4l2_dev, "%s wait timeout, mode:%d state:0x%x\n",
+				  __func__, isp_dev->rd_mode, isp_dev->isp_state);
 		rkisp_isp_stop(isp_dev);
-		atomic_dec(&isp_dev->hw_dev->refcnt);
+		atomic_dec(&hw_dev->refcnt);
 		rkisp_params_stream_stop(&isp_dev->params_vdev);
+		atomic_set(&isp_dev->isp_sdev.frm_sync_seq, 0);
 		rkisp_stop_3a_run(isp_dev);
 		return 0;
 	}
 
+	hw_dev->is_runing = true;
 	rkisp_start_3a_run(isp_dev);
 	memset(&isp_dev->isp_sdev.dbg, 0, sizeof(isp_dev->isp_sdev.dbg));
-	atomic_inc(&isp_dev->hw_dev->refcnt);
-	atomic_set(&isp_dev->isp_sdev.frm_sync_seq, 0);
-	rkisp_global_update_mi(isp_dev);
+	if (atomic_inc_return(&hw_dev->refcnt) > hw_dev->dev_link_num) {
+		dev_err(isp_dev->dev, "%s fail: input link before hw start\n", __func__);
+		atomic_dec(&hw_dev->refcnt);
+		return -EINVAL;
+	}
+
 	rkisp_config_cif(isp_dev);
 	rkisp_isp_start(isp_dev);
+	rkisp_global_update_mi(isp_dev);
+	isp_dev->isp_state = ISP_START | ISP_FRAME_END;
 	rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, NULL);
 	return 0;
+}
+
+static void rkisp_rx_buf_free(struct rkisp_device *dev, struct rkisp_rx_buf *dbufs)
+{
+	const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops;
+	struct rkisp_rx_buf_pool *pool;
+	int i = 0;
+
+	if (!dbufs)
+		return;
+
+	for (i = 0; i < RKISP_RX_BUF_POOL_MAX; i++) {
+		pool = &dev->pv_pool[i];
+		if (dbufs == pool->dbufs) {
+			if (pool->mem_priv) {
+				g_ops->unmap_dmabuf(pool->mem_priv);
+				g_ops->detach_dmabuf(pool->mem_priv);
+				dma_buf_put(pool->dbufs->dbuf);
+				pool->mem_priv = NULL;
+			}
+			pool->dbufs = NULL;
+			break;
+		}
+	}
+}
+
+static void rkisp_rx_qbuf_online(struct rkisp_stream *stream,
+				 struct rkisp_rx_buf_pool *pool)
+{
+	struct rkisp_device *dev = stream->ispdev;
+	u32 val = pool->buf.buff_addr[RKISP_PLANE_Y];
+
+	rkisp_write(dev, stream->config->mi.y_base_ad_init, val, false);
+	if (dev->hw_dev->unite == ISP_UNITE_TWO) {
+		u32 offs = stream->out_fmt.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL;
+
+		if (stream->memory)
+			offs *= DIV_ROUND_UP(stream->out_isp_fmt.bpp[0], 8);
+		else
+			offs = offs * stream->out_isp_fmt.bpp[0] / 8;
+		val += offs;
+		rkisp_next_write(dev, stream->config->mi.y_base_ad_init, val, false);
+	}
+}
+
+static void rkisp_rx_qbuf_rdbk(struct rkisp_stream *stream,
+			       struct rkisp_rx_buf_pool *pool)
+{
+	struct rkisp_device *dev = stream->ispdev;
+	unsigned long lock_flags = 0;
+	struct rkisp_buffer *ispbuf = &pool->buf;
+	struct isp2x_csi_trigger trigger = {
+		.frame_timestamp = ispbuf->vb.vb2_buf.timestamp,
+		.sof_timestamp = ispbuf->vb.vb2_buf.timestamp,
+		.frame_id = ispbuf->vb.sequence,
+		.mode = 0,
+		.times = 0,
+	};
+	spin_lock_irqsave(&stream->vbq_lock, lock_flags);
+	if (list_empty(&stream->buf_queue) && !stream->curr_buf) {
+		stream->curr_buf = ispbuf;
+		stream->ops->update_mi(stream);
+	} else {
+		list_add_tail(&ispbuf->queue, &stream->buf_queue);
+	}
+	spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
+	if (stream->id == RKISP_STREAM_RAWRD2)
+		rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, &trigger);
+}
+
+static int rkisp_rx_qbuf(struct rkisp_device *dev,
+			 struct rkisp_rx_buf *dbufs)
+{
+	struct rkisp_stream *stream;
+	struct rkisp_rx_buf_pool *pool;
+	int i;
+
+	for (i = 0; i < RKISP_RX_BUF_POOL_MAX; i++) {
+		pool = &dev->pv_pool[i];
+		if (dbufs == pool->dbufs)
+			break;
+	}
+
+	if (pool->dbufs == NULL || pool->dbufs != dbufs)
+		return -EINVAL;
+	switch (dbufs->type) {
+	case BUF_SHORT:
+		stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD2];
+		break;
+	case BUF_MIDDLE:
+		stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD0];
+		break;
+	case BUF_LONG:
+	default:
+		stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD1];
+	}
+
+	v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
+		 "%s rd_mode:%d seq:%d dma:0x%x\n",
+		 __func__, dev->rd_mode, dbufs->sequence,
+		 pool->buf.buff_addr[RKISP_PLANE_Y]);
+
+	if (!IS_HDR_RDBK(dev->rd_mode)) {
+		rkisp_rx_qbuf_online(stream, pool);
+	} else {
+		pool->buf.vb.vb2_buf.timestamp = dbufs->timestamp;
+		pool->buf.vb.sequence = dbufs->sequence;
+		rkisp_rx_qbuf_rdbk(stream, pool);
+	}
+	return 0;
+}
+
+void rkisp_rx_buf_pool_free(struct rkisp_device *dev)
+{
+	const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops;
+	struct rkisp_rx_buf_pool *pool;
+	int i;
+
+	for (i = 0; i < RKISP_RX_BUF_POOL_MAX; i++) {
+		pool = &dev->pv_pool[i];
+		if (!pool->dbufs)
+			break;
+		if (pool->mem_priv) {
+			g_ops->unmap_dmabuf(pool->mem_priv);
+			g_ops->detach_dmabuf(pool->mem_priv);
+			dma_buf_put(pool->dbufs->dbuf);
+			pool->mem_priv = NULL;
+		}
+		pool->dbufs = NULL;
+	}
+}
+
+static int rkisp_rx_buf_pool_init(struct rkisp_device *dev,
+				  struct rkisp_rx_buf *dbufs)
+{
+	const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops;
+	struct rkisp_stream *stream;
+	struct rkisp_rx_buf_pool *pool;
+	struct sg_table  *sg_tbl;
+	dma_addr_t dma;
+	int i, ret;
+	void *mem, *vaddr = NULL;
+
+	for (i = 0; i < RKISP_RX_BUF_POOL_MAX; i++) {
+		pool = &dev->pv_pool[i];
+		if (!pool->dbufs)
+			break;
+	}
+
+	pool->dbufs = dbufs;
+	v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
+		 "%s type:0x%x first:%d dbufs[%d]:%p", __func__,
+		 dbufs->type, dbufs->is_first, i, dbufs);
+
+	if (dbufs->is_resmem) {
+		dma = dbufs->dma;
+		goto end;
+	}
+	mem = g_ops->attach_dmabuf(dev->hw_dev->dev, dbufs->dbuf,
+				   dbufs->dbuf->size, DMA_BIDIRECTIONAL);
+	if (IS_ERR(mem)) {
+		ret = PTR_ERR(mem);
+		goto err;
+	}
+	pool->mem_priv = mem;
+	ret = g_ops->map_dmabuf(mem);
+	if (ret)
+		goto err;
+	if (dev->hw_dev->is_dma_sg_ops) {
+		sg_tbl = (struct sg_table *)g_ops->cookie(mem);
+		dma = sg_dma_address(sg_tbl->sgl);
+	} else {
+		dma = *((dma_addr_t *)g_ops->cookie(mem));
+	}
+	get_dma_buf(dbufs->dbuf);
+	vaddr = g_ops->vaddr(mem);
+end:
+	dbufs->is_init = true;
+	pool->buf.other = dbufs;
+	pool->buf.buff_addr[RKISP_PLANE_Y] = dma;
+	pool->buf.vaddr[RKISP_PLANE_Y] = vaddr;
+
+	switch (dbufs->type) {
+	case BUF_SHORT:
+		stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD2];
+		break;
+	case BUF_MIDDLE:
+		stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD0];
+		break;
+	case BUF_LONG:
+	default:
+		stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD1];
+	}
+	if (dbufs->is_first) {
+		stream->memory = 0;
+		if (dbufs->is_uncompact)
+			stream->memory = SW_CSI_RAW_WR_SIMG_MODE;
+		rkisp_dmarx_set_fmt(stream, stream->out_fmt);
+		stream->ops->config_mi(stream);
+		dbufs->is_first = false;
+	}
+	v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
+		 "%s dma:0x%x vaddr:%p", __func__, (u32)dma, vaddr);
+	return 0;
+err:
+	rkisp_rx_buf_pool_free(dev);
+	return ret;
+}
+
+static int rkisp_sd_s_rx_buffer(struct v4l2_subdev *sd,
+				void *buf, unsigned int *size)
+{
+	struct rkisp_device *dev = sd_to_isp_dev(sd);
+	struct rkisp_rx_buf *dbufs;
+	int ret = 0;
+
+	if (!buf)
+		return -EINVAL;
+
+	dbufs = buf;
+	if (!dbufs->is_init)
+		ret = rkisp_rx_buf_pool_init(dev, dbufs);
+	if (!ret)
+		ret = rkisp_rx_qbuf(dev, dbufs);
+
+	return ret;
 }
 
 static int rkisp_isp_sd_s_power(struct v4l2_subdev *sd, int on)
@@ -2300,14 +3131,11 @@
 	struct rkisp_device *isp_dev = sd_to_isp_dev(sd);
 	int ret;
 
-	if (isp_dev->hw_dev->is_thunderboot)
-		return 0;
-
 	v4l2_dbg(1, rkisp_debug, &isp_dev->v4l2_dev,
 		 "%s on:%d\n", __func__, on);
 
 	if (on) {
-		if (isp_dev->isp_ver == ISP_V20 || isp_dev->isp_ver == ISP_V21)
+		if (isp_dev->isp_ver >= ISP_V20)
 			kfifo_reset(&isp_dev->rdbk_kfifo);
 		ret = pm_runtime_get_sync(isp_dev->dev);
 	} else {
@@ -2337,6 +3165,15 @@
 	dev = sd_to_isp_dev(sd);
 	if (!dev)
 		return -ENODEV;
+
+	if (dev->hw_dev->is_runing &&
+	    (!dev->isp_inp ||
+	     !(dev->isp_inp & ~rawrd) ||
+	     !strcmp(remote->entity->name, CSI_DEV_NAME) ||
+	     strstr(remote->entity->name, "rkcif"))) {
+		v4l2_err(sd, "no support link for isp hw working\n");
+		return -EINVAL;
+	}
 
 	if (!strcmp(remote->entity->name, DMA_VDEV_NAME)) {
 		stream = &dev->dmarx_dev.stream[RKISP_STREAM_DMARX];
@@ -2386,6 +3223,18 @@
 		} else {
 			dev->isp_inp &= ~INP_RAWRD2;
 		}
+	} else if (!strcmp(remote->entity->name, FBC_VDEV_NAME)) {
+		stream = &dev->cap_dev.stream[RKISP_STREAM_FBC];
+	} else if (!strcmp(remote->entity->name, BP_VDEV_NAME)) {
+		stream = &dev->cap_dev.stream[RKISP_STREAM_BP];
+	} else if (!strcmp(remote->entity->name, MPDS_VDEV_NAME)) {
+		stream = &dev->cap_dev.stream[RKISP_STREAM_MPDS];
+	} else if (!strcmp(remote->entity->name, BPDS_VDEV_NAME)) {
+		stream = &dev->cap_dev.stream[RKISP_STREAM_BPDS];
+	} else if (!strcmp(remote->entity->name, LUMA_VDEV_NAME)) {
+		stream = &dev->cap_dev.stream[RKISP_STREAM_LUMA];
+	} else if (!strcmp(remote->entity->name, VIR_VDEV_NAME)) {
+		stream = &dev->cap_dev.stream[RKISP_STREAM_VIR];
 	} else if (!strcmp(remote->entity->name, SP_VDEV_NAME)) {
 		stream = &dev->cap_dev.stream[RKISP_STREAM_SP];
 	} else if (!strcmp(remote->entity->name, MP_VDEV_NAME)) {
@@ -2430,11 +3279,31 @@
 
 	if (stream)
 		stream->linked = flags & MEDIA_LNK_FL_ENABLED;
-	if (dev->isp_inp & rawrd)
+	if (dev->isp_inp & rawrd) {
 		dev->dmarx_dev.trigger = T_MANUAL;
-	else
+		dev->is_rdbk_auto = false;
+	} else {
 		dev->dmarx_dev.trigger = T_AUTO;
+	}
+	if (dev->isp_inp & INP_CIF) {
+		struct v4l2_subdev *remote = get_remote_sensor(sd);
+		struct rkisp_vicap_mode mode;
 
+		memset(&mode, 0, sizeof(mode));
+		mode.name = dev->name;
+		mode.rdbk_mode = !!(dev->isp_inp & rawrd);
+		/* read back mode only */
+		if (dev->isp_ver < ISP_V30 || !dev->hw_dev->is_single)
+			mode.rdbk_mode = RKISP_VICAP_RDBK_AIQ;
+		v4l2_subdev_call(remote, core, ioctl,
+				 RKISP_VICAP_CMD_MODE, &mode);
+		dev->vicap_in = mode.input;
+	}
+
+	if (!dev->isp_inp)
+		dev->is_hw_link = false;
+	else
+		dev->is_hw_link = true;
 	v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
 		 "isp input:0x%x\n", dev->isp_inp);
 	return 0;
@@ -2482,7 +3351,6 @@
 			atomic_inc_return(&isp->frm_sync_seq) - 1,
 	};
 
-	event.timestamp = ns_to_timespec(ktime_get_ns());
 	v4l2_event_queue(isp->sd.devnode, &event);
 }
 
@@ -2499,24 +3367,148 @@
 	return v4l2_event_subscribe(fh, sub, ISP_V4L2_EVENT_ELEMS, NULL);
 }
 
+static int rkisp_get_info(struct rkisp_device *dev, struct rkisp_isp_info *info)
+{
+	struct v4l2_rect *in_crop = &dev->isp_sdev.in_crop;
+	u32 rd_mode, mode = 0, bit = 0;
+	int ret;
+
+	if (!(dev->isp_state & ISP_START)) {
+		struct rkmodule_hdr_cfg cfg;
+
+		ret = rkisp_csi_get_hdr_cfg(dev, &cfg);
+		if (ret)
+			return ret;
+		rd_mode = cfg.hdr_mode;
+		if (rd_mode == HDR_COMPR)
+			bit = cfg.compr.bit > 20 ? 20 : cfg.compr.bit;
+	} else {
+		rd_mode = dev->rd_mode;
+		bit = dev->hdr.compr_bit;
+	}
+
+	switch (rd_mode) {
+	case HDR_RDBK_FRAME2:
+	case HDR_FRAMEX2_DDR:
+	case HDR_LINEX2_DDR:
+		mode = RKISP_ISP_HDR2;
+		break;
+	case HDR_RDBK_FRAME3:
+	case HDR_FRAMEX3_DDR:
+	case HDR_LINEX3_DDR:
+		mode = RKISP_ISP_HDR3;
+		break;
+	default:
+		mode = RKISP_ISP_NORMAL;
+	}
+	if (bit)
+		mode = RKISP_ISP_COMPR;
+	info->compr_bit = bit;
+
+	if (dev->is_bigmode)
+		mode |= RKISP_ISP_BIGMODE;
+	info->mode = mode;
+	if (dev->hw_dev->unite)
+		info->act_width = in_crop->width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL;
+	else
+		info->act_width = in_crop->width;
+	info->act_height = in_crop->height;
+	return 0;
+}
+
+static int rkisp_set_work_mode_by_vicap(struct rkisp_device *isp_dev,
+					struct rkisp_vicap_mode *vicap_mode)
+{
+	struct rkisp_hw_dev *hw = isp_dev->hw_dev;
+	int rd_mode = isp_dev->rd_mode;
+
+	isp_dev->is_suspend_one_frame = false;
+	if (vicap_mode->rdbk_mode == RKISP_VICAP_ONLINE) {
+		if (!hw->is_single)
+			return -EINVAL;
+		/* switch to online mode for single sensor */
+		switch (rd_mode) {
+		case HDR_RDBK_FRAME3:
+			isp_dev->rd_mode = HDR_LINEX3_DDR;
+			break;
+		case HDR_RDBK_FRAME2:
+			isp_dev->rd_mode = HDR_LINEX2_DDR;
+			break;
+		default:
+			isp_dev->rd_mode = HDR_NORMAL;
+		}
+	} else if (vicap_mode->rdbk_mode == RKISP_VICAP_RDBK_AUTO ||
+		   vicap_mode->rdbk_mode == RKISP_VICAP_RDBK_AUTO_ONE_FRAME) {
+		/* switch to readback mode */
+		switch (rd_mode) {
+		case HDR_LINEX3_DDR:
+			isp_dev->rd_mode = HDR_RDBK_FRAME3;
+			break;
+		case HDR_LINEX2_DDR:
+			isp_dev->rd_mode = HDR_RDBK_FRAME2;
+			break;
+		default:
+			isp_dev->rd_mode = HDR_RDBK_FRAME1;
+		}
+		if (vicap_mode->rdbk_mode == RKISP_VICAP_RDBK_AUTO_ONE_FRAME)
+			isp_dev->is_suspend_one_frame = true;
+	} else {
+		return -EINVAL;
+	}
+	isp_dev->hdr.op_mode = isp_dev->rd_mode;
+	if (rd_mode != isp_dev->rd_mode && hw->cur_dev_id == isp_dev->dev_id) {
+		rkisp_unite_write(isp_dev, CSI2RX_CTRL0,
+				  SW_IBUF_OP_MODE(isp_dev->rd_mode), true);
+		if (IS_HDR_RDBK(isp_dev->rd_mode))
+			rkisp_unite_set_bits(isp_dev, CTRL_SWS_CFG, 0,
+					     SW_MPIP_DROP_FRM_DIS, true);
+		else
+			rkisp_unite_clear_bits(isp_dev, CTRL_SWS_CFG,
+					       SW_MPIP_DROP_FRM_DIS, true);
+	}
+	return 0;
+}
+
 static long rkisp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	struct rkisp_device *isp_dev = sd_to_isp_dev(sd);
 	struct rkisp_thunderboot_resmem *resmem;
+	struct rkisp32_thunderboot_resmem_head *tb_head_v32;
 	struct rkisp_thunderboot_resmem_head *head;
 	struct rkisp_thunderboot_shmem *shmem;
 	struct isp2x_buf_idxfd *idxfd;
+	struct rkisp_rx_buf *dbufs;
 	void *resmem_va;
 	long ret = 0;
 
-	if (!arg && cmd != RKISP_CMD_FREE_SHARED_BUF)
+	if (!arg &&
+	    (cmd != RKISP_CMD_FREE_SHARED_BUF &&
+	     cmd != RKISP_CMD_MULTI_DEV_FORCE_ENUM))
 		return -EINVAL;
 
 	switch (cmd) {
 	case RKISP_CMD_TRIGGER_READ_BACK:
 		rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, arg);
 		break;
+	case RKISP_CMD_GET_ISP_INFO:
+		rkisp_get_info(isp_dev, arg);
+		break;
+	case RKISP_CMD_GET_TB_HEAD_V32:
+		if (isp_dev->tb_head.complete != RKISP_TB_OK) {
+			ret = -EINVAL;
+			break;
+		}
+		tb_head_v32 = arg;
+		memcpy(tb_head_v32, &isp_dev->tb_head,
+		       sizeof(struct rkisp_thunderboot_resmem_head));
+		memcpy(&tb_head_v32->cfg, isp_dev->params_vdev.isp32_params,
+		       sizeof(struct isp32_isp_params_cfg));
+		break;
 	case RKISP_CMD_GET_SHARED_BUF:
+		if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP)) {
+			ret = -ENOIOCTLCMD;
+			break;
+		}
 		resmem = (struct rkisp_thunderboot_resmem *)arg;
 		resmem->resmem_padr = isp_dev->resmem_pa;
 		resmem->resmem_size = isp_dev->resmem_size;
@@ -2546,6 +3538,10 @@
 		}
 		break;
 	case RKISP_CMD_FREE_SHARED_BUF:
+		if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP)) {
+			ret = -ENOIOCTLCMD;
+			break;
+		}
 		if (isp_dev->resmem_pa && isp_dev->resmem_size) {
 			dma_unmap_single(isp_dev->dev, isp_dev->resmem_pa,
 					 sizeof(struct rkisp_thunderboot_resmem_head),
@@ -2564,15 +3560,48 @@
 		break;
 	case RKISP_CMD_SET_LDCHBUF_SIZE:
 	case RKISP_CMD_SET_MESHBUF_SIZE:
-		rkisp_params_set_meshbuf_size(&isp_dev->params_vdev, arg);
+		ret = rkisp_params_set_meshbuf_size(&isp_dev->params_vdev, arg);
 		break;
 	case RKISP_CMD_GET_SHM_BUFFD:
+		if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP)) {
+			ret = -ENOIOCTLCMD;
+			break;
+		}
 		shmem = (struct rkisp_thunderboot_shmem *)arg;
 		ret = rkisp_tb_shm_ioctl(shmem);
 		break;
 	case RKISP_CMD_GET_FBCBUF_FD:
 		idxfd = (struct isp2x_buf_idxfd *)arg;
 		ret = rkisp_bridge_get_fbcbuf_fd(isp_dev, idxfd);
+		break;
+	case RKISP_CMD_INFO2DDR:
+		ret = rkisp_params_info2ddr_cfg(&isp_dev->params_vdev, arg);
+		break;
+	case RKISP_CMD_MESHBUF_FREE:
+		rkisp_params_meshbuf_free(&isp_dev->params_vdev, *(u64 *)arg);
+		break;
+	case RKISP_VICAP_CMD_RX_BUFFER_FREE:
+		dbufs = (struct rkisp_rx_buf *)arg;
+		rkisp_rx_buf_free(isp_dev, dbufs);
+		break;
+	case RKISP_CMD_MULTI_DEV_FORCE_ENUM:
+		if (isp_dev->hw_dev->is_runing) {
+			ret = -EINVAL;
+		} else {
+			isp_dev->hw_dev->is_single = true;
+			isp_dev->hw_dev->is_multi_overflow = false;
+			rkisp_hw_enum_isp_size(isp_dev->hw_dev);
+		}
+		break;
+	case RKISP_VICAP_CMD_SET_STREAM:
+		ret = rkisp_reset_handle(isp_dev);
+		if (!ret) {
+			if (isp_dev->hw_dev->monitor.state & ISP_CIF_RESET)
+				isp_dev->hw_dev->monitor.state &= ~ISP_CIF_RESET;
+		}
+		break;
+	case RKISP_VICAP_CMD_MODE:
+		ret = rkisp_set_work_mode_by_vicap(isp_dev, arg);
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -2594,7 +3623,9 @@
 	struct rkisp_meshbuf_size meshsize;
 	struct rkisp_thunderboot_shmem shmem;
 	struct isp2x_buf_idxfd idxfd;
+	struct rkisp_info2ddr info2ddr;
 	long ret = 0;
+	u64 module_id;
 
 	if (!up && cmd != RKISP_CMD_FREE_SHARED_BUF)
 		return -EINVAL;
@@ -2606,11 +3637,19 @@
 		ret = rkisp_ioctl(sd, cmd, &trigger);
 		break;
 	case RKISP_CMD_GET_SHARED_BUF:
+		if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP)) {
+			ret = -ENOIOCTLCMD;
+			break;
+		}
 		ret = rkisp_ioctl(sd, cmd, &resmem);
 		if (!ret && copy_to_user(up, &resmem, sizeof(resmem)))
 			ret = -EFAULT;
 		break;
 	case RKISP_CMD_FREE_SHARED_BUF:
+		if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP)) {
+			ret = -ENOIOCTLCMD;
+			break;
+		}
 		ret = rkisp_ioctl(sd, cmd, NULL);
 		break;
 	case RKISP_CMD_GET_LDCHBUF_INFO:
@@ -2624,7 +3663,7 @@
 		ret = rkisp_ioctl(sd, cmd, &ldchsize);
 		break;
 	case RKISP_CMD_GET_MESHBUF_INFO:
-		if (copy_from_user(&meshsize, up, sizeof(meshsize)))
+		if (copy_from_user(&meshbuf, up, sizeof(meshbuf)))
 			return -EFAULT;
 		ret = rkisp_ioctl(sd, cmd, &meshbuf);
 		if (!ret && copy_to_user(up, &meshbuf, sizeof(meshbuf)))
@@ -2636,6 +3675,10 @@
 		ret = rkisp_ioctl(sd, cmd, &meshsize);
 		break;
 	case RKISP_CMD_GET_SHM_BUFFD:
+		if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP)) {
+			ret = -ENOIOCTLCMD;
+			break;
+		}
 		if (copy_from_user(&shmem, up, sizeof(shmem)))
 			return -EFAULT;
 		ret = rkisp_ioctl(sd, cmd, &shmem);
@@ -2646,6 +3689,24 @@
 		ret = rkisp_ioctl(sd, cmd, &idxfd);
 		if (!ret && copy_to_user(up, &idxfd, sizeof(idxfd)))
 			ret = -EFAULT;
+		break;
+	case RKISP_CMD_INFO2DDR:
+		if (copy_from_user(&info2ddr, up, sizeof(info2ddr)))
+			return -EFAULT;
+		ret = rkisp_ioctl(sd, cmd, &info2ddr);
+		if (!ret && copy_to_user(up, &info2ddr, sizeof(info2ddr)))
+			ret = -EFAULT;
+		break;
+	case RKISP_CMD_MESHBUF_FREE:
+		if (copy_from_user(&module_id, up, sizeof(module_id)))
+			return -EFAULT;
+		ret = rkisp_ioctl(sd, cmd, &module_id);
+		break;
+	case RKISP_CMD_MULTI_DEV_FORCE_ENUM:
+		ret = rkisp_ioctl(sd, cmd, NULL);
+		break;
+	case RKISP_VICAP_CMD_SET_STREAM:
+		ret = rkisp_ioctl(sd, cmd, NULL);
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -2673,6 +3734,7 @@
 
 static const struct v4l2_subdev_video_ops rkisp_isp_sd_video_ops = {
 	.s_stream = rkisp_isp_sd_s_stream,
+	.s_rx_buffer = rkisp_sd_s_rx_buffer,
 };
 
 static const struct v4l2_subdev_core_ops rkisp_isp_core_ops = {
@@ -2699,7 +3761,7 @@
 	struct ispsd_in_fmt *in_fmt = &isp_sd->in_fmt;
 	struct ispsd_out_fmt *out_fmt = &isp_sd->out_fmt;
 
-	*in_fmt = rkisp_isp_input_formats[0];
+	*in_fmt = rkisp_isp_input_formats[8];
 	in_frm->width = RKISP_DEFAULT_WIDTH;
 	in_frm->height = RKISP_DEFAULT_HEIGHT;
 	in_frm->code = in_fmt->mbus_code;
@@ -2723,6 +3785,8 @@
 	struct v4l2_subdev *sd = &isp_sdev->sd;
 	int ret;
 
+	mutex_init(&isp_dev->buf_lock);
+	spin_lock_init(&isp_dev->cmsk_lock);
 	spin_lock_init(&isp_dev->rdbk_lock);
 	ret = kfifo_alloc(&isp_dev->rdbk_kfifo,
 		16 * sizeof(struct isp2x_csi_trigger), GFP_KERNEL);
@@ -2760,8 +3824,10 @@
 	rkisp_isp_sd_init_default_fmt(isp_sdev);
 	isp_dev->hdr.sensor = NULL;
 	isp_dev->isp_state = ISP_STOP;
-
+	atomic_set(&isp_sdev->frm_sync_seq, 0);
 	rkisp_monitor_init(isp_dev);
+	INIT_WORK(&isp_dev->rdbk_work, rkisp_rdbk_work);
+	init_completion(&isp_dev->pm_cmpl);
 	return 0;
 err_cleanup_media_entity:
 	media_entity_cleanup(&sd->entity);
@@ -2801,56 +3867,120 @@
 	(cond) ? 0 : -ETIMEDOUT; \
 })
 
+void rkisp_save_tb_info(struct rkisp_device *isp_dev)
+{
+	struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev;
+	void *resmem_va = phys_to_virt(isp_dev->resmem_pa);
+	struct rkisp_thunderboot_resmem_head *head = resmem_va;
+	int size = 0, offset = 0;
+	void *param = NULL;
+
+	switch (isp_dev->isp_ver) {
+	case ISP_V32:
+		size = sizeof(struct rkisp32_thunderboot_resmem_head);
+		offset = size * isp_dev->dev_id;
+		break;
+	default:
+		break;
+	}
+
+	if (size && size < isp_dev->resmem_size) {
+		dma_sync_single_for_cpu(isp_dev->dev, isp_dev->resmem_addr + offset,
+					size, DMA_FROM_DEVICE);
+		if (isp_dev->is_rtt_first)
+			params_vdev->is_first_cfg = true;
+		if (isp_dev->isp_ver == ISP_V32) {
+			struct rkisp32_thunderboot_resmem_head *tmp = resmem_va + offset;
+
+			param = &tmp->cfg;
+			head = &tmp->head;
+			v4l2_info(&isp_dev->v4l2_dev,
+				  "tb param module en:0x%llx upd:0x%llx cfg upd:0x%llx\n",
+				  tmp->cfg.module_en_update,
+				  tmp->cfg.module_ens,
+				  tmp->cfg.module_cfg_update);
+		}
+		if (param && (isp_dev->isp_state & ISP_STOP))
+			params_vdev->ops->save_first_param(params_vdev, param);
+	} else if (size > isp_dev->resmem_size) {
+		v4l2_err(&isp_dev->v4l2_dev,
+			 "resmem size:%zu no enough for head:%d\n",
+			 isp_dev->resmem_size, size);
+		head->complete = RKISP_TB_NG;
+	}
+	memcpy(&isp_dev->tb_head, head, sizeof(*head));
+}
+
 #ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP
 void rkisp_chk_tb_over(struct rkisp_device *isp_dev)
 {
+	struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev;
+	struct rkisp_hw_dev *hw = isp_dev->hw_dev;
 	struct rkisp_thunderboot_resmem_head *head;
 	enum rkisp_tb_state tb_state;
 	void *resmem_va;
 
-	if (!isp_dev->hw_dev->is_thunderboot)
+	if (!isp_dev->is_thunderboot)
 		return;
 
-	if (!atomic_read(&isp_dev->hw_dev->tb_ref)) {
-		rkisp_tb_set_state(RKISP_TB_NG);
-		rkisp_tb_unprotect_clk();
-		rkisp_register_irq(isp_dev->hw_dev);
-		isp_dev->hw_dev->is_thunderboot = false;
-		return;
-	}
+	if (isp_dev->isp_ver == ISP_V32 && params_vdev->is_first_cfg)
+		goto end;
 
 	resmem_va = phys_to_virt(isp_dev->resmem_pa);
 	head = (struct rkisp_thunderboot_resmem_head *)resmem_va;
-	if (isp_dev->is_thunderboot) {
-		shm_head_poll_timeout(isp_dev, !!head->enable, 2000, 200 * USEC_PER_MSEC);
-		shm_head_poll_timeout(isp_dev, !!head->complete, 5000, 600 * USEC_PER_MSEC);
-		if (head->complete != RKISP_TB_OK)
-			v4l2_info(&isp_dev->v4l2_dev,
-				  "wait thunderboot over timeout\n");
+	dma_sync_single_for_cpu(isp_dev->dev, isp_dev->resmem_addr,
+				sizeof(struct rkisp_thunderboot_resmem_head),
+				DMA_FROM_DEVICE);
 
-		v4l2_info(&isp_dev->v4l2_dev,
-			  "thunderboot info: %d, %d, %d, %d, %d, %d, 0x%x\n",
-			  head->enable,
-			  head->complete,
-			  head->frm_total,
-			  head->hdr_mode,
-			  head->width,
-			  head->height,
-			  head->bus_fmt);
+	shm_head_poll_timeout(isp_dev, !!head->complete, 5000, 400 * USEC_PER_MSEC);
+	if (head->complete != RKISP_TB_OK) {
+		v4l2_err(&isp_dev->v4l2_dev, "wait thunderboot over timeout\n");
+	} else {
+		int i, timeout = 50;
 
-		tb_state = RKISP_TB_OK;
-		if (head->complete != RKISP_TB_OK) {
-			head->frm_total = 0;
-			tb_state = RKISP_TB_NG;
+		/* wait for all isp dev to register */
+		if (head->camera_num > 1) {
+			while (timeout--) {
+				if (hw->dev_num >= head->camera_num &&
+				    hw->isp[hw->dev_num - 1]->is_probe_end)
+					break;
+				usleep_range(200, 210);
+			}
+			if (head->camera_num > hw->dev_num) {
+				v4l2_err(&isp_dev->v4l2_dev,
+					 "thunderboot invalid camera num:%d, dev num:%d\n",
+					 head->camera_num, hw->dev_num);
+				goto end;
+			}
 		}
+		for (i = 0; i < head->camera_num; i++)
+			rkisp_save_tb_info(hw->isp[i]);
+	}
+end:
+	head = &isp_dev->tb_head;
+	v4l2_info(&isp_dev->v4l2_dev,
+		  "tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d\n",
+		  head->enable,
+		  head->complete,
+		  head->frm_total,
+		  head->width,
+		  head->height,
+		  head->camera_num,
+		  head->camera_index);
+
+	tb_state = RKISP_TB_OK;
+	if (head->complete != RKISP_TB_OK) {
+		head->frm_total = 0;
+		tb_state = RKISP_TB_NG;
+	}
+
+	if (hw->is_thunderboot) {
+		rkisp_register_irq(hw);
 		rkisp_tb_set_state(tb_state);
 		rkisp_tb_unprotect_clk();
-		rkisp_register_irq(isp_dev->hw_dev);
-		pm_runtime_put(isp_dev->hw_dev->dev);
-		isp_dev->hw_dev->is_thunderboot = false;
-		isp_dev->is_thunderboot = false;
-		atomic_dec(&isp_dev->hw_dev->tb_ref);
+		hw->is_thunderboot = false;
 	}
+	isp_dev->is_thunderboot = false;
 }
 #endif
 
@@ -2958,7 +4088,9 @@
 		   unsigned int isp3a_mis,
 		   struct rkisp_device *dev)
 {
-	void __iomem *base = dev->base_addr;
+	struct rkisp_hw_dev *hw = dev->hw_dev;
+	void __iomem *base = hw->unite != ISP_UNITE_TWO ?
+		hw->base_addr : hw->base_next_addr;
 	unsigned int isp_mis_tmp = 0;
 	unsigned int isp_err = 0;
 	u32 si3a_isr_mask = ISP2X_SIAWB_DONE | ISP2X_SIAF_FIN |
@@ -2968,7 +4100,7 @@
 		ISP2X_3A_RAWHIST_BIG | ISP2X_3A_RAWHIST_CH0 |
 		ISP2X_3A_RAWHIST_CH1 | ISP2X_3A_RAWHIST_CH2 |
 		ISP2X_3A_RAWAF_SUM | ISP2X_3A_RAWAF_LUM |
-		ISP2X_3A_RAWAF | ISP2X_3A_RAWAWB;
+		ISP2X_3A_RAWAWB;
 	bool sof_event_later = false;
 
 	/*
@@ -2978,40 +4110,51 @@
 	if (isp3a_mis & ISP2X_3A_RAWAE_BIG && dev->params_vdev.rdbk_times > 0)
 		writel(BIT(31), base + RAWAE_BIG1_BASE + RAWAE_BIG_CTRL);
 
+	if (hw->unite == ISP_UNITE_TWO) {
+		u32 val = rkisp_read(dev, ISP3X_ISP_RIS, true);
+
+		if (val) {
+			rkisp_write(dev, ISP3X_ISP_ICR, val, true);
+			v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
+				 "left isp isr:0x%x\n", val);
+			if (isp_mis & CIF_ISP_FRAME && !(val & CIF_ISP_FRAME)) {
+				/* wait isp0 frame end */
+				int timeout = read_poll_timeout_atomic(rkisp_read,
+					val, val & CIF_ISP_FRAME, 20, 20 * 50, true, dev, ISP3X_ISP_RIS, true);
+
+				if (val)
+					rkisp_write(dev, ISP3X_ISP_ICR, val, true);
+				if (timeout)
+					dev_err(dev->dev, "wait isp end timeout\n");
+			}
+		}
+	}
 	v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
 		 "isp isr:0x%x, 0x%x\n", isp_mis, isp3a_mis);
 	dev->isp_isr_cnt++;
 	/* start edge of v_sync */
 	if (isp_mis & CIF_ISP_V_START) {
-		if (dev->isp_state & ISP_FRAME_END) {
-			u64 tmp = dev->isp_sdev.dbg.interval +
-					dev->isp_sdev.dbg.timestamp;
-
-			dev->isp_sdev.dbg.timestamp = ktime_get_ns();
-			/* v-blank: frame_end - frame_start */
-			dev->isp_sdev.dbg.delay = dev->isp_sdev.dbg.timestamp - tmp;
-		}
-		rkisp_set_state(&dev->isp_state, ISP_FRAME_VS);
 		if (dev->hw_dev->monitor.is_en) {
 			rkisp_set_state(&dev->hw_dev->monitor.state, ISP_FRAME_VS);
 			if (!completion_done(&dev->hw_dev->monitor.cmpl))
 				complete(&dev->hw_dev->monitor.cmpl);
 		}
-		/* last vsync to config next buf */
-		if (!dev->filt_state[RDBK_F_VS])
-			rkisp_bridge_update_mi(dev, isp_mis);
-		else
-			dev->filt_state[RDBK_F_VS]--;
+
 		if (IS_HDR_RDBK(dev->hdr.op_mode)) {
-			/* read 3d lut at isp readback */
-			if (!dev->hw_dev->is_single)
-				rkisp_write(dev, ISP_3DLUT_UPDATE, 0, true);
+			/* disabled frame end to read 3dlut for multi sensor
+			 * 3dlut will update at isp readback
+			 */
+			if (!dev->hw_dev->is_single) {
+				writel(0, hw->base_addr + ISP_3DLUT_UPDATE);
+				if (hw->unite == ISP_UNITE_TWO)
+					writel(0, hw->base_next_addr + ISP_3DLUT_UPDATE);
+			}
 			rkisp_stats_rdbk_enable(&dev->stats_vdev, true);
 			goto vs_skip;
 		}
 		if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced) {
 			/* 0 = ODD 1 = EVEN */
-			if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
+			if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) {
 				void __iomem *addr = NULL;
 
 				if (dev->isp_ver == ISP_V10 ||
@@ -3033,8 +4176,9 @@
 		if (isp_mis & CIF_ISP_FRAME)
 			sof_event_later = true;
 		if (dev->vs_irq < 0 && !sof_event_later) {
-			dev->isp_sdev.frm_timestamp = ktime_get_ns();
+			dev->isp_sdev.frm_timestamp = rkisp_time_get_ns(dev);
 			rkisp_isp_queue_event_sof(&dev->isp_sdev);
+			rkisp_stream_frame_start(dev, isp_mis);
 		}
 vs_skip:
 		writel(CIF_ISP_V_START, base + CIF_ISP_ICR);
@@ -3078,6 +4222,16 @@
 		}
 	}
 
+	if (isp3a_mis & ISP2X_3A_RAWAF) {
+		writel(ISP3X_3A_RAWAF, base + ISP3X_ISP_3A_ICR);
+		/* 3a irq will with lsc_lut_err irq if isp version below isp32 */
+		if (isp_mis & ISP2X_LSC_LUT_ERR)
+			isp_mis &= ~ISP2X_LSC_LUT_ERR;
+		if (dev->rawaf_irq_cnt == 0)
+			rkisp_stream_buf_done_early(dev);
+		dev->rawaf_irq_cnt++;
+	}
+
 	if (isp_mis & ISP2X_LSC_LUT_ERR) {
 		writel(ISP2X_LSC_LUT_ERR, base + CIF_ISP_ICR);
 
@@ -3089,21 +4243,22 @@
 
 	/* sampled input frame is complete */
 	if (isp_mis & CIF_ISP_FRAME_IN) {
+		dev->isp_sdev.dbg.interval =
+			rkisp_time_get_ns(dev) - dev->isp_sdev.dbg.timestamp;
 		rkisp_set_state(&dev->isp_state, ISP_FRAME_IN);
 		writel(CIF_ISP_FRAME_IN, base + CIF_ISP_ICR);
 		isp_mis_tmp = readl(base + CIF_ISP_MIS);
 		if (isp_mis_tmp & CIF_ISP_FRAME_IN)
 			v4l2_err(&dev->v4l2_dev, "isp icr frame_in err: 0x%x\n",
 				 isp_mis_tmp);
-
-		dev->isp_err_cnt = 0;
-		dev->isp_state &= ~ISP_ERROR;
 	}
 
 	/* frame was completely put out */
 	if (isp_mis & CIF_ISP_FRAME) {
-		dev->isp_sdev.dbg.interval =
-			ktime_get_ns() - dev->isp_sdev.dbg.timestamp;
+		dev->rawaf_irq_cnt = 0;
+		if (!dev->is_pre_on || !IS_HDR_RDBK(dev->rd_mode))
+			dev->isp_sdev.dbg.interval =
+				rkisp_time_get_ns(dev) - dev->isp_sdev.dbg.timestamp;
 		/* Clear Frame In (ISP) */
 		rkisp_set_state(&dev->isp_state, ISP_FRAME_END);
 		writel(CIF_ISP_FRAME, base + CIF_ISP_ICR);
@@ -3113,6 +4268,25 @@
 				 "isp icr frame end err: 0x%x\n", isp_mis_tmp);
 		rkisp_dmarx_get_frame(dev, &dev->isp_sdev.dbg.id, NULL, NULL, true);
 		rkisp_isp_read_add_fifo_data(dev);
+
+		dev->isp_err_cnt = 0;
+		dev->isp_state &= ~ISP_ERROR;
+	}
+
+	if (isp_mis & CIF_ISP_V_START) {
+		if (dev->isp_state & ISP_FRAME_END) {
+			u64 tmp = dev->isp_sdev.dbg.interval +
+					dev->isp_sdev.dbg.timestamp;
+
+			dev->isp_sdev.dbg.timestamp = rkisp_time_get_ns(dev);
+			/* v-blank: frame(N)start - frame(N-1)end */
+			dev->isp_sdev.dbg.delay = dev->isp_sdev.dbg.timestamp - tmp;
+		}
+		rkisp_set_state(&dev->isp_state, ISP_FRAME_VS);
+		if (dev->procfs.is_fs_wait) {
+			dev->procfs.is_fs_wait = false;
+			wake_up(&dev->procfs.fs_wait);
+		}
 	}
 
 	if ((isp_mis & (CIF_ISP_FRAME | si3a_isr_mask)) ||
@@ -3129,6 +4303,21 @@
 
 		if ((isp_mis & CIF_ISP_FRAME) && dev->stats_vdev.rdbk_mode)
 			rkisp_stats_rdbk_enable(&dev->stats_vdev, false);
+
+		if (!IS_HDR_RDBK(dev->hdr.op_mode))
+			rkisp_config_cmsk(dev);
+	}
+
+	if (isp_mis & CIF_ISP_FRAME) {
+		if (dev->hw_dev->isp_ver == ISP_V32) {
+			struct rkisp_stream *s = &dev->cap_dev.stream[RKISP_STREAM_LUMA];
+
+			s->ops->frame_end(s, FRAME_IRQ);
+		}
+		if (dev->procfs.is_fe_wait) {
+			dev->procfs.is_fe_wait = false;
+			wake_up(&dev->procfs.fe_wait);
+		}
 	}
 
 	/*
@@ -3136,16 +4325,30 @@
 	 * lot of register writes. Do those only one per frame.
 	 * Do the updates in the order of the processing flow.
 	 */
-	rkisp_params_isr(&dev->params_vdev, isp_mis);
+	if (isp_mis & (CIF_ISP_V_START | CIF_ISP_FRAME))
+		rkisp_params_isr(&dev->params_vdev, isp_mis);
 
 	/* cur frame end and next frame start irq togeter */
 	if (dev->vs_irq < 0 && sof_event_later) {
-		dev->isp_sdev.frm_timestamp = ktime_get_ns();
+		dev->isp_sdev.frm_timestamp = rkisp_time_get_ns(dev);
 		rkisp_isp_queue_event_sof(&dev->isp_sdev);
+		rkisp_stream_frame_start(dev, isp_mis);
 	}
 
-	if (isp_mis & CIF_ISP_FRAME_IN)
-		rkisp_check_idle(dev, ISP_FRAME_IN);
+	if (isp_mis & ISP3X_OUT_FRM_QUARTER) {
+		writel(ISP3X_OUT_FRM_QUARTER, base + CIF_ISP_ICR);
+		rkisp_dvbm_event(dev, ISP3X_OUT_FRM_QUARTER);
+	}
+	if (isp_mis & ISP3X_OUT_FRM_HALF) {
+		writel(ISP3X_OUT_FRM_HALF, base + CIF_ISP_ICR);
+		rkisp_dvbm_event(dev, ISP3X_OUT_FRM_HALF);
+		rkisp_stream_buf_done_early(dev);
+	}
+	if (isp_mis & ISP3X_OUT_FRM_END) {
+		writel(ISP3X_OUT_FRM_END, base + CIF_ISP_ICR);
+		rkisp_dvbm_event(dev, ISP3X_OUT_FRM_END);
+	}
+
 	if (isp_mis & CIF_ISP_FRAME)
 		rkisp_check_idle(dev, ISP_FRAME_END);
 }

--
Gitblit v1.6.2