Module Name: src Committed By: jmcneill Date: Sat Nov 16 13:23:13 UTC 2019
Modified Files: src/sys/arch/arm/rockchip: rk3399_cru.c rk_cru.h rk_cru_composite.c Log Message: Add support for I2S clocks. To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/sys/arch/arm/rockchip/rk3399_cru.c cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/rockchip/rk_cru.h cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/rockchip/rk_cru_composite.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.12 src/sys/arch/arm/rockchip/rk3399_cru.c:1.13 --- src/sys/arch/arm/rockchip/rk3399_cru.c:1.12 Sun Nov 10 11:43:04 2019 +++ src/sys/arch/arm/rockchip/rk3399_cru.c Sat Nov 16 13:23:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: rk3399_cru.c,v 1.12 2019/11/10 11:43:04 jmcneill Exp $ */ +/* $NetBSD: rk3399_cru.c,v 1.13 2019/11/16 13:23:13 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.12 2019/11/10 11:43:04 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.13 2019/11/16 13:23:13 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -361,6 +361,11 @@ static const char * mux_aclk_perihp_pare static const char * mux_aclk_cci_parents[] = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" }; static const char * mux_dclk_vop0_parents[] = { "dclk_vop0_div", "dclk_vop0_frac" }; static const char * mux_dclk_vop1_parents[] = { "dclk_vop1_div", "dclk_vop1_frac" }; +static const char * mux_i2s0_parents[] = { "clk_i2s0_div", "clk_i2s0_frac", "clkin_i2s", "xin12m" }; +static const char * mux_i2s1_parents[] = { "clk_i2s1_div", "clk_i2s1_frac", "clkin_i2s", "xin12m" }; +static const char * mux_i2s2_parents[] = { "clk_i2s2_div", "clk_i2s2_frac", "clkin_i2s", "xin12m" }; +static const char * mux_i2sch_parents[] = { "clk_i2s0", "clk_i2s1", "clk_i2s2" }; +static const char * mux_i2sout_parents[] = { "clk_i2sout_src", "xin12m" }; static const char * mux_uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; static const char * mux_uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; static const char * mux_uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; @@ -939,13 +944,73 @@ static struct rk_cru_clk rk3399_cru_clks 0), RK_GATE(RK3399_PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", CLKGATE_CON(29), 6), RK_GATE(RK3399_SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", CLKGATE_CON(11), 6), + + /* I2S2 */ + RK_COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_parents, + CLKSEL_CON(28), /* muxdiv_reg */ + __BIT(7), /* mux_mask */ + __BITS(6,0), /* div_mask */ + CLKGATE_CON(8), /* gate_reg */ + __BIT(3), /* gate_mask */ + 0), + RK_COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_parents, + CLKSEL_CON(29), /* muxdiv_reg */ + __BIT(7), /* mux_mask */ + __BITS(6,0), /* div_mask */ + CLKGATE_CON(8), /* gate_reg */ + __BIT(6), /* gate_mask */ + 0), + RK_COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_parents, + CLKSEL_CON(30), /* muxdiv_reg */ + __BIT(7), /* mux_mask */ + __BITS(6,0), /* div_mask */ + CLKGATE_CON(8), /* gate_reg */ + __BIT(9), /* gate_mask */ + 0), + RK_COMPOSITE_FRAC(0, "clk_i2s0_frac", "clk_i2s0_div", + CLKSEL_CON(96), /* frac_reg */ + 0), + RK_COMPOSITE_FRAC(0, "clk_i2s1_frac", "clk_i2s1_div", + CLKSEL_CON(97), /* frac_reg */ + 0), + RK_COMPOSITE_FRAC(0, "clk_i2s2_frac", "clk_i2s2_div", + CLKSEL_CON(98), /* frac_reg */ + 0), + RK_MUX(0, "clk_i2s0_mux", mux_i2s0_parents, CLKSEL_CON(28), __BITS(9,8)), + RK_MUX(0, "clk_i2s1_mux", mux_i2s1_parents, CLKSEL_CON(29), __BITS(9,8)), + RK_MUX(0, "clk_i2s2_mux", mux_i2s2_parents, CLKSEL_CON(30), __BITS(9,8)), + RK_GATE(RK3399_SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLKGATE_CON(8), 5), + RK_GATE(RK3399_SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLKGATE_CON(8), 8), + RK_GATE(RK3399_SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLKGATE_CON(8), 11), + RK_GATE(RK3399_HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", CLKGATE_CON(34), 0), + RK_GATE(RK3399_HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", CLKGATE_CON(34), 1), + RK_GATE(RK3399_HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", CLKGATE_CON(34), 2), + RK_MUX(0, "clk_i2sout_src", mux_i2sch_parents, CLKSEL_CON(31), __BITS(1,0)), + RK_COMPOSITE(RK3399_SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_parents, + CLKSEL_CON(31), /* muxdiv_reg */ + __BIT(2), /* mux_mask */ + 0, /* div_mask */ + CLKGATE_CON(8), /* gate_reg */ + __BIT(12), /* gate_mask */ + RK_COMPOSITE_SET_RATE_PARENT), +}; + +static const struct rk3399_init_param { + const char *clk; + const char *parent; +} rk3399_init_params[] = { + { .clk = "clk_i2s0_mux", .parent = "clk_i2s0_frac" }, + { .clk = "clk_i2s1_mux", .parent = "clk_i2s1_frac" }, + { .clk = "clk_i2s2_mux", .parent = "clk_i2s2_frac" }, }; static void rk3399_cru_init(struct rk_cru_softc *sc) { - struct rk_cru_clk *clk; + struct rk_cru_clk *clk, *pclk; uint32_t write_mask, write_val; + int error; + u_int n; /* * Force an update of BPLL to bring it out of slow mode. @@ -960,6 +1025,25 @@ rk3399_cru_init(struct rk_cru_softc *sc) write_val = 0; CRU_WRITE(sc, CLKSEL_CON(49), write_mask | write_val); CRU_WRITE(sc, CLKSEL_CON(50), write_mask | write_val); + + /* + * Set defaults + */ + for (n = 0; n < __arraycount(rk3399_init_params); n++) { + const struct rk3399_init_param *param = &rk3399_init_params[n]; + clk = rk_cru_clock_find(sc, param->clk); + KASSERTMSG(clk != NULL, "couldn't find clock %s", param->clk); + if (param->parent != NULL) { + pclk = rk_cru_clock_find(sc, param->parent); + KASSERTMSG(pclk != NULL, "couldn't find clock %s", param->parent); + error = clk_set_parent(&clk->base, &pclk->base); + if (error != 0) { + aprint_error_dev(sc->sc_dev, "couldn't set %s parent to %s: %d\n", + param->clk, param->parent, error); + continue; + } + } + } } static int Index: src/sys/arch/arm/rockchip/rk_cru.h diff -u src/sys/arch/arm/rockchip/rk_cru.h:1.6 src/sys/arch/arm/rockchip/rk_cru.h:1.7 --- src/sys/arch/arm/rockchip/rk_cru.h:1.6 Sun Nov 10 11:43:04 2019 +++ src/sys/arch/arm/rockchip/rk_cru.h Sat Nov 16 13:23:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: rk_cru.h,v 1.6 2019/11/10 11:43:04 jmcneill Exp $ */ +/* $NetBSD: rk_cru.h,v 1.7 2019/11/16 13:23:13 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -200,11 +200,13 @@ struct rk_cru_composite { uint32_t div_mask; bus_size_t gate_reg; uint32_t gate_mask; + bus_size_t frac_reg; const char **parents; u_int nparents; u_int flags; #define RK_COMPOSITE_ROUND_DOWN 0x01 #define RK_COMPOSITE_SET_RATE_PARENT 0x02 +#define RK_COMPOSITE_FRACDIV 0x04 }; int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int); @@ -213,7 +215,7 @@ int rk_cru_composite_set_rate(struct rk_ const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); int rk_cru_composite_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); -#define RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _flags) \ +#define _RK_COMPOSITE_INIT(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _frac_reg, _flags) \ { \ .id = (_id), \ .type = RK_CRU_COMPOSITE, \ @@ -226,6 +228,7 @@ int rk_cru_composite_set_parent(struct r .u.composite.div_mask = (_div_mask), \ .u.composite.gate_reg = (_gate_reg), \ .u.composite.gate_mask = (_gate_mask), \ + .u.composite.frac_reg = (_frac_reg), \ .u.composite.flags = (_flags), \ .enable = rk_cru_composite_enable, \ .get_rate = rk_cru_composite_get_rate, \ @@ -234,14 +237,20 @@ int rk_cru_composite_set_parent(struct r .set_parent = rk_cru_composite_set_parent, \ } +#define RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _flags) \ + _RK_COMPOSITE_INIT(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, 0, _flags) + #define RK_COMPOSITE_NOMUX(_id, _name, _parent, _div_reg, _div_mask, _gate_reg, _gate_mask, _flags) \ - RK_COMPOSITE(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, _gate_reg, _gate_mask, _flags) + _RK_COMPOSITE_INIT(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, _gate_reg, _gate_mask, 0, _flags) #define RK_COMPOSITE_NOGATE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _flags) \ - RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, 0, 0, _flags) + _RK_COMPOSITE_INIT(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, 0, 0, 0, _flags) + +#define RK_COMPOSITE_FRAC(_id, _name, _parent, _frac_reg, _flags) \ + _RK_COMPOSITE_INIT(_id, _name, (const char *[]){ _parent }, 0, 0, 0, 0, 0, _frac_reg, (_flags) | RK_COMPOSITE_FRACDIV) #define RK_DIV(_id, _name, _parent, _div_reg, _div_mask, _flags) \ - RK_COMPOSITE(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, 0, 0, _flags) + _RK_COMPOSITE_INIT(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, 0, 0, 0, _flags) /* Gate clocks */ Index: src/sys/arch/arm/rockchip/rk_cru_composite.c diff -u src/sys/arch/arm/rockchip/rk_cru_composite.c:1.4 src/sys/arch/arm/rockchip/rk_cru_composite.c:1.5 --- src/sys/arch/arm/rockchip/rk_cru_composite.c:1.4 Sun Nov 10 11:43:04 2019 +++ src/sys/arch/arm/rockchip/rk_cru_composite.c Sat Nov 16 13:23:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: rk_cru_composite.c,v 1.4 2019/11/10 11:43:04 jmcneill Exp $ */ +/* $NetBSD: rk_cru_composite.c,v 1.5 2019/11/16 13:23:13 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rk_cru_composite.c,v 1.4 2019/11/10 11:43:04 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rk_cru_composite.c,v 1.5 2019/11/16 13:23:13 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -75,10 +75,55 @@ rk_cru_composite_get_rate(struct rk_cru_ if (prate == 0) return 0; - const uint32_t val = CRU_READ(sc, composite->muxdiv_reg); - const u_int div = __SHIFTOUT(val, composite->div_mask) + 1; + if (composite->flags & RK_COMPOSITE_FRACDIV) { + const uint32_t val = CRU_READ(sc, composite->frac_reg); + const u_int num = (val >> 16) & 0xffff; + const u_int den = val & 0xffff; - return prate / div; + return (u_int)((uint64_t)prate * num / den); + } else { + const uint32_t val = CRU_READ(sc, composite->muxdiv_reg); + const u_int div = __SHIFTOUT(val, composite->div_mask) + 1; + + return prate / div; + } +} + +static u_int +rk_cru_composite_get_frac_div(u_int n, u_int d) +{ + u_int tmp; + + while (d > 0) { + tmp = d; + d = n % d; + n = tmp; + } + + return n; +} + +static int +rk_cru_composite_set_rate_frac(struct rk_cru_softc *sc, + struct rk_cru_clk *clk, u_int rate) +{ + struct rk_cru_composite *composite = &clk->u.composite; + struct clk *clk_parent; + + clk_parent = clk_get_parent(&clk->base); + if (clk_parent == NULL) + return ENXIO; + + const u_int prate = clk_get_rate(clk_parent); + const u_int v = rk_cru_composite_get_frac_div(prate, rate); + const u_int num = (prate / v) & 0xffff; + const u_int den = (rate / v) & 0xffff; + if (prate / num * den != rate) + return EINVAL; + + CRU_WRITE(sc, composite->frac_reg, (den << 16) | num); + + return 0; } int @@ -99,6 +144,10 @@ rk_cru_composite_set_rate(struct rk_cru_ return clk_set_rate(clk_parent, rate); } + if (composite->flags & RK_COMPOSITE_FRACDIV) { + return rk_cru_composite_set_rate_frac(sc, clk, rate); + } + best_div = 0; best_mux = 0; best_diff = INT_MAX;