linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] drm: rcar-du: Rework clock configuration
@ 2018-07-30 17:20 Jacopo Mondi
  2018-07-30 17:20 ` [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits Jacopo Mondi
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Jacopo Mondi @ 2018-07-30 17:20 UTC (permalink / raw)
  To: Laurent Pinchart, David Airlie
  Cc: Jacopo Mondi, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list

Hello
   this series improves the DU peripheral input clock selection procedure,
fixing high-resolution modes for non-DPLL channels, as DPAD and LVDS ones.

The first patch in the series is a rework from Laurent of the clock selection
procedure, clearly separating DPLL equipped channels from channels only
equipped with an interanl divider.

The non-DPLL channels clock input selection procedure is improved in patch
[3/3] by exploiting the external clock source ability to generate the desired
pixel clock (when possible).

This improvements is sparkled from the following BSP patch
https://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas-bsp.git/commit/
?id=32e9be612773ce0ed75295a10764151633938528

that un-conditionally uses the externally generated clock source as output
pixel clock.

Tested on M3-W Salvator-X board and VGA output: fixes 1920x1080 display.

Jacopo Mondi (2):
  drm: rcar-du: Rename var to a more precise name
  drm: rcar-du: Improve non-DPLL clock selection

Laurent Pinchart (1):
  drm: rcar-du: Rework clock configuration based on hardware limits

 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 182 ++++++++++++++++++++++-----------
 1 file changed, 122 insertions(+), 60 deletions(-)

--
2.7.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits
  2018-07-30 17:20 [PATCH 0/3] drm: rcar-du: Rework clock configuration Jacopo Mondi
@ 2018-07-30 17:20 ` Jacopo Mondi
  2018-09-14 13:56   ` jacopo mondi
  2018-07-30 17:20 ` [PATCH 2/3] drm: rcar-du: Rename var to a more precise name Jacopo Mondi
  2018-07-30 17:20 ` [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection Jacopo Mondi
  2 siblings, 1 reply; 10+ messages in thread
From: Jacopo Mondi @ 2018-07-30 17:20 UTC (permalink / raw)
  To: Laurent Pinchart, David Airlie
  Cc: Jacopo Mondi, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

The DU channels that have a display PLL (DPLL) can only use external
clock sources, and don't have an internal clock divider (with the
exception of H3 ES1.x where the post-divider is present and needs to be
used as a workaround for a DPLL silicon issue).

Rework the clock configuration to take this into account, avoiding
selection of non-existing clock sources or usage of a missing
post-divider.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 122 ++++++++++++++++++---------------
 1 file changed, 67 insertions(+), 55 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index b52b3e8..6d55cec 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -208,78 +208,90 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
 	struct rcar_du_device *rcdu = rcrtc->group->dev;
 	unsigned long mode_clock = mode->clock * 1000;
-	unsigned long clk;
 	u32 value;
 	u32 escr;
-	u32 div;
 
-	/*
-	 * Compute the clock divisor and select the internal or external dot
-	 * clock based on the requested frequency.
-	 */
-	clk = clk_get_rate(rcrtc->clock);
-	div = DIV_ROUND_CLOSEST(clk, mode_clock);
-	div = clamp(div, 1U, 64U) - 1;
-	escr = div | ESCR_DCLKSEL_CLKS;
-
-	if (rcrtc->extclock) {
+	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
+		unsigned long target = mode_clock;
 		struct dpll_info dpll = { 0 };
 		unsigned long extclk;
-		unsigned long extrate;
-		unsigned long rate;
-		u32 extdiv;
+		u32 dpllcr;
+		u32 div = 0;
 
-		extclk = clk_get_rate(rcrtc->extclock);
-		if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
-			unsigned long target = mode_clock;
+		/*
+		 * DU channels that have a display PLL can't use the internal
+		 * system clock, and have no internal clock divider.
+		 */
 
-			/*
-			 * The H3 ES1.x exhibits dot clock duty cycle stability
-			 * issues. We can work around them by configuring the
-			 * DPLL to twice the desired frequency, coupled with a
-			 * /2 post-divider. This isn't needed on other SoCs and
-			 * breaks HDMI output on M3-W for a currently unknown
-			 * reason, so restrict the workaround to H3 ES1.x.
-			 */
-			if (soc_device_match(rcar_du_r8a7795_es1))
-				target *= 2;
+		if (WARN_ON(!rcrtc->extclock))
+			return;
 
-			rcar_du_dpll_divider(rcrtc, &dpll, extclk, target);
-			extclk = dpll.output;
+		/*
+		 * The H3 ES1.x exhibits dot clock duty cycle stability issues.
+		 * We can work around them by configuring the DPLL to twice the
+		 * desired frequency, coupled with a /2 post-divider. Restrict
+		 * the workaround to H3 ES1.x as ES2.0 and all other SoCs have
+		 * no post-divider when a display PLL is present (as shown by
+		 * the workaround breaking HDMI output on M3-W during testing).
+		 */
+		if (soc_device_match(rcar_du_r8a7795_es1)) {
+			target *= 2;
+			div = 1;
 		}
 
-		extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
-		extdiv = clamp(extdiv, 1U, 64U) - 1;
+		extclk = clk_get_rate(rcrtc->extclock);
+		rcar_du_dpll_divider(rcrtc, &dpll, extclk, target);
 
-		rate = clk / (div + 1);
-		extrate = extclk / (extdiv + 1);
+		dpllcr = DPLLCR_CODE | DPLLCR_CLKE
+		       | DPLLCR_FDPLL(dpll.fdpll)
+		       | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
+		       | DPLLCR_STBY;
 
-		if (abs((long)extrate - (long)mode_clock) <
-		    abs((long)rate - (long)mode_clock)) {
+		if (rcrtc->index == 1)
+			dpllcr |= DPLLCR_PLCS1
+			       |  DPLLCR_INCS_DOTCLKIN1;
+		else
+			dpllcr |= DPLLCR_PLCS0
+			       |  DPLLCR_INCS_DOTCLKIN0;
 
-			if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
-				u32 dpllcr = DPLLCR_CODE | DPLLCR_CLKE
-					   | DPLLCR_FDPLL(dpll.fdpll)
-					   | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
-					   | DPLLCR_STBY;
+		rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr);
 
-				if (rcrtc->index == 1)
-					dpllcr |= DPLLCR_PLCS1
-					       |  DPLLCR_INCS_DOTCLKIN1;
-				else
-					dpllcr |= DPLLCR_PLCS0
-					       |  DPLLCR_INCS_DOTCLKIN0;
+		escr = ESCR_DCLKSEL_DCLKIN | div;
+	} else {
+		unsigned long clk;
+		u32 div;
 
-				rcar_du_group_write(rcrtc->group, DPLLCR,
-						    dpllcr);
-			}
+		/*
+		 * Compute the clock divisor and select the internal or external
+		 * dot clock based on the requested frequency.
+		 */
+		clk = clk_get_rate(rcrtc->clock);
+		div = DIV_ROUND_CLOSEST(clk, mode_clock);
+		div = clamp(div, 1U, 64U) - 1;
 
-			escr = ESCR_DCLKSEL_DCLKIN | extdiv;
-		}
+		escr = ESCR_DCLKSEL_CLKS | div;
 
-		dev_dbg(rcrtc->group->dev->dev,
-			"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
-			mode_clock, extrate, rate, escr);
+		if (rcrtc->extclock) {
+			unsigned long extclk;
+			unsigned long extrate;
+			unsigned long rate;
+			u32 extdiv;
+
+			extclk = clk_get_rate(rcrtc->extclock);
+			extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
+			extdiv = clamp(extdiv, 1U, 64U) - 1;
+
+			extrate = extclk / (extdiv + 1);
+			rate = clk / (div + 1);
+
+			if (abs((long)extrate - (long)mode_clock) <
+			    abs((long)rate - (long)mode_clock))
+				escr = ESCR_DCLKSEL_DCLKIN | extdiv;
+
+			dev_dbg(rcrtc->group->dev->dev,
+				"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
+				mode_clock, extrate, rate, escr);
+		}
 	}
 
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] drm: rcar-du: Rename var to a more precise name
  2018-07-30 17:20 [PATCH 0/3] drm: rcar-du: Rework clock configuration Jacopo Mondi
  2018-07-30 17:20 ` [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits Jacopo Mondi
@ 2018-07-30 17:20 ` Jacopo Mondi
  2018-07-31  8:24   ` Sergei Shtylyov
                     ` (2 more replies)
  2018-07-30 17:20 ` [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection Jacopo Mondi
  2 siblings, 3 replies; 10+ messages in thread
From: Jacopo Mondi @ 2018-07-30 17:20 UTC (permalink / raw)
  To: Laurent Pinchart, David Airlie
  Cc: Jacopo Mondi, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

Rename the 'value' variable, only used to for writing to DMSR register to a
more precise 'dmsr' name.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 6d55cec..4d7907c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -208,7 +208,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
 	struct rcar_du_device *rcdu = rcrtc->group->dev;
 	unsigned long mode_clock = mode->clock * 1000;
-	u32 value;
+	u32 dsmr;
 	u32 escr;
 
 	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
@@ -299,11 +299,11 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
 
 	/* Signal polarities */
-	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
-	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
-	      | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
-	      | DSMR_DIPM_DISP | DSMR_CSPM;
-	rcar_du_crtc_write(rcrtc, DSMR, value);
+	dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
+	       | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
+	       | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
+	       | DSMR_DIPM_DISP | DSMR_CSPM;
+	rcar_du_crtc_write(rcrtc, DSMR, dsmr);
 
 	/* Display timings */
 	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection
  2018-07-30 17:20 [PATCH 0/3] drm: rcar-du: Rework clock configuration Jacopo Mondi
  2018-07-30 17:20 ` [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits Jacopo Mondi
  2018-07-30 17:20 ` [PATCH 2/3] drm: rcar-du: Rename var to a more precise name Jacopo Mondi
@ 2018-07-30 17:20 ` Jacopo Mondi
  2018-08-20 10:30   ` Laurent Pinchart
  2 siblings, 1 reply; 10+ messages in thread
From: Jacopo Mondi @ 2018-07-30 17:20 UTC (permalink / raw)
  To: Laurent Pinchart, David Airlie
  Cc: Jacopo Mondi, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list

DU channels not equipped with a DPLL use an internal (aka SoC provided) or
external clock source combined with an internal divider to generate the
desired output dot clock frequency.

The current clock selection procedure does not fully exploit the ability
of external clock sources to generate the exact dot clock frequency by
themselves, but relies instead on tuning the internal DU clock divider
only, resulting in a less precise clock generation process.

When possible, and desirable, ask the external clock source for the exact
output dot clock frequency, and test all available clock sources (internally
generated clock, externally generated clock rounded to the closest possible
frequency, and not rounded externally generated clock) to better approximate
the desired output dot clock.

This patch specifically targets platforms (like Salvator-X[S] and ULCBs)
where the DU's input dotclock.in is generated by the versaclock VC5 clock
source, which is capable of generating the exact rate the DU needs as pixel
clock output.

This patch fixes higher resolution modes wich requires an high pixel clock
output currently not working on non-HDMI DU channel (as VGA 1920x1080@60Hz).

Fixes: 1b30dbde8 "drm: rcar-du: Add support for external pixel clock"

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 96 ++++++++++++++++++++++++++--------
 1 file changed, 73 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 4d7907c..0dfb28ff 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -207,12 +207,12 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 {
 	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
 	struct rcar_du_device *rcdu = rcrtc->group->dev;
-	unsigned long mode_clock = mode->clock * 1000;
+	unsigned long mode_pixelclock = mode->clock * 1000;
 	u32 dsmr;
 	u32 escr;
 
 	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
-		unsigned long target = mode_clock;
+		unsigned long target = mode_pixelclock;
 		struct dpll_info dpll = { 0 };
 		unsigned long extclk;
 		u32 dpllcr;
@@ -258,42 +258,92 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 
 		escr = ESCR_DCLKSEL_DCLKIN | div;
 	} else {
-		unsigned long clk;
+		struct du_clkin_desc {
+			unsigned long dist;
+			unsigned long rate;
+			struct clk *clk;
+			u32 escr;
+		} du_clkins[3];
+		struct du_clkin_desc *du_clkin = du_clkins;
+		struct du_clkin_desc *clkin_best;
+		unsigned long best = -1UL;
+		unsigned long pixelclock;
+		unsigned long cpgrate;
 		u32 div;
 
 		/*
 		 * Compute the clock divisor and select the internal or external
 		 * dot clock based on the requested frequency.
 		 */
-		clk = clk_get_rate(rcrtc->clock);
-		div = DIV_ROUND_CLOSEST(clk, mode_clock);
-		div = clamp(div, 1U, 64U) - 1;
+		cpgrate = clk_get_rate(rcrtc->clock);
+		div = clamp(DIV_ROUND_CLOSEST(cpgrate, mode_pixelclock),
+			    1UL, 64UL) - 1;
+		pixelclock = cpgrate / (div + 1);
 
-		escr = ESCR_DCLKSEL_CLKS | div;
+		du_clkin->dist = abs(pixelclock - mode_pixelclock);
+		du_clkin->escr = ESCR_DCLKSEL_CLKS | div;
+		du_clkin->clk = rcrtc->clock;
+		du_clkin->rate = cpgrate;
+		clkin_best = du_clkin;
 
 		if (rcrtc->extclock) {
-			unsigned long extclk;
+			unsigned long roundrate;
 			unsigned long extrate;
-			unsigned long rate;
-			u32 extdiv;
-
-			extclk = clk_get_rate(rcrtc->extclock);
-			extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
-			extdiv = clamp(extdiv, 1U, 64U) - 1;
 
-			extrate = extclk / (extdiv + 1);
-			rate = clk / (div + 1);
-
-			if (abs((long)extrate - (long)mode_clock) <
-			    abs((long)rate - (long)mode_clock))
-				escr = ESCR_DCLKSEL_DCLKIN | extdiv;
+			/*
+			 * If an external clock source is present ask it
+			 * for the exact dot clock rate, and test all possible
+			 * combinations (internal, external rounded, external
+			 * not rounded) to achieve the best possible clock
+			 * accuracy.
+			 */
+			extrate = clk_get_rate(rcrtc->extclock);
+			roundrate = clk_round_rate(rcrtc->extclock,
+						   mode_pixelclock);
+
+			if (roundrate == mode_pixelclock) {
+				/* We can't do better than this... */
+				clk_set_rate(rcrtc->extclock, roundrate);
+				escr = ESCR_DCLKSEL_DCLKIN;
+				goto set_escr;
+			}
 
-			dev_dbg(rcrtc->group->dev->dev,
-				"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
-				mode_clock, extrate, rate, escr);
+			/* Test the external clock 'plain' rate. */
+			du_clkin++;
+			div = clamp(DIV_ROUND_CLOSEST(extrate, mode_pixelclock),
+				    1UL, 64UL) - 1;
+			pixelclock = extrate / (div + 1);
+			du_clkin->dist = abs(pixelclock - mode_pixelclock);
+			du_clkin->escr = ESCR_DCLKSEL_DCLKIN | div;
+			du_clkin->clk = rcrtc->extclock;
+			du_clkin->rate = extrate;
+
+			/* Test the external clock 'rounded' rate. */
+			du_clkin++;
+			div = clamp(DIV_ROUND_CLOSEST(roundrate, mode_pixelclock),
+				    1UL, 64UL) - 1;
+			pixelclock = roundrate / (div + 1);
+			du_clkin->dist = abs(pixelclock - mode_pixelclock);
+			du_clkin->escr = ESCR_DCLKSEL_DCLKIN | div;
+			du_clkin->clk = rcrtc->extclock;
+			du_clkin->rate = roundrate;
+
+			/* Find out the best approximation we got. */
+			for (; du_clkin >= du_clkins; --du_clkin) {
+				if (du_clkin->dist < best) {
+					best = du_clkin->dist;
+					clkin_best = du_clkin;
+				}
+			}
+			clk_set_rate(clkin_best->clk, clkin_best->rate);
 		}
+
+		escr = clkin_best->escr;
 	}
 
+set_escr:
+	dev_err(rcrtc->group->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
+
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
 			    escr);
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] drm: rcar-du: Rename var to a more precise name
  2018-07-30 17:20 ` [PATCH 2/3] drm: rcar-du: Rename var to a more precise name Jacopo Mondi
@ 2018-07-31  8:24   ` Sergei Shtylyov
  2018-08-06 15:49   ` Kieran Bingham
  2018-08-20 10:18   ` Laurent Pinchart
  2 siblings, 0 replies; 10+ messages in thread
From: Sergei Shtylyov @ 2018-07-31  8:24 UTC (permalink / raw)
  To: Jacopo Mondi, Laurent Pinchart, David Airlie
  Cc: open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

Hello!

On 7/30/2018 8:20 PM, Jacopo Mondi wrote:

> Rename the 'value' variable, only used to for writing to DMSR register to a
                                          ^^ not needed

> more precise 'dmsr' name.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
[...]

MBR, Sergei

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] drm: rcar-du: Rename var to a more precise name
  2018-07-30 17:20 ` [PATCH 2/3] drm: rcar-du: Rename var to a more precise name Jacopo Mondi
  2018-07-31  8:24   ` Sergei Shtylyov
@ 2018-08-06 15:49   ` Kieran Bingham
  2018-08-06 17:08     ` Laurent Pinchart
  2018-08-20 10:18   ` Laurent Pinchart
  2 siblings, 1 reply; 10+ messages in thread
From: Kieran Bingham @ 2018-08-06 15:49 UTC (permalink / raw)
  To: Jacopo Mondi, Laurent Pinchart, David Airlie
  Cc: open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

Hi Jacopo,

Thankyou for the patch,

On 30/07/18 18:20, Jacopo Mondi wrote:
> Rename the 'value' variable, only used to for writing to DMSR register to a
> more precise 'dmsr' name.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 6d55cec..4d7907c 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -208,7 +208,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
>  	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
>  	struct rcar_du_device *rcdu = rcrtc->group->dev;
>  	unsigned long mode_clock = mode->clock * 1000;
> -	u32 value;
> +	u32 dsmr;
>  	u32 escr;
>  
>  	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> @@ -299,11 +299,11 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
>  	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
>  
>  	/* Signal polarities */
> -	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
> -	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
> -	      | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
> -	      | DSMR_DIPM_DISP | DSMR_CSPM;
> -	rcar_du_crtc_write(rcrtc, DSMR, value);
> +	dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
> +	       | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
> +	       | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
> +	       | DSMR_DIPM_DISP | DSMR_CSPM;

Quite nit-picky I'm afraid, but here, you have increased the indent such
that the '|' operator is now aligned with the first '(', rather than the
'=' as used by the rest of the driver.

Was this intentional ?

I think it should be brought forwards to align under the '=' to match.


> +	rcar_du_crtc_write(rcrtc, DSMR, dsmr);
>  
>  	/* Display timings */
>  	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] drm: rcar-du: Rename var to a more precise name
  2018-08-06 15:49   ` Kieran Bingham
@ 2018-08-06 17:08     ` Laurent Pinchart
  0 siblings, 0 replies; 10+ messages in thread
From: Laurent Pinchart @ 2018-08-06 17:08 UTC (permalink / raw)
  To: kieran.bingham+renesas
  Cc: Jacopo Mondi, David Airlie, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

Hi Kieran,

On Monday, 6 August 2018 18:49:12 EEST Kieran Bingham wrote:
> On 30/07/18 18:20, Jacopo Mondi wrote:
> > Rename the 'value' variable, only used to for writing to DMSR register to
> > a more precise 'dmsr' name.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> > 
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 12 ++++++------
> >  1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 6d55cec..4d7907c 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > @@ -208,7 +208,7 @@ static void rcar_du_crtc_set_display_timing(struct
> > rcar_du_crtc *rcrtc)> 
> >  	const struct drm_display_mode *mode = &rcrtc->crtc.state-
>adjusted_mode;
> >  	struct rcar_du_device *rcdu = rcrtc->group->dev;
> >  	unsigned long mode_clock = mode->clock * 1000;
> > 
> > -	u32 value;
> > +	u32 dsmr;
> > 
> >  	u32 escr;
> >  	
> >  	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> > 
> > @@ -299,11 +299,11 @@ static void rcar_du_crtc_set_display_timing(struct
> > rcar_du_crtc *rcrtc)> 
> >  	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
> >  	
> >  	/* Signal polarities */
> > 
> > -	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
> > -	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
> > -	      | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
> > -	      | DSMR_DIPM_DISP | DSMR_CSPM;
> > -	rcar_du_crtc_write(rcrtc, DSMR, value);
> > +	dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
> > +	       | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
> > +	       | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
> > +	       | DSMR_DIPM_DISP | DSMR_CSPM;
> 
> Quite nit-picky I'm afraid, but here, you have increased the indent such
> that the '|' operator is now aligned with the first '(', rather than the
> '=' as used by the rest of the driver.
> 
> Was this intentional ?
> 
> I think it should be brought forwards to align under the '=' to match.

Agreed.

For the record, this change was part of patch 1/3 that I provided on its own 
to Jacopo, who then split it out. I'd be inclined to squash the two changes 
back together, I don't think this rename requires a patch of its own.

> > +	rcar_du_crtc_write(rcrtc, DSMR, dsmr);
> > 
> >  	/* Display timings */
> >  	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);

-- 
Regards,

Laurent Pinchart




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] drm: rcar-du: Rename var to a more precise name
  2018-07-30 17:20 ` [PATCH 2/3] drm: rcar-du: Rename var to a more precise name Jacopo Mondi
  2018-07-31  8:24   ` Sergei Shtylyov
  2018-08-06 15:49   ` Kieran Bingham
@ 2018-08-20 10:18   ` Laurent Pinchart
  2 siblings, 0 replies; 10+ messages in thread
From: Laurent Pinchart @ 2018-08-20 10:18 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: David Airlie, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

Hi Jacopo,

Thank you for the patch.

On Monday, 30 July 2018 20:20:13 EEST Jacopo Mondi wrote:
> Rename the 'value' variable, only used to for writing to DMSR register to a
> more precise 'dmsr' name.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>

I think this simple change can be squashed with patch 1/3.

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 6d55cec..4d7907c 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -208,7 +208,7 @@ static void rcar_du_crtc_set_display_timing(struct
> rcar_du_crtc *rcrtc) const struct drm_display_mode *mode =
> &rcrtc->crtc.state->adjusted_mode; struct rcar_du_device *rcdu =
> rcrtc->group->dev;
>  	unsigned long mode_clock = mode->clock * 1000;
> -	u32 value;
> +	u32 dsmr;
>  	u32 escr;
> 
>  	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> @@ -299,11 +299,11 @@ static void rcar_du_crtc_set_display_timing(struct
> rcar_du_crtc *rcrtc) rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ?
> OTAR2 : OTAR, 0);
> 
>  	/* Signal polarities */
> -	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
> -	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
> -	      | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
> -	      | DSMR_DIPM_DISP | DSMR_CSPM;
> -	rcar_du_crtc_write(rcrtc, DSMR, value);
> +	dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
> +	       | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
> +	       | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
> +	       | DSMR_DIPM_DISP | DSMR_CSPM;
> +	rcar_du_crtc_write(rcrtc, DSMR, dsmr);
> 
>  	/* Display timings */
>  	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);


-- 
Regards,

Laurent Pinchart




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection
  2018-07-30 17:20 ` [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection Jacopo Mondi
@ 2018-08-20 10:30   ` Laurent Pinchart
  0 siblings, 0 replies; 10+ messages in thread
From: Laurent Pinchart @ 2018-08-20 10:30 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: David Airlie, open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list

Hi Jacopo,

Thank you for the patch.

On Monday, 30 July 2018 20:20:14 EEST Jacopo Mondi wrote:
> DU channels not equipped with a DPLL use an internal (aka SoC provided) or
> external clock source combined with an internal divider to generate the
> desired output dot clock frequency.
> 
> The current clock selection procedure does not fully exploit the ability
> of external clock sources to generate the exact dot clock frequency by
> themselves, but relies instead on tuning the internal DU clock divider
> only, resulting in a less precise clock generation process.
> 
> When possible, and desirable, ask the external clock source for the exact
> output dot clock frequency, and test all available clock sources (internally
> generated clock, externally generated clock rounded to the closest possible
> frequency, and not rounded externally generated clock) to better
> approximate the desired output dot clock.

I don't think you need to care about the "not rounded externally generated 
clock" (which incidentally isn't really about rounding, but about requesting a 
specific rate), for two reasons.

The first one is that I don't think using whatever rate is currently 
programmed for the external clock will lead to a better result. There's no 
real reason why the current external rate would be better, other than possibly 
just chance, and I don't think we should rely on chance.

The second reason is that it would lead to a non-deterministic behaviour. The 
system will boot with a default clock rate for the external source, but as 
soon as you set a mode, that rate could change, and will never revert back to 
the default. The second mode you will set will thus depend for its clock 
selection on the modes previously set, generating all kind of bugs difficult 
to reproduce.

> This patch specifically targets platforms (like Salvator-X[S] and ULCBs)
> where the DU's input dotclock.in is generated by the versaclock VC5 clock
> source, which is capable of generating the exact rate the DU needs as pixel
> clock output.
> 
> This patch fixes higher resolution modes wich requires an high pixel clock
> output currently not working on non-HDMI DU channel (as VGA 1920x1080@60Hz).
> 
> Fixes: 1b30dbde8 "drm: rcar-du: Add support for external pixel clock"
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 96 ++++++++++++++++++++++++------
>  1 file changed, 73 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 4d7907c..0dfb28ff 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -207,12 +207,12 @@ static void rcar_du_crtc_set_display_timing(struct
> rcar_du_crtc *rcrtc) {
>  	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
>  	struct rcar_du_device *rcdu = rcrtc->group->dev;
> -	unsigned long mode_clock = mode->clock * 1000;
> +	unsigned long mode_pixelclock = mode->clock * 1000;
>  	u32 dsmr;
>  	u32 escr;
> 
>  	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> -		unsigned long target = mode_clock;
> +		unsigned long target = mode_pixelclock;
>  		struct dpll_info dpll = { 0 };
>  		unsigned long extclk;
>  		u32 dpllcr;
> @@ -258,42 +258,92 @@ static void rcar_du_crtc_set_display_timing(struct
> rcar_du_crtc *rcrtc)
> 
>  		escr = ESCR_DCLKSEL_DCLKIN | div;
>  	} else {
> -		unsigned long clk;
> +		struct du_clkin_desc {
> +			unsigned long dist;
> +			unsigned long rate;
> +			struct clk *clk;
> +			u32 escr;
> +		} du_clkins[3];
> +		struct du_clkin_desc *du_clkin = du_clkins;
> +		struct du_clkin_desc *clkin_best;
> +		unsigned long best = -1UL;
> +		unsigned long pixelclock;
> +		unsigned long cpgrate;
>  		u32 div;
> 
>  		/*
>  		 * Compute the clock divisor and select the internal or external
>  		 * dot clock based on the requested frequency.
>  		 */
> -		clk = clk_get_rate(rcrtc->clock);
> -		div = DIV_ROUND_CLOSEST(clk, mode_clock);
> -		div = clamp(div, 1U, 64U) - 1;
> +		cpgrate = clk_get_rate(rcrtc->clock);
> +		div = clamp(DIV_ROUND_CLOSEST(cpgrate, mode_pixelclock),
> +			    1UL, 64UL) - 1;
> +		pixelclock = cpgrate / (div + 1);
> 
> -		escr = ESCR_DCLKSEL_CLKS | div;
> +		du_clkin->dist = abs(pixelclock - mode_pixelclock);
> +		du_clkin->escr = ESCR_DCLKSEL_CLKS | div;
> +		du_clkin->clk = rcrtc->clock;
> +		du_clkin->rate = cpgrate;
> +		clkin_best = du_clkin;
> 
>  		if (rcrtc->extclock) {
> -			unsigned long extclk;
> +			unsigned long roundrate;
>  			unsigned long extrate;
> -			unsigned long rate;
> -			u32 extdiv;
> -
> -			extclk = clk_get_rate(rcrtc->extclock);
> -			extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
> -			extdiv = clamp(extdiv, 1U, 64U) - 1;
> 
> -			extrate = extclk / (extdiv + 1);
> -			rate = clk / (div + 1);
> -
> -			if (abs((long)extrate - (long)mode_clock) <
> -			    abs((long)rate - (long)mode_clock))
> -				escr = ESCR_DCLKSEL_DCLKIN | extdiv;
> +			/*
> +			 * If an external clock source is present ask it
> +			 * for the exact dot clock rate, and test all possible
> +			 * combinations (internal, external rounded, external
> +			 * not rounded) to achieve the best possible clock
> +			 * accuracy.
> +			 */
> +			extrate = clk_get_rate(rcrtc->extclock);
> +			roundrate = clk_round_rate(rcrtc->extclock,
> +						   mode_pixelclock);
> +
> +			if (roundrate == mode_pixelclock) {
> +				/* We can't do better than this... */
> +				clk_set_rate(rcrtc->extclock, roundrate);
> +				escr = ESCR_DCLKSEL_DCLKIN;
> +				goto set_escr;
> +			}
> 
> -			dev_dbg(rcrtc->group->dev->dev,
> -				"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
> -				mode_clock, extrate, rate, escr);
> +			/* Test the external clock 'plain' rate. */
> +			du_clkin++;
> +			div = clamp(DIV_ROUND_CLOSEST(extrate, mode_pixelclock),
> +				    1UL, 64UL) - 1;
> +			pixelclock = extrate / (div + 1);
> +			du_clkin->dist = abs(pixelclock - mode_pixelclock);
> +			du_clkin->escr = ESCR_DCLKSEL_DCLKIN | div;
> +			du_clkin->clk = rcrtc->extclock;
> +			du_clkin->rate = extrate;

If we remove this option, there will only be two options to compare, and I 
think it would then be possible to keep the current code structure to simplify 
this patch.

> +			/* Test the external clock 'rounded' rate. */
> +			du_clkin++;
> +			div = clamp(DIV_ROUND_CLOSEST(roundrate, mode_pixelclock),
> +				    1UL, 64UL) - 1;
> +			pixelclock = roundrate / (div + 1);
> +			du_clkin->dist = abs(pixelclock - mode_pixelclock);
> +			du_clkin->escr = ESCR_DCLKSEL_DCLKIN | div;
> +			du_clkin->clk = rcrtc->extclock;
> +			du_clkin->rate = roundrate;
> +
> +			/* Find out the best approximation we got. */
> +			for (; du_clkin >= du_clkins; --du_clkin) {
> +				if (du_clkin->dist < best) {
> +					best = du_clkin->dist;
> +					clkin_best = du_clkin;
> +				}
> +			}
> +			clk_set_rate(clkin_best->clk, clkin_best->rate);
>  		}
> +
> +		escr = clkin_best->escr;
>  	}
> 
> +set_escr:
> +	dev_err(rcrtc->group->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
> +
>  	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
>  			    escr);
>  	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);

-- 
Regards,

Laurent Pinchart




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits
  2018-07-30 17:20 ` [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits Jacopo Mondi
@ 2018-09-14 13:56   ` jacopo mondi
  0 siblings, 0 replies; 10+ messages in thread
From: jacopo mondi @ 2018-09-14 13:56 UTC (permalink / raw)
  To: Laurent Pinchart, David Airlie
  Cc: open list:DRM DRIVERS FOR RENESAS,
	open list:DRM DRIVERS FOR RENESAS, open list, Laurent Pinchart

[-- Attachment #1: Type: text/plain, Size: 6038 bytes --]

Hi Laurent,

On Mon, Jul 30, 2018 at 07:20:12PM +0200, Jacopo Mondi wrote:
> From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
>
> The DU channels that have a display PLL (DPLL) can only use external
> clock sources, and don't have an internal clock divider (with the
> exception of H3 ES1.x where the post-divider is present and needs to be
> used as a workaround for a DPLL silicon issue).
>
> Rework the clock configuration to take this into account, avoiding
> selection of non-existing clock sources or usage of a missing
> post-divider.
>

I have based my work on non-DPLL channel selection on this patch, but
always forgot to add my:
Reviewed-by: Jacopo Mondi <jacopo+renesas@jmondi.org>

Thanks
   j

> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 122 ++++++++++++++++++---------------
>  1 file changed, 67 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index b52b3e8..6d55cec 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -208,78 +208,90 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
>  	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
>  	struct rcar_du_device *rcdu = rcrtc->group->dev;
>  	unsigned long mode_clock = mode->clock * 1000;
> -	unsigned long clk;
>  	u32 value;
>  	u32 escr;
> -	u32 div;
>
> -	/*
> -	 * Compute the clock divisor and select the internal or external dot
> -	 * clock based on the requested frequency.
> -	 */
> -	clk = clk_get_rate(rcrtc->clock);
> -	div = DIV_ROUND_CLOSEST(clk, mode_clock);
> -	div = clamp(div, 1U, 64U) - 1;
> -	escr = div | ESCR_DCLKSEL_CLKS;
> -
> -	if (rcrtc->extclock) {
> +	if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> +		unsigned long target = mode_clock;
>  		struct dpll_info dpll = { 0 };
>  		unsigned long extclk;
> -		unsigned long extrate;
> -		unsigned long rate;
> -		u32 extdiv;
> +		u32 dpllcr;
> +		u32 div = 0;
>
> -		extclk = clk_get_rate(rcrtc->extclock);
> -		if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> -			unsigned long target = mode_clock;
> +		/*
> +		 * DU channels that have a display PLL can't use the internal
> +		 * system clock, and have no internal clock divider.
> +		 */
>
> -			/*
> -			 * The H3 ES1.x exhibits dot clock duty cycle stability
> -			 * issues. We can work around them by configuring the
> -			 * DPLL to twice the desired frequency, coupled with a
> -			 * /2 post-divider. This isn't needed on other SoCs and
> -			 * breaks HDMI output on M3-W for a currently unknown
> -			 * reason, so restrict the workaround to H3 ES1.x.
> -			 */
> -			if (soc_device_match(rcar_du_r8a7795_es1))
> -				target *= 2;
> +		if (WARN_ON(!rcrtc->extclock))
> +			return;
>
> -			rcar_du_dpll_divider(rcrtc, &dpll, extclk, target);
> -			extclk = dpll.output;
> +		/*
> +		 * The H3 ES1.x exhibits dot clock duty cycle stability issues.
> +		 * We can work around them by configuring the DPLL to twice the
> +		 * desired frequency, coupled with a /2 post-divider. Restrict
> +		 * the workaround to H3 ES1.x as ES2.0 and all other SoCs have
> +		 * no post-divider when a display PLL is present (as shown by
> +		 * the workaround breaking HDMI output on M3-W during testing).
> +		 */
> +		if (soc_device_match(rcar_du_r8a7795_es1)) {
> +			target *= 2;
> +			div = 1;
>  		}
>
> -		extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
> -		extdiv = clamp(extdiv, 1U, 64U) - 1;
> +		extclk = clk_get_rate(rcrtc->extclock);
> +		rcar_du_dpll_divider(rcrtc, &dpll, extclk, target);
>
> -		rate = clk / (div + 1);
> -		extrate = extclk / (extdiv + 1);
> +		dpllcr = DPLLCR_CODE | DPLLCR_CLKE
> +		       | DPLLCR_FDPLL(dpll.fdpll)
> +		       | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
> +		       | DPLLCR_STBY;
>
> -		if (abs((long)extrate - (long)mode_clock) <
> -		    abs((long)rate - (long)mode_clock)) {
> +		if (rcrtc->index == 1)
> +			dpllcr |= DPLLCR_PLCS1
> +			       |  DPLLCR_INCS_DOTCLKIN1;
> +		else
> +			dpllcr |= DPLLCR_PLCS0
> +			       |  DPLLCR_INCS_DOTCLKIN0;
>
> -			if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
> -				u32 dpllcr = DPLLCR_CODE | DPLLCR_CLKE
> -					   | DPLLCR_FDPLL(dpll.fdpll)
> -					   | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
> -					   | DPLLCR_STBY;
> +		rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr);
>
> -				if (rcrtc->index == 1)
> -					dpllcr |= DPLLCR_PLCS1
> -					       |  DPLLCR_INCS_DOTCLKIN1;
> -				else
> -					dpllcr |= DPLLCR_PLCS0
> -					       |  DPLLCR_INCS_DOTCLKIN0;
> +		escr = ESCR_DCLKSEL_DCLKIN | div;
> +	} else {
> +		unsigned long clk;
> +		u32 div;
>
> -				rcar_du_group_write(rcrtc->group, DPLLCR,
> -						    dpllcr);
> -			}
> +		/*
> +		 * Compute the clock divisor and select the internal or external
> +		 * dot clock based on the requested frequency.
> +		 */
> +		clk = clk_get_rate(rcrtc->clock);
> +		div = DIV_ROUND_CLOSEST(clk, mode_clock);
> +		div = clamp(div, 1U, 64U) - 1;
>
> -			escr = ESCR_DCLKSEL_DCLKIN | extdiv;
> -		}
> +		escr = ESCR_DCLKSEL_CLKS | div;
>
> -		dev_dbg(rcrtc->group->dev->dev,
> -			"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
> -			mode_clock, extrate, rate, escr);
> +		if (rcrtc->extclock) {
> +			unsigned long extclk;
> +			unsigned long extrate;
> +			unsigned long rate;
> +			u32 extdiv;
> +
> +			extclk = clk_get_rate(rcrtc->extclock);
> +			extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
> +			extdiv = clamp(extdiv, 1U, 64U) - 1;
> +
> +			extrate = extclk / (extdiv + 1);
> +			rate = clk / (div + 1);
> +
> +			if (abs((long)extrate - (long)mode_clock) <
> +			    abs((long)rate - (long)mode_clock))
> +				escr = ESCR_DCLKSEL_DCLKIN | extdiv;
> +
> +			dev_dbg(rcrtc->group->dev->dev,
> +				"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
> +				mode_clock, extrate, rate, escr);
> +		}
>  	}
>
>  	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
> --
> 2.7.4
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-09-14 13:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-30 17:20 [PATCH 0/3] drm: rcar-du: Rework clock configuration Jacopo Mondi
2018-07-30 17:20 ` [PATCH 1/3] drm: rcar-du: Rework clock configuration based on hardware limits Jacopo Mondi
2018-09-14 13:56   ` jacopo mondi
2018-07-30 17:20 ` [PATCH 2/3] drm: rcar-du: Rename var to a more precise name Jacopo Mondi
2018-07-31  8:24   ` Sergei Shtylyov
2018-08-06 15:49   ` Kieran Bingham
2018-08-06 17:08     ` Laurent Pinchart
2018-08-20 10:18   ` Laurent Pinchart
2018-07-30 17:20 ` [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection Jacopo Mondi
2018-08-20 10:30   ` Laurent Pinchart

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).