summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2023-02-26 12:39:49 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2023-02-26 12:39:49 +0000
commit7b8bfaa26930bb7f2556d9c346084b077280857d (patch)
tree145c7acaa12c95c261dd5478a806b5d6735d9d7e
parent10a2fbc59b1c8cf93d89594ac0ead2acfd0e436b (diff)
RK3588 support.
ok patrick@
-rw-r--r--sys/dev/fdt/rkclock.c579
-rw-r--r--sys/dev/fdt/rkclock_clocks.h80
-rw-r--r--sys/dev/fdt/rkpinctrl.c213
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;
+}