> From: joshua stein <j...@jcs.org>
> 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
> 
> 

Reply via email to