[PATCH v2 2/2] drm: rcar-du: Improve non-DPLL clock selection

Laurent Pinchart laurent.pinchart at ideasonboard.com
Mon Aug 20 20:03:21 UTC 2018


Hi Jacopo,

Thank you for the patch.

On Monday, 20 August 2018 18:26:17 EEST Jacopo Mondi wrote:
> From: Jacopo Mondi <jacopo at jmondi.org>
> 
> DU channels not equipped with a DPLL use an internal (aka SoC provided) or

I'd say "SoC internal (provided by the CPG)"

> external clock source combined with an internal divider to generate the

and here "a DU internal divider" to avoid confusion with an SoC internal 
divider outside of the DU.

> 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 the returned frequency against the
> internally generated one to better approximate the desired output dot clock.

To make this a big more generic, I' say "and select the clock source that 
produces the frequency closest to 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

s/wich/which/

> output currently not working on non-HDMI DU channel (as VGA 1920x1080 at 60Hz).

Maybe "(such as 1920x1080 at 60Hz on the VGA output)" ?
> 
> Fixes: 1b30dbde8 "drm: rcar-du: Add support for external pixel clock"

Please use the output of git show --pretty=fixes to generate the fixes line. 
Your SHA1 needs more digits, and the subject should be enclosed with 
parentheses.

> Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 53 +++++++++++++++++++------------
>  1 file changed, 32 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 077e681..98ae697 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -258,42 +258,53 @@ static void rcar_du_crtc_set_display_timing(struct
> rcar_du_crtc *rcrtc)
> 
>  		escr = ESCR_DCLKSEL_DCLKIN | div;
>  	} else {
> -		unsigned long clk;
> +		unsigned long dotclkin_rate;
> +		struct clk *dotclkin_clk;
> +		unsigned long cpg_dist;
>  		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;
> -
> +		dotclkin_clk = rcrtc->clock;
> +		dotclkin_rate = clk_get_rate(rcrtc->clock);
> +		div = clamp(DIV_ROUND_CLOSEST(dotclkin_rate, mode_clock),
> +			    1UL, 64UL) - 1;
> +		cpg_dist = abs(dotclkin_rate / (div + 1) - mode_clock);
>  		escr = ESCR_DCLKSEL_CLKS | div;
> 
>  		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;
> +			unsigned long ext_rate;
> +			unsigned long ext_dist;
> 
> -			extrate = extclk / (extdiv + 1);
> -			rate = clk / (div + 1);
> +			/*
> +			 * If an external clock source is present ask it
> +			 * for the exact dot clock rate, and test the
> +			 * returned value against the cpg provided one.
> +			 */
> +			ext_rate = clk_round_rate(rcrtc->extclock,
> +						  mode_clock);
> 
> -			if (abs((long)extrate - (long)mode_clock) <
> -			    abs((long)rate - (long)mode_clock))
> -				escr = ESCR_DCLKSEL_DCLKIN | extdiv;
> +			div = clamp(DIV_ROUND_CLOSEST(ext_rate, mode_clock),
> +				    1UL, 64UL) - 1;
> +			ext_dist = abs(ext_rate / (div + 1) - mode_clock);
> 
> -			dev_dbg(rcrtc->group->dev->dev,
> -				"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
> -				mode_clock, extrate, rate, escr);
> +			if (ext_dist < cpg_dist) {
> +				dotclkin_clk = rcrtc->extclock;
> +				dotclkin_rate = ext_rate;
> +				escr = ESCR_DCLKSEL_DCLKIN | div;
> +			}
>  		}

I think we can do something much simpler here by factoring some code out to a 
function. I'll send a proposal in reply to this e-mail.

> +		dev_dbg(rcrtc->group->dev->dev,	"mode clock %lu %s rate %lu\n",
> +			mode_clock, dotclkin_clk == rcrtc->clock ? "cpg" : "ext",
> +			dotclkin_rate);
> +		clk_set_rate(dotclkin_clk, dotclkin_rate);
>  	}
> 
> +	dev_dbg(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





More information about the dri-devel mailing list