Date: Sat, 26 Nov 2016 10:36:48 +0000 (UTC) From: Emmanuel Vadot <manu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r309190 - head/sys/arm/allwinner/clk Message-ID: <201611261036.uAQAam0Z047291@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611261036.uAQAam0Z047291>