From 426f0642e86d7c27cfa47e635cd6cf79ec63c29b Mon Sep 17 00:00:00 2001
From: Robert Chiras <robert.chiras@nxp.com>
Date: Fri, 1 Mar 2019 10:40:10 +0200
Subject: [PATCH] MLK-20718-5: drm/imx: nwl_dsi-imx: Correct clk usage

For QM and QXP, the PHY_REF clock was default ON on SCFW so it was not
handled by driver. Since now this clock is OFF in SCFW, it can be
correctly handled by kernel driver.
Now, the PHY_REF clock rate is set by the nwl-dsi bridge driver,
depending on the display mode used.
In this driver, the PIXEL and BYPASS clocks rates were set to the same
rate as the PHY_REF, but their rates need to be set to current display
mode clock.
Also, the order of the clocks matters, so make sure the BYPASS is
enabled before the PIXEL clock.

Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
Reviewed-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
---
 drivers/gpu/drm/imx/nwl_dsi-imx.c | 70 +++++++++++++++++++------------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/imx/nwl_dsi-imx.c b/drivers/gpu/drm/imx/nwl_dsi-imx.c
index 85ee45a125025f..da1239f350bcef 100644
--- a/drivers/gpu/drm/imx/nwl_dsi-imx.c
+++ b/drivers/gpu/drm/imx/nwl_dsi-imx.c
@@ -117,9 +117,9 @@ static struct devtype imx8qm_dev = {
 	.poweroff = &imx8qm_dsi_poweroff,
 	.clk_config = {
 		{ .id = CLK_CORE,   .present = false },
-		{ .id = CLK_PIXEL,  .present = true },
-		{ .id = CLK_BYPASS, .present = true },
 		{ .id = CLK_PHYREF, .present = true },
+		{ .id = CLK_BYPASS, .present = true },
+		{ .id = CLK_PIXEL,  .present = true },
 	},
 	.ext_regs = IMX_REG_CSR,
 	.tx_ulps_reg   = 0x00,
@@ -134,9 +134,9 @@ static struct devtype imx8qxp_dev = {
 	.poweroff = &imx8qxp_dsi_poweroff,
 	.clk_config = {
 		{ .id = CLK_CORE,   .present = false },
-		{ .id = CLK_PIXEL,  .present = true },
-		{ .id = CLK_BYPASS, .present = true },
 		{ .id = CLK_PHYREF, .present = true },
+		{ .id = CLK_BYPASS, .present = true },
+		{ .id = CLK_PIXEL,  .present = true },
 	},
 	.ext_regs = IMX_REG_CSR,
 	.tx_ulps_reg   = 0x30,
@@ -177,28 +177,10 @@ static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable)
 	struct device *dev = dsi->dev;
 	const char *id;
 	struct clk *clk;
-	unsigned long new_rate, cur_rate, phy_rate = 0;
+	unsigned long new_rate, cur_rate;
 	bool enabled;
 	size_t i;
 
-	/*
-	 * PHY_REF rate should be set by the nwl-dsi bridge, depending on the
-	 * current mode used. We need that rate to set the PIXEL clock for
-	 * QM or QXP.
-	 */
-	for (i = 0; i < dsi->clk_num; i++) {
-		if (!dsi->clk_config[i].present)
-			continue;
-		id = dsi->clk_config[i].id;
-		clk = dsi->clk_config[i].clk;
-
-		if (!strcmp(id, CLK_BYPASS) || !strcmp(id, CLK_PHYREF)) {
-			dsi->clk_config[i].rate = clk_get_rate(clk);
-			phy_rate = dsi->clk_config[i].rate;
-			break;
-		}
-	}
-
 	for (i = 0; i < dsi->clk_num; i++) {
 		if (!dsi->clk_config[i].present)
 			continue;
@@ -208,9 +190,6 @@ static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable)
 		cur_rate = clk_get_rate(clk);
 		enabled = dsi->clk_config[i].enabled;
 
-		if (!strcmp(id, CLK_PIXEL) && phy_rate)
-			new_rate = phy_rate;
-
 		if (enable) {
 			if (enabled && new_rate != cur_rate)
 				clk_disable_unprepare(clk);
@@ -571,6 +550,25 @@ static bool imx_nwl_dsi_mode_fixup(struct imx_mipi_dsi *dsi,
 	return true;
 }
 
+static void imx_nwl_dsi_mode_set(struct imx_mipi_dsi *dsi,
+				 struct drm_display_mode *mode)
+{	const char *id;
+	struct clk *clk;
+	size_t i;
+
+	for (i = 0; i < dsi->clk_num; i++) {
+		if (!dsi->clk_config[i].present)
+			continue;
+		id = dsi->clk_config[i].id;
+		clk = dsi->clk_config[i].clk;
+
+		/* Set bypass and pixel clocks to mode clock rate */
+		if (!strcmp(id, CLK_BYPASS) || !strcmp(id, CLK_PIXEL))
+			dsi->clk_config[i].rate = mode->crtc_clock * 1000;
+	}
+
+}
+
 static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
@@ -583,11 +581,21 @@ static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 	return !imx_nwl_dsi_mode_fixup(dsi, &crtc_state->adjusted_mode);
 }
 
+static void imx_nwl_dsi_encoder_mode_set(struct drm_encoder *encoder,
+			 struct drm_display_mode *mode,
+			 struct drm_display_mode *adjusted_mode)
+{
+	struct imx_mipi_dsi *dsi = encoder_to_dsi(encoder);
+
+	imx_nwl_dsi_mode_set(dsi, adjusted_mode);
+}
+
 static const struct drm_encoder_helper_funcs
 imx_nwl_dsi_encoder_helper_funcs = {
 	.enable = imx_nwl_dsi_encoder_enable,
 	.disable = imx_nwl_dsi_encoder_disable,
 	.atomic_check = imx_nwl_dsi_encoder_atomic_check,
+	.mode_set = imx_nwl_dsi_encoder_mode_set,
 };
 
 static void imx_nwl_dsi_encoder_destroy(struct drm_encoder *encoder)
@@ -625,6 +633,15 @@ static bool imx_nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	return imx_nwl_dsi_mode_fixup(dsi, adjusted);
 }
 
+static void imx_nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
+			   struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted)
+{
+	struct imx_mipi_dsi *dsi = bridge->driver_private;
+
+	imx_nwl_dsi_mode_set(dsi, adjusted);
+}
+
 static int imx_nwl_dsi_bridge_attach(struct drm_bridge *bridge)
 {
 	struct imx_mipi_dsi *dsi = bridge->driver_private;
@@ -663,6 +680,7 @@ static const struct drm_bridge_funcs imx_nwl_dsi_bridge_funcs = {
 	.enable = imx_nwl_dsi_bridge_enable,
 	.disable = imx_nwl_dsi_bridge_disable,
 	.mode_fixup = imx_nwl_dsi_bridge_mode_fixup,
+	.mode_set = imx_nwl_dsi_bridge_mode_set,
 	.attach = imx_nwl_dsi_bridge_attach,
 	.detach = imx_nwl_dsi_bridge_detach,
 };
-- 
GitLab