-/* $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>
*
#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
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 *);
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
}
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);
}
/*
#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) {
RK3399_CRU_ATCLK_CORE_DIV_CON_MASK << 16 |
div << RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT);
}
-
+
return 0;
}
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;
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;
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;