Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/rockchip Add support for I2S clocks.



details:   https://anonhg.NetBSD.org/src/rev/0fb1a18d0f18
branches:  trunk
changeset: 846432:0fb1a18d0f18
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Nov 16 13:23:13 2019 +0000

description:
Add support for I2S clocks.

diffstat:

 sys/arch/arm/rockchip/rk3399_cru.c       |  90 ++++++++++++++++++++++++++++++-
 sys/arch/arm/rockchip/rk_cru.h           |  19 ++++-
 sys/arch/arm/rockchip/rk_cru_composite.c |  59 +++++++++++++++++++-
 3 files changed, 155 insertions(+), 13 deletions(-)

diffs (283 lines):

diff -r 457cadc12014 -r 0fb1a18d0f18 sys/arch/arm/rockchip/rk3399_cru.c
--- a/sys/arch/arm/rockchip/rk3399_cru.c        Sat Nov 16 13:10:07 2019 +0000
+++ b/sys/arch/arm/rockchip/rk3399_cru.c        Sat Nov 16 13:23:13 2019 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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_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 @@
                     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 @@
        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
diff -r 457cadc12014 -r 0fb1a18d0f18 sys/arch/arm/rockchip/rk_cru.h
--- a/sys/arch/arm/rockchip/rk_cru.h    Sat Nov 16 13:10:07 2019 +0000
+++ b/sys/arch/arm/rockchip/rk_cru.h    Sat Nov 16 13:23:13 2019 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -200,11 +200,13 @@
        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 @@
 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 @@
                .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 @@
                .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 */
 
diff -r 457cadc12014 -r 0fb1a18d0f18 sys/arch/arm/rockchip/rk_cru_composite.c
--- a/sys/arch/arm/rockchip/rk_cru_composite.c  Sat Nov 16 13:10:07 2019 +0000
+++ b/sys/arch/arm/rockchip/rk_cru_composite.c  Sat Nov 16 13:23:13 2019 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 @@
        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 (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 prate / div;
+       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 @@
                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;



Home | Main Index | Thread Index | Old Index