> From: joshua stein <[email protected]>
> Date: Wed, 7 May 2025 21:52:21 -0500
>
> 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(-)
This has all kinds of debug leftovers so I'm assuming this needs a bit
more work before you'll ask for ok's?
A few general notes:
* Doesn't the cpuresetfn function provided dwdog(4) reset the board
already?
* You're adding a lot of #defines that aren't used.
* Try to make the #defines for clock numbers in the device tree match
a bit closer. So RK3128_SCLK_EMMC instead of RK3128_CLK_EMMC etc.
* The get/set_peri() and get/set_mmc() functions really shouldn't be
necessary if you provide the right information in the
rk3128_clocks[] data structure.
* There is no stupid remapping of reset IDs, so you should be able to
implement rk3128_reset() in a very similar way as rk3288_reset().
> 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
>
>