On Mon, Nov 09, 2020 at 01:33:57PM +0800, Icenowy Zheng wrote: > According to the user manual, PLL-CPUX have two dividers, in which P is > only allowed when the desired rate is less than 240MHz. As the CCU > framework have no such feature yet and the clock rate that allows P is > much lower than where we normally operate, disallow the usage of P > factor now. > > M is not restricted in the user manual, however according to the BSP PLL > setup table (see [1]), it's not used at all. To follow what the BSP > does, disable this factor too. > > Disabling the dividers will make it possible to remove the need to > switch to osc24M when doing frequency scaling on PLL-CPUX. > > In order to prevent boot-time usage of dividers (current known mainline > U-Boot implementation use m = 2), tweaking of the factors are done when > probing CCU driver. > > Signed-off-by: Icenowy Zheng > --- > drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 79 ++++++++++++++++++++++++++- > 1 file changed, 77 insertions(+), 2 deletions(-) > > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c > index 5f66bf879772..6108d150a0e3 100644 > --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c > @@ -4,6 +4,7 @@ > */ > > #include > +#include > #include > #include > #include > @@ -23,13 +24,14 @@ > > #include "ccu-sun50i-a64.h" > > +#define SUN50I_A64_PLL_CPUX_REG 0x000 > static struct ccu_nkmp pll_cpux_clk = { > .enable = BIT(31), > .lock = BIT(28), > .n = _SUNXI_CCU_MULT(8, 5), > .k = _SUNXI_CCU_MULT(4, 2), > - .m = _SUNXI_CCU_DIV(0, 2), > - .p = _SUNXI_CCU_DIV_MAX(16, 2, 4), > + .m = _SUNXI_CCU_DIV_MAX(16, 2, 1), > + .p = _SUNXI_CCU_DIV_MAX(0, 2, 1), > .common = { > .reg = 0x000, > .hw.init = CLK_HW_INIT("pll-cpux", > @@ -215,6 +217,7 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", > BIT(28), /* lock */ > CLK_SET_RATE_UNGATE); > > +#define SUN50I_A64_CPUX_AXI_REG 0x050 > static const char * const cpux_parents[] = { "osc32k", "osc24M", > "pll-cpux", "pll-cpux" }; > static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, > @@ -954,6 +957,78 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev) > > writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); > > + /* Disable any possible dividers on PLL-CPUX */ > + val = readl(reg + SUN50I_A64_PLL_CPUX_REG); > + if (val & (GENMASK(17, 16) | GENMASK(1, 0))) { > + unsigned int n, k, m, p; > + > + n = ((val & GENMASK(12, 8)) >> 8) + 1; > + k = ((val & GENMASK(5, 4)) >> 4) + 1; > + m = (val & GENMASK(1, 0)) + 1; > + p = 1 << ((val & GENMASK(17, 16)) >> 16); > + > + /* > + * Known mainline U-Boot revisions never uses > + * divider p, and it will only use m when k = 3 or 4. > + * Specially judge for these cases, to satisfy > + * what will most possibly happen. > + * For m = 2 and k = 3, fractional change will be > + * applied to n, to mostly keep the clock rate. > + * For m = 2 and k = 4, just change to m = 1 and k = 2. > + * For other cases, just try to divide it from N. > + */ > + if (p >= 2) { > + n /= p; > + p = 1; > + } > + > + if (m == 2) { > + if (k == 3) { > + k = 2; > + n = n * 3 / 4; > + m = 1; > + } > + if (k == 4) { > + k = 2; > + m = 1; > + } > + } > + > + if (m >= 2) { > + n /= m; > + m = 1; > + } I'm not sure we should rely on the behavior of U-Boot there, and ideally we should move that code to a function of its own, but on principle I'm fine with that code. Maxime