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 <icen...@aosc.io>
> ---
>  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 <linux/clk-provider.h>
> +#include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/of_address.h>
>  #include <linux/platform_device.h>
> @@ -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

Attachment: signature.asc
Description: PGP signature

Reply via email to