Module Name: src Committed By: jmcneill Date: Sat Sep 1 19:35:53 UTC 2018
Modified Files: src/sys/arch/arm/rockchip: rk3399_cru.c rk_cru.h rk_cru_arm.c Log Message: Add support for RK3399 CPU clocks. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/rockchip/rk3399_cru.c cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/rockchip/rk_cru.h cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/rockchip/rk_cru_arm.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/rockchip/rk3399_cru.c diff -u src/sys/arch/arm/rockchip/rk3399_cru.c:1.2 src/sys/arch/arm/rockchip/rk3399_cru.c:1.3 --- src/sys/arch/arm/rockchip/rk3399_cru.c:1.2 Sun Aug 12 19:28:41 2018 +++ src/sys/arch/arm/rockchip/rk3399_cru.c Sat Sep 1 19:35:53 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: rk3399_cru.c,v 1.2 2018/08/12 19:28:41 jmcneill Exp $ */ +/* $NetBSD: rk3399_cru.c,v 1.3 2018/09/01 19:35:53 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.2 2018/08/12 19:28:41 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.3 2018/09/01 19:35:53 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -139,6 +139,67 @@ static const struct rk_cru_pll_rate pll_ static const struct rk_cru_pll_rate pll_norates[] = { }; +#define RK3399_ACLKM_MASK __BITS(12,8) +#define RK3399_ATCLK_MASK __BITS(4,0) +#define RK3399_PDBG_MASK __BITS(12,8) + +#define RK3399_CPUL_RATE(_rate, _aclkm, _atclk, _pdbg) \ + RK_CPU_RATE(_rate, \ + CLKSEL_CON(0), RK3399_ACLKM_MASK, \ + __SHIFTIN((_aclkm), RK3399_ACLKM_MASK), \ + CLKSEL_CON(1), RK3399_ATCLK_MASK|RK3399_PDBG_MASK, \ + __SHIFTIN((_atclk), RK3399_ATCLK_MASK)|__SHIFTIN((_pdbg), RK3399_PDBG_MASK)) + +#define RK3399_CPUB_RATE(_rate, _aclkm, _atclk, _pdbg) \ + RK_CPU_RATE(_rate, \ + CLKSEL_CON(2), RK3399_ACLKM_MASK, \ + __SHIFTIN((_aclkm), RK3399_ACLKM_MASK), \ + CLKSEL_CON(3), RK3399_ATCLK_MASK|RK3399_PDBG_MASK, \ + __SHIFTIN((_atclk), RK3399_ATCLK_MASK)|__SHIFTIN((_pdbg), RK3399_PDBG_MASK)) + +static const struct rk_cru_cpu_rate armclkl_rates[] = { + RK3399_CPUL_RATE(1800000000, 1, 8, 8), + RK3399_CPUL_RATE(1704000000, 1, 8, 8), + RK3399_CPUL_RATE(1608000000, 1, 7, 7), + RK3399_CPUL_RATE(1512000000, 1, 7, 7), + RK3399_CPUL_RATE(1488000000, 1, 6, 6), + RK3399_CPUL_RATE(1416000000, 1, 6, 6), + RK3399_CPUL_RATE(1200000000, 1, 5, 5), + RK3399_CPUL_RATE(1008000000, 1, 4, 4), + RK3399_CPUL_RATE( 816000000, 1, 3, 3), + RK3399_CPUL_RATE( 696000000, 1, 3, 3), + RK3399_CPUL_RATE( 600000000, 1, 2, 2), + RK3399_CPUL_RATE( 408000000, 1, 1, 1), + RK3399_CPUL_RATE( 312000000, 1, 1, 1), + RK3399_CPUL_RATE( 216000000, 1, 1, 1), + RK3399_CPUL_RATE( 96000000, 1, 1, 1), +}; + +static const struct rk_cru_cpu_rate armclkb_rates[] = { + RK3399_CPUB_RATE(2208000000, 1, 11, 11), + RK3399_CPUB_RATE(2184000000, 1, 11, 11), + RK3399_CPUB_RATE(2088000000, 1, 10, 10), + RK3399_CPUB_RATE(2040000000, 1, 10, 10), + RK3399_CPUB_RATE(2016000000, 1, 9, 9), + RK3399_CPUB_RATE(1992000000, 1, 9, 9), + RK3399_CPUB_RATE(1896000000, 1, 9, 9), + RK3399_CPUB_RATE(1800000000, 1, 8, 8), + RK3399_CPUB_RATE(1704000000, 1, 8, 8), + RK3399_CPUB_RATE(1608000000, 1, 7, 7), + RK3399_CPUB_RATE(1512000000, 1, 7, 7), + RK3399_CPUB_RATE(1488000000, 1, 6, 6), + RK3399_CPUB_RATE(1416000000, 1, 6, 6), + RK3399_CPUB_RATE(1200000000, 1, 5, 5), + RK3399_CPUB_RATE(1008000000, 1, 5, 5), + RK3399_CPUB_RATE( 816000000, 1, 4, 4), + RK3399_CPUB_RATE( 696000000, 1, 3, 3), + RK3399_CPUB_RATE( 600000000, 1, 3, 3), + RK3399_CPUB_RATE( 408000000, 1, 2, 2), + RK3399_CPUB_RATE( 312000000, 1, 1, 1), + RK3399_CPUB_RATE( 216000000, 1, 1, 1), + RK3399_CPUB_RATE( 96000000, 1, 1, 1), +}; + #define PLL_CON0 0x00 #define PLL_FBDIV __BITS(11,0) @@ -229,14 +290,13 @@ rk3399_cru_pll_set_rate(struct rk_cru_so CRU_WRITE(sc, pll->con_base + PLL_CON3, val); CRU_WRITE(sc, pll->con_base + PLL_CON0, - __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) | - PLL_WRITE_MASK); + __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) | (PLL_FBDIV << 16)); CRU_WRITE(sc, pll->con_base + PLL_CON1, __SHIFTIN(pll_rate->postdiv2, PLL_POSTDIV2) | __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) | __SHIFTIN(pll_rate->refdiv, PLL_REFDIV) | - PLL_WRITE_MASK); + ((PLL_POSTDIV2 | PLL_POSTDIV1 | PLL_REFDIV) << 16)); val = CRU_READ(sc, pll->con_base + PLL_CON2); val &= ~PLL_FRACDIV; @@ -246,11 +306,6 @@ rk3399_cru_pll_set_rate(struct rk_cru_so val = __SHIFTIN(pll_rate->dsmpd, PLL_DSMPD) | (PLL_DSMPD << 16); CRU_WRITE(sc, pll->con_base + PLL_CON3, val); - /* Set PLL work mode to normal */ - const uint32_t write_mask = pll->mode_mask << 16; - const uint32_t write_val = pll->mode_mask; - CRU_WRITE(sc, pll->mode_reg, write_mask | write_val); - for (retry = 1000; retry > 0; retry--) { if (CRU_READ(sc, pll->con_base + PLL_CON2) & pll->lock_mask) break; @@ -261,6 +316,7 @@ rk3399_cru_pll_set_rate(struct rk_cru_so device_printf(sc->sc_dev, "WARNING: %s failed to lock\n", clk->base.name); + /* Set PLL work mode to normal */ val = __SHIFTIN(PLL_WORK_MODE_NORMAL, PLL_WORK_MODE) | (PLL_WORK_MODE << 16); CRU_WRITE(sc, pll->con_base + PLL_CON3, val); @@ -287,6 +343,8 @@ rk3399_cru_pll_set_rate(struct rk_cru_so } static const char * pll_parents[] = { "xin24m", "xin32k" }; +static const char * armclkl_parents[] = { "clk_core_l_lpll_src", "clk_core_l_bpll_src", "clk_core_l_dpll_src", "clk_core_l_gpll_src" }; +static const char * armclkb_parents[] = { "clk_core_b_lpll_src", "clk_core_b_bpll_src", "clk_core_b_dpll_src", "clk_core_b_gpll_src" }; static const char * mux_pll_src_cpll_gpll_parents[] = { "cpll", "gpll" }; static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" }; static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" }; @@ -346,6 +404,28 @@ static struct rk_cru_clk rk3399_cru_clks __BIT(31), /* lock_mask */ pll_rates), + RK_GATE(0, "clk_core_l_lpll_src", "lpll", CLKGATE_CON(0), 0), + RK_GATE(0, "clk_core_l_bpll_src", "bpll", CLKGATE_CON(0), 1), + RK_GATE(0, "clk_core_l_dpll_src", "dpll", CLKGATE_CON(0), 2), + RK_GATE(0, "clk_core_l_gpll_src", "gpll", CLKGATE_CON(0), 3), + + RK_CPU(RK3399_ARMCLKL, "armclkl", armclkl_parents, + CLKSEL_CON(0), /* reg */ + __BITS(7,6), 0, 3, /* mux_mask, mux_main, mux_alt */ + __BITS(4,0), /* div_mask */ + armclkl_rates), + + RK_GATE(0, "clk_core_b_lpll_src", "lpll", CLKGATE_CON(1), 0), + RK_GATE(0, "clk_core_b_bpll_src", "bpll", CLKGATE_CON(1), 1), + RK_GATE(0, "clk_core_b_dpll_src", "dpll", CLKGATE_CON(1), 2), + RK_GATE(0, "clk_core_b_gpll_src", "gpll", CLKGATE_CON(1), 3), + + RK_CPU(RK3399_ARMCLKB, "armclkb", armclkb_parents, + CLKSEL_CON(2), /* reg */ + __BITS(7,6), 1, 3, /* mux_mask, mux_main, mux_alt */ + __BITS(4,0), /* div_mask */ + armclkb_rates), + /* * perilp0 */ Index: src/sys/arch/arm/rockchip/rk_cru.h diff -u src/sys/arch/arm/rockchip/rk_cru.h:1.3 src/sys/arch/arm/rockchip/rk_cru.h:1.4 --- src/sys/arch/arm/rockchip/rk_cru.h:1.3 Sun Aug 12 16:48:05 2018 +++ src/sys/arch/arm/rockchip/rk_cru.h Sat Sep 1 19:35:53 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: rk_cru.h,v 1.3 2018/08/12 16:48:05 jmcneill Exp $ */ +/* $NetBSD: rk_cru.h,v 1.4 2018/09/01 19:35:53 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -118,6 +118,19 @@ struct rk_cru_arm_rate { .div = (_div), \ } +struct rk_cru_cpu_rate { + u_int rate; + u_int reg1, reg1_mask, reg1_val; + u_int reg2, reg2_mask, reg2_val; +}; + +#define RK_CPU_RATE(_rate, _reg1, _reg1_mask, _reg1_val, _reg2, _reg2_mask, _reg2_val) \ + { \ + .rate = (_rate), \ + .reg1 = (_reg1), .reg1_mask = (_reg1_mask), .reg1_val = (_reg1_val), \ + .reg2 = (_reg2), .reg2_mask = (_reg2_mask), .reg2_val = (_reg2_val), \ + } + struct rk_cru_arm { bus_size_t reg; uint32_t mux_mask; @@ -127,11 +140,13 @@ struct rk_cru_arm { const char **parents; u_int nparents; const struct rk_cru_arm_rate *rates; + const struct rk_cru_cpu_rate *cpurates; u_int nrates; }; u_int rk_cru_arm_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); int rk_cru_arm_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); +int rk_cru_arm_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); const char *rk_cru_arm_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); int rk_cru_arm_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); @@ -156,6 +171,27 @@ int rk_cru_arm_set_parent(struct rk_cru_ .set_parent = rk_cru_arm_set_parent, \ } +#define RK_CPU(_id, _name, _parents, _reg, _mux_mask, _mux_main, _mux_alt, _div_mask, _cpurates) \ + { \ + .id = (_id), \ + .type = RK_CRU_ARM, \ + .base.name = (_name), \ + .base.flags = 0, \ + .u.arm.parents = (_parents), \ + .u.arm.nparents = __arraycount(_parents), \ + .u.arm.reg = (_reg), \ + .u.arm.mux_mask = (_mux_mask), \ + .u.arm.mux_main = (_mux_main), \ + .u.arm.mux_alt = (_mux_alt), \ + .u.arm.div_mask = (_div_mask), \ + .u.arm.cpurates = (_cpurates), \ + .u.arm.nrates = __arraycount(_cpurates), \ + .get_rate = rk_cru_arm_get_rate, \ + .set_rate = rk_cru_arm_set_rate, \ + .get_parent = rk_cru_arm_get_parent, \ + .set_parent = rk_cru_arm_set_parent, \ + } + /* Composite clocks */ struct rk_cru_composite { Index: src/sys/arch/arm/rockchip/rk_cru_arm.c diff -u src/sys/arch/arm/rockchip/rk_cru_arm.c:1.1 src/sys/arch/arm/rockchip/rk_cru_arm.c:1.2 --- src/sys/arch/arm/rockchip/rk_cru_arm.c:1.1 Sat Jun 16 00:19:04 2018 +++ src/sys/arch/arm/rockchip/rk_cru_arm.c Sat Sep 1 19:35:53 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: rk_cru_arm.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */ +/* $NetBSD: rk_cru_arm.c,v 1.2 2018/09/01 19:35:53 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rk_cru_arm.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rk_cru_arm.c,v 1.2 2018/09/01 19:35:53 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -60,13 +60,13 @@ rk_cru_arm_get_rate(struct rk_cru_softc return fref / div; } -int -rk_cru_arm_set_rate(struct rk_cru_softc *sc, +static int +rk_cru_arm_set_rate_rates(struct rk_cru_softc *sc, struct rk_cru_clk *clk, u_int rate) { struct rk_cru_arm *arm = &clk->u.arm; + struct rk_cru_clk *main_parent, *alt_parent; const struct rk_cru_arm_rate *arm_rate = NULL; - struct clk *clkp_parent; int error; KASSERT(clk->type == RK_CRU_ARM); @@ -82,26 +82,101 @@ rk_cru_arm_set_rate(struct rk_cru_softc if (arm_rate == NULL) return EINVAL; - error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]); + main_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_main]); + alt_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_alt]); + if (main_parent == NULL || alt_parent == NULL) { + device_printf(sc->sc_dev, "couldn't get clock parents\n"); + return ENXIO; + } + + error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_alt]); if (error != 0) return error; - clkp_parent = clk_get_parent(&clk->base); - if (clkp_parent == NULL) - return ENXIO; - const u_int parent_rate = arm_rate->rate / arm_rate->div; - error = clk_set_rate(clkp_parent, parent_rate); + error = clk_set_rate(&main_parent->base, parent_rate); if (error != 0) - return error; + goto done; const uint32_t write_mask = arm->div_mask << 16; const uint32_t write_val = __SHIFTIN(arm_rate->div - 1, arm->div_mask); CRU_WRITE(sc, arm->reg, write_mask | write_val); - return 0; +done: + rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]); + return error; +} + +static int +rk_cru_arm_set_rate_cpurates(struct rk_cru_softc *sc, + struct rk_cru_clk *clk, u_int rate) +{ + struct rk_cru_arm *arm = &clk->u.arm; + struct rk_cru_clk *main_parent, *alt_parent; + const struct rk_cru_cpu_rate *cpu_rate = NULL; + uint32_t write_mask, write_val; + int error; + + KASSERT(clk->type == RK_CRU_ARM); + + if (arm->cpurates == NULL || rate == 0) + return EIO; + + for (int i = 0; i < arm->nrates; i++) + if (arm->cpurates[i].rate == rate) { + cpu_rate = &arm->cpurates[i]; + break; + } + if (cpu_rate == NULL) + return EINVAL; + + main_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_main]); + alt_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_alt]); + if (main_parent == NULL || alt_parent == NULL) { + device_printf(sc->sc_dev, "couldn't get clock parents\n"); + return ENXIO; + } + + error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_alt]); + if (error != 0) + return error; + + error = clk_set_rate(&main_parent->base, rate); + if (error != 0) + goto done; + + write_mask = cpu_rate->reg1_mask << 16; + write_val = cpu_rate->reg1_val; + CRU_WRITE(sc, cpu_rate->reg1, write_mask | write_val); + + write_mask = cpu_rate->reg2_mask << 16; + write_val = cpu_rate->reg2_val; + CRU_WRITE(sc, cpu_rate->reg2, write_mask | write_val); + + write_mask = arm->div_mask << 16; + write_val = __SHIFTIN(0, arm->div_mask); + CRU_WRITE(sc, arm->reg, write_mask | write_val); + +done: + rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]); + return error; +} + + +int +rk_cru_arm_set_rate(struct rk_cru_softc *sc, + struct rk_cru_clk *clk, u_int rate) +{ + struct rk_cru_arm *arm = &clk->u.arm; + + if (arm->rates) + return rk_cru_arm_set_rate_rates(sc, clk, rate); + else if (arm->cpurates) + return rk_cru_arm_set_rate_cpurates(sc, clk, rate); + else + return EIO; } const char *