Module Name:    src
Committed By:   jmcneill
Date:           Fri Nov 12 22:02:08 UTC 2021

Modified Files:
        src/sys/arch/arm/rockchip: files.rockchip rk3328_cru.c rk3399_cru.c
            rk_cru.h rk_cru_composite.c rk_cru_pll.c rk_gmac.c rk_i2c.c
            rk_platform.c
        src/sys/arch/evbarm/conf: GENERIC files.generic
Added Files:
        src/sys/arch/arm/rockchip: rk3066_smp.c rk3288_cru.c rk3288_cru.h
            rk3288_iomux.c rk3288_platform.h rk3288_usb.c

Log Message:
arm: rockchip: Add support for RK3288 SoC.

The Rockchip RK3288 is a quad core Cortex-A17 SoC.


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/sys/arch/arm/rockchip/files.rockchip
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/rockchip/rk3066_smp.c \
    src/sys/arch/arm/rockchip/rk3288_cru.c \
    src/sys/arch/arm/rockchip/rk3288_cru.h \
    src/sys/arch/arm/rockchip/rk3288_iomux.c \
    src/sys/arch/arm/rockchip/rk3288_platform.h \
    src/sys/arch/arm/rockchip/rk3288_usb.c
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/rockchip/rk3328_cru.c
cvs rdiff -u -r1.22 -r1.23 src/sys/arch/arm/rockchip/rk3399_cru.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/rockchip/rk_cru.h
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/rockchip/rk_cru_composite.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/rockchip/rk_cru_pll.c
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/arm/rockchip/rk_gmac.c
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/arm/rockchip/rk_i2c.c
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/arm/rockchip/rk_platform.c
cvs rdiff -u -r1.100 -r1.101 src/sys/arch/evbarm/conf/GENERIC
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/evbarm/conf/files.generic

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/files.rockchip
diff -u src/sys/arch/arm/rockchip/files.rockchip:1.24 src/sys/arch/arm/rockchip/files.rockchip:1.25
--- src/sys/arch/arm/rockchip/files.rockchip:1.24	Sun May 17 19:57:25 2020
+++ src/sys/arch/arm/rockchip/files.rockchip	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: files.rockchip,v 1.24 2020/05/17 19:57:25 riastradh Exp $
+#	$NetBSD: files.rockchip,v 1.25 2021/11/12 22:02:08 jmcneill Exp $
 #
 # Configuration info for Rockchip family SoCs
 #
@@ -6,6 +6,8 @@
 
 file	arch/arm/rockchip/rk_platform.c		soc_rockchip
 
+file	arch/arm/rockchip/rk3066_smp.c		soc_rk3288
+
 # Clock and reset unit (CRU)
 device	rkcru: rk_cru
 file	arch/arm/rockchip/rk_cru.c		rk_cru
@@ -15,6 +17,14 @@ file	arch/arm/rockchip/rk_cru_gate.c		rk
 file	arch/arm/rockchip/rk_cru_mux.c		rk_cru
 file	arch/arm/rockchip/rk_cru_pll.c		rk_cru
 
+ifdef arm
+
+# RK3288 clock and reset unit
+attach	rkcru at fdt with rk3288_cru
+file	arch/arm/rockchip/rk3288_cru.c		rk3288_cru & soc_rk3288
+
+else
+
 # RK3328 clock and reset unit
 attach	rkcru at fdt with rk3328_cru
 file	arch/arm/rockchip/rk3328_cru.c		rk3328_cru & soc_rk3328
@@ -25,13 +35,25 @@ file	arch/arm/rockchip/rk3399_cru.c		rk3
 attach	rkcru at fdt with rk3399_pmucru
 file	arch/arm/rockchip/rk3399_pmucru.c	rk3399_pmucru & soc_rk3399
 
+endif
+
 # IOMUX control
 device	rkiomux { }
+
+ifdef arm
+
+attach	rkiomux at fdt with rk3288_iomux
+file	arch/arm/rockchip/rk3288_iomux.c	rk3288_iomux & soc_rk3288
+
+else
+
 attach	rkiomux at fdt with rk3328_iomux
 file	arch/arm/rockchip/rk3328_iomux.c	rk3328_iomux & soc_rk3328
 attach	rkiomux at fdt with rk3399_iomux
 file	arch/arm/rockchip/rk3399_iomux.c	rk3399_iomux & soc_rk3399
 
+endif
+
 # GPIO
 device	rkgpio: gpiobus
 attach	rkgpio at rkiomux with rk_gpio
@@ -54,6 +76,12 @@ device	rkusbphy
 attach	rkusbphy at rkusb with rk_usbphy
 file	arch/arm/rockchip/rk_usb.c		rk_usb | rk_usbphy
 
+device	rk3288usb { }
+attach	rk3288usb at fdt with rk3288_usb
+device	rk3288usbphy
+attach	rk3288usbphy at rk3288usb with rk3288_usbphy
+file	arch/arm/rockchip/rk3288_usb.c		rk3288_usb | rk3288_usbphy
+
 # GMAC
 attach	awge at fdt with rk_gmac
 file	arch/arm/rockchip/rk_gmac.c		rk_gmac
@@ -119,5 +147,6 @@ file	arch/arm/rockchip/rk_v1crypto.c		rk
 
 # SOC parameters
 defflag	opt_soc.h			SOC_ROCKCHIP
+defflag	opt_soc.h			SOC_RK3288: SOC_ROCKCHIP
 defflag	opt_soc.h			SOC_RK3328: SOC_ROCKCHIP
 defflag	opt_soc.h			SOC_RK3399: SOC_ROCKCHIP

Index: src/sys/arch/arm/rockchip/rk3328_cru.c
diff -u src/sys/arch/arm/rockchip/rk3328_cru.c:1.8 src/sys/arch/arm/rockchip/rk3328_cru.c:1.9
--- src/sys/arch/arm/rockchip/rk3328_cru.c:1.8	Sat May 15 08:46:00 2021
+++ src/sys/arch/arm/rockchip/rk3328_cru.c	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk3328_cru.c,v 1.8 2021/05/15 08:46:00 mrg Exp $ */
+/* $NetBSD: rk3328_cru.c,v 1.9 2021/11/12 22:02:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: rk3328_cru.c,v 1.8 2021/05/15 08:46:00 mrg Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rk3328_cru.c,v 1.9 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -501,6 +501,7 @@ rk3328_cru_attach(device_t parent, devic
 	sc->sc_clks = rk3328_cru_clks;
 	sc->sc_nclks = __arraycount(rk3328_cru_clks);
 
+	sc->sc_grf_soc_status = 0x0480;
 	sc->sc_softrst_base = SOFTRST_CON(0);
 
 	if (rk_cru_attach(sc) != 0)

Index: src/sys/arch/arm/rockchip/rk3399_cru.c
diff -u src/sys/arch/arm/rockchip/rk3399_cru.c:1.22 src/sys/arch/arm/rockchip/rk3399_cru.c:1.23
--- src/sys/arch/arm/rockchip/rk3399_cru.c:1.22	Thu May 20 01:07:24 2021
+++ src/sys/arch/arm/rockchip/rk3399_cru.c	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk3399_cru.c,v 1.22 2021/05/20 01:07:24 msaitoh Exp $ */
+/* $NetBSD: rk3399_cru.c,v 1.23 2021/11/12 22:02:08 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.22 2021/05/20 01:07:24 msaitoh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.23 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -1126,6 +1126,7 @@ rk3399_cru_attach(device_t parent, devic
 	sc->sc_clks = rk3399_cru_clks;
 	sc->sc_nclks = __arraycount(rk3399_cru_clks);
 
+	sc->sc_grf_soc_status = 0x0480;
 	sc->sc_softrst_base = SOFTRST_CON(0);
 
 	if (rk_cru_attach(sc) != 0)

Index: src/sys/arch/arm/rockchip/rk_cru.h
diff -u src/sys/arch/arm/rockchip/rk_cru.h:1.7 src/sys/arch/arm/rockchip/rk_cru.h:1.8
--- src/sys/arch/arm/rockchip/rk_cru.h:1.7	Sat Nov 16 13:23:13 2019
+++ src/sys/arch/arm/rockchip/rk_cru.h	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru.h,v 1.7 2019/11/16 13:23:13 jmcneill Exp $ */
+/* $NetBSD: rk_cru.h,v 1.8 2021/11/12 22:02:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -80,6 +80,8 @@ struct rk_cru_pll {
 	u_int		nrates;
 	const char	**parents;
 	u_int		nparents;
+	u_int		flags;
+#define	RK_PLL_RK3288	0x01
 };
 
 u_int	rk_cru_pll_get_rate(struct rk_cru_softc *, struct rk_cru_clk *);
@@ -100,6 +102,27 @@ const char *rk_cru_pll_get_parent(struct
 		.u.pll.lock_mask = (_lock_mask),		\
 		.u.pll.rates = (_rates),			\
 		.u.pll.nrates = __arraycount(_rates),		\
+		.u.pll.flags = 0,				\
+		.get_rate = rk_cru_pll_get_rate,		\
+		.set_rate = rk_cru_pll_set_rate,		\
+		.get_parent = rk_cru_pll_get_parent,		\
+	}
+
+#define	RK3288_PLL(_id, _name, _parents, _con_base, _mode_reg, _mode_mask, _lock_mask, _rates) \
+	{							\
+		.id = (_id),					\
+		.type = RK_CRU_PLL,				\
+		.base.name = (_name),				\
+		.base.flags = 0,				\
+		.u.pll.parents = (_parents),			\
+		.u.pll.nparents = __arraycount(_parents),	\
+		.u.pll.con_base = (_con_base),			\
+		.u.pll.mode_reg = (_mode_reg),			\
+		.u.pll.mode_mask = (_mode_mask),		\
+		.u.pll.lock_mask = (_lock_mask),		\
+		.u.pll.rates = (_rates),			\
+		.u.pll.nrates = __arraycount(_rates),		\
+		.u.pll.flags = RK_PLL_RK3288,			\
 		.get_rate = rk_cru_pll_get_rate,		\
 		.set_rate = rk_cru_pll_set_rate,		\
 		.get_parent = rk_cru_pll_get_parent,		\
@@ -207,6 +230,7 @@ struct rk_cru_composite {
 #define	RK_COMPOSITE_ROUND_DOWN		0x01
 #define	RK_COMPOSITE_SET_RATE_PARENT	0x02
 #define	RK_COMPOSITE_FRACDIV		0x04
+#define	RK_COMPOSITE_POW2		0x08
 };
 
 int	rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int);
@@ -367,6 +391,7 @@ struct rk_cru_softc {
 	struct rk_cru_clk	*sc_clks;
 	u_int			sc_nclks;
 
+	bus_size_t		sc_grf_soc_status;	/* for PLL lock */
 	bus_size_t		sc_softrst_base;
 };
 

Index: src/sys/arch/arm/rockchip/rk_cru_composite.c
diff -u src/sys/arch/arm/rockchip/rk_cru_composite.c:1.6 src/sys/arch/arm/rockchip/rk_cru_composite.c:1.7
--- src/sys/arch/arm/rockchip/rk_cru_composite.c:1.6	Thu May 20 01:41:55 2021
+++ src/sys/arch/arm/rockchip/rk_cru_composite.c	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru_composite.c,v 1.6 2021/05/20 01:41:55 msaitoh Exp $ */
+/* $NetBSD: rk_cru_composite.c,v 1.7 2021/11/12 22:02:08 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.6 2021/05/20 01:41:55 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_cru_composite.c,v 1.7 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -83,9 +83,14 @@ rk_cru_composite_get_rate(struct rk_cru_
 		return (u_int)((uint64_t)prate * num / den);
 	} else {
 		const uint32_t val = CRU_READ(sc, composite->muxdiv_reg);
-		const u_int div = (composite->div_mask != 0)
-		    ? __SHIFTOUT(val, composite->div_mask) + 1 : 1;
+		u_int div;
 
+		if (composite->flags & RK_COMPOSITE_POW2) {
+			div = 1U << __SHIFTOUT(val, composite->div_mask);
+		} else {
+			div = (composite->div_mask != 0)
+			    ? __SHIFTOUT(val, composite->div_mask) + 1 : 1;
+		}
 		return prate / div;
 	}
 }
@@ -149,6 +154,10 @@ rk_cru_composite_set_rate(struct rk_cru_
 		return rk_cru_composite_set_rate_frac(sc, clk, rate);
 	}
 
+	if (composite->flags & RK_COMPOSITE_POW2) {
+		return ENXIO;	/* TODO */
+	}
+
 	best_div = 0;
 	best_mux = 0;
 	best_diff = INT_MAX;

Index: src/sys/arch/arm/rockchip/rk_cru_pll.c
diff -u src/sys/arch/arm/rockchip/rk_cru_pll.c:1.4 src/sys/arch/arm/rockchip/rk_cru_pll.c:1.5
--- src/sys/arch/arm/rockchip/rk_cru_pll.c:1.4	Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk_cru_pll.c	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru_pll.c,v 1.4 2018/08/12 16:48:05 jmcneill Exp $ */
+/* $NetBSD: rk_cru_pll.c,v 1.5 2021/11/12 22:02:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_cru_pll.c,v 1.4 2018/08/12 16:48:05 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_cru_pll.c,v 1.5 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -57,9 +57,20 @@ __KERNEL_RCSID(0, "$NetBSD: rk_cru_pll.c
 #define	 PLL_DACPD		__BIT(24)
 #define	 PLL_FRACDIV		__BITS(23,0)
 
+#define	PLL_CON3		0x0c
+
 #define	PLL_WRITE_MASK		0xffff0000	/* for CON0 and CON1 */
 
-#define	GRF_SOC_STATUS0		0x0480
+/* RK3288 CON0 */
+#define	RK3288_CLKR		__BITS(13,8)
+#define	RK3288_CLKOD		__BITS(3,0)
+/* RK3288 CON1 */
+#define	RK3288_LOCK		__BIT(31)
+#define	RK3288_CLKF		__BITS(12,0)
+/* RK3288 CON2 */
+#define	RK3288_BWADJ		__BITS(11,0)
+/* RK3288 CON3 */
+#define	RK3288_BYPASS		__BIT(0)
 
 u_int
 rk_cru_pll_get_rate(struct rk_cru_softc *sc,
@@ -83,24 +94,39 @@ rk_cru_pll_get_rate(struct rk_cru_softc 
 	const uint32_t con0 = CRU_READ(sc, pll->con_base + PLL_CON0);
 	const uint32_t con1 = CRU_READ(sc, pll->con_base + PLL_CON1);
 	const uint32_t con2 = CRU_READ(sc, pll->con_base + PLL_CON2);
+	const uint32_t con3 = CRU_READ(sc, pll->con_base + PLL_CON3);
+
+	if ((pll->flags & RK_PLL_RK3288) != 0) {
+		if ((con3 & RK3288_BYPASS) != 0) {
+			return fref;
+		}
+
+		const u_int nr = __SHIFTOUT(con0, RK3288_CLKR) + 1;
+		const u_int no = __SHIFTOUT(con0, RK3288_CLKOD) + 1;
+		const u_int nf = __SHIFTOUT(con1, RK3288_CLKF) + 1;
+
+		const uint64_t tmp = (uint64_t)fref * nf / nr / no;
 
-	const u_int postdiv1 = __SHIFTOUT(con0, PLL_POSTDIV1);
-	const u_int fbdiv = __SHIFTOUT(con0, PLL_FBDIV);
-	const u_int dsmpd = __SHIFTOUT(con1, PLL_DSMPD);
-	const u_int refdiv = __SHIFTOUT(con1, PLL_REFDIV);
-	const u_int postdiv2 = __SHIFTOUT(con1, PLL_POSTDIV2);
-	const u_int fracdiv = __SHIFTOUT(con2, PLL_FRACDIV);
-
-	if (dsmpd == 1) {
-		/* integer mode */
-		foutvco = fref / refdiv * fbdiv;
+		return (u_int)tmp;
 	} else {
-		/* fractional mode */
-		foutvco = fref / refdiv * fbdiv + ((fref * fracdiv) >> 24);
-	}
-	foutpostdiv = foutvco / postdiv1 / postdiv2;
+		const u_int postdiv1 = __SHIFTOUT(con0, PLL_POSTDIV1);
+		const u_int fbdiv = __SHIFTOUT(con0, PLL_FBDIV);
+		const u_int dsmpd = __SHIFTOUT(con1, PLL_DSMPD);
+		const u_int refdiv = __SHIFTOUT(con1, PLL_REFDIV);
+		const u_int postdiv2 = __SHIFTOUT(con1, PLL_POSTDIV2);
+		const u_int fracdiv = __SHIFTOUT(con2, PLL_FRACDIV);
+
+		if (dsmpd == 1) {
+			/* integer mode */
+			foutvco = fref / refdiv * fbdiv;
+		} else {
+			/* fractional mode */
+			foutvco = fref / refdiv * fbdiv + ((fref * fracdiv) >> 24);
+		}
+		foutpostdiv = foutvco / postdiv1 / postdiv2;
 
-	return foutpostdiv;
+		return foutpostdiv;
+	}
 }
 
 int
@@ -125,6 +151,8 @@ rk_cru_pll_set_rate(struct rk_cru_softc 
 	if (pll_rate == NULL)
 		return EINVAL;
 
+	KASSERT((pll->flags & RK_PLL_RK3288) == 0);	/* XXX TODO */
+
 	CRU_WRITE(sc, pll->con_base + PLL_CON0,
 	    __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) |
 	    __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) |
@@ -148,7 +176,7 @@ rk_cru_pll_set_rate(struct rk_cru_softc 
 
 	syscon_lock(sc->sc_grf);
 	for (retry = 1000; retry > 0; retry--) {
-		if (syscon_read_4(sc->sc_grf, GRF_SOC_STATUS0) & pll->lock_mask)
+		if (syscon_read_4(sc->sc_grf, sc->sc_grf_soc_status) & pll->lock_mask)
 			break;
 		delay(1);
 	}

Index: src/sys/arch/arm/rockchip/rk_gmac.c
diff -u src/sys/arch/arm/rockchip/rk_gmac.c:1.20 src/sys/arch/arm/rockchip/rk_gmac.c:1.21
--- src/sys/arch/arm/rockchip/rk_gmac.c:1.20	Sun Nov  7 19:21:33 2021
+++ src/sys/arch/arm/rockchip/rk_gmac.c	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_gmac.c,v 1.20 2021/11/07 19:21:33 jmcneill Exp $ */
+/* $NetBSD: rk_gmac.c,v 1.21 2021/11/12 22:02:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 1.20 2021/11/07 19:21:33 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 1.21 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -54,11 +54,13 @@ __KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 
 #define	RK_GMAC_RXDLY_DEFAULT	0x10
 
 enum rk_gmac_type {
-	GMAC_RK3328 = 1,
+	GMAC_RK3288 = 1,
+	GMAC_RK3328,
 	GMAC_RK3399
 };
 
 static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "rockchip,rk3288-gmac",	.value = GMAC_RK3288 },
 	{ .compat = "rockchip,rk3328-gmac",	.value = GMAC_RK3328 },
 	{ .compat = "rockchip,rk3399-gmac",	.value = GMAC_RK3399 },
 	DEVICE_COMPAT_EOL
@@ -71,6 +73,98 @@ struct rk_gmac_softc {
 };
 
 /*
+ * RK3288 specific
+ */
+
+#define	RK3288_GRF_SOC_CON1	0x0248
+#define	 RK3288_GRF_SOC_CON1_RMII_MODE		__BIT(14)
+#define	 RK3288_GRF_SOC_CON1_GMAC_CLK_SEL	__BITS(13,12)
+#define	  RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_125M		0
+#define	  RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_2_5M		2
+#define	  RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_25M		3
+#define	 RK3288_GRF_SOC_CON1_RMII_CLK_SEL	__BIT(11)
+#define	  RK3288_GRF_SOC_CON1_RMII_CLK_SEL_25M		1
+#define	  RK3288_GRF_SOC_CON1_RMII_CLK_SEL_2_5M		0
+#define	 RK3288_GRF_SOC_CON1_GMAC_SPEED		__BIT(10)
+#define	  RK3288_GRF_SOC_CON1_GMAC_SPEED_10M		0
+#define	  RK3288_GRF_SOC_CON1_GMAC_SPEED_100M		1
+#define	 RK3288_GRF_SOC_CON1_GMAC_FLOWCTRL	__BIT(9)
+#define	 RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL	__BITS(8,6)
+#define	  RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL_RGMII	1
+#define	  RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL_RMII	4
+
+#define	RK3288_GRF_SOC_CON3	0x0250
+#define	 RK3288_GRF_SOC_CON3_RXCLK_DLY_ENA_GMAC	__BIT(15)
+#define	 RK3288_GRF_SOC_CON3_TXCLK_DLY_ENA_GMAC	__BIT(14)
+#define	 RK3288_GRF_SOC_CON3_CLK_RX_DL_CFG_GMAC	__BITS(13,7)
+#define	 RK3288_GRF_SOC_CON3_CLK_TX_DL_CFG_GMAC	__BITS(6,0)
+
+static void
+rk3288_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay, bool set_delay)
+{
+	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
+	uint32_t write_mask, write_val;
+
+	syscon_lock(rk_sc->sc_syscon);
+
+	write_mask = (RK3288_GRF_SOC_CON1_RMII_MODE |
+		      RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL) << 16;
+	write_val = __SHIFTIN(RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL_RGMII,
+			      RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL);
+	syscon_write_4(rk_sc->sc_syscon, RK3288_GRF_SOC_CON1,
+	    write_mask | write_val);
+
+	if (set_delay) {
+		write_mask = (RK3288_GRF_SOC_CON3_RXCLK_DLY_ENA_GMAC |
+			      RK3288_GRF_SOC_CON3_TXCLK_DLY_ENA_GMAC |
+			      RK3288_GRF_SOC_CON3_CLK_RX_DL_CFG_GMAC |
+			      RK3288_GRF_SOC_CON3_CLK_TX_DL_CFG_GMAC) << 16;
+		write_val = 0;
+		if (tx_delay) {
+			write_mask |= RK3288_GRF_SOC_CON3_TXCLK_DLY_ENA_GMAC |
+				      __SHIFTIN(tx_delay,
+						RK3288_GRF_SOC_CON3_CLK_TX_DL_CFG_GMAC);
+		}
+		if (rx_delay) {
+			write_mask |= RK3288_GRF_SOC_CON3_RXCLK_DLY_ENA_GMAC |
+				      __SHIFTIN(rx_delay,
+						RK3288_GRF_SOC_CON3_CLK_RX_DL_CFG_GMAC);
+		}
+		syscon_write_4(rk_sc->sc_syscon, RK3288_GRF_SOC_CON3,
+		    write_mask | write_val);
+	}
+
+	syscon_unlock(rk_sc->sc_syscon);
+}
+
+static void
+rk3288_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed)
+{
+	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
+	uint32_t write_mask, write_val;
+
+	syscon_lock(rk_sc->sc_syscon);
+
+	write_mask = (RK3288_GRF_SOC_CON1_GMAC_CLK_SEL) << 16;
+	switch (speed) {
+	case IFM_10_T:
+		write_val = RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_2_5M;
+		break;
+	case IFM_100_TX:
+		write_val = RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_25M;
+		break;
+	case IFM_1000_T:
+	default:
+		write_val = RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_125M;
+		break;
+	}
+	syscon_write_4(rk_sc->sc_syscon, RK3288_GRF_SOC_CON1,
+	    write_mask | write_val);
+
+	syscon_unlock(rk_sc->sc_syscon);
+}
+
+/*
  * RK3328 specific
  */
 
@@ -415,6 +509,17 @@ rk_gmac_attach(device_t parent, device_t
 	}
 
 	switch (rk_sc->sc_type) {
+	case GMAC_RK3288:
+		if (strncmp(phy_mode, "rgmii", 5) == 0) {
+			rk3288_gmac_set_mode_rgmii(sc, tx_delay, rx_delay,
+			    set_delay);
+
+			sc->sc_set_speed = rk3288_gmac_set_speed_rgmii;
+		} else {
+			aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
+			return;
+		}
+		break;
 	case GMAC_RK3328:
 		if (strncmp(phy_mode, "rgmii", 5) == 0) {
 			rk3328_gmac_set_mode_rgmii(sc, tx_delay, rx_delay,

Index: src/sys/arch/arm/rockchip/rk_i2c.c
diff -u src/sys/arch/arm/rockchip/rk_i2c.c:1.10 src/sys/arch/arm/rockchip/rk_i2c.c:1.11
--- src/sys/arch/arm/rockchip/rk_i2c.c:1.10	Wed Jan 27 03:10:19 2021
+++ src/sys/arch/arm/rockchip/rk_i2c.c	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_i2c.c,v 1.10 2021/01/27 03:10:19 thorpej Exp $ */
+/* $NetBSD: rk_i2c.c,v 1.11 2021/11/12 22:02:08 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: rk_i2c.c,v 1.10 2021/01/27 03:10:19 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_i2c.c,v 1.11 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -100,8 +100,14 @@ __KERNEL_RCSID(0, "$NetBSD: rk_i2c.c,v 1
 #define	RKI2C_TXDATA(n)		(0x100 + (n) * 4)
 #define	RKI2C_RXDATA(n)		(0x200 + (n) * 4)
 
+/* Compat data flags */
+#define	RKI2C_HAS_PCLK		__BIT(0)
+
 static const struct device_compatible_entry compat_data[] = {
-	{ .compat = "rockchip,rk3399-i2c" },
+#if notyet
+	{ .compat = "rockchip,rk3288-i2c",	.value = 0 },
+#endif
+	{ .compat = "rockchip,rk3399-i2c",	.value = RKI2C_HAS_PCLK },
 	DEVICE_COMPAT_EOL
 };
 
@@ -377,22 +383,27 @@ rk_i2c_attach(device_t parent, device_t 
 	const int phandle = faa->faa_phandle;
 	bus_addr_t addr;
 	bus_size_t size;
+	u_int flags;
 
 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
 		aprint_error(": couldn't get registers\n");
 		return;
 	}
 
+	flags = of_compatible_lookup(phandle, compat_data)->value;
+
 	sc->sc_sclk = fdtbus_clock_get(phandle, "i2c");
 	if (sc->sc_sclk == NULL || clk_enable(sc->sc_sclk) != 0) {
 		aprint_error(": couldn't enable sclk\n");
 		return;
 	}
 
-	sc->sc_pclk = fdtbus_clock_get(phandle, "pclk");
-	if (sc->sc_pclk == NULL || clk_enable(sc->sc_pclk) != 0) {
-		aprint_error(": couldn't enable pclk\n");
-		return;
+	if (ISSET(flags, RKI2C_HAS_PCLK)) {
+		sc->sc_pclk = fdtbus_clock_get(phandle, "pclk");
+		if (sc->sc_pclk == NULL || clk_enable(sc->sc_pclk) != 0) {
+			aprint_error(": couldn't enable pclk\n");
+			return;
+		}
 	}
 
 	if (of_getprop_uint32(phandle, "clock-frequency", &sc->sc_clkfreq))

Index: src/sys/arch/arm/rockchip/rk_platform.c
diff -u src/sys/arch/arm/rockchip/rk_platform.c:1.14 src/sys/arch/arm/rockchip/rk_platform.c:1.15
--- src/sys/arch/arm/rockchip/rk_platform.c:1.14	Fri Sep  3 01:23:33 2021
+++ src/sys/arch/arm/rockchip/rk_platform.c	Fri Nov 12 22:02:08 2021
@@ -1,7 +1,7 @@
-/* $NetBSD: rk_platform.c,v 1.14 2021/09/03 01:23:33 mrg Exp $ */
+/* $NetBSD: rk_platform.c,v 1.15 2021/11/12 22:02:08 jmcneill Exp $ */
 
 /*-
- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
+ * Copyright (c) 2018,2021 Jared McNeill <jmcne...@invisible.ca>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
 #include "opt_console.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_platform.c,v 1.14 2021/09/03 01:23:33 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_platform.c,v 1.15 2021/11/12 22:02:08 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -101,6 +101,95 @@ rk_platform_bootstrap(void)
 	}
 }
 
+#ifdef SOC_RK3288
+
+#define	RK3288_WDT_BASE		0xff800000
+#define	RK3288_WDT_SIZE		0x10000
+
+#define	RK3288_WDT_CR		0x0000
+#define	 RK3288_WDT_CR_WDT_EN		__BIT(0)
+#define	RK3288_WDT_TORR		0x0004
+#define	RK3288_WDT_CRR		0x000c
+#define	 RK3288_WDT_MAGIC		0x76
+
+static bus_space_handle_t rk3288_wdt_bsh;
+
+#include <arm/rockchip/rk3288_platform.h>
+
+static const struct pmap_devmap *
+rk3288_platform_devmap(void)
+{
+	static const struct pmap_devmap devmap[] = {
+		DEVMAP_ENTRY(RK3288_CORE_VBASE,
+			     RK3288_CORE_PBASE,
+			     RK3288_CORE_SIZE),
+		DEVMAP_ENTRY_END
+	};
+
+	return devmap;
+}
+
+void rk3288_platform_early_putchar(char);
+
+void __noasan
+rk3288_platform_early_putchar(char c)
+{
+#ifdef CONSADDR
+#define CONSADDR_VA	((CONSADDR - RK3288_CORE_PBASE) + RK3288_CORE_VBASE)
+	volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
+	    (volatile uint32_t *)CONSADDR_VA :
+	    (volatile uint32_t *)CONSADDR;
+
+	while ((le32toh(uartaddr[com_lsr]) & LSR_TXRDY) == 0)
+		;
+
+	uartaddr[com_data] = htole32(c);
+#undef CONSADDR_VA
+#endif
+}
+
+static void
+rk3288_platform_bootstrap(void)
+{
+	bus_space_tag_t bst = &arm_generic_bs_tag;
+
+	rk_platform_bootstrap();
+	bus_space_map(bst, RK3288_WDT_BASE, RK3288_WDT_SIZE, 0, &rk3288_wdt_bsh);
+}
+
+static void
+rk3288_platform_reset(void)
+{
+	bus_space_tag_t bst = &arm_generic_bs_tag;
+
+	bus_space_write_4(bst, rk3288_wdt_bsh, RK3288_WDT_TORR, 0);
+	bus_space_write_4(bst, rk3288_wdt_bsh, RK3288_WDT_CRR, RK3288_WDT_MAGIC);
+	for (;;) {
+		bus_space_write_4(bst, rk3288_wdt_bsh, RK3288_WDT_CR, RK3288_WDT_CR_WDT_EN);
+	}
+}
+
+static u_int
+rk3288_platform_uart_freq(void)
+{
+	return RK3288_UART_FREQ;
+}
+
+static const struct arm_platform rk3288_platform = {
+	.ap_devmap = rk3288_platform_devmap,
+	.ap_bootstrap = rk3288_platform_bootstrap,
+	.ap_init_attach_args = rk_platform_init_attach_args,
+	.ap_device_register = rk_platform_device_register,
+	.ap_reset = rk3288_platform_reset,
+	.ap_delay = gtmr_delay,
+	.ap_uart_freq = rk3288_platform_uart_freq,
+	.ap_mpstart = arm_fdt_cpu_mpstart,
+};
+
+ARM_PLATFORM(rk3288, "rockchip,rk3288", &rk3288_platform);
+#endif /* SOC_RK3288 */
+
+
 #ifdef SOC_RK3328
 
 #include <arm/rockchip/rk3328_platform.h>

Index: src/sys/arch/evbarm/conf/GENERIC
diff -u src/sys/arch/evbarm/conf/GENERIC:1.100 src/sys/arch/evbarm/conf/GENERIC:1.101
--- src/sys/arch/evbarm/conf/GENERIC:1.100	Thu Aug 26 17:08:34 2021
+++ src/sys/arch/evbarm/conf/GENERIC	Fri Nov 12 22:02:08 2021
@@ -1,5 +1,5 @@
 #
-#	$NetBSD: GENERIC,v 1.100 2021/08/26 17:08:34 thorpej Exp $
+#	$NetBSD: GENERIC,v 1.101 2021/11/12 22:02:08 jmcneill Exp $
 #
 #	GENERIC ARM (aarch32) kernel
 #
@@ -19,6 +19,7 @@ options 	SOC_IMX6QDL
 options 	SOC_IMX7D
 options 	SOC_MESON8B
 options 	SOC_OMAP3
+options 	SOC_RK3288
 options 	SOC_SUN4I_A10
 options 	SOC_SUN5I_A13
 options 	SOC_SUN6I_A31
@@ -79,6 +80,7 @@ options 	MSGBUFSIZE=32768
 #options 	EARLYCONS=vexpress, CONSADDR=0x1c090000
 #options 	EARLYCONS=virt, CONSADDR=0x09000000
 #options 	EARLYCONS=zynq, CONSADDR=0xe0001000
+#options 	EARLYCONS=rk3288, CONSADDR=0xff690000
 
 # Kernel Undefined Behavior Sanitizer (kUBSan). Use UBSAN_ALWAYS_FATAL
 # if you want panics instead of warnings.
@@ -134,6 +136,7 @@ meson8bclkc* 	at fdt? pass 2		# Amlogic 
 mesonresets* 	at fdt? pass 2		# Amlogic Meson misc. clock resets
 omap3cm* 	at fdt? pass 1		# TI OMAP3 CM
 omap3prm* 	at fdt? pass 1		# TI OMAP3 PRM
+rkcru*		at fdt? pass 2		# Rockchip RK3288 CRU
 sun4ia10ccu* 	at fdt? pass 2		# Allwinner A10/A20 CCU
 sun5ia13ccu* 	at fdt? pass 2		# Allwinner A13 CCU
 sun6ia31ccu* 	at fdt? pass 2		# Allwinner A31 CCU
@@ -258,6 +261,7 @@ imxgpio* 	at fdt? pass 3		# i.MX GPIO
 mesonpinctrl* 	at fdt? pass 2		# Amlogic Meson GPIO
 plgpio* 	at fdt?			# ARM PrimeCell GPIO
 sunxigpio* 	at fdt? pass 3		# Allwinner GPIO
+rkgpio*		at rkiomux?		# Rockchip GPIO
 tegragpio* 	at fdt? pass 2		# NVIDIA Tegra GPIO
 tigpio* 	at fdt? pass 2		# TI GPIO
 gpio* 		at gpiobus?
@@ -265,6 +269,7 @@ gpio* 		at gpiobus?
 # IOMUX / MPIO / Pinmux
 pinctrl* 	at fdt? pass 2		# Generic pinctrl driver
 imxiomux* 	at fdt? pass 2		# i.MX IOMUX
+rkiomux*	at fdt? pass 3		# Rockchip IOMUX
 tegrapinmux* 	at fdt?			# NVIDIA Tegra MPIO
 
 # PWM controller
@@ -349,6 +354,7 @@ options 	I2C_MAX_ADDR=0xfff
 bsciic* 	at fdt?			# Broadcom BCM283x Serial Control
 exyoi2c* 	at fdt?			# Samsung Exynos I2C
 imxi2c* 	at fdt? pass 4		# i.MX I2C
+rkiic*		at fdt? pass 4		# Rockchip I2C
 sunxirsb* 	at fdt? pass 4		# Allwinner RSB
 sunxitwi* 	at fdt?			# Allwinner TWI
 tegrai2c* 	at fdt? pass 4		# NVIDIA Tegra I2C
@@ -370,6 +376,7 @@ em3027rtc* 	at iic?
 max77620pmic* 	at iic?
 pcaiicmux*	at iic?			# PCA954x / PCA984x I2C switch / mux
 pcf8563rtc* 	at iic?			# PCF8563 RTC
+rkpmic*		at iic?			# Rockchip Power Management IC
 seeprom* 	at iic?			# AT24Cxx Serial EEPROM
 sy8106a* 	at iic?			# Silergy SY81061 regulator
 tcakp* 		at iic?			# TI TCA8418 Keypad Scan IC
@@ -549,6 +556,8 @@ exusbphy* 	at fdt? pass 9		# Samsung Exy
 exusbdrdphy* 	at fdt? pass 9		# Samsung Exynos USB3 DRD PHY
 imxusbphy* 	at fdt? pass 9		# i.MX USB PHY
 mesonusbphy* 	at fdt? pass 9		# Amlogic Meson USB2 PHY
+rk3288usb*	at fdt? pass 9		# Rockchip USB PHY
+rk3288usbphy*	at rk3288usb?
 sun9iusbphy* 	at fdt? pass 9		# Allwinner A80 USB PHY
 sunxiusbphy* 	at fdt? pass 9		# Allwinner USB PHY
 sunxiusb3phy* 	at fdt? pass 9		# Allwinner USB3 PHY

Index: src/sys/arch/evbarm/conf/files.generic
diff -u src/sys/arch/evbarm/conf/files.generic:1.11 src/sys/arch/evbarm/conf/files.generic:1.12
--- src/sys/arch/evbarm/conf/files.generic:1.11	Wed Dec 23 14:42:38 2020
+++ src/sys/arch/evbarm/conf/files.generic	Fri Nov 12 22:02:08 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: files.generic,v 1.11 2020/12/23 14:42:38 skrll Exp $
+#	$NetBSD: files.generic,v 1.12 2021/11/12 22:02:08 jmcneill Exp $
 #
 # A generic (aarch32) kernel configuration info
 #
@@ -22,6 +22,7 @@ include "arch/arm/amlogic/files.meson"
 include "arch/arm/broadcom/files.bcm2835"
 include "arch/arm/nvidia/files.tegra"
 include "arch/arm/nxp/files.imx"
+include "arch/arm/rockchip/files.rockchip"
 include "arch/arm/samsung/files.exynos"
 include "arch/arm/sunxi/files.sunxi"
 include "arch/arm/ti/files.ti"

Added files:

Index: src/sys/arch/arm/rockchip/rk3066_smp.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3066_smp.c:1.1
--- /dev/null	Fri Nov 12 22:02:08 2021
+++ src/sys/arch/arm/rockchip/rk3066_smp.c	Fri Nov 12 22:02:08 2021
@@ -0,0 +1,166 @@
+/* $NetBSD: rk3066_smp.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_soc.h"
+#include "opt_multiprocessor.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rk3066_smp.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <arm/fdt/arm_fdtvar.h>
+
+#include <uvm/uvm_extern.h>
+
+#define	PMU_PWRDN_CON		0x0008
+#define	PMU_PWRDN_ST		0x000c
+
+#define	SRAM_ENTRY_PA		0x0008
+#define	SRAM_DOORBELL		0x0004
+#define	SRAM_DOORBELL_MAGIC	0xdeadbeaf
+
+extern struct bus_space arm_generic_bs_tag;
+
+static uint32_t
+rk3066_mpstart_pa(void)
+{
+	bool ok __diagused;
+	paddr_t pa;
+
+	ok = pmap_extract(pmap_kernel(), (vaddr_t)cpu_mpstart, &pa);
+	KASSERT(ok);
+
+	return (uint32_t)pa;
+}
+
+static int
+rk3066_map(int phandle, bus_space_tag_t bst, bus_space_handle_t *pbsh,
+    bus_size_t *psize)
+{
+	bus_addr_t addr;
+	int error;
+
+	error = fdtbus_get_reg(phandle, 0, &addr, psize);
+	if (error != 0) {
+		return error;
+	}
+
+	return bus_space_map(bst, addr, *psize, 0, pbsh);
+}
+
+static int
+rk3066_smp_enable(int cpus_phandle, u_int cpuno)
+{
+	bus_space_tag_t bst = &arm_generic_bs_tag;
+	bus_space_handle_t bsh_sram, bsh_pmu;
+	bus_size_t sz_sram, sz_pmu;
+	uint32_t val;
+	int error;
+
+	const int sram_phandle =
+	    of_find_bycompat(OF_peer(0), "rockchip,rk3066-smp-sram");
+	if (sram_phandle == -1) {
+		printf("%s: missing rockchip,rk3066-smp-sram node\n",
+		    __func__);
+		return ENXIO;
+	}
+
+	const int pmu_phandle = fdtbus_get_phandle(cpus_phandle,
+	    "rockchip,pmu");
+	if (pmu_phandle == -1) {
+		printf("%s: missing rockchip,pmu xref\n", __func__);
+		return ENXIO;
+	}
+
+	error = rk3066_map(sram_phandle, bst, &bsh_sram, &sz_sram);
+	if (error != 0) {
+		return error;
+	}
+
+	error = rk3066_map(pmu_phandle, bst, &bsh_pmu, &sz_pmu);
+	if (error != 0) {
+		bus_space_unmap(bst, bsh_pmu, sz_pmu);
+		return error;
+	}
+
+	/* Enable the A17 core's power domain */
+	val = bus_space_read_4(bst, bsh_pmu, PMU_PWRDN_CON);
+	val &= ~__BIT(cpuno);
+	bus_space_write_4(bst, bsh_pmu, PMU_PWRDN_CON, val);
+
+	/* Wait for the A17 core to power on */
+	do {
+		val = bus_space_read_4(bst, bsh_pmu, PMU_PWRDN_ST);
+	} while ((val & __BIT(cpuno)) != 0);
+
+	delay(2000);
+
+	/* Set wake vector */
+	bus_space_write_4(bst, bsh_sram, SRAM_ENTRY_PA, rk3066_mpstart_pa());
+	/* Notify boot rom that we are ready to start */
+	bus_space_write_4(bst, bsh_sram, SRAM_DOORBELL, SRAM_DOORBELL_MAGIC);
+	dsb();
+	sev();
+
+	bus_space_unmap(bst, bsh_pmu, sz_pmu);
+	bus_space_unmap(bst, bsh_sram, sz_sram);
+
+	return 0;
+}
+
+static int
+cpu_enable_rk3066(int phandle)
+{
+	static uint32_t enabled;
+	uint64_t mpidr;
+	int error = 0;
+
+	fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
+
+	const u_int cpuno = __SHIFTOUT(mpidr, MPIDR_AFF0);
+	const bool is_enabled = enabled & __BIT(cpuno);
+
+	if (!is_enabled) {
+		error = rk3066_smp_enable(OF_parent(phandle), cpuno);
+		if (error == 0) {
+			enabled |= __BIT(cpuno);
+		}
+	} else {
+		printf("WARNING: CPU enable called more than once for CPU %u\n",
+		    cpuno);
+	}
+
+	return error;
+}
+
+ARM_CPU_METHOD(rk3066, "rockchip,rk3066-smp", cpu_enable_rk3066);
Index: src/sys/arch/arm/rockchip/rk3288_cru.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3288_cru.c:1.1
--- /dev/null	Fri Nov 12 22:02:08 2021
+++ src/sys/arch/arm/rockchip/rk3288_cru.c	Fri Nov 12 22:02:08 2021
@@ -0,0 +1,309 @@
+/* $NetBSD: rk3288_cru.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: rk3288_cru.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <arm/rockchip/rk_cru.h>
+#include <arm/rockchip/rk3288_cru.h>
+
+#define	PLL_CON(n)	(0x0000 + (n) * 4)
+#define	MODE_CON	0x0050
+#define	CLKSEL_CON(n)	(0x0060 + (n) * 4)
+#define	CLKGATE_CON(n)	(0x0160 + (n) * 4)
+#define	SOFTRST_CON(n)	(0x01b8 + (n) * 4)
+
+#define	GRF_SOC_CON4	0x0410
+#define	GRF_MAC_CON1	0x0904
+
+static int rk3288_cru_match(device_t, cfdata_t, void *);
+static void rk3288_cru_attach(device_t, device_t, void *);
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "rockchip,rk3288-cru" },
+	DEVICE_COMPAT_EOL
+};
+
+CFATTACH_DECL_NEW(rk3288_cru, sizeof(struct rk_cru_softc),
+	rk3288_cru_match, rk3288_cru_attach, NULL, NULL);
+
+static const char * pll_parents[] = { "xin24m" };
+static const char * aclk_cpu_src_parents[] = { "cpll_aclk_cpu", "gpll_aclk_cpu" };
+static const char * uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" };
+static const char * uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" };
+static const char * uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" };
+static const char * uart3_parents[] = { "clk_uart3_div", "clk_uart3_frac", "xin24m" };
+static const char * uart4_parents[] = { "clk_uart4_div", "clk_uart4_frac", "xin24m" };
+static const char * mmc_parents[] = { "cpll", "gpll", "xin24m", "xin24m" };
+static const char * mac_parents[] = { "mac_pll_src", "ext_gmac" };
+static const char * mux_2plls_parents[] = { "cpll", "gpll" };
+static const char * mux_npll_cpll_gpll_parents[] = { "npll", "cpll", "gpll" };
+static const char * mux_3plls_usb_parents[] = { "cpll", "gpll", "usbphy480m_src", "npll" };
+
+static struct rk_cru_pll_rate rk3288_pll_rates[] = {
+	/* TODO */
+};
+
+static struct rk_cru_clk rk3288_cru_clks[] = {
+	RK3288_PLL(RK3288_PLL_CPLL, "cpll", pll_parents,
+		   PLL_CON(8),		/* con_base */
+		   MODE_CON,		/* mode_reg */
+		   __BIT(8),		/* mode_mask */
+		   __BIT(2),		/* lock_mask */
+		   rk3288_pll_rates),
+	RK3288_PLL(RK3288_PLL_GPLL, "gpll", pll_parents,
+		   PLL_CON(12),		/* con_base */
+		   MODE_CON,		/* mode_reg */
+		   __BIT(12),		/* mode_mask */
+		   __BIT(3),		/* lock_mask */
+		   rk3288_pll_rates),
+	RK3288_PLL(RK3288_PLL_NPLL, "npll", pll_parents,
+		   PLL_CON(16),		/* con_base */
+		   MODE_CON,		/* mode_reg */
+		   __BIT(14),		/* mode_mask */
+		   __BIT(4),		/* lock_mask */
+		   rk3288_pll_rates),
+
+	RK_COMPOSITE_NOGATE(0, "aclk_cpu_src", aclk_cpu_src_parents,
+			    CLKSEL_CON(1),	/* muxdiv_reg */
+			    __BIT(15),		/* mux_mask */
+			    __BITS(7,3),	/* div_mask */
+			    0),
+        RK_COMPOSITE_NOMUX(RK3288_PCLK_CPU, "pclk_cpu", "aclk_cpu_pre",
+			   CLKSEL_CON(1),	/* div_reg */
+			   __BITS(14,12),	/* div_mask */
+			   CLKGATE_CON(0),	/* gate_reg */
+			   __BIT(5),		/* gate_mask */
+			   0),
+	RK_COMPOSITE_NOMUX(RK3288_HCLK_PERI, "hclk_peri", "aclk_peri_src",
+			   CLKSEL_CON(10),	/* div_reg */
+			   __BITS(9,8),		/* div_mask */
+			   CLKGATE_CON(2),	/* gate_reg */
+			   __BIT(2),		/* gate_mask */
+			   RK_COMPOSITE_POW2),
+	RK_COMPOSITE(0, "aclk_peri_src", mux_2plls_parents,
+		     CLKSEL_CON(10),		/* muxdiv_reg */
+		     __BIT(15),			/* mux_mask */
+		     __BITS(4,0),		/* div_mask */
+		     CLKGATE_CON(2),		/* gate_reg */
+		     __BIT(0),			/* gate_mask */
+		     0),
+	RK_COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll",
+			   CLKSEL_CON(33),	/* div_reg */
+			   __BITS(4,0),		/* div_mask */
+			   CLKGATE_CON(5),	/* gate_reg */
+			   __BIT(8),		/* gate_mask */
+			   0),
+	RK_COMPOSITE_NOMUX(RK3288_PCLK_PERI, "pclk_peri", "aclk_peri_src",
+			   CLKSEL_CON(10),	/* div_reg */
+			   __BITS(13,12),	/* div_mask */
+			   CLKGATE_CON(2),	/* gate_reg */
+			   __BIT(3),		/* gate_mask */
+			   0),
+
+	/* UARTs */
+	RK_COMPOSITE(0, "clk_uart0_div", mux_3plls_usb_parents,
+		     CLKSEL_CON(13),		/* muxdiv_reg */
+		     __BITS(14,13),		/* mux_mask */
+		     __BITS(6,0),		/* div_mask */
+		     CLKGATE_CON(1),		/* gate_reg */
+		     __BIT(8),			/* gate_mask */
+		     0),
+	/* XXX TODO: CRU_CLKGATE1_CON bit 9 (clk_uart0_frac_src_gate_en) */
+	RK_COMPOSITE_FRAC(0, "clk_uart0_frac", "clk_uart0_div",
+			  CLKSEL_CON(17),	/* fracdiv_reg */
+			  0),
+	RK_COMPOSITE_NOMUX(0, "clk_uart1_div", "uart_src",
+			   CLKSEL_CON(14),	/* div_reg */
+			   __BITS(6,0),		/* div_mask */
+			   CLKGATE_CON(1),	/* gate_reg */
+			   __BIT(10),		/* gate_mask */
+			   0),
+	/* XXX TODO: CRU_CLKGATE1_CON bit 11 (clk_uart1_frac_src_gate_en) */
+	RK_COMPOSITE_FRAC(0, "clk_uart1_frac", "clk_uart1_div",
+			  CLKSEL_CON(18),	/* fracdiv_reg */
+			  0),
+	RK_COMPOSITE_NOMUX(0, "clk_uart2_div", "uart_src",
+			   CLKSEL_CON(15),	/* div_reg */
+			   __BITS(6,0),		/* div_mask */
+			   CLKGATE_CON(1),	/* gate_reg */
+			   __BIT(12),		/* gate_mask */
+			   0),
+	/* XXX TODO: CRU_CLKGATE1_CON bit 13 (clk_uart2_frac_src_gate_en) */
+	RK_COMPOSITE_FRAC(0, "clk_uart2_frac", "clk_uart2_div",
+			  CLKSEL_CON(19),	/* fracdiv_reg */
+			  0),
+	RK_COMPOSITE_NOMUX(0, "clk_uart3_div", "uart_src",
+			   CLKSEL_CON(16),	/* div_reg */
+			   __BITS(6,0),		/* div_mask */
+			   CLKGATE_CON(1),	/* gate_reg */
+			   __BIT(14),		/* gate_mask */
+			   0),
+	/* XXX TODO: CRU_CLKGATE1_CON bit 15 (clk_uart3_frac_src_gate_en) */
+	RK_COMPOSITE_FRAC(0, "clk_uart3_frac", "clk_uart3_div",
+			  CLKSEL_CON(20),	/* fracdiv_reg */
+			  0),
+	RK_COMPOSITE_NOMUX(0, "clk_uart4_div", "uart_src",
+			   CLKSEL_CON(3),	/* div_reg */
+			   __BITS(6,0),		/* div_mask */
+			   CLKGATE_CON(2),	/* gate_reg */
+			   __BIT(12),		/* gate_mask */
+			   0),
+	/* XXX TODO: CRU_CLKGATE2_CON bit 13 (clk_uart4_frac_src_gate_en) */
+	RK_COMPOSITE_FRAC(0, "clk_uart4_frac", "clk_uart4_div",
+			  CLKSEL_CON(7),	/* fracdiv_reg */
+			  0),
+
+	/* SD/eMMC/SDIO */
+	RK_COMPOSITE(RK3288_SCLK_SDMMC, "sclk_sdmmc", mmc_parents,
+		     CLKSEL_CON(11),		/* muxdiv_reg */
+		     __BITS(7,6),		/* mux_mask */
+		     __BITS(5,0),		/* div_mask */
+		     CLKGATE_CON(13),		/* gate_reg */
+		     __BIT(0),			/* gate_mask */
+		     0),
+	RK_COMPOSITE(RK3288_SCLK_SDIO0, "sclk_sdio0", mmc_parents,
+		     CLKSEL_CON(12),		/* muxdiv_reg */
+		     __BITS(7,6),		/* mux_mask */
+		     __BITS(5,0),		/* div_mask */
+		     CLKGATE_CON(13),		/* gate_reg */
+		     __BIT(1),			/* gate_mask */
+		     0),
+	RK_COMPOSITE(RK3288_SCLK_SDIO1, "sclk_sdio1", mmc_parents,
+		     CLKSEL_CON(34),		/* muxdiv_reg */
+		     __BITS(15,14),		/* mux_mask */
+		     __BITS(13,8),		/* div_mask */
+		     CLKGATE_CON(13),		/* gate_reg */
+		     __BIT(2),			/* gate_mask */
+		     0),
+	RK_COMPOSITE(RK3288_SCLK_EMMC, "sclk_emmc", mmc_parents,
+		     CLKSEL_CON(12),		/* muxdiv_reg */
+		     __BITS(15,14),		/* mux_mask */
+		     __BITS(13,8),		/* div_mask */
+		     CLKGATE_CON(13),		/* gate_reg */
+		     __BIT(3),			/* gate_mask */
+		     0),
+
+	/* MAC */
+	RK_COMPOSITE(0, "mac_pll_src", mux_npll_cpll_gpll_parents,
+		     CLKSEL_CON(21),		/* muxdiv_reg */
+		     __BITS(1,0),		/* mux_mask */
+		     __BITS(12,8),		/* div_mask */
+		     CLKGATE_CON(2),		/* gate_reg */
+		     __BIT(5),			/* gate_mask */
+		     0),
+
+	RK_DIV(0, "aclk_cpu_pre", "aclk_cpu_src", CLKSEL_CON(1), __BITS(3,0), 0),
+	RK_DIV(0, "clk_24m", "xin24m", CLKSEL_CON(2), __BITS(12,8), 0),
+	RK_DIV(0, "pclk_pd_alive", "gpll", CLKSEL_CON(33), __BITS(12,8), 0),
+
+	RK_MUX(RK3288_SCLK_UART0, "sclk_uart0", uart0_parents, CLKSEL_CON(13), __BITS(9,8)),
+	RK_MUX(RK3288_SCLK_UART1, "sclk_uart1", uart1_parents, CLKSEL_CON(14), __BITS(9,8)),
+	RK_MUX(RK3288_SCLK_UART2, "sclk_uart2", uart2_parents, CLKSEL_CON(15), __BITS(9,8)),
+	RK_MUX(RK3288_SCLK_UART3, "sclk_uart3", uart3_parents, CLKSEL_CON(16), __BITS(9,8)),
+	RK_MUX(RK3288_SCLK_UART4, "sclk_uart4", uart4_parents, CLKSEL_CON(3), __BITS(9,8)),
+	RK_MUX(0, "uart_src", mux_2plls_parents, CLKSEL_CON(15), __BIT(15)),
+	RK_MUX(RK3288_SCLK_MAC, "mac_clk", mac_parents, CLKSEL_CON(21), __BIT(4)),
+
+	RK_GATE(0, "gpll_aclk_cpu", "gpll", CLKGATE_CON(0), 10),
+	RK_GATE(0, "cpll_aclk_cpu", "cpll", CLKGATE_CON(0), 11),
+	RK_GATE(RK3288_ACLK_PERI, "aclk_peri", "aclk_peri_src", CLKGATE_CON(2), 1),
+	RK_GATE(RK3288_SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", CLKGATE_CON(5), 0),
+	RK_GATE(RK3288_SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", CLKGATE_CON(5), 1),
+	RK_GATE(RK3288_SCLK_MACREF, "sclk_macref", "mac_clk", CLKGATE_CON(5), 2),
+	RK_GATE(RK3288_SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", CLKGATE_CON(5), 3),
+	RK_GATE(RK3288_PCLK_I2C1, "pclk_i2c1", "pclk_peri", CLKGATE_CON(6), 13),
+	RK_GATE(RK3288_PCLK_I2C3, "pclk_i2c3", "pclk_peri", CLKGATE_CON(6), 14),
+	RK_GATE(RK3288_PCLK_I2C4, "pclk_i2c4", "pclk_peri", CLKGATE_CON(6), 15),
+	RK_GATE(RK3288_PCLK_I2C5, "pclk_i2c5", "pclk_peri", CLKGATE_CON(7), 0),
+	RK_GATE(RK3288_HCLK_USBHOST0, "hclk_host0", "hclk_peri", CLKGATE_CON(7), 6),
+	RK_GATE(RK3288_HCLK_USBHOST1, "hclk_host1", "hclk_peri", CLKGATE_CON(7), 7),
+	RK_GATE(RK3288_HCLK_HSIC, "hclk_hsic", "hclk_peri", CLKGATE_CON(7), 8),
+	RK_GATE(RK3288_PCLK_GMAC, "pclk_gmac", "pclk_peri", CLKGATE_CON(8), 1),
+	RK_GATE(RK3288_HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", CLKGATE_CON(8), 3),
+	RK_GATE(RK3288_HCLK_SDIO0, "hclk_sdio0", "hclk_peri", CLKGATE_CON(8), 4),
+	RK_GATE(RK3288_HCLK_SDIO1, "hclk_sdio1", "hclk_peri", CLKGATE_CON(8), 5),
+	RK_GATE(RK3288_ACLK_GMAC, "aclk_gmac", "aclk_peri", CLKGATE_CON(8), 0),
+	RK_GATE(RK3288_HCLK_EMMC, "hclk_emmc", "hclk_peri", CLKGATE_CON(8), 6),
+	RK_GATE(RK3288_PCLK_I2C0, "pclk_i2c0", "pclk_cpu", CLKGATE_CON(10), 2),
+	RK_GATE(RK3288_PCLK_I2C2, "pclk_i2c2", "pclk_cpu", CLKGATE_CON(10), 3),
+	RK_GATE(RK3288_PCLK_UART2, "pclk_uart2", "pclk_cpu", CLKGATE_CON(11), 9),
+	RK_GATE(RK3288_SCLK_OTGPHY0, "sclk_otgphy0", "xin24m", CLKGATE_CON(13), 4),
+	RK_GATE(RK3288_SCLK_OTGPHY1, "sclk_otgphy1", "xin24m", CLKGATE_CON(13), 5),
+	RK_GATE(RK3288_SCLK_OTGPHY2, "sclk_otgphy2", "xin24m", CLKGATE_CON(13), 6),
+	RK_GATE(RK3288_PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", CLKGATE_CON(14), 1),
+	RK_GATE(RK3288_PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", CLKGATE_CON(14), 2),
+	RK_GATE(RK3288_PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", CLKGATE_CON(14), 3),
+	RK_GATE(RK3288_PCLK_GPIO4, "pclk_gpio4", "pclk_pd_alive", CLKGATE_CON(14), 4),
+	RK_GATE(RK3288_PCLK_GPIO5, "pclk_gpio5", "pclk_pd_alive", CLKGATE_CON(14), 5),
+	RK_GATE(RK3288_PCLK_GPIO6, "pclk_gpio6", "pclk_pd_alive", CLKGATE_CON(14), 6),
+	RK_GATE(RK3288_PCLK_GPIO7, "pclk_gpio7", "pclk_pd_alive", CLKGATE_CON(14), 7),
+	RK_GATE(RK3288_PCLK_GPIO8, "pclk_gpio8", "pclk_pd_alive", CLKGATE_CON(14), 8),
+	RK_GATE(RK3288_PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", CLKGATE_CON(17), 4),
+};
+
+static int
+rk3288_cru_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct fdt_attach_args * const faa = aux;
+
+	return of_compatible_match(faa->faa_phandle, compat_data);
+}
+
+static void
+rk3288_cru_attach(device_t parent, device_t self, void *aux)
+{
+	struct rk_cru_softc * const sc = device_private(self);
+	struct fdt_attach_args * const faa = aux;
+
+	sc->sc_dev = self;
+	sc->sc_phandle = faa->faa_phandle;
+	sc->sc_bst = faa->faa_bst;
+
+	sc->sc_clks = rk3288_cru_clks;
+	sc->sc_nclks = __arraycount(rk3288_cru_clks);
+
+	sc->sc_grf_soc_status = 0x0284;
+	sc->sc_softrst_base = SOFTRST_CON(0);
+
+	if (rk_cru_attach(sc) != 0)
+		return;
+
+	aprint_naive("\n");
+	aprint_normal(": RK3288 CRU\n");
+
+	rk_cru_print(sc);
+}
Index: src/sys/arch/arm/rockchip/rk3288_cru.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3288_cru.h:1.1
--- /dev/null	Fri Nov 12 22:02:08 2021
+++ src/sys/arch/arm/rockchip/rk3288_cru.h	Fri Nov 12 22:02:08 2021
@@ -0,0 +1,209 @@
+/* $NetBSD: rk3288_cru.h,v 1.1 2021/11/12 22:02:08 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RK3328_CRU_H
+#define _RK3328_CRU_H
+
+#define  RK3288_PLL_APLL                            1
+#define  RK3288_PLL_DPLL                            2
+#define  RK3288_PLL_CPLL                            3
+#define  RK3288_PLL_GPLL                            4
+#define  RK3288_PLL_NPLL                            5
+#define  RK3288_ARMCLK                              6
+#define  RK3288_SCLK_GPU                            64
+#define  RK3288_SCLK_SPI0                           65
+#define  RK3288_SCLK_SPI1                           66
+#define  RK3288_SCLK_SPI2                           67
+#define  RK3288_SCLK_SDMMC                          68
+#define  RK3288_SCLK_SDIO0                          69
+#define  RK3288_SCLK_SDIO1                          70
+#define  RK3288_SCLK_EMMC                           71
+#define  RK3288_SCLK_TSADC                          72
+#define  RK3288_SCLK_SARADC                         73
+#define  RK3288_SCLK_PS2C                           74
+#define  RK3288_SCLK_NANDC0                         75
+#define  RK3288_SCLK_NANDC1                         76
+#define  RK3288_SCLK_UART0                          77
+#define  RK3288_SCLK_UART1                          78
+#define  RK3288_SCLK_UART2                          79
+#define  RK3288_SCLK_UART3                          80
+#define  RK3288_SCLK_UART4                          81
+#define  RK3288_SCLK_I2S0                           82
+#define  RK3288_SCLK_SPDIF                          83
+#define  RK3288_SCLK_SPDIF8CH                       84
+#define  RK3288_SCLK_TIMER0                         85
+#define  RK3288_SCLK_TIMER1                         86
+#define  RK3288_SCLK_TIMER2                         87
+#define  RK3288_SCLK_TIMER3                         88
+#define  RK3288_SCLK_TIMER4                         89
+#define  RK3288_SCLK_TIMER5                         90
+#define  RK3288_SCLK_TIMER6                         91
+#define  RK3288_SCLK_HSADC                          92
+#define  RK3288_SCLK_OTGPHY0                        93
+#define  RK3288_SCLK_OTGPHY1                        94
+#define  RK3288_SCLK_OTGPHY2                        95
+#define  RK3288_SCLK_OTG_ADP                        96
+#define  RK3288_SCLK_HSICPHY480M                    97
+#define  RK3288_SCLK_HSICPHY12M                     98
+#define  RK3288_SCLK_MACREF                         99
+#define  RK3288_SCLK_LCDC_PWM0                      100
+#define  RK3288_SCLK_LCDC_PWM1                      101
+#define  RK3288_SCLK_MAC_RX                         102
+#define  RK3288_SCLK_MAC_TX                         103
+#define  RK3288_SCLK_EDP_24M                        104
+#define  RK3288_SCLK_EDP                            105
+#define  RK3288_SCLK_RGA                            106
+#define  RK3288_SCLK_ISP                            107
+#define  RK3288_SCLK_ISP_JPE                        108
+#define  RK3288_SCLK_HDMI_HDCP                      109
+#define  RK3288_SCLK_HDMI_CEC                       110
+#define  RK3288_SCLK_HEVC_CABAC                     111
+#define  RK3288_SCLK_HEVC_CORE                      112
+#define  RK3288_SCLK_I2S0_OUT                       113
+#define  RK3288_SCLK_SDMMC_DRV                      114
+#define  RK3288_SCLK_SDIO0_DRV                      115
+#define  RK3288_SCLK_SDIO1_DRV                      116
+#define  RK3288_SCLK_EMMC_DRV                       117
+#define  RK3288_SCLK_SDMMC_SAMPLE                   118
+#define  RK3288_SCLK_SDIO0_SAMPLE                   119
+#define  RK3288_SCLK_SDIO1_SAMPLE                   120
+#define  RK3288_SCLK_EMMC_SAMPLE                    121
+#define  RK3288_SCLK_USBPHY480M_SRC                 122
+#define  RK3288_SCLK_PVTM_CORE                      123
+#define  RK3288_SCLK_PVTM_GPU                       124
+#define  RK3288_SCLK_CRYPTO                         125
+#define  RK3288_SCLK_MIPIDSI_24M                    126
+#define  RK3288_SCLK_VIP_OUT                        127
+#define  RK3288_SCLK_MAC                            151
+#define  RK3288_SCLK_MACREF_OUT                     152
+#define  RK3288_DCLK_VOP0                           190
+#define  RK3288_DCLK_VOP1                           191
+#define  RK3288_ACLK_GPU                            192
+#define  RK3288_ACLK_DMAC1                          193
+#define  RK3288_ACLK_DMAC2                          194
+#define  RK3288_ACLK_MMU                            195
+#define  RK3288_ACLK_GMAC                           196
+#define  RK3288_ACLK_VOP0                           197
+#define  RK3288_ACLK_VOP1                           198
+#define  RK3288_ACLK_CRYPTO                         199
+#define  RK3288_ACLK_RGA                            200
+#define  RK3288_ACLK_RGA_NIU                        201
+#define  RK3288_ACLK_IEP                            202
+#define  RK3288_ACLK_VIO0_NIU                       203
+#define  RK3288_ACLK_VIP                            204
+#define  RK3288_ACLK_ISP                            205
+#define  RK3288_ACLK_VIO1_NIU                       206
+#define  RK3288_ACLK_HEVC                           207
+#define  RK3288_ACLK_VCODEC                         208
+#define  RK3288_ACLK_CPU                            209
+#define  RK3288_ACLK_PERI                           210
+#define  RK3288_PCLK_GPIO0                          320
+#define  RK3288_PCLK_GPIO1                          321
+#define  RK3288_PCLK_GPIO2                          322
+#define  RK3288_PCLK_GPIO3                          323
+#define  RK3288_PCLK_GPIO4                          324
+#define  RK3288_PCLK_GPIO5                          325
+#define  RK3288_PCLK_GPIO6                          326
+#define  RK3288_PCLK_GPIO7                          327
+#define  RK3288_PCLK_GPIO8                          328
+#define  RK3288_PCLK_GRF                            329
+#define  RK3288_PCLK_SGRF                           330
+#define  RK3288_PCLK_PMU                            331
+#define  RK3288_PCLK_I2C0                           332
+#define  RK3288_PCLK_I2C1                           333
+#define  RK3288_PCLK_I2C2                           334
+#define  RK3288_PCLK_I2C3                           335
+#define  RK3288_PCLK_I2C4                           336
+#define  RK3288_PCLK_I2C5                           337
+#define  RK3288_PCLK_SPI0                           338
+#define  RK3288_PCLK_SPI1                           339
+#define  RK3288_PCLK_SPI2                           340
+#define  RK3288_PCLK_UART0                          341
+#define  RK3288_PCLK_UART1                          342
+#define  RK3288_PCLK_UART2                          343
+#define  RK3288_PCLK_UART3                          344
+#define  RK3288_PCLK_UART4                          345
+#define  RK3288_PCLK_TSADC                          346
+#define  RK3288_PCLK_SARADC                         347
+#define  RK3288_PCLK_SIM                            348
+#define  RK3288_PCLK_GMAC                           349
+#define  RK3288_PCLK_PWM                            350
+#define  RK3288_PCLK_RKPWM                          351
+#define  RK3288_PCLK_PS2C                           352
+#define  RK3288_PCLK_TIMER                          353
+#define  RK3288_PCLK_TZPC                           354
+#define  RK3288_PCLK_EDP_CTRL                       355
+#define  RK3288_PCLK_MIPI_DSI0                      356
+#define  RK3288_PCLK_MIPI_DSI1                      357
+#define  RK3288_PCLK_MIPI_CSI                       358
+#define  RK3288_PCLK_LVDS_PHY                       359
+#define  RK3288_PCLK_HDMI_CTRL                      360
+#define  RK3288_PCLK_VIO2_H2P                       361
+#define  RK3288_PCLK_CPU                            362
+#define  RK3288_PCLK_PERI                           363
+#define  RK3288_PCLK_DDRUPCTL0                      364
+#define  RK3288_PCLK_PUBL0                          365
+#define  RK3288_PCLK_DDRUPCTL1                      366
+#define  RK3288_PCLK_PUBL1                          367
+#define  RK3288_PCLK_WDT                            368
+#define  RK3288_PCLK_EFUSE256                       369
+#define  RK3288_PCLK_EFUSE1024                      370
+#define  RK3288_PCLK_ISP_IN                         371
+#define  RK3288_HCLK_GPS                            448
+#define  RK3288_HCLK_OTG0                           449
+#define  RK3288_HCLK_USBHOST0                       450
+#define  RK3288_HCLK_USBHOST1                       451
+#define  RK3288_HCLK_HSIC                           452
+#define  RK3288_HCLK_NANDC0                         453
+#define  RK3288_HCLK_NANDC1                         454
+#define  RK3288_HCLK_TSP                            455
+#define  RK3288_HCLK_SDMMC                          456
+#define  RK3288_HCLK_SDIO0                          457
+#define  RK3288_HCLK_SDIO1                          458
+#define  RK3288_HCLK_EMMC                           459
+#define  RK3288_HCLK_HSADC                          460
+#define  RK3288_HCLK_CRYPTO                         461
+#define  RK3288_HCLK_I2S0                           462
+#define  RK3288_HCLK_SPDIF                          463
+#define  RK3288_HCLK_SPDIF8CH                       464
+#define  RK3288_HCLK_VOP0                           465
+#define  RK3288_HCLK_VOP1                           466
+#define  RK3288_HCLK_ROM                            467
+#define  RK3288_HCLK_IEP                            468
+#define  RK3288_HCLK_ISP                            469
+#define  RK3288_HCLK_RGA                            470
+#define  RK3288_HCLK_VIO_AHB_ARBI                   471
+#define  RK3288_HCLK_VIO_NIU                        472
+#define  RK3288_HCLK_VIP                            473
+#define  RK3288_HCLK_VIO2_H2P                       474
+#define  RK3288_HCLK_HEVC                           475
+#define  RK3288_HCLK_VCODEC                         476
+#define  RK3288_HCLK_CPU                            477
+#define  RK3288_HCLK_PERI                           478
+
+#endif /* !_RK3328_CRU_H */
Index: src/sys/arch/arm/rockchip/rk3288_iomux.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3288_iomux.c:1.1
--- /dev/null	Fri Nov 12 22:02:08 2021
+++ src/sys/arch/arm/rockchip/rk3288_iomux.c	Fri Nov 12 22:02:08 2021
@@ -0,0 +1,367 @@
+/* $NetBSD: rk3288_iomux.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rk3288_iomux.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/mutex.h>
+#include <sys/kmem.h>
+#include <sys/lwp.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/syscon.h>
+
+#define	GPIO_P_CTL_Z		0
+#define	GPIO_P_CTL_PULLUP	1
+#define	GPIO_P_CTL_PULLDOWN	2
+#define	GPIO_P_CTL_MASK		0x3U
+
+#define	GPIO_E_CTL_2MA		0
+#define	GPIO_E_CTL_4MA		1
+#define	GPIO_E_CTL_8MA		2
+#define	GPIO_E_CTL_12MA		3
+#define	GPIO_E_CTL_MASK		0x3U
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "rockchip,rk3288-pinctrl" },
+	DEVICE_COMPAT_EOL
+};
+
+struct rk3288_iomux_softc {
+	device_t sc_dev;
+	struct syscon *sc_grf;
+	struct syscon *sc_pmu;
+};
+
+struct rk3288_iomux_reg {
+	struct syscon	*syscon;
+	int		mux_reg;
+	uint32_t	mux_bit;
+	int		pull_reg;
+	uint32_t	pull_bit;
+	int		drv_reg;
+	uint32_t	drv_bit;
+	uint32_t	flags;
+#define	IOMUX_NOROUTE	__BIT(0)
+#define	IOMUX_4BIT	__BIT(1)
+};
+
+#define	LOCK(reg)		\
+	syscon_lock((reg)->syscon)
+#define	UNLOCK(reg)		\
+	syscon_unlock((reg)->syscon)
+#define	RD4(reg, off)		\
+	syscon_read_4((reg)->syscon, (off))
+#define	WR4(reg, off, val)	\
+	syscon_write_4((reg)->syscon, (off), (val))
+
+static int	rk3288_iomux_match(device_t, cfdata_t, void *);
+static void	rk3288_iomux_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(rk3288_iomux, sizeof(struct rk3288_iomux_softc),
+	rk3288_iomux_match, rk3288_iomux_attach, NULL, NULL);
+
+#define	NBANKS		9
+#define	NPINSPERBANK	32
+
+static uint32_t rk3288_iomux_flags[NBANKS][NPINSPERBANK / 8] = {
+	[0] = { 0, 0, 0, IOMUX_NOROUTE },
+	[1] = { IOMUX_NOROUTE, IOMUX_NOROUTE, IOMUX_NOROUTE, 0 },
+	[2] = { 0, 0, 0, IOMUX_NOROUTE },
+	[3] = { 0, 0, 0, IOMUX_4BIT },
+	[4] = { IOMUX_4BIT, IOMUX_4BIT, 0, 0 },
+	[5] = { IOMUX_NOROUTE, 0, 0, IOMUX_NOROUTE },
+	[6] = { 0, 0, 0, IOMUX_NOROUTE },
+	[7] = { 0, 0, IOMUX_4BIT, IOMUX_NOROUTE },
+	[8] = { 0, 0, IOMUX_NOROUTE, IOMUX_NOROUTE }
+};
+
+static int rk3288_iomux_offset[NBANKS][NPINSPERBANK / 8] = {
+	/* PMU offsets */
+	[0] = { 0x84, 0x88, 0x8c, -1 },
+	/* GRF offsets */
+	[1] = { -1, -1, -1, 0x0c },
+	[2] = { 0x10, 0x14, 0x18, -1 },
+	[3] = { 0x20, 0x24, 0x28, 0x2c },
+	[4] = { 0x34, 0x3c, 0x44, 0x48 },
+	[5] = { -1, 0x50, 0x54, -1 },
+	[6] = { 0x5c, 0x60, 0x64, -1 },
+	[7] = { 0x6c, 0x70, 0x74, -1 },
+	[8] = { 0x80, 0x84, -1, -1 },
+};
+
+static bool
+rk3288_iomux_get_reg(struct rk3288_iomux_softc *sc, u_int bank, u_int idx,
+    struct rk3288_iomux_reg *reg)
+{
+	if (bank >= NBANKS || idx >= NPINSPERBANK) {
+		return false;
+	}
+
+	if (bank == 0) {
+		reg->syscon = sc->sc_pmu;
+		reg->pull_reg = 0x64 + (idx / 8) * 4;
+		reg->pull_bit = idx % 8 * 2;
+		reg->drv_reg = 0x70 + (idx / 8) * 4;
+		reg->drv_bit = idx % 8 * 2;
+	} else {
+		reg->syscon = sc->sc_grf;
+		reg->pull_reg = 0x130 + (bank * 0x10) + (idx / 8) * 4;
+		reg->pull_bit = idx % 8 * 2;
+		reg->drv_reg = 0x1b0 + (bank * 0x10) + (idx / 8) * 4;
+		reg->drv_bit = idx % 8 * 2;
+	}
+	reg->flags = rk3288_iomux_flags[bank][idx / 8];
+	reg->mux_reg = rk3288_iomux_offset[bank][idx / 8];
+	if (reg->mux_reg != -1) {
+		if ((reg->flags & IOMUX_4BIT) == 0) {
+			reg->mux_bit = idx % 8 * 2;
+		} else {
+			reg->mux_bit = idx % 4 * 4;
+			if ((idx % 8) >= 4) {
+				reg->mux_reg += 0x4;
+			}
+		}
+	}
+
+	return true;
+}
+
+static void
+rk3288_iomux_set_bias(struct rk3288_iomux_softc *sc, struct rk3288_iomux_reg *reg,
+    int bias)
+{
+	uint32_t val;
+	u_int p;
+
+	switch (bias) {
+	case 0:
+		p = GPIO_P_CTL_Z;
+		break;
+	case GPIO_PIN_PULLUP:
+		p = GPIO_P_CTL_PULLUP;
+		break;
+	case GPIO_PIN_PULLDOWN:
+		p = GPIO_P_CTL_PULLDOWN;
+		break;
+	default:
+		return;
+	}
+
+	val = GPIO_P_CTL_MASK << (reg->pull_bit + 16);
+	val |= p << reg->pull_bit;
+
+#ifdef RK3288_IOMUX_DEBUG
+	const uint32_t oval = RD4(reg, reg->pull_reg);
+	printf("%s: wr %#x -> %#x (%#x)\n", __func__,
+	    oval & (GPIO_P_CTL_MASK << reg->pull_bit),
+	    val & 0xffff,
+	    GPIO_P_CTL_MASK << reg->pull_bit);
+#endif
+
+	WR4(reg, reg->pull_reg, val);
+}
+
+static void
+rk3288_iomux_set_drive_strength(struct rk3288_iomux_softc *sc,
+    struct rk3288_iomux_reg *reg, int drv)
+{
+	uint32_t val;
+	u_int e;
+
+	switch (drv) {
+	case 2:
+		e = GPIO_E_CTL_2MA;
+		break;
+	case 4:
+		e = GPIO_E_CTL_4MA;
+		break;
+	case 8:
+		e = GPIO_E_CTL_8MA;
+		break;
+	case 12:
+		e = GPIO_E_CTL_12MA;
+		break;
+	default:
+		return;
+	}
+
+	val = GPIO_E_CTL_MASK << (reg->drv_bit + 16);
+	val |= e << reg->drv_bit;
+	WR4(reg, reg->drv_reg, val);
+}
+
+static void
+rk3288_iomux_set_mux(struct rk3288_iomux_softc *sc,
+    struct rk3288_iomux_reg *reg, u_int mux)
+{
+	uint32_t val;
+
+	KASSERT(reg->mux_reg != -1);
+
+	val = ((reg->flags & IOMUX_4BIT) ? 0xf : 0x3) << (reg->mux_bit + 16);
+	val |= mux << reg->mux_bit;
+
+	WR4(reg, reg->mux_reg, val);
+}
+
+static void
+rk3288_iomux_config(struct rk3288_iomux_softc *sc, struct rk3288_iomux_reg *reg,
+    u_int mux, const int phandle)
+{
+	int bias, drv;
+
+	bias = fdtbus_pinctrl_parse_bias(phandle, NULL);
+	drv = fdtbus_pinctrl_parse_drive_strength(phandle);
+
+#ifdef RK3288_IOMUX_DEBUG
+	printf("  -> %s mux %#x/%d, pull %#x/%d, drv %#x/%d, flags %#x\n",
+	    reg->syscon == sc->sc_pmu ? "pmu" : "grf",
+	    reg->mux_reg, reg->mux_bit,
+	    reg->pull_reg, reg->pull_bit,
+	    reg->drv_reg, reg->drv_bit,
+	    reg->flags);
+	printf("     bias %d drv %d mux %u\n", bias, drv, mux);
+#endif
+
+	/* XXX
+	 * ASUS Tinkerboard goes nuts if we update any PMU bias fields.
+	 * Skip them until we figure out why.
+	 */
+	if (reg->syscon == sc->sc_pmu) {
+		bias = -1;
+	}
+
+	LOCK(reg);
+
+	if (bias != -1) {
+		rk3288_iomux_set_bias(sc, reg, bias);
+	}
+	if (drv != -1) {
+		rk3288_iomux_set_drive_strength(sc, reg, drv);
+	}
+	if ((reg->flags & IOMUX_NOROUTE) == 0) {
+		rk3288_iomux_set_mux(sc, reg, mux);
+	}
+
+	UNLOCK(reg);
+}
+
+static int
+rk3288_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len)
+{
+	struct rk3288_iomux_softc * const sc = device_private(dev);
+	int pins_len = 0;
+
+	if (len != 4) {
+		return -1;
+	}
+
+	const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
+	const u_int *pins = fdtbus_get_prop(phandle, "rockchip,pins", &pins_len);
+
+	while (pins_len >= 16) {
+		const u_int bank = be32toh(pins[0]);
+		const u_int idx = be32toh(pins[1]);
+		const u_int mux = be32toh(pins[2]);
+		const int cfg = fdtbus_get_phandle_from_native(be32toh(pins[3]));
+		struct rk3288_iomux_reg regdef = {};
+
+		if (rk3288_iomux_get_reg(sc, bank, idx, &regdef)) {
+#ifdef RK3288_IOMUX_DEBUG
+			printf(" -> gpio%u P%c%u (%u)\n", bank, 'A' + (idx / 8), idx % 8, idx);
+#endif
+			rk3288_iomux_config(sc, &regdef, mux, cfg);
+		} else {
+			aprint_error_dev(dev, "unsupported iomux bank %u idx %u\n",
+			    bank, mux);
+		}
+
+		pins_len -= 16;
+		pins += 4;
+	}
+
+	return 0;
+}
+
+static struct fdtbus_pinctrl_controller_func rk3288_iomux_pinctrl_funcs = {
+	.set_config = rk3288_iomux_pinctrl_set_config,
+};
+
+static int
+rk3288_iomux_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct fdt_attach_args * const faa = aux;
+
+	return of_compatible_match(faa->faa_phandle, compat_data);
+}
+
+static void
+rk3288_iomux_attach(device_t parent, device_t self, void *aux)
+{
+	struct rk3288_iomux_softc * const sc = device_private(self);
+	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+
+	sc->sc_dev = self;
+	sc->sc_grf = fdtbus_syscon_acquire(phandle, "rockchip,grf");
+	if (sc->sc_grf == NULL) {
+		aprint_error(": couldn't acquire grf syscon\n");
+		return;
+	}
+	sc->sc_pmu = fdtbus_syscon_acquire(phandle, "rockchip,pmu");
+	if (sc->sc_pmu == NULL) {
+		aprint_error(": couldn't acquire pmu syscon\n");
+		return;
+	}
+
+	aprint_naive("\n");
+	aprint_normal(": RK3288 IOMUX control\n");
+
+	for (int child = OF_child(phandle); child; child = OF_peer(child)) {
+		for (int sub = OF_child(child); sub; sub = OF_peer(sub)) {
+			if (!of_hasprop(sub, "rockchip,pins"))
+				continue;
+			fdtbus_register_pinctrl_config(self, sub, &rk3288_iomux_pinctrl_funcs);
+		}
+	}
+
+	for (int child = OF_child(phandle); child; child = OF_peer(child)) {
+		struct fdt_attach_args cfaa = *faa;
+		cfaa.faa_phandle = child;
+		cfaa.faa_name = fdtbus_get_string(child, "name");
+		cfaa.faa_quiet = false;
+
+		config_found(self, &cfaa, NULL, CFARGS_NONE);
+	}
+}
Index: src/sys/arch/arm/rockchip/rk3288_platform.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3288_platform.h:1.1
--- /dev/null	Fri Nov 12 22:02:08 2021
+++ src/sys/arch/arm/rockchip/rk3288_platform.h	Fri Nov 12 22:02:08 2021
@@ -0,0 +1,40 @@
+/* $NetBSD: rk3288_platform.h,v 1.1 2021/11/12 22:02:08 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_RK3288_PLATFORM_H
+#define _ARM_RK3288_PLATFORM_H
+
+#include <arch/evbarm/fdt/platform.h>
+
+#define	RK3288_CORE_VBASE	KERNEL_IO_VBASE
+#define	RK3288_CORE_PBASE	0xff000000
+#define	RK3288_CORE_SIZE	0x01000000
+
+#define	RK3288_UART_FREQ	24000000
+
+#endif /* _ARM_RK3288_PLATFORM_H */
Index: src/sys/arch/arm/rockchip/rk3288_usb.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3288_usb.c:1.1
--- /dev/null	Fri Nov 12 22:02:08 2021
+++ src/sys/arch/arm/rockchip/rk3288_usb.c	Fri Nov 12 22:02:08 2021
@@ -0,0 +1,183 @@
+/* $NetBSD: rk3288_usb.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(0, "$NetBSD: rk3288_usb.c,v 1.1 2021/11/12 22:02:08 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/syscon.h>
+
+#define	GRF_UOCn_CON0_SIDDQ	__BIT(13)
+
+static int rk3288_usb_match(device_t, cfdata_t, void *);
+static void rk3288_usb_attach(device_t, device_t, void *);
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "rockchip,rk3288-usb-phy" },
+	DEVICE_COMPAT_EOL
+};
+
+CFATTACH_DECL_NEW(rk3288_usb, 0,
+	rk3288_usb_match, rk3288_usb_attach, NULL, NULL);
+
+static int
+rk3288_usb_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct fdt_attach_args * const faa = aux;
+
+	return of_compatible_match(faa->faa_phandle, compat_data);
+}
+
+static void
+rk3288_usb_attach(device_t parent, device_t self, void *aux)
+{
+	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+	int child;
+
+	aprint_naive("\n");
+	aprint_normal(": USB PHY\n");
+
+	for (child = OF_child(phandle); child; child = OF_peer(child)) {
+		if (!fdtbus_status_okay(child))
+			continue;
+
+		struct fdt_attach_args cfaa = *faa;
+		cfaa.faa_phandle = child;
+		cfaa.faa_name = fdtbus_get_string(child, "name");
+		cfaa.faa_quiet = false;
+
+		config_found(self, &cfaa, NULL, CFARGS_NONE);
+	}
+}
+
+/*
+ * USB PHY
+ */
+
+static int rk3288_usbphy_match(device_t, cfdata_t, void *);
+static void rk3288_usbphy_attach(device_t, device_t, void *);
+
+struct rk3288_usbphy_softc {
+	device_t	sc_dev;
+	int		sc_phandle;
+	struct syscon	*sc_syscon;
+	bus_addr_t	sc_reg;
+};
+
+CFATTACH_DECL_NEW(rk3288_usbphy, sizeof(struct rk3288_usbphy_softc),
+	rk3288_usbphy_match, rk3288_usbphy_attach, NULL, NULL);
+
+static void *
+rk3288_usbphy_acquire(device_t dev, const void *data, size_t len)
+{
+	struct rk3288_usbphy_softc * const sc = device_private(dev);
+
+	if (len != 0)
+		return NULL;
+
+	return sc;
+}
+
+static void
+rk3288_usbphy_release(device_t dev, void *priv)
+{
+}
+
+static int
+rk3288_usbphy_enable(device_t dev, void *priv, bool enable)
+{
+	struct rk3288_usbphy_softc * const sc = device_private(dev);
+	uint32_t write_mask, write_val;
+
+	write_mask = GRF_UOCn_CON0_SIDDQ << 16;
+	write_val = enable ? 0 : GRF_UOCn_CON0_SIDDQ;
+
+	syscon_lock(sc->sc_syscon);
+	syscon_write_4(sc->sc_syscon, sc->sc_reg, write_mask | write_val);
+	syscon_unlock(sc->sc_syscon);
+
+	return 0;
+}
+
+const struct fdtbus_phy_controller_func rk3288_usbphy_funcs = {
+	.acquire = rk3288_usbphy_acquire,
+	.release = rk3288_usbphy_release,
+	.enable = rk3288_usbphy_enable,
+};
+
+static int
+rk3288_usbphy_match(device_t parent, cfdata_t cf, void *aux)
+{
+	return 1;
+}
+
+static void
+rk3288_usbphy_attach(device_t parent, device_t self, void *aux)
+{
+	struct rk3288_usbphy_softc * const sc = device_private(self);
+	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+	struct fdtbus_reset *rst;
+
+	sc->sc_dev = self;
+	sc->sc_phandle = phandle;
+	sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(OF_parent(phandle)));
+	if (sc->sc_syscon == NULL) {
+		aprint_error(": couldn't find syscon\n");
+		return;
+	}
+	if (fdtbus_get_reg(phandle, 0, &sc->sc_reg, NULL) != 0) {
+		aprint_error(": couldn't find registers\n");
+		return;
+	}
+
+	rst = fdtbus_reset_get(phandle, "phy-reset");
+	if (rst == NULL || fdtbus_reset_deassert(rst) != 0) {
+		aprint_error(": couldn't de-assert reset\n");
+		return;
+	}
+	if (fdtbus_clock_enable(phandle, "phyclk", true) != 0) {
+		aprint_error(": couildn't enable clock\n");
+		return;
+	}
+
+	aprint_naive("\n");
+	aprint_normal(": USB port\n");
+
+	fdtbus_register_phy_controller(self, phandle, &rk3288_usbphy_funcs);
+}

Reply via email to