RK3588 support.
authorkettenis <kettenis@openbsd.org>
Sun, 26 Feb 2023 12:39:07 +0000 (12:39 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 26 Feb 2023 12:39:07 +0000 (12:39 +0000)
ok patrick@

sys/dev/fdt/rkclock.c
sys/dev/fdt/rkclock_clocks.h

index b638c4a..9e6458a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rkclock.c,v 1.65 2023/02/15 14:06:43 kettenis Exp $   */
+/*     $OpenBSD: rkclock.c,v 1.66 2023/02/26 12:39:07 kettenis Exp $   */
 /*
  * Copyright (c) 2017, 2018 Mark Kettenis <kettenis@openbsd.org>
  *
 #define RK3568_PMUCRU_MODE_CON         0x0080
 #define RK3568_PMUCRU_CLKSEL_CON(i)    (0x0100 + (i) * 4)
 
+/* RK3588 registers */
+#define RK3588_CRU_AUPLL_CON(i)                (0x00180 + (i) * 4)
+#define RK3588_CRU_CPLL_CON(i)         (0x001a0 + (i) * 4)
+#define RK3588_CRU_GPLL_CON(i)         (0x001c0 + (i) * 4)
+#define RK3588_CRU_NPLL_CON(i)         (0x001e0 + (i) * 4)
+#define  RK3588_CRU_PLL_M_MASK                 (0x3ff << 0)
+#define  RK3588_CRU_PLL_M_SHIFT                        0
+#define  RK3588_CRU_PLL_RESETB                 (1 << 13)
+#define  RK3588_CRU_PLL_S_MASK                 (0x7 << 6)
+#define  RK3588_CRU_PLL_S_SHIFT                        6
+#define  RK3588_CRU_PLL_P_MASK                 (0x3f << 0)
+#define  RK3588_CRU_PLL_P_SHIFT                        0
+#define  RK3588_CRU_PLL_K_MASK                 (0xffff << 0)
+#define  RK3588_CRU_PLL_K_SHIFT                        0
+#define  RK3588_CRU_PLL_PLL_LOCK               (1 << 15)
+#define RK3588_CRU_MODE_CON            0x00280
+#define  RK3588_CRU_MODE_MASK                  0x3
+#define  RK3588_CRU_MODE_SLOW                  0x0
+#define  RK3588_CRU_MODE_NORMAL                        0x1
+
+#define RK3588_CRU_CLKSEL_CON(i)       (0x00300 + (i) * 4)
+#define RK3588_CRU_GATE_CON(i)         (0x00800 + (i) * 4)
+
+#define RK3588_PHPTOPCRU_PPLL_CON(i)   (0x08200 + (i) * 4)
+#define RK3588_PMUCRU_CLKSEL_CON(i)    (0x30300 + (i) * 4)
+
 #include "rkclock_clocks.h"
 
 struct rkclock {
        uint16_t idx;
-       uint16_t reg;
+       uint32_t reg;
        uint16_t sel_mask;
        uint16_t div_mask;
        uint16_t parents[8];
@@ -282,6 +308,12 @@ int        rk3568_pmu_set_frequency(void *, uint32_t *, uint32_t);
 void   rk3568_pmu_enable(void *, uint32_t *, int);
 void   rk3568_pmu_reset(void *, uint32_t *, int);
 
+void   rk3588_init(struct rkclock_softc *);
+uint32_t rk3588_get_frequency(void *, uint32_t *);
+int    rk3588_set_frequency(void *, uint32_t *, uint32_t);
+void   rk3588_enable(void *, uint32_t *, int);
+void   rk3588_reset(void *, uint32_t *, int);
+
 struct rkclock_compat {
        const char *compat;
        int     assign;
@@ -335,7 +367,13 @@ const struct rkclock_compat rkclock_compat[] = {
                rk3568_pmu_enable, rk3568_pmu_get_frequency,
                rk3568_pmu_set_frequency, NULL,
                rk3568_pmu_reset
-       }
+       },
+       {
+               "rockchip,rk3588-cru", 1, rk3588_init,
+               rk3588_enable, rk3588_get_frequency,
+               rk3588_set_frequency, NULL,
+               rk3588_reset
+       },
 };
 
 int
@@ -541,27 +579,33 @@ rkclock_set_frequency(struct rkclock_softc *sc, uint32_t idx, uint32_t freq)
        }
 
        /*
-        * If there is no divider, see if we have a parent with the
-        * right frequency.
+        * If there is no divider, pick the parent with the frequency
+        * closest to the target frequency.
         */
        if (clk->div_mask == 0) {
+               /*
+                * Start out with the current parent.  This prevents
+                * unnecessary switching to a different parent.
+                */
                parent = clk->parents[mux];
-               if (freq == sc->sc_cd.cd_get_frequency(sc, &parent))
-                       return 0;
+               best_freq = sc->sc_cd.cd_get_frequency(sc, &parent);
+               best_mux = mux;
 
                for (i = 0; i < nitems(clk->parents); i++) {
                        if (clk->parents[i] == 0)
                                continue;
                        parent = clk->parents[i];
-                       if (freq == sc->sc_cd.cd_get_frequency(sc, &parent)) {
-                               HWRITE4(sc, clk->reg,
-                                   clk->sel_mask << 16 | i << sel_shift);
-                               return 0;
+                       f = sc->sc_cd.cd_get_frequency(sc, &parent);
+                       if ((best_freq > freq && f < best_freq) ||
+                           (f > best_freq && f <= freq)) {
+                               best_freq = f;
+                               best_mux = i;
                        }
                }
 
-               printf("%s: 0x%08x\n", __func__, idx);
-               return -1;
+               HWRITE4(sc, clk->reg,
+                   clk->sel_mask << 16 | best_mux << sel_shift);
+               return 0;
        }
 
        /*
@@ -580,8 +624,8 @@ rkclock_set_frequency(struct rkclock_softc *sc, uint32_t idx, uint32_t freq)
                        if (clk->parents[i] == 0)
                                continue;
                        f = rkclock_freq(sc, clk, i, freq);
-                       if ((f > best_freq && f <= freq) ||
-                           (f < best_freq && f >= freq)) {
+                       if ((best_freq > freq && f < best_freq) ||
+                           (f > best_freq && f <= freq)) {
                                best_freq = f;
                                best_mux = i;
                        }
@@ -2011,19 +2055,14 @@ rk3328_get_frequency(void *cookie, uint32_t *cells)
        switch (idx) {
        case RK3328_PLL_APLL:
                return rk3328_get_pll(sc, RK3328_CRU_APLL_CON(0));
-               break;
        case RK3328_PLL_DPLL:
                return rk3328_get_pll(sc, RK3328_CRU_DPLL_CON(0));
-               break;
        case RK3328_PLL_CPLL:
                return rk3328_get_pll(sc, RK3328_CRU_CPLL_CON(0));
-               break;
        case RK3328_PLL_GPLL:
                return rk3328_get_pll(sc, RK3328_CRU_GPLL_CON(0));
-               break;
        case RK3328_PLL_NPLL:
                return rk3328_get_pll(sc, RK3328_CRU_NPLL_CON(0));
-               break;
        case RK3328_ARMCLK:
                return rk3328_get_armclk(sc);
        case RK3328_XIN24M:
@@ -2989,7 +3028,6 @@ rk3399_pmu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
        switch (idx) {
        case RK3399_PLL_PPLL:
                return rk3399_set_pll(sc, RK3399_PMUCRU_PPLL_CON(0), freq);
-               break;
        default:
                break;
        }
@@ -3393,22 +3431,16 @@ rk3568_get_frequency(void *cookie, uint32_t *cells)
        switch (idx) {
        case RK3568_PLL_APLL:
                return rk3328_get_pll(sc, RK3568_CRU_APLL_CON(0));
-               break;
        case RK3568_PLL_DPLL:
                return rk3328_get_pll(sc, RK3568_CRU_DPLL_CON(0));
-               break;
        case RK3568_PLL_CPLL:
                return rk3328_get_pll(sc, RK3568_CRU_CPLL_CON(0));
-               break;
        case RK3568_PLL_GPLL:
                return rk3328_get_pll(sc, RK3568_CRU_GPLL_CON(0));
-               break;
        case RK3568_PLL_NPLL:
                return rk3328_get_pll(sc, RK3568_CRU_NPLL_CON(0));
-               break;
        case RK3568_PLL_VPLL:
                return rk3328_get_pll(sc, RK3568_CRU_VPLL_CON(0));
-               break;
        case RK3568_SCLK_GMAC0_DIV_50:
                idx = RK3568_SCLK_GMAC0;
                return rk3568_get_frequency(sc, &idx) / 50;
@@ -3642,3 +3674,496 @@ rk3568_pmu_reset(void *cookie, uint32_t *cells, int on)
 
        printf("%s: 0x%08x\n", __func__, idx);
 }
+
+/* 
+ * Rockchip RK3588 
+ */
+
+const struct rkclock rk3588_clocks[] = {
+       {
+               RK3588_ACLK_BUS_ROOT, RK3588_CRU_CLKSEL_CON(38),
+               SEL(5, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART1_SRC, RK3588_CRU_CLKSEL_CON(41),
+               SEL(14, 14), DIV(13, 9),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART1, RK3588_CRU_CLKSEL_CON(43),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART1_SRC, RK3588_CLK_UART1_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART1, 0, 0, 0,
+               { RK3588_CLK_UART1 }
+       },
+       {
+               RK3588_CLK_UART2_SRC, RK3588_CRU_CLKSEL_CON(43),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART2, RK3588_CRU_CLKSEL_CON(45),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART2_SRC, RK3588_CLK_UART2_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART2, 0, 0, 0,
+               { RK3588_CLK_UART2 }
+       },
+       {
+               RK3588_CLK_UART3_SRC, RK3588_CRU_CLKSEL_CON(45),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART3, RK3588_CRU_CLKSEL_CON(47),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART3_SRC, RK3588_CLK_UART3_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART3, 0, 0, 0,
+               { RK3588_CLK_UART3 }
+       },
+       {
+               RK3588_CLK_UART4_SRC, RK3588_CRU_CLKSEL_CON(47),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART4, RK3588_CRU_CLKSEL_CON(49),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART4_SRC, RK3588_CLK_UART4_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART4, 0, 0, 0,
+               { RK3588_CLK_UART4 }
+       },
+       {
+               RK3588_CLK_UART5_SRC, RK3588_CRU_CLKSEL_CON(49),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART5, RK3588_CRU_CLKSEL_CON(51),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART5_SRC, RK3588_CLK_UART5_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART5, 0, 0, 0,
+               { RK3588_CLK_UART5 }
+       },
+       {
+               RK3588_CLK_UART6_SRC, RK3588_CRU_CLKSEL_CON(51),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART6, RK3588_CRU_CLKSEL_CON(53),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART6_SRC, RK3588_CLK_UART6_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART6, 0, 0, 0,
+               { RK3588_CLK_UART6 }
+       },
+       {
+               RK3588_CLK_UART7_SRC, RK3588_CRU_CLKSEL_CON(53),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART7, RK3588_CRU_CLKSEL_CON(55),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART7_SRC, RK3588_CLK_UART7_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART7, 0, 0, 0,
+               { RK3588_CLK_UART7 }
+       },
+       {
+               RK3588_CLK_UART8_SRC, RK3588_CRU_CLKSEL_CON(55),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART8, RK3588_CRU_CLKSEL_CON(57),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART8_SRC, RK3588_CLK_UART8_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART8, 0, 0, 0,
+               { RK3588_CLK_UART8 }
+       },
+       {
+               RK3588_CLK_UART9_SRC, RK3588_CRU_CLKSEL_CON(57),
+               SEL(7, 7), DIV(6, 2),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART9, RK3588_CRU_CLKSEL_CON(59),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART9_SRC, RK3588_CLK_UART9_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART9, 0, 0, 0,
+               { RK3588_CLK_UART9 }
+       },
+       {
+               RK3588_ACLK_CENTER_ROOT, RK3588_CRU_CLKSEL_CON(165),
+               SEL(1, 0), 0,
+               { RK3588_CLK_700M_SRC, RK3588_CLK_400M_SRC,
+                 RK3588_CLK_200M_SRC, RK3588_XIN24M }
+       },
+       {
+               RK3588_ACLK_CENTER_LOW_ROOT, RK3588_CRU_CLKSEL_CON(165),
+               SEL(3, 2), 0,
+               { RK3588_CLK_500M_SRC, RK3588_CLK_250M_SRC,
+                 RK3588_CLK_100M_SRC, RK3588_XIN24M }
+       },
+       {
+               RK3588_HCLK_CENTER_ROOT, RK3588_CRU_CLKSEL_CON(165),
+               SEL(5, 4), 0,
+               { RK3588_CLK_400M_SRC, RK3588_CLK_200M_SRC,
+                 RK3588_CLK_100M_SRC, RK3588_XIN24M }
+       },
+       {
+               RK3588_CLK_50M_SRC, RK3588_CRU_CLKSEL_CON(0),
+               SEL(5, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_100M_SRC, RK3588_CRU_CLKSEL_CON(0),
+               SEL(11, 11), DIV(10, 6),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_150M_SRC, RK3588_CRU_CLKSEL_CON(1),
+               SEL(5, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_200M_SRC, RK3588_CRU_CLKSEL_CON(1),
+               SEL(11, 11), DIV(10, 6),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_250M_SRC, RK3588_CRU_CLKSEL_CON(2),
+               SEL(5, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_400M_SRC, RK3588_CRU_CLKSEL_CON(3),
+               SEL(11, 11), DIV(10, 6),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_500M_SRC, RK3588_CRU_CLKSEL_CON(4),
+               SEL(11, 11), DIV(10, 6),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_700M_SRC, RK3588_CRU_CLKSEL_CON(6),
+               SEL(5, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_SPLL }
+       },
+       {
+               RK3588_ACLK_TOP_ROOT, RK3588_CRU_CLKSEL_CON(8),
+               SEL(6, 5), 0,
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_PLL_AUPLL }
+       },
+       {
+               RK3588_PCLK_TOP_ROOT, RK3588_CRU_CLKSEL_CON(8),
+               SEL(8, 7), 0,
+               { RK3588_CLK_100M_SRC, RK3588_CLK_50M_SRC, RK3588_XIN24M }
+       },
+       {
+               RK3588_ACLK_LOW_TOP_ROOT, RK3588_CRU_CLKSEL_CON(8),
+               SEL(14, 14), DIV(13, 9),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_GPU_SRC, RK3588_CRU_CLKSEL_CON(158),
+               SEL(7, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_PLL_AUPLL,
+                 RK3588_PLL_NPLL, RK3588_PLL_SPLL }
+       },
+       {
+               RK3588_CLK_GPU, 0, 0, 0,
+               { RK3588_CLK_GPU_SRC },
+               SET_PARENT
+       },
+       {
+               RK3588_ACLK_VOP_ROOT, RK3588_CRU_CLKSEL_CON(110),
+               SEL(7, 5), DIV(4, 0),
+               { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_PLL_AUPLL,
+                 RK3588_PLL_NPLL, RK3588_PLL_SPLL }
+       },
+       {
+               RK3588_ACLK_VOP, 0, 0, 0,
+               { RK3588_ACLK_VOP_SUB_SRC },
+               SET_PARENT
+       },
+       {
+               RK3588_ACLK_VOP_SUB_SRC, RK3588_CRU_CLKSEL_CON(115),
+               SEL(9, 9), 0,
+               { RK3588_ACLK_VOP_ROOT, 0 /* RK3588_ACLK_VOP_DIV2_SRC */ },
+               SET_PARENT
+       },
+       {
+               RK3588_CLK_PMU1_50M_SRC, RK3588_PMUCRU_CLKSEL_CON(0),
+               0, DIV(3, 0),
+               { RK3588_CLK_PMU1_400M_SRC }
+       },
+       {
+               RK3588_CLK_PMU1_100M_SRC, RK3588_PMUCRU_CLKSEL_CON(0),
+               0, DIV(6, 4),
+               { RK3588_CLK_PMU1_400M_SRC }
+       },
+       {
+               RK3588_CLK_PMU1_200M_SRC, RK3588_PMUCRU_CLKSEL_CON(0),
+               0, DIV(9, 7),
+               { RK3588_CLK_PMU1_400M_SRC }
+       },
+       {
+               RK3588_CLK_PMU1_400M_SRC, RK3588_PMUCRU_CLKSEL_CON(1),
+               SEL(5, 5), DIV(4, 0),
+               { RK3588_CLK_400M_SRC, RK3588_XIN24M }
+       },
+       {
+               RK3588_PCLK_PMU1_ROOT, RK3588_PMUCRU_CLKSEL_CON(1),
+               SEL(9, 8), 0,
+               { RK3588_CLK_PMU1_100M_SRC, RK3588_CLK_PMU1_50M_SRC,
+                 RK3588_XIN24M }
+       },
+       {
+               RK3588_PCLK_PMU0_ROOT, 0, 0, 0,
+               { RK3588_PCLK_PMU1_ROOT },
+               SET_PARENT
+       },
+       {
+               RK3588_HCLK_PMU_CM0_ROOT, RK3588_PMUCRU_CLKSEL_CON(1),
+               SEL(11, 10), 0,
+               { RK3588_CLK_PMU1_400M_SRC, RK3588_CLK_PMU1_200M_SRC,
+                 RK3588_CLK_PMU1_100M_SRC, RK3588_XIN24M }
+       },
+       {
+               RK3588_CLK_UART0_SRC, RK3588_PMUCRU_CLKSEL_CON(3),
+               0, DIV(11, 7),
+               { RK3588_PLL_CPLL }
+       },
+       {
+               RK3588_CLK_UART0, RK3588_PMUCRU_CLKSEL_CON(5),
+               SEL(1, 0), 0,
+               { RK3588_CLK_UART0_SRC, RK3588_CLK_UART0_FRAC, RK3588_XIN24M }
+       },
+       {
+               RK3588_SCLK_UART0, 0, 0, 0,
+               { RK3588_CLK_UART0 }
+       },
+       {
+               /* Sentinel */
+       }
+};
+
+/* Certain test clocks are disabled. */
+const uint32_t rk3588_gates[78] = {
+       [2] = 0x00000050,
+       [22] = 0x00000200,
+       [25] = 0x00000200,
+       [29] = 0x00000004,
+       [66] = 0x00000004,
+};
+
+void
+rk3588_init(struct rkclock_softc *sc)
+{
+       int i;
+
+       /* The code below assumes all clocks are enabled.  Check this!. */
+       for (i = 0; i < nitems(rk3588_gates); i++) {
+               if (HREAD4(sc, RK3588_CRU_GATE_CON(i)) != rk3588_gates[i]) {
+                       printf("CRU_GATE_CON%d: 0x%08x\n", i,
+                           HREAD4(sc, RK3588_CRU_GATE_CON(i)));
+               }
+       }
+
+       sc->sc_clocks = rk3588_clocks;
+}
+
+int
+rk3588_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq)
+{
+       uint32_t p, m, s, k;
+       int mode_shift = -1;
+
+       switch (base) {
+       case RK3588_CRU_AUPLL_CON(0):
+               mode_shift = 6;
+               break;
+       case RK3588_CRU_GPLL_CON(0):
+               mode_shift = 2;
+               break;
+       case RK3588_CRU_NPLL_CON(0):
+               mode_shift = 0;
+               break;
+       case RK3588_PHPTOPCRU_PPLL_CON(0):
+               mode_shift = 10;
+               break;
+       }
+       KASSERT(mode_shift != -1);
+
+       /*
+        * It is not clear whether all combinations of the clock
+        * dividers result in a stable clock.  Therefore this function
+        * only supports a limited set of PLL clock rates.
+        */
+       switch (freq) {
+       case 1188000000U:
+               p = 2; m = 198; s = 1; k = 0;
+               break;
+       case 850000000U:
+               p = 3; m = 425; s = 2; k = 0;
+               break;
+       case 786432000U:
+               p = 2; m = 262; s = 2; k = 9437;
+               break;
+       case 100000000U:
+               p = 3; m = 400; s = 5; k = 0;
+               break;
+       default:
+               printf("%s: %u Hz\n", __func__, freq);
+               return -1;
+       }
+
+       /*
+        * Select slow mode to guarantee a stable clock while we're
+        * adjusting the PLL.
+        */
+       HWRITE4(sc, RK3588_CRU_MODE_CON,
+           (RK3588_CRU_MODE_MASK << 16 |RK3588_CRU_MODE_SLOW) << mode_shift);
+
+       /* Power down PLL. */
+       HWRITE4(sc, base + 0x0004,
+           RK3588_CRU_PLL_RESETB << 16 | RK3588_CRU_PLL_RESETB);
+       
+       /* Set PLL rate. */
+       HWRITE4(sc, base + 0x0000,
+           RK3588_CRU_PLL_M_MASK << 16 | m << RK3588_CRU_PLL_M_SHIFT);
+       HWRITE4(sc, base + 0x0004,
+           RK3588_CRU_PLL_S_MASK << 16 | s << RK3588_CRU_PLL_S_SHIFT |
+           RK3588_CRU_PLL_P_MASK << 16 | p << RK3588_CRU_PLL_P_SHIFT);
+       HWRITE4(sc, base + 0x0008,
+           RK3588_CRU_PLL_K_MASK << 16 | k << RK3588_CRU_PLL_K_SHIFT);
+
+       /* Power up PLL. */
+       HWRITE4(sc, base + 0x0004, RK3588_CRU_PLL_RESETB << 16);
+
+       /* Wait for PLL to stabilize. */
+       while ((HREAD4(sc, base + 0x0018) & RK3588_CRU_PLL_PLL_LOCK) == 0)
+               delay(10);
+
+       /* Switch back to normal mode. */
+       HWRITE4(sc, RK3588_CRU_MODE_CON,
+           (RK3588_CRU_MODE_MASK << 16 | RK3588_CRU_MODE_NORMAL) << mode_shift);
+
+       return 0;
+}
+
+uint32_t
+rk3588_get_pll(struct rkclock_softc *sc, bus_size_t base)
+{
+       uint64_t freq, frac;
+       uint32_t k, m, p, s;
+       uint32_t reg;
+
+       reg = HREAD4(sc, base);
+       m = (reg & RK3588_CRU_PLL_M_MASK) >> RK3588_CRU_PLL_M_SHIFT;
+       reg = HREAD4(sc, base + 4);
+       p = (reg & RK3588_CRU_PLL_P_MASK) >> RK3588_CRU_PLL_P_SHIFT;
+       s = (reg & RK3588_CRU_PLL_S_MASK) >> RK3588_CRU_PLL_S_SHIFT;
+       reg = HREAD4(sc, base + 8);
+       k = (reg & RK3588_CRU_PLL_K_MASK) >> RK3588_CRU_PLL_K_SHIFT;
+
+       freq = (24000000ULL * m) / p;
+       if (k) {
+               frac = ((24000000ULL * k) / (p * 65535));
+               freq += frac;
+       }
+
+       return freq >> s;
+}
+
+uint32_t
+rk3588_get_frequency(void *cookie, uint32_t *cells)
+{
+       struct rkclock_softc *sc = cookie;
+       uint32_t idx = cells[0];
+       uint32_t freq;
+
+       switch (idx) {
+       case RK3588_PLL_AUPLL:
+               return rk3588_get_pll(sc, RK3588_CRU_AUPLL_CON(0));
+       case RK3588_PLL_CPLL:
+               return rk3588_get_pll(sc, RK3588_CRU_CPLL_CON(0));
+       case RK3588_PLL_GPLL:
+               return rk3588_get_pll(sc, RK3588_CRU_GPLL_CON(0));
+       case RK3588_PLL_NPLL:
+               return rk3588_get_pll(sc, RK3588_CRU_NPLL_CON(0));
+       case RK3588_PLL_PPLL:
+               return rk3588_get_pll(sc, RK3588_PHPTOPCRU_PPLL_CON(0));
+       case RK3588_PLL_SPLL:
+               return rkclock_external_frequency("spll");
+       case RK3588_XIN24M:
+               return 24000000;
+       default:
+               break;
+       }
+
+       freq = rkclock_get_frequency(sc, idx);
+       return freq;
+}
+
+int
+rk3588_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
+{
+       struct rkclock_softc *sc = cookie;
+       uint32_t idx = cells[0];
+
+       switch (idx) {
+       case RK3588_PLL_AUPLL:
+               return rk3588_set_pll(sc, RK3588_CRU_AUPLL_CON(0), freq);
+       case RK3588_PLL_GPLL:
+               return rk3588_set_pll(sc, RK3588_CRU_GPLL_CON(0), freq);
+       case RK3588_PLL_NPLL:
+               return rk3588_set_pll(sc, RK3588_CRU_NPLL_CON(0), freq);
+       case RK3588_PLL_PPLL:
+               return rk3588_set_pll(sc, RK3588_PHPTOPCRU_PPLL_CON(0), freq);
+       default:
+               break;
+       }
+
+       return rkclock_set_frequency(sc, idx, freq);
+}
+
+void
+rk3588_enable(void *cookie, uint32_t *cells, int on)
+{
+       uint32_t idx = cells[0];
+
+       /* All clocks are enabled upon hardware reset. */
+       if (!on) {
+               printf("%s: 0x%08x\n", __func__, idx);
+               return;
+       }
+}
+
+void
+rk3588_reset(void *cookie, uint32_t *cells, int on)
+{
+       uint32_t idx = cells[0];
+
+       printf("%s: 0x%08x\n", __func__, idx);
+}
index 3df0603..ae01215 100644 (file)
 #define RK3568_SCLK_UART0              11
 #define RK3568_PCLK_I2C0                       45
 #define RK3568_CLK_PDPMU               49
+
+/*
+ * RK3588 clocks.
+ */
+#define RK3588_PLL_AUPLL               4
+#define RK3588_PLL_CPLL                        5
+#define RK3588_PLL_GPLL                        6
+#define RK3588_PLL_NPLL                        7
+#define RK3588_PLL_PPLL                        8
+
+#define RK3588_ACLK_BUS_ROOT           113
+#define RK3588_CLK_UART1_SRC           168
+#define RK3588_CLK_UART1_FRAC          169
+#define RK3588_CLK_UART1               170
+#define RK3588_SCLK_UART1              171
+#define RK3588_CLK_UART2_SRC           172
+#define RK3588_CLK_UART2_FRAC          173
+#define RK3588_CLK_UART2               174
+#define RK3588_SCLK_UART2              175
+#define RK3588_CLK_UART3_SRC           176
+#define RK3588_CLK_UART3_FRAC          177
+#define RK3588_CLK_UART3               178
+#define RK3588_SCLK_UART3              179
+#define RK3588_CLK_UART4_SRC           180
+#define RK3588_CLK_UART4_FRAC          181
+#define RK3588_CLK_UART4               182
+#define RK3588_SCLK_UART4              183
+#define RK3588_CLK_UART5_SRC           184
+#define RK3588_CLK_UART5_FRAC          185
+#define RK3588_CLK_UART5               186
+#define RK3588_SCLK_UART5              187
+#define RK3588_CLK_UART6_SRC           188
+#define RK3588_CLK_UART6_FRAC          189
+#define RK3588_CLK_UART6               190
+#define RK3588_SCLK_UART6              191
+#define RK3588_CLK_UART7_SRC           192
+#define RK3588_CLK_UART7_FRAC          193
+#define RK3588_CLK_UART7               194
+#define RK3588_SCLK_UART7              195
+#define RK3588_CLK_UART8_SRC           196
+#define RK3588_CLK_UART8_FRAC          197
+#define RK3588_CLK_UART8               198
+#define RK3588_SCLK_UART8              199
+#define RK3588_CLK_UART9_SRC           200
+#define RK3588_CLK_UART9_FRAC          201
+#define RK3588_CLK_UART9               202
+#define RK3588_SCLK_UART9              203
+#define RK3588_ACLK_CENTER_ROOT                204
+#define RK3588_ACLK_CENTER_LOW_ROOT    205
+#define RK3588_HCLK_CENTER_ROOT                206
+#define RK3588_CLK_50M_SRC             222
+#define RK3588_CLK_100M_SRC            223
+#define RK3588_CLK_150M_SRC            224
+#define RK3588_CLK_200M_SRC            225
+#define RK3588_CLK_250M_SRC            226
+#define RK3588_CLK_400M_SRC            229
+#define RK3588_CLK_500M_SRC            231
+#define RK3588_CLK_700M_SRC            234
+#define RK3588_ACLK_TOP_ROOT           256
+#define RK3588_PCLK_TOP_ROOT           257
+#define RK3588_ACLK_LOW_TOP_ROOT       258
+#define RK3588_CLK_GPU_SRC             261
+#define RK3588_CLK_GPU                 262
+#define RK3588_ACLK_VOP_ROOT           600
+#define RK3588_ACLK_VOP                        605
+#define RK3588_ACLK_VOP_SUB_SRC                619
+#define RK3588_CLK_PMU1_50M_SRC                639
+#define RK3588_CLK_PMU1_100M_SRC       640
+#define RK3588_CLK_PMU1_200M_SRC       641
+#define RK3588_CLK_PMU1_400M_SRC       643
+#define RK3588_PCLK_PMU1_ROOT          645
+#define RK3588_PCLK_PMU0_ROOT          646
+#define RK3588_HCLK_PMU_CM0_ROOT       647
+#define RK3588_CLK_UART0_SRC           664
+#define RK3588_CLK_UART0_FRAC          665
+#define RK3588_CLK_UART0               666
+#define RK3588_SCLK_UART0              667
+
+#define RK3588_PLL_SPLL                        1022
+#define RK3588_XIN24M                  1023