diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-02-26 12:39:49 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-02-26 12:39:49 +0000 |
commit | 7b8bfaa26930bb7f2556d9c346084b077280857d (patch) | |
tree | 145c7acaa12c95c261dd5478a806b5d6735d9d7e | |
parent | 10a2fbc59b1c8cf93d89594ac0ead2acfd0e436b (diff) |
RK3588 support.
ok patrick@
-rw-r--r-- | sys/dev/fdt/rkclock.c | 579 | ||||
-rw-r--r-- | sys/dev/fdt/rkclock_clocks.h | 80 | ||||
-rw-r--r-- | sys/dev/fdt/rkpinctrl.c | 213 |
3 files changed, 842 insertions, 30 deletions
diff --git a/sys/dev/fdt/rkclock.c b/sys/dev/fdt/rkclock.c index b638c4a3be0..9e6458acb19 100644 --- a/sys/dev/fdt/rkclock.c +++ b/sys/dev/fdt/rkclock.c @@ -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> * @@ -187,11 +187,37 @@ #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); +} diff --git a/sys/dev/fdt/rkclock_clocks.h b/sys/dev/fdt/rkclock_clocks.h index 3df0603e7e5..ae012153442 100644 --- a/sys/dev/fdt/rkclock_clocks.h +++ b/sys/dev/fdt/rkclock_clocks.h @@ -357,3 +357,83 @@ #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 diff --git a/sys/dev/fdt/rkpinctrl.c b/sys/dev/fdt/rkpinctrl.c index ac274dcbef8..94df22a19cd 100644 --- a/sys/dev/fdt/rkpinctrl.c +++ b/sys/dev/fdt/rkpinctrl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rkpinctrl.c,v 1.9 2022/10/09 20:30:59 kettenis Exp $ */ +/* $OpenBSD: rkpinctrl.c,v 1.10 2023/02/26 12:39:48 kettenis Exp $ */ /* * Copyright (c) 2017, 2018 Mark Kettenis <kettenis@openbsd.org> * @@ -82,6 +82,7 @@ int rk3308_pinctrl(uint32_t, void *); int rk3328_pinctrl(uint32_t, void *); int rk3399_pinctrl(uint32_t, void *); int rk3568_pinctrl(uint32_t, void *); +int rk3588_pinctrl(uint32_t, void *); int rkpinctrl_match(struct device *parent, void *match, void *aux) @@ -92,7 +93,8 @@ rkpinctrl_match(struct device *parent, void *match, void *aux) OF_is_compatible(faa->fa_node, "rockchip,rk3308-pinctrl") || OF_is_compatible(faa->fa_node, "rockchip,rk3328-pinctrl") || OF_is_compatible(faa->fa_node, "rockchip,rk3399-pinctrl") || - OF_is_compatible(faa->fa_node, "rockchip,rk3568-pinctrl")); + OF_is_compatible(faa->fa_node, "rockchip,rk3568-pinctrl") || + OF_is_compatible(faa->fa_node, "rockchip,rk3588-pinctrl")); } void @@ -120,8 +122,10 @@ rkpinctrl_attach(struct device *parent, struct device *self, void *aux) pinctrl_register(faa->fa_node, rk3328_pinctrl, sc); else if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-pinctrl")) pinctrl_register(faa->fa_node, rk3399_pinctrl, sc); - else + else if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pinctrl")) pinctrl_register(faa->fa_node, rk3568_pinctrl, sc); + else + pinctrl_register(faa->fa_node, rk3588_pinctrl, sc); /* Attach GPIO banks. */ simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa); @@ -901,3 +905,206 @@ fail: free(pins, M_TEMP, len); return -1; } + + +/* + * Rockchip RK3588 + */ + +int +rk3588_pull(uint32_t bank, uint32_t idx, uint32_t phandle) +{ + int node; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return -1; + + if (OF_getproplen(node, "bias-disable") == 0) + return 0; + if (OF_getproplen(node, "bias-pull-up") == 0) + return 3; + if (OF_getproplen(node, "bias-pull-down") == 0) + return 1; + + return -1; +} + +int +rk3588_strength(uint32_t bank, uint32_t idx, uint32_t phandle) +{ + int node; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return -1; + + return OF_getpropint(node, "drive-strength", -1); +} + +int +rk3588_schmitt(uint32_t bank, uint32_t idx, uint32_t phandle) +{ + int node; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return -1; + + if (OF_getproplen(node, "input-schmitt-disable") == 0) + return 0; + if (OF_getproplen(node, "input-schmitt-enable") == 0) + return 1; + + return -1; +} + +#define RK3588_PMU1_IOC 0x0000 +#define RK3588_PMU2_IOC 0x4000 +#define RK3588_BUS_IOC 0x8000 +#define RK3588_VCCIO1_4_IOC 0x9000 +#define RK3588_VCCIO3_5_IOC 0xa000 +#define RK3588_VCCIO2_IOC 0xb000 +#define RK3588_VCCIO6_IOC 0xc000 +#define RK3588_EMMC_IOC 0xd000 + +bus_size_t +rk3588_base(uint32_t bank, uint32_t idx) +{ + if (bank == 1 && idx < 32) + return RK3588_VCCIO1_4_IOC; + if (bank == 2 && idx < 6) + return RK3588_EMMC_IOC; + if (bank == 2 && idx < 24) + return RK3588_VCCIO3_5_IOC; + if (bank == 2 && idx < 32) + return RK3588_EMMC_IOC; + if (bank == 3 && idx < 32) + return RK3588_VCCIO3_5_IOC; + if (bank == 4 && idx < 18) + return RK3588_VCCIO6_IOC; + if (bank == 4 && idx < 24) + return RK3588_VCCIO3_5_IOC; + if (bank == 4 && idx < 32) + return RK3588_VCCIO2_IOC; + + return (bus_size_t)-1; +} + +int +rk3588_pinctrl(uint32_t phandle, void *cookie) +{ + struct rkpinctrl_softc *sc = cookie; + struct regmap *rm = sc->sc_grf; + uint32_t *pins; + int node, len, i; + + KASSERT(sc->sc_grf); + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return -1; + + len = OF_getproplen(node, "rockchip,pins"); + if (len <= 0) + return -1; + + pins = malloc(len, M_TEMP, M_WAITOK); + if (OF_getpropintarray(node, "rockchip,pins", pins, len) != len) + goto fail; + + for (i = 0; i < len / sizeof(uint32_t); i += 4) { + bus_size_t iomux_base, p_base, ds_base, smt_base, off; + uint32_t bank, idx, mux; + int pull, strength, schmitt; + uint32_t mask, bits; + int s; + + bank = pins[i]; + idx = pins[i + 1]; + mux = pins[i + 2]; + pull = rk3568_pull(bank, idx, pins[i + 3]); + strength = rk3568_strength(bank, idx, pins[i + 3]); + schmitt = rk3568_schmitt(bank, idx, pins[i + 3]); + + if (bank > 5 || idx > 32 || mux > 15) + continue; + + if (bank == 0 && idx < 12) { + /* PMU1 */ + iomux_base = RK3588_PMU1_IOC; + } else { + /* BUS */ + iomux_base = RK3588_BUS_IOC; + } + + if (bank == 0) { + if (idx < 12) { + /* PMU1 */ + p_base = RK3588_PMU1_IOC + 0x0020; + ds_base = RK3588_PMU1_IOC + 0x0010; + smt_base = RK3588_PMU1_IOC + 0x0030; + } else { + /* PMU2 */ + p_base = RK3588_PMU2_IOC + 0x0024; + ds_base = RK3588_PMU2_IOC + 0x0008; + smt_base = RK3588_PMU2_IOC + 0x003c; + } + } else { + bus_size_t base = rk3588_base(bank, idx); + KASSERT(base != (bus_size_t)-1); + + p_base = base + 0x0100; + ds_base = base + 0x0000; + smt_base = base + 0x0200; + } + + s = splhigh(); + + /* IOMUX control */ + off = bank * 0x20 + (idx / 4) * 0x04; + mask = (0xf << ((idx % 4) * 4)); + bits = (mux << ((idx % 4) * 4)); + regmap_write_4(rm, iomux_base + off, mask << 16 | bits); + if (bank == 0 && idx > 12) { + iomux_base = RK3588_PMU2_IOC; + off = (idx - 12) / 4 * 0x04; + mux = (mux < 8) ? mux : 8; + bits = (mux << ((idx % 4) * 4)); + regmap_write_4(rm, iomux_base + off, mask << 16 | bits); + } + + /* GPIO pad pull down and pull up control */ + if (pull >= 0) { + off = bank * 0x10 + (idx / 8) * 0x04; + mask = (0x3 << ((idx % 8) * 2)); + bits = (pull << ((idx % 8) * 2)); + regmap_write_4(rm, p_base + off, mask << 16 | bits); + } + + /* GPIO drive strength control */ + if (strength >= 0) { + off = bank * 0x20 + (idx / 4) * 0x04; + mask = (0xf << ((idx % 4) * 4)); + bits = ((1 << (strength + 1)) - 1) << ((idx % 4) * 4); + regmap_write_4(rm, ds_base + off, mask << 16 | bits); + } + + /* GPIO Schmitt trigger. */ + if (schmitt >= 0) { + off = bank * 0x10 + (idx / 8) * 0x04; + mask = (0x1 << (idx % 8)); + bits = schmitt << (idx % 8); + regmap_write_4(rm, smt_base + off, mask << 16 | bits); + } + + splx(s); + } + + free(pins, M_TEMP, len); + return 0; + +fail: + free(pins, M_TEMP, len); + return -1; +} |