From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 02:45:28 +0000
Subject: [PATCH] add boot partition  size

---
 kernel/drivers/media/i2c/sc200ai.c |  472 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 411 insertions(+), 61 deletions(-)

diff --git a/kernel/drivers/media/i2c/sc200ai.c b/kernel/drivers/media/i2c/sc200ai.c
index 8b9dd82..e47fa1a 100644
--- a/kernel/drivers/media/i2c/sc200ai.c
+++ b/kernel/drivers/media/i2c/sc200ai.c
@@ -33,6 +33,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
 #include <linux/pinctrl/consumer.h>
+#include "../platform/rockchip/isp/rkisp_tb_helper.h"
 
 #define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x07)
 
@@ -46,6 +47,7 @@
 
 #define PIXEL_RATE_WITH_371M_10BIT		(SC200AI_LINK_FREQ_371 * 2 * \
 					SC200AI_LANES / SC200AI_BITS_PER_SAMPLE)
+
 #define SC200AI_XVCLK_FREQ		27000000
 
 #define CHIP_ID				0xcb1c
@@ -125,14 +127,6 @@
 
 #define SC200AI_NUM_SUPPLIES ARRAY_SIZE(sc200ai_supply_names)
 
-enum sc200ai_max_pad {
-	PAD0, /* link to isp */
-	PAD1, /* link to csi wr0 | hdr x2:L x3:M */
-	PAD2, /* link to csi wr1 | hdr      x3:L */
-	PAD3, /* link to csi wr2 | hdr x2:M x3:S */
-	PAD_MAX,
-};
-
 struct regval {
 	u16 addr;
 	u8 val;
@@ -172,6 +166,7 @@
 	struct v4l2_ctrl	*vblank;
 	struct v4l2_ctrl	*test_pattern;
 	struct mutex		mutex;
+	struct v4l2_fract	cur_fps;
 	bool			streaming;
 	bool			power_on;
 	const struct sc200ai_mode *cur_mode;
@@ -181,6 +176,8 @@
 	const char		*len_name;
 	u32			cur_vts;
 	bool			has_init_exp;
+	bool			is_thunderboot;
+	bool			is_first_streamoff;
 	struct preisp_hdrae_exp_s init_hdrae_exp;
 };
 
@@ -195,10 +192,10 @@
 
 /*
  * Xclk 24Mhz
- * max_framerate 90fps
+ * max_framerate 60fps
  * mipi_datarate per lane 1008Mbps, 4lane
  */
-static const struct regval sc200ai_linear_10_1920x1080_regs[] = {
+static const struct regval sc200ai_linear_10_1920x1080_60fps_regs[] = {
 	{0x0103, 0x01},
 	{0x0100, 0x00},
 	{0x36e9, 0x80},
@@ -338,6 +335,113 @@
 /*
  * Xclk 27Mhz
  * max_framerate 30fps
+ * mipi_datarate per lane 371.25Mbps, 2lane
+ */
+static const struct regval sc200ai_linear_10_1920x1080_30fps_regs[] = {
+	{0x0103, 0x01},
+	{0x0100, 0x00},
+	{0x36e9, 0x80},
+	{0x36f9, 0x80},
+	{0x301f, 0x03},
+	//HTS=1100*2=2200
+	{0x320c, 0x04},
+	{0x320d, 0x4c},
+	//VTS=1125
+	{0x320e, 0x04},
+	{0x320f, 0x65},
+	{0x3243, 0x01},
+	{0x3248, 0x02},
+	{0x3249, 0x09},
+	{0x3253, 0x08},
+	{0x3271, 0x0a},
+	{0x3301, 0x20},
+	{0x3304, 0x40},
+	{0x3306, 0x32},
+	{0x330b, 0x88},
+	{0x330f, 0x02},
+	{0x331e, 0x39},
+	{0x3333, 0x10},
+	{0x3621, 0xe8},
+	{0x3622, 0x16},
+	{0x3637, 0x1b},
+	{0x363a, 0x1f},
+	{0x363b, 0xc6},
+	{0x363c, 0x0e},
+	{0x3670, 0x0a},
+	{0x3674, 0x82},
+	{0x3675, 0x76},
+	{0x3676, 0x78},
+	{0x367c, 0x48},
+	{0x367d, 0x58},
+	{0x3690, 0x34},
+	{0x3691, 0x33},
+	{0x3692, 0x44},
+	{0x369c, 0x40},
+	{0x369d, 0x48},
+	{0x3901, 0x02},
+	{0x3904, 0x04},
+	{0x3908, 0x41},
+	{0x391d, 0x14},
+	{0x391f, 0x18},
+	{0x3e01, 0x8c},
+	{0x3e02, 0x20},
+	{0x3e16, 0x00},
+	{0x3e17, 0x80},
+	{0x3f09, 0x48},
+	{0x5787, 0x10},
+	{0x5788, 0x06},
+	{0x578a, 0x10},
+	{0x578b, 0x06},
+	{0x5790, 0x10},
+	{0x5791, 0x10},
+	{0x5792, 0x00},
+	{0x5793, 0x10},
+	{0x5794, 0x10},
+	{0x5795, 0x00},
+	{0x5799, 0x00},
+	{0x57c7, 0x10},
+	{0x57c8, 0x06},
+	{0x57ca, 0x10},
+	{0x57cb, 0x06},
+	{0x57d1, 0x10},
+	{0x57d4, 0x10},
+	{0x57d9, 0x00},
+	{0x59e0, 0x60},
+	{0x59e1, 0x08},
+	{0x59e2, 0x3f},
+	{0x59e3, 0x18},
+	{0x59e4, 0x18},
+	{0x59e5, 0x3f},
+	{0x59e6, 0x06},
+	{0x59e7, 0x02},
+	{0x59e8, 0x38},
+	{0x59e9, 0x10},
+	{0x59ea, 0x0c},
+	{0x59eb, 0x10},
+	{0x59ec, 0x04},
+	{0x59ed, 0x02},
+	{0x59ee, 0xa0},
+	{0x59ef, 0x08},
+	{0x59f4, 0x18},
+	{0x59f5, 0x10},
+	{0x59f6, 0x0c},
+	{0x59f7, 0x10},
+	{0x59f8, 0x06},
+	{0x59f9, 0x02},
+	{0x59fa, 0x18},
+	{0x59fb, 0x10},
+	{0x59fc, 0x0c},
+	{0x59fd, 0x10},
+	{0x59fe, 0x04},
+	{0x59ff, 0x02},
+	{0x36e9, 0x20},
+	{0x36f9, 0x27},
+	{REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 27Mhz
+ * max_framerate 30fps
  * mipi_datarate per lane 742.5Mbps, HDR 2lane
  */
 static const struct regval sc200ai_hdr_10_1920x1080_regs[] = {
@@ -346,8 +450,12 @@
 	{0x36e9, 0x80},
 	{0x36f9, 0x80},
 	{0x301f, 0x02},
+	//HTS=1100*2=2200
+	{0x320c, 0x04},
+	{0x320d, 0x4c},
+	//VTS =2252
 	{0x320e, 0x08},
-	{0x320f, 0xca},
+	{0x320f, 0xcc},
 	{0x3220, 0x53},
 	{0x3243, 0x01},
 	{0x3248, 0x02},
@@ -372,9 +480,11 @@
 	{0x331f, 0x61},
 	{0x3320, 0x07},
 	{0x3333, 0x10},
+	{0x3347, 0x77},
 	{0x334c, 0x08},
 	{0x3356, 0x09},
 	{0x3364, 0x17},
+	{0x336c, 0xcc},
 	{0x3390, 0x08},
 	{0x3391, 0x18},
 	{0x3392, 0x38},
@@ -431,8 +541,8 @@
 	{0x3e13, 0x40},
 	{0x3e16, 0x00},
 	{0x3e17, 0x80},
-	{0x3e23, 0x00},
-	{0x3e24, 0x40},
+	{0x3e23, 0x01},
+	{0x3e24, 0x9e},
 	{0x3f09, 0x48},
 	{0x4816, 0xb1},
 	{0x4819, 0x09},
@@ -501,13 +611,27 @@
 		.height = 1080,
 		.max_fps = {
 			.numerator = 10000,
+			.denominator = 300000,
+		},
+		.exp_def = 0x0080,
+		.hts_def = 0x44C * 2,
+		.vts_def = 0x0465,
+		.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,
+		.reg_list = sc200ai_linear_10_1920x1080_30fps_regs,
+		.hdr_mode = NO_HDR,
+		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
+	}, {
+		.width = 1920,
+		.height = 1080,
+		.max_fps = {
+			.numerator = 10000,
 			.denominator = 600000,
 		},
 		.exp_def = 0x0080,
 		.hts_def = 0x44C * 2,
 		.vts_def = 0x0465,
 		.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,
-		.reg_list = sc200ai_linear_10_1920x1080_regs,
+		.reg_list = sc200ai_linear_10_1920x1080_60fps_regs,
 		.hdr_mode = NO_HDR,
 		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
 	}, {
@@ -519,7 +643,7 @@
 		},
 		.exp_def = 0x0080,
 		.hts_def = 0x44C * 2,
-		.vts_def = 0x08CA,
+		.vts_def = 0x08CC,
 		.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,
 		.reg_list = sc200ai_hdr_10_1920x1080_regs,
 		.hdr_mode = HDR_X2,
@@ -814,8 +938,8 @@
 	s_exp_time = s_exp_time * 2;
 	if (l_exp_time > 4362)                  //(2250 - 64 - 5) * 2
 		l_exp_time = 4362;
-	if (s_exp_time > 118)                //(64 - 5) * 2
-		s_exp_time = 118;
+	if (s_exp_time > 404)                //(64 - 5) * 2
+		s_exp_time = 404;
 
 	ret = sc200ai_write_reg(sc200ai->client,
 				SC200AI_REG_EXPOSURE_H,
@@ -837,7 +961,6 @@
 				 SC200AI_REG_SEXPOSURE_L,
 				 SC200AI_REG_VALUE_08BIT,
 				 SC200AI_FETCH_EXP_L(s_exp_time));
-
 
 	ret |= sc200ai_set_gain_reg(sc200ai, l_a_gain, SC200AI_LGAIN);
 	ret |= sc200ai_set_gain_reg(sc200ai, s_a_gain, SC200AI_SGAIN);
@@ -902,6 +1025,8 @@
 		__v4l2_ctrl_modify_range(sc200ai->vblank, vblank_def,
 					 SC200AI_VTS_MAX - mode->height,
 					 1, vblank_def);
+		sc200ai->cur_fps = mode->max_fps;
+		sc200ai->cur_vts = mode->vts_def;
 	}
 
 	mutex_unlock(&sc200ai->mutex);
@@ -994,14 +1119,15 @@
 	struct sc200ai *sc200ai = to_sc200ai(sd);
 	const struct sc200ai_mode *mode = sc200ai->cur_mode;
 
-	mutex_lock(&sc200ai->mutex);
-	fi->interval = mode->max_fps;
-	mutex_unlock(&sc200ai->mutex);
+	if (sc200ai->streaming)
+		fi->interval = sc200ai->cur_fps;
+	else
+		fi->interval = mode->max_fps;
 
 	return 0;
 }
 
-static int sc200ai_g_mbus_config(struct v4l2_subdev *sd,
+static int sc200ai_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
 				 struct v4l2_mbus_config *config)
 {
 	struct sc200ai *sc200ai = to_sc200ai(sd);
@@ -1015,7 +1141,7 @@
 	if (mode->hdr_mode == HDR_X3)
 		val |= V4L2_MBUS_CSI2_CHANNEL_2;
 
-	config->type = V4L2_MBUS_CSI2;
+	config->type = V4L2_MBUS_CSI2_DPHY;
 	config->flags = val;
 
 	return 0;
@@ -1031,10 +1157,22 @@
 	strlcpy(inf->base.lens, sc200ai->len_name, sizeof(inf->base.lens));
 }
 
+static int sc200ai_get_channel_info(struct sc200ai *sc200ai, struct rkmodule_channel_info *ch_info)
+{
+	if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX)
+		return -EINVAL;
+	ch_info->vc = sc200ai->cur_mode->vc[ch_info->index];
+	ch_info->width = sc200ai->cur_mode->width;
+	ch_info->height = sc200ai->cur_mode->height;
+	ch_info->bus_fmt = sc200ai->cur_mode->bus_fmt;
+	return 0;
+}
+
 static long sc200ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	struct sc200ai *sc200ai = to_sc200ai(sd);
 	struct rkmodule_hdr_cfg *hdr;
+	struct rkmodule_channel_info *ch_info;
 	u32 i, h, w;
 	long ret = 0;
 	u32 stream = 0;
@@ -1071,6 +1209,8 @@
 			__v4l2_ctrl_modify_range(sc200ai->hblank, w, w, 1, w);
 			__v4l2_ctrl_modify_range(sc200ai->vblank, h,
 						 SC200AI_VTS_MAX - sc200ai->cur_mode->height, 1, h);
+			sc200ai->cur_fps = sc200ai->cur_mode->max_fps;
+			sc200ai->cur_vts = sc200ai->cur_mode->vts_def;
 		}
 		break;
 	case PREISP_CMD_SET_HDRAE_EXP:
@@ -1086,6 +1226,10 @@
 		else
 			ret = sc200ai_write_reg(sc200ai->client, SC200AI_REG_CTRL_MODE,
 				 SC200AI_REG_VALUE_08BIT, SC200AI_MODE_SW_STANDBY);
+		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = (struct rkmodule_channel_info *)arg;
+		ret = sc200ai_get_channel_info(sc200ai, ch_info);
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -1104,6 +1248,7 @@
 	struct rkmodule_awb_cfg *cfg;
 	struct rkmodule_hdr_cfg *hdr;
 	struct preisp_hdrae_exp_s *hdrae;
+	struct rkmodule_channel_info *ch_info;
 	long ret;
 	u32 stream = 0;
 
@@ -1116,8 +1261,11 @@
 		}
 
 		ret = sc200ai_ioctl(sd, cmd, inf);
-		if (!ret)
+		if (!ret) {
 			ret = copy_to_user(up, inf, sizeof(*inf));
+			if (ret)
+				ret = -EFAULT;
+		}
 		kfree(inf);
 		break;
 	case RKMODULE_AWB_CFG:
@@ -1130,6 +1278,8 @@
 		ret = copy_from_user(cfg, up, sizeof(*cfg));
 		if (!ret)
 			ret = sc200ai_ioctl(sd, cmd, cfg);
+		else
+			ret = -EFAULT;
 		kfree(cfg);
 		break;
 	case RKMODULE_GET_HDR_CFG:
@@ -1140,8 +1290,11 @@
 		}
 
 		ret = sc200ai_ioctl(sd, cmd, hdr);
-		if (!ret)
+		if (!ret) {
 			ret = copy_to_user(up, hdr, sizeof(*hdr));
+			if (ret)
+				ret = -EFAULT;
+		}
 		kfree(hdr);
 		break;
 	case RKMODULE_SET_HDR_CFG:
@@ -1154,6 +1307,8 @@
 		ret = copy_from_user(hdr, up, sizeof(*hdr));
 		if (!ret)
 			ret = sc200ai_ioctl(sd, cmd, hdr);
+		else
+			ret = -EFAULT;
 		kfree(hdr);
 		break;
 	case PREISP_CMD_SET_HDRAE_EXP:
@@ -1166,12 +1321,31 @@
 		ret = copy_from_user(hdrae, up, sizeof(*hdrae));
 		if (!ret)
 			ret = sc200ai_ioctl(sd, cmd, hdrae);
+		else
+			ret = -EFAULT;
 		kfree(hdrae);
 		break;
 	case RKMODULE_SET_QUICK_STREAM:
 		ret = copy_from_user(&stream, up, sizeof(u32));
 		if (!ret)
 			ret = sc200ai_ioctl(sd, cmd, &stream);
+		else
+			ret = -EFAULT;
+		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
+		if (!ch_info) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = sc200ai_ioctl(sd, cmd, ch_info);
+		if (!ret) {
+			ret = copy_to_user(up, ch_info, sizeof(*ch_info));
+			if (ret)
+				ret = -EFAULT;
+		}
+		kfree(ch_info);
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -1186,21 +1360,30 @@
 {
 	int ret;
 
-	ret = sc200ai_write_array(sc200ai->client, sc200ai->cur_mode->reg_list);
-	if (ret)
-		return ret;
-
-	/* In case these controls are set before streaming */
-	ret = __v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler);
-	if (ret)
-		return ret;
-	if (sc200ai->has_init_exp && sc200ai->cur_mode->hdr_mode != NO_HDR) {
-		ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP,
-			&sc200ai->init_hdrae_exp);
-		if (ret) {
-			dev_err(&sc200ai->client->dev,
-				"init exp fail in hdr mode\n");
+	dev_info(&sc200ai->client->dev,
+		 "%dx%d@%d, mode %d, vts 0x%x\n",
+		 sc200ai->cur_mode->width,
+		 sc200ai->cur_mode->height,
+		 sc200ai->cur_fps.denominator / sc200ai->cur_fps.numerator,
+		 sc200ai->cur_mode->hdr_mode,
+		 sc200ai->cur_vts);
+	if (!sc200ai->is_thunderboot) {
+		ret = sc200ai_write_array(sc200ai->client, sc200ai->cur_mode->reg_list);
+		if (ret)
 			return ret;
+
+		/* In case these controls are set before streaming */
+		ret = __v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler);
+		if (ret)
+			return ret;
+		if (sc200ai->has_init_exp && sc200ai->cur_mode->hdr_mode != NO_HDR) {
+			ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP,
+				&sc200ai->init_hdrae_exp);
+			if (ret) {
+				dev_err(&sc200ai->client->dev,
+					"init exp fail in hdr mode\n");
+				return ret;
+			}
 		}
 	}
 
@@ -1211,10 +1394,15 @@
 static int __sc200ai_stop_stream(struct sc200ai *sc200ai)
 {
 	sc200ai->has_init_exp = false;
+	if (sc200ai->is_thunderboot) {
+		sc200ai->is_first_streamoff = true;
+		pm_runtime_put(&sc200ai->client->dev);
+	}
 	return sc200ai_write_reg(sc200ai->client, SC200AI_REG_CTRL_MODE,
 				 SC200AI_REG_VALUE_08BIT, SC200AI_MODE_SW_STANDBY);
 }
 
+static int __sc200ai_power_on(struct sc200ai *sc200ai);
 static int sc200ai_s_stream(struct v4l2_subdev *sd, int on)
 {
 	struct sc200ai *sc200ai = to_sc200ai(sd);
@@ -1227,6 +1415,10 @@
 		goto unlock_and_return;
 
 	if (on) {
+		if (sc200ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) {
+			sc200ai->is_thunderboot = false;
+			__sc200ai_power_on(sc200ai);
+		}
 		ret = pm_runtime_get_sync(&client->dev);
 		if (ret < 0) {
 			pm_runtime_put_noidle(&client->dev);
@@ -1271,11 +1463,13 @@
 			goto unlock_and_return;
 		}
 
-		ret = sc200ai_write_array(sc200ai->client, sc200ai_global_regs);
-		if (ret) {
-			v4l2_err(sd, "could not set init registers\n");
-			pm_runtime_put_noidle(&client->dev);
-			goto unlock_and_return;
+		if (!sc200ai->is_thunderboot) {
+			ret = sc200ai_write_array(sc200ai->client, sc200ai_global_regs);
+			if (ret) {
+				v4l2_err(sd, "could not set init registers\n");
+				pm_runtime_put_noidle(&client->dev);
+				goto unlock_and_return;
+			}
 		}
 
 		sc200ai->power_on = true;
@@ -1318,6 +1512,9 @@
 		dev_err(dev, "Failed to enable xvclk\n");
 		return ret;
 	}
+	if (sc200ai->is_thunderboot)
+		return 0;
+
 	if (!IS_ERR(sc200ai->reset_gpio))
 		gpiod_set_value_cansleep(sc200ai->reset_gpio, 0);
 
@@ -1356,6 +1553,15 @@
 	int ret;
 	struct device *dev = &sc200ai->client->dev;
 
+	clk_disable_unprepare(sc200ai->xvclk);
+	if (sc200ai->is_thunderboot) {
+		if (sc200ai->is_first_streamoff) {
+			sc200ai->is_thunderboot = false;
+			sc200ai->is_first_streamoff = false;
+		} else {
+			return;
+		}
+	}
 	if (!IS_ERR(sc200ai->pwdn_gpio))
 		gpiod_set_value_cansleep(sc200ai->pwdn_gpio, 0);
 	clk_disable_unprepare(sc200ai->xvclk);
@@ -1449,7 +1655,6 @@
 static const struct v4l2_subdev_video_ops sc200ai_video_ops = {
 	.s_stream = sc200ai_s_stream,
 	.g_frame_interval = sc200ai_g_frame_interval,
-	.g_mbus_config = sc200ai_g_mbus_config,
 };
 
 static const struct v4l2_subdev_pad_ops sc200ai_pad_ops = {
@@ -1458,6 +1663,7 @@
 	.enum_frame_interval = sc200ai_enum_frame_interval,
 	.get_fmt = sc200ai_get_fmt,
 	.set_fmt = sc200ai_set_fmt,
+	.get_mbus_config = sc200ai_g_mbus_config,
 };
 
 static const struct v4l2_subdev_ops sc200ai_subdev_ops = {
@@ -1465,6 +1671,14 @@
 	.video	= &sc200ai_video_ops,
 	.pad	= &sc200ai_pad_ops,
 };
+
+static void sc200ai_modify_fps_info(struct sc200ai *sc200ai)
+{
+	const struct sc200ai_mode *mode = sc200ai->cur_mode;
+
+	sc200ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def/
+				       sc200ai->cur_vts;
+}
 
 static int sc200ai_set_ctrl(struct v4l2_ctrl *ctrl)
 {
@@ -1528,7 +1742,10 @@
 					 SC200AI_REG_VALUE_08BIT,
 					 (ctrl->val + sc200ai->cur_mode->height)
 					 & 0xff);
-		sc200ai->cur_vts = ctrl->val + sc200ai->cur_mode->height;
+		if (!ret)
+			sc200ai->cur_vts = ctrl->val + sc200ai->cur_mode->height;
+		if (sc200ai->cur_vts != sc200ai->cur_mode->vts_def)
+			sc200ai_modify_fps_info(sc200ai);
 		break;
 	case V4L2_CID_TEST_PATTERN:
 		ret = sc200ai_enable_test_pattern(sc200ai, ctrl->val);
@@ -1591,12 +1808,14 @@
 					    h_blank, h_blank, 1, h_blank);
 	if (sc200ai->hblank)
 		sc200ai->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	sc200ai->cur_fps = mode->max_fps;
 	vblank_def = mode->vts_def - mode->height;
+	sc200ai->cur_vts = mode->vts_def;
 	sc200ai->vblank = v4l2_ctrl_new_std(handler, &sc200ai_ctrl_ops,
 					    V4L2_CID_VBLANK, vblank_def,
 					    SC200AI_VTS_MAX - mode->height,
 					    1, vblank_def);
-	exposure_max = mode->vts_def - 4;
+	exposure_max = 2 * mode->vts_def - 8;
 	sc200ai->exposure = v4l2_ctrl_new_std(handler, &sc200ai_ctrl_ops,
 					      V4L2_CID_EXPOSURE, SC200AI_EXPOSURE_MIN,
 					      exposure_max, SC200AI_EXPOSURE_STEP,
@@ -1641,6 +1860,11 @@
 	u32 id = 0;
 	int ret;
 
+	if (sc200ai->is_thunderboot) {
+		dev_info(dev, "Enable thunderboot mode, skip sensor id check\n");
+		return 0;
+	}
+
 	ret = sc200ai_read_reg(client, SC200AI_REG_CHIP_ID,
 			       SC200AI_REG_VALUE_16BIT, &id);
 	if (id != CHIP_ID) {
@@ -1665,6 +1889,132 @@
 				       sc200ai->supplies);
 }
 
+#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP
+static u32 rk_cam_hdr;
+static u32 rk_cam_w;
+static u32 rk_cam_h;
+static u32 rk_cam_fps;
+
+static int __init __maybe_unused rk_cam_hdr_setup(char *str)
+{
+	int ret = 0;
+	unsigned long val = 0;
+
+	ret = kstrtoul(str, 0, &val);
+	if (!ret)
+		rk_cam_hdr = (u32)val;
+	else
+		pr_err("get rk_cam_hdr fail\n");
+	return 1;
+}
+
+static int __init __maybe_unused rk_cam_w_setup(char *str)
+{
+	int ret = 0;
+	unsigned long val = 0;
+
+	ret = kstrtoul(str, 0, &val);
+	if (!ret)
+		rk_cam_w = (u32)val;
+	else
+		pr_err("get rk_cam_w fail\n");
+	return 1;
+}
+
+static int __init __maybe_unused rk_cam_h_setup(char *str)
+{
+	int ret = 0;
+	unsigned long val = 0;
+
+	ret = kstrtoul(str, 0, &val);
+	if (!ret)
+		rk_cam_h = (u32)val;
+	else
+		pr_err("get rk_cam_h fail\n");
+	return 1;
+}
+
+static int __init __maybe_unused rk_cam_fps_setup(char *str)
+{
+	int ret = 0;
+	unsigned long val = 0;
+
+	ret = kstrtoul(str, 0, &val);
+	if (!ret)
+		rk_cam_fps = (u32)val;
+	else
+		pr_err("get rk_cam_fps fail\n");
+	return 1;
+}
+
+__setup("rk_cam_hdr=", rk_cam_hdr_setup);
+__setup("rk_cam_w=", rk_cam_w_setup);
+__setup("rk_cam_h=", rk_cam_h_setup);
+__setup("rk_cam_fps=", rk_cam_fps_setup);
+
+static void find_terminal_resolution(struct sc200ai *sc200ai)
+{
+	int i = 0;
+	const struct sc200ai_mode *mode = NULL;
+	const struct sc200ai_mode *fit_mode = NULL;
+	u32 cur_fps = 0;
+	u32 dst_fps = 0;
+	u32 tmp_fps = 0;
+
+	if (rk_cam_w == 0 || rk_cam_h == 0 ||
+	    rk_cam_fps == 0)
+		goto err_find_res;
+
+	dst_fps = rk_cam_fps;
+	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+		mode = &supported_modes[i];
+		cur_fps = mode->max_fps.denominator / mode->max_fps.numerator;
+		if (mode->width == rk_cam_w && mode->height == rk_cam_h &&
+		    mode->hdr_mode == rk_cam_hdr) {
+			if (cur_fps == dst_fps) {
+				sc200ai->cur_mode = mode;
+				return;
+			}
+			if (cur_fps >= dst_fps) {
+				if (fit_mode) {
+					tmp_fps = fit_mode->max_fps.denominator / fit_mode->max_fps.numerator;
+					if (tmp_fps - dst_fps > cur_fps - dst_fps)
+						fit_mode = mode;
+				} else {
+					fit_mode = mode;
+				}
+			}
+		}
+	}
+	if (fit_mode) {
+		sc200ai->cur_mode = fit_mode;
+		return;
+	}
+err_find_res:
+	dev_err(&sc200ai->client->dev, "not match %dx%d@%dfps mode %d\n!",
+		rk_cam_w, rk_cam_h, dst_fps, rk_cam_hdr);
+	sc200ai->cur_mode = &supported_modes[0];
+}
+#else
+static void find_terminal_resolution(struct sc200ai *sc200ai)
+{
+	u32 hdr_mode = 0;
+	struct device_node *node = sc200ai->client->dev.of_node;
+	int i = 0;
+
+	of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode);
+	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+		if (hdr_mode == supported_modes[i].hdr_mode) {
+			sc200ai->cur_mode = &supported_modes[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(supported_modes))
+		sc200ai->cur_mode = &supported_modes[0];
+
+}
+#endif
+
 static int sc200ai_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -1674,7 +2024,6 @@
 	struct v4l2_subdev *sd;
 	char facing[2];
 	int ret;
-	u32 i, hdr_mode = 0;
 
 	dev_info(dev, "driver version: %02x.%02x.%02x",
 		 DRIVER_VERSION >> 16,
@@ -1685,7 +2034,6 @@
 	if (!sc200ai)
 		return -ENOMEM;
 
-	of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode);
 	ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
 				   &sc200ai->module_index);
 	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
@@ -1699,15 +2047,10 @@
 		return -EINVAL;
 	}
 
+	sc200ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP);
 	sc200ai->client = client;
-	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
-		if (hdr_mode == supported_modes[i].hdr_mode) {
-			sc200ai->cur_mode = &supported_modes[i];
-			break;
-		}
-	}
-	if (i == ARRAY_SIZE(supported_modes))
-		sc200ai->cur_mode = &supported_modes[0];
+
+	find_terminal_resolution(sc200ai);
 
 	sc200ai->xvclk = devm_clk_get(dev, "xvclk");
 	if (IS_ERR(sc200ai->xvclk)) {
@@ -1715,11 +2058,11 @@
 		return -EINVAL;
 	}
 
-	sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
 	if (IS_ERR(sc200ai->reset_gpio))
 		dev_warn(dev, "Failed to get reset-gpios\n");
 
-	sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
+	sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS);
 	if (IS_ERR(sc200ai->pwdn_gpio))
 		dev_warn(dev, "Failed to get pwdn-gpios\n");
 
@@ -1792,7 +2135,10 @@
 
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
-	pm_runtime_idle(dev);
+	if (sc200ai->is_thunderboot)
+		pm_runtime_get_sync(dev);
+	else
+		pm_runtime_idle(dev);
 
 	return 0;
 
@@ -1864,8 +2210,12 @@
 	i2c_del_driver(&sc200ai_i2c_driver);
 }
 
+#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC)
+subsys_initcall(sensor_mod_init);
+#else
 device_initcall_sync(sensor_mod_init);
+#endif
 module_exit(sensor_mod_exit);
 
 MODULE_DESCRIPTION("smartsens sc200ai sensor driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");

--
Gitblit v1.6.2