git: d03fd8ede2c4 - main - rockchip: add audio-related clocks to the CRU driver

Oleksandr Tymoshenko gonzo at FreeBSD.org
Mon Jan 4 01:07:05 UTC 2021


The branch main has been updated by gonzo:

URL: https://cgit.FreeBSD.org/src/commit/?id=d03fd8ede2c493d0c5a74b625a93a48e018515e1

commit d03fd8ede2c493d0c5a74b625a93a48e018515e1
Author:     Oleksandr Tymoshenko <gonzo at FreeBSD.org>
AuthorDate: 2020-12-30 00:25:52 +0000
Commit:     Oleksandr Tymoshenko <gonzo at FreeBSD.org>
CommitDate: 2021-01-04 00:50:42 +0000

    rockchip: add audio-related clocks to the CRU driver
    
    - Add I2S and CODEC clocks to CRU driver
    - Add support for gate selection to frac clock
    - Add setfreq support to mux clock
    
    Reviewed by:    manu
    Differential Revision:  https://reviews.freebsd.org/D27831
---
 sys/arm64/rockchip/clk/rk3328_cru.c   | 275 ++++++++++++++++++++++++++++++++++
 sys/arm64/rockchip/clk/rk3399_cru.c   |   6 +-
 sys/arm64/rockchip/clk/rk_clk_fract.c |  35 +++++
 sys/arm64/rockchip/clk/rk_clk_fract.h |   4 +
 sys/arm64/rockchip/clk/rk_clk_mux.c   |  61 ++++++++
 sys/arm64/rockchip/clk/rk_clk_mux.h   |   1 +
 6 files changed, 379 insertions(+), 3 deletions(-)

diff --git a/sys/arm64/rockchip/clk/rk3328_cru.c b/sys/arm64/rockchip/clk/rk3328_cru.c
index 69ad2dac873c..e110564f773d 100644
--- a/sys/arm64/rockchip/clk/rk3328_cru.c
+++ b/sys/arm64/rockchip/clk/rk3328_cru.c
@@ -56,6 +56,11 @@ __FBSDID("$FreeBSD$");
 
 /* GATES */
 
+#define	SCLK_I2S0		41
+#define	SCLK_I2S1		42
+#define	SCLK_I2S2		43
+#define	SCLK_I2S1_OUT		44
+#define	SCLK_I2S2_OUT		45
 #define	SCLK_MAC2PHY_RXTX	83
 #define	SCLK_MAC2PHY_SRC	84
 #define	SCLK_MAC2PHY_REF	85
@@ -90,6 +95,10 @@ __FBSDID("$FreeBSD$");
 #define	PCLK_USB3PHY_OTG	224
 #define	PCLK_USB3PHY_PIPE	225
 #define	PCLK_USB3_GRF		226
+#define	PCLK_ACODECPHY		235
+#define	HCLK_I2S0_8CH		311
+#define	HCLK_I2S1_8CH		312
+#define	HCLK_I2S2_2CH		313
 #define	HCLK_SDMMC		317
 #define	HCLK_SDIO		318
 #define	HCLK_EMMC		319
@@ -102,6 +111,11 @@ static struct rk_cru_gate rk3328_gates[] = {
 	CRU_GATE(0, "gpll_core", "gpll", 0x200, 2)
 	CRU_GATE(0, "npll_core", "npll", 0x200, 12)
 
+	/* CRU_CLKGATE_CON1 */
+	CRU_GATE(SCLK_I2S0, "clk_i2s0", "clk_i2s0_mux", 0x204, 3)
+	CRU_GATE(SCLK_I2S1, "clk_i2s1", "clk_i2s1_mux", 0x204, 6)
+	CRU_GATE(SCLK_I2S1, "clk_i2s2", "clk_i2s2_mux", 0x204, 10)
+
 	/* CRU_CLKGATE_CON4 */
 	CRU_GATE(0, "gpll_peri", "gpll", 0x210, 0)
 	CRU_GATE(0, "cpll_peri", "cpll", 0x210, 1)
@@ -123,6 +137,9 @@ static struct rk_cru_gate rk3328_gates[] = {
 	CRU_GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre", 0x228, 0)
 
 	/* CRU_CLKGATE_CON15*/
+	CRU_GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0x23C, 3)
+	CRU_GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_bus_pre", 0x23C, 4)
+	CRU_GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0x23C, 5)
 	CRU_GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0x23C, 10)
 
 	/* CRU_CLKGATE_CON16 */
@@ -138,6 +155,7 @@ static struct rk_cru_gate rk3328_gates[] = {
 
 	/* CRU_CLKGATE_CON17 */
 	CRU_GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", 0x244, 2)
+	CRU_GATE(PCLK_ACODECPHY, "pclk_acodecphy", "pclk_phy_pre", 0x244, 5)
 
 	/* CRU_CLKGATE_CON19 */
 	CRU_GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0x24C, 0)
@@ -1115,6 +1133,215 @@ static struct rk_clk_composite_def ref_usb3otg_src = {
 	.flags = RK_CLK_COMPOSITE_HAVE_GATE,
 };
 
+/* I2S0 */
+static const char *i2s0_div_parents[] = { "cpll", "gpll" };
+static struct rk_clk_composite_def i2s0_div = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s0_div",
+		.parent_names = i2s0_div_parents,
+		.parent_cnt = nitems(i2s0_div_parents),
+	},
+	/* CRU_CLKSEL_CON6 */
+	.muxdiv_offset = 0x118,
+
+	.mux_shift = 15,
+	.mux_width = 1,
+
+	.div_shift = 0,
+	.div_width = 7,
+
+	/* CRU_CLKGATE_CON1 */
+	.gate_offset = 0x204,
+	.gate_shift = 1,
+
+	.flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+static const char *i2s0_frac_parents[] = { "clk_i2s0_div" };
+static struct rk_clk_fract_def i2s0_frac = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s0_frac",
+		.parent_names = i2s0_frac_parents,
+		.parent_cnt = nitems(i2s0_frac_parents),
+	},
+	/* CRU_CLKSEL_CON7 */
+	.offset = 0x11c,
+
+	/* CRU_CLKGATE_CON1 */
+	.gate_offset = 0x204,
+	.gate_shift = 2,
+
+	.flags = RK_CLK_FRACT_HAVE_GATE,
+};
+
+static const char *i2s0_mux_parents[] = { "clk_i2s0_div", "clk_i2s0_frac", "xin12m", "xin12m" };
+static struct rk_clk_mux_def i2s0_mux = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s0_mux",
+		.parent_names = i2s0_mux_parents,
+		.parent_cnt = nitems(i2s0_mux_parents),
+	},
+	.offset = 0x118,
+
+	.shift = 8,
+	.width = 2,
+
+	.mux_flags = RK_CLK_MUX_REPARENT,
+};
+
+/* I2S1 */
+static const char *i2s1_div_parents[] = { "cpll", "gpll" };
+static struct rk_clk_composite_def i2s1_div = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s1_div",
+		.parent_names = i2s1_div_parents,
+		.parent_cnt = nitems(i2s1_div_parents),
+	},
+	/* CRU_CLKSEL_CON8 */
+	.muxdiv_offset = 0x120,
+
+	.mux_shift = 15,
+	.mux_width = 1,
+
+	.div_shift = 0,
+	.div_width = 7,
+
+	/* CRU_CLKGATE_CON1 */
+	.gate_offset = 0x204,
+	.gate_shift = 4,
+
+	.flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+static const char *i2s1_frac_parents[] = { "clk_i2s1_div" };
+static struct rk_clk_fract_def i2s1_frac = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s1_frac",
+		.parent_names = i2s1_frac_parents,
+		.parent_cnt = nitems(i2s1_frac_parents),
+	},
+	/* CRU_CLKSEL_CON9 */
+	.offset = 0x124,
+
+	/* CRU_CLKGATE_CON1 */
+	.gate_offset = 0x204,
+	.gate_shift = 5,
+
+	.flags = RK_CLK_FRACT_HAVE_GATE,
+};
+
+static const char *i2s1_mux_parents[] = { "clk_i2s1_div", "clk_i2s1_frac", "clkin_i2s1", "xin12m" };
+static struct rk_clk_mux_def i2s1_mux = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s1_mux",
+		.parent_names = i2s1_mux_parents,
+		.parent_cnt = nitems(i2s1_mux_parents),
+	},
+	.offset = 0x120,
+
+	.shift = 8,
+	.width = 2,
+	.mux_flags = RK_CLK_MUX_REPARENT,
+};
+
+static struct clk_fixed_def clkin_i2s1 = {
+	.clkdef = {
+		.id = 0,
+		.name = "clkin_i2s1",
+		.parent_names = NULL,
+		.parent_cnt = 0
+	},
+
+	.freq = 0,
+};
+
+/* I2S2 */
+static const char *i2s2_div_parents[] = { "cpll", "gpll" };
+static struct rk_clk_composite_def i2s2_div = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s2_div",
+		.parent_names = i2s2_div_parents,
+		.parent_cnt = nitems(i2s2_div_parents),
+	},
+	/* CRU_CLKSEL_CON10 */
+	.muxdiv_offset = 0x128,
+
+	.mux_shift = 15,
+	.mux_width = 1,
+
+	.div_shift = 0,
+	.div_width = 7,
+
+	/* CRU_CLKGATE_CON1 */
+	.gate_offset = 0x204,
+	.gate_shift = 8,
+
+	.flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+static const char *i2s2_frac_parents[] = { "clk_i2s2_div" };
+static struct rk_clk_fract_def i2s2_frac = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s2_frac",
+		.parent_names = i2s2_frac_parents,
+		.parent_cnt = nitems(i2s2_frac_parents),
+	},
+	/* CRU_CLKSEL_CON11 */
+	.offset = 0x12c,
+
+	/* CRU_CLKGATE_CON1 */
+	.gate_offset = 0x204,
+	.gate_shift = 9,
+
+	.flags = RK_CLK_FRACT_HAVE_GATE,
+};
+
+static const char *i2s2_mux_parents[] = { "clk_i2s2_div", "clk_i2s2_frac", "clkin_i2s2", "xin12m" };
+static struct rk_clk_mux_def i2s2_mux = {
+	.clkdef = {
+		.id = 0,
+		.name = "clk_i2s2_mux",
+		.parent_names = i2s2_mux_parents,
+		.parent_cnt = nitems(i2s2_mux_parents),
+	},
+	.offset = 0x128,
+
+	.shift = 8,
+	.width = 2,
+
+	.mux_flags = RK_CLK_MUX_REPARENT,
+};
+
+static struct clk_fixed_def clkin_i2s2 = {
+	.clkdef = {
+		.id = 0,
+		.name = "clkin_i2s2",
+		.parent_names = NULL,
+		.parent_cnt = 0
+	},
+
+	.freq = 0,
+};
+
+static struct clk_fixed_def xin12m = {
+	.clkdef = {
+		.id = 0,
+		.name = "xin12m",
+		.parent_names = NULL,
+		.parent_cnt = 0
+	},
+
+	.freq = 12000000,
+};
+
 static const char *mac2io_src_parents[] = { "cpll", "gpll" };
 
 static struct rk_clk_composite_def mac2io_src = {
@@ -1417,6 +1644,54 @@ static struct rk_clk rk3328_clks[] = {
 		.type = RK_CLK_COMPOSITE,
 		.clk.composite = &usb3otg_suspend
 	},
+	{
+		.type = RK_CLK_COMPOSITE,
+		.clk.composite = &i2s0_div
+	},
+	{
+		.type = RK_CLK_FRACT,
+		.clk.fract = &i2s0_frac
+	},
+	{
+		.type = RK_CLK_MUX,
+		.clk.mux = &i2s0_mux
+	},
+	{
+		.type = RK_CLK_COMPOSITE,
+		.clk.composite = &i2s1_div
+	},
+	{
+		.type = RK_CLK_FRACT,
+		.clk.fract = &i2s1_frac
+	},
+	{
+		.type = RK_CLK_MUX,
+		.clk.mux = &i2s1_mux
+	},
+	{
+		.type = RK_CLK_FIXED,
+		.clk.fixed = &clkin_i2s1
+	},
+	{
+		.type = RK_CLK_COMPOSITE,
+		.clk.composite = &i2s2_div
+	},
+	{
+		.type = RK_CLK_FRACT,
+		.clk.fract = &i2s2_frac
+	},
+	{
+		.type = RK_CLK_MUX,
+		.clk.mux = &i2s2_mux
+	},
+	{
+		.type = RK_CLK_FIXED,
+		.clk.fixed = &clkin_i2s2
+	},
+	{
+		.type = RK_CLK_FIXED,
+		.clk.fixed = &xin12m
+	},
 	{
 		.type = RK_CLK_COMPOSITE,
 		.clk.composite = &mac2io_src
diff --git a/sys/arm64/rockchip/clk/rk3399_cru.c b/sys/arm64/rockchip/clk/rk3399_cru.c
index 77686ecb66b8..595085862e13 100644
--- a/sys/arm64/rockchip/clk/rk3399_cru.c
+++ b/sys/arm64/rockchip/clk/rk3399_cru.c
@@ -964,19 +964,19 @@ static struct rk_clk rk3399_clks[] = {
 	    27, 0, 10,	15, 1),
 
 	/* CRU_CLKSEL_CON28 */
-	MUX(0, "clk_i2s0_mux", i2s0_p, 0,
+	MUX(0, "clk_i2s0_mux", i2s0_p, RK_CLK_MUX_REPARENT,
 	    28, 8, 2),
 	COMP(0, "clk_i2s0_div_c", pll_src_cpll_gpll_p, 0,
 	    28, 0, 7,	7, 1),
 
 	/* CRU_CLKSEL_CON29 */
-	MUX(0, "clk_i2s1_mux", i2s1_p, 0,
+	MUX(0, "clk_i2s1_mux", i2s1_p, RK_CLK_MUX_REPARENT,
 	    29,		8, 2),
 	COMP(0, "clk_i2s1_div_c", pll_src_cpll_gpll_p, 0,
 	    29, 0, 7,	7, 1),
 
 	/* CRU_CLKSEL_CON30 */
-	MUX(0, "clk_i2s2_mux", i2s2_p, 0,
+	MUX(0, "clk_i2s2_mux", i2s2_p, RK_CLK_MUX_REPARENT,
 	    30,		8, 2),
 	COMP(0, "clk_i2s2_div_c", pll_src_cpll_gpll_p, 0,
 	    30, 0, 7,	7, 1),
diff --git a/sys/arm64/rockchip/clk/rk_clk_fract.c b/sys/arm64/rockchip/clk/rk_clk_fract.c
index 9bb4e169fb97..afdf56cfade7 100644
--- a/sys/arm64/rockchip/clk/rk_clk_fract.c
+++ b/sys/arm64/rockchip/clk/rk_clk_fract.c
@@ -49,21 +49,27 @@ __FBSDID("$FreeBSD$");
 #define	DEVICE_UNLOCK(_clk)						\
 	CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
 
+#define	RK_CLK_FRACT_MASK_SHIFT	16
+
 static int rk_clk_fract_init(struct clknode *clk, device_t dev);
 static int rk_clk_fract_recalc(struct clknode *clk, uint64_t *req);
 static int rk_clk_fract_set_freq(struct clknode *clknode, uint64_t fin,
     uint64_t *fout, int flag, int *stop);
+static int rk_clk_fract_set_gate(struct clknode *clk, bool enable);
 
 struct rk_clk_fract_sc {
 	uint32_t	flags;
 	uint32_t	offset;
 	uint32_t	numerator;
 	uint32_t	denominator;
+	uint32_t	gate_offset;
+	uint32_t	gate_shift;
 };
 
 static clknode_method_t rk_clk_fract_methods[] = {
 	/* Device interface */
 	CLKNODEMETHOD(clknode_init,		rk_clk_fract_init),
+	CLKNODEMETHOD(clknode_set_gate,		rk_clk_fract_set_gate),
 	CLKNODEMETHOD(clknode_recalc_freq,	rk_clk_fract_recalc),
 	CLKNODEMETHOD(clknode_set_freq,		rk_clk_fract_set_freq),
 	CLKNODEMETHOD_END
@@ -149,6 +155,33 @@ rk_clk_fract_init(struct clknode *clk, device_t dev)
 	return(0);
 }
 
+static int
+rk_clk_fract_set_gate(struct clknode *clk, bool enable)
+{
+	struct rk_clk_fract_sc *sc;
+	uint32_t val = 0;
+
+	sc = clknode_get_softc(clk);
+
+	if ((sc->flags & RK_CLK_FRACT_HAVE_GATE) == 0)
+		return (0);
+
+	RD4(clk, sc->gate_offset, &val);
+
+	val = 0;
+	if (!enable)
+		val |= 1 << sc->gate_shift;
+	val |= (1 << sc->gate_shift) << RK_CLK_FRACT_MASK_SHIFT;
+	DEVICE_LOCK(clk);
+	WR4(clk, sc->gate_offset, val);
+	DEVICE_UNLOCK(clk);
+
+	return (0);
+}
+
+static int
+rk_clk_fract_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop);
 static int
 rk_clk_fract_recalc(struct clknode *clk, uint64_t *freq)
 {
@@ -240,6 +273,8 @@ rk_clk_fract_register(struct clkdom *clkdom, struct rk_clk_fract_def *clkdef)
 	sc = clknode_get_softc(clk);
 	sc->flags = clkdef->flags;
 	sc->offset = clkdef->offset;
+	sc->gate_offset = clkdef->gate_offset;
+	sc->gate_shift = clkdef->gate_shift;
 
 	clknode_register(clkdom, clk);
 	return (0);
diff --git a/sys/arm64/rockchip/clk/rk_clk_fract.h b/sys/arm64/rockchip/clk/rk_clk_fract.h
index 2fe8f47586e5..03fab3fd2884 100644
--- a/sys/arm64/rockchip/clk/rk_clk_fract.h
+++ b/sys/arm64/rockchip/clk/rk_clk_fract.h
@@ -35,9 +35,13 @@
 struct rk_clk_fract_def {
 	struct clknode_init_def clkdef;
 	uint32_t		offset;
+	uint32_t		gate_offset;
+	uint32_t		gate_shift;
 	uint32_t		flags;
 };
 
+#define	RK_CLK_FRACT_HAVE_GATE	0x0001
+
 int rk_clk_fract_register(struct clkdom *clkdom,
     struct rk_clk_fract_def *clkdef);
 
diff --git a/sys/arm64/rockchip/clk/rk_clk_mux.c b/sys/arm64/rockchip/clk/rk_clk_mux.c
index 94d31d34c47b..2280051b5a0c 100644
--- a/sys/arm64/rockchip/clk/rk_clk_mux.c
+++ b/sys/arm64/rockchip/clk/rk_clk_mux.c
@@ -55,8 +55,17 @@ __FBSDID("$FreeBSD$");
 #define	DEVICE_UNLOCK(_clk)						\
 	CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
 
+#if 0
+#define	dprintf(format, arg...)						\
+	printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
+#else
+#define	dprintf(format, arg...)
+#endif
+
 static int rk_clk_mux_init(struct clknode *clk, device_t dev);
 static int rk_clk_mux_set_mux(struct clknode *clk, int idx);
+static int rk_clk_mux_set_freq(struct clknode *clk, uint64_t fparent,
+    uint64_t *fout, int flags, int *stop);
 
 struct rk_clk_mux_sc {
 	uint32_t	offset;
@@ -69,6 +78,7 @@ static clknode_method_t rk_clk_mux_methods[] = {
 	/* Device interface */
 	CLKNODEMETHOD(clknode_init, 	rk_clk_mux_init),
 	CLKNODEMETHOD(clknode_set_mux, 	rk_clk_mux_set_mux),
+	CLKNODEMETHOD(clknode_set_freq,	rk_clk_mux_set_freq),
 	CLKNODEMETHOD_END
 };
 DEFINE_CLASS_1(rk_clk_mux, rk_clk_mux_class, rk_clk_mux_methods,
@@ -116,6 +126,57 @@ rk_clk_mux_set_mux(struct clknode *clk, int idx)
 	return(0);
 }
 
+static int
+rk_clk_mux_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct rk_clk_mux_sc *sc;
+	struct clknode *p_clk, *p_best_clk;
+	const char **p_names;
+	int p_idx, best_parent;
+	int rv;
+
+	sc = clknode_get_softc(clk);
+
+	if ((sc->mux_flags & RK_CLK_MUX_REPARENT) == 0)
+		return (0);
+
+	dprintf("Finding best parent for target freq of %ju\n", *fout);
+	p_names = clknode_get_parent_names(clk);
+	for (p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) {
+		p_clk = clknode_find_by_name(p_names[p_idx]);
+		dprintf("Testing with parent %s (%d)\n",
+		    clknode_get_name(p_clk), p_idx);
+
+		rv = clknode_set_freq(p_clk, *fout, flags | CLK_SET_DRYRUN, 0);
+		dprintf("Testing with parent %s (%d) rv=%d\n",
+		    clknode_get_name(p_clk), p_idx, rv);
+		if (rv == 0) {
+			best_parent = p_idx;
+			p_best_clk = p_clk;
+			*stop = 1;
+		}
+	}
+
+	if (!*stop)
+		return (0);
+
+	if ((flags & CLK_SET_DRYRUN) != 0)
+		return (0);
+
+	p_idx = clknode_get_parent_idx(clk);
+	if (p_idx != best_parent) {
+		dprintf("Switching parent index from %d to %d\n", p_idx,
+		    best_parent);
+		clknode_set_parent_by_idx(clk, best_parent);
+	}
+
+	clknode_set_freq(p_best_clk, *fout, flags, 0);
+	clknode_get_freq(p_best_clk, fout);
+
+	return (0);
+}
+
 int
 rk_clk_mux_register(struct clkdom *clkdom, struct rk_clk_mux_def *clkdef)
 {
diff --git a/sys/arm64/rockchip/clk/rk_clk_mux.h b/sys/arm64/rockchip/clk/rk_clk_mux.h
index f44443790b18..7825f8892ac3 100644
--- a/sys/arm64/rockchip/clk/rk_clk_mux.h
+++ b/sys/arm64/rockchip/clk/rk_clk_mux.h
@@ -41,6 +41,7 @@ struct rk_clk_mux_def {
 };
 
 #define	RK_CLK_MUX_MASK		0xFFFF0000
+#define	RK_CLK_MUX_REPARENT	(1 << 0)
 
 int rk_clk_mux_register(struct clkdom *clkdom, struct rk_clk_mux_def *clkdef);
 


More information about the dev-commits-src-all mailing list