Hello Mark,
below is the patch I'm using for a while now on Pinebook and A64+.
I thought, if it's good enough maybe it could be accepted to the main
tree.

I used it with device tree entries below, apm was able to set lowest
and highest clock, running stable for more than a week.

It's actually same as H3 implementation but - since A64 already had
its own set of functions I replicated it there.

I had one problem with the implementation - "delay(1)" for PLL just
hung on Pinebook (was fine on A64+). It didn't look like it was
looping, i.e. breaking the loop after some threshold did not resume
the execution as far as I could tell.

Increasing the delay value by trial and error solved the issue for me.

/ {
        compatible = "allwinner,sun50i-a64";
};

&{/} {
        cpu0_opp_table: opp_table0 {
                compatible = "operating-points-v2";
                opp-shared;

                opp-648000000 {
                        opp-hz = /bits/ 64 <648000000>;
                        opp-microvolt = <1040000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-792000000 {
                        opp-hz = /bits/ 64 <792000000>;
                        opp-microvolt = <1100000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-816000000 {
                        opp-hz = /bits/ 64 <816000000>;
                        opp-microvolt = <1100000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-912000000 {
                        opp-hz = /bits/ 64 <912000000>;
                        opp-microvolt = <1120000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-960000000 {
                        opp-hz = /bits/ 64 <960000000>;
                        opp-microvolt = <1160000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-1008000000 {
                        opp-hz = /bits/ 64 <1008000000>;
                        opp-microvolt = <1200000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-1056000000 {
                        opp-hz = /bits/ 64 <1056000000>;
                        opp-microvolt = <1240000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-1104000000 {
                        opp-hz = /bits/ 64 <1104000000>;
                        opp-microvolt = <1260000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
                opp-1152000000 {
                        opp-hz = /bits/ 64 <1152000000>;
                        opp-microvolt = <1300000>;
                        clock-latency-ns = <244144>; /* 8 32k periods */
                };
        };
};

&{/cpus/cpu@0} {
        operating-points-v2 = <&cpu0_opp_table>;
        clocks = <&ccu 21>;
        clock-names = "cpu";
        cpu-supply = <&reg_dcdc2>;
};

&{/cpus/cpu@1} {
        operating-points-v2 = <&cpu0_opp_table>;
};

&{/cpus/cpu@2} {
        operating-points-v2 = <&cpu0_opp_table>;
};

&{/cpus/cpu@3} {
        operating-points-v2 = <&cpu0_opp_table>;
};

--
Krystian

Index: sys/dev/fdt/sxiccmu.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu.c,v
retrieving revision 1.22
diff -u -p -r1.22 sxiccmu.c
--- sys/dev/fdt/sxiccmu.c       12 Feb 2019 21:34:11 -0000      1.22
+++ sys/dev/fdt/sxiccmu.c       28 Aug 2019 22:16:15 -0000
@@ -971,13 +971,55 @@ sxiccmu_a23_get_frequency(struct sxiccmu
        return 0;
 }
 
+#define A64_PLL_CPUX_CTRL_REG          0x0000
+#define A64_PLL_CPUX_LOCK              (1 << 28)
+#define A64_PLL_CPUX_OUT_EXT_DIVP(x)   (((x) >> 16) & 0x3)
+#define A64_PLL_CPUX_OUT_EXT_DIVP_MASK (0x3 << 16)
+#define A64_PLL_CPUX_FACTOR_N(x)               (((x) >> 8) & 0x1f)
+#define A64_PLL_CPUX_FACTOR_N_MASK     (0x1f << 8)
+#define A64_PLL_CPUX_FACTOR_N_SHIFT    8
+#define A64_PLL_CPUX_FACTOR_K(x)               (((x) >> 4) & 0x3)
+#define A64_PLL_CPUX_FACTOR_K_MASK     (0x3 << 4)
+#define A64_PLL_CPUX_FACTOR_K_SHIFT    4
+#define A64_PLL_CPUX_FACTOR_M(x)               (((x) >> 0) & 0x3)
+#define A64_PLL_CPUX_FACTOR_M_MASK     (0x3 << 0)
+#define A64_CPUX_AXI_CFG_REG           0x0050
+#define A64_CPUX_CLK_SRC_SEL           (0x3 << 16)
+#define A64_CPUX_CLK_SRC_SEL_LOSC      (0x0 << 16)
+#define A64_CPUX_CLK_SRC_SEL_OSC24M    (0x1 << 16)
+#define A64_CPUX_CLK_SRC_SEL_PLL_CPUX  (0x2 << 16)
+
 uint32_t
 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
        uint32_t parent;
        uint32_t reg, div;
+       uint32_t k, m, n, p;
 
        switch (idx) {
+       case A64_CLK_PLL_CPUX:
+               reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
+               k = A64_PLL_CPUX_FACTOR_K(reg) + 1;
+               m = A64_PLL_CPUX_FACTOR_M(reg) + 1;
+               n = A64_PLL_CPUX_FACTOR_N(reg) + 1;
+               p = 1 << A64_PLL_CPUX_OUT_EXT_DIVP(reg);
+               return (24000000 * n * k) / (m * p);
+       case A64_CLK_CPUX:
+               reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
+               switch (reg & A64_CPUX_CLK_SRC_SEL) {
+               case A64_CPUX_CLK_SRC_SEL_LOSC:
+                       parent = A64_CLK_LOSC;
+                       break;
+               case A64_CPUX_CLK_SRC_SEL_OSC24M:
+                       parent = A64_CLK_HOSC;
+                       break;
+               case A64_CPUX_CLK_SRC_SEL_PLL_CPUX:
+                       parent = A64_CLK_PLL_CPUX;
+                       break;
+               default:
+                       return 0;
+               }
+               return sxiccmu_ccu_get_frequency(sc, &parent);
        case A64_CLK_LOSC:
                return clock_get_frequency(sc->sc_node, "losc");
        case A64_CLK_HOSC:
@@ -1369,8 +1411,49 @@ sxiccmu_a64_set_frequency(struct sxiccmu
 {
        struct sxiccmu_clock clock;
        uint32_t parent, parent_freq;
+       uint32_t reg;
+       int k, n;
+       int error;
 
        switch (idx) {
+       case A64_CLK_PLL_CPUX:
+               k = 1; n = 32;
+               while (k <= 4 && (24000000 * n * k) < freq)
+                       k++;
+               while (n >= 1 && (24000000 * n * k) > freq)
+                       n--;
+
+               reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
+               reg &= ~A64_PLL_CPUX_OUT_EXT_DIVP_MASK;
+               reg &= ~A64_PLL_CPUX_FACTOR_N_MASK;
+               reg &= ~A64_PLL_CPUX_FACTOR_K_MASK;
+               reg &= ~A64_PLL_CPUX_FACTOR_M_MASK;
+               reg |= ((n - 1) << A64_PLL_CPUX_FACTOR_N_SHIFT);
+               reg |= ((k - 1) << A64_PLL_CPUX_FACTOR_K_SHIFT);
+               SXIWRITE4(sc, A64_PLL_CPUX_CTRL_REG, reg);
+
+               /* Wait for PLL to lock. */
+               while ((SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG) &
+                   A64_PLL_CPUX_LOCK) == 0) {
+                       delay(200);
+               }
+
+               return 0;
+       case A64_CLK_CPUX:
+               /* Switch to 24 MHz clock. */
+               reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
+               reg &= ~A64_CPUX_CLK_SRC_SEL;
+               reg |= A64_CPUX_CLK_SRC_SEL_OSC24M;
+               SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
+
+               error = sxiccmu_a64_set_frequency(sc, A64_CLK_PLL_CPUX, freq);
+
+               /* Switch back to PLL. */
+               reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
+               reg &= ~A64_CPUX_CLK_SRC_SEL;
+               reg |= A64_CPUX_CLK_SRC_SEL_PLL_CPUX;
+               SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
+               return error;
        case A64_CLK_MMC0:
        case A64_CLK_MMC1:
        case A64_CLK_MMC2:

Index: sys/dev/fdt/sxiccmu_clocks.h
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu_clocks.h,v
retrieving revision 1.25
diff -u -p -r1.25 sxiccmu_clocks.h
--- sys/dev/fdt/sxiccmu_clocks.h        19 Aug 2019 06:13:44 -0000      1.25
+++ sys/dev/fdt/sxiccmu_clocks.h        28 Aug 2019 22:16:20 -0000
@@ -140,9 +140,12 @@ struct sxiccmu_ccu_bit sun8i_a23_gates[]
 
 /* A64 */
 
+#define A64_CLK_PLL_CPUX       1
+
 #define A64_CLK_PLL_PERIPH0    11
 #define A64_CLK_PLL_PERIPH0_2X 12
 
+#define A64_CLK_CPUX           21
 #define A64_CLK_AXI            22
 #define A64_CLK_APB            23
 #define A64_CLK_AHB1           24

Reply via email to