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

---
 kernel/drivers/media/i2c/rk628/rk628_csi_v4l2.c |  215 +++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 166 insertions(+), 49 deletions(-)

diff --git a/kernel/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/kernel/drivers/media/i2c/rk628/rk628_csi_v4l2.c
index d8a39ca..7cb20b7 100644
--- a/kernel/drivers/media/i2c/rk628/rk628_csi_v4l2.c
+++ b/kernel/drivers/media/i2c/rk628/rk628_csi_v4l2.c
@@ -26,6 +26,7 @@
 #include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/workqueue.h>
+#include <linux/rk_hdmirx_class.h>
 #include <media/v4l2-controls_rockchip.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -54,10 +55,10 @@
 #define EDID_BLOCK_SIZE			128
 
 #define RK628_CSI_LINK_FREQ_LOW		350000000
-#define RK628_CSI_LINK_FREQ_HIGH	400000000
+#define RK628_CSI_LINK_FREQ_HIGH	600000000
 #define RK628_CSI_PIXEL_RATE_LOW	400000000
 #define RK628_CSI_PIXEL_RATE_HIGH	600000000
-#define MIPI_DATARATE_MBPS_LOW		750
+#define MIPI_DATARATE_MBPS_LOW		700
 #define MIPI_DATARATE_MBPS_HIGH		1250
 
 #define POLL_INTERVAL_MS		1000
@@ -126,12 +127,14 @@
 	bool hpd_output_inverted;
 	bool avi_rcv_rdy;
 	bool vid_ints_en;
+	bool continues_clk;
 	struct rk628_hdcp hdcp;
 	bool i2s_enable_default;
 	HAUDINFO audio_info;
 	struct rk628_combtxphy *txphy;
 	struct rk628_dsi dsi;
 	const struct rk628_plat_data *plat_data;
+	struct device *classdev;
 };
 
 struct rk628_csi_mode {
@@ -152,7 +155,7 @@
 	.type = V4L2_DV_BT_656_1120,
 	/* keep this initialization for compatibility with GCC < 4.4.6 */
 	.reserved = { 0 },
-	V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 400000000,
+	V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 600000000,
 			V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
 			V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
 			V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED |
@@ -194,6 +197,17 @@
 	0x16, 0x20, 0x58, 0x2C, 0x25, 0x00, 0xC0, 0x6C,
 	0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1,
+};
+
+static struct rkmodule_csi_dphy_param rk3588_dcphy_param = {
+	.vendor = PHY_VENDOR_SAMSUNG,
+	.lp_vol_ref = 0,
+	.lp_hys_sw = {3, 0, 0, 0},
+	.lp_escclk_pol_sel = {1, 0, 0, 0},
+	.skew_data_cal_clk = {0, 3, 3, 3},
+	.clk_hs_term_sel = 2,
+	.data_hs_term_sel = {2, 2, 2, 2},
+	.reserved = {0},
 };
 
 static const struct rk628_csi_mode supported_modes[] = {
@@ -492,6 +506,7 @@
 	mutex_lock(&csi->confctl_mutex);
 	csi->avi_rcv_rdy = false;
 	plugin = tx_5v_power_present(sd);
+	v4l2_ctrl_s_ctrl(csi->detect_tx_5v_ctrl, plugin);
 	v4l2_dbg(1, debug, sd, "%s: 5v_det:%d\n", __func__, plugin);
 	if (plugin) {
 		rk628_csi_enable_interrupts(sd, false);
@@ -872,7 +887,16 @@
 			BYPASS_SELECT(1));
 	rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD);
 	rk628_i2c_write(csi->rk628, CSITX_SYS_CTRL2, VOP_WHOLE_FRM_EN | VSYNC_ENABLE);
-	rk628_i2c_update_bits(csi->rk628, CSITX_SYS_CTRL3_IMD,
+	if (csi->continues_clk)
+		rk628_i2c_update_bits(csi->rk628, CSITX_SYS_CTRL3_IMD,
+			CONT_MODE_CLK_CLR_MASK |
+			CONT_MODE_CLK_SET_MASK |
+			NON_CONTINUOUS_MODE_MASK,
+			CONT_MODE_CLK_CLR(0) |
+			CONT_MODE_CLK_SET(1) |
+			NON_CONTINUOUS_MODE(0));
+	else
+		rk628_i2c_update_bits(csi->rk628, CSITX_SYS_CTRL3_IMD,
 			CONT_MODE_CLK_CLR_MASK |
 			CONT_MODE_CLK_SET_MASK |
 			NON_CONTINUOUS_MODE_MASK,
@@ -1476,21 +1500,6 @@
 	return 0;
 }
 
-static int rk628_csi_get_ctrl(struct v4l2_ctrl *ctrl)
-{
-	int ret = -1;
-	struct rk628_csi *csi = container_of(ctrl->handler, struct rk628_csi,
-			hdl);
-	struct v4l2_subdev *sd = &(csi->sd);
-
-	if (ctrl->id == V4L2_CID_DV_RX_POWER_PRESENT) {
-		ret = tx_5v_power_present(sd);
-		*ctrl->p_new.p_s32 = ret;
-	}
-
-	return ret;
-}
-
 static int rk628_csi_enum_frame_sizes(struct v4l2_subdev *sd,
 				   struct v4l2_subdev_pad_config *cfg,
 				   struct v4l2_subdev_frame_size_enum *fse)
@@ -1541,6 +1550,25 @@
 	format->format.field = csi->timings.bt.interlaced ?
 		V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
 	mutex_unlock(&csi->confctl_mutex);
+
+	if (((csi->timings.bt.width == 3840) && (csi->timings.bt.height == 2160)) ||
+		csi->csi_lanes_in_use <= 2) {
+		v4l2_dbg(1, debug, sd,
+			"%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n",
+			__func__, csi->timings.bt.width, csi->timings.bt.height,
+			link_freq_menu_items[1], RK628_CSI_PIXEL_RATE_HIGH);
+		__v4l2_ctrl_s_ctrl(csi->link_freq, 1);
+		__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate,
+			RK628_CSI_PIXEL_RATE_HIGH);
+	} else {
+		v4l2_dbg(1, debug, sd,
+			"%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n",
+			__func__, csi->timings.bt.width, csi->timings.bt.height,
+			link_freq_menu_items[0], RK628_CSI_PIXEL_RATE_LOW);
+		__v4l2_ctrl_s_ctrl(csi->link_freq, 0);
+		__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate,
+			RK628_CSI_PIXEL_RATE_LOW);
+	}
 
 	v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field code:%d\n",
 			__func__, format->format.code, format->format.width,
@@ -1614,24 +1642,6 @@
 	csi->mbus_fmt_code = format->format.code;
 	mode = rk628_csi_find_best_fit(format);
 	csi->cur_mode = mode;
-
-	if ((mode->width == 3840) && (mode->height == 2160)) {
-		v4l2_dbg(1, debug, sd,
-			"%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n",
-			__func__, mode->width, mode->height,
-			link_freq_menu_items[1], RK628_CSI_PIXEL_RATE_HIGH);
-		__v4l2_ctrl_s_ctrl(csi->link_freq, 1);
-		__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate,
-			RK628_CSI_PIXEL_RATE_HIGH);
-	} else {
-		v4l2_dbg(1, debug, sd,
-			"%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n",
-			__func__, mode->width, mode->height,
-			link_freq_menu_items[0], RK628_CSI_PIXEL_RATE_LOW);
-		__v4l2_ctrl_s_ctrl(csi->link_freq, 0);
-		__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate,
-			RK628_CSI_PIXEL_RATE_LOW);
-	}
 
 	enable_stream(sd, false);
 
@@ -1778,10 +1788,28 @@
 {
 	struct rk628_csi *csi = to_csi(sd);
 	long ret = 0;
+	struct rkmodule_csi_dphy_param *dphy_param;
 
 	switch (cmd) {
 	case RKMODULE_GET_MODULE_INFO:
 		rk628_csi_get_module_inf(csi, (struct rkmodule_inf *)arg);
+		break;
+	case RKMODULE_GET_HDMI_MODE:
+		*(int *)arg = RKMODULE_HDMIIN_MODE;
+		break;
+	case RKMODULE_SET_CSI_DPHY_PARAM:
+		dphy_param = (struct rkmodule_csi_dphy_param *)arg;
+		if (dphy_param->vendor == PHY_VENDOR_SAMSUNG)
+			rk3588_dcphy_param = *dphy_param;
+		v4l2_dbg(1, debug, sd,
+			"sensor set dphy param\n");
+		break;
+	case RKMODULE_GET_CSI_DPHY_PARAM:
+		dphy_param = (struct rkmodule_csi_dphy_param *)arg;
+		*dphy_param = rk3588_dcphy_param;
+
+		v4l2_dbg(1, debug, sd,
+			"sensor get dphy param\n");
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -1811,6 +1839,10 @@
 	rk628_txphy_set_bus_width(csi->rk628, bus_width);
 	rk628_txphy_set_mode(csi->rk628, PHY_MODE_VIDEO_MIPI);
 
+	if (csi->lane_mbps == MIPI_DATARATE_MBPS_HIGH)
+		mipi_dphy_init_hsmanual(csi->rk628, true);
+	else
+		mipi_dphy_init_hsmanual(csi->rk628, false);
 	mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps);
 	usleep_range(1500, 2000);
 	rk628_txphy_power_on(csi->rk628);
@@ -1840,6 +1872,8 @@
 	void __user *up = compat_ptr(arg);
 	struct rkmodule_inf *inf;
 	long ret;
+	int *seq;
+	struct rkmodule_csi_dphy_param *dphy_param;
 
 	switch (cmd) {
 	case RKMODULE_GET_MODULE_INFO:
@@ -1857,7 +1891,50 @@
 		}
 		kfree(inf);
 		break;
+	case RKMODULE_GET_HDMI_MODE:
+		seq = kzalloc(sizeof(*seq), GFP_KERNEL);
+		if (!seq) {
+			ret = -ENOMEM;
+			return ret;
+		}
 
+		ret = rk628_csi_ioctl(sd, cmd, seq);
+		if (!ret) {
+			ret = copy_to_user(up, seq, sizeof(*seq));
+			if (ret)
+				ret = -EFAULT;
+		}
+		kfree(seq);
+		break;
+	case RKMODULE_SET_CSI_DPHY_PARAM:
+		dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL);
+		if (!dphy_param) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = copy_from_user(dphy_param, up, sizeof(*dphy_param));
+		if (!ret)
+			ret = rk628_csi_ioctl(sd, cmd, dphy_param);
+		else
+			ret = -EFAULT;
+		kfree(dphy_param);
+		break;
+	case RKMODULE_GET_CSI_DPHY_PARAM:
+		dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL);
+		if (!dphy_param) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = rk628_csi_ioctl(sd, cmd, dphy_param);
+		if (!ret) {
+			ret = copy_to_user(up, dphy_param, sizeof(*dphy_param));
+			if (ret)
+				ret = -EFAULT;
+		}
+		kfree(dphy_param);
+		break;
 	default:
 		ret = -ENOIOCTLCMD;
 		break;
@@ -1866,10 +1943,6 @@
 	return ret;
 }
 #endif
-
-static const struct v4l2_ctrl_ops rk628_csi_ctrl_ops = {
-	.g_volatile_ctrl = rk628_csi_get_ctrl,
-};
 
 static const struct v4l2_subdev_core_ops rk628_csi_core_ops = {
 	.interrupt_service_routine = rk628_csi_isr,
@@ -1971,6 +2044,7 @@
 	int ret = -EINVAL;
 	bool hdcp1x_enable = false, i2s_enable_default = false;
 	bool scaler_en = false;
+	bool continues_clk = false;
 
 	csi->soc_24M = devm_clk_get(dev, "soc_24M");
 	if (csi->soc_24M == ERR_PTR(-ENOENT))
@@ -1986,21 +2060,21 @@
 	if (IS_ERR(csi->enable_gpio)) {
 		ret = PTR_ERR(csi->enable_gpio);
 		dev_err(dev, "failed to request enable GPIO: %d\n", ret);
-		return ret;
+		goto clk_put;
 	}
 
 	csi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(csi->reset_gpio)) {
 		ret = PTR_ERR(csi->reset_gpio);
 		dev_err(dev, "failed to request reset GPIO: %d\n", ret);
-		return ret;
+		goto clk_put;
 	}
 
 	csi->power_gpio = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_HIGH);
 	if (IS_ERR(csi->power_gpio)) {
 		dev_err(dev, "failed to get power gpio\n");
 		ret = PTR_ERR(csi->power_gpio);
-		return ret;
+		goto clk_put;
 	}
 
 	csi->plugin_det_gpio = devm_gpiod_get_optional(dev, "plugin-det",
@@ -2008,7 +2082,7 @@
 	if (IS_ERR(csi->plugin_det_gpio)) {
 		dev_err(dev, "failed to get hdmirx det gpio\n");
 		ret = PTR_ERR(csi->plugin_det_gpio);
-		return ret;
+		goto clk_put;
 	}
 
 	if (csi->enable_gpio) {
@@ -2043,10 +2117,14 @@
 	if (of_property_read_bool(dev->of_node, "scaler-en"))
 		scaler_en = true;
 
+	if (of_property_read_bool(dev->of_node, "continues-clk"))
+		continues_clk = true;
+
 	ep = of_graph_get_next_endpoint(dev->of_node, NULL);
 	if (!ep) {
 		dev_err(dev, "missing endpoint node\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto clk_put;
 	}
 
 	ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
@@ -2067,6 +2145,7 @@
 	csi->scaler_en = scaler_en;
 	if (csi->scaler_en)
 		csi->timings = dst_timing;
+	csi->continues_clk = continues_clk;
 
 	csi->rxphy_pwron = false;
 	csi->txphy_pwron = false;
@@ -2080,6 +2159,8 @@
 	v4l2_fwnode_endpoint_free(&endpoint);
 put_node:
 	of_node_put(ep);
+clk_put:
+	clk_disable_unprepare(csi->soc_24M);
 
 	return ret;
 }
@@ -2108,6 +2189,36 @@
 	{}
 };
 MODULE_DEVICE_TABLE(of, rk628_csi_of_match);
+
+static bool tx_5v_power_present(struct v4l2_subdev *sd);
+
+static ssize_t audio_rate_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct rk628_csi *csi = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d", rk628_hdmirx_audio_fs(csi->audio_info));
+}
+
+static ssize_t audio_present_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct rk628_csi *csi = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d",
+			tx_5v_power_present(&csi->sd) ?
+			rk628_hdmirx_audio_present(csi->audio_info) : 0);
+}
+
+static DEVICE_ATTR_RO(audio_rate);
+static DEVICE_ATTR_RO(audio_present);
+
+static struct attribute *rk628_attrs[] = {
+	&dev_attr_audio_rate.attr,
+	&dev_attr_audio_present.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(rk628);
 
 static int rk628_csi_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
@@ -2203,10 +2314,8 @@
 			V4L2_CID_PIXEL_RATE, 0, RK628_CSI_PIXEL_RATE_HIGH, 1,
 			RK628_CSI_PIXEL_RATE_HIGH);
 	csi->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&csi->hdl,
-			&rk628_csi_ctrl_ops, V4L2_CID_DV_RX_POWER_PRESENT,
+			NULL, V4L2_CID_DV_RX_POWER_PRESENT,
 			0, 1, 0, 0);
-	if (csi->detect_tx_5v_ctrl)
-		csi->detect_tx_5v_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
 
 	/* custom controls */
 	csi->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&csi->hdl,
@@ -2255,6 +2364,14 @@
 		goto err_hdl;
 	}
 
+	csi->classdev = device_create_with_groups(rk_hdmirx_class(),
+						  dev, MKDEV(0, 0),
+						  csi,
+						  rk628_groups,
+						  "rk628");
+	if (IS_ERR(csi->classdev))
+		goto err_hdl;
+
 	INIT_DELAYED_WORK(&csi->delayed_work_enable_hotplug,
 			rk628_csi_delayed_work_enable_hotplug);
 	INIT_DELAYED_WORK(&csi->delayed_work_res_change,

--
Gitblit v1.6.2