From 1af18cc176787adb8047614c2af737b43dee895b Mon Sep 17 00:00:00 2001 From: kettenis Date: Wed, 1 Aug 2018 15:55:50 +0000 Subject: [PATCH] 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. --- sys/dev/fdt/rkclock.c | 123 ++++++++++++++++++++++++++++++++++-------- 1 file 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 * @@ -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; -- 2.20.1