From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 31 Jan 2024 03:29:01 +0000
Subject: [PATCH] add lvds1024*800

---
 kernel/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c |  235 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 188 insertions(+), 47 deletions(-)

diff --git a/kernel/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/kernel/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
index 75c9739..e66df80 100644
--- a/kernel/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
+++ b/kernel/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
@@ -246,6 +246,8 @@
 	struct phy *dcphy;
 	union phy_configure_opts phy_opts;
 
+	bool disable_hold_mode;
+	bool auto_calc_mode;
 	bool c_option;
 	bool scrambling_en;
 	unsigned int slice_width;
@@ -270,13 +272,16 @@
 	u32 lanes;
 	u32 format;
 	unsigned long mode_flags;
-
+	u64 mipi_pixel_rate;
 	const struct dw_mipi_dsi2_plat_data *pdata;
 	struct rockchip_drm_sub_dev sub_dev;
 
 	struct gpio_desc *te_gpio;
-	bool user_split_mode;
-	struct drm_property *user_split_mode_prop;
+
+	/* split with other display interface */
+	bool dual_connector_split;
+	bool left_display;
+	u32 split_area;
 };
 
 static inline struct dw_mipi_dsi2 *host_to_dsi2(struct mipi_dsi_host *host)
@@ -450,7 +455,8 @@
 		dw_mipi_dsi2_post_disable(dsi2->slave);
 }
 
-static void dw_mipi_dsi2_encoder_disable(struct drm_encoder *encoder)
+static void dw_mipi_dsi2_encoder_atomic_disable(struct drm_encoder *encoder,
+						struct drm_atomic_state *state)
 {
 	struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder);
 	struct drm_crtc *crtc = encoder->crtc;
@@ -605,9 +611,8 @@
 
 static void dw_mipi_dsi2_phy_ratio_cfg(struct dw_mipi_dsi2 *dsi2)
 {
-	struct drm_display_mode *mode = &dsi2->mode;
 	u64 sys_clk = clk_get_rate(dsi2->sys_clk);
-	u64 pixel_clk, ipi_clk, phy_hsclk;
+	u64 ipi_clk, phy_hsclk;
 	u64 tmp;
 
 	/*
@@ -621,8 +626,9 @@
 		phy_hsclk = DIV_ROUND_CLOSEST_ULL(dsi2->lane_hs_rate * MSEC_PER_SEC, 16);
 
 	/* IPI_RATIO_MAN_CFG = PHY_HSTX_CLK / IPI_CLK */
-	pixel_clk = mode->crtc_clock * MSEC_PER_SEC;
-	ipi_clk = pixel_clk / 4;
+	ipi_clk = dsi2->mipi_pixel_rate;
+	if (!sys_clk || !ipi_clk)
+		return;
 
 	tmp = DIV_ROUND_CLOSEST_ULL(phy_hsclk << 16, ipi_clk);
 	regmap_write(dsi2->regmap, DSI2_PHY_IPI_RATIO_MAN_CFG,
@@ -662,6 +668,10 @@
 {
 	dw_mipi_dsi2_phy_mode_cfg(dsi2);
 	dw_mipi_dsi2_phy_clk_mode_cfg(dsi2);
+
+	if (dsi2->auto_calc_mode)
+		return;
+
 	dw_mipi_dsi2_phy_ratio_cfg(dsi2);
 	dw_mipi_dsi2_lp2hs_or_hs2lp_cfg(dsi2);
 
@@ -729,6 +739,9 @@
 	regmap_write(dsi2->regmap, DSI2_IPI_PIX_PKT_CFG, MAX_PIX_PKT(val));
 
 	dw_mipi_dsi2_ipi_color_coding_cfg(dsi2);
+
+	if (dsi2->auto_calc_mode)
+		return;
 
 	/*
 	 * if the controller is intended to operate in data stream mode,
@@ -803,7 +816,7 @@
 
 	/* there may be some timeout registers may be configured if desired */
 
-	dw_mipi_dsi2_work_mode(dsi2, MANUAL_MODE_EN);
+	dw_mipi_dsi2_work_mode(dsi2, dsi2->auto_calc_mode ? 0 : MANUAL_MODE_EN);
 	dw_mipi_dsi2_phy_init(dsi2);
 	dw_mipi_dsi2_tx_option_set(dsi2);
 	dw_mipi_dsi2_irq_enable(dsi2, 1);
@@ -826,7 +839,19 @@
 
 static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2)
 {
+	u32 mode;
+	int ret;
+
 	dw_mipi_dsi2_ipi_set(dsi2);
+
+	if (dsi2->auto_calc_mode) {
+		regmap_write(dsi2->regmap, DSI2_MODE_CTRL, AUTOCALC_MODE);
+		ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,
+					       mode, mode == IDLE_MODE,
+					       1000, MODE_STATUS_TIMEOUT_US);
+		if (ret < 0)
+			dev_err(dsi2->dev, "auto calculation training failed\n");
+	}
 
 	if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)
 		dw_mipi_dsi2_set_vid_mode(dsi2);
@@ -837,9 +862,82 @@
 		dw_mipi_dsi2_enable(dsi2->slave);
 }
 
-static void dw_mipi_dsi2_encoder_enable(struct drm_encoder *encoder)
+static void dw_mipi_dsi2_get_mipi_pixel_clk(struct dw_mipi_dsi2 *dsi2,
+					    struct rockchip_crtc_state *s)
+{
+	struct drm_display_mode *mode = &dsi2->mode;
+	u8 k = dsi2->slave ? 2 : 1;
+
+	/* 1.When MIPI works in uncompressed mode:
+	 * (Video Timing Pixel Rate)/(4)=(MIPI Pixel ClockxK)=(dclk_out×K)=dclk_core
+	 * 2.When MIPI works in compressed mode:
+	 * MIPI Pixel Clock = cds_clk / 2
+	 * MIPI is configured as double channel display mode, K=2, otherwise K=1.
+	 */
+	if (dsi2->dsc_enable) {
+		dsi2->mipi_pixel_rate = s->dsc_cds_clk_rate / 2;
+		if (dsi2->slave)
+			dsi2->slave->mipi_pixel_rate = dsi2->mipi_pixel_rate;
+
+		return;
+	}
+
+	dsi2->mipi_pixel_rate = (mode->crtc_clock * MSEC_PER_SEC) / (4 * k);
+	if (dsi2->slave)
+		dsi2->slave->mipi_pixel_rate = dsi2->mipi_pixel_rate;
+}
+
+static int dw_mipi_dsi2_encoder_mode_set(struct dw_mipi_dsi2 *dsi2,
+					 struct drm_atomic_state *state)
+{
+	struct drm_encoder *encoder = &dsi2->encoder;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct rockchip_crtc_state *vcstate;
+	const struct drm_display_mode *adjusted_mode;
+	struct drm_display_mode *mode = &dsi2->mode;
+
+	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+	if (!connector)
+		return -ENODEV;
+
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	if (!conn_state)
+		return -ENODEV;
+
+	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+	if (!crtc_state) {
+		dev_err(dsi2->dev, "failed to get crtc state\n");
+		return -ENODEV;
+	}
+
+	vcstate = to_rockchip_crtc_state(crtc_state);
+	adjusted_mode = &crtc_state->adjusted_mode;
+	drm_mode_copy(mode, adjusted_mode);
+
+	if (dsi2->dual_connector_split)
+		drm_mode_convert_to_origin_mode(mode);
+
+	if (dsi2->slave)
+		drm_mode_copy(&dsi2->slave->mode, mode);
+
+	dw_mipi_dsi2_get_mipi_pixel_clk(dsi2, vcstate);
+
+	return 0;
+}
+
+static void dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder *encoder,
+					       struct drm_atomic_state *state)
 {
 	struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder);
+	int ret;
+
+	ret = dw_mipi_dsi2_encoder_mode_set(dsi2, state);
+	if (ret) {
+		dev_err(dsi2->dev, "failed to set dsi2 mode\n");
+		return;
+	}
 
 	dw_mipi_dsi2_get_lane_rate(dsi2);
 
@@ -867,8 +965,8 @@
 
 static int
 dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
-				 struct drm_crtc_state *crtc_state,
-				 struct drm_connector_state *conn_state)
+				  struct drm_crtc_state *crtc_state,
+				  struct drm_connector_state *conn_state)
 {
 
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
@@ -906,7 +1004,7 @@
 	if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)) {
 		s->output_flags |= ROCKCHIP_OUTPUT_MIPI_DS_MODE;
 		s->soft_te = dsi2->te_gpio ? true : false;
-		s->hold_mode = true;
+		s->hold_mode = dsi2->disable_hold_mode ? false : true;
 	}
 
 	if (dsi2->slave) {
@@ -915,6 +1013,15 @@
 			s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
 
 		s->output_if |= VOP_OUTPUT_IF_MIPI1;
+	}
+
+	if (dsi2->dual_connector_split) {
+		s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CONNECTOR_SPLIT_MODE;
+
+		if (dsi2->left_display)
+			s->output_if_left_panel |= dsi2->id ?
+						   VOP_OUTPUT_IF_MIPI1 :
+						   VOP_OUTPUT_IF_MIPI0;
 	}
 
 	if (dsi2->dsc_enable) {
@@ -931,18 +1038,6 @@
 	}
 
 	return 0;
-}
-
-static void
-dw_mipi_dsi2_encoder_atomic_mode_set(struct drm_encoder *encoder,
-				    struct drm_crtc_state *crtc_state,
-				    struct drm_connector_state *connector_state)
-{
-	struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder);
-
-	drm_mode_copy(&dsi2->mode, &crtc_state->adjusted_mode);
-	if (dsi2->slave)
-		drm_mode_copy(&dsi2->slave->mode, &crtc_state->adjusted_mode);
 }
 
 static void dw_mipi_dsi2_loader_protect(struct dw_mipi_dsi2 *dsi2, bool on)
@@ -980,10 +1075,9 @@
 
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi2_encoder_helper_funcs = {
-	.enable = dw_mipi_dsi2_encoder_enable,
-	.disable = dw_mipi_dsi2_encoder_disable,
+	.atomic_enable = dw_mipi_dsi2_encoder_atomic_enable,
+	.atomic_disable = dw_mipi_dsi2_encoder_atomic_disable,
 	.atomic_check = dw_mipi_dsi2_encoder_atomic_check,
-	.atomic_mode_set = dw_mipi_dsi2_encoder_atomic_mode_set,
 };
 
 static int dw_mipi_dsi2_connector_get_modes(struct drm_connector *connector)
@@ -1065,6 +1159,32 @@
 	drm_connector_cleanup(connector);
 }
 
+static int
+dw_mipi_dsi2_atomic_connector_get_property(struct drm_connector *connector,
+					   const struct drm_connector_state *state,
+					   struct drm_property *property,
+					   uint64_t *val)
+{
+	struct rockchip_drm_private *private = connector->dev->dev_private;
+	struct dw_mipi_dsi2 *dsi2 = con_to_dsi2(connector);
+
+	if (property == private->split_area_prop) {
+		switch (dsi2->split_area) {
+		case 1:
+			*val = ROCKCHIP_DRM_SPLIT_LEFT_SIDE;
+			break;
+		case 2:
+			*val = ROCKCHIP_DRM_SPLIT_RIGHT_SIDE;
+			break;
+		default:
+			*val = ROCKCHIP_DRM_SPLIT_UNSET;
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static const struct drm_connector_funcs dw_mipi_dsi2_atomic_connector_funcs = {
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = dw_mipi_dsi2_connector_detect,
@@ -1072,6 +1192,7 @@
 	.reset = drm_atomic_helper_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_get_property = dw_mipi_dsi2_atomic_connector_get_property,
 };
 
 static int dw_mipi_dsi2_dual_channel_probe(struct dw_mipi_dsi2 *dsi2)
@@ -1093,6 +1214,7 @@
 		dsi2->slave->master = dsi2;
 		dsi2->lanes /= 2;
 
+		dsi2->slave->auto_calc_mode = dsi2->auto_calc_mode;
 		dsi2->slave->lanes = dsi2->lanes;
 		dsi2->slave->channel = dsi2->channel;
 		dsi2->slave->format = dsi2->format;
@@ -1143,6 +1265,9 @@
 		dsi2->slave->dsc_enable = dsi2->dsc_enable;
 	}
 
+	if (!dsi2->dsc_enable)
+		return 0;
+
 	of_property_read_u32(np, "slice-width", &dsi2->slice_width);
 	of_property_read_u32(np, "slice-height", &dsi2->slice_height);
 	of_property_read_u8(np, "version-major", &dsi2->version_major);
@@ -1178,7 +1303,20 @@
 		len -= header->payload_length;
 	}
 
+	if (!pps) {
+		dev_err(dsi2->dev, "not found dsc pps definition\n");
+		return -EINVAL;
+	}
+
 	dsi2->pps = pps;
+
+	if (dsi2->slave) {
+		u16 pic_width = be16_to_cpu(pps->pic_width) / 2;
+
+		dsi2->pps->pic_width = cpu_to_be16(pic_width);
+		dev_info(dsi2->dev, "dsc pic_width change from %d to %d\n",
+			 pic_width * 2, pic_width);
+	}
 
 	return 0;
 }
@@ -1218,22 +1356,15 @@
 static int dw_mipi_dsi2_register_sub_dev(struct dw_mipi_dsi2 *dsi2,
 					 struct drm_connector *connector)
 {
+	struct rockchip_drm_private *private;
 	struct device *dev = dsi2->dev;
-	struct drm_property *prop;
-	int ret;
 
-	prop = drm_property_create_bool(dsi2->drm_dev, DRM_MODE_PROP_IMMUTABLE,
-					"USER_SPLIT_MODE");
-	if (!prop) {
-		ret = -EINVAL;
-		DRM_DEV_ERROR(dev, "create user split mode prop failed\n");
-		goto connector_cleanup;
-	}
+	private = connector->dev->dev_private;
 
-	dsi2->user_split_mode_prop = prop;
-	drm_object_attach_property(&connector->base,
-				   dsi2->user_split_mode_prop,
-				   dsi2->user_split_mode ? 1 : 0);
+	if (dsi2->split_area)
+		drm_object_attach_property(&connector->base,
+					   private->split_area_prop,
+					   dsi2->split_area);
 
 	dsi2->sub_dev.connector = connector;
 	dsi2->sub_dev.of_node = dev->of_node;
@@ -1241,11 +1372,6 @@
 	rockchip_drm_register_sub_dev(&dsi2->sub_dev);
 
 	return 0;
-
-connector_cleanup:
-	connector->funcs->destroy(connector);
-
-	return ret;
 }
 
 static int dw_mipi_dsi2_bind(struct device *dev, struct device *master,
@@ -1563,7 +1689,22 @@
 	dsi2->id = id;
 	dsi2->pdata = of_device_get_match_data(dev);
 	platform_set_drvdata(pdev, dsi2);
-	dsi2->user_split_mode = device_property_read_bool(dev, "user-split-mode");
+
+	if (device_property_read_bool(dev, "auto-calculation-mode"))
+		dsi2->auto_calc_mode = true;
+
+	if (device_property_read_bool(dev, "disable-hold-mode"))
+		dsi2->disable_hold_mode = true;
+
+	if (device_property_read_bool(dev, "dual-connector-split")) {
+		dsi2->dual_connector_split = true;
+
+		if (device_property_read_bool(dev, "left-display"))
+			dsi2->left_display = true;
+	}
+
+	if (device_property_read_u32(dev, "split-area", &dsi2->split_area))
+		dsi2->split_area = 0;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(dev, res);

--
Gitblit v1.6.2