summaryrefslogtreecommitdiff
path: root/sys/dev/fdt
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2018-08-01 15:55:51 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2018-08-01 15:55:51 +0000
commitaea8c319f78b6ed6c6cd280f96f91ae2d761a081 (patch)
tree1b7759401a1cc552dc50ba7966107fecf7a2ce85 /sys/dev/fdt
parentc630e4b5d1a8d3a5cad566ee19832ea5e82e40a0 (diff)
Fix various RK3399 clocks and add support for getting the clock frequency
of the clocks that we can set. Assign clock rates (and parents) based on the "assigned-clocks" device tree property, but only on RK3399 for now as the code for the other Rockchip SoCs isn't quite ready yet. Last but not least, fixup a mistake on the firmware for the Theobroma Systems RK3399-Q7 module such that the "big" cluster uses BPLL as intended.
Diffstat (limited to 'sys/dev/fdt')
-rw-r--r--sys/dev/fdt/rkclock.c123
1 files changed, 100 insertions, 23 deletions
diff --git a/sys/dev/fdt/rkclock.c b/sys/dev/fdt/rkclock.c
index c48683090a3..28bf5091e30 100644
--- a/sys/dev/fdt/rkclock.c
+++ b/sys/dev/fdt/rkclock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rkclock.c,v 1.26 2018/07/31 10:08:24 kettenis Exp $ */
+/* $OpenBSD: rkclock.c,v 1.27 2018/08/01 15:55:50 kettenis Exp $ */
/*
* Copyright (c) 2017, 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -88,6 +88,10 @@
#define RK3399_CRU_ACLKM_CORE_DIV_CON_MASK (0x1f << 8)
#define RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT 8
#define RK3399_CRU_CORE_PLL_SEL_MASK (0x3 << 6)
+#define RK3399_CRU_CORE_PLL_SEL_APLL (0x0 << 6)
+#define RK3399_CRU_CORE_PLL_SEL_BPLL (0x1 << 6)
+#define RK3399_CRU_CORE_PLL_SEL_DPLL (0x2 << 6)
+#define RK3399_CRU_CORE_PLL_SEL_GPLL (0x3 << 6)
#define RK3399_CRU_CORE_PLL_SEL_SHIFT 6
#define RK3399_CRU_CLK_CORE_DIV_CON_MASK (0x1f << 0)
#define RK3399_CRU_CLK_CORE_DIV_CON_SHIFT 0
@@ -163,6 +167,7 @@ void rk3399_pmu_reset(void *, uint32_t *, int);
struct rkclock_compat {
const char *compat;
+ int assign;
void (*init)(struct rkclock_softc *);
void (*enable)(void *, uint32_t *, int);
uint32_t (*get_frequency)(void *, uint32_t *);
@@ -172,22 +177,22 @@ struct rkclock_compat {
struct rkclock_compat rkclock_compat[] = {
{
- "rockchip,rk3288-cru", rk3288_init,
+ "rockchip,rk3288-cru", 0, rk3288_init,
rk3288_enable, rk3288_get_frequency,
rk3288_set_frequency, rk3288_reset
},
{
- "rockchip,rk3328-cru", rk3328_init,
+ "rockchip,rk3328-cru", 0, rk3328_init,
rk3328_enable, rk3328_get_frequency,
rk3328_set_frequency, rk3328_reset
},
{
- "rockchip,rk3399-cru", rk3399_init,
+ "rockchip,rk3399-cru", 1, rk3399_init,
rk3399_enable, rk3399_get_frequency,
rk3399_set_frequency, rk3399_reset,
},
{
- "rockchip,rk3399-pmucru", rk3399_pmu_init,
+ "rockchip,rk3399-pmucru", 1, rk3399_pmu_init,
rk3399_pmu_enable, rk3399_pmu_get_frequency,
rk3399_pmu_set_frequency, rk3399_pmu_reset
}
@@ -250,6 +255,9 @@ rkclock_attach(struct device *parent, struct device *self, void *aux)
sc->sc_rd.rd_cookie = sc;
sc->sc_rd.rd_reset = rkclock_compat[i].reset;
reset_register(&sc->sc_rd);
+
+ if (rkclock_compat[i].assign)
+ clock_set_assigned(faa->fa_node);
}
/*
@@ -785,6 +793,16 @@ rk3399_init(struct rkclock_softc *sc)
#endif
}
+ /*
+ * The U-Boot shipped on the Theobroma Systems RK3399-Q7
+ * module is buggy and sets the parent of the clock for the
+ * "big" cluster to LPLL. Undo that mistake here such that
+ * the clocks of both clusters are independent.
+ */
+ HWRITE4(sc, RK3399_CRU_CLKSEL_CON(2),
+ RK3399_CRU_CORE_PLL_SEL_MASK << 16 |
+ RK3399_CRU_CORE_PLL_SEL_BPLL);
+
/* The code below assumes all clocks are enabled. Check this!. */
for (i = 0; i <= 34; i++) {
if (HREAD4(sc, RK3399_CRU_CLKGATE_CON(i)) != 0x00000000) {
@@ -998,7 +1016,7 @@ rk3399_set_armclk(struct rkclock_softc *sc, bus_size_t clksel, uint32_t freq)
RK3399_CRU_ATCLK_CORE_DIV_CON_MASK << 16 |
div << RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT);
}
-
+
return 0;
}
@@ -1174,26 +1192,90 @@ rk3399_get_frequency(void *cookie, uint32_t *cells)
case RK3399_ACLK_PERIPH:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(14));
mux = (reg >> 7) & 0x1;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
div_con = reg & 0x1f;
return rk3399_get_frequency(sc, &idx) / (div_con + 1);
case RK3399_ACLK_PERILP0:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(23));
mux = (reg >> 7) & 0x1;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
+ div_con = reg & 0x1f;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_ACLK_VIO:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(42));
+ mux = (reg >> 6) & 0x3;
+ switch (mux) {
+ case 0:
+ idx = RK3399_PLL_CPLL;
+ break;
+ case 1:
+ idx = RK3399_PLL_GPLL;
+ break;
+#ifdef notyet
+ case 2:
+ idx = RK3399_PLL_PPLL;
+ break;
+#endif
+ default:
+ return -1;
+ }
+ div_con = reg & 0x1f;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_ACLK_CCI:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(5));
+ mux = (reg >> 6) & 0x3;
+ switch (mux) {
+ case 0:
+ idx = RK3399_PLL_CPLL;
+ break;
+ case 1:
+ idx = RK3399_PLL_GPLL;
+ break;
+ case 2:
+ idx = RK3399_PLL_NPLL;
+ break;
+ case 3:
+ idx = RK3399_PLL_VPLL;
+ break;
+ }
div_con = reg & 0x1f;
return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_PCLK_PERIPH:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(14));
+ idx = RK3399_ACLK_PERIPH;
+ div_con = (reg >> 12) & 0x7;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_PCLK_PERILP0:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(23));
+ idx = RK3399_ACLK_PERILP0;
+ div_con = (reg >> 12) & 0x7;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_PCLK_PERILP1:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(25));
+ idx = RK3399_HCLK_PERILP1;
+ div_con = (reg >> 8) & 0x7;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_HCLK_PERIPH:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(14));
+ idx = RK3399_ACLK_PERIPH;
+ div_con = (reg >> 8) & 0x3;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
+ case RK3399_HCLK_PERILP0:
+ reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(23));
+ idx = RK3399_ACLK_PERILP0;
+ div_con = (reg >> 8) & 0x3;
+ return rk3399_get_frequency(sc, &idx) / (div_con + 1);
case RK3399_HCLK_PERILP1:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(25));
mux = (reg >> 7) & 0x1;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
div_con = reg & 0x1f;
return rk3399_get_frequency(sc, &idx) / (div_con + 1);
case RK3399_HCLK_SDMMC:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(13));
mux = (reg >> 15) & 0x1;
div_con = (reg >> 8) & 0x1f;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
return rk3399_get_frequency(sc, &idx) / (div_con + 1);
default:
break;
@@ -1232,14 +1314,14 @@ rk3399_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
case RK3399_ACLK_PERIPH:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(14));
mux = (reg >> 7) & 0x1;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(14),
0x1f << 16 | rk3399_div_con(sc, idx, freq));
return 0;
case RK3399_ACLK_PERILP0:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(23));
mux = (reg >> 7) & 0x1;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(23),
0x1f << 16 | rk3399_div_con(sc, idx, freq));
return 0;
@@ -1285,39 +1367,34 @@ rk3399_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
0x1f << 16 | rk3399_div_con(sc, idx, freq));
return 0;
case RK3399_PCLK_PERIPH:
- reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(14));
idx = RK3399_ACLK_PERIPH;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(14),
- (0x7 << 28 | rk3399_div_con(sc, idx, freq)) << 12);
+ (0x7 << 16 | rk3399_div_con(sc, idx, freq)) << 12);
return 0;
case RK3399_PCLK_PERILP0:
- reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(23));
idx = RK3399_ACLK_PERILP0;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(23),
- (0x7 << 28 | rk3399_div_con(sc, idx, freq)) << 12);
+ (0x7 << 16 | rk3399_div_con(sc, idx, freq)) << 12);
return 0;
case RK3399_PCLK_PERILP1:
- reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(25));
idx = RK3399_HCLK_PERILP1;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(25),
- (0x3 << 24 | rk3399_div_con(sc, idx, freq)) << 8);
+ (0x7 << 16 | rk3399_div_con(sc, idx, freq)) << 8);
return 0;
case RK3399_HCLK_PERIPH:
- reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(14));
idx = RK3399_ACLK_PERIPH;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(14),
- (0x3 << 24 | rk3399_div_con(sc, idx, freq)) << 8);
+ (0x3 << 16 | rk3399_div_con(sc, idx, freq)) << 8);
return 0;
case RK3399_HCLK_PERILP0:
- reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(23));
idx = RK3399_ACLK_PERILP0;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(23),
- (0x3 << 24 | rk3399_div_con(sc, idx, freq)) << 8);
+ (0x3 << 16 | rk3399_div_con(sc, idx, freq)) << 8);
return 0;
case RK3399_HCLK_PERILP1:
reg = HREAD4(sc, RK3399_CRU_CLKSEL_CON(25));
mux = (reg >> 7) & 0x1;
- idx = mux ? RK3399_PLL_CPLL : RK3399_PLL_GPLL;
+ idx = mux ? RK3399_PLL_GPLL : RK3399_PLL_CPLL;
HWRITE4(sc, RK3399_CRU_CLKSEL_CON(25),
0x1f << 16 | rk3399_div_con(sc, idx, freq));
return 0;