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/2ec3b2992605
branches: trunk
changeset: 465309:2ec3b2992605
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 fc3c0ca2d33d -r 2ec3b2992605 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 fc3c0ca2d33d -r 2ec3b2992605 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 fc3c0ca2d33d -r 2ec3b2992605 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