Use RK3128_CRU_GLB_SOFTRST_1 to implement cpuresetfn
---
sys/dev/fdt/rkclock.c | 590 ++++++++++++++++++++++++++++++++++-
sys/dev/fdt/rkclock_clocks.h | 52 +++
2 files changed, 634 insertions(+), 8 deletions(-)
diff --git a/sys/dev/fdt/rkclock.c b/sys/dev/fdt/rkclock.c
index 35a02642e7f..a0e5659748c 100644
--- a/sys/dev/fdt/rkclock.c
+++ b/sys/dev/fdt/rkclock.c
@@ -29,6 +29,62 @@
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/fdt.h>
+#define SEL(l, f) (((1 << (l - f + 1)) - 1) << f)
+#define DIV(l, f) SEL(l, f)
+
+/* RK3128 registers */
+#define RK3128_CRU_APLL_CON(i) (0x0000 + (i) * 4)
+#define RK3128_CRU_DPLL_CON(i) (0x0010 + (i) * 4)
+#define RK3128_CRU_CPLL_CON(i) (0x0020 + (i) * 4)
+#define RK3128_CRU_GPLL_CON(i) (0x0030 + (i) * 4)
+#define RK3128_CRU_PLL_POSTDIV1_MASK SEL(14, 12)
+#define RK3128_CRU_PLL_POSTDIV1_SHIFT 12
+#define RK3128_CRU_PLL_FBDIV_MASK SEL(11, 0)
+#define RK3128_CRU_PLL_FBDIV_SHIFT 0
+#define RK3128_CRU_PLL_DSMPD_MASK (1 << 12)
+#define RK3128_CRU_PLL_DSMPD_SHIFT 12
+#define RK3128_CRU_PLL_PLL_LOCK (1 << 10)
+#define RK3128_CRU_PLL_POSTDIV2_MASK SEL(8, 6)
+#define RK3128_CRU_PLL_POSTDIV2_SHIFT 6
+#define RK3128_CRU_PLL_REFDIV_MASK SEL(5, 0)
+#define RK3128_CRU_PLL_REFDIV_SHIFT 0
+#define RK3128_CRU_PLL_FRAC_MASK SEL(23, 0)
+#define RK3128_CRU_PLL_FRAC_SHIFT 0
+#define RK3128_CRU_MODE_CON 0x0040
+#define RK3128_CRU_MODE_PLL_WORK_MODE_MASK 0x3
+#define RK3128_CRU_MODE_PLL_WORK_MODE_SLOW 0x0
+#define RK3128_CRU_MODE_PLL_WORK_MODE_NORMAL 0x1
+#define RK3128_CRU_CLKSEL_CON(i) (0x0044 + (i) * 4)
+#define RK3128_CRU_CPU_CLK_PLL_SEL_MASK SEL(14, 13)
+#define RK3128_CRU_CPU_CLK_PLL_SEL_SHIFT 13
+#define RK3128_CRU_CORE_ACLK_DIV_CON_SHIFT 8
+#define RK3128_CRU_CORE_ACLK_DIV_CON_MASK SEL(12, 8)
+#define RK3128_CRU_CORE_ACLK_DIV_CON_SHIFT 8
+#define RK3128_CRU_CORE_CLK_PLL_SEL_MASK (1 << 7)
+#define RK3128_CRU_CORE_CLK_PLL_SEL_SHIFT 7
+#define RK3128_CRU_CLK_CORE_DIV_CON_MASK SEL(4, 0)
+#define RK3128_CRU_CLK_CORE_DIV_CON_SHIFT 0
+#define RK3128_CRU_PERI_PLL_SEL_MASK SEL(15, 14)
+#define RK3128_CRU_PERI_PLL_SEL_SHIFT 14
+#define RK3128_CRU_PERI_PCLK_DIV_CON_MASK SEL(13, 12)
+#define RK3128_CRU_PERI_PCLK_DIV_CON_SHIFT 12
+#define RK3128_CRU_CLKGATE_CON(i) (0x00d0 + (i) * 4)
+#define RK3128_CRU_GLB_SOFTRST_1 0x0100
+#define RK3128_CRU_GLB_SRSTN_1 0xfdb9
+#define RK3128_CRU_GLB_SOFTRST_2 0x0104
+#define RK3128_CRU_GLB_SRSTN_2 0xeca8
+#define RK3128_CRU_SOFTRST_CON(i) (0x0110 + (i) * 4)
+#define RK3128_EMMC_PLL_SHIFT 14
+#define RK3128_EMMC_PLL_MASK (3 << RK3128_EMMC_PLL_SHIFT)
+#define RK3128_EMMC_DIV_SHIFT 8
+#define RK3128_EMMC_DIV_MASK (0x3f << RK3128_EMMC_DIV_SHIFT)
+#define RK3128_MMC0_PLL_SHIFT 6
+#define RK3128_MMC0_PLL_MASK (3 << RK3128_MMC0_PLL_SHIFT)
+#define RK3128_MMC0_DIV_SHIFT 0
+#define RK3128_MMC0_DIV_MASK (0x3f << RK3128_MMC0_DIV_SHIFT)
+#define RK3128_MMC_SEL_GPLL 0x1
+#define RK3128_MMC_SEL_24M 0x3
+
/* RK3288 registers */
#define RK3288_CRU_APLL_CON(i) (0x0000 + (i) * 4)
#define RK3288_CRU_CPLL_CON(i) (0x0020 + (i) * 4)
@@ -233,9 +289,6 @@ struct rkclock {
uint32_t flags;
};
-#define SEL(l, f) (((1 << (l - f + 1)) - 1) << f)
-#define DIV(l, f) SEL(l, f)
-
#define FIXED_PARENT (1 << 0)
#define SET_PARENT (1 << 1)
@@ -261,9 +314,13 @@ struct rkclock_softc {
struct reset_device sc_rd;
};
+static struct rkclock_softc *the_rkclock = NULL;
+
int rkclock_match(struct device *, void *, void *);
void rkclock_attach(struct device *, struct device *, void *);
+extern void (*cpuresetfn)(void);
+
const struct cfattach rkclock_ca = {
sizeof (struct rkclock_softc), rkclock_match, rkclock_attach
};
@@ -272,6 +329,15 @@ struct cfdriver rkclock_cd = {
NULL, "rkclock", DV_DULL
};
+void rk3128_init(struct rkclock_softc *);
+uint32_t rk3128_get_frequency(void *, uint32_t *);
+int rk3128_set_frequency(void *, uint32_t *, uint32_t);
+int rk3128_set_mmc_frequency(void *, uint32_t, uint32_t, uint32_t);
+int rk3128_set_parent(void *, uint32_t *, uint32_t *);
+void rk3128_enable(void *, uint32_t *, int);
+void rk3128_reset(void *, uint32_t *, int);
+void rk3128_cpureset(void);
+
void rk3288_init(struct rkclock_softc *);
uint32_t rk3288_get_frequency(void *, uint32_t *);
int rk3288_set_frequency(void *, uint32_t *, uint32_t);
@@ -344,6 +410,12 @@ struct rkclock_compat {
};
const struct rkclock_compat rkclock_compat[] = {
+ {
+ "rockchip,rk3128-cru", NULL, 0, rk3128_init,
+ rk3128_enable, rk3128_get_frequency,
+ rk3128_set_frequency, rk3128_set_parent,
+ rk3128_reset
+ },
{
"rockchip,rk3288-cru", NULL, 0, rk3288_init,
rk3288_enable, rk3288_get_frequency,
@@ -519,7 +591,7 @@ rkclock_div_con(struct rkclock_softc *sc, const struct
rkclock *clk,
/* Derive maximum value from mask. */
max_div_con = clk->div_mask >> (ffs(clk->div_mask) - 1);
-
+
parent_freq = sc->sc_cd.cd_get_frequency(sc, &idx);
div = (parent_freq + freq - 1) / freq;
div_con = (div > 0 ? div - 1 : 0);
@@ -542,7 +614,7 @@ uint32_t
rkclock_get_frequency(struct rkclock_softc *sc, uint32_t idx)
{
const struct rkclock *clk;
- uint32_t reg, mux, div_con;
+ uint32_t reg, mux, div_con, ret;
int shift;
clk = rkclock_lookup(sc, idx);
@@ -568,7 +640,8 @@ rkclock_get_frequency(struct rkclock_softc *sc, uint32_t
idx)
return 0;
}
idx = clk->parents[mux];
- return sc->sc_cd.cd_get_frequency(sc, &idx) / (div_con + 1);
+ ret = sc->sc_cd.cd_get_frequency(sc, &idx) / (div_con + 1);
+ return ret;
}
int
@@ -582,8 +655,8 @@ rkclock_set_frequency(struct rkclock_softc *sc, uint32_t
idx, uint32_t freq)
clk = rkclock_lookup(sc, idx);
if (clk == NULL) {
- printf("%s(%s, %u, %u)\n", __func__, sc->sc_dev.dv_xname,
- idx, freq);
+ printf("%s(%s, %u, %u) failed lookup\n", __func__,
+ sc->sc_dev.dv_xname, idx, freq);
return -1;
}
@@ -696,6 +769,507 @@ rkclock_set_parent(struct rkclock_softc *sc, uint32_t
idx, uint32_t parent)
return 0;
}
+/*
+ * Rockchip RK3128
+ */
+
+const struct rkclock rk3128_clocks[] = {
+ {
+ RK3128_CLK_SDMMC, RK3128_CRU_CLKSEL_CON(11),
+ SEL(7, 6), DIV(5, 0),
+ { RK3128_PLL_CPLL, RK3128_PLL_GPLL, RK3128_PLL_GPLL_DIV2,
+ RK3128_XIN24M }
+ },
+ {
+ RK3128_CLK_EMMC, RK3128_CRU_CLKSEL_CON(12),
+ SEL(15, 14), DIV(13, 8),
+ { RK3128_PLL_CPLL, RK3128_PLL_GPLL, RK3128_PLL_GPLL_DIV2,
+ RK3128_XIN24M }
+ },
+ {
+ RK3128_CLK_UART0, RK3128_CRU_CLKSEL_CON(13),
+ SEL(12, 12), DIV(6, 0),
+ { RK3128_PLL_CPLL, RK3128_PLL_GPLL, RK3128_PLL_GPLL_DIV2,
+ RK3128_CLK_USB480M }
+ },
+ /* RK3128_CLK_UART1 */
+ {
+ RK3128_CLK_MAC, RK3128_CRU_CLKSEL_CON(5),
+ SEL(7, 6), DIV(4, 0),
+ { RK3128_PLL_CPLL, RK3128_PLL_GPLL, RK3128_PLL_GPLL_DIV2 }
+ },
+ {
+ RK3128_CLK_MAC_SRC, RK3128_CRU_CLKSEL_CON(5),
+ SEL(7, 6), DIV(4, 0),
+ { RK3128_PLL_CPLL, RK3128_PLL_GPLL, RK3128_PLL_GPLL_DIV2 }
+ },
+ /* RK3128_PCLK_I2C0 */
+ /* RK3128_PCLK_I2C1 */
+ /* RK3128_PCLK_I2C2 */
+ /* RK3128_PCLK_I2C3 */
+ {}
+};
+
+void
+rk3128_init(struct rkclock_softc *sc)
+{
+ int i;
+
+ /* The code below assumes all clocks are enabled. Check this!. */
+ for (i = 0; i <= 10; i++) {
+ if (HREAD4(sc, RK3128_CRU_CLKGATE_CON(i)) != 0x00000000) {
+ printf("CRU_CLKGATE_CON%d: 0x%08x\n", i,
+ HREAD4(sc, RK3128_CRU_CLKGATE_CON(i)));
+ }
+ }
+
+ sc->sc_clocks = rk3128_clocks;
+ the_rkclock = sc;
+ cpuresetfn = rk3128_cpureset;
+}
+
+void
+rk3128_cpureset(void)
+{
+ if (the_rkclock == NULL)
+ return;
+
+ HWRITE4(the_rkclock, RK3128_CRU_GLB_SOFTRST_1, RK3128_CRU_GLB_SRSTN_1);
+}
+
+uint32_t
+rk3128_get_armclk(struct rkclock_softc *sc)
+{
+ uint32_t reg, mux, div_con, idx;
+
+ reg = HREAD4(sc, RK3308_CRU_CLKSEL_CON(0));
+ mux = (reg & RK3308_CRU_CORE_CLK_PLL_SEL_MASK) >>
+ RK3308_CRU_CORE_CLK_PLL_SEL_SHIFT;
+ div_con = (reg & RK3308_CRU_CLK_CORE_DIV_CON_MASK) >>
+ RK3308_CRU_CLK_CORE_DIV_CON_SHIFT;
+ idx = mux ? RK3128_PLL_GPLL_DIV2 : RK3128_PLL_APLL;
+
+ return rk3128_get_frequency(sc, &idx) / (div_con + 1);
+}
+
+uint32_t
+rk3128_get_pll(struct rkclock_softc *sc, bus_size_t base)
+{
+ uint32_t fbdiv, postdiv1, postdiv2, refdiv, con;
+
+ con = HREAD4(sc, RK3128_CRU_MODE_CON);
+
+ switch ((con >> (base >> 2)) & 0x1) {
+ case 0:
+ /* slow */
+ return 24000000;
+ case 1:
+ /* normal */
+ con = HREAD4(sc, base);
+ postdiv1 = (con & RK3128_CRU_PLL_POSTDIV1_MASK) >>
+ RK3128_CRU_PLL_POSTDIV1_SHIFT;
+ fbdiv = (con & RK3128_CRU_PLL_FBDIV_MASK) >>
+ RK3128_CRU_PLL_FBDIV_SHIFT;
+ con = HREAD4(sc, base + 0x0004);
+ postdiv2 = (con & RK3128_CRU_PLL_POSTDIV2_MASK) >>
+ RK3128_CRU_PLL_POSTDIV2_SHIFT;
+ refdiv = (con & RK3128_CRU_PLL_REFDIV_MASK) >>
+ RK3128_CRU_PLL_REFDIV_SHIFT;
+ return 24 * fbdiv / refdiv * postdiv1 * postdiv2 * 1000000;
+ default:
+ return 32768;
+ }
+}
+
+int
+rk3128_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq)
+{
+ uint32_t fbdiv, postdiv1, postdiv2, refdiv;
+ int mode_shift;
+
+ /*
+ * 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. For now
+ * this set covers all the CPU frequencies supported by the
+ * Linux kernel.
+ */
+ switch (freq) {
+ case 1608000000U:
+ case 1584000000U:
+ case 1560000000U:
+ case 1536000000U:
+ case 1512000000U:
+ case 1488000000U:
+ case 1464000000U:
+ case 1440000000U:
+ case 1416000000U:
+ case 1392000000U:
+ case 1368000000U:
+ case 1344000000U:
+ case 1320000000U:
+ case 1296000000U:
+ case 1272000000U:
+ case 1248000000U:
+ case 1200000000U:
+ case 1104000000U:
+ postdiv1 = postdiv2 = refdiv = 1;
+ break;
+ case 1188000000U:
+ refdiv = 2; postdiv1 = postdiv2 = 1;
+ break;
+ case 1100000000U:
+ refdiv = 12; postdiv1 = postdiv2 = 1;
+ break;
+ case 1000000000U:
+ refdiv = 6; postdiv1 = postdiv2 = 1;
+ break;
+ case 1008000000U:
+ case 984000000U:
+ case 960000000U:
+ case 936000000U:
+ case 912000000U:
+ case 888000000U:
+ case 864000000U:
+ case 840000000U:
+ case 816000000U:
+ case 696000000U:
+ case 624000000U:
+ postdiv1 = 2; postdiv2 = refdiv = 1;
+ break;
+ case 900000000U:
+ refdiv = 4; postdiv1 = 2; postdiv2 = 1;
+ break;
+ case 800000000U:
+ case 700000000U:
+ case 500000000U:
+ refdiv = 6; postdiv1 = 2; postdiv2 = 1;
+ break;
+ case 600000000U:
+ case 504000000U:
+ postdiv1 = 3; postdiv2 = refdiv = 1;
+ break;
+ case 594000000U:
+ refdiv = 2; postdiv1 = 2; postdiv2 = 1;
+ break;
+ case 408000000U:
+ case 312000000U:
+ postdiv1 = postdiv2 = 2; refdiv = 1;
+ break;
+ case 216000000U:
+ postdiv1 = 4; postdiv2 = 2; refdiv = 1;
+ break;
+ case 96000000U:
+ postdiv1 = postdiv2 = 4; refdiv = 1;
+ break;
+ default:
+ printf("%s: %u Hz\n", __func__, freq);
+ return -1;
+ }
+
+ /* Calculate feedback divider. */
+ fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000;
+
+ printf("%s: setting 0x%lx pll to freq:%d postdiv1:%d fbdiv:%d dsmpd:%d
postdiv2:%d refdiv:%d\n",
+ __func__, base, freq, postdiv1, fbdiv, 0 /* dsmpd */, postdiv2,
refdiv);
+
+ /*
+ * Select slow mode to guarantee a stable clock while we're
+ * adjusting the PLL.
+ */
+ mode_shift = base >> 2;
+ HWRITE4(sc, RK3128_CRU_MODE_CON,
+ (RK3128_CRU_MODE_PLL_WORK_MODE_MASK << 16 |
+ RK3128_CRU_MODE_PLL_WORK_MODE_SLOW) << mode_shift);
+
+ /* Set PLL rate. */
+ HWRITE4(sc, base,
+ RK3128_CRU_PLL_POSTDIV1_MASK << 16 |
+ postdiv1 << RK3128_CRU_PLL_POSTDIV1_SHIFT |
+ RK3128_CRU_PLL_FBDIV_MASK << 16 |
+ fbdiv << RK3128_CRU_PLL_FBDIV_SHIFT);
+ HWRITE4(sc, base + 0x0004,
+ RK3128_CRU_PLL_DSMPD_MASK << 16 | RK3128_CRU_PLL_DSMPD_MASK |
+ RK3128_CRU_PLL_POSTDIV2_MASK << 16 |
+ postdiv2 << RK3128_CRU_PLL_POSTDIV2_SHIFT |
+ RK3128_CRU_PLL_REFDIV_MASK << 16 |
+ refdiv << RK3128_CRU_PLL_REFDIV_SHIFT);
+
+ /* Wait for PLL to stabilize. */
+ while ((HREAD4(sc, base + 0x0004) & RK3128_CRU_PLL_PLL_LOCK) == 0)
+ delay(10);
+
+ /* Switch back to normal mode. */
+ HWRITE4(sc, RK3128_CRU_MODE_CON,
+ (RK3128_CRU_MODE_PLL_WORK_MODE_MASK << 16 |
+ RK3128_CRU_MODE_PLL_WORK_MODE_NORMAL) << mode_shift);
+
+ return 0;
+}
+
+uint32_t
+rk3128_get_mmc(struct rkclock_softc *sc, uint32_t idx)
+{
+ uint32_t reg, mux, div, gclk;
+
+ switch (idx) {
+ case RK3128_CLK_EMMC:
+ reg = HREAD4(sc, RK3128_CRU_CLKSEL_CON(12));
+ mux = (reg & RK3128_EMMC_PLL_MASK) >> RK3128_EMMC_PLL_SHIFT;
+ div = (reg & RK3128_EMMC_DIV_MASK) >> RK3128_EMMC_DIV_SHIFT;
+ break;
+ case RK3128_CLK_SDMMC:
+ reg = HREAD4(sc, RK3128_CRU_CLKSEL_CON(11));
+ mux = (reg & RK3128_MMC0_PLL_MASK) >> RK3128_MMC0_PLL_SHIFT;
+ div = (reg & RK3128_MMC0_DIV_MASK) >> RK3128_MMC0_DIV_SHIFT;
+ break;
+ default:
+ return 0;
+ }
+
+ if (mux == RK3128_MMC_SEL_24M)
+ return 24000000 / (div + 1);
+ else {
+ gclk = RK3128_PLL_GPLL;
+ return rk3128_get_frequency(sc, &gclk) / (div + 1);
+ }
+}
+
+int
+rk3128_set_mmc(void *cookie, uint32_t gclk_rate, uint32_t idx, uint32_t freq)
+{
+ struct rkclock_softc *sc = cookie;
+ uint32_t src_clk_div;
+ int mux;
+
+ src_clk_div = ((gclk_rate / 2) + freq - 1) / freq;
+ if (src_clk_div > 128) {
+ src_clk_div = ((24000000 / 2) + freq - 1) / freq;
+ mux = RK3128_MMC_SEL_24M;
+ } else {
+ mux = RK3128_MMC_SEL_GPLL;
+ }
+
+ switch (idx) {
+ case RK3128_CLK_EMMC:
+ HWRITE4(sc, RK3128_CRU_CLKSEL_CON(12),
+ (RK3128_EMMC_PLL_MASK | RK3128_EMMC_DIV_MASK |
+ mux << RK3128_EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << RK3128_EMMC_DIV_SHIFT) << 16 |
+ mux << RK3128_EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << RK3128_EMMC_DIV_SHIFT);
+ break;
+ case RK3128_CLK_SDMMC:
+ HWRITE4(sc, RK3128_CRU_CLKSEL_CON(11),
+ (RK3128_MMC0_PLL_MASK | RK3128_MMC0_DIV_MASK |
+ mux << RK3128_MMC0_PLL_SHIFT |
+ (src_clk_div - 1) << RK3128_MMC0_DIV_SHIFT) << 16 |
+ mux << RK3128_MMC0_PLL_SHIFT |
+ (src_clk_div - 1) << RK3128_MMC0_DIV_SHIFT);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+uint32_t
+rk3128_get_peri(struct rkclock_softc *sc, uint32_t idx)
+{
+ uint32_t reg, div;
+
+ switch (idx) {
+ case RK3128_PCLK_I2C0:
+ case RK3128_PCLK_I2C1:
+ case RK3128_PCLK_I2C2:
+ case RK3128_PCLK_I2C3:
+ case RK3128_PCLK_PWM:
+ reg = HREAD4(sc, RK3128_CRU_CLKSEL_CON(10));
+ div = (reg & RK3128_CRU_PERI_PCLK_DIV_CON_MASK) >>
+ RK3128_CRU_PERI_PCLK_DIV_CON_SHIFT;
+ break;
+ default:
+ return 0;
+ }
+
+ /* PERI_ACLK_HZ */
+ return 148500000 / (div + 1);
+}
+
+int
+rk3128_set_peri(struct rkclock_softc *sc, uint32_t idx, uint32_t freq)
+{
+ uint32_t src_clk_div;
+
+ /* PERI_ACLK_HZ */
+ src_clk_div = 148500000 / freq;
+
+ switch (idx) {
+ case RK3128_PCLK_I2C0:
+ case RK3128_PCLK_I2C1:
+ case RK3128_PCLK_I2C2:
+ case RK3128_PCLK_I2C3:
+ case RK3128_PCLK_PWM:
+ HWRITE4(sc, RK3128_CRU_CLKSEL_CON(10),
+ ((src_clk_div - 1) <<
+ RK3128_CRU_PERI_PCLK_DIV_CON_SHIFT) << 16 |
+ (src_clk_div - 1) << RK3128_CRU_PERI_PCLK_DIV_CON_SHIFT);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+uint32_t
+rk3128_get_frequency(void *cookie, uint32_t *cells)
+{
+ struct rkclock_softc *sc = cookie;
+ uint32_t idx = cells[0];
+
+ switch (idx) {
+ case RK3128_PLL_APLL:
+ return rk3128_get_pll(sc, RK3128_CRU_APLL_CON(0));
+ case RK3128_PLL_DPLL:
+ return rk3128_get_pll(sc, RK3128_CRU_DPLL_CON(0));
+ case RK3128_PLL_CPLL:
+ return rk3128_get_pll(sc, RK3128_CRU_CPLL_CON(0));
+ case RK3128_PLL_GPLL:
+ return rk3128_get_pll(sc, RK3128_CRU_GPLL_CON(0));
+ case RK3128_PLL_GPLL_DIV2:
+ return rk3128_get_pll(sc, RK3128_CRU_GPLL_CON(0)) / 2;
+ case RK3128_PLL_GPLL_DIV3:
+ return rk3128_get_pll(sc, RK3128_CRU_GPLL_CON(0)) / 3;
+ case RK3128_ARMCLK:
+ return rk3128_get_armclk(sc);
+ case RK3128_CLK_EMMC:
+ case RK3128_CLK_SDMMC:
+ return rk3128_get_mmc(sc, idx);
+ case RK3128_PCLK_I2C0:
+ case RK3128_PCLK_I2C1:
+ case RK3128_PCLK_I2C2:
+ case RK3128_PCLK_I2C3:
+ case RK3128_PCLK_PWM:
+ return rk3128_get_peri(sc, idx);
+ default:
+ return rkclock_get_frequency(sc, idx);
+ }
+}
+
+int
+rk3128_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
+{
+ struct rkclock_softc *sc = cookie;
+ uint32_t idx = cells[0], gclk, gclk_rate;
+
+ if (idx < 64)
+ return 0;
+
+ gclk = RK3128_PLL_GPLL;
+ gclk_rate = rk3128_get_frequency(sc, &gclk);
+
+ switch (idx) {
+ case RK3128_CLK_EMMC:
+ case RK3128_CLK_SDMMC:
+ return rk3128_set_mmc(sc, gclk_rate, idx, freq);
+ case RK3128_PCLK_I2C0:
+ case RK3128_PCLK_I2C1:
+ case RK3128_PCLK_I2C2:
+ case RK3128_PCLK_I2C3:
+ return rk3128_set_peri(sc, idx, freq);
+ case RK3128_CLK_MAC_SRC:
+ return rkclock_set_frequency(sc, idx, freq);
+ default:
+ printf("%s: TODO implement %d -> %d\n", __func__, idx, freq);
+ break;
+ }
+
+ return -1;
+}
+
+void
+rk3128_enable(void *cookie, uint32_t *cells, int on)
+{
+ uint32_t idx = cells[0];
+
+ switch (idx) {
+ case RK3128_CLK_SDMMC:
+ case RK3128_CLK_EMMC:
+ case RK3128_CLK_UART0:
+ case RK3128_CLK_UART1:
+ case RK3128_CLK_UART2:
+ case RK3128_CLK_MAC:
+ case RK3128_CLK_MAC_RX:
+ case RK3128_CLK_MAC_TX:
+ case RK3128_CLK_SDMMC_DRV:
+ case RK3128_CLK_EMMC_DRV:
+ case RK3128_CLK_SDMMC_SAMPLE:
+ case RK3128_CLK_EMMC_SAMPLE:
+ case RK3128_CLK_OTGPHY0:
+ case RK3128_CLK_OTGPHY1:
+ case RK3128_ACLK_GMAC:
+ case RK3128_PCLK_I2C0:
+ case RK3128_PCLK_I2C1:
+ case RK3128_PCLK_I2C2:
+ case RK3128_PCLK_I2C3:
+ case RK3128_PCLK_TSADC:
+ case RK3128_PCLK_GMAC:
+ case RK3128_HCLK_SDMMC:
+ case RK3128_HCLK_EMMC:
+ case RK3128_HCLK_HOST2:
+ /* Enabled by default. */
+ break;
+ default:
+ printf("%s: 0x%08x\n", __func__, idx);
+ break;
+ }
+}
+
+int
+rk3128_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells)
+{
+ struct rkclock_softc *sc = cookie;
+
+ printf("%s: %d -> %d\n", __func__, cells[0], pcells[1]);
+
+ return rkclock_set_parent(sc, cells[0], pcells[1]);
+}
+
+void
+rk3128_reset(void *cookie, uint32_t *cells, int on)
+{
+ struct rkclock_softc *sc = cookie;
+ uint32_t idx = cells[0];
+ uint32_t bit, mask, reg;
+
+ switch (idx) {
+ case RK3128_SRST_I2C0:
+ reg = RK3128_CRU_SOFTRST_CON(2);
+ bit = 11;
+ break;
+ case RK3128_SRST_GMAC:
+ reg = RK3128_CRU_SOFTRST_CON(3);
+ bit = 8;
+ break;
+ case RK3128_SRST_SDMMC:
+ reg = RK3128_CRU_SOFTRST_CON(5);
+ bit = 1;
+ break;
+ case RK3128_SRST_EMMC:
+ reg = RK3128_CRU_SOFTRST_CON(5);
+ bit = 3;
+ break;
+ default:
+ printf("%s: %d\n", __func__, idx);
+ return;
+ }
+
+ mask = (1 << bit);
+ HWRITE4(sc, reg, mask << 16 | (on ? mask : 0));
+}
+
/*
* Rockchip RK3288
*/
diff --git a/sys/dev/fdt/rkclock_clocks.h b/sys/dev/fdt/rkclock_clocks.h
index 66a45f690c5..47339ccf247 100644
--- a/sys/dev/fdt/rkclock_clocks.h
+++ b/sys/dev/fdt/rkclock_clocks.h
@@ -1,5 +1,57 @@
/* Public Domain */
+/*
+ * RK3128 clocks.
+ */
+
+#define RK3128_PLL_APLL 1
+#define RK3128_PLL_DPLL 2
+#define RK3128_PLL_CPLL 3
+#define RK3128_PLL_GPLL 4
+#define RK3128_ARMCLK 5
+#define RK3128_PLL_GPLL_DIV2 6
+#define RK3128_PLL_GPLL_DIV3 7
+
+#define RK3128_CLK_SDMMC 68
+#define RK3128_CLK_EMMC 71
+#define RK3128_CLK_UART0 77
+#define RK3128_CLK_UART1 78
+#define RK3128_CLK_UART2 79
+#define RK3128_CLK_SDMMC_DRV 114
+#define RK3128_CLK_EMMC_DRV 117
+#define RK3128_CLK_SDMMC_SAMPLE 118
+#define RK3128_CLK_EMMC_SAMPLE 121
+#define RK3128_CLK_MAC_SRC 124
+#define RK3128_CLK_MAC 126
+#define RK3128_CLK_MAC_RX 129
+#define RK3128_CLK_MAC_TX 130
+#define RK3128_CLK_OTGPHY0 142
+#define RK3128_CLK_OTGPHY1 143
+#define RK3128_CLK_USB480M 154
+
+#define RK3128_ACLK_GMAC 212
+
+#define RK3128_PCLK_I2C0 332
+#define RK3128_PCLK_I2C1 333
+#define RK3128_PCLK_I2C2 334
+#define RK3128_PCLK_I2C3 335
+#define RK3128_PCLK_TSADC 344
+#define RK3128_PCLK_PWM 350
+#define RK3128_PCLK_GMAC 367
+
+#define RK3128_HCLK_SDMMC 456
+#define RK3128_HCLK_EMMC 459
+#define RK3128_HCLK_HOST2 473
+
+#define RK3128_SRST_I2C0 43
+#define RK3128_SRST_GMAC 56
+#define RK3128_SRST_SDMMC 81
+#define RK3128_SRST_SDIO 82
+#define RK3128_SRST_EMMC 83
+#define RK3128_SRST_SARADC 87
+
+#define RK3128_XIN24M 1023
+
/*
* RK3288 clocks.
*/
--
2.47.1