Module Name: src
Committed By: jmcneill
Date: Sat Jun 16 00:19:04 UTC 2018
Modified Files:
src/sys/arch/evbarm/conf: GENERIC64 files.generic64
src/sys/dev/fdt: files.fdt
Added Files:
src/sys/arch/arm/rockchip: files.rockchip rk3328_cru.c rk3328_cru.h
rk3328_platform.h rk_cru.c rk_cru.h rk_cru_arm.c rk_cru_composite.c
rk_cru_gate.c rk_cru_mux.c rk_cru_pll.c rk_gmac.c rk_gpio.c
rk_iomux.c rk_platform.c rk_usb.c
src/sys/dev/fdt: dwc2_fdt.c dwcmmc_fdt.c
Log Message:
Add initial support for Rockchip RK3328 SoC.
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.13 src/sys/arch/arm/rockchip/files.rockchip
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/rockchip/rk3328_cru.c \
src/sys/arch/arm/rockchip/rk3328_cru.h \
src/sys/arch/arm/rockchip/rk3328_platform.h \
src/sys/arch/arm/rockchip/rk_cru.c src/sys/arch/arm/rockchip/rk_cru.h \
src/sys/arch/arm/rockchip/rk_cru_arm.c \
src/sys/arch/arm/rockchip/rk_cru_composite.c \
src/sys/arch/arm/rockchip/rk_cru_gate.c \
src/sys/arch/arm/rockchip/rk_cru_mux.c \
src/sys/arch/arm/rockchip/rk_cru_pll.c \
src/sys/arch/arm/rockchip/rk_gmac.c src/sys/arch/arm/rockchip/rk_gpio.c \
src/sys/arch/arm/rockchip/rk_iomux.c \
src/sys/arch/arm/rockchip/rk_platform.c \
src/sys/arch/arm/rockchip/rk_usb.c
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/evbarm/conf/GENERIC64
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/evbarm/conf/files.generic64
cvs rdiff -u -r0 -r1.1 src/sys/dev/fdt/dwc2_fdt.c \
src/sys/dev/fdt/dwcmmc_fdt.c
cvs rdiff -u -r1.31 -r1.32 src/sys/dev/fdt/files.fdt
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/evbarm/conf/GENERIC64
diff -u src/sys/arch/evbarm/conf/GENERIC64:1.16 src/sys/arch/evbarm/conf/GENERIC64:1.17
--- src/sys/arch/evbarm/conf/GENERIC64:1.16 Thu Jun 14 10:56:39 2018
+++ src/sys/arch/evbarm/conf/GENERIC64 Sat Jun 16 00:19:04 2018
@@ -1,5 +1,5 @@
#
-# $NetBSD: GENERIC64,v 1.16 2018/06/14 10:56:39 jmcneill Exp $
+# $NetBSD: GENERIC64,v 1.17 2018/06/16 00:19:04 jmcneill Exp $
#
# GENERIC ARM (aarch64) kernel
#
@@ -14,10 +14,14 @@ include "arch/evbarm/conf/GENERIC.common
#
makeoptions DTSARCH="arm aarch64"
makeoptions DTSGNUARCH="arm arm64"
-makeoptions DTSSUBDIR="allwinner broadcom nvidia"
+makeoptions DTSSUBDIR="allwinner broadcom nvidia rockchip"
makeoptions DTS="
bcm2837-rpi-3-b.dts
+ rk3328-evb.dts
+ rk3328-roc-cc.dts
+ rk3328-rock64.dts
+
sun50i-a64-bananapi-m64.dts
sun50i-a64-nanopi-a64.dts
sun50i-a64-olinuxino.dts
@@ -45,6 +49,7 @@ makeoptions DTS="
options CPU_CORTEXA53
options CPU_CORTEXA57
options SOC_BCM2837
+options SOC_RK3328
options SOC_TEGRA210
options SOC_SUN50I_A64
options SOC_SUN50I_H5
@@ -62,6 +67,7 @@ options DEBUG
options VERBOSE_INIT_ARM # verbose bootstrapping messages
# EARLYCONS is required for early init messages from VERBOSE_INIT_ARM.
#options EARLYCONS=bcm2837
+options EARLYCONS=rk3328, CONSADDR=0xff130000
#options EARLYCONS=sunxi, CONSADDR=0x01c28000
#options EARLYCONS=tegra, CONSADDR=0x70006000
#options EARLYCONS=virt
@@ -131,6 +137,7 @@ tegrapmc* at fdt? pass 4 # NVIDIA Tegra
# Clock and Reset controller
bcmcprman* at fdt? pass 1 # Broadcom BCM283x Clock Manager
bcmaux* at fdt? pass 1 # Broadcom BCM283x Aux Periph Clocks
+rkcru* at fdt? pass 2 # Rockchip RK3328 CRU
sun8ih3ccu* at fdt? pass 2 # Allwinner H3/H5 CCU
sun8ih3rccu* at fdt? pass 2 # Allwinner H3/H5 CCU (PRCM)
sun50ia64ccu* at fdt? pass 2 # Allwinner A64 CCU
@@ -146,12 +153,14 @@ tegra210car* at fdt? pass 3 # NVIDIA Te
bcmgpio* at fdt? # Broadcom BCM283x GPIO
sunxigpio* at fdt? pass 3 # Allwinner GPIO
tegragpio* at fdt? pass 2 # NVIDIA Tegra GPIO
+rkgpio* at rkiomux? # Rockchip GPIO
gpio* at gpiobus?
# PWM controller
sunxipwm* at fdt? pass 3 # Allwinner PWM
# MPIO / Pinmux
+rkiomux* at fdt? pass 2 # Rockchip IOMUX
tegrapinmux* at fdt? # NVIDIA Tegra MPIO
# XUSB PADCTL
@@ -165,6 +174,7 @@ ppb* at pci? dev ? function ?
pci* at ppb?
# Ethernet
+awge* at fdt? # DesignWare Gigabit Ethernet
emac* at fdt? # Allwinner Gigabit Ethernet (EMAC)
re* at pci? dev ? function ? # Realtek RTL8111GS
@@ -229,6 +239,7 @@ sunxirtc* at fdt? # Allwinner RTC
tegrartc* at fdt? # NVIDIA Tegra RTC
# SDMMC
+dwcmmc* at fdt? # Designware SD/MMC
mmcpwrseq* at fdt? # Simple MMC power sequence provider
sdhc* at fdt? # SD Host Controller Interface
sdhost* at fdt? # Broadcom BCM283x SD Host Interface
@@ -302,6 +313,8 @@ sunxithermal* at fdt? # Allwinner ther
tegrasoctherm* at fdt? # NVIDIA Tegra SOC_THERM
# USB
+rkusb* at fdt? pass 9 # Rockchip USB PHY
+rkusbphy* at rkusb?
sunxiusbphy* at fdt? pass 9 # Allwinner USB PHY
sunxiusb3phy* at fdt? pass 9 # Allwinner USB3 PHY
tegrausbphy* at fdt? # NVIDIA Tegra USB PHY
Index: src/sys/arch/evbarm/conf/files.generic64
diff -u src/sys/arch/evbarm/conf/files.generic64:1.2 src/sys/arch/evbarm/conf/files.generic64:1.3
--- src/sys/arch/evbarm/conf/files.generic64:1.2 Thu Jun 14 10:56:39 2018
+++ src/sys/arch/evbarm/conf/files.generic64 Sat Jun 16 00:19:04 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.generic64,v 1.2 2018/06/14 10:56:39 jmcneill Exp $
+# $NetBSD: files.generic64,v 1.3 2018/06/16 00:19:04 jmcneill Exp $
#
defparam opt_arm_debug.h EARLYCONS
@@ -12,5 +12,6 @@ include "arch/evbarm/conf/files.fdt"
#
include "arch/arm/broadcom/files.bcm2835"
include "arch/arm/nvidia/files.tegra"
+include "arch/arm/rockchip/files.rockchip"
include "arch/arm/sunxi/files.sunxi"
include "arch/arm/virt/files.virt"
Index: src/sys/dev/fdt/files.fdt
diff -u src/sys/dev/fdt/files.fdt:1.31 src/sys/dev/fdt/files.fdt:1.32
--- src/sys/dev/fdt/files.fdt:1.31 Fri Jun 15 19:52:01 2018
+++ src/sys/dev/fdt/files.fdt Sat Jun 16 00:19:04 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.fdt,v 1.31 2018/06/15 19:52:01 jakllsch Exp $
+# $NetBSD: files.fdt,v 1.32 2018/06/16 00:19:04 jmcneill Exp $
include "external/bsd/libfdt/conf/files.libfdt"
@@ -88,10 +88,18 @@ file dev/fdt/simplefb.c simplefb
attach com at fdt with dw_apb_uart
file dev/fdt/dw_apb_uart.c dw_apb_uart
+# Designware USB2 OTG
+attach dwctwo at fdt with dwc2_fdt
+file dev/fdt/dwc2_fdt.c dwc2_fdt
+
# Designware USB3 XHCI
attach xhci at fdt with dwc3_fdt
file dev/fdt/dwc3_fdt.c dwc3_fdt
+# Designware SD/MMC
+attach dwcmmc at fdt with dwcmmc_fdt
+file dev/fdt/dwcmmc_fdt.c dwcmmc_fdt
+
# Virtio virtio,mmio
attach virtio at fdt with virtio_mmio_fdt: virtio_mmio
file dev/fdt/virtio_mmio_fdt.c virtio_mmio_fdt
Added files:
Index: src/sys/arch/arm/rockchip/files.rockchip
diff -u /dev/null src/sys/arch/arm/rockchip/files.rockchip:1.13
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/files.rockchip Sat Jun 16 00:19:04 2018
@@ -0,0 +1,45 @@
+# $NetBSD: files.rockchip,v 1.13 2018/06/16 00:19:04 jmcneill Exp $
+#
+# Configuration info for Rockchip family SoCs
+#
+#
+
+file arch/arm/rockchip/rk_platform.c soc_rockchip
+
+# Clock and reset unit (CRU)
+device rkcru: rk_cru
+file arch/arm/rockchip/rk_cru.c rk_cru
+file arch/arm/rockchip/rk_cru_arm.c rk_cru
+file arch/arm/rockchip/rk_cru_composite.c rk_cru
+file arch/arm/rockchip/rk_cru_gate.c rk_cru
+file arch/arm/rockchip/rk_cru_mux.c rk_cru
+file arch/arm/rockchip/rk_cru_pll.c rk_cru
+
+# RK3328 clock and reset unit
+attach rkcru at fdt with rk3328_cru
+file arch/arm/rockchip/rk3328_cru.c rk3328_cru & soc_rk3328
+
+# IOMUX control
+device rkiomux { }
+attach rkiomux at fdt with rk_iomux
+file arch/arm/rockchip/rk_iomux.c rk_iomux
+
+# GPIO
+device rkgpio: gpiobus
+attach rkgpio at rkiomux with rk_gpio
+file arch/arm/rockchip/rk_gpio.c rk_gpio
+
+# USB PHY
+device rkusb { }
+attach rkusb at fdt with rk_usb
+device rkusbphy
+attach rkusbphy at rkusb with rk_usbphy
+file arch/arm/rockchip/rk_usb.c rk_usb | rk_usbphy
+
+# GMAC
+attach awge at fdt with rk_gmac
+file arch/arm/rockchip/rk_gmac.c rk_gmac
+
+# SOC parameters
+defflag opt_soc.h SOC_ROCKCHIP
+defflag opt_soc.h SOC_RK3328: SOC_ROCKCHIP
Index: src/sys/arch/arm/rockchip/rk3328_cru.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3328_cru.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk3328_cru.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,361 @@
+/* $NetBSD: rk3328_cru.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk3328_cru.c,v 1.1 2018/06/16 00:19:04 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/rk3328_cru.h>
+
+static int rk3328_cru_match(device_t, cfdata_t, void *);
+static void rk3328_cru_attach(device_t, device_t, void *);
+
+static const char * const compatible[] = {
+ "rockchip,rk3328-cru",
+ NULL
+};
+
+CFATTACH_DECL_NEW(rk3328_cru, sizeof(struct rk_cru_softc),
+ rk3328_cru_match, rk3328_cru_attach, NULL, NULL);
+
+static const struct rk_cru_pll_rate pll_rates[] = {
+ RK_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+ RK_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+ RK_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+ RK_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+ RK_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+ RK_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+ RK_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+ RK_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+ RK_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+ RK_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+ RK_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+ RK_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+ RK_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+ RK_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+ RK_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+ RK_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+ RK_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+ RK_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+ RK_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ RK_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+ RK_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+ RK_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+ RK_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+ RK_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+ RK_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+ RK_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+ RK_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+ RK_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+ RK_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+ RK_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
+ RK_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+ RK_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+ RK_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+ RK_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
+ RK_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+ RK_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+ RK_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+ RK_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+ RK_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+ RK_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
+};
+
+static const struct rk_cru_pll_rate pll_frac_rates[] = {
+ RK_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
+ RK_PLL_RATE( 983040000, 24, 983, 1, 1, 0, 671088),
+ RK_PLL_RATE( 491520000, 24, 983, 2, 1, 0, 671088),
+ RK_PLL_RATE( 61440000, 6, 215, 7, 2, 0, 671088),
+ RK_PLL_RATE( 56448000, 12, 451, 4, 4, 0, 9797894),
+ RK_PLL_RATE( 40960000, 12, 409, 4, 5, 0, 10066329),
+};
+
+static const struct rk_cru_pll_rate pll_norates[] = {
+};
+
+static const struct rk_cru_arm_rate armclk_rates[] = {
+ RK_ARM_RATE(1296000000, 1),
+ RK_ARM_RATE(1200000000, 1),
+ RK_ARM_RATE(1104000000, 1),
+ RK_ARM_RATE(1008000000, 1),
+ RK_ARM_RATE( 912000000, 1),
+ RK_ARM_RATE( 816000000, 1),
+ RK_ARM_RATE( 696000000, 1),
+ RK_ARM_RATE( 600000000, 1),
+ RK_ARM_RATE( 408000000, 1),
+ RK_ARM_RATE( 312000000, 1),
+ RK_ARM_RATE( 216000000, 1),
+ RK_ARM_RATE( 96000000, 1),
+};
+
+static const char * armclk_parents[] = { "apll", "gpll", "dpll", "npll" };
+static const char * aclk_bus_pre_parents[] = { "cpll", "gpll", "hdmiphy" };
+static const char * hclk_bus_pre_parents[] = { "aclk_bus_pre" };
+static const char * aclk_peri_pre_parents[] = { "cpll", "gpll", "hdmiphy" };
+static const char * mmc_parents[] = { "cpll", "gpll", "xin24m", "usb480m" };
+static const char * phclk_peri_parents[] = { "aclk_peri_pre" };
+static const char * mux_usb480m_parents[] = { "usb480m_phy", "xin24m" };
+static const char * mux_uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" };
+static const char * mux_uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" };
+static const char * mux_uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" };
+static const char * mux_mac2io_src_parents[] = { "clk_mac2io_src", "gmac_clkin" };
+static const char * mux_mac2io_ext_parents[] = { "clk_mac2io", "gmac_clkin" };
+static const char * mux_2plls_parents[] = { "cpll", "gpll" };
+static const char * mux_2plls_hdmiphy_parents[] = { "cpll", "gpll", "dummy_hdmiphy" };
+static const char * comp_uart_parents[] = { "cpll", "gpll", "usb480m" };
+static const char * pclk_gmac_parents[] = { "aclk_gmac" };
+
+static struct rk_cru_clk rk3328_cru_clks[] = {
+ RK_PLL(RK3328_PLL_APLL, "apll", "xin24m",
+ 0x0000, /* con_base */
+ 0x80, /* mode_reg */
+ __BIT(0), /* mode_mask */
+ __BIT(4), /* lock_mask */
+ pll_frac_rates),
+ RK_PLL(RK3328_PLL_DPLL, "dpll", "xin24m",
+ 0x0020, /* con_base */
+ 0x80, /* mode_reg */
+ __BIT(4), /* mode_mask */
+ __BIT(3), /* lock_mask */
+ pll_norates),
+ RK_PLL(RK3328_PLL_CPLL, "cpll", "xin24m",
+ 0x0040, /* con_base */
+ 0x80, /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(2), /* lock_mask */
+ pll_rates),
+ RK_PLL(RK3328_PLL_GPLL, "gpll", "xin24m",
+ 0x0060, /* con_base */
+ 0x80, /* mode_reg */
+ __BIT(12), /* mode_mask */
+ __BIT(1), /* lock_mask */
+ pll_frac_rates),
+ RK_PLL(RK3328_PLL_NPLL, "npll", "xin24m",
+ 0x00a0, /* con_base */
+ 0x80, /* mode_reg */
+ __BIT(1), /* mode_mask */
+ __BIT(0), /* lock_mask */
+ pll_rates),
+
+ RK_ARM(RK3328_ARMCLK, "armclk", armclk_parents,
+ 0x0100, /* reg */
+ __BITS(7,6), 3, 0, /* mux_mask, mux_main, mux_alt */
+ __BITS(4,0), /* div_mask */
+ armclk_rates),
+
+ RK_COMPOSITE(RK3328_ACLK_BUS_PRE, "aclk_bus_pre", aclk_bus_pre_parents,
+ 0x0100, /* muxdiv_reg */
+ __BITS(14,13), /* mux_mask */
+ __BITS(12,8), /* div_mask */
+ 0x0220, /* gate_reg */
+ __BIT(0), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_HCLK_BUS_PRE, "hclk_bus_pre", hclk_bus_pre_parents,
+ 0x0104, /* muxdiv_reg */
+ 0, /* mux_mask */
+ __BITS(9,8), /* div_mask */
+ 0x0220, /* gate_reg */
+ __BIT(1), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_PCLK_BUS_PRE, "pclk_bus_pre", hclk_bus_pre_parents,
+ 0x0104, /* muxdiv_reg */
+ 0, /* mux_mask */
+ __BITS(14,12), /* div_mask */
+ 0x0220, /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_ACLK_PERI_PRE, "aclk_peri_pre", aclk_peri_pre_parents,
+ 0x0170, /* muxdiv_reg */
+ __BITS(7,6), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ 0, 0, /* gate_reg, gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_PCLK_PERI, "pclk_peri", phclk_peri_parents,
+ 0x0174, /* muxdiv_reg */
+ 0, /* mux_mask */
+ __BITS(6,4), /* div_mask */
+ 0x0228, /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_HCLK_PERI, "hclk_peri", phclk_peri_parents,
+ 0x0174, /* muxdiv_reg */
+ 0, /* mux_mask */
+ __BITS(1,0), /* div_mask */
+ 0x0228, /* gate_reg */
+ __BIT(1), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_SCLK_SDMMC, "clk_sdmmc", mmc_parents,
+ 0x0178, /* muxdiv_reg */
+ __BITS(9,8), /* mux_mask */
+ __BITS(7,0), /* div_mask */
+ 0x0210, /* gate_reg */
+ __BIT(3), /* gate_mask */
+ RK_COMPOSITE_ROUND_DOWN),
+ RK_COMPOSITE(RK3328_SCLK_SDIO, "clk_sdio", mmc_parents,
+ 0x0180, /* muxdiv_reg */
+ __BITS(9,8), /* mux_mask */
+ __BITS(7,0), /* div_mask */
+ 0x0210, /* gate_reg */
+ __BIT(5), /* gate_mask */
+ RK_COMPOSITE_ROUND_DOWN),
+ RK_COMPOSITE(RK3328_SCLK_EMMC, "clk_emmc", mmc_parents,
+ 0x017c, /* muxdiv_reg */
+ __BITS(9,8), /* mux_mask */
+ __BITS(7,0), /* div_mask */
+ 0x0210, /* gate_reg */
+ __BIT(4), /* gate_mask */
+ RK_COMPOSITE_ROUND_DOWN),
+ RK_COMPOSITE(0, "clk_uart0_div", comp_uart_parents,
+ 0x0138, /* muxdiv_reg */
+ __BITS(13,12), /* mux_mask */
+ __BITS(6,0), /* div_mask */
+ 0x0204, /* gate_reg */
+ __BIT(14), /* gate_mask */
+ 0),
+ RK_COMPOSITE(0, "clk_uart1_div", comp_uart_parents,
+ 0x0140, /* muxdiv_reg */
+ __BITS(13,12), /* mux_mask */
+ __BITS(6,0), /* div_mask */
+ 0x0208, /* gate_reg */
+ __BIT(0), /* gate_mask */
+ 0),
+ RK_COMPOSITE(0, "clk_uart2_div", comp_uart_parents,
+ 0x0148, /* muxdiv_reg */
+ __BITS(13,12), /* mux_mask */
+ __BITS(6,0), /* div_mask */
+ 0x0208, /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_parents,
+ 0x018c, /* muxdiv_reg */
+ __BITS(7,6), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ 0x020c, /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_PCLK_GMAC, "pclk_gmac", pclk_gmac_parents,
+ 0x0164, /* muxdiv_reg */
+ 0, /* mux_mask */
+ __BITS(10,8), /* div_mask */
+ 0x0224, /* gate_reg */
+ __BIT(0), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_SCLK_MAC2IO_SRC, "clk_mac2io_src", mux_2plls_parents,
+ 0x016c, /* muxdiv_reg */
+ __BIT(7), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ 0x020c, /* gate_reg */
+ __BIT(1), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3328_SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_parents,
+ 0x016c, /* muxdiv_reg */
+ __BIT(15), /* mux_mask */
+ __BITS(12,8), /* div_mask */
+ 0x020c, /* gate_reg */
+ __BIT(5), /* gate_mask */
+ 0),
+
+ RK_GATE(0, "apll_core", "apll", 0x200, 0),
+ RK_GATE(0, "dpll_core", "dpll", 0x200, 1),
+ RK_GATE(0, "gpll_core", "gpll", 0x200, 2),
+ RK_GATE(0, "npll_core", "npll", 0x200, 12),
+ RK_GATE(0, "gpll_peri", "gpll", 0x210, 0),
+ RK_GATE(0, "cpll_peri", "cpll", 0x210, 1),
+ RK_GATE(0, "pclk_bus", "pclk_bus_pre", 0x220, 3),
+ RK_GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0x220, 4),
+ RK_GATE(RK3328_ACLK_PERI, "aclk_peri", "aclk_peri_pre", 0x228, 0),
+ RK_GATE(RK3328_PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0x240, 7),
+ RK_GATE(RK3328_PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0x240, 8),
+ RK_GATE(RK3328_PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0x240, 9),
+ RK_GATE(RK3328_PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0x240, 10),
+ RK_GATE(RK3328_PCLK_UART0, "pclk_uart0", "pclk_bus", 0x240, 11),
+ RK_GATE(RK3328_PCLK_UART1, "pclk_uart1", "pclk_bus", 0x240, 12),
+ RK_GATE(RK3328_PCLK_UART2, "pclk_uart2", "pclk_bus", 0x240, 13),
+ RK_GATE(RK3328_SCLK_MAC2IO_REF, "clk_mac2io_ref", "clk_mac2io", 0x224, 7),
+ RK_GATE(RK3328_SCLK_MAC2IO_RX, "clk_mac2io_rx", "clk_mac2io", 0x224, 4),
+ RK_GATE(RK3328_SCLK_MAC2IO_TX, "clk_mac2io_tx", "clk_mac2io", 0x224, 5),
+ RK_GATE(RK3328_SCLK_MAC2IO_REFOUT, "clk_mac2io_refout", "clk_mac2io", 0x224, 6),
+ RK_GATE(RK3328_ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0x24c, 4),
+ RK_GATE(RK3328_HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0x24c, 0),
+ RK_GATE(RK3328_HCLK_SDIO, "hclk_sdio", "hclk_peri", 0x24c, 1),
+ RK_GATE(RK3328_HCLK_EMMC, "hclk_emmc", "hclk_peri", 0x24c, 2),
+ RK_GATE(RK3328_HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0x24c, 15),
+ RK_GATE(RK3328_HCLK_HOST0, "hclk_host0", "hclk_peri", 0x24c, 6),
+ RK_GATE(RK3328_HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", 0x24c, 7),
+ RK_GATE(RK3328_HCLK_OTG, "hclk_otg", "hclk_peri", 0x24c, 8),
+ RK_GATE(RK3328_HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0x24c, 9),
+ RK_GATE(RK3328_ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0x268, 2),
+ RK_GATE(RK3328_PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0x268, 3),
+
+ RK_MUX(RK3328_USB480M, "usb480m", mux_usb480m_parents, 0x0084, __BIT(13)),
+ RK_MUX(RK3328_SCLK_UART0, "sclk_uart0", mux_uart0_parents, 0x0138, __BITS(9,8)),
+ RK_MUX(RK3328_SCLK_UART1, "sclk_uart1", mux_uart1_parents, 0x0140, __BITS(9,8)),
+ RK_MUX(RK3328_SCLK_UART2, "sclk_uart2", mux_uart2_parents, 0x0148, __BITS(9,8)),
+ RK_MUXGRF(RK3328_SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_parents, 0x0904, __BIT(10)),
+ RK_MUXGRF(RK3328_SCLK_MAC2IO_EXT, "clk_mac2io_ext", mux_mac2io_ext_parents, 0x0410, __BIT(14)),
+};
+
+static int
+rk3328_cru_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+rk3328_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 = rk3328_cru_clks;
+ sc->sc_nclks = __arraycount(rk3328_cru_clks);
+
+ if (rk_cru_attach(sc) != 0)
+ return;
+
+ aprint_naive("\n");
+ aprint_normal(": RK3328 CRU\n");
+
+ rk_cru_print(sc);
+}
Index: src/sys/arch/arm/rockchip/rk3328_cru.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3328_cru.h:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk3328_cru.h Sat Jun 16 00:19:04 2018
@@ -0,0 +1,213 @@
+/* $NetBSD: rk3328_cru.h,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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 RK3328_PLL_APLL 1
+#define RK3328_PLL_DPLL 2
+#define RK3328_PLL_CPLL 3
+#define RK3328_PLL_GPLL 4
+#define RK3328_PLL_NPLL 5
+#define RK3328_ARMCLK 6
+#define RK3328_SCLK_RTC32K 30
+#define RK3328_SCLK_SDMMC_EXT 31
+#define RK3328_SCLK_SPI 32
+#define RK3328_SCLK_SDMMC 33
+#define RK3328_SCLK_SDIO 34
+#define RK3328_SCLK_EMMC 35
+#define RK3328_SCLK_TSADC 36
+#define RK3328_SCLK_SARADC 37
+#define RK3328_SCLK_UART0 38
+#define RK3328_SCLK_UART1 39
+#define RK3328_SCLK_UART2 40
+#define RK3328_SCLK_I2S0 41
+#define RK3328_SCLK_I2S1 42
+#define RK3328_SCLK_I2S2 43
+#define RK3328_SCLK_I2S1_OUT 44
+#define RK3328_SCLK_I2S2_OUT 45
+#define RK3328_SCLK_SPDIF 46
+#define RK3328_SCLK_TIMER0 47
+#define RK3328_SCLK_TIMER1 48
+#define RK3328_SCLK_TIMER2 49
+#define RK3328_SCLK_TIMER3 50
+#define RK3328_SCLK_TIMER4 51
+#define RK3328_SCLK_TIMER5 52
+#define RK3328_SCLK_WIFI 53
+#define RK3328_SCLK_CIF_OUT 54
+#define RK3328_SCLK_I2C0 55
+#define RK3328_SCLK_I2C1 56
+#define RK3328_SCLK_I2C2 57
+#define RK3328_SCLK_I2C3 58
+#define RK3328_SCLK_CRYPTO 59
+#define RK3328_SCLK_PWM 60
+#define RK3328_SCLK_PDM 61
+#define RK3328_SCLK_EFUSE 62
+#define RK3328_SCLK_OTP 63
+#define RK3328_SCLK_DDRCLK 64
+#define RK3328_SCLK_VDEC_CABAC 65
+#define RK3328_SCLK_VDEC_CORE 66
+#define RK3328_SCLK_VENC_DSP 67
+#define RK3328_SCLK_VENC_CORE 68
+#define RK3328_SCLK_RGA 69
+#define RK3328_SCLK_HDMI_SFC 70
+#define RK3328_SCLK_HDMI_CEC 71
+#define RK3328_SCLK_USB3_REF 72
+#define RK3328_SCLK_USB3_SUSPEND 73
+#define RK3328_SCLK_SDMMC_DRV 74
+#define RK3328_SCLK_SDIO_DRV 75
+#define RK3328_SCLK_EMMC_DRV 76
+#define RK3328_SCLK_SDMMC_EXT_DRV 77
+#define RK3328_SCLK_SDMMC_SAMPLE 78
+#define RK3328_SCLK_SDIO_SAMPLE 79
+#define RK3328_SCLK_EMMC_SAMPLE 80
+#define RK3328_SCLK_SDMMC_EXT_SAMPLE 81
+#define RK3328_SCLK_VOP 82
+#define RK3328_SCLK_MAC2PHY_RXTX 83
+#define RK3328_SCLK_MAC2PHY_SRC 84
+#define RK3328_SCLK_MAC2PHY_REF 85
+#define RK3328_SCLK_MAC2PHY_OUT 86
+#define RK3328_SCLK_MAC2IO_RX 87
+#define RK3328_SCLK_MAC2IO_TX 88
+#define RK3328_SCLK_MAC2IO_REFOUT 89
+#define RK3328_SCLK_MAC2IO_REF 90
+#define RK3328_SCLK_MAC2IO_OUT 91
+#define RK3328_SCLK_TSP 92
+#define RK3328_SCLK_HSADC_TSP 93
+#define RK3328_SCLK_USB3PHY_REF 94
+#define RK3328_SCLK_REF_USB3OTG 95
+#define RK3328_SCLK_USB3OTG_REF 96
+#define RK3328_SCLK_USB3OTG_SUSPEND 97
+#define RK3328_SCLK_REF_USB3OTG_SRC 98
+#define RK3328_SCLK_MAC2IO_SRC 99
+#define RK3328_SCLK_MAC2IO 100
+#define RK3328_SCLK_MAC2PHY 101
+#define RK3328_SCLK_MAC2IO_EXT 102
+#define RK3328_DCLK_LCDC 120
+#define RK3328_DCLK_HDMIPHY 121
+#define RK3328_HDMIPHY 122
+#define RK3328_USB480M 123
+#define RK3328_DCLK_LCDC_SRC 124
+#define RK3328_ACLK_AXISRAM 130
+#define RK3328_ACLK_VOP_PRE 131
+#define RK3328_ACLK_USB3OTG 132
+#define RK3328_ACLK_RGA_PRE 133
+#define RK3328_ACLK_DMAC 134
+#define RK3328_ACLK_GPU 135
+#define RK3328_ACLK_BUS_PRE 136
+#define RK3328_ACLK_PERI_PRE 137
+#define RK3328_ACLK_RKVDEC_PRE 138
+#define RK3328_ACLK_RKVDEC 139
+#define RK3328_ACLK_RKVENC 140
+#define RK3328_ACLK_VPU_PRE 141
+#define RK3328_ACLK_VIO_PRE 142
+#define RK3328_ACLK_VPU 143
+#define RK3328_ACLK_VIO 144
+#define RK3328_ACLK_VOP 145
+#define RK3328_ACLK_GMAC 146
+#define RK3328_ACLK_H265 147
+#define RK3328_ACLK_H264 148
+#define RK3328_ACLK_MAC2PHY 149
+#define RK3328_ACLK_MAC2IO 150
+#define RK3328_ACLK_DCF 151
+#define RK3328_ACLK_TSP 152
+#define RK3328_ACLK_PERI 153
+#define RK3328_ACLK_RGA 154
+#define RK3328_ACLK_IEP 155
+#define RK3328_ACLK_CIF 156
+#define RK3328_ACLK_HDCP 157
+#define RK3328_PCLK_GPIO0 200
+#define RK3328_PCLK_GPIO1 201
+#define RK3328_PCLK_GPIO2 202
+#define RK3328_PCLK_GPIO3 203
+#define RK3328_PCLK_GRF 204
+#define RK3328_PCLK_I2C0 205
+#define RK3328_PCLK_I2C1 206
+#define RK3328_PCLK_I2C2 207
+#define RK3328_PCLK_I2C3 208
+#define RK3328_PCLK_SPI 209
+#define RK3328_PCLK_UART0 210
+#define RK3328_PCLK_UART1 211
+#define RK3328_PCLK_UART2 212
+#define RK3328_PCLK_TSADC 213
+#define RK3328_PCLK_PWM 214
+#define RK3328_PCLK_TIMER 215
+#define RK3328_PCLK_BUS_PRE 216
+#define RK3328_PCLK_PERI_PRE 217
+#define RK3328_PCLK_HDMI_CTRL 218
+#define RK3328_PCLK_HDMI_PHY 219
+#define RK3328_PCLK_GMAC 220
+#define RK3328_PCLK_H265 221
+#define RK3328_PCLK_MAC2PHY 222
+#define RK3328_PCLK_MAC2IO 223
+#define RK3328_PCLK_USB3PHY_OTG 224
+#define RK3328_PCLK_USB3PHY_PIPE 225
+#define RK3328_PCLK_USB3_GRF 226
+#define RK3328_PCLK_USB2_GRF 227
+#define RK3328_PCLK_HDMIPHY 228
+#define RK3328_PCLK_DDR 229
+#define RK3328_PCLK_PERI 230
+#define RK3328_PCLK_HDMI 231
+#define RK3328_PCLK_HDCP 232
+#define RK3328_PCLK_DCF 233
+#define RK3328_PCLK_SARADC 234
+#define RK3328_HCLK_PERI 308
+#define RK3328_HCLK_TSP 309
+#define RK3328_HCLK_GMAC 310
+#define RK3328_HCLK_I2S0_8CH 311
+#define RK3328_HCLK_I2S1_8CH 313
+#define RK3328_HCLK_I2S2_2CH 313
+#define RK3328_HCLK_SPDIF_8CH 314
+#define RK3328_HCLK_VOP 315
+#define RK3328_HCLK_NANDC 316
+#define RK3328_HCLK_SDMMC 317
+#define RK3328_HCLK_SDIO 318
+#define RK3328_HCLK_EMMC 319
+#define RK3328_HCLK_SDMMC_EXT 320
+#define RK3328_HCLK_RKVDEC_PRE 321
+#define RK3328_HCLK_RKVDEC 322
+#define RK3328_HCLK_RKVENC 323
+#define RK3328_HCLK_VPU_PRE 324
+#define RK3328_HCLK_VIO_PRE 325
+#define RK3328_HCLK_VPU 326
+#define RK3328_HCLK_BUS_PRE 328
+#define RK3328_HCLK_PERI_PRE 329
+#define RK3328_HCLK_H264 330
+#define RK3328_HCLK_CIF 331
+#define RK3328_HCLK_OTG_PMU 332
+#define RK3328_HCLK_OTG 333
+#define RK3328_HCLK_HOST0 334
+#define RK3328_HCLK_HOST0_ARB 335
+#define RK3328_HCLK_CRYPTO_MST 336
+#define RK3328_HCLK_CRYPTO_SLV 337
+#define RK3328_HCLK_PDM 338
+#define RK3328_HCLK_IEP 339
+#define RK3328_HCLK_RGA 340
+#define RK3328_HCLK_HDCP 341
+
+#endif /* !_RK3328_CRU_H */
Index: src/sys/arch/arm/rockchip/rk3328_platform.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3328_platform.h:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk3328_platform.h Sat Jun 16 00:19:04 2018
@@ -0,0 +1,40 @@
+/* $NetBSD: rk3328_platform.h,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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_RK3328_PLATFORM_H
+#define _ARM_RK3328_PLATFORM_H
+
+#include <arch/evbarm/fdt/platform.h>
+
+#define RK3328_CORE_VBASE KERNEL_IO_VBASE
+#define RK3328_CORE_PBASE 0xff000000
+#define RK3328_CORE_SIZE 0x01000000
+
+#define RK3328_UART_FREQ 24000000
+
+#endif /* _ARM_RK3328_PLATFORM_H */
Index: src/sys/arch/arm/rockchip/rk_cru.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,379 @@
+/* $NetBSD: rk_cru.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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_fdt_arm.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rk_cru.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/rockchip/rk_cru.h>
+
+#define CRU_SOFTRST_CON0 0x0300
+
+static void *
+rk_cru_reset_acquire(device_t dev, const void *data, size_t len)
+{
+ if (len != 4)
+ return NULL;
+
+ return (void *)(uintptr_t)be32dec(data);
+}
+
+static void
+rk_cru_reset_release(device_t dev, void *priv)
+{
+}
+
+static int
+rk_cru_reset_assert(device_t dev, void *priv)
+{
+ struct rk_cru_softc * const sc = device_private(dev);
+ const uintptr_t reset_id = (uintptr_t)priv;
+ const bus_size_t reg = CRU_SOFTRST_CON0 + (reset_id / 32) * 4;
+ const u_int shift = reset_id % 32;
+
+ CRU_WRITE(sc, reg, (1 << (shift + 16)) | (0 << shift));
+
+ return 0;
+}
+
+static int
+rk_cru_reset_deassert(device_t dev, void *priv)
+{
+ struct rk_cru_softc * const sc = device_private(dev);
+ const uintptr_t reset_id = (uintptr_t)priv;
+ const bus_size_t reg = CRU_SOFTRST_CON0 + (reset_id / 32) * 4;
+ const u_int shift = reset_id % 32;
+
+ CRU_WRITE(sc, reg, (1 << (shift + 16)) | (1 << shift));
+
+ return 0;
+}
+
+static const struct fdtbus_reset_controller_func rk_cru_fdtreset_funcs = {
+ .acquire = rk_cru_reset_acquire,
+ .release = rk_cru_reset_release,
+ .reset_assert = rk_cru_reset_assert,
+ .reset_deassert = rk_cru_reset_deassert,
+};
+
+static struct clk *
+rk_cru_clock_decode(device_t dev, const void *data, size_t len)
+{
+ struct rk_cru_softc * const sc = device_private(dev);
+ struct rk_cru_clk *clk;
+
+ if (len != 4)
+ return NULL;
+
+ const u_int clock_id = be32dec(data);
+
+ for (int i = 0; i < sc->sc_nclks; i++) {
+ clk = &sc->sc_clks[i];
+ if (clk->id == clock_id)
+ return &clk->base;
+ }
+
+ return NULL;
+}
+
+static const struct fdtbus_clock_controller_func rk_cru_fdtclock_funcs = {
+ .decode = rk_cru_clock_decode,
+};
+
+static struct clk *
+rk_cru_clock_get(void *priv, const char *name)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk;
+
+ clk = rk_cru_clock_find(sc, name);
+ if (clk == NULL)
+ return NULL;
+
+ return &clk->base;
+}
+
+static void
+rk_cru_clock_put(void *priv, struct clk *clk)
+{
+}
+
+static u_int
+rk_cru_clock_get_rate(void *priv, struct clk *clkp)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+ struct clk *clkp_parent;
+
+ if (clk->get_rate)
+ return clk->get_rate(sc, clk);
+
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL) {
+ aprint_error("%s: no parent for %s\n", __func__, clk->base.name);
+ return 0;
+ }
+
+ return clk_get_rate(clkp_parent);
+}
+
+static int
+rk_cru_clock_set_rate(void *priv, struct clk *clkp, u_int rate)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+ struct clk *clkp_parent;
+
+ if (clkp->flags & CLK_SET_RATE_PARENT) {
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL) {
+ aprint_error("%s: no parent for %s\n", __func__, clk->base.name);
+ return ENXIO;
+ }
+ return clk_set_rate(clkp_parent, rate);
+ }
+
+ if (clk->set_rate)
+ return clk->set_rate(sc, clk, rate);
+
+ return ENXIO;
+}
+
+static u_int
+rk_cru_clock_round_rate(void *priv, struct clk *clkp, u_int rate)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+ struct clk *clkp_parent;
+
+ if (clkp->flags & CLK_SET_RATE_PARENT) {
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL) {
+ aprint_error("%s: no parent for %s\n", __func__, clk->base.name);
+ return 0;
+ }
+ return clk_round_rate(clkp_parent, rate);
+ }
+
+ if (clk->round_rate)
+ return clk->round_rate(sc, clk, rate);
+
+ return 0;
+}
+
+static int
+rk_cru_clock_enable(void *priv, struct clk *clkp)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+ struct clk *clkp_parent;
+ int error = 0;
+
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent != NULL) {
+ error = clk_enable(clkp_parent);
+ if (error != 0)
+ return error;
+ }
+
+ if (clk->enable)
+ error = clk->enable(sc, clk, 1);
+
+ return error;
+}
+
+static int
+rk_cru_clock_disable(void *priv, struct clk *clkp)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+ int error = EINVAL;
+
+ if (clk->enable)
+ error = clk->enable(sc, clk, 0);
+
+ return error;
+}
+
+static int
+rk_cru_clock_set_parent(void *priv, struct clk *clkp,
+ struct clk *clkp_parent)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+
+ if (clk->set_parent == NULL)
+ return EINVAL;
+
+ return clk->set_parent(sc, clk, clkp_parent->name);
+}
+
+static struct clk *
+rk_cru_clock_get_parent(void *priv, struct clk *clkp)
+{
+ struct rk_cru_softc * const sc = priv;
+ struct rk_cru_clk *clk = (struct rk_cru_clk *)clkp;
+ struct rk_cru_clk *clk_parent;
+ const char *parent;
+
+ if (clk->get_parent == NULL)
+ return NULL;
+
+ parent = clk->get_parent(sc, clk);
+ if (parent == NULL)
+ return NULL;
+
+ clk_parent = rk_cru_clock_find(sc, parent);
+ if (clk_parent != NULL)
+ return &clk_parent->base;
+
+ /* No parent in this domain, try FDT */
+ return fdtbus_clock_byname(parent);
+}
+
+static const struct clk_funcs rk_cru_clock_funcs = {
+ .get = rk_cru_clock_get,
+ .put = rk_cru_clock_put,
+ .get_rate = rk_cru_clock_get_rate,
+ .set_rate = rk_cru_clock_set_rate,
+ .round_rate = rk_cru_clock_round_rate,
+ .enable = rk_cru_clock_enable,
+ .disable = rk_cru_clock_disable,
+ .set_parent = rk_cru_clock_set_parent,
+ .get_parent = rk_cru_clock_get_parent,
+};
+
+struct rk_cru_clk *
+rk_cru_clock_find(struct rk_cru_softc *sc, const char *name)
+{
+ for (int i = 0; i < sc->sc_nclks; i++) {
+ if (sc->sc_clks[i].base.name == NULL)
+ continue;
+ if (strcmp(sc->sc_clks[i].base.name, name) == 0)
+ return &sc->sc_clks[i];
+ }
+
+ return NULL;
+}
+
+int
+rk_cru_attach(struct rk_cru_softc *sc)
+{
+ bus_addr_t addr;
+ bus_size_t size;
+ int i;
+
+ if (of_hasprop(sc->sc_phandle, "rockchip,grf")) {
+ const int grf_phandle = fdtbus_get_phandle(sc->sc_phandle, "rockchip,grf");
+ if (grf_phandle == -1) {
+ aprint_error(": couldn't get grf phandle\n");
+ return ENXIO;
+ }
+
+ if (fdtbus_get_reg(grf_phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get grf registers\n");
+ return ENXIO;
+ }
+
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh_grf) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return ENXIO;
+ }
+ }
+
+ if (fdtbus_get_reg(sc->sc_phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return ENXIO;
+ }
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return ENXIO;
+ }
+
+ sc->sc_clkdom.name = device_xname(sc->sc_dev);
+ sc->sc_clkdom.funcs = &rk_cru_clock_funcs;
+ sc->sc_clkdom.priv = sc;
+ for (i = 0; i < sc->sc_nclks; i++) {
+ sc->sc_clks[i].base.domain = &sc->sc_clkdom;
+ clk_attach(&sc->sc_clks[i].base);
+ }
+
+ fdtbus_register_clock_controller(sc->sc_dev, sc->sc_phandle,
+ &rk_cru_fdtclock_funcs);
+
+ fdtbus_register_reset_controller(sc->sc_dev, sc->sc_phandle,
+ &rk_cru_fdtreset_funcs);
+
+ return 0;
+}
+
+void
+rk_cru_print(struct rk_cru_softc *sc)
+{
+ struct rk_cru_clk *clk;
+ struct clk *clkp_parent;
+ const char *type;
+ int i;
+
+ for (i = 0; i < sc->sc_nclks; i++) {
+ clk = &sc->sc_clks[i];
+ if (clk->type == RK_CRU_UNKNOWN)
+ continue;
+
+ clkp_parent = clk_get_parent(&clk->base);
+
+ switch (clk->type) {
+ case RK_CRU_PLL: type = "pll"; break;
+ case RK_CRU_ARM: type = "arm"; break;
+ case RK_CRU_COMPOSITE: type = "comp"; break;
+ case RK_CRU_GATE: type = "gate"; break;
+ case RK_CRU_MUX: type = "mux"; break;
+ default: type = "???"; break;
+ }
+
+ device_printf(sc->sc_dev,
+ "%3d %-14s %2s %-14s %-7s ",
+ clk->id,
+ clk->base.name,
+ clkp_parent ? "<-" : "",
+ clkp_parent ? clkp_parent->name : "",
+ type);
+ printf("%10d Hz\n", clk_get_rate(&clk->base));
+ }
+}
Index: src/sys/arch/arm/rockchip/rk_cru.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru.h:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru.h Sat Jun 16 00:19:04 2018
@@ -0,0 +1,321 @@
+/* $NetBSD: rk_cru.h,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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_RK_CRU_H
+#define _ARM_RK_CRU_H
+
+#include <dev/clk/clk_backend.h>
+
+struct rk_cru_softc;
+struct rk_cru_clk;
+
+/*
+ * Clocks
+ */
+
+enum rk_cru_clktype {
+ RK_CRU_UNKNOWN,
+ RK_CRU_PLL,
+ RK_CRU_ARM,
+ RK_CRU_COMPOSITE,
+ RK_CRU_GATE,
+ RK_CRU_MUX,
+};
+
+/* PLL clocks */
+
+struct rk_cru_pll_rate {
+ u_int rate;
+ u_int refdiv;
+ u_int fbdiv;
+ u_int postdiv1;
+ u_int postdiv2;
+ u_int dsmpd;
+ u_int fracdiv;
+};
+
+#define RK_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _fracdiv) \
+ { \
+ .rate = (_rate), \
+ .refdiv = (_refdiv), \
+ .fbdiv = (_fbdiv), \
+ .postdiv1 = (_postdiv1), \
+ .postdiv2 = (_postdiv2), \
+ .dsmpd = (_dsmpd), \
+ .fracdiv = (_fracdiv), \
+ }
+
+struct rk_cru_pll {
+ bus_size_t con_base;
+ bus_size_t mode_reg;
+ uint32_t mode_mask;
+ uint32_t lock_mask;
+ const struct rk_cru_pll_rate *rates;
+ u_int nrates;
+ const char *parent;
+};
+
+u_int rk_cru_pll_get_rate(struct rk_cru_softc *, struct rk_cru_clk *);
+int rk_cru_pll_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int);
+const char *rk_cru_pll_get_parent(struct rk_cru_softc *, struct rk_cru_clk *);
+
+#define RK_PLL(_id, _name, _parent, _con_base, _mode_reg, _mode_mask, _lock_mask, _rates) \
+ { \
+ .id = (_id), \
+ .type = RK_CRU_PLL, \
+ .base.name = (_name), \
+ .base.flags = 0, \
+ .u.pll.parent = (_parent), \
+ .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), \
+ .get_rate = rk_cru_pll_get_rate, \
+ .set_rate = rk_cru_pll_set_rate, \
+ .get_parent = rk_cru_pll_get_parent, \
+ }
+
+/* ARM clocks */
+
+struct rk_cru_arm_rate {
+ u_int rate;
+ u_int div;
+};
+
+#define RK_ARM_RATE(_rate, _div) \
+ { \
+ .rate = (_rate), \
+ .div = (_div), \
+ }
+
+struct rk_cru_arm {
+ bus_size_t reg;
+ uint32_t mux_mask;
+ u_int mux_main;
+ u_int mux_alt;
+ uint32_t div_mask;
+ const char **parents;
+ u_int nparents;
+ const struct rk_cru_arm_rate *rates;
+ 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);
+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 *);
+
+#define RK_ARM(_id, _name, _parents, _reg, _mux_mask, _mux_main, _mux_alt, _div_mask, _rates) \
+ { \
+ .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.rates = (_rates), \
+ .u.arm.nrates = __arraycount(_rates), \
+ .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 {
+ bus_size_t muxdiv_reg;
+ uint32_t mux_mask;
+ uint32_t div_mask;
+ bus_size_t gate_reg;
+ uint32_t gate_mask;
+ const char **parents;
+ u_int nparents;
+ u_int flags;
+#define RK_COMPOSITE_ROUND_DOWN 0x01
+};
+
+int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int);
+u_int rk_cru_composite_get_rate(struct rk_cru_softc *, struct rk_cru_clk *);
+int rk_cru_composite_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int);
+const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *);
+int rk_cru_composite_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *);
+
+#define RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _flags) \
+ { \
+ .id = (_id), \
+ .type = RK_CRU_COMPOSITE, \
+ .base.name = (_name), \
+ .base.flags = 0, \
+ .u.composite.parents = (_parents), \
+ .u.composite.nparents = __arraycount(_parents), \
+ .u.composite.muxdiv_reg = (_muxdiv_reg), \
+ .u.composite.mux_mask = (_mux_mask), \
+ .u.composite.div_mask = (_div_mask), \
+ .u.composite.gate_reg = (_gate_reg), \
+ .u.composite.gate_mask = (_gate_mask), \
+ .u.composite.flags = (_flags), \
+ .enable = rk_cru_composite_enable, \
+ .get_rate = rk_cru_composite_get_rate, \
+ .set_rate = rk_cru_composite_set_rate, \
+ .get_parent = rk_cru_composite_get_parent, \
+ .set_parent = rk_cru_composite_set_parent, \
+ }
+
+/* Gate clocks */
+
+struct rk_cru_gate {
+ bus_size_t reg;
+ uint32_t mask;
+ const char *parent;
+};
+
+int rk_cru_gate_enable(struct rk_cru_softc *,
+ struct rk_cru_clk *, int);
+const char *rk_cru_gate_get_parent(struct rk_cru_softc *,
+ struct rk_cru_clk *);
+
+#define RK_GATE(_id, _name, _pname, _reg, _bit) \
+ { \
+ .id = (_id), \
+ .type = RK_CRU_GATE, \
+ .base.name = (_name), \
+ .base.flags = CLK_SET_RATE_PARENT, \
+ .u.gate.parent = (_pname), \
+ .u.gate.reg = (_reg), \
+ .u.gate.mask = __BIT(_bit), \
+ .enable = rk_cru_gate_enable, \
+ .get_parent = rk_cru_gate_get_parent, \
+ }
+
+/* Mux clocks */
+
+struct rk_cru_mux {
+ bus_size_t reg;
+ uint32_t mask;
+ const char **parents;
+ u_int nparents;
+ u_int flags;
+#define RK_MUX_GRF 0x01
+};
+
+const char *rk_cru_mux_get_parent(struct rk_cru_softc *, struct rk_cru_clk *);
+int rk_cru_mux_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *);
+
+#define RK_MUX_FLAGS(_id, _name, _parents, _reg, _mask, _flags) \
+ { \
+ .id = (_id), \
+ .type = RK_CRU_MUX, \
+ .base.name = (_name), \
+ .base.flags = CLK_SET_RATE_PARENT, \
+ .u.mux.parents = (_parents), \
+ .u.mux.nparents = __arraycount(_parents), \
+ .u.mux.reg = (_reg), \
+ .u.mux.mask = (_mask), \
+ .u.mux.flags = (_flags), \
+ .set_parent = rk_cru_mux_set_parent, \
+ .get_parent = rk_cru_mux_get_parent, \
+ }
+#define RK_MUX(_id, _name, _parents, _reg, _mask) \
+ RK_MUX_FLAGS(_id, _name, _parents, _reg, _mask, 0)
+#define RK_MUXGRF(_id, _name, _parents, _reg, _mask) \
+ RK_MUX_FLAGS(_id, _name, _parents, _reg, _mask, RK_MUX_GRF)
+
+/*
+ * Rockchip clock definition
+ */
+
+struct rk_cru_clk {
+ struct clk base;
+ u_int id;
+ enum rk_cru_clktype type;
+ union {
+ struct rk_cru_pll pll;
+ struct rk_cru_arm arm;
+ struct rk_cru_composite composite;
+ struct rk_cru_gate gate;
+ struct rk_cru_mux mux;
+ } u;
+
+ int (*enable)(struct rk_cru_softc *,
+ struct rk_cru_clk *, int);
+ u_int (*get_rate)(struct rk_cru_softc *,
+ struct rk_cru_clk *);
+ int (*set_rate)(struct rk_cru_softc *,
+ struct rk_cru_clk *, u_int);
+ u_int (*round_rate)(struct rk_cru_softc *,
+ struct rk_cru_clk *, u_int);
+ const char * (*get_parent)(struct rk_cru_softc *,
+ struct rk_cru_clk *);
+ int (*set_parent)(struct rk_cru_softc *,
+ struct rk_cru_clk *,
+ const char *);
+};
+
+/*
+ * Driver state
+ */
+
+struct rk_cru_softc {
+ device_t sc_dev;
+ int sc_phandle;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ bus_space_handle_t sc_bsh_grf;
+
+ struct clk_domain sc_clkdom;
+
+ struct rk_cru_clk *sc_clks;
+ u_int sc_nclks;
+};
+
+int rk_cru_attach(struct rk_cru_softc *);
+struct rk_cru_clk *rk_cru_clock_find(struct rk_cru_softc *,
+ const char *);
+void rk_cru_print(struct rk_cru_softc *);
+
+#define CRU_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define CRU_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+#define GRF_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh_grf, (reg))
+#define GRF_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh_grf, (reg), (val))
+
+#define HAS_GRF(sc) ((sc)->sc_bsh_grf != 0)
+
+#endif /* _ARM_RK_CRU_H */
Index: src/sys/arch/arm/rockchip/rk_cru_arm.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru_arm.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru_arm.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,139 @@
+/* $NetBSD: rk_cru_arm.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_cru_arm.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/rockchip/rk_cru.h>
+
+u_int
+rk_cru_arm_get_rate(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_arm *arm = &clk->u.arm;
+ struct clk *clkp, *clkp_parent;
+
+ KASSERT(clk->type == RK_CRU_ARM);
+
+ clkp = &clk->base;
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL)
+ return 0;
+
+ const u_int fref = clk_get_rate(clkp_parent);
+ if (fref == 0)
+ return 0;
+
+ const uint32_t val = CRU_READ(sc, arm->reg);
+ const u_int div = __SHIFTOUT(val, arm->div_mask) + 1;
+
+ return fref / div;
+}
+
+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;
+ const struct rk_cru_arm_rate *arm_rate = NULL;
+ struct clk *clkp_parent;
+ int error;
+
+ KASSERT(clk->type == RK_CRU_ARM);
+
+ if (arm->rates == NULL || rate == 0)
+ return EIO;
+
+ for (int i = 0; i < arm->nrates; i++)
+ if (arm->rates[i].rate == rate) {
+ arm_rate = &arm->rates[i];
+ break;
+ }
+ if (arm_rate == NULL)
+ return EINVAL;
+
+ error = rk_cru_arm_set_parent(sc, clk, arm->parents[arm->mux_main]);
+ 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);
+ if (error != 0)
+ return error;
+
+ 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;
+}
+
+const char *
+rk_cru_arm_get_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_arm *arm = &clk->u.arm;
+
+ KASSERT(clk->type == RK_CRU_ARM);
+
+ const uint32_t val = CRU_READ(sc, arm->reg);
+ const u_int mux = __SHIFTOUT(val, arm->mux_mask);
+
+ return arm->parents[mux];
+}
+
+int
+rk_cru_arm_set_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk, const char *parent)
+{
+ struct rk_cru_arm *arm = &clk->u.arm;
+
+ KASSERT(clk->type == RK_CRU_ARM);
+
+ for (u_int mux = 0; mux < arm->nparents; mux++)
+ if (strcmp(arm->parents[mux], parent) == 0) {
+ const uint32_t write_mask = arm->mux_mask << 16;
+ const uint32_t write_val = __SHIFTIN(mux, arm->mux_mask);
+
+ CRU_WRITE(sc, arm->reg, write_mask | write_val);
+ return 0;
+ }
+
+ return EINVAL;
+}
Index: src/sys/arch/arm/rockchip/rk_cru_composite.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru_composite.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru_composite.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,178 @@
+/* $NetBSD: rk_cru_composite.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_cru_composite.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/rockchip/rk_cru.h>
+
+int
+rk_cru_composite_enable(struct rk_cru_softc *sc, struct rk_cru_clk *clk,
+ int enable)
+{
+ struct rk_cru_composite *composite = &clk->u.composite;
+
+ KASSERT(clk->type == RK_CRU_COMPOSITE);
+
+ if (composite->gate_mask == 0)
+ return enable ? 0 : ENXIO;
+
+ const uint32_t write_mask = composite->gate_mask << 16;
+ const uint32_t write_val = __SHIFTIN(!enable, composite->gate_mask);
+
+ CRU_WRITE(sc, composite->gate_reg, write_mask | write_val);
+
+ return 0;
+}
+
+u_int
+rk_cru_composite_get_rate(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_composite *composite = &clk->u.composite;
+ struct clk *clkp, *clkp_parent;
+
+ KASSERT(clk->type == RK_CRU_COMPOSITE);
+
+ clkp = &clk->base;
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL)
+ return 0;
+
+ const u_int prate = clk_get_rate(clkp_parent);
+ if (prate == 0)
+ return 0;
+
+ const uint32_t val = CRU_READ(sc, composite->muxdiv_reg);
+ const u_int div = __SHIFTOUT(val, composite->div_mask) + 1;
+
+ return prate / div;
+}
+
+int
+rk_cru_composite_set_rate(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk, u_int rate)
+{
+ struct rk_cru_composite *composite = &clk->u.composite;
+ u_int best_div, best_mux, best_diff;
+ struct rk_cru_clk *clk_parent;
+
+ KASSERT(clk->type == RK_CRU_COMPOSITE);
+
+ best_div = 0;
+ best_mux = 0;
+ best_diff = INT_MAX;
+ for (u_int mux = 0; mux < composite->nparents; mux++) {
+ clk_parent = rk_cru_clock_find(sc, composite->parents[mux]);
+ if (clk_parent == NULL)
+ continue;
+ const u_int prate = clk_get_rate(&clk_parent->base);
+ if (prate == 0)
+ continue;
+
+ for (u_int div = 1; div <= __SHIFTOUT_MASK(composite->div_mask) + 1; div++) {
+ const u_int cur_rate = prate / div;
+ const int diff = (int)rate - (int)cur_rate;
+ if (composite->flags & RK_COMPOSITE_ROUND_DOWN) {
+ if (diff >= 0 && diff < best_diff) {
+ best_diff = diff;
+ best_mux = mux;
+ best_div = div;
+ }
+ } else {
+ if (abs(diff) < best_diff) {
+ best_diff = abs(diff);
+ best_mux = mux;
+ best_div = div;
+ }
+ }
+ }
+ }
+ if (best_diff == INT_MAX)
+ return ERANGE;
+
+ uint32_t write_mask = composite->div_mask << 16;
+ uint32_t write_val = __SHIFTIN(best_div - 1, composite->div_mask);
+ if (composite->mux_mask) {
+ write_mask |= composite->mux_mask << 16;
+ write_val |= __SHIFTIN(best_mux, composite->mux_mask);
+ }
+
+ CRU_WRITE(sc, composite->muxdiv_reg, write_mask | write_val);
+
+ return 0;
+}
+
+const char *
+rk_cru_composite_get_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_composite *composite = &clk->u.composite;
+ uint32_t val;
+ u_int mux;
+
+ KASSERT(clk->type == RK_CRU_COMPOSITE);
+
+ if (composite->mux_mask) {
+ val = CRU_READ(sc, composite->muxdiv_reg);
+ mux = __SHIFTOUT(val, composite->mux_mask);
+ } else {
+ mux = 0;
+ }
+
+ return composite->parents[mux];
+}
+
+int
+rk_cru_composite_set_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk, const char *parent)
+{
+ struct rk_cru_composite *composite = &clk->u.composite;
+
+ KASSERT(clk->type == RK_CRU_COMPOSITE);
+
+ if (!composite->mux_mask)
+ return EINVAL;
+
+ for (u_int mux = 0; mux < composite->nparents; mux++) {
+ if (strcmp(composite->parents[mux], parent) == 0) {
+ const uint32_t write_mask = composite->mux_mask << 16;
+ const uint32_t write_val = __SHIFTIN(mux, composite->mux_mask);
+
+ CRU_WRITE(sc, composite->muxdiv_reg, write_mask | write_val);
+ return 0;
+ }
+ }
+
+ return EINVAL;
+}
Index: src/sys/arch/arm/rockchip/rk_cru_gate.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru_gate.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru_gate.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,64 @@
+/* $NetBSD: rk_cru_gate.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_cru_gate.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/rockchip/rk_cru.h>
+
+int
+rk_cru_gate_enable(struct rk_cru_softc *sc, struct rk_cru_clk *clk,
+ int enable)
+{
+ struct rk_cru_gate *gate = &clk->u.gate;
+
+ KASSERT(clk->type == RK_CRU_GATE);
+
+ const uint32_t write_mask = gate->mask << 16;
+ const uint32_t write_val = __SHIFTIN(!enable, gate->mask);
+
+ CRU_WRITE(sc, gate->reg, write_mask | write_val);
+
+ return 0;
+}
+
+const char *
+rk_cru_gate_get_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_gate *gate = &clk->u.gate;
+
+ KASSERT(clk->type == RK_CRU_GATE);
+
+ return gate->parent;
+}
Index: src/sys/arch/arm/rockchip/rk_cru_mux.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru_mux.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru_mux.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,84 @@
+/* $NetBSD: rk_cru_mux.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_cru_mux.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/rockchip/rk_cru.h>
+
+const char *
+rk_cru_mux_get_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_mux *mux = &clk->u.mux;
+ const bool mux_grf = (mux->flags & RK_MUX_GRF) != 0;
+
+ KASSERT(clk->type == RK_CRU_MUX);
+
+ if (mux_grf && !HAS_GRF(sc))
+ return NULL;
+
+ const uint32_t val = mux_grf ? GRF_READ(sc, mux->reg) : CRU_READ(sc, mux->reg);
+ const u_int index = __SHIFTOUT(val, mux->mask);
+
+ return mux->parents[index];
+}
+
+int
+rk_cru_mux_set_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk, const char *parent)
+{
+ struct rk_cru_mux *mux = &clk->u.mux;
+ const bool mux_grf = (mux->flags & RK_MUX_GRF) != 0;
+
+ KASSERT(clk->type == RK_CRU_MUX);
+
+ if (mux_grf && !HAS_GRF(sc))
+ return ENXIO;
+
+ for (u_int index = 0; index < mux->nparents; index++) {
+ if (strcmp(mux->parents[index], parent) == 0) {
+ const uint32_t write_mask = mux->mask << 16;
+ const uint32_t write_val = __SHIFTIN(index, mux->mask);
+
+ if (mux_grf)
+ GRF_WRITE(sc, mux->reg, write_mask | write_val);
+ else
+ CRU_WRITE(sc, mux->reg, write_mask | write_val);
+
+ return 0;
+ }
+ }
+
+ return EINVAL;
+}
Index: src/sys/arch/arm/rockchip/rk_cru_pll.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_cru_pll.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_cru_pll.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,170 @@
+/* $NetBSD: rk_cru_pll.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_cru_pll.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/rockchip/rk_cru.h>
+
+#define PLL_CON0 0x00
+#define PLL_BYPASS __BIT(15)
+#define PLL_POSTDIV1 __BITS(14,12)
+#define PLL_FBDIV __BITS(11,0)
+
+#define PLL_CON1 0x04
+#define PLL_PDSEL __BIT(15)
+#define PLL_PD1 __BIT(14)
+#define PLL_PD0 __BIT(13)
+#define PLL_DSMPD __BIT(12)
+#define PLL_LOCK __BIT(10)
+#define PLL_POSTDIV2 __BITS(8,6)
+#define PLL_REFDIV __BITS(5,0)
+
+#define PLL_CON2 0x08
+#define PLL_FOUT4PHASEPD __BIT(27)
+#define PLL_FOUTVCOPD __BIT(26)
+#define PLL_FOUTPOSTDIVPD __BIT(25)
+#define PLL_DACPD __BIT(24)
+#define PLL_FRACDIV __BITS(23,0)
+
+#define PLL_WRITE_MASK 0xffff0000 /* for CON0 and CON1 */
+
+#define GRF_SOC_STATUS0 0x0480
+
+u_int
+rk_cru_pll_get_rate(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_pll *pll = &clk->u.pll;
+ struct clk *clkp, *clkp_parent;
+ u_int foutvco, foutpostdiv;
+
+ KASSERT(clk->type == RK_CRU_PLL);
+
+ clkp = &clk->base;
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL)
+ return 0;
+
+ const u_int fref = clk_get_rate(clkp_parent);
+ if (fref == 0)
+ return 0;
+
+ 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 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 + fracdiv / 224);
+ }
+ foutpostdiv = foutvco / postdiv1 / postdiv2;
+
+ return foutpostdiv;
+}
+
+int
+rk_cru_pll_set_rate(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk, u_int rate)
+{
+ struct rk_cru_pll *pll = &clk->u.pll;
+ const struct rk_cru_pll_rate *pll_rate = NULL;
+ uint32_t val;
+ int retry;
+
+ KASSERT(clk->type == RK_CRU_PLL);
+
+ if (pll->rates == NULL || rate == 0 || !HAS_GRF(sc))
+ return EIO;
+
+ for (int i = 0; i < pll->nrates; i++)
+ if (pll->rates[i].rate == rate) {
+ pll_rate = &pll->rates[i];
+ break;
+ }
+ if (pll_rate == NULL)
+ return EINVAL;
+
+ CRU_WRITE(sc, pll->con_base + PLL_CON0,
+ __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) |
+ __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) |
+ PLL_WRITE_MASK);
+
+ CRU_WRITE(sc, pll->con_base + PLL_CON1,
+ __SHIFTIN(pll_rate->dsmpd, PLL_DSMPD) |
+ __SHIFTIN(pll_rate->postdiv2, PLL_POSTDIV2) |
+ __SHIFTIN(pll_rate->refdiv, PLL_REFDIV) |
+ PLL_WRITE_MASK);
+
+ val = CRU_READ(sc, pll->con_base + PLL_CON2);
+ val &= ~PLL_FRACDIV;
+ val |= __SHIFTIN(pll_rate->fracdiv, PLL_FRACDIV);
+ CRU_WRITE(sc, pll->con_base + PLL_CON2, 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 (GRF_READ(sc, GRF_SOC_STATUS0) & pll->lock_mask)
+ break;
+ delay(1);
+ }
+ if (retry == 0)
+ device_printf(sc->sc_dev, "WARNING: %s failed to lock\n",
+ clk->base.name);
+
+ return 0;
+}
+
+const char *
+rk_cru_pll_get_parent(struct rk_cru_softc *sc,
+ struct rk_cru_clk *clk)
+{
+ struct rk_cru_pll *pll = &clk->u.pll;
+
+ KASSERT(clk->type == RK_CRU_PLL);
+
+ return pll->parent;
+}
Index: src/sys/arch/arm/rockchip/rk_gmac.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_gmac.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_gmac.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,323 @@
+/* $NetBSD: rk_gmac.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_gmac.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/gpio.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/dwc_gmac_var.h>
+#include <dev/ic/dwc_gmac_reg.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#define RK3328_GRF_MAC_CON0 0x0900
+#define RK3328_GRF_MAC_CON0_RXDLY __BITS(13,7)
+#define RK3328_GRF_MAC_CON0_TXDLY __BITS(6,0)
+
+#define RK3328_GRF_MAC_CON1 0x0904
+#define RK3328_GRF_MAC_CON1_CLKSEL __BITS(12,11)
+#define RK3328_GRF_MAC_CON1_CLKSEL_125M 0
+#define RK3328_GRF_MAC_CON1_CLKSEL_2_5M 2
+#define RK3328_GRF_MAC_CON1_CLKSEL_25M 3
+#define RK3328_GRF_MAC_CON1_MODE __BIT(9)
+#define RK3328_GRF_MAC_CON1_SEL __BITS(6,4)
+#define RK3328_GRF_MAC_CON1_SEL_RGMII 1
+#define RK3328_GRF_MAC_CON1_RXDLY_EN __BIT(1)
+#define RK3328_GRF_MAC_CON1_TXDLY_EN __BIT(0)
+
+#define RK_GMAC_TXDLY_DEFAULT 0x30
+#define RK_GMAC_RXDLY_DEFAULT 0x10
+
+static const char * compatible[] = {
+ "rockchip,rk3328-gmac",
+ NULL
+};
+
+struct rk_gmac_softc {
+ struct dwc_gmac_softc sc_base;
+ bus_space_handle_t sc_grf_bsh;
+};
+
+static int
+rk_gmac_reset(const int phandle)
+{
+#if notyet
+ struct fdtbus_gpio_pin *pin_reset;
+ const u_int *reset_delay_us;
+ bool reset_active_low;
+ int len, val;
+
+ if (!of_hasprop(phandle, "snps,reset-gpio"))
+ return 0;
+
+ pin_reset = fdtbus_gpio_acquire(phandle, "snps,reset-gpio", GPIO_PIN_OUTPUT);
+ if (pin_reset == NULL)
+ return ENOENT;
+
+ reset_delay_us = fdtbus_get_prop(phandle, "snps,reset-delays-us", &len);
+ if (reset_delay_us == NULL || len != 12)
+ return ENXIO;
+
+ reset_active_low = of_hasprop(phandle, "snps,reset-active-low");
+
+ val = reset_active_low ? 1 : 0;
+
+ fdtbus_gpio_write(pin_reset, val);
+ if (be32toh(reset_delay_us[0]) > 0)
+ delay(be32toh(reset_delay_us[0]));
+ fdtbus_gpio_write(pin_reset, !val);
+ if (be32toh(reset_delay_us[1]) > 0)
+ delay(be32toh(reset_delay_us[1]));
+ fdtbus_gpio_write(pin_reset, val);
+ if (be32toh(reset_delay_us[2]) > 0)
+ delay(be32toh(reset_delay_us[2]));
+#endif
+
+ return 0;
+}
+
+static int
+rk_gmac_intr(void *arg)
+{
+ return dwc_gmac_intr(arg);
+}
+
+static void
+rk3328_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay)
+{
+ struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
+
+ const uint32_t write_mask =
+ (RK3328_GRF_MAC_CON1_MODE | RK3328_GRF_MAC_CON1_SEL |
+ RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN) << 16;
+ const uint32_t write_val =
+ __SHIFTIN(RK3328_GRF_MAC_CON1_SEL_RGMII, RK3328_GRF_MAC_CON1_SEL) |
+ RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN;
+
+ bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1, write_mask | write_val);
+ bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON0,
+ (RK3328_GRF_MAC_CON0_TXDLY << 16) |
+ (RK3328_GRF_MAC_CON0_RXDLY << 16) |
+ __SHIFTIN(tx_delay, RK3328_GRF_MAC_CON0_TXDLY) |
+ __SHIFTIN(rx_delay, RK3328_GRF_MAC_CON0_RXDLY));
+}
+
+static void
+rk3328_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed)
+{
+ struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
+ u_int clksel;
+
+ switch (speed) {
+ case IFM_10_T:
+ clksel = RK3328_GRF_MAC_CON1_CLKSEL_2_5M;
+ break;
+ case IFM_100_TX:
+ clksel = RK3328_GRF_MAC_CON1_CLKSEL_25M;
+ break;
+ default:
+ clksel = RK3328_GRF_MAC_CON1_CLKSEL_125M;
+ break;
+ }
+
+ bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1,
+ (RK3328_GRF_MAC_CON1_CLKSEL << 16) |
+ __SHIFTIN(RK3328_GRF_MAC_CON1_CLKSEL_125M, RK3328_GRF_MAC_CON1_CLKSEL));
+}
+
+static int
+rk_gmac_setup_clocks(int phandle)
+{
+ static const char * const clknames[] = {
+#if 0
+ "stmmaceth",
+ "mac_clk_rx",
+ "mac_clk_tx",
+ "clk_mac_ref",
+ "clk_mac_refout",
+ "aclk_mac",
+ "pclk_mac"
+#else
+ "stmmaceth",
+ "aclk_mac",
+ "pclk_mac",
+ "mac_clk_tx",
+#endif
+ };
+ static const char * const rstnames[] = {
+ "stmmaceth"
+ };
+ struct fdtbus_reset *rst;
+ struct clk *clk;
+ int error, n;
+
+ fdtbus_clock_assign(phandle);
+
+ for (n = 0; n < __arraycount(clknames); n++) {
+ clk = fdtbus_clock_get(phandle, clknames[n]);
+ if (clk == NULL) {
+ aprint_error(": couldn't get %s clock\n", clknames[n]);
+ return ENXIO;
+ }
+ error = clk_enable(clk);
+ if (error != 0) {
+ aprint_error(": couldn't enable %s clock: %d\n",
+ clknames[n], error);
+ return error;
+ }
+ }
+
+ for (n = 0; n < __arraycount(rstnames); n++) {
+ rst = fdtbus_reset_get(phandle, rstnames[n]);
+ if (rst == NULL) {
+ aprint_error(": couldn't get %s reset\n", rstnames[n]);
+ return ENXIO;
+ }
+ error = fdtbus_reset_deassert(rst);
+ if (error != 0) {
+ aprint_error(": couldn't de-assert %s reset: %d\n",
+ rstnames[n], error);
+ return error;
+ }
+ }
+
+ delay(5000);
+
+ return 0;
+}
+
+static int
+rk_gmac_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+rk_gmac_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk_gmac_softc * const rk_sc = device_private(self);
+ struct dwc_gmac_softc * const sc = &rk_sc->sc_base;
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ const char *phy_mode;
+ char intrstr[128];
+ bus_addr_t addr, grf_addr;
+ bus_size_t size, grf_size;
+ u_int tx_delay, rx_delay;
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ const int grf_phandle = fdtbus_get_phandle(phandle, "rockchip,grf");
+ if (grf_phandle == -1) {
+ aprint_error(": couldn't get grf phandle\n");
+ return;
+ }
+ if (fdtbus_get_reg(grf_phandle, 0, &grf_addr, &grf_size) != 0) {
+ aprint_error(": couldn't get grf registers\n");
+ return;
+ }
+ if (bus_space_map(faa->faa_bst, grf_addr, grf_size, 0, &rk_sc->sc_grf_bsh) != 0) {
+ aprint_error(": couldn't map grf registers\n");
+ return;
+ }
+
+ if (of_getprop_uint32(phandle, "tx_delay", &tx_delay) != 0)
+ tx_delay = RK_GMAC_TXDLY_DEFAULT;
+
+ if (of_getprop_uint32(phandle, "rx_delay", &rx_delay) != 0)
+ rx_delay = RK_GMAC_RXDLY_DEFAULT;
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ sc->sc_dmat = faa->faa_dmat;
+
+ if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+ aprint_error(": failed to decode interrupt\n");
+ return;
+ }
+
+ if (rk_gmac_setup_clocks(phandle) != 0)
+ return;
+
+ if (rk_gmac_reset(phandle) != 0)
+ aprint_error_dev(self, "PHY reset failed\n");
+
+ if (of_hasprop(phandle, "snps,force_thresh_dma_mode"))
+ sc->sc_flags |= DWC_GMAC_FORCE_THRESH_DMA_MODE;
+
+ phy_mode = fdtbus_get_string(phandle, "phy-mode");
+ if (phy_mode == NULL) {
+ aprint_error(": missing 'phy-mode' property\n");
+ return;
+ }
+
+ if (strcmp(phy_mode, "rgmii") == 0) {
+ rk3328_gmac_set_mode_rgmii(sc, tx_delay, rx_delay);
+
+ sc->sc_set_speed = rk3328_gmac_set_speed_rgmii;
+ } else {
+ aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
+ return;
+ }
+
+ aprint_naive("\n");
+ aprint_normal(": GMAC\n");
+
+ if (fdtbus_intr_establish(phandle, 0, IPL_NET, 0, rk_gmac_intr, sc) == NULL) {
+ aprint_error_dev(self, "failed to establish interrupt on %s\n", intrstr);
+ return;
+ }
+ aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
+ dwc_gmac_attach(sc, GMAC_MII_CLK_150_250M_DIV102);
+}
+
+CFATTACH_DECL_NEW(rk_gmac, sizeof(struct rk_gmac_softc),
+ rk_gmac_match, rk_gmac_attach, NULL, NULL);
Index: src/sys/arch/arm/rockchip/rk_gpio.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_gpio.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_gpio.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,323 @@
+/* $NetBSD: rk_gpio.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_gpio.c,v 1.1 2018/06/16 00:19:04 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/gpio.h>
+#include <sys/bitops.h>
+#include <sys/lwp.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/gpio/gpiovar.h>
+
+#define GPIO_SWPORTA_DR_REG 0x0000
+#define GPIO_SWPORTA_DDR_REG 0x0004
+#define GPIO_INTEN_REG 0x0030
+#define GPIO_INTMASK_REG 0x0034
+#define GPIO_INTTYPE_LEVEL_REG 0x0038
+#define GPIO_INT_POLARITY_REG 0x003c
+#define GPIO_INT_STATUS_REG 0x0040
+#define GPIO_INT_RAWSTATUS_REG 0x0044
+#define GPIO_DEBOUNCE_REG 0x0048
+#define GPIO_PORTA_EOI_REG 0x004c
+#define GPIO_EXT_PORTA_REG 0x0050
+#define GPIO_LS_SYNC_REG 0x0060
+
+static const char * const compatible[] = {
+ "rockchip,gpio-bank",
+ NULL
+};
+
+struct rk_gpio_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ kmutex_t sc_lock;
+
+ struct gpio_chipset_tag sc_gp;
+ gpio_pin_t sc_pins[32];
+ device_t sc_gpiodev;
+};
+
+struct rk_gpio_pin {
+ struct rk_gpio_softc *pin_sc;
+ u_int pin_nr;
+ int pin_flags;
+ bool pin_actlo;
+};
+
+#define RD4(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int rk_gpio_match(device_t, cfdata_t, void *);
+static void rk_gpio_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(rk_gpio, sizeof(struct rk_gpio_softc),
+ rk_gpio_match, rk_gpio_attach, NULL, NULL);
+
+static int
+rk_gpio_ctl(struct rk_gpio_softc *sc, u_int pin, int flags)
+{
+ uint32_t ddr;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ ddr = RD4(sc, GPIO_SWPORTA_DDR_REG);
+ if (flags & GPIO_PIN_INPUT)
+ ddr &= ~__BIT(pin);
+ else if (flags & GPIO_PIN_OUTPUT)
+ ddr |= __BIT(pin);
+ WR4(sc, GPIO_SWPORTA_DDR_REG, ddr);
+
+ return 0;
+}
+
+static void *
+rk_gpio_acquire(device_t dev, const void *data, size_t len, int flags)
+{
+ struct rk_gpio_softc * const sc = device_private(dev);
+ struct rk_gpio_pin *gpin;
+ const u_int *gpio = data;
+ int error;
+
+ if (len != 12)
+ return NULL;
+
+ const uint8_t pin = be32toh(gpio[1]) & 0xff;
+ const bool actlo = be32toh(gpio[2]) & 1;
+
+ if (pin >= __arraycount(sc->sc_pins))
+ return NULL;
+
+ mutex_enter(&sc->sc_lock);
+ error = rk_gpio_ctl(sc, pin, flags);
+ mutex_exit(&sc->sc_lock);
+
+ if (error != 0)
+ return NULL;
+
+ gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP);
+ gpin->pin_sc = sc;
+ gpin->pin_nr = pin;
+ gpin->pin_flags = flags;
+ gpin->pin_actlo = actlo;
+
+ return gpin;
+}
+
+static void
+rk_gpio_release(device_t dev, void *priv)
+{
+ struct rk_gpio_softc * const sc = device_private(dev);
+ struct rk_gpio_pin *pin = priv;
+
+ mutex_enter(&sc->sc_lock);
+ rk_gpio_ctl(pin->pin_sc, pin->pin_nr, GPIO_PIN_INPUT);
+ mutex_exit(&sc->sc_lock);
+
+ kmem_free(pin, sizeof(*pin));
+}
+
+static int
+rk_gpio_read(device_t dev, void *priv, bool raw)
+{
+ struct rk_gpio_softc * const sc = device_private(dev);
+ struct rk_gpio_pin *pin = priv;
+ uint32_t data;
+ int val;
+
+ KASSERT(sc == pin->pin_sc);
+
+ const uint32_t data_mask = __BIT(pin->pin_nr);
+
+ /* No lock required for reads */
+ data = RD4(sc, GPIO_EXT_PORTA_REG);
+ val = __SHIFTOUT(data, data_mask);
+ if (!raw && pin->pin_actlo)
+ val = !val;
+
+ return val;
+}
+
+static void
+rk_gpio_write(device_t dev, void *priv, int val, bool raw)
+{
+ struct rk_gpio_softc * const sc = device_private(dev);
+ struct rk_gpio_pin *pin = priv;
+ uint32_t data;
+
+ KASSERT(sc == pin->pin_sc);
+
+ const uint32_t data_mask = __BIT(pin->pin_nr);
+
+ if (!raw && pin->pin_actlo)
+ val = !val;
+
+ mutex_enter(&sc->sc_lock);
+ data = RD4(sc, GPIO_SWPORTA_DR_REG);
+ data &= ~data_mask;
+ data |= __SHIFTIN(val, data_mask);
+ WR4(sc, GPIO_SWPORTA_DR_REG, data);
+ mutex_exit(&sc->sc_lock);
+}
+
+static struct fdtbus_gpio_controller_func rk_gpio_funcs = {
+ .acquire = rk_gpio_acquire,
+ .release = rk_gpio_release,
+ .read = rk_gpio_read,
+ .write = rk_gpio_write,
+};
+
+static int
+rk_gpio_pin_read(void *priv, int pin)
+{
+ struct rk_gpio_softc * const sc = priv;
+ uint32_t data;
+ int val;
+
+ KASSERT(pin < __arraycount(sc->sc_pins));
+
+ const uint32_t data_mask = __BIT(pin);
+
+ /* No lock required for reads */
+ data = RD4(sc, GPIO_SWPORTA_DR_REG);
+ val = __SHIFTOUT(data, data_mask);
+
+ return val;
+}
+
+static void
+rk_gpio_pin_write(void *priv, int pin, int val)
+{
+ struct rk_gpio_softc * const sc = priv;
+ uint32_t data;
+
+ KASSERT(pin < __arraycount(sc->sc_pins));
+
+ const uint32_t data_mask = __BIT(pin);
+
+ mutex_enter(&sc->sc_lock);
+ data = RD4(sc, GPIO_SWPORTA_DR_REG);
+ if (val)
+ data |= data_mask;
+ else
+ data &= ~data_mask;
+ WR4(sc, GPIO_SWPORTA_DR_REG, data);
+ mutex_exit(&sc->sc_lock);
+}
+
+static void
+rk_gpio_pin_ctl(void *priv, int pin, int flags)
+{
+ struct rk_gpio_softc * const sc = priv;
+
+ KASSERT(pin < __arraycount(sc->sc_pins));
+
+ mutex_enter(&sc->sc_lock);
+ rk_gpio_ctl(sc, pin, flags);
+ mutex_exit(&sc->sc_lock);
+}
+
+static void
+rk_gpio_attach_ports(struct rk_gpio_softc *sc)
+{
+ struct gpio_chipset_tag *gp = &sc->sc_gp;
+ struct gpiobus_attach_args gba;
+ u_int pin;
+
+ gp->gp_cookie = sc;
+ gp->gp_pin_read = rk_gpio_pin_read;
+ gp->gp_pin_write = rk_gpio_pin_write;
+ gp->gp_pin_ctl = rk_gpio_pin_ctl;
+
+ for (pin = 0; pin < __arraycount(sc->sc_pins); pin++) {
+ sc->sc_pins[pin].pin_num = pin;
+ sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+ sc->sc_pins[pin].pin_state = rk_gpio_pin_read(sc, pin);
+ }
+
+ memset(&gba, 0, sizeof(gba));
+ gba.gba_gc = gp;
+ gba.gba_pins = sc->sc_pins;
+ gba.gba_npins = __arraycount(sc->sc_pins);
+ sc->sc_gpiodev = config_found_ia(sc->sc_dev, "gpiobus", &gba, NULL);
+}
+
+static int
+rk_gpio_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+rk_gpio_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk_gpio_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ struct clk *clk;
+ bus_addr_t addr;
+ bus_size_t size;
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ if ((clk = fdtbus_clock_get_index(phandle, 0)) == NULL || clk_enable(clk) != 0) {
+ aprint_error(": couldn't enable clock\n");
+ return;
+ }
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
+
+ aprint_naive("\n");
+ aprint_normal(": GPIO (%s)\n", fdtbus_get_string(phandle, "name"));
+
+ fdtbus_register_gpio_controller(self, phandle, &rk_gpio_funcs);
+
+ rk_gpio_attach_ports(sc);
+}
Index: src/sys/arch/arm/rockchip/rk_iomux.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_iomux.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_iomux.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,329 @@
+/* $NetBSD: rk_iomux.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_iomux.c,v 1.1 2018/06/16 00:19:04 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>
+
+#define GRF_GPIO_IOMUX_REG(_bank, _idx) (0x0000 + (_bank) * 0x10 + ((_idx) >> 3) * 4)
+#define GRF_GPIO_IOMUX_SEL(_idx) (0x3 << (((_idx) & 7) * 2))
+#define GRF_GPIO_IOMUX_SEL_MASK 0x3
+#define GRF_GPIO_IOMUX_WRITE_EN(_idx) (0x3 << (((_idx) & 7) * 2 + 16))
+
+#define GRF_GPIO_P_REG(_bank, _idx) (0x0100 + (_bank) * 0x10 + ((_idx) >> 3) * 4)
+#define GRF_GPIO_P_CTL(_idx) (0x3 << (((_idx) & 7) * 2))
+#define GRF_GPIO_P_CTL_Z 0
+#define GRF_GPIO_P_CTL_PULLUP 1
+#define GRF_GPIO_P_CTL_PULLDOWN 2
+#define GRF_GPIO_P_CTL_REPEATER 3
+#define GRF_GPIO_P_CTL_MASK 0x3
+#define GRF_GPIO_P_WRITE_EN(_idx) (0x3 << (((_idx) & 7) * 2 + 16))
+
+#define GRF_GPIO_E_REG(_bank, _idx) (0x0200 + (_bank) * 0x10 + ((_idx) >> 3) * 4)
+#define GRF_GPIO_E_CTL(_idx) (0x3 << (((_idx) & 7) * 2))
+#define GRF_GPIO_E_CTL_2MA 0
+#define GRF_GPIO_E_CTL_4MA 1
+#define GRF_GPIO_E_CTL_8MA 2
+#define GRF_GPIO_E_CTL_12MA 3
+#define GRF_GPIO_E_CTL_MASK 0x3
+#define GRF_GPIO_E_WRITE_EN(_idx) (0x3 << (((_idx) & 7) * 2 + 16))
+
+struct rk_iomux {
+ bus_size_t base;
+ u_int type;
+#define RK_IOMUX_TYPE_3BIT 0x01
+};
+
+struct rk_iomux_bank {
+ struct rk_iomux iomux[4];
+};
+
+#define RK_IOMUX(_reg, _shift, _mask) \
+ { .reg = (_reg), .shift = (_shift), .mask = (_mask) }
+
+static const struct rk_iomux_bank rk3328_iomux_banks[] = {
+ [0] = {
+ .iomux = {
+ [0] = { .base = 0x0000 },
+ [1] = { .base = 0x0004 },
+ [2] = { .base = 0x0008 },
+ [3] = { .base = 0x000c },
+ },
+ },
+ [1] = {
+ .iomux = {
+ [0] = { .base = 0x0010 },
+ [1] = { .base = 0x0014 },
+ [2] = { .base = 0x0018 },
+ [3] = { .base = 0x001c },
+ }
+ },
+ [2] = {
+ .iomux = {
+ [0] = { .base = 0x0020 },
+ [1] = { .base = 0x0024, .type = RK_IOMUX_TYPE_3BIT },
+ [2] = { .base = 0x002c, .type = RK_IOMUX_TYPE_3BIT },
+ [3] = { .base = 0x0034 },
+ },
+ },
+ [3] = {
+ .iomux = {
+ [0] = { .base = 0x0038, .type = RK_IOMUX_TYPE_3BIT },
+ [1] = { .base = 0x0040, .type = RK_IOMUX_TYPE_3BIT },
+ [2] = { .base = 0x0048 },
+ [3] = { .base = 0x004c },
+ },
+ },
+};
+
+struct rk_iomux_config {
+ const struct rk_iomux_bank *banks;
+ u_int nbanks;
+};
+
+static const struct rk_iomux_config rk3328_iomux_config = {
+ .banks = rk3328_iomux_banks,
+ .nbanks = __arraycount(rk3328_iomux_banks),
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3328-pinctrl", (uintptr_t)&rk3328_iomux_config },
+ { NULL }
+};
+
+struct rk_iomux_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+
+ const struct rk_iomux_config *sc_conf;
+};
+
+#define RD4(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int rk_iomux_match(device_t, cfdata_t, void *);
+static void rk_iomux_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(rk_iomux, sizeof(struct rk_iomux_softc),
+ rk_iomux_match, rk_iomux_attach, NULL, NULL);
+
+static void
+rk_iomux_calc_iomux_reg(struct rk_iomux_softc *sc, u_int bank, u_int pin, bus_size_t *reg, uint32_t *mask)
+{
+ const struct rk_iomux_bank *banks = sc->sc_conf->banks;
+
+ KASSERT(bank < sc->sc_conf->nbanks);
+
+ *reg = banks[bank].iomux[pin / 8].base;
+ if (banks[bank].iomux[pin / 8].type & RK_IOMUX_TYPE_3BIT) {
+ if ((pin % 8) >= 5)
+ *reg += 0x04;
+ const u_int bit = (pin % 8 % 5) * 3;
+ *mask = 7 << bit;
+ } else {
+ const u_int bit = (pin % 8) * 2;
+ *mask = 3 << bit;
+ }
+}
+
+static void
+rk_iomux_set_bias(struct rk_iomux_softc *sc, u_int bank, u_int idx, u_int bias)
+{
+ WR4(sc, GRF_GPIO_P_REG(bank, idx),
+ __SHIFTIN(GRF_GPIO_P_CTL_MASK, GRF_GPIO_P_WRITE_EN(idx)) |
+ __SHIFTIN(bias, GRF_GPIO_P_CTL(idx)));
+}
+
+static void
+rk_iomux_set_drive_strength(struct rk_iomux_softc *sc, u_int bank, u_int idx, u_int drv)
+{
+ WR4(sc, GRF_GPIO_E_REG(bank, idx),
+ __SHIFTIN(GRF_GPIO_E_CTL_MASK, GRF_GPIO_E_WRITE_EN(idx)) |
+ __SHIFTIN(drv, GRF_GPIO_E_CTL(idx)));
+}
+
+static void
+rk_iomux_set_mux(struct rk_iomux_softc *sc, u_int bank, u_int idx, u_int mux)
+{
+ bus_size_t reg;
+ uint32_t mask;
+
+ rk_iomux_calc_iomux_reg(sc, bank, idx, ®, &mask);
+
+ WR4(sc, reg, (mask << 16) | __SHIFTIN(mux, mask));
+}
+
+static int
+rk_iomux_config(struct rk_iomux_softc *sc, const int phandle, u_int bank, u_int idx, u_int mux)
+{
+ u_int drv;
+
+ if (of_hasprop(phandle, "bias-disable"))
+ rk_iomux_set_bias(sc, bank, idx, GRF_GPIO_P_CTL_Z);
+ else if (of_hasprop(phandle, "bias-pull-up"))
+ rk_iomux_set_bias(sc, bank, idx, GRF_GPIO_P_CTL_PULLUP);
+ else if (of_hasprop(phandle, "bias-pull-down"))
+ rk_iomux_set_bias(sc, bank, idx, GRF_GPIO_P_CTL_PULLDOWN);
+
+ if (of_getprop_uint32(phandle, "drive-strength", &drv) == 0) {
+ switch (drv) {
+ case 2:
+ rk_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_2MA);
+ break;
+ case 4:
+ rk_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_4MA);
+ break;
+ case 8:
+ rk_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_8MA);
+ break;
+ case 12:
+ rk_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_12MA);
+ break;
+ default:
+ aprint_error_dev(sc->sc_dev, "unsupported drive-strength %u\n", drv);
+ return EINVAL;
+ }
+ }
+
+#if notyet
+ if (of_hasprop(phandle, "input-enable"))
+ rk_iomux_set_direction(sc, bank, idx, GPIO_PIN_INPUT, -1);
+ else if (of_hasprop(phandle, "output-high"))
+ rk_iomux_set_direction(sc, bank, idx, GPIO_PIN_OUTPUT, GPIO_PIN_HIGH);
+ else if (of_hasprop(phandle, "output-low"))
+ rk_iomux_set_direction(sc, bank, idx, GPIO_PIN_OUTPUT, GPIO_PIN_LOW);
+#endif
+
+ rk_iomux_set_mux(sc, bank, idx, mux);
+
+ return 0;
+}
+
+static int
+rk_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len)
+{
+ struct rk_iomux_softc * const sc = device_private(dev);
+ int pins_len;
+
+ 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]));
+
+ rk_iomux_config(sc, cfg, bank, idx, mux);
+
+ pins_len -= 16;
+ pins += 4;
+ }
+
+ return 0;
+}
+
+static struct fdtbus_pinctrl_controller_func rk_iomux_pinctrl_funcs = {
+ .set_config = rk_iomux_pinctrl_set_config,
+};
+
+static int
+rk_iomux_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+static void
+rk_iomux_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk_iomux_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ bus_addr_t addr;
+ bus_size_t size;
+ int child, sub;
+
+ const int grf_phandle = fdtbus_get_phandle(phandle, "rockchip,grf");
+ if (grf_phandle == -1) {
+ aprint_error(": couldn't get grf phandle\n");
+ return;
+ }
+
+ if (fdtbus_get_reg(grf_phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get grf registers\n");
+ return;
+ }
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data;
+
+ aprint_naive("\n");
+ aprint_normal(": IOMUX control\n");
+
+ for (child = OF_child(phandle); child; child = OF_peer(child)) {
+ for (sub = OF_child(child); sub; sub = OF_peer(sub)) {
+ if (!of_hasprop(sub, "rockchip,pins"))
+ continue;
+ fdtbus_register_pinctrl_config(self, sub, &rk_iomux_pinctrl_funcs);
+ }
+ }
+
+ fdtbus_pinctrl_configure();
+
+ for (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);
+ }
+}
Index: src/sys/arch/arm/rockchip/rk_platform.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_platform.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_platform.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,160 @@
+/* $NetBSD: rk_platform.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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 "opt_fdt_arm.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rk_platform.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/termios.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <arm/fdt/arm_fdtvar.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/bootconfig.h>
+#include <arm/cpufunc.h>
+
+#include <arm/cortex/gtmr_var.h>
+
+#include <dev/ic/ns16550reg.h>
+#include <dev/ic/comreg.h>
+
+#include <arm/arm/psci.h>
+#include <arm/fdt/psci_fdt.h>
+
+#include <libfdt.h>
+
+extern struct arm32_bus_dma_tag arm_generic_dma_tag;
+extern struct bus_space arm_generic_bs_tag;
+extern struct bus_space arm_generic_a4x_bs_tag;
+
+static void
+rk_platform_init_attach_args(struct fdt_attach_args *faa)
+{
+ faa->faa_bst = &arm_generic_bs_tag;
+ faa->faa_a4x_bst = &arm_generic_a4x_bs_tag;
+ faa->faa_dmat = &arm_generic_dma_tag;
+}
+
+static void
+rk_platform_device_register(device_t self, void *aux)
+{
+}
+
+static void
+rk_platform_bootstrap(void)
+{
+ void *fdt_data = __UNCONST(fdtbus_get_data());
+
+ psci_fdt_bootstrap();
+
+ const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
+ if (chosen_off < 0)
+ return;
+
+ if (match_bootconf_option(boot_args, "console", "fb")) {
+ const int framebuffer_off =
+ fdt_path_offset(fdt_data, "/chosen/framebuffer");
+ if (framebuffer_off >= 0) {
+ const char *status = fdt_getprop(fdt_data,
+ framebuffer_off, "status", NULL);
+ if (status == NULL || strncmp(status, "ok", 2) == 0) {
+ fdt_setprop_string(fdt_data, chosen_off,
+ "stdout-path", "/chosen/framebuffer");
+ }
+ }
+ } else if (match_bootconf_option(boot_args, "console", "serial")) {
+ fdt_setprop_string(fdt_data, chosen_off,
+ "stdout-path", "serial0:115200n8");
+ }
+}
+
+#ifdef SOC_RK3328
+
+#include <arm/rockchip/rk3328_platform.h>
+
+static const struct pmap_devmap *
+rk3328_platform_devmap(void)
+{
+ static const struct pmap_devmap devmap[] = {
+ DEVMAP_ENTRY(RK3328_CORE_VBASE,
+ RK3328_CORE_PBASE,
+ RK3328_CORE_SIZE),
+ DEVMAP_ENTRY_END
+ };
+
+ return devmap;
+}
+
+void rk3328_platform_early_putchar(char);
+
+void
+rk3328_platform_early_putchar(char c)
+{
+#ifdef CONSADDR
+#define CONSADDR_VA ((CONSADDR - RK3328_CORE_PBASE) + RK3328_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 u_int
+rk3328_platform_uart_freq(void)
+{
+ return RK3328_UART_FREQ;
+}
+
+static const struct arm_platform rk3328_platform = {
+ .devmap = rk3328_platform_devmap,
+ .bootstrap = rk_platform_bootstrap,
+ .init_attach_args = rk_platform_init_attach_args,
+ .early_putchar = rk3328_platform_early_putchar,
+ .device_register = rk_platform_device_register,
+ .reset = psci_fdt_reset,
+ .delay = gtmr_delay,
+ .uart_freq = rk3328_platform_uart_freq,
+};
+
+ARM_PLATFORM(rk3328, "rockchip,rk3328", &rk3328_platform);
+
+#endif /* SOC_RK3328 */
Index: src/sys/arch/arm/rockchip/rk_usb.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk_usb.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/arch/arm/rockchip/rk_usb.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,316 @@
+/* $NetBSD: rk_usb.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * 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: rk_usb.c,v 1.1 2018/06/16 00:19:04 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/clk/clk_backend.h>
+
+#include <dev/fdt/fdtvar.h>
+
+static int rk_usb_match(device_t, cfdata_t, void *);
+static void rk_usb_attach(device_t, device_t, void *);
+
+#define CON0_REG 0x00
+#define CON1_REG 0x04
+#define CON2_REG 0x08
+#define USBPHY_COMMONONN __BIT(4)
+
+enum rk_usb_type {
+ USB_RK3328 = 1,
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3328-usb2phy", USB_RK3328 },
+ { NULL }
+};
+
+struct rk_usb_clk {
+ struct clk base;
+ bus_size_t reg;
+};
+
+struct rk_usb_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ enum rk_usb_type sc_type;
+
+ struct clk_domain sc_clkdom;
+ struct rk_usb_clk sc_usbclk;
+};
+
+#define USB_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define USB_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+CFATTACH_DECL_NEW(rk_usb, sizeof(struct rk_usb_softc),
+ rk_usb_match, rk_usb_attach, NULL, NULL);
+
+static struct clk *
+rk_usb_clk_get(void *priv, const char *name)
+{
+ struct rk_usb_softc * const sc = priv;
+
+ if (strcmp(name, sc->sc_usbclk.base.name) != 0)
+ return NULL;
+
+ return &sc->sc_usbclk.base;
+}
+
+static void
+rk_usb_clk_put(void *priv, struct clk *clk)
+{
+}
+
+static u_int
+rk_usb_clk_get_rate(void *priv, struct clk *clk)
+{
+ return 480000000;
+}
+
+static int
+rk_usb_clk_enable(void *priv, struct clk *clk)
+{
+ struct rk_usb_softc * const sc = priv;
+
+ const uint32_t write_mask = USBPHY_COMMONONN << 16;
+ const uint32_t write_val = 0;
+ USB_WRITE(sc, CON2_REG, write_mask | write_val);
+
+ return 0;
+}
+
+static int
+rk_usb_clk_disable(void *priv, struct clk *clk)
+{
+ struct rk_usb_softc * const sc = priv;
+
+ const uint32_t write_mask = USBPHY_COMMONONN << 16;
+ const uint32_t write_val = USBPHY_COMMONONN;
+ USB_WRITE(sc, CON2_REG, write_mask | write_val);
+
+ return 0;
+}
+
+static const struct clk_funcs rk_usb_clk_funcs = {
+ .get = rk_usb_clk_get,
+ .put = rk_usb_clk_put,
+ .get_rate = rk_usb_clk_get_rate,
+ .enable = rk_usb_clk_enable,
+ .disable = rk_usb_clk_disable,
+};
+
+static struct clk *
+rk_usb_fdt_decode(device_t dev, const void *data, size_t len)
+{
+ struct rk_usb_softc * const sc = device_private(dev);
+
+ if (len != 0)
+ return NULL;
+
+ return &sc->sc_usbclk.base;
+}
+
+static const struct fdtbus_clock_controller_func rk_usb_fdt_funcs = {
+ .decode = rk_usb_fdt_decode
+};
+
+static int
+rk_usb_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+static void
+rk_usb_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk_usb_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ bus_addr_t grf_addr, phy_addr, phy_size;
+ int child;
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ sc->sc_type = of_search_compatible(phandle, compat_data)->data;
+
+ if (fdtbus_get_reg(OF_parent(phandle), 0, &grf_addr, NULL) != 0) {
+ aprint_error(": couldn't get grf registers\n");
+ }
+ if (fdtbus_get_reg(phandle, 0, &phy_addr, &phy_size) != 0) {
+ aprint_error(": couldn't get phy registers\n");
+ return;
+ }
+ if (bus_space_map(sc->sc_bst, grf_addr + phy_addr, phy_size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map phy registers\n");
+ return;
+ }
+
+ const char *clkname = fdtbus_get_string(phandle, "clock-output-names");
+ if (clkname == NULL)
+ clkname = faa->faa_name;
+
+ sc->sc_clkdom.name = device_xname(self);
+ sc->sc_clkdom.funcs = &rk_usb_clk_funcs;
+ sc->sc_clkdom.priv = sc;
+ sc->sc_usbclk.base.domain = &sc->sc_clkdom;
+ sc->sc_usbclk.base.name = kmem_asprintf("%s", clkname);
+ clk_attach(&sc->sc_usbclk.base);
+
+ aprint_naive("\n");
+ aprint_normal(": USB2 PHY\n");
+
+ fdtbus_register_clock_controller(self, phandle, &rk_usb_fdt_funcs);
+
+ 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);
+ }
+}
+
+/*
+ * USB PHY
+ */
+
+static int rk_usbphy_match(device_t, cfdata_t, void *);
+static void rk_usbphy_attach(device_t, device_t, void *);
+
+struct rk_usbphy_softc {
+ device_t sc_dev;
+ int sc_phandle;
+};
+
+CFATTACH_DECL_NEW(rk_usbphy, sizeof(struct rk_usbphy_softc),
+ rk_usbphy_match, rk_usbphy_attach, NULL, NULL);
+
+static void *
+rk_usbphy_acquire(device_t dev, const void *data, size_t len)
+{
+ struct rk_usbphy_softc * const sc = device_private(dev);
+
+ if (len != 0)
+ return NULL;
+
+ return sc;
+}
+
+static void
+rk_usbphy_release(device_t dev, void *priv)
+{
+}
+
+static int
+rk_usbphy_otg_enable(device_t dev, void *priv, bool enable)
+{
+ struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
+
+ const uint32_t write_mask = 0x1ffU << 16;
+ const uint32_t write_val = enable ? 0 : 0x1d1;
+ USB_WRITE(usb_sc, CON0_REG, write_mask | write_val);
+
+ return 0;
+}
+
+static int
+rk_usbphy_host_enable(device_t dev, void *priv, bool enable)
+{
+ struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
+
+ const uint32_t write_mask = 0x1ffU << 16;
+ const uint32_t write_val = enable ? 0 : 0x1d1;
+ USB_WRITE(usb_sc, CON1_REG, write_mask | write_val);
+
+ return 0;
+}
+
+const struct fdtbus_phy_controller_func rk_usbphy_otg_funcs = {
+ .acquire = rk_usbphy_acquire,
+ .release = rk_usbphy_release,
+ .enable = rk_usbphy_otg_enable,
+};
+
+const struct fdtbus_phy_controller_func rk_usbphy_host_funcs = {
+ .acquire = rk_usbphy_acquire,
+ .release = rk_usbphy_release,
+ .enable = rk_usbphy_host_enable,
+};
+
+static int
+rk_usbphy_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ const char *name = fdtbus_get_string(phandle, "name");
+
+ if (strcmp(name, "otg-port") == 0 || strcmp(name, "host-port") == 0)
+ return 1;
+
+ return 0;
+}
+
+static void
+rk_usbphy_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk_usbphy_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ const char *name = fdtbus_get_string(phandle, "name");
+
+ sc->sc_dev = self;
+ sc->sc_phandle = phandle;
+
+ aprint_naive("\n");
+
+ if (strcmp(name, "otg-port") == 0) {
+ aprint_normal(": USB2 OTG port\n");
+ fdtbus_register_phy_controller(self, phandle, &rk_usbphy_otg_funcs);
+ } else if (strcmp(name, "host-port") == 0) {
+ aprint_normal(": USB2 host port\n");
+ fdtbus_register_phy_controller(self, phandle, &rk_usbphy_host_funcs);
+ }
+}
Index: src/sys/dev/fdt/dwc2_fdt.c
diff -u /dev/null src/sys/dev/fdt/dwc2_fdt.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/dev/fdt/dwc2_fdt.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,207 @@
+/* $NetBSD: dwc2_fdt.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Nick Hudson
+ *
+ * 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: dwc2_fdt.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/workqueue.h>
+
+#include <arm/broadcom/bcm2835reg.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <dwc2/dwc2var.h>
+
+#include <dwc2/dwc2.h>
+#include "dwc2_core.h"
+
+struct dwc2_fdt_softc {
+ struct dwc2_softc sc_dwc2;
+
+ struct dwc2_core_params sc_params;
+
+ void *sc_ih;
+ int sc_phandle;
+};
+
+static int dwc2_fdt_match(device_t, struct cfdata *, void *);
+static void dwc2_fdt_attach(device_t, device_t, void *);
+static void dwc2_fdt_deferred(device_t);
+
+static void dwc2_fdt_rockchip_params(struct dwc2_fdt_softc *, struct dwc2_core_params *);
+
+struct dwc2_fdt_config {
+ void (*params)(struct dwc2_fdt_softc *, struct dwc2_core_params *);
+};
+
+static const struct dwc2_fdt_config dwc2_fdt_rk3066_config = {
+ .params = dwc2_fdt_rockchip_params,
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3066-usb", (uintptr_t)&dwc2_fdt_rk3066_config },
+ { NULL }
+};
+
+CFATTACH_DECL_NEW(dwc2_fdt, sizeof(struct dwc2_fdt_softc),
+ dwc2_fdt_match, dwc2_fdt_attach, NULL, NULL);
+
+/* ARGSUSED */
+static int
+dwc2_fdt_match(device_t parent, struct cfdata *match, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+/* ARGSUSED */
+static void
+dwc2_fdt_attach(device_t parent, device_t self, void *aux)
+{
+ struct dwc2_fdt_softc *sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ const struct dwc2_fdt_config *conf =
+ (void *)of_search_compatible(phandle, compat_data)->data;
+ char intrstr[128];
+ struct fdtbus_phy *phy;
+ struct clk *clk;
+ bus_addr_t addr;
+ bus_size_t size;
+ int error;
+
+ const char *dr_mode = fdtbus_get_string(phandle, "dr_mode");
+ if (dr_mode == NULL || strcmp(dr_mode, "host") != 0) {
+ aprint_error(": mode '%s' not supported\n", dr_mode);
+ return;
+ }
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ clk = fdtbus_clock_get(phandle, "otg");
+ if (clk == NULL || clk_enable(clk) != 0) {
+ aprint_error(": couldn't enable otg clock\n");
+ return;
+ }
+
+ /* Enable optional phy */
+ phy = fdtbus_phy_get(phandle, "usb2-phy");
+ if (phy && fdtbus_phy_enable(phy, true) != 0) {
+ aprint_error(": couldn't enable phy\n");
+ return;
+ }
+
+ sc->sc_phandle = phandle;
+ sc->sc_dwc2.sc_dev = self;
+ sc->sc_dwc2.sc_iot = faa->faa_bst;
+ sc->sc_dwc2.sc_bus.ub_dmatag = faa->faa_dmat;
+
+ error = bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_dwc2.sc_ioh);
+ if (error) {
+ aprint_error(": couldn't map device\n");
+ return;
+ }
+
+ if (conf->params) {
+ conf->params(sc, &sc->sc_params);
+ sc->sc_dwc2.sc_params = &sc->sc_params;
+ }
+
+ if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+ aprint_error(": failed to decode interrupt\n");
+ return;
+ }
+
+ aprint_naive("\n");
+ aprint_normal(": DesignWare USB2 OTG\n");
+
+ sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM, FDT_INTR_MPSAFE,
+ dwc2_intr, &sc->sc_dwc2);
+
+ if (sc->sc_ih == NULL) {
+ aprint_error_dev(self, "failed to establish interrupt %s\n",
+ intrstr);
+ goto fail;
+ }
+ aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+ config_interrupts(self, dwc2_fdt_deferred);
+
+ return;
+
+fail:
+ if (sc->sc_ih) {
+ fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih);
+ sc->sc_ih = NULL;
+ }
+ bus_space_unmap(sc->sc_dwc2.sc_iot, sc->sc_dwc2.sc_ioh, size);
+}
+
+static void
+dwc2_fdt_deferred(device_t self)
+{
+ struct dwc2_fdt_softc *sc = device_private(self);
+ int error;
+
+ error = dwc2_init(&sc->sc_dwc2);
+ if (error != 0) {
+ aprint_error_dev(self, "couldn't initialize host, error=%d\n",
+ error);
+ return;
+ }
+ sc->sc_dwc2.sc_child = config_found(sc->sc_dwc2.sc_dev,
+ &sc->sc_dwc2.sc_bus, usbctlprint);
+}
+
+static void
+dwc2_fdt_rockchip_params(struct dwc2_fdt_softc *sc, struct dwc2_core_params *params)
+{
+ dwc2_set_all_params(params, -1);
+
+ params->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+ params->host_rx_fifo_size = 525;
+ params->host_nperio_tx_fifo_size = 128;
+ params->host_perio_tx_fifo_size = 256;
+ params->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
+}
Index: src/sys/dev/fdt/dwcmmc_fdt.c
diff -u /dev/null src/sys/dev/fdt/dwcmmc_fdt.c:1.1
--- /dev/null Sat Jun 16 00:19:04 2018
+++ src/sys/dev/fdt/dwcmmc_fdt.c Sat Jun 16 00:19:04 2018
@@ -0,0 +1,176 @@
+/* $NetBSD: dwcmmc_fdt.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2015-2018 Jared McNeill <[email protected]>
+ * 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: dwcmmc_fdt.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/gpio.h>
+
+#include <dev/ic/dwc_mmc_var.h>
+#include <dev/fdt/fdtvar.h>
+
+static int dwcmmc_fdt_match(device_t, cfdata_t, void *);
+static void dwcmmc_fdt_attach(device_t, device_t, void *);
+
+static int dwcmmc_fdt_card_detect(struct dwc_mmc_softc *);
+
+struct dwcmmc_fdt_config {
+ u_int ciu_div;
+};
+
+static const struct dwcmmc_fdt_config dwcmmc_rk3328_config = {
+ .ciu_div = 2,
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3328-dw-mshc", (uintptr_t)&dwcmmc_rk3328_config },
+ { NULL }
+};
+
+struct dwcmmc_fdt_softc {
+ struct dwc_mmc_softc sc;
+ struct clk *sc_clk_biu;
+ struct clk *sc_clk_ciu;
+ struct fdtbus_gpio_pin *sc_pin_cd;
+ const struct dwcmmc_fdt_config *sc_conf;
+};
+
+CFATTACH_DECL_NEW(dwcmmc_fdt, sizeof(struct dwc_mmc_softc),
+ dwcmmc_fdt_match, dwcmmc_fdt_attach, NULL, NULL);
+
+static int
+dwcmmc_fdt_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+static void
+dwcmmc_fdt_attach(device_t parent, device_t self, void *aux)
+{
+ struct dwcmmc_fdt_softc *esc = device_private(self);
+ struct dwc_mmc_softc *sc = &esc->sc;
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ char intrstr[128];
+ bus_addr_t addr;
+ bus_size_t size;
+ u_int fifo_depth;
+ int error;
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ if (of_getprop_uint32(phandle, "fifo-depth", &fifo_depth))
+ fifo_depth = 0;
+
+ esc->sc_clk_biu = fdtbus_clock_get(phandle, "biu");
+ if (esc->sc_clk_biu == NULL) {
+ aprint_error(": couldn't get clock biu\n");
+ return;
+ }
+ esc->sc_clk_ciu = fdtbus_clock_get(phandle, "ciu");
+ if (esc->sc_clk_ciu == NULL) {
+ aprint_error(": couldn't get clock ciu\n");
+ return;
+ }
+
+ error = clk_enable(esc->sc_clk_biu);
+ if (error) {
+ aprint_error(": couldn't enable clock biu: %d\n", error);
+ return;
+ }
+ error = clk_enable(esc->sc_clk_ciu);
+ if (error) {
+ aprint_error(": couldn't enable clock ciu: %d\n", error);
+ return;
+ }
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ sc->sc_dmat = faa->faa_dmat;
+ error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
+ if (error) {
+ aprint_error(": couldn't map %#llx: %d\n",
+ (uint64_t)addr, error);
+ return;
+ }
+ esc->sc_conf = of_search_compatible(phandle, compat_data)->data;
+
+ const u_int ciu_div = esc->sc_conf->ciu_div > 0 ? esc->sc_conf->ciu_div : 1;
+
+ sc->sc_clock_freq = clk_get_rate(esc->sc_clk_ciu) / (ciu_div + 1);
+ sc->sc_fifo_depth = fifo_depth;
+ sc->sc_flags = DWC_MMC_F_USE_HOLD_REG | DWC_MMC_F_DMA;
+
+ esc->sc_pin_cd = fdtbus_gpio_acquire(phandle, "cd-gpios",
+ GPIO_PIN_INPUT);
+ if (esc->sc_pin_cd)
+ sc->sc_card_detect = dwcmmc_fdt_card_detect;
+
+ aprint_naive("\n");
+ aprint_normal(": SD/MMC controller (%u Hz)\n", sc->sc_clock_freq);
+
+ if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+ aprint_error_dev(self, "failed to decode interrupt\n");
+ return;
+ }
+
+ if (dwc_mmc_init(sc) != 0)
+ return;
+
+ sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_BIO, 0,
+ dwc_mmc_intr, sc);
+ if (sc->sc_ih == NULL) {
+ aprint_error_dev(self, "couldn't establish interrupt on %s\n",
+ intrstr);
+ return;
+ }
+ aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+}
+
+static int
+dwcmmc_fdt_card_detect(struct dwc_mmc_softc *sc)
+{
+ struct dwcmmc_fdt_softc *esc = device_private(sc->sc_dev);
+
+ KASSERT(esc->sc_pin_cd != NULL);
+
+ return fdtbus_gpio_read(esc->sc_pin_cd);
+}