From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp

---
 kernel/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c |  308 +++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 238 insertions(+), 70 deletions(-)

diff --git a/kernel/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c b/kernel/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c
index 33e777b..81827de 100644
--- a/kernel/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c
+++ b/kernel/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c
@@ -21,7 +21,9 @@
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-device.h>
+#include <linux/phy/phy.h>
 #include "phy-rockchip-csi2-dphy-common.h"
+#include "phy-rockchip-samsung-dcphy.h"
 
 struct sensor_async_subdev {
 	struct v4l2_async_subdev asd;
@@ -29,7 +31,6 @@
 	int lanes;
 };
 
-static DEFINE_MUTEX(csi2dphy_dev_mutex);
 static LIST_HEAD(csi2dphy_device_list);
 
 static inline struct csi2_dphy *to_csi2_dphy(struct v4l2_subdev *subdev)
@@ -73,6 +74,9 @@
 	struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ, };
 	int ret;
 
+	if (!sensor_sd)
+		return -ENODEV;
+
 	link_freq = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_LINK_FREQ);
 	if (!link_freq) {
 		v4l2_warn(sd, "No pixel rate control in subdev\n");
@@ -101,11 +105,18 @@
 {
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
-	struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd);
+	struct csi2_sensor *sensor;
 	struct v4l2_mbus_config mbus;
+	struct rkmodule_bus_config bus_config;
 	int ret;
 
-	ret = v4l2_subdev_call(sensor_sd, video, g_mbus_config, &mbus);
+	if (!sensor_sd)
+		return -ENODEV;
+	sensor = sd_to_sensor(dphy, sensor_sd);
+	if (!sensor)
+		return -ENODEV;
+
+	ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, &mbus);
 	if (ret)
 		return ret;
 
@@ -126,14 +137,69 @@
 	default:
 		return -EINVAL;
 	}
-
-	return 0;
+	if (dphy->drv_data->vendor == PHY_VENDOR_INNO) {
+		ret = v4l2_subdev_call(sensor_sd, core, ioctl,
+				       RKMODULE_GET_BUS_CONFIG, &bus_config);
+		if (!ret) {
+			dev_info(dphy->dev, "phy_mode %d,lane %d\n",
+				bus_config.bus.phy_mode, bus_config.bus.lanes);
+			if (bus_config.bus.phy_mode == PHY_FULL_MODE) {
+				if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588 &&
+				    dphy->phy_index % 3 == 2) {
+					dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n",
+						__func__, dphy->phy_index);
+					ret = -EINVAL;
+				}
+				dphy->lane_mode = LANE_MODE_FULL;
+			} else if (bus_config.bus.phy_mode == PHY_SPLIT_01) {
+				if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588_DCPHY) {
+					dev_err(dphy->dev, "%s The chip not support split mode\n",
+						__func__);
+					ret = -EINVAL;
+				} else if (dphy->phy_index % 3 == 2) {
+					dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n",
+						__func__, dphy->phy_index);
+					ret = -EINVAL;
+				} else {
+					dphy->lane_mode = LANE_MODE_SPLIT;
+				}
+			} else if (bus_config.bus.phy_mode == PHY_SPLIT_23) {
+				if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588_DCPHY) {
+					dev_err(dphy->dev, "%s The chip not support split mode\n",
+						__func__);
+					ret = -EINVAL;
+				} else if (dphy->phy_index % 3 != 2) {
+					dev_err(dphy->dev, "%s dphy%d not support PHY_SPLIT_23\n",
+						__func__, dphy->phy_index);
+					ret = -EINVAL;
+				} else {
+					dphy->lane_mode = LANE_MODE_SPLIT;
+				}
+			}
+			if (!ret)
+				dphy->dphy_hw->lane_mode = dphy->lane_mode;
+		} else {
+			ret = 0;
+		}
+	}
+	if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) {
+		ret = v4l2_subdev_call(sensor_sd, core, ioctl,
+				       RKMODULE_GET_CSI_DPHY_PARAM,
+				       &dphy->dphy_param);
+		if (ret) {
+			dev_dbg(dphy->dev, "%s fail to get dphy param, used default value\n",
+				__func__);
+			ret = 0;
+		}
+	}
+	return ret;
 }
 
 static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd)
 {
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct csi2_dphy_hw *hw = dphy->dphy_hw;
+	struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy;
 	int  ret = 0;
 
 	if (dphy->is_streaming)
@@ -145,8 +211,13 @@
 
 	csi2_dphy_update_sensor_mbus(sd);
 
-	if (hw->stream_on)
-		hw->stream_on(dphy, sd);
+	if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) {
+		if (samsung_phy && samsung_phy->stream_on)
+			samsung_phy->stream_on(dphy, sd);
+	} else {
+		if (hw->stream_on)
+			hw->stream_on(dphy, sd);
+	}
 
 	dphy->is_streaming = true;
 
@@ -157,12 +228,18 @@
 {
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct csi2_dphy_hw *hw = dphy->dphy_hw;
+	struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy;
 
 	if (!dphy->is_streaming)
 		return 0;
 
-	if (hw->stream_off)
-		hw->stream_off(dphy, sd);
+	if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) {
+		if (samsung_phy && samsung_phy->stream_off)
+			samsung_phy->stream_off(dphy, sd);
+	} else {
+		if (hw->stream_off)
+			hw->stream_off(dphy, sd);
+	}
 
 	dphy->is_streaming = false;
 
@@ -202,7 +279,8 @@
 }
 
 static int csi2_dphy_g_mbus_config(struct v4l2_subdev *sd,
-				  struct v4l2_mbus_config *config)
+				   unsigned int pad_id,
+				   struct v4l2_mbus_config *config)
 {
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
@@ -211,6 +289,8 @@
 	if (!sensor_sd)
 		return -ENODEV;
 	sensor = sd_to_sensor(dphy, sensor_sd);
+	if (!sensor)
+		return -ENODEV;
 	csi2_dphy_update_sensor_mbus(sd);
 	*config = sensor->mbus;
 
@@ -233,9 +313,15 @@
 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct csi2_dphy_hw *hw = dphy->dphy_hw;
+	struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy;
 
-	if (hw)
-		clk_bulk_disable_unprepare(hw->num_clks, hw->clks);
+	if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) {
+		if (samsung_phy)
+			clk_disable_unprepare(samsung_phy->pclk);
+	} else {
+		if (hw)
+			clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk);
+	}
 
 	return 0;
 }
@@ -246,13 +332,19 @@
 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct csi2_dphy_hw *hw = dphy->dphy_hw;
+	struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy;
 	int ret;
 
-	if (hw) {
-		ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks);
-		if (ret) {
-			dev_err(hw->dev, "failed to enable clks\n");
-			return ret;
+	if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) {
+		if (samsung_phy)
+			clk_prepare_enable(samsung_phy->pclk);
+	} else {
+		if (hw) {
+			ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks_bulk);
+			if (ret) {
+				dev_err(hw->dev, "failed to enable clks\n");
+				return ret;
+			}
 		}
 	}
 
@@ -266,7 +358,7 @@
 {
 	struct csi2_dphy *dphy = to_csi2_dphy(sd);
 	struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
-	struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd);
+	struct csi2_sensor *sensor;
 	int ret;
 	/*
 	 * Do not allow format changes and just relay whatever
@@ -274,8 +366,11 @@
 	 */
 	if (!sensor_sd)
 		return -ENODEV;
+	sensor = sd_to_sensor(dphy, sensor_sd);
+	if (!sensor)
+		return -ENODEV;
 	ret = v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, fmt);
-	if (!ret && fmt->pad == 0)
+	if (!ret && fmt->pad == 0 && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 		sensor->format = fmt->format;
 	return ret;
 }
@@ -295,7 +390,6 @@
 
 static const struct v4l2_subdev_video_ops csi2_dphy_video_ops = {
 	.g_frame_interval = csi2_dphy_g_frame_interval,
-	.g_mbus_config = csi2_dphy_g_mbus_config,
 	.s_stream = csi2_dphy_s_stream,
 };
 
@@ -303,6 +397,7 @@
 	.set_fmt = csi2_dphy_get_set_fmt,
 	.get_fmt = csi2_dphy_get_set_fmt,
 	.get_selection = csi2_dphy_get_selection,
+	.get_mbus_config = csi2_dphy_g_mbus_config,
 };
 
 static const struct v4l2_subdev_ops csi2_dphy_subdev_ops = {
@@ -373,7 +468,8 @@
 						  notifier);
 	struct csi2_sensor *sensor = sd_to_sensor(dphy, sd);
 
-	sensor->sd = NULL;
+	if (sensor)
+		sensor->sd = NULL;
 }
 
 static const struct
@@ -395,10 +491,13 @@
 		return -EINVAL;
 	}
 
-	if (vep->bus_type == V4L2_MBUS_CSI2) {
-		config->type = V4L2_MBUS_CSI2;
+	if (vep->bus_type == V4L2_MBUS_CSI2_DPHY) {
+		config->type = V4L2_MBUS_CSI2_DPHY;
 		config->flags = vep->bus.mipi_csi2.flags;
 		s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
+	} else if (vep->bus_type == V4L2_MBUS_CCP2) {
+		config->type = V4L2_MBUS_CCP2;
+		s_asd->lanes = vep->bus.mipi_csi1.data_lane;
 	} else {
 		dev_err(dev, "Only CSI2 type is currently supported\n");
 		return -EINVAL;
@@ -438,15 +537,14 @@
 	if (ret < 0)
 		return ret;
 
+	v4l2_async_notifier_init(&dphy->notifier);
+
 	ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
 		dphy->dev, &dphy->notifier,
 		sizeof(struct sensor_async_subdev), 0,
 		rockchip_csi2_dphy_fwnode_parse);
 	if (ret < 0)
 		return ret;
-
-	if (!dphy->notifier.num_subdevs)
-		return -ENODEV;	/* no endpoint */
 
 	dphy->sd.subdev_notifier = &dphy->notifier;
 	dphy->notifier.ops = &rockchip_csi2_dphy_async_ops;
@@ -461,6 +559,47 @@
 	return v4l2_async_register_subdev(&dphy->sd);
 }
 
+static int rockchip_csi2_dphy_attach_samsung_phy(struct csi2_dphy *dphy)
+{
+	struct device *dev = dphy->dev;
+	struct phy *dcphy;
+	struct samsung_mipi_dcphy *dphy_hw;
+	int ret = 0;
+
+	dcphy = devm_phy_optional_get(dev, "dcphy");
+	if (IS_ERR(dcphy)) {
+		ret = PTR_ERR(dcphy);
+		dev_err(dphy->dev, "failed to get mipi dcphy: %d\n", ret);
+		return ret;
+	}
+
+	dphy_hw = phy_get_drvdata(dcphy);
+	dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy;
+	dphy_hw->dphy_dev_num++;
+	dphy->samsung_phy = dphy_hw;
+
+	return 0;
+}
+
+static int rockchip_csi2_dphy_detach_samsung_phy(struct csi2_dphy *dphy)
+{
+	struct samsung_mipi_dcphy *dphy_hw = dphy->samsung_phy;
+	struct csi2_dphy *csi2_dphy = NULL;
+	int i;
+
+	for (i = 0; i < dphy_hw->dphy_dev_num; i++) {
+		csi2_dphy = dphy_hw->dphy_dev[i];
+		if (csi2_dphy &&
+		    csi2_dphy->phy_index == dphy->phy_index) {
+			dphy_hw->dphy_dev[i] = NULL;
+			dphy_hw->dphy_dev_num--;
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static int rockchip_csi2_dphy_attach_hw(struct csi2_dphy *dphy)
 {
 	struct platform_device *plat_dev;
@@ -470,7 +609,7 @@
 	enum csi2_dphy_lane_mode target_mode;
 	int i;
 
-	if (dphy->phy_index == 0)
+	if (dphy->phy_index % 3 == 0)
 		target_mode = LANE_MODE_FULL;
 	else
 		target_mode = LANE_MODE_SPLIT;
@@ -547,9 +686,53 @@
 	return 0;
 }
 
+static struct dphy_drv_data rk3568_dphy_drv_data = {
+	.dev_name = "csi2dphy",
+	.vendor = PHY_VENDOR_INNO,
+};
+
+static struct dphy_drv_data rk3588_dcphy_drv_data = {
+	.dev_name = "csi2dcphy",
+	.vendor = PHY_VENDOR_SAMSUNG,
+};
+
+static struct rkmodule_csi_dphy_param rk3588_dcphy_param = {
+	.vendor = PHY_VENDOR_SAMSUNG,
+	.lp_vol_ref = 3,
+	.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 struct dphy_drv_data rv1106_dphy_drv_data = {
+	.dev_name = "csi2dphy",
+	.vendor = PHY_VENDOR_INNO,
+};
+
+static struct dphy_drv_data rk3562_dphy_drv_data = {
+	.dev_name = "csi2dphy",
+	.vendor = PHY_VENDOR_INNO,
+};
+
 static const struct of_device_id rockchip_csi2_dphy_match_id[] = {
 	{
 		.compatible = "rockchip,rk3568-csi2-dphy",
+		.data = &rk3568_dphy_drv_data,
+	},
+	{
+		.compatible = "rockchip,rk3588-csi2-dcphy",
+		.data = &rk3588_dcphy_drv_data,
+	},
+	{
+		.compatible = "rockchip,rv1106-csi2-dphy",
+		.data = &rv1106_dphy_drv_data,
+	},
+	{
+		.compatible = "rockchip,rk3562-csi2-dphy",
+		.data = &rk3562_dphy_drv_data,
 	},
 	{}
 };
@@ -561,6 +744,7 @@
 	const struct of_device_id *of_id;
 	struct csi2_dphy *csi2dphy;
 	struct v4l2_subdev *sd;
+	const struct dphy_drv_data *drv_data;
 	int ret;
 
 	csi2dphy = devm_kzalloc(dev, sizeof(*csi2dphy), GFP_KERNEL);
@@ -571,12 +755,17 @@
 	of_id = of_match_device(rockchip_csi2_dphy_match_id, dev);
 	if (!of_id)
 		return -EINVAL;
-
-	csi2dphy->phy_index = of_alias_get_id(dev->of_node, "csi2dphy");
-	if (csi2dphy->phy_index < 0 || csi2dphy->phy_index > 2)
+	drv_data = of_id->data;
+	csi2dphy->drv_data = drv_data;
+	csi2dphy->phy_index = of_alias_get_id(dev->of_node, drv_data->dev_name);
+	if (csi2dphy->phy_index < 0 || csi2dphy->phy_index >= PHY_MAX)
 		csi2dphy->phy_index = 0;
-
-	ret = rockchip_csi2_dphy_attach_hw(csi2dphy);
+	if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) {
+		ret = rockchip_csi2_dphy_attach_samsung_phy(csi2dphy);
+		csi2dphy->dphy_param = rk3588_dcphy_param;
+	} else {
+		ret = rockchip_csi2_dphy_attach_hw(csi2dphy);
+	}
 	if (ret) {
 		dev_err(dev,
 			"csi2 dphy hw can't be attached, register dphy%d failed!\n",
@@ -606,7 +795,10 @@
 
 detach_hw:
 	mutex_destroy(&csi2dphy->mutex);
-	rockchip_csi2_dphy_detach_hw(csi2dphy);
+	if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG)
+		rockchip_csi2_dphy_detach_samsung_phy(csi2dphy);
+	else
+		rockchip_csi2_dphy_detach_hw(csi2dphy);
 
 	return 0;
 }
@@ -623,42 +815,6 @@
 	mutex_destroy(&dphy->mutex);
 	return 0;
 }
-static int __maybe_unused __rockchip_csi2dphy_clr_unready_dev(void)
-{
-	struct csi2_dphy *csi2dphy;
-
-	mutex_lock(&csi2dphy_dev_mutex);
-	list_for_each_entry(csi2dphy, &csi2dphy_device_list, list)
-		v4l2_async_notifier_clr_unready_dev(&csi2dphy->notifier);
-	mutex_unlock(&csi2dphy_dev_mutex);
-
-	return 0;
-}
-
-static int rockchip_csi2dphy_clr_unready_dev_param_set(const char *val,
-						       const struct kernel_param *kp)
-{
-#ifdef MODULE
-	__rockchip_csi2dphy_clr_unready_dev();
-#endif
-
-	return 0;
-}
-
-module_param_call(clr_unready_dev,
-		  rockchip_csi2dphy_clr_unready_dev_param_set,
-		  NULL, NULL, 0200);
-MODULE_PARM_DESC(clr_unready_dev, "clear unready devices");
-
-#ifndef MODULE
-static int __init rockchip_csi2_dphy_clr_unready_dev(void)
-{
-	__rockchip_csi2dphy_clr_unready_dev();
-
-	return 0;
-}
-late_initcall_sync(rockchip_csi2_dphy_clr_unready_dev);
-#endif
 
 static const struct dev_pm_ops rockchip_csi2_dphy_pm_ops = {
 	SET_RUNTIME_PM_OPS(csi2_dphy_runtime_suspend,
@@ -674,7 +830,19 @@
 		.of_match_table = rockchip_csi2_dphy_match_id,
 	},
 };
-EXPORT_SYMBOL(rockchip_csi2_dphy_driver);
+
+int rockchip_csi2_dphy_init(void)
+{
+	return platform_driver_register(&rockchip_csi2_dphy_driver);
+}
+
+#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC)
+subsys_initcall(rockchip_csi2_dphy_init);
+#else
+#if !defined(CONFIG_VIDEO_REVERSE_IMAGE)
+module_platform_driver(rockchip_csi2_dphy_driver);
+#endif
+#endif
 
 MODULE_AUTHOR("Rockchip Camera/ISP team");
 MODULE_DESCRIPTION("Rockchip MIPI CSI2 DPHY driver");

--
Gitblit v1.6.2