Module Name:    src
Committed By:   jmcneill
Date:           Sat Sep  1 19:35:53 UTC 2018

Modified Files:
        src/sys/arch/arm/rockchip: rk3399_cru.c rk_cru.h rk_cru_arm.c

Log Message:
Add support for RK3399 CPU clocks.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/rockchip/rk3399_cru.c
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/rockchip/rk_cru.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/rockchip/rk_cru_arm.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.2 src/sys/arch/arm/rockchip/rk3399_cru.c:1.3
--- src/sys/arch/arm/rockchip/rk3399_cru.c:1.2	Sun Aug 12 19:28:41 2018
+++ src/sys/arch/arm/rockchip/rk3399_cru.c	Sat Sep  1 19:35:53 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk3399_cru.c,v 1.2 2018/08/12 19:28:41 jmcneill Exp $ */
+/* $NetBSD: rk3399_cru.c,v 1.3 2018/09/01 19:35:53 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.2 2018/08/12 19:28:41 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.3 2018/09/01 19:35:53 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -139,6 +139,67 @@ static const struct rk_cru_pll_rate pll_
 static const struct rk_cru_pll_rate pll_norates[] = {
 };
 
+#define	RK3399_ACLKM_MASK	__BITS(12,8)
+#define	RK3399_ATCLK_MASK	__BITS(4,0)
+#define	RK3399_PDBG_MASK	__BITS(12,8)
+
+#define	RK3399_CPUL_RATE(_rate, _aclkm, _atclk, _pdbg)			\
+	RK_CPU_RATE(_rate,						\
+		    CLKSEL_CON(0), RK3399_ACLKM_MASK,			\
+		    __SHIFTIN((_aclkm), RK3399_ACLKM_MASK),		\
+		    CLKSEL_CON(1), RK3399_ATCLK_MASK|RK3399_PDBG_MASK,	\
+		    __SHIFTIN((_atclk), RK3399_ATCLK_MASK)|__SHIFTIN((_pdbg), RK3399_PDBG_MASK))
+
+#define	RK3399_CPUB_RATE(_rate, _aclkm, _atclk, _pdbg)			\
+	RK_CPU_RATE(_rate,						\
+		    CLKSEL_CON(2), RK3399_ACLKM_MASK,			\
+		    __SHIFTIN((_aclkm), RK3399_ACLKM_MASK),		\
+		    CLKSEL_CON(3), RK3399_ATCLK_MASK|RK3399_PDBG_MASK,	\
+		    __SHIFTIN((_atclk), RK3399_ATCLK_MASK)|__SHIFTIN((_pdbg), RK3399_PDBG_MASK))
+
+static const struct rk_cru_cpu_rate armclkl_rates[] = {
+        RK3399_CPUL_RATE(1800000000, 1, 8, 8),
+        RK3399_CPUL_RATE(1704000000, 1, 8, 8),
+        RK3399_CPUL_RATE(1608000000, 1, 7, 7),
+        RK3399_CPUL_RATE(1512000000, 1, 7, 7),
+        RK3399_CPUL_RATE(1488000000, 1, 6, 6),
+        RK3399_CPUL_RATE(1416000000, 1, 6, 6),
+        RK3399_CPUL_RATE(1200000000, 1, 5, 5),
+        RK3399_CPUL_RATE(1008000000, 1, 4, 4),
+        RK3399_CPUL_RATE( 816000000, 1, 3, 3),
+        RK3399_CPUL_RATE( 696000000, 1, 3, 3),
+        RK3399_CPUL_RATE( 600000000, 1, 2, 2),
+        RK3399_CPUL_RATE( 408000000, 1, 1, 1),
+        RK3399_CPUL_RATE( 312000000, 1, 1, 1),
+        RK3399_CPUL_RATE( 216000000, 1, 1, 1),
+        RK3399_CPUL_RATE(  96000000, 1, 1, 1),
+};
+
+static const struct rk_cru_cpu_rate armclkb_rates[] = {
+        RK3399_CPUB_RATE(2208000000, 1, 11, 11),
+        RK3399_CPUB_RATE(2184000000, 1, 11, 11),
+        RK3399_CPUB_RATE(2088000000, 1, 10, 10),
+        RK3399_CPUB_RATE(2040000000, 1, 10, 10),
+        RK3399_CPUB_RATE(2016000000, 1, 9, 9),
+        RK3399_CPUB_RATE(1992000000, 1, 9, 9),
+        RK3399_CPUB_RATE(1896000000, 1, 9, 9),
+        RK3399_CPUB_RATE(1800000000, 1, 8, 8),
+        RK3399_CPUB_RATE(1704000000, 1, 8, 8),
+        RK3399_CPUB_RATE(1608000000, 1, 7, 7),
+        RK3399_CPUB_RATE(1512000000, 1, 7, 7),
+        RK3399_CPUB_RATE(1488000000, 1, 6, 6),
+        RK3399_CPUB_RATE(1416000000, 1, 6, 6),
+        RK3399_CPUB_RATE(1200000000, 1, 5, 5),
+        RK3399_CPUB_RATE(1008000000, 1, 5, 5),
+        RK3399_CPUB_RATE( 816000000, 1, 4, 4),
+        RK3399_CPUB_RATE( 696000000, 1, 3, 3),
+        RK3399_CPUB_RATE( 600000000, 1, 3, 3),
+        RK3399_CPUB_RATE( 408000000, 1, 2, 2),
+        RK3399_CPUB_RATE( 312000000, 1, 1, 1),
+        RK3399_CPUB_RATE( 216000000, 1, 1, 1),
+        RK3399_CPUB_RATE(  96000000, 1, 1, 1),
+};
+
 #define	PLL_CON0	0x00
 #define	 PLL_FBDIV	__BITS(11,0)
 
@@ -229,14 +290,13 @@ rk3399_cru_pll_set_rate(struct rk_cru_so
 	CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
 
 	CRU_WRITE(sc, pll->con_base + PLL_CON0,
-	    __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) |
-	    PLL_WRITE_MASK);
+	    __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) | (PLL_FBDIV << 16));
 
 	CRU_WRITE(sc, pll->con_base + PLL_CON1,
 	    __SHIFTIN(pll_rate->postdiv2, PLL_POSTDIV2) |
 	    __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) |
 	    __SHIFTIN(pll_rate->refdiv, PLL_REFDIV) |
-	    PLL_WRITE_MASK);
+	    ((PLL_POSTDIV2 | PLL_POSTDIV1 | PLL_REFDIV) << 16));
 
 	val = CRU_READ(sc, pll->con_base + PLL_CON2);
 	val &= ~PLL_FRACDIV;
@@ -246,11 +306,6 @@ rk3399_cru_pll_set_rate(struct rk_cru_so
 	val = __SHIFTIN(pll_rate->dsmpd, PLL_DSMPD) | (PLL_DSMPD << 16);
 	CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
 
-	/* Set PLL work mode to normal */
-	const uint32_t write_mask = pll->mode_mask << 16;
-	const uint32_t write_val = pll->mode_mask;
-	CRU_WRITE(sc, pll->mode_reg, write_mask | write_val);
-
 	for (retry = 1000; retry > 0; retry--) {
 		if (CRU_READ(sc, pll->con_base + PLL_CON2) & pll->lock_mask)
 			break;
@@ -261,6 +316,7 @@ rk3399_cru_pll_set_rate(struct rk_cru_so
 		device_printf(sc->sc_dev, "WARNING: %s failed to lock\n",
 		    clk->base.name);
 
+	/* Set PLL work mode to normal */
 	val = __SHIFTIN(PLL_WORK_MODE_NORMAL, PLL_WORK_MODE) | (PLL_WORK_MODE << 16);
 	CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
 
@@ -287,6 +343,8 @@ rk3399_cru_pll_set_rate(struct rk_cru_so
         }
 
 static const char * pll_parents[] = { "xin24m", "xin32k" };
+static const char * armclkl_parents[] = { "clk_core_l_lpll_src", "clk_core_l_bpll_src", "clk_core_l_dpll_src", "clk_core_l_gpll_src" };
+static const char * armclkb_parents[] = { "clk_core_b_lpll_src", "clk_core_b_bpll_src", "clk_core_b_dpll_src", "clk_core_b_gpll_src" };
 static const char * mux_pll_src_cpll_gpll_parents[] = { "cpll", "gpll" };
 static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" };
 static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" };
@@ -346,6 +404,28 @@ static struct rk_cru_clk rk3399_cru_clks
 		   __BIT(31),		/* lock_mask */
 		   pll_rates),
 
+	RK_GATE(0, "clk_core_l_lpll_src", "lpll", CLKGATE_CON(0), 0),
+	RK_GATE(0, "clk_core_l_bpll_src", "bpll", CLKGATE_CON(0), 1),
+	RK_GATE(0, "clk_core_l_dpll_src", "dpll", CLKGATE_CON(0), 2),
+	RK_GATE(0, "clk_core_l_gpll_src", "gpll", CLKGATE_CON(0), 3),
+
+	RK_CPU(RK3399_ARMCLKL, "armclkl", armclkl_parents,
+	       CLKSEL_CON(0),		/* reg */
+	       __BITS(7,6), 0, 3,	/* mux_mask, mux_main, mux_alt */
+	       __BITS(4,0),		/* div_mask */
+	       armclkl_rates),
+
+	RK_GATE(0, "clk_core_b_lpll_src", "lpll", CLKGATE_CON(1), 0),
+	RK_GATE(0, "clk_core_b_bpll_src", "bpll", CLKGATE_CON(1), 1),
+	RK_GATE(0, "clk_core_b_dpll_src", "dpll", CLKGATE_CON(1), 2),
+	RK_GATE(0, "clk_core_b_gpll_src", "gpll", CLKGATE_CON(1), 3),
+
+	RK_CPU(RK3399_ARMCLKB, "armclkb", armclkb_parents,
+	       CLKSEL_CON(2),		/* reg */
+	       __BITS(7,6), 1, 3,	/* mux_mask, mux_main, mux_alt */
+	       __BITS(4,0),		/* div_mask */
+	       armclkb_rates),
+
 	/*
 	 * perilp0
 	 */

Index: src/sys/arch/arm/rockchip/rk_cru.h
diff -u src/sys/arch/arm/rockchip/rk_cru.h:1.3 src/sys/arch/arm/rockchip/rk_cru.h:1.4
--- src/sys/arch/arm/rockchip/rk_cru.h:1.3	Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk_cru.h	Sat Sep  1 19:35:53 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru.h,v 1.3 2018/08/12 16:48:05 jmcneill Exp $ */
+/* $NetBSD: rk_cru.h,v 1.4 2018/09/01 19:35:53 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -118,6 +118,19 @@ struct rk_cru_arm_rate {
 		.div = (_div),					\
 	}
 
+struct rk_cru_cpu_rate {
+	u_int		rate;
+	u_int		reg1, reg1_mask, reg1_val;
+	u_int		reg2, reg2_mask, reg2_val;
+};
+
+#define	RK_CPU_RATE(_rate, _reg1, _reg1_mask, _reg1_val, _reg2, _reg2_mask, _reg2_val)	\
+	{										\
+		.rate = (_rate),							\
+		.reg1 = (_reg1), .reg1_mask = (_reg1_mask), .reg1_val = (_reg1_val),	\
+		.reg2 = (_reg2), .reg2_mask = (_reg2_mask), .reg2_val = (_reg2_val),	\
+	}
+
 struct rk_cru_arm {
 	bus_size_t	reg;
 	uint32_t	mux_mask;
@@ -127,11 +140,13 @@ struct rk_cru_arm {
 	const char	**parents;
 	u_int		nparents;
 	const struct rk_cru_arm_rate *rates;
+	const struct rk_cru_cpu_rate *cpurates;
 	u_int		nrates;
 };
 
 u_int	rk_cru_arm_get_rate(struct rk_cru_softc *, struct rk_cru_clk *);
 int	rk_cru_arm_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int);
+int	rk_cru_arm_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int);
 const char *rk_cru_arm_get_parent(struct rk_cru_softc *, struct rk_cru_clk *);
 int	rk_cru_arm_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *);
 
@@ -156,6 +171,27 @@ int	rk_cru_arm_set_parent(struct rk_cru_
 		.set_parent = rk_cru_arm_set_parent,		\
 	}
 
+#define	RK_CPU(_id, _name, _parents, _reg, _mux_mask, _mux_main, _mux_alt, _div_mask, _cpurates) \
+	{							\
+		.id = (_id),					\
+		.type = RK_CRU_ARM,				\
+		.base.name = (_name),				\
+		.base.flags = 0,				\
+		.u.arm.parents = (_parents),			\
+		.u.arm.nparents = __arraycount(_parents),	\
+		.u.arm.reg = (_reg),				\
+		.u.arm.mux_mask = (_mux_mask),			\
+		.u.arm.mux_main = (_mux_main),			\
+		.u.arm.mux_alt = (_mux_alt),			\
+		.u.arm.div_mask = (_div_mask),			\
+		.u.arm.cpurates = (_cpurates),			\
+		.u.arm.nrates = __arraycount(_cpurates),	\
+		.get_rate = rk_cru_arm_get_rate,		\
+		.set_rate = rk_cru_arm_set_rate,		\
+		.get_parent = rk_cru_arm_get_parent,		\
+		.set_parent = rk_cru_arm_set_parent,		\
+	}
+
 /* Composite clocks */
 
 struct rk_cru_composite {

Index: src/sys/arch/arm/rockchip/rk_cru_arm.c
diff -u src/sys/arch/arm/rockchip/rk_cru_arm.c:1.1 src/sys/arch/arm/rockchip/rk_cru_arm.c:1.2
--- src/sys/arch/arm/rockchip/rk_cru_arm.c:1.1	Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru_arm.c	Sat Sep  1 19:35:53 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru_arm.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+/* $NetBSD: rk_cru_arm.c,v 1.2 2018/09/01 19:35:53 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_cru_arm.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_cru_arm.c,v 1.2 2018/09/01 19:35:53 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -60,13 +60,13 @@ rk_cru_arm_get_rate(struct rk_cru_softc 
 	return fref / div;
 }
 
-int
-rk_cru_arm_set_rate(struct rk_cru_softc *sc,
+static int
+rk_cru_arm_set_rate_rates(struct rk_cru_softc *sc,
     struct rk_cru_clk *clk, u_int rate)
 {
 	struct rk_cru_arm *arm = &clk->u.arm;
+	struct rk_cru_clk *main_parent, *alt_parent;
 	const struct rk_cru_arm_rate *arm_rate = NULL;
-	struct clk *clkp_parent;
 	int error;
 
 	KASSERT(clk->type == RK_CRU_ARM);
@@ -82,26 +82,101 @@ rk_cru_arm_set_rate(struct rk_cru_softc 
 	if (arm_rate == NULL)
 		return EINVAL;
 
-	error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]);
+	main_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_main]);
+	alt_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_alt]);
+	if (main_parent == NULL || alt_parent == NULL) {
+		device_printf(sc->sc_dev, "couldn't get clock parents\n");
+		return ENXIO;
+	}
+
+	error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_alt]);
 	if (error != 0)
 		return error;
 
-	clkp_parent = clk_get_parent(&clk->base);
-	if (clkp_parent == NULL)
-		return ENXIO;
-
 	const u_int parent_rate = arm_rate->rate / arm_rate->div;
 
-	error = clk_set_rate(clkp_parent, parent_rate);
+	error = clk_set_rate(&main_parent->base, parent_rate);
 	if (error != 0)
-		return error;
+		goto done;
 
 	const uint32_t write_mask = arm->div_mask << 16;
 	const uint32_t write_val = __SHIFTIN(arm_rate->div - 1, arm->div_mask);
 
 	CRU_WRITE(sc, arm->reg, write_mask | write_val);
 
-	return 0;
+done:
+	rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]);
+	return error;
+}
+
+static int
+rk_cru_arm_set_rate_cpurates(struct rk_cru_softc *sc,
+    struct rk_cru_clk *clk, u_int rate)
+{
+	struct rk_cru_arm *arm = &clk->u.arm;
+	struct rk_cru_clk *main_parent, *alt_parent;
+	const struct rk_cru_cpu_rate *cpu_rate = NULL;
+	uint32_t write_mask, write_val;
+	int error;
+
+	KASSERT(clk->type == RK_CRU_ARM);
+
+	if (arm->cpurates == NULL || rate == 0)
+		return EIO;
+
+	for (int i = 0; i < arm->nrates; i++)
+		if (arm->cpurates[i].rate == rate) {
+			cpu_rate = &arm->cpurates[i];
+			break;
+		}
+	if (cpu_rate == NULL)
+		return EINVAL;
+
+	main_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_main]);
+	alt_parent = rk_cru_clock_find(sc, arm->parents[arm->mux_alt]);
+	if (main_parent == NULL || alt_parent == NULL) {
+		device_printf(sc->sc_dev, "couldn't get clock parents\n");
+		return ENXIO;
+	}
+
+	error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_alt]);
+	if (error != 0)
+		return error;
+
+	error = clk_set_rate(&main_parent->base, rate);
+	if (error != 0)
+		goto done;
+
+	write_mask = cpu_rate->reg1_mask << 16;
+	write_val = cpu_rate->reg1_val;
+	CRU_WRITE(sc, cpu_rate->reg1, write_mask | write_val);
+
+	write_mask = cpu_rate->reg2_mask << 16;
+	write_val = cpu_rate->reg2_val;
+	CRU_WRITE(sc, cpu_rate->reg2, write_mask | write_val);
+
+	write_mask = arm->div_mask << 16;
+	write_val = __SHIFTIN(0, arm->div_mask);
+	CRU_WRITE(sc, arm->reg, write_mask | write_val);
+
+done:
+	rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]);
+	return error;
+}
+
+
+int
+rk_cru_arm_set_rate(struct rk_cru_softc *sc,
+    struct rk_cru_clk *clk, u_int rate)
+{
+	struct rk_cru_arm *arm = &clk->u.arm;
+
+	if (arm->rates)
+		return rk_cru_arm_set_rate_rates(sc, clk, rate);
+	else if (arm->cpurates)
+		return rk_cru_arm_set_rate_cpurates(sc, clk, rate);
+	else
+		return EIO;
 }
 
 const char *

Reply via email to