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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(1, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RK3328_CRU_H +#define _RK3328_CRU_H + +#define 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ARM_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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_soc.h" +#include "opt_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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ARM_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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_soc.h" +#include "opt_multiprocessor.h" +#include "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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(0, "$NetBSD: 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 <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: 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); +}