From fe6c762c8d16cddae0a0fd5673f7ab8c6b06f4e5 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 16 Mar 2021 09:01:48 +0100
Subject: [PATCH 06/22] ARM 5.10.10-stm32mp1-r1 DRM

---
 drivers/gpu/drm/bridge/sii902x.c              | 100 +++++++++-
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 172 ++++++++++++++----
 drivers/gpu/drm/drm_modes.c                   |  19 +-
 .../gpu/drm/panel/panel-orisetech-otm8009a.c  |  24 +--
 drivers/gpu/drm/panel/panel-raydium-rm68200.c |  17 +-
 drivers/gpu/drm/stm/dw_mipi_dsi-stm.c         |   3 +-
 drivers/gpu/drm/stm/ltdc.c                    |  72 +++++---
 drivers/input/touchscreen/edt-ft5x06.c        |  18 +-
 drivers/input/touchscreen/goodix.c            |  15 ++
 include/uapi/drm/drm_mode.h                   |   6 +
 10 files changed, 346 insertions(+), 100 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 89558e581530..69208ead5384 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -16,6 +16,7 @@
 #include <linux/i2c-mux.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
@@ -162,6 +163,11 @@
 
 #define SII902X_AUDIO_PORT_INDEX		3
 
+/* CEC device */
+#define SII902X_CEC_I2C_ADDR			0x30
+
+#define SII902X_CEC_SETUP			0x8e
+
 struct sii902x {
 	struct i2c_client *i2c;
 	struct regmap *regmap;
@@ -170,6 +176,7 @@ struct sii902x {
 	struct gpio_desc *reset_gpio;
 	struct i2c_mux_core *i2cmux;
 	struct regulator_bulk_data supplies[2];
+	struct edid *edid;
 	/*
 	 * Mutex protects audio and video functions from interfering
 	 * each other, by keeping their i2c command sequences atomic.
@@ -280,6 +287,8 @@ static int sii902x_get_modes(struct drm_connector *connector)
 
 	mutex_lock(&sii902x->mutex);
 
+	kfree(sii902x->edid);
+	sii902x->edid = NULL;
 	edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]);
 	drm_connector_update_edid_property(connector, edid);
 	if (edid) {
@@ -287,7 +296,7 @@ static int sii902x_get_modes(struct drm_connector *connector)
 			output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI;
 
 		num = drm_add_edid_modes(connector, edid);
-		kfree(edid);
+		sii902x->edid = edid;
 	}
 
 	ret = drm_display_info_set_bus_formats(&connector->display_info,
@@ -337,6 +346,7 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge)
 static void sii902x_bridge_enable(struct drm_bridge *bridge)
 {
 	struct sii902x *sii902x = bridge_to_sii902x(bridge);
+	u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI;
 
 	mutex_lock(&sii902x->mutex);
 
@@ -346,6 +356,14 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge)
 	regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
 			   SII902X_SYS_CTRL_PWR_DWN, 0);
 
+	if (sii902x->edid) {
+		if (drm_detect_hdmi_monitor(sii902x->edid))
+			output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI;
+	}
+
+	regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
+			   SII902X_SYS_CTRL_OUTPUT_MODE, output_mode);
+
 	mutex_unlock(&sii902x->mutex);
 }
 
@@ -960,6 +978,13 @@ static int sii902x_init(struct sii902x *sii902x)
 {
 	struct device *dev = &sii902x->i2c->dev;
 	unsigned int status = 0;
+	unsigned char data[2] = { SII902X_CEC_SETUP, 0};
+	struct i2c_msg msg = {
+		.addr	= SII902X_CEC_I2C_ADDR << 1,
+		.flags	= 0,
+		.len	= 2,
+		.buf	= data,
+	};
 	u8 chipid[4];
 	int ret;
 
@@ -982,13 +1007,22 @@ static int sii902x_init(struct sii902x *sii902x)
 		return -EINVAL;
 	}
 
+	/*
+	 * By default, CEC must be disabled to allow other CEC devives
+	 * to bypass the bridge.
+	 */
+	ret = i2c_transfer(sii902x->i2c->adapter, &msg, 1);
+	if (ret < 0)
+		dev_warn(&sii902x->i2c->dev, "Failed to disable CEC device!\n");
+
 	/* Clear all pending interrupts */
 	regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
 	regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
 
 	if (sii902x->i2c->irq > 0) {
-		regmap_write(sii902x->regmap, SII902X_INT_ENABLE,
-			     SII902X_HOTPLUG_EVENT);
+		regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE,
+				   SII902X_HOTPLUG_EVENT,
+				   SII902X_HOTPLUG_EVENT);
 
 		ret = devm_request_threaded_irq(dev, sii902x->i2c->irq, NULL,
 						sii902x_interrupt,
@@ -1087,6 +1121,65 @@ static int sii902x_remove(struct i2c_client *client)
 	return 0;
 }
 
+static int sii902x_pm_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sii902x *sii902x = i2c_get_clientdata(client);
+
+	DRM_DEBUG_DRIVER("\n");
+
+	if (sii902x->reset_gpio)
+		gpiod_set_value(sii902x->reset_gpio, 1);
+
+	regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
+			       sii902x->supplies);
+
+	return 0;
+}
+
+static int sii902x_pm_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sii902x *sii902x = i2c_get_clientdata(client);
+	unsigned char data[2] = { SII902X_CEC_SETUP, 0};
+	struct i2c_msg msg = {
+		.addr	= SII902X_CEC_I2C_ADDR << 1,
+		.flags	= 0,
+		.len	= 2,
+		.buf	= data,
+	};
+	int ret;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies),
+				    sii902x->supplies);
+	if (ret) {
+		DRM_ERROR("regulator_bulk_enable failed\n");
+		return ret;
+	}
+
+	if (sii902x->reset_gpio)
+		gpiod_set_value(sii902x->reset_gpio, 0);
+
+	regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00);
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		DRM_ERROR("Failed to disable CEC device!\n");
+
+	if (client->irq > 0)
+		regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE,
+				   SII902X_HOTPLUG_EVENT,
+				   SII902X_HOTPLUG_EVENT);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sii902x_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume)
+};
+
 static const struct of_device_id sii902x_dt_ids[] = {
 	{ .compatible = "sil,sii9022", },
 	{ }
@@ -1105,6 +1198,7 @@ static struct i2c_driver sii902x_driver = {
 	.driver = {
 		.name = "sii902x",
 		.of_match_table = sii902x_dt_ids,
+		.pm = &sii902x_pm_ops,
 	},
 	.id_table = sii902x_i2c_ids,
 };
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 6b268f9445b3..25b63491135f 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -213,6 +213,20 @@
 
 #define DSI_INT_ST0			0xbc
 #define DSI_INT_ST1			0xc0
+#define GPRXE				BIT(12)
+#define GPRDE				BIT(11)
+#define GPTXE				BIT(10)
+#define GPWRE				BIT(9)
+#define GCWRE				BIT(8)
+#define DPIPLDWE			BIT(7)
+#define EOTPE				BIT(6)
+#define PSE				BIT(5)
+#define CRCE				BIT(4)
+#define ECCME				BIT(3)
+#define ECCSE				BIT(2)
+#define TOLPRX				BIT(1)
+#define TOHSTX				BIT(0)
+
 #define DSI_INT_MSK0			0xc4
 #define DSI_INT_MSK1			0xc8
 
@@ -314,9 +328,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 {
 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
 	const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
-	struct drm_bridge *bridge;
-	struct drm_panel *panel;
-	int ret;
+	int ret = -ENODEV;
 
 	if (device->lanes > dsi->plat_data->max_data_lanes) {
 		dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
@@ -329,22 +341,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 	dsi->format = device->format;
 	dsi->mode_flags = device->mode_flags;
 
-	ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0,
-					  &panel, &bridge);
-	if (ret)
-		return ret;
-
-	if (panel) {
-		bridge = drm_panel_bridge_add_typed(panel,
-						    DRM_MODE_CONNECTOR_DSI);
-		if (IS_ERR(bridge))
-			return PTR_ERR(bridge);
-	}
-
-	dsi->panel_bridge = bridge;
-
-	drm_bridge_add(&dsi->bridge);
-
 	if (pdata->host_ops && pdata->host_ops->attach) {
 		ret = pdata->host_ops->attach(pdata->priv_data, device);
 		if (ret < 0)
@@ -367,10 +363,6 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
 			return ret;
 	}
 
-	drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
-
-	drm_bridge_remove(&dsi->bridge);
-
 	return 0;
 }
 
@@ -431,6 +423,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
 	return 0;
 }
 
+static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi)
+{
+	u32 val;
+
+	val = dsi_read(dsi, DSI_INT_ST1);
+
+	if (val & GPRXE)
+		DRM_DEBUG_DRIVER("DSI Generic payload receive error\n");
+	if (val & GPRDE)
+		DRM_DEBUG_DRIVER("DSI Generic payload read error\n");
+	if (val & GPTXE)
+		DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n");
+	if (val & GPWRE)
+		DRM_DEBUG_DRIVER("DSI Generic payload write error\n");
+	if (val & GCWRE)
+		DRM_DEBUG_DRIVER("DSI Generic command write error\n");
+	if (val & DPIPLDWE)
+		DRM_DEBUG_DRIVER("DSI DPI payload write error\n");
+	if (val & EOTPE)
+		DRM_DEBUG_DRIVER("DSI EoTp error\n");
+	if (val & PSE)
+		DRM_DEBUG_DRIVER("DSI Packet size error\n");
+	if (val & CRCE)
+		DRM_DEBUG_DRIVER("DSI CRC error\n");
+	if (val & ECCME)
+		DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n");
+	if (val & ECCSE)
+		DRM_DEBUG_DRIVER("DSI ECC single-bit error\n");
+	if (val & TOLPRX)
+		DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n");
+	if (val & TOHSTX)
+		DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n");
+
+	return val;
+}
+
 static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
 			     const struct mipi_dsi_packet *packet)
 {
@@ -460,6 +488,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
 				"failed to get available write payload FIFO\n");
 			return ret;
 		}
+
+		val = dw_mipi_dsi_read_status(dsi);
+		if (val) {
+			dev_err(dsi->dev, "dsi status error 0x%0x\n", val);
+			return -EINVAL;
+		}
 	}
 
 	word = 0;
@@ -493,6 +527,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
 			return ret;
 		}
 
+		val = dw_mipi_dsi_read_status(dsi);
+		if (val) {
+			dev_err(dsi->dev, "dsi status error 0x%0x\n", val);
+			return -EINVAL;
+		}
+
 		val = dsi_read(dsi, DSI_GEN_PLD_DATA);
 		for (j = 0; j < 4 && j + i < len; j++)
 			buf[i + j] = val >> (8 * j);
@@ -507,6 +547,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
 	struct mipi_dsi_packet packet;
 	int ret, nb_bytes;
+	int retry = 3;
 
 	ret = mipi_dsi_create_packet(&packet, msg);
 	if (ret) {
@@ -518,24 +559,32 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
 	if (dsi->slave)
 		dw_mipi_message_config(dsi->slave, msg);
 
-	ret = dw_mipi_dsi_write(dsi, &packet);
-	if (ret)
-		return ret;
-	if (dsi->slave) {
-		ret = dw_mipi_dsi_write(dsi->slave, &packet);
+	while (retry--) {
+		ret = dw_mipi_dsi_write(dsi, &packet);
 		if (ret)
-			return ret;
-	}
+			continue;
 
-	if (msg->rx_buf && msg->rx_len) {
-		ret = dw_mipi_dsi_read(dsi, msg);
-		if (ret)
-			return ret;
-		nb_bytes = msg->rx_len;
-	} else {
-		nb_bytes = packet.size;
+		if (dsi->slave) {
+			ret = dw_mipi_dsi_write(dsi->slave, &packet);
+			if (ret)
+				continue;
+		}
+
+		if (msg->rx_buf && msg->rx_len) {
+			ret = dw_mipi_dsi_read(dsi, msg);
+			if (ret)
+				continue;
+			nb_bytes = msg->rx_len;
+			break;
+		} else {
+			nb_bytes = packet.size;
+			break;
+		}
 	}
 
+	if (ret)
+		return ret;
+
 	return nb_bytes;
 }
 
@@ -1105,6 +1154,9 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
 	struct device *dev = &pdev->dev;
 	struct reset_control *apb_rst;
 	struct dw_mipi_dsi *dsi;
+	struct drm_bridge *bridge;
+	struct drm_panel *panel;
+	int i, nb_endpoints;
 	int ret;
 
 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
@@ -1172,8 +1224,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
 	ret = mipi_dsi_host_register(&dsi->dsi_host);
 	if (ret) {
 		dev_err(dev, "Failed to register MIPI host: %d\n", ret);
-		dw_mipi_dsi_debugfs_remove(dsi);
-		return ERR_PTR(ret);
+		goto err_pmr_enable;
 	}
 
 	dsi->bridge.driver_private = dsi;
@@ -1182,11 +1233,54 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
 	dsi->bridge.of_node = pdev->dev.of_node;
 #endif
 
+	/* Get number of endpoints */
+	nb_endpoints = of_graph_get_endpoint_count(pdev->dev.of_node);
+	if (!nb_endpoints) {
+		ret = -ENODEV;
+		goto err_host_reg;
+	}
+
+	for (i = 1; i < nb_endpoints; i++) {
+		ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, i, 0,
+						  &panel, &bridge);
+		if (!ret)
+			break;
+		else if (ret == -EPROBE_DEFER)
+			goto err_host_reg;
+	}
+
+	/* check if an error is returned >> no panel or bridge detected */
+	if (ret)
+		goto err_host_reg;
+
+	if (panel) {
+		bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI);
+		if (IS_ERR(bridge)) {
+			ret = PTR_ERR(bridge);
+			goto err_host_reg;
+		}
+	}
+
+	dsi->panel_bridge = bridge;
+
+	drm_bridge_add(&dsi->bridge);
+
 	return dsi;
+
+err_host_reg:
+	mipi_dsi_host_unregister(&dsi->dsi_host);
+
+err_pmr_enable:
+	pm_runtime_disable(dev);
+	dw_mipi_dsi_debugfs_remove(dsi);
+
+	return ERR_PTR(ret);
 }
 
 static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
 {
+	drm_bridge_remove(&dsi->bridge);
+	drm_panel_bridge_remove(dsi->panel_bridge);
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 
 	pm_runtime_disable(dsi->dev);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 501b4fe55a3d..125aab6b12e8 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -127,7 +127,7 @@ EXPORT_SYMBOL(drm_mode_probed_add);
  * according to the hdisplay, vdisplay, vrefresh.
  * It is based from the VESA(TM) Coordinated Video Timing Generator by
  * Graham Loveridge April 9, 2003 available at
- * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls 
+ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
  *
  * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
  * What I have done is to translate it by using integer calculation.
@@ -615,6 +615,15 @@ void drm_display_mode_from_videomode(const struct videomode *vm,
 		dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
 	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
 		dmode->flags |= DRM_MODE_FLAG_DBLCLK;
+	if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+		dmode->flags |= DRM_MODE_FLAG_PPIXDATA;
+	else if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+		dmode->flags |= DRM_MODE_FLAG_NPIXDATA;
+	if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
+		dmode->flags |= DRM_MODE_FLAG_PDE;
+	else if (vm->flags & DISPLAY_FLAGS_DE_LOW)
+		dmode->flags |= DRM_MODE_FLAG_NDE;
+
 	drm_mode_set_name(dmode);
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
@@ -656,6 +665,14 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
 		vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
 	if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
 		vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
+	if (dmode->flags & DRM_MODE_FLAG_PPIXDATA)
+		vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+	else if (dmode->flags & DRM_MODE_FLAG_NPIXDATA)
+		vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+	if (dmode->flags & DRM_MODE_FLAG_PDE)
+		vm->flags |= DISPLAY_FLAGS_DE_HIGH;
+	else if (dmode->flags & DRM_MODE_FLAG_NDE)
+		vm->flags |= DISPLAY_FLAGS_DE_LOW;
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
 
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
index 6ac1accade80..da0970ca98f8 100644
--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -99,20 +99,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data,
 		dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n");
 }
 
-static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data,
-				      size_t len)
-{
-	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
-
-	/* data will be sent in dsi hs mode (ie. no lpm) */
-	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
-
-	otm8009a_dcs_write_buf(ctx, data, len);
-
-	/* restore back the dsi lpm mode */
-	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
-}
-
 #define dcs_write_seq(ctx, seq...)			\
 ({							\
 	static const u8 d[] = { seq };			\
@@ -400,7 +386,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
 		 */
 		data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS;
 		data[1] = bd->props.brightness;
-		otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data));
+		otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data));
 
 		/* set Brightness Control & Backlight on */
 		data[1] = 0x24;
@@ -412,7 +398,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
 
 	/* Update Brightness Control & Backlight */
 	data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY;
-	otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data));
+	otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data));
 
 	return 0;
 }
@@ -433,8 +419,10 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi)
 
 	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(ctx->reset_gpio)) {
-		dev_err(dev, "cannot get reset-gpio\n");
-		return PTR_ERR(ctx->reset_gpio);
+		ret = PTR_ERR(ctx->reset_gpio);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "cannot get reset GPIO: %d\n", ret);
+		return ret;
 	}
 
 	ctx->supply = devm_regulator_get(dev, "power");
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c
index f908eeafb1af..74fa3596618d 100644
--- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c
+++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c
@@ -82,15 +82,15 @@ struct rm68200 {
 };
 
 static const struct drm_display_mode default_mode = {
-	.clock = 52582,
+	.clock = 54000,
 	.hdisplay = 720,
-	.hsync_start = 720 + 38,
-	.hsync_end = 720 + 38 + 8,
-	.htotal = 720 + 38 + 8 + 38,
+	.hsync_start = 720 + 48,
+	.hsync_end = 720 + 48 + 9,
+	.htotal = 720 + 48 + 9 + 48,
 	.vdisplay = 1280,
 	.vsync_start = 1280 + 12,
-	.vsync_end = 1280 + 12 + 4,
-	.vtotal = 1280 + 12 + 4 + 12,
+	.vsync_end = 1280 + 12 + 5,
+	.vtotal = 1280 + 12 + 5 + 12,
 	.flags = 0,
 	.width_mm = 68,
 	.height_mm = 122,
@@ -372,7 +372,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi)
 	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(ctx->reset_gpio)) {
 		ret = PTR_ERR(ctx->reset_gpio);
-		dev_err(dev, "cannot get reset GPIO: %d\n", ret);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "cannot get reset GPIO: %d\n", ret);
 		return ret;
 	}
 
@@ -391,7 +392,7 @@ static int rm68200_probe(struct mipi_dsi_device *dsi)
 	dsi->lanes = 2;
 	dsi->format = MIPI_DSI_FMT_RGB888;
 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
-			  MIPI_DSI_MODE_LPM;
+			  MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS;
 
 	drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs,
 		       DRM_MODE_CONNECTOR_DSI);
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
index 2e1f2664495d..164f79ef6269 100644
--- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
@@ -419,7 +419,8 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
 	dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data);
 	if (IS_ERR(dsi->dsi)) {
 		ret = PTR_ERR(dsi->dsi);
-		DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret);
+		if (ret != -EPROBE_DEFER)
+			DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret);
 		goto err_dsi_probe;
 	}
 
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 6e28f707092f..308755aa7b95 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -724,22 +724,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane,
 				   struct drm_plane_state *state)
 {
 	struct drm_framebuffer *fb = state->fb;
-	u32 src_w, src_h;
+	struct drm_crtc_state *crtc_state;
+	struct drm_rect *src = &state->src;
+	struct drm_rect *dst = &state->dst;
 
 	DRM_DEBUG_DRIVER("\n");
 
 	if (!fb)
 		return 0;
 
-	/* convert src_ from 16:16 format */
-	src_w = state->src_w >> 16;
-	src_h = state->src_h >> 16;
+	/* convert src from 16:16 format */
+	src->x1 = state->src_x >> 16;
+	src->y1 = state->src_y >> 16;
+	src->x2 = (state->src_w >> 16) + src->x1 - 1;
+	src->y2 = (state->src_h >> 16) + src->y1 - 1;
 
-	/* Reject scaling */
-	if (src_w != state->crtc_w || src_h != state->crtc_h) {
-		DRM_ERROR("Scaling is not supported");
+	dst->x1 = state->crtc_x;
+	dst->y1 = state->crtc_y;
+	dst->x2 = state->crtc_w + dst->x1 - 1;
+	dst->y2 = state->crtc_h + dst->y1 - 1;
+
+	DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n",
+			 plane->base.id, fb->base.id,
+			 src->x2 - src->x1 + 1, src->y2 - src->y1 + 1,
+			 src->x1, src->y1,
+			 dst->x2 - dst->x1 + 1, dst->y2 - dst->y1 + 1,
+			 dst->x1, dst->y1);
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+							state->crtc);
+	/* destination coordinates do not have to exceed display sizes */
+	if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 ||
+			   crtc_state->mode.vdisplay <= dst->y2))
+		return -EINVAL;
+
+	/* source sizes do not have to exceed destination sizes */
+	if (dst->x2 - dst->x1 < src->x2 - src->x1 ||
+	    dst->y2 - dst->y1 < src->y2 - src->y1)
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -749,44 +771,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
 {
 	struct ltdc_device *ldev = plane_to_ltdc(plane);
 	struct drm_plane_state *state = plane->state;
+	struct drm_rect *src = &state->src;
+	struct drm_rect *dst = &state->dst;
 	struct drm_framebuffer *fb = state->fb;
 	u32 lofs = plane->index * LAY_OFS;
-	u32 x0 = state->crtc_x;
-	u32 x1 = state->crtc_x + state->crtc_w - 1;
-	u32 y0 = state->crtc_y;
-	u32 y1 = state->crtc_y + state->crtc_h - 1;
-	u32 src_x, src_y, src_w, src_h;
 	u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr;
 	enum ltdc_pix_fmt pf;
+	struct drm_rect dr;
 
 	if (!state->crtc || !fb) {
 		DRM_DEBUG_DRIVER("fb or crtc NULL");
 		return;
 	}
 
-	/* convert src_ from 16:16 format */
-	src_x = state->src_x >> 16;
-	src_y = state->src_y >> 16;
-	src_w = state->src_w >> 16;
-	src_h = state->src_h >> 16;
-
-	DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n",
-			 plane->base.id, fb->base.id,
-			 src_w, src_h, src_x, src_y,
-			 state->crtc_w, state->crtc_h,
-			 state->crtc_x, state->crtc_y);
+	/* compute final coordinates of frame buffer */
+	dr.x1 = src->x1 + dst->x1;
+	dr.y1 = src->y1 + dst->y1;
+	dr.x2 = src->x2 + dst->x1;
+	dr.y2 = src->y2 + dst->y1;
 
 	bpcr = reg_read(ldev->regs, LTDC_BPCR);
 	ahbp = (bpcr & BPCR_AHBP) >> 16;
 	avbp = bpcr & BPCR_AVBP;
 
 	/* Configures the horizontal start and stop position */
-	val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp);
+	val = ((dr.x2 + 1 + ahbp) << 16) + (dr.x1 + 1 + ahbp);
 	reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs,
 			LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val);
 
 	/* Configures the vertical start and stop position */
-	val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp);
+	val = ((dr.y2 + 1 + avbp) << 16) + (dr.y1 + 1 + avbp);
 	reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs,
 			LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val);
 
@@ -805,8 +819,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
 
 	/* Configures the color frame buffer pitch in bytes & line length */
 	pitch_in_bytes = fb->pitches[0];
-	line_length = fb->format->cpp[0] *
-		      (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1;
+	line_length = fb->format->cpp[0] * (dr.x2 - dr.x1 + 1) +
+		      (ldev->caps.bus_width >> 3) - 1;
 	val = ((pitch_in_bytes << 16) | line_length);
 	reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs,
 			LXCFBLR_CFBLL | LXCFBLR_CFBP, val);
@@ -829,7 +843,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
 			LXBFCR_BF2 | LXBFCR_BF1, val);
 
 	/* Configures the frame buffer line number */
-	val = y1 - y0 + 1;
+	val = dr.y2 - dr.y1 + 1;
 	reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val);
 
 	/* Sets the FB address */
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 6ff81d48da86..1643ddf5f65e 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -30,6 +30,8 @@
 #include <linux/uaccess.h>
 
 #include <asm/unaligned.h>
+#include <linux/of_device.h>
+#include <drm/drm_mipi_dsi.h>
 
 #define WORK_REGISTER_THRESHOLD		0x00
 #define WORK_REGISTER_REPORT_RATE	0x08
@@ -1074,6 +1076,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 	const struct edt_i2c_chip_data *chip_data;
 	struct edt_ft5x06_ts_data *tsdata;
 	u8 buf[2] = { 0xfc, 0x00 };
+	struct mipi_dsi_device *panel;
+	struct device_node *np;
 	struct input_dev *input;
 	unsigned long irq_flags;
 	int error;
@@ -1173,7 +1177,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 
 	error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
 	if (error) {
-		dev_err(&client->dev, "touchscreen probe failed\n");
+		dev_dbg(&client->dev, "touchscreen probe failed\n");
 		return error;
 	}
 
@@ -1242,6 +1246,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 	if (error)
 		return error;
 
+	np = of_parse_phandle(client->dev.of_node, "panel", 0);
+	if (np) {
+		panel = of_find_mipi_dsi_device_by_node(np);
+		of_node_put(np);
+		if (!panel)
+			return -EPROBE_DEFER;
+
+		device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS |
+				DL_FLAG_AUTOREMOVE_SUPPLIER);
+		put_device(&panel->dev);
+	}
+
 	edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
 
 	dev_dbg(&client->dev,
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 6612f9e2d7e8..dee33d8dd9f6 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -21,6 +21,7 @@
 #include <linux/input/touchscreen.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <drm/drm_mipi_dsi.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/regulator/consumer.h>
@@ -1204,6 +1205,8 @@ static int goodix_ts_probe(struct i2c_client *client,
 			   const struct i2c_device_id *id)
 {
 	struct goodix_ts_data *ts;
+	struct mipi_dsi_device *panel;
+	struct device_node *np;
 	int error;
 
 	dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
@@ -1303,6 +1306,17 @@ static int goodix_ts_probe(struct i2c_client *client,
 			return error;
 	}
 
+	np = of_parse_phandle(client->dev.of_node, "panel", 0);
+	if (np) {
+		panel = of_find_mipi_dsi_device_by_node(np);
+		of_node_put(np);
+		if (!panel)
+			return -EPROBE_DEFER;
+		device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS |
+				DL_FLAG_AUTOREMOVE_SUPPLIER);
+		put_device(&panel->dev);
+	}
+
 	return 0;
 }
 
@@ -1358,6 +1372,7 @@ static int __maybe_unused goodix_suspend(struct device *dev)
 	 * sooner, delay 58ms here.
 	 */
 	msleep(58);
+
 	return 0;
 }
 
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 863eda048265..7d845d86a474 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -97,6 +97,12 @@ extern "C" {
 #define  DRM_MODE_FLAG_3D_TOP_AND_BOTTOM	(7<<14)
 #define  DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF	(8<<14)
 
+/* flags for polarity clock & data enable polarities */
+#define DRM_MODE_FLAG_PPIXDATA			(1 << 19)
+#define DRM_MODE_FLAG_NPIXDATA			(1 << 20)
+#define DRM_MODE_FLAG_PDE			(1 << 21)
+#define DRM_MODE_FLAG_NDE			(1 << 22)
+
 /* Picture aspect ratio options */
 #define DRM_MODE_PICTURE_ASPECT_NONE		0
 #define DRM_MODE_PICTURE_ASPECT_4_3		1
-- 
2.17.1

