Hi,

I thought to avoid false-LOCKed situation but I didn't consider
about false-unLOCKed. So same as adr says, it is the best solution
to wait simply with delay(PLL_STABLE_TIME_REG1 usec). No need to refer
LOCK flag.

Here is renewed diff. I also tested on Banana Pi BPI-P2 (Allwinner H2+).
This diff fixes the unstability (sudden death with page fault by unknown
reason) at boot on Allwinner H2+.

Index: sxiccmu.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu.c,v
retrieving revision 1.27
diff -u -p -r1.27 sxiccmu.c
--- sxiccmu.c   28 Mar 2020 12:32:53 -0000      1.27
+++ sxiccmu.c   25 Aug 2020 09:02:51 -0000
@@ -1158,6 +1158,7 @@ sxiccmu_a80_get_frequency(struct sxiccmu
 
 /* Allwinner H3/H5 */
 #define H3_PLL_CPUX_CTRL_REG           0x0000
+#define H3_PLL_CPUX_ENABLE             (1 << 31)
 #define H3_PLL_CPUX_LOCK               (1 << 28)
 #define H3_PLL_CPUX_OUT_EXT_DIVP(x)    (((x) >> 16) & 0x3)
 #define H3_PLL_CPUX_OUT_EXT_DIVP_MASK  (0x3 << 16)
@@ -1176,6 +1177,8 @@ sxiccmu_a80_get_frequency(struct sxiccmu
 #define H3_CPUX_CLK_SRC_SEL_LOSC       (0x0 << 16)
 #define H3_CPUX_CLK_SRC_SEL_OSC24M     (0x1 << 16)
 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX   (0x2 << 16)
+#define H3_PLL_STABLE_TIME_REG1                0x0204
+#define H3_PLL_STABLE_TIME_REG1_TIME(x)        (((x) >> 0) & 0xffff)
 
 uint32_t
 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
@@ -1632,7 +1635,7 @@ sxiccmu_h3_set_frequency(struct sxiccmu_
 {
        struct sxiccmu_clock clock;
        uint32_t parent, parent_freq;
-       uint32_t reg;
+       uint32_t reg, lock_time;
        int k, n;
        int error;
 
@@ -1644,7 +1647,12 @@ sxiccmu_h3_set_frequency(struct sxiccmu_
                while (n >= 1 && (24000000 * n * k) > freq)
                        n--;
 
+               /* Gate the PLL first */
                reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
+               reg &= ~H3_PLL_CPUX_ENABLE;
+               SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
+
+               /* Set factors and external divider. */
                reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK;
                reg &= ~H3_PLL_CPUX_FACTOR_N_MASK;
                reg &= ~H3_PLL_CPUX_FACTOR_K_MASK;
@@ -1653,10 +1661,13 @@ sxiccmu_h3_set_frequency(struct sxiccmu_
                reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT);
                SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
 
-               /* Wait for PLL to lock. */
-               while ((SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG) &
-                   H3_PLL_CPUX_LOCK) == 0)
-                       delay(1);
+               /* Ungate the PLL */
+               reg |= H3_PLL_CPUX_ENABLE;
+               SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
+
+               /* Wait for PLL to lock. (LOCK flag is unreliable) */
+               lock_time = SXIREAD4(sc, H3_PLL_STABLE_TIME_REG1);
+               delay(H3_PLL_STABLE_TIME_REG1_TIME(lock_time));
 
                return 0;
        case H3_CLK_CPUX:
@@ -1665,6 +1676,8 @@ sxiccmu_h3_set_frequency(struct sxiccmu_
                reg &= ~H3_CPUX_CLK_SRC_SEL;
                reg |= H3_CPUX_CLK_SRC_SEL_OSC24M;
                SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
+               /* Must wait at least 8 cycles of the current clock. */
+               delay(1);
 
                error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq);
 
@@ -1673,6 +1686,7 @@ sxiccmu_h3_set_frequency(struct sxiccmu_
                reg &= ~H3_CPUX_CLK_SRC_SEL;
                reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX;
                SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
+               delay(1);
                return error;
        case H3_CLK_MMC0:
        case H3_CLK_MMC1:


Best regards,
-- 
SASANO Takayoshi (JG1UAA) <[email protected]>

Reply via email to