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

Emmanuel Vadot manu at FreeBSD.org
Sat Nov 26 10:36:50 UTC 2016


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);


More information about the svn-src-all mailing list