svn commit: r309190 - head/sys/arm/allwinner/clk

Emmanuel Vadot manu at bidouilliste.com
Sat Nov 26 11:12:59 UTC 2016


 I should have added that this fix HDMI video output when booting in
non-verbose.

 The PLL wasn't correctly calculated because of the non-usage of the
fractional mode.
 The issue doesn't appears on verbose because the clock framework print
out the clock value when created. To get the clock value it calls the
recalc_freq method of the clock, which read directly the divisor and
other factor from the register. As U-Boot leave the clock enable and
setup, the clock framework will get the value set by U-Boot.
 When choosing the best video mode, we usually end up with the same
choice as U-Boot (because both U-Boot and the driver use EDID to get the
monitor capabilities), meaning we will get the same dotclock frequency.
 When setting the PLL to the dotclock frequency, the clock framework
first compare the current and desired frequency, as they are the same
the underlying methods for setting the clock weren't called.
 When booting in non-verbose mode, the current clock wasn't known so
the methods were called but they wrongly calculated the best frequency
for the dotclock.

On Sat, 26 Nov 2016 10:36:48 +0000 (UTC)
Emmanuel Vadot <manu at FreeBSD.org> wrote:

> Author: manu
> Date: Sat Nov 26 10:36:48 2016
> New Revision: 309190
> URL: https://svnweb.freebsd.org/changeset/base/309190
> 
> Log:
>   PLL3 have a fractional mode where an explicit frequency (297Mhz or 270)
>   can be selected for it. If the desired frequency is one of those two, use
>   this mode instead of the integer one.
>   When calculating the PLL3 freq for the dotclock, check if it is a multiple
>   of the fracional frequencies.
>   
>   MFC after:	2 weeks
> 
> Modified:
>   head/sys/arm/allwinner/clk/aw_lcdclk.c
>   head/sys/arm/allwinner/clk/aw_pll.c
> 
> Modified: head/sys/arm/allwinner/clk/aw_lcdclk.c
> ==============================================================================
> --- head/sys/arm/allwinner/clk/aw_lcdclk.c	Sat Nov 26 10:33:53 2016	(r309189)
> +++ head/sys/arm/allwinner/clk/aw_lcdclk.c	Sat Nov 26 10:36:48 2016	(r309190)
> @@ -78,6 +78,8 @@ __FBSDID("$FreeBSD$");
>  #define	CH1_CLK_DIV_RATIO_M_SHIFT	0
>  
>  #define	TCON_PLLREF			3000000ULL
> +#define	TCON_PLLREF_FRAC1		297000000ULL
> +#define	TCON_PLLREF_FRAC2		270000000ULL
>  #define	TCON_PLL_M_MIN			1
>  #define	TCON_PLL_M_MAX			15
>  #define	TCON_PLL_N_MIN			9
> @@ -290,7 +292,7 @@ aw_lcdclk_recalc_freq(struct clknode *cl
>  }
>  
>  static void
> -calc_tcon_pll(uint64_t fin, uint64_t fout, uint32_t *pm, uint32_t *pn)
> +calc_tcon_pll_integer(uint64_t fin, uint64_t fout, uint32_t *pm, uint32_t *pn)
>  {
>  	int64_t diff, fcur, best;
>  	int m, n;
> @@ -310,14 +312,86 @@ calc_tcon_pll(uint64_t fin, uint64_t fou
>  }
>  
>  static int
> +calc_tcon_pll_fractional(uint64_t fin, uint64_t fout, int *clk_div)
> +{
> +	int m;
> +
> +	/* Test for 1X match */
> +	for (m = TCON_PLL_M_MIN; m <= TCON_PLL_M_MAX; m++) {
> +		if (fout == (fin / m)) {
> +			*clk_div = m;
> +			return (CH0_CLK_SRC_SEL_PLL3_1X);
> +		}
> +	}
> +
> +	/* Test for 2X match */
> +	for (m = TCON_PLL_M_MIN; m <= TCON_PLL_M_MAX; m++) {
> +		if (fout == ((fin * 2) / m)) {
> +			*clk_div = m;
> +			return (CH0_CLK_SRC_SEL_PLL3_2X);
> +		}
> +	}
> +
> +	return (-1);
> +}
> +
> +static int
> +calc_tcon_pll(uint64_t fin, uint64_t fout, uint64_t *pll_freq, int *tcon_pll_div)
> +{
> +	uint32_t m, m2, n, n2;
> +	uint64_t fsingle, fdouble;
> +	int src_sel;
> +	bool dbl;
> +
> +	/* Test fractional freq first */
> +	src_sel = calc_tcon_pll_fractional(TCON_PLLREF_FRAC1, fout,
> +	    tcon_pll_div);
> +	if (src_sel != -1) {
> +		*pll_freq = TCON_PLLREF_FRAC1;
> +		return src_sel;
> +	}
> +	src_sel = calc_tcon_pll_fractional(TCON_PLLREF_FRAC2, fout,
> +	    tcon_pll_div);
> +	if (src_sel != -1) {
> +		*pll_freq = TCON_PLLREF_FRAC2;
> +		return src_sel;
> +	}
> +
> +	m = n = m2 = n2 = 0;
> +	dbl = false;
> +
> +	/* Find the frequency closes to the target dot clock, using
> +	 * both 1X and 2X PLL inputs as possible candidates.
> +	 */
> +	calc_tcon_pll_integer(TCON_PLLREF, fout, &m, &n);
> +	calc_tcon_pll_integer(TCON_PLLREF * 2, fout, &m2, &n2);
> +
> +	fsingle = m ? (n * TCON_PLLREF) / m : 0;
> +	fdouble = m2 ? (n2 * TCON_PLLREF * 2) / m2 : 0;
> +
> +	if (fdouble > fsingle) {
> +		dbl = true;
> +		m = m2;
> +		n = n2;
> +	}
> +
> +	/* Set desired parent frequency */
> +	*pll_freq = n * TCON_PLLREF;
> +	*tcon_pll_div = m;
> +
> +	/* Return the desired source clock */
> +	return (dbl ? CH0_CLK_SRC_SEL_PLL3_2X :
> +	    CH0_CLK_SRC_SEL_PLL3_1X);
> +}
> +
> +static int
>  aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
>      int flags, int *stop)
>  {
>  	struct aw_lcdclk_softc *sc;
> -	uint32_t val, m, m2, n, n2, src_sel;
> -	uint64_t fsingle, fdouble;
> -	int error;
> -	bool dbl;
> +	uint64_t pll_freq;
> +	uint32_t val, src_sel;
> +	int error, tcon_pll_div;
>  
>  	sc = clknode_get_softc(clk);
>  
> @@ -329,26 +403,7 @@ aw_lcdclk_set_freq(struct clknode *clk, 
>  		if (sc->id != CLK_IDX_CH1_SCLK2)
>  			return (ENXIO);
>  
> -		m = n = m2 = n2 = 0;
> -		dbl = false;
> -
> -		/* Find the frequency closes to the target dot clock, using
> -		 * both 1X and 2X PLL inputs as possible candidates.
> -		 */
> -		calc_tcon_pll(TCON_PLLREF, *fout, &m, &n);
> -		calc_tcon_pll(TCON_PLLREF * 2, *fout, &m2, &n2);
> -
> -		fsingle = m ? (n * TCON_PLLREF) / m : 0;
> -		fdouble = m2 ? (n2 * TCON_PLLREF * 2) / m2 : 0;
> -
> -		if (fdouble > fsingle) {
> -			dbl = true;
> -			m = m2;
> -			n = n2;
> -		}
> -
> -		src_sel = dbl ? CH0_CLK_SRC_SEL_PLL3_2X :
> -		    CH0_CLK_SRC_SEL_PLL3_1X;
> +		src_sel = calc_tcon_pll(fin, *fout, &pll_freq, &tcon_pll_div);
>  
>  		/* Switch parent clock if necessary */
>  		if (src_sel != clknode_get_parent_idx(clk)) {
> @@ -357,10 +412,8 @@ aw_lcdclk_set_freq(struct clknode *clk, 
>  				return (error);
>  		}
>  
> -		/* Set desired parent frequency */
> -		fin = n * TCON_PLLREF;
> -
> -		error = clknode_set_freq(clknode_get_parent(clk), fin, 0, 0);
> +		error = clknode_set_freq(clknode_get_parent(clk), pll_freq,
> +		    0, 0);
>  		if (error != 0)
>  			return (error);
>  
> @@ -369,7 +422,7 @@ aw_lcdclk_set_freq(struct clknode *clk, 
>  			return (error);
>  
>  		/* Fetch new input frequency */
> -		error = clknode_get_freq(clknode_get_parent(clk), &fin);
> +		error = clknode_get_freq(clknode_get_parent(clk), &pll_freq);
>  		if (error != 0)
>  			return (error);
>  
> @@ -377,11 +430,11 @@ aw_lcdclk_set_freq(struct clknode *clk, 
>  		DEVICE_LOCK(sc);
>  		LCDCLK_READ(sc, &val);
>  		val &= ~CH1_CLK_DIV_RATIO_M;
> -		val |= ((m - 1) << CH1_CLK_DIV_RATIO_M_SHIFT);
> +		val |= ((tcon_pll_div - 1) << CH1_CLK_DIV_RATIO_M_SHIFT);
>  		LCDCLK_WRITE(sc, val);
>  		DEVICE_UNLOCK(sc);
>  
> -		*fout = fin / m;
> +		*fout = pll_freq / tcon_pll_div;
>  		*stop = 1;
>  
>  		break;
> 
> Modified: head/sys/arm/allwinner/clk/aw_pll.c
> ==============================================================================
> --- head/sys/arm/allwinner/clk/aw_pll.c	Sat Nov 26 10:33:53 2016	(r309189)
> +++ head/sys/arm/allwinner/clk/aw_pll.c	Sat Nov 26 10:36:48 2016	(r309190)
> @@ -482,11 +482,20 @@ a10_pll3_set_freq(struct aw_pll_sc *sc, 
>  {
>  	uint32_t val, m, mode, func;
>  
> -	m = *fout / A10_PLL3_REF_FREQ;
> -
> -	mode = A10_PLL3_MODE_SEL_INT;
> -	func = 0;
> -	*fout = m * A10_PLL3_REF_FREQ;
> +	if (*fout == 297000000) {
> +		func = A10_PLL3_FUNC_SET_297MHZ;
> +		mode = A10_PLL3_MODE_SEL_FRACT;
> +		m = 0;
> +	} else if (*fout == 270000000) {
> +		func = A10_PLL3_FUNC_SET_270MHZ;
> +		mode = A10_PLL3_MODE_SEL_FRACT;
> +		m = 0;
> +	} else {
> +		mode = A10_PLL3_MODE_SEL_INT;
> +		func = 0;
> +		m = *fout / A10_PLL3_REF_FREQ;
> +		*fout = m * A10_PLL3_REF_FREQ;
> +	}
>  
>  	DEVICE_LOCK(sc);
>  	PLL_READ(sc, &val);


-- 
Emmanuel Vadot <manu at bidouilliste.com> <manu at freebsd.org>


More information about the svn-src-all mailing list