Re: [RFC PATCH 1/2] clk: sunxi-ng: a64: disable dividers in PLL-CPUX

From: Maxime Ripard
Date: Fri Nov 20 2020 - 10:24:53 EST


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 <icenowy@xxxxxxx>
> ---
> 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