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;

Reply via email to