Module Name: src
Committed By: jmcneill
Date: Sun Aug 12 16:48:05 UTC 2018
Modified Files:
src/sys/arch/arm/rockchip: files.rockchip rk3328_cru.c rk_cru.c
rk_cru.h rk_cru_pll.c rk_gmac.c rk_platform.c rk_usb.c
Added Files:
src/sys/arch/arm/rockchip: rk3328_iomux.c rk3399_cru.c rk3399_cru.h
rk3399_iomux.c rk3399_platform.h rk3399_pmucru.c rk3399_pmucru.h
Removed Files:
src/sys/arch/arm/rockchip: rk_iomux.c
Log Message:
Add support for Rockchip RK3399 SoC.
To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/arm/rockchip/files.rockchip
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/rockchip/rk3328_cru.c \
src/sys/arch/arm/rockchip/rk_cru_pll.c src/sys/arch/arm/rockchip/rk_usb.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/rockchip/rk3328_iomux.c \
src/sys/arch/arm/rockchip/rk3399_cru.c \
src/sys/arch/arm/rockchip/rk3399_cru.h \
src/sys/arch/arm/rockchip/rk3399_iomux.c \
src/sys/arch/arm/rockchip/rk3399_platform.h \
src/sys/arch/arm/rockchip/rk3399_pmucru.c \
src/sys/arch/arm/rockchip/rk3399_pmucru.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/rockchip/rk_cru.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/rockchip/rk_cru.h \
src/sys/arch/arm/rockchip/rk_platform.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/rockchip/rk_gmac.c
cvs rdiff -u -r1.3 -r0 src/sys/arch/arm/rockchip/rk_iomux.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/rockchip/files.rockchip
diff -u src/sys/arch/arm/rockchip/files.rockchip:1.14 src/sys/arch/arm/rockchip/files.rockchip:1.15
--- src/sys/arch/arm/rockchip/files.rockchip:1.14 Sun Jul 1 18:16:58 2018
+++ src/sys/arch/arm/rockchip/files.rockchip Sun Aug 12 16:48:04 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.rockchip,v 1.14 2018/07/01 18:16:58 jmcneill Exp $
+# $NetBSD: files.rockchip,v 1.15 2018/08/12 16:48:04 jmcneill Exp $
#
# Configuration info for Rockchip family SoCs
#
@@ -19,10 +19,18 @@ file arch/arm/rockchip/rk_cru_pll.c rk_
attach rkcru at fdt with rk3328_cru
file arch/arm/rockchip/rk3328_cru.c rk3328_cru & soc_rk3328
+# RK3399 clock and reset unit
+attach rkcru at fdt with rk3399_cru
+file arch/arm/rockchip/rk3399_cru.c rk3399_cru & soc_rk3399
+attach rkcru at fdt with rk3399_pmucru
+file arch/arm/rockchip/rk3399_pmucru.c rk3399_pmucru & soc_rk3399
+
# IOMUX control
device rkiomux { }
-attach rkiomux at fdt with rk_iomux
-file arch/arm/rockchip/rk_iomux.c rk_iomux
+attach rkiomux at fdt with rk3328_iomux
+file arch/arm/rockchip/rk3328_iomux.c rk3328_iomux & soc_rk3328
+attach rkiomux at fdt with rk3399_iomux
+file arch/arm/rockchip/rk3399_iomux.c rk3399_iomux & soc_rk3399
# GPIO
device rkgpio: gpiobus
@@ -48,3 +56,4 @@ file arch/arm/rockchip/rk_gmac.c rk_gma
# SOC parameters
defflag opt_soc.h SOC_ROCKCHIP
defflag opt_soc.h SOC_RK3328: SOC_ROCKCHIP
+defflag opt_soc.h SOC_RK3399: SOC_ROCKCHIP
Index: src/sys/arch/arm/rockchip/rk3328_cru.c
diff -u src/sys/arch/arm/rockchip/rk3328_cru.c:1.3 src/sys/arch/arm/rockchip/rk3328_cru.c:1.4
--- src/sys/arch/arm/rockchip/rk3328_cru.c:1.3 Sun Jul 1 18:15:19 2018
+++ src/sys/arch/arm/rockchip/rk3328_cru.c Sun Aug 12 16:48:04 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk3328_cru.c,v 1.3 2018/07/01 18:15:19 jmcneill Exp $ */
+/* $NetBSD: rk3328_cru.c,v 1.4 2018/08/12 16:48:04 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: rk3328_cru.c,v 1.3 2018/07/01 18:15:19 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rk3328_cru.c,v 1.4 2018/08/12 16:48:04 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -44,6 +44,7 @@ __KERNEL_RCSID(1, "$NetBSD: rk3328_cru.c
#define MISC_CON 0x0084
#define CLKSEL_CON(n) (0x0100 + (n) * 4)
#define CLKGATE_CON(n) (0x0200 + (n) * 4)
+#define SOFTRST_CON(n) (0x0300 + (n) * 4)
#define GRF_SOC_CON4 0x0410
#define GRF_MAC_CON1 0x0904
@@ -131,6 +132,7 @@ static const struct rk_cru_arm_rate armc
RK_ARM_RATE( 96000000, 1),
};
+static const char * pll_parents[] = { "xin24m" };
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" };
@@ -151,31 +153,31 @@ static const char * comp_uart_parents[]
static const char * pclk_gmac_parents[] = { "aclk_gmac" };
static struct rk_cru_clk rk3328_cru_clks[] = {
- RK_PLL(RK3328_PLL_APLL, "apll", "xin24m",
+ RK_PLL(RK3328_PLL_APLL, "apll", pll_parents,
PLL_CON(0), /* con_base */
0x80, /* mode_reg */
__BIT(0), /* mode_mask */
__BIT(4), /* lock_mask */
pll_frac_rates),
- RK_PLL(RK3328_PLL_DPLL, "dpll", "xin24m",
+ RK_PLL(RK3328_PLL_DPLL, "dpll", pll_parents,
PLL_CON(8), /* con_base */
0x80, /* mode_reg */
__BIT(4), /* mode_mask */
__BIT(3), /* lock_mask */
pll_norates),
- RK_PLL(RK3328_PLL_CPLL, "cpll", "xin24m",
+ RK_PLL(RK3328_PLL_CPLL, "cpll", pll_parents,
PLL_CON(16), /* con_base */
0x80, /* mode_reg */
__BIT(8), /* mode_mask */
__BIT(2), /* lock_mask */
pll_rates),
- RK_PLL(RK3328_PLL_GPLL, "gpll", "xin24m",
+ RK_PLL(RK3328_PLL_GPLL, "gpll", pll_parents,
PLL_CON(24), /* con_base */
0x80, /* mode_reg */
__BIT(12), /* mode_mask */
__BIT(1), /* lock_mask */
pll_frac_rates),
- RK_PLL(RK3328_PLL_NPLL, "npll", "xin24m",
+ RK_PLL(RK3328_PLL_NPLL, "npll", pll_parents,
PLL_CON(40), /* con_base */
0x80, /* mode_reg */
__BIT(1), /* mode_mask */
@@ -398,6 +400,8 @@ rk3328_cru_attach(device_t parent, devic
sc->sc_clks = rk3328_cru_clks;
sc->sc_nclks = __arraycount(rk3328_cru_clks);
+ sc->sc_softrst_base = SOFTRST_CON(0);
+
if (rk_cru_attach(sc) != 0)
return;
Index: src/sys/arch/arm/rockchip/rk_cru_pll.c
diff -u src/sys/arch/arm/rockchip/rk_cru_pll.c:1.3 src/sys/arch/arm/rockchip/rk_cru_pll.c:1.4
--- src/sys/arch/arm/rockchip/rk_cru_pll.c:1.3 Sat Jun 30 17:54:07 2018
+++ src/sys/arch/arm/rockchip/rk_cru_pll.c Sun Aug 12 16:48:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru_pll.c,v 1.3 2018/06/30 17:54:07 jmcneill Exp $ */
+/* $NetBSD: rk_cru_pll.c,v 1.4 2018/08/12 16:48:05 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_cru_pll.c,v 1.3 2018/06/30 17:54:07 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_cru_pll.c,v 1.4 2018/08/12 16:48:05 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -169,5 +169,5 @@ rk_cru_pll_get_parent(struct rk_cru_soft
KASSERT(clk->type == RK_CRU_PLL);
- return pll->parent;
+ return pll->parents[0];
}
Index: src/sys/arch/arm/rockchip/rk_usb.c
diff -u src/sys/arch/arm/rockchip/rk_usb.c:1.3 src/sys/arch/arm/rockchip/rk_usb.c:1.4
--- src/sys/arch/arm/rockchip/rk_usb.c:1.3 Sat Jun 30 18:07:32 2018
+++ src/sys/arch/arm/rockchip/rk_usb.c Sun Aug 12 16:48:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_usb.c,v 1.3 2018/06/30 18:07:32 jmcneill Exp $ */
+/* $NetBSD: rk_usb.c,v 1.4 2018/08/12 16:48:05 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1.3 2018/06/30 18:07:32 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1.4 2018/08/12 16:48:05 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -46,17 +46,31 @@ __KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1
static int rk_usb_match(device_t, cfdata_t, void *);
static void rk_usb_attach(device_t, device_t, void *);
-#define CON0_REG 0x100
-#define CON1_REG 0x104
-#define CON2_REG 0x108
-#define USBPHY_COMMONONN __BIT(4)
+#define RK3328_CON0_REG 0x100
+#define RK3328_CON1_REG 0x104
+#define RK3328_CON2_REG 0x108
+#define RK3328_USBPHY_COMMONONN __BIT(4)
+
+#define RK3399_GRF_USB20_PHY0_CON0_REG 0x0e450
+#define RK3399_GRF_USB20_PHY1_CON0_REG 0x0e460
+#define RK3399_USBPHY_COMMONONN __BIT(4)
+#define RK3399_GRF_USB20_PHY0_CON1_REG 0x0e454
+#define RK3399_GRF_USB20_PHY1_CON1_REG 0x0e464
+#define RK3399_GRF_USB20_PHY0_CON2_REG 0x0e458
+#define RK3399_GRF_USB20_PHY1_CON2_REG 0x0e468
+#define RK3399_USBPHY_SUSPEND_N __BIT(1)
+#define RK3399_USBPHY_UTMI_SEL __BIT(0)
+
+#define RK3399_PHY_NO(_sc) ((_sc)->sc_reg == 0xe450 ? 0 : 1)
enum rk_usb_type {
USB_RK3328 = 1,
+ USB_RK3399,
};
static const struct of_compat_data compat_data[] = {
{ "rockchip,rk3328-usb2phy", USB_RK3328 },
+ { "rockchip,rk3399-usb2phy", USB_RK3399 },
{ NULL }
};
@@ -71,6 +85,8 @@ struct rk_usb_softc {
struct clk_domain sc_clkdom;
struct rk_usb_clk sc_usbclk;
+
+ bus_addr_t sc_reg;
};
CFATTACH_DECL_NEW(rk_usb, sizeof(struct rk_usb_softc),
@@ -102,12 +118,27 @@ static int
rk_usb_clk_enable(void *priv, struct clk *clk)
{
struct rk_usb_softc * const sc = priv;
+ uint32_t reg, write_mask, write_val;
- const uint32_t write_mask = USBPHY_COMMONONN << 16;
- const uint32_t write_val = 0;
+ switch (sc->sc_type) {
+ case USB_RK3328:
+ reg = RK3328_CON2_REG;
+ write_mask = RK3328_USBPHY_COMMONONN << 16;
+ write_val = 0;
+ break;
+ case USB_RK3399:
+ reg = RK3399_PHY_NO(sc) == 0 ?
+ RK3399_GRF_USB20_PHY0_CON0_REG :
+ RK3399_GRF_USB20_PHY1_CON0_REG;
+ write_mask = RK3399_USBPHY_COMMONONN << 16;
+ write_val = 0;
+ break;
+ default:
+ return ENXIO;
+ }
syscon_lock(sc->sc_syscon);
- syscon_write_4(sc->sc_syscon, CON2_REG, write_mask | write_val);
+ syscon_write_4(sc->sc_syscon, reg, write_mask | write_val);
syscon_unlock(sc->sc_syscon);
return 0;
@@ -117,12 +148,27 @@ static int
rk_usb_clk_disable(void *priv, struct clk *clk)
{
struct rk_usb_softc * const sc = priv;
+ uint32_t reg, write_mask, write_val;
- const uint32_t write_mask = USBPHY_COMMONONN << 16;
- const uint32_t write_val = USBPHY_COMMONONN;
+ switch (sc->sc_type) {
+ case USB_RK3328:
+ reg = RK3328_CON2_REG;
+ write_mask = RK3328_USBPHY_COMMONONN << 16;
+ write_val = RK3328_USBPHY_COMMONONN;
+ break;
+ case USB_RK3399:
+ reg = RK3399_PHY_NO(sc) == 0 ?
+ RK3399_GRF_USB20_PHY0_CON0_REG :
+ RK3399_GRF_USB20_PHY1_CON0_REG;
+ write_mask = RK3399_USBPHY_COMMONONN << 16;
+ write_val = RK3399_USBPHY_COMMONONN;
+ break;
+ default:
+ return ENXIO;
+ }
syscon_lock(sc->sc_syscon);
- syscon_write_4(sc->sc_syscon, CON2_REG, write_mask | write_val);
+ syscon_write_4(sc->sc_syscon, reg, write_mask | write_val);
syscon_unlock(sc->sc_syscon);
return 0;
@@ -165,8 +211,22 @@ rk_usb_attach(device_t parent, device_t
struct rk_usb_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
+ struct clk *clk;
int child;
+ /* Cache the base address of this PHY so we know which instance we are */
+ if (fdtbus_get_reg(phandle, 0, &sc->sc_reg, NULL) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ clk = fdtbus_clock_get(phandle, "phyclk");
+KASSERT(clk != NULL);
+ if (clk && clk_enable(clk) != 0) {
+ aprint_error(": couldn't enable phy clock\n");
+ return;
+ }
+
sc->sc_dev = self;
sc->sc_type = of_search_compatible(phandle, compat_data)->data;
sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(phandle));
@@ -214,6 +274,7 @@ static void rk_usbphy_attach(device_t, d
struct rk_usbphy_softc {
device_t sc_dev;
int sc_phandle;
+ struct fdtbus_regulator *sc_supply;
};
CFATTACH_DECL_NEW(rk_usbphy, sizeof(struct rk_usbphy_softc),
@@ -238,13 +299,37 @@ rk_usbphy_release(device_t dev, void *pr
static int
rk_usbphy_otg_enable(device_t dev, void *priv, bool enable)
{
+ struct rk_usbphy_softc * const sc = device_private(dev);
struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
+ uint32_t reg, write_mask, write_val;
+ int error;
- const uint32_t write_mask = 0x1ffU << 16;
- const uint32_t write_val = enable ? 0 : 0x1d1;
+ switch (usb_sc->sc_type) {
+ case USB_RK3328:
+ reg = RK3328_CON0_REG;
+ write_mask = 0x1ffU << 16;
+ write_val = enable ? 0 : 0x1d1;
+ break;
+ case USB_RK3399:
+ reg = RK3399_PHY_NO(usb_sc) == 0 ?
+ RK3399_GRF_USB20_PHY0_CON1_REG :
+ RK3399_GRF_USB20_PHY1_CON1_REG;
+ write_mask = (RK3399_USBPHY_SUSPEND_N|RK3399_USBPHY_UTMI_SEL) << 16;
+ write_val = RK3399_USBPHY_UTMI_SEL;
+ break;
+ default:
+ return ENXIO;
+ }
+
+ if (sc->sc_supply) {
+ error = enable ? fdtbus_regulator_enable(sc->sc_supply) :
+ fdtbus_regulator_disable(sc->sc_supply);
+ if (error != 0)
+ return error;
+ }
syscon_lock(usb_sc->sc_syscon);
- syscon_write_4(usb_sc->sc_syscon, CON0_REG, write_mask | write_val);
+ syscon_write_4(usb_sc->sc_syscon, reg, write_mask | write_val);
syscon_unlock(usb_sc->sc_syscon);
return 0;
@@ -253,13 +338,37 @@ rk_usbphy_otg_enable(device_t dev, void
static int
rk_usbphy_host_enable(device_t dev, void *priv, bool enable)
{
+ struct rk_usbphy_softc * const sc = device_private(dev);
struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
+ uint32_t reg, write_mask, write_val;
+ int error;
- const uint32_t write_mask = 0x1ffU << 16;
- const uint32_t write_val = enable ? 0 : 0x1d1;
+ switch (usb_sc->sc_type) {
+ case USB_RK3328:
+ reg = RK3328_CON1_REG;
+ write_mask = 0x1ffU << 16;
+ write_val = enable ? 0 : 0x1d1;
+ break;
+ case USB_RK3399:
+ reg = RK3399_PHY_NO(usb_sc) == 0 ?
+ RK3399_GRF_USB20_PHY0_CON2_REG :
+ RK3399_GRF_USB20_PHY1_CON2_REG;
+ write_mask = (RK3399_USBPHY_SUSPEND_N|RK3399_USBPHY_UTMI_SEL) << 16;
+ write_val = RK3399_USBPHY_UTMI_SEL;
+ break;
+ default:
+ return ENXIO;
+ }
+
+ if (sc->sc_supply) {
+ error = enable ? fdtbus_regulator_enable(sc->sc_supply) :
+ fdtbus_regulator_disable(sc->sc_supply);
+ if (error != 0)
+ return error;
+ }
syscon_lock(usb_sc->sc_syscon);
- syscon_write_4(usb_sc->sc_syscon, CON1_REG, write_mask | write_val);
+ syscon_write_4(usb_sc->sc_syscon, reg, write_mask | write_val);
syscon_unlock(usb_sc->sc_syscon);
return 0;
@@ -300,6 +409,13 @@ rk_usbphy_attach(device_t parent, device
sc->sc_dev = self;
sc->sc_phandle = phandle;
+ if (of_hasprop(phandle, "phy-supply")) {
+ sc->sc_supply = fdtbus_regulator_acquire(phandle, "phy-supply");
+ if (sc->sc_supply == NULL) {
+ aprint_error(": couldn't acquire regulator\n");
+ return;
+ }
+ }
aprint_naive("\n");
Index: src/sys/arch/arm/rockchip/rk_cru.c
diff -u src/sys/arch/arm/rockchip/rk_cru.c:1.4 src/sys/arch/arm/rockchip/rk_cru.c:1.5
--- src/sys/arch/arm/rockchip/rk_cru.c:1.4 Sat Jun 30 17:54:07 2018
+++ src/sys/arch/arm/rockchip/rk_cru.c Sun Aug 12 16:48:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru.c,v 1.4 2018/06/30 17:54:07 jmcneill Exp $ */
+/* $NetBSD: rk_cru.c,v 1.5 2018/08/12 16:48:05 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -30,7 +30,7 @@
#include "opt_fdt_arm.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_cru.c,v 1.4 2018/06/30 17:54:07 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_cru.c,v 1.5 2018/08/12 16:48:05 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -43,8 +43,6 @@ __KERNEL_RCSID(0, "$NetBSD: rk_cru.c,v 1
#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)
{
@@ -64,7 +62,7 @@ rk_cru_reset_assert(device_t dev, void *
{
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 / 16) * 4;
+ const bus_size_t reg = sc->sc_softrst_base + (reset_id / 16) * 4;
const u_int shift = reset_id % 16;
CRU_WRITE(sc, reg, (1 << (shift + 16)) | (1 << shift));
@@ -77,7 +75,7 @@ rk_cru_reset_deassert(device_t dev, void
{
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 / 16) * 4;
+ const bus_size_t reg = sc->sc_softrst_base + (reset_id / 16) * 4;
const u_int shift = reset_id % 16;
CRU_WRITE(sc, reg, (1 << (shift + 16)) | (0 << shift));
@@ -357,13 +355,13 @@ rk_cru_print(struct rk_cru_softc *sc)
default: type = "???"; break;
}
- aprint_debug_dev(sc->sc_dev,
+ aprint_normal_dev(sc->sc_dev,
"%3d %-14s %2s %-14s %-7s ",
clk->id,
clk->base.name,
clkp_parent ? "<-" : "",
clkp_parent ? clkp_parent->name : "",
type);
- aprint_debug("%10d Hz\n", clk_get_rate(&clk->base));
+ aprint_normal("%10d Hz\n", clk_get_rate(&clk->base));
}
}
Index: src/sys/arch/arm/rockchip/rk_cru.h
diff -u src/sys/arch/arm/rockchip/rk_cru.h:1.2 src/sys/arch/arm/rockchip/rk_cru.h:1.3
--- src/sys/arch/arm/rockchip/rk_cru.h:1.2 Sat Jun 30 17:54:07 2018
+++ src/sys/arch/arm/rockchip/rk_cru.h Sun Aug 12 16:48:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_cru.h,v 1.2 2018/06/30 17:54:07 jmcneill Exp $ */
+/* $NetBSD: rk_cru.h,v 1.3 2018/08/12 16:48:05 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -78,20 +78,22 @@ struct rk_cru_pll {
uint32_t lock_mask;
const struct rk_cru_pll_rate *rates;
u_int nrates;
- const char *parent;
+ const char **parents;
+ u_int nparents;
};
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) \
+#define RK_PLL(_id, _name, _parents, _con_base, _mode_reg, _mode_mask, _lock_mask, _rates) \
{ \
.id = (_id), \
.type = RK_CRU_PLL, \
.base.name = (_name), \
.base.flags = 0, \
- .u.pll.parent = (_parent), \
+ .u.pll.parents = (_parents), \
+ .u.pll.nparents = __arraycount(_parents), \
.u.pll.con_base = (_con_base), \
.u.pll.mode_reg = (_mode_reg), \
.u.pll.mode_mask = (_mode_mask), \
@@ -195,6 +197,15 @@ int rk_cru_composite_set_parent(struct r
.set_parent = rk_cru_composite_set_parent, \
}
+#define RK_COMPOSITE_NOMUX(_id, _name, _parent, _div_reg, _div_mask, _gate_reg, _gate_mask, _flags) \
+ RK_COMPOSITE(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, _gate_reg, _gate_mask, _flags)
+
+#define RK_COMPOSITE_NOGATE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _flags) \
+ RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, 0, 0, _flags)
+
+#define RK_DIV(_id, _name, _parent, _div_reg, _div_mask, _flags) \
+ RK_COMPOSITE(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, 0, 0, _flags)
+
/* Gate clocks */
struct rk_cru_gate {
@@ -300,6 +311,8 @@ struct rk_cru_softc {
struct rk_cru_clk *sc_clks;
u_int sc_nclks;
+
+ bus_size_t sc_softrst_base;
};
int rk_cru_attach(struct rk_cru_softc *);
Index: src/sys/arch/arm/rockchip/rk_platform.c
diff -u src/sys/arch/arm/rockchip/rk_platform.c:1.2 src/sys/arch/arm/rockchip/rk_platform.c:1.3
--- src/sys/arch/arm/rockchip/rk_platform.c:1.2 Sun Aug 5 14:02:35 2018
+++ src/sys/arch/arm/rockchip/rk_platform.c Sun Aug 12 16:48:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_platform.c,v 1.2 2018/08/05 14:02:35 skrll Exp $ */
+/* $NetBSD: rk_platform.c,v 1.3 2018/08/12 16:48:05 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -31,7 +31,7 @@
#include "opt_fdt_arm.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_platform.c,v 1.2 2018/08/05 14:02:35 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_platform.c,v 1.3 2018/08/12 16:48:05 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -158,3 +158,61 @@ static const struct arm_platform rk3328_
ARM_PLATFORM(rk3328, "rockchip,rk3328", &rk3328_platform);
#endif /* SOC_RK3328 */
+
+
+#ifdef SOC_RK3399
+
+#include <arm/rockchip/rk3399_platform.h>
+
+static const struct pmap_devmap *
+rk3399_platform_devmap(void)
+{
+ static const struct pmap_devmap devmap[] = {
+ DEVMAP_ENTRY(RK3399_CORE_VBASE,
+ RK3399_CORE_PBASE,
+ RK3399_CORE_SIZE),
+ DEVMAP_ENTRY_END
+ };
+
+ return devmap;
+}
+
+void rk3399_platform_early_putchar(char);
+
+void
+rk3399_platform_early_putchar(char c)
+{
+#ifdef CONSADDR
+#define CONSADDR_VA ((CONSADDR - RK3399_CORE_PBASE) + RK3399_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
+rk3399_platform_uart_freq(void)
+{
+ return RK3399_UART_FREQ;
+}
+
+static const struct arm_platform rk3399_platform = {
+ .ap_devmap = rk3399_platform_devmap,
+ .ap_bootstrap = rk_platform_bootstrap,
+ .ap_init_attach_args = rk_platform_init_attach_args,
+ .ap_early_putchar = rk3399_platform_early_putchar,
+ .ap_device_register = rk_platform_device_register,
+ .ap_reset = psci_fdt_reset,
+ .ap_delay = gtmr_delay,
+ .ap_uart_freq = rk3399_platform_uart_freq,
+};
+
+ARM_PLATFORM(rk3399, "rockchip,rk3399", &rk3399_platform);
+
+#endif /* SOC_RK3399 */
Index: src/sys/arch/arm/rockchip/rk_gmac.c
diff -u src/sys/arch/arm/rockchip/rk_gmac.c:1.7 src/sys/arch/arm/rockchip/rk_gmac.c:1.8
--- src/sys/arch/arm/rockchip/rk_gmac.c:1.7 Mon Jul 16 23:11:47 2018
+++ src/sys/arch/arm/rockchip/rk_gmac.c Sun Aug 12 16:48:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_gmac.c,v 1.7 2018/07/16 23:11:47 christos Exp $ */
+/* $NetBSD: rk_gmac.c,v 1.8 2018/08/12 16:48:05 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 1.7 2018/07/16 23:11:47 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 1.8 2018/08/12 16:48:05 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -49,6 +49,30 @@ __KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v
#include <dev/fdt/fdtvar.h>
#include <dev/fdt/syscon.h>
+#define RK_GMAC_TXDLY_DEFAULT 0x30
+#define RK_GMAC_RXDLY_DEFAULT 0x10
+
+enum rk_gmac_type {
+ GMAC_RK3328 = 1,
+ GMAC_RK3399
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3328-gmac", GMAC_RK3328 },
+ { "rockchip,rk3399-gmac", GMAC_RK3399 },
+ { NULL }
+};
+
+struct rk_gmac_softc {
+ struct dwc_gmac_softc sc_base;
+ struct syscon *sc_syscon;
+ enum rk_gmac_type sc_type;
+};
+
+/*
+ * RK3328 specific
+ */
+
#define RK3328_GRF_MAC_CON0 0x0900
#define RK3328_GRF_MAC_CON0_RXDLY __BITS(13,7)
#define RK3328_GRF_MAC_CON0_TXDLY __BITS(6,0)
@@ -64,56 +88,6 @@ __KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v
#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;
- struct syscon *sc_syscon;
-};
-
-static int
-rk_gmac_reset(const int phandle)
-{
- struct fdtbus_gpio_pin *pin_reset;
- const u_int *reset_delay_us;
- bool reset_active_low;
- int len;
-
- 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");
-
- fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0);
- delay(be32toh(reset_delay_us[0]));
- fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1);
- delay(be32toh(reset_delay_us[1]));
- fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0);
- delay(be32toh(reset_delay_us[2]));
-
- 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)
{
@@ -167,6 +141,112 @@ rk3328_gmac_set_speed_rgmii(struct dwc_g
syscon_unlock(rk_sc->sc_syscon);
}
+/*
+ * RK3399 specific
+ */
+
+#define RK3399_GRF_SOC_CON5 0x0c214
+#define RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL __BITS(11,9)
+#define RK3399_GRF_SOC_CON5_GMAC_FLOWCTRL __BIT(8)
+#define RK3399_GRF_SOC_CON5_GMAC_SPEED __BIT(7)
+#define RK3399_GRF_SOC_CON5_RMII_MODE __BIT(6)
+#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL __BITS(5,4)
+#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_125M 0
+#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_25M 1
+#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_2_5M 2
+#define RK3399_GRF_SOC_CON5_RMII_CLK_SEL __BIT(3)
+#define RK3399_GRF_SOC_CON6 0x0c218
+#define RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA __BIT(15)
+#define RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG __BITS(14,8)
+#define RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA __BIT(7)
+#define RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG __BITS(6,0)
+
+static void
+rk3399_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 con5_mask =
+ (RK3399_GRF_SOC_CON5_RMII_MODE | RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL) << 16;
+ const uint32_t con5 = __SHIFTIN(1, RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL);
+
+ const uint32_t con6_mask =
+ (RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG | RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG) << 16;
+ const uint32_t con6 =
+ __SHIFTIN(rx_delay, RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG) |
+ __SHIFTIN(tx_delay, RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG);
+
+ syscon_lock(rk_sc->sc_syscon);
+ syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON5, con5 | con5_mask);
+ syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON6, con6 | con6_mask);
+ syscon_unlock(rk_sc->sc_syscon);
+}
+
+static void
+rk3399_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 = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_2_5M;
+ break;
+ case IFM_100_TX:
+ clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_25M;
+ break;
+ default:
+ clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_125M;
+ break;
+ }
+
+ const uint32_t con5_mask =
+ RK3399_GRF_SOC_CON5_GMAC_CLK_SEL << 16;
+ const uint32_t con5 =
+ __SHIFTIN(clksel, RK3399_GRF_SOC_CON5_GMAC_CLK_SEL);
+
+ syscon_lock(rk_sc->sc_syscon);
+ syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON5, con5 | con5_mask);
+ syscon_unlock(rk_sc->sc_syscon);
+}
+
+static int
+rk_gmac_reset(const int phandle)
+{
+ struct fdtbus_gpio_pin *pin_reset;
+ const u_int *reset_delay_us;
+ bool reset_active_low;
+ int len;
+
+ 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");
+
+ fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0);
+ delay(be32toh(reset_delay_us[0]));
+ fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1);
+ delay(be32toh(reset_delay_us[1]));
+ fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0);
+ delay(be32toh(reset_delay_us[2]));
+
+ return 0;
+}
+
+static int
+rk_gmac_intr(void *arg)
+{
+ return dwc_gmac_intr(arg);
+}
+
static int
rk_gmac_setup_clocks(int phandle)
{
@@ -234,7 +314,7 @@ rk_gmac_match(device_t parent, cfdata_t
{
struct fdt_attach_args * const faa = aux;
- return of_match_compatible(faa->faa_phandle, compatible);
+ return of_match_compat_data(faa->faa_phandle, compat_data);
}
static void
@@ -255,6 +335,8 @@ rk_gmac_attach(device_t parent, device_t
return;
}
+ rk_sc->sc_type = of_search_compatible(phandle, compat_data)->data;
+
rk_sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf");
if (rk_sc->sc_syscon == NULL) {
aprint_error(": couldn't get grf syscon\n");
@@ -300,13 +382,27 @@ rk_gmac_attach(device_t parent, device_t
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;
+ switch (rk_sc->sc_type) {
+ case GMAC_RK3328:
+ 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;
+ }
+ break;
+ case GMAC_RK3399:
+ if (strcmp(phy_mode, "rgmii") == 0) {
+ rk3399_gmac_set_mode_rgmii(sc, tx_delay, rx_delay);
+
+ sc->sc_set_speed = rk3399_gmac_set_speed_rgmii;
+ } else {
+ aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
+ return;
+ }
+ break;
}
aprint_naive("\n");
Added files:
Index: src/sys/arch/arm/rockchip/rk3328_iomux.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3328_iomux.c:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3328_iomux.c Sun Aug 12 16:48:04 2018
@@ -0,0 +1,314 @@
+/* $NetBSD: rk3328_iomux.c,v 1.1 2018/08/12 16:48:04 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rk3328_iomux.c,v 1.1 2018/08/12 16:48: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>
+#include <dev/fdt/syscon.h>
+
+#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 rk3328_iomux {
+ bus_size_t base;
+ u_int type;
+#define RK3328_IOMUX_TYPE_3BIT 0x01
+};
+
+struct rk3328_iomux_bank {
+ struct rk3328_iomux iomux[4];
+};
+
+static const struct rk3328_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 = RK3328_IOMUX_TYPE_3BIT },
+ [2] = { .base = 0x002c, .type = RK3328_IOMUX_TYPE_3BIT },
+ [3] = { .base = 0x0034 },
+ },
+ },
+ [3] = {
+ .iomux = {
+ [0] = { .base = 0x0038, .type = RK3328_IOMUX_TYPE_3BIT },
+ [1] = { .base = 0x0040, .type = RK3328_IOMUX_TYPE_3BIT },
+ [2] = { .base = 0x0048 },
+ [3] = { .base = 0x004c },
+ },
+ },
+};
+
+struct rk3328_iomux_conf {
+ const struct rk3328_iomux_bank *banks;
+ u_int nbanks;
+};
+
+static const struct rk3328_iomux_conf rk3328_iomux_conf = {
+ .banks = rk3328_iomux_banks,
+ .nbanks = __arraycount(rk3328_iomux_banks),
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3328-pinctrl", (uintptr_t)&rk3328_iomux_conf },
+ { NULL }
+};
+
+struct rk3328_iomux_softc {
+ device_t sc_dev;
+ struct syscon *sc_syscon;
+
+ const struct rk3328_iomux_conf *sc_conf;
+};
+
+#define LOCK(sc) \
+ syscon_lock((sc)->sc_syscon)
+#define UNLOCK(sc) \
+ syscon_unlock((sc)->sc_syscon)
+#define RD4(sc, reg) \
+ syscon_read_4((sc)->sc_syscon, (reg))
+#define WR4(sc, reg, val) \
+ syscon_write_4((sc)->sc_syscon, (reg), (val))
+
+static int rk3328_iomux_match(device_t, cfdata_t, void *);
+static void rk3328_iomux_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(rk3328_iomux, sizeof(struct rk3328_iomux_softc),
+ rk3328_iomux_match, rk3328_iomux_attach, NULL, NULL);
+
+static void
+rk3328_iomux_calc_iomux_reg(struct rk3328_iomux_softc *sc, u_int bank, u_int pin, bus_size_t *reg, uint32_t *mask)
+{
+ const struct rk3328_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 & RK3328_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
+rk3328_iomux_set_bias(struct rk3328_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
+rk3328_iomux_set_drive_strength(struct rk3328_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
+rk3328_iomux_set_mux(struct rk3328_iomux_softc *sc, u_int bank, u_int idx, u_int mux)
+{
+ bus_size_t reg;
+ uint32_t mask;
+
+ rk3328_iomux_calc_iomux_reg(sc, bank, idx, ®, &mask);
+
+ WR4(sc, reg, (mask << 16) | __SHIFTIN(mux, mask));
+}
+
+static int
+rk3328_iomux_config(struct rk3328_iomux_softc *sc, const int phandle, u_int bank, u_int idx, u_int mux)
+{
+ u_int drv;
+
+ if (of_hasprop(phandle, "bias-disable"))
+ rk3328_iomux_set_bias(sc, bank, idx, GRF_GPIO_P_CTL_Z);
+ else if (of_hasprop(phandle, "bias-pull-up"))
+ rk3328_iomux_set_bias(sc, bank, idx, GRF_GPIO_P_CTL_PULLUP);
+ else if (of_hasprop(phandle, "bias-pull-down"))
+ rk3328_iomux_set_bias(sc, bank, idx, GRF_GPIO_P_CTL_PULLDOWN);
+
+ if (of_getprop_uint32(phandle, "drive-strength", &drv) == 0) {
+ switch (drv) {
+ case 2:
+ rk3328_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_2MA);
+ break;
+ case 4:
+ rk3328_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_4MA);
+ break;
+ case 8:
+ rk3328_iomux_set_drive_strength(sc, bank, idx, GRF_GPIO_E_CTL_8MA);
+ break;
+ case 12:
+ rk3328_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"))
+ rk3328_iomux_set_direction(sc, bank, idx, GPIO_PIN_INPUT, -1);
+ else if (of_hasprop(phandle, "output-high"))
+ rk3328_iomux_set_direction(sc, bank, idx, GPIO_PIN_OUTPUT, GPIO_PIN_HIGH);
+ else if (of_hasprop(phandle, "output-low"))
+ rk3328_iomux_set_direction(sc, bank, idx, GPIO_PIN_OUTPUT, GPIO_PIN_LOW);
+#endif
+
+ rk3328_iomux_set_mux(sc, bank, idx, mux);
+
+ return 0;
+}
+
+static int
+rk3328_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len)
+{
+ struct rk3328_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]));
+
+ LOCK(sc);
+ rk3328_iomux_config(sc, cfg, bank, idx, mux);
+ UNLOCK(sc);
+
+ pins_len -= 16;
+ pins += 4;
+ }
+
+ return 0;
+}
+
+static struct fdtbus_pinctrl_controller_func rk3328_iomux_pinctrl_funcs = {
+ .set_config = rk3328_iomux_pinctrl_set_config,
+};
+
+static int
+rk3328_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
+rk3328_iomux_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk3328_iomux_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ int child, sub;
+
+ sc->sc_dev = self;
+ sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf");
+ if (sc->sc_syscon == NULL) {
+ aprint_error(": couldn't acquire grf syscon\n");
+ return;
+ }
+ sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data;
+
+ aprint_naive("\n");
+ aprint_normal(": RK3328 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, &rk3328_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/rk3399_cru.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3399_cru.c:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3399_cru.c Sun Aug 12 16:48:05 2018
@@ -0,0 +1,636 @@
+/* $NetBSD: rk3399_cru.c,v 1.1 2018/08/12 16:48:05 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.1 2018/08/12 16:48:05 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/rk3399_cru.h>
+
+#define PLL_CON(n) (0x0000 + (n) * 4)
+#define CLKSEL_CON(n) (0x0100 + (n) * 4)
+#define CLKGATE_CON(n) (0x0300 + (n) * 4)
+#define SOFTRST_CON(n) (0x0400 + (n) * 4)
+
+static int rk3399_cru_match(device_t, cfdata_t, void *);
+static void rk3399_cru_attach(device_t, device_t, void *);
+
+static const char * const compatible[] = {
+ "rockchip,rk3399-cru",
+ NULL
+};
+
+CFATTACH_DECL_NEW(rk3399_cru, sizeof(struct rk_cru_softc),
+ rk3399_cru_match, rk3399_cru_attach, NULL, NULL);
+
+static const struct rk_cru_pll_rate pll_rates[] = {
+ RK_PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0),
+ RK_PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0),
+ RK_PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0),
+ RK_PLL_RATE(2136000000, 1, 89, 1, 1, 1, 0),
+ RK_PLL_RATE(2112000000, 1, 88, 1, 1, 1, 0),
+ RK_PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0),
+ RK_PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0),
+ RK_PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0),
+ RK_PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0),
+ RK_PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0),
+ RK_PLL_RATE(1968000000, 1, 82, 1, 1, 1, 0),
+ RK_PLL_RATE(1944000000, 1, 81, 1, 1, 1, 0),
+ RK_PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0),
+ RK_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
+ RK_PLL_RATE(1872000000, 1, 78, 1, 1, 1, 0),
+ RK_PLL_RATE(1848000000, 1, 77, 1, 1, 1, 0),
+ RK_PLL_RATE(1824000000, 1, 76, 1, 1, 1, 0),
+ RK_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
+ RK_PLL_RATE(1776000000, 1, 74, 1, 1, 1, 0),
+ RK_PLL_RATE(1752000000, 1, 73, 1, 1, 1, 0),
+ RK_PLL_RATE(1728000000, 1, 72, 1, 1, 1, 0),
+ RK_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
+ RK_PLL_RATE(1680000000, 1, 70, 1, 1, 1, 0),
+ RK_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0),
+ RK_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0),
+ RK_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK_PLL_RATE(1600000000, 3, 200, 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, 1, 125, 3, 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, 1, 100, 3, 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( 676000000, 3, 169, 2, 1, 1, 0),
+ RK_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+ RK_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0),
+ RK_PLL_RATE( 533250000, 8, 711, 4, 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( 297000000, 1, 99, 4, 2, 1, 0),
+ RK_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+ RK_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0),
+ RK_PLL_RATE( 106500000, 1, 71, 4, 4, 1, 0),
+ RK_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
+ RK_PLL_RATE( 74250000, 2, 99, 4, 4, 1, 0),
+ RK_PLL_RATE( 65000000, 1, 65, 6, 4, 1, 0),
+ RK_PLL_RATE( 54000000, 1, 54, 6, 4, 1, 0),
+ RK_PLL_RATE( 27000000, 1, 27, 6, 4, 1, 0),
+};
+
+static const struct rk_cru_pll_rate pll_norates[] = {
+};
+
+#define PLL_CON0 0x00
+#define PLL_FBDIV __BITS(11,0)
+
+#define PLL_CON1 0x04
+#define PLL_POSTDIV2 __BITS(14,12)
+#define PLL_POSTDIV1 __BITS(10,8)
+#define PLL_REFDIV __BITS(5,0)
+
+#define PLL_CON2 0x08
+#define PLL_LOCK __BIT(31)
+#define PLL_FRACDIV __BITS(23,0)
+
+#define PLL_CON3 0x0c
+#define PLL_WORK_MODE __BITS(9,8)
+#define PLL_WORK_MODE_SLOW 0
+#define PLL_WORK_MODE_NORMAL 1
+#define PLL_WORK_MODE_DEEP_SLOW 2
+#define PLL_DSMPD __BIT(3)
+
+#define PLL_WRITE_MASK 0xffff0000
+
+static u_int
+rk3399_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 uint32_t con3 = CRU_READ(sc, pll->con_base + PLL_CON3);
+
+ const u_int fbdiv = __SHIFTOUT(con0, PLL_FBDIV);
+ const u_int postdiv2 = __SHIFTOUT(con1, PLL_POSTDIV2);
+ const u_int postdiv1 = __SHIFTOUT(con1, PLL_POSTDIV1);
+ const u_int refdiv = __SHIFTOUT(con1, PLL_REFDIV);
+ const u_int fracdiv = __SHIFTOUT(con2, PLL_FRACDIV);
+ const u_int dsmpd = __SHIFTOUT(con3, PLL_DSMPD);
+
+ if (dsmpd == 1) {
+ /* integer mode */
+ foutvco = fref / refdiv * fbdiv;
+ } else {
+ /* fractional mode */
+ foutvco = fref / refdiv * fbdiv + ((fref * fracdiv) >> 24);
+ }
+ foutpostdiv = foutvco / postdiv1 / postdiv2;
+
+ return foutpostdiv;
+}
+
+static int
+rk3399_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)
+ 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;
+
+ val = __SHIFTIN(PLL_WORK_MODE_SLOW, PLL_WORK_MODE) | (PLL_WORK_MODE << 16);
+ CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
+
+ CRU_WRITE(sc, pll->con_base + PLL_CON0,
+ __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) |
+ PLL_WRITE_MASK);
+
+ CRU_WRITE(sc, pll->con_base + PLL_CON1,
+ __SHIFTIN(pll_rate->postdiv2, PLL_POSTDIV2) |
+ __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) |
+ __SHIFTIN(pll_rate->refdiv, PLL_REFDIV) |
+ PLL_WRITE_MASK);
+
+ 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);
+
+ val = __SHIFTIN(pll_rate->dsmpd, PLL_DSMPD) | (PLL_DSMPD << 16);
+ CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
+
+ /* Set PLL work mode to normal */
+ const uint32_t write_mask = pll->mode_mask << 16;
+ const uint32_t write_val = pll->mode_mask;
+ CRU_WRITE(sc, pll->mode_reg, write_mask | write_val);
+
+ for (retry = 1000; retry > 0; retry--) {
+ if (CRU_READ(sc, pll->con_base + PLL_CON2) & pll->lock_mask)
+ break;
+ delay(1);
+ }
+
+ if (retry == 0)
+ device_printf(sc->sc_dev, "WARNING: %s failed to lock\n",
+ clk->base.name);
+
+ val = __SHIFTIN(PLL_WORK_MODE_NORMAL, PLL_WORK_MODE) | (PLL_WORK_MODE << 16);
+ CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
+
+ return 0;
+}
+
+#define RK3399_PLL(_id, _name, _parents, _con_base, _mode_reg, _mode_mask, _lock_mask, _rates) \
+ { \
+ .id = (_id), \
+ .type = RK_CRU_PLL, \
+ .base.name = (_name), \
+ .base.flags = 0, \
+ .u.pll.parents = (_parents), \
+ .u.pll.nparents = __arraycount(_parents), \
+ .u.pll.con_base = (_con_base), \
+ .u.pll.mode_reg = (_mode_reg), \
+ .u.pll.mode_mask = (_mode_mask), \
+ .u.pll.lock_mask = (_lock_mask), \
+ .u.pll.rates = (_rates), \
+ .u.pll.nrates = __arraycount(_rates), \
+ .get_rate = rk3399_cru_pll_get_rate, \
+ .set_rate = rk3399_cru_pll_set_rate, \
+ .get_parent = rk_cru_pll_get_parent, \
+ }
+
+static const char * pll_parents[] = { "xin24m", "xin32k" };
+static const char * mux_pll_src_cpll_gpll_parents[] = { "cpll", "gpll" };
+static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" };
+static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" };
+static const char * mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents[] = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" };
+static const char * mux_aclk_perilp0_parents[] = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" };
+static const char * mux_hclk_perilp1_parents[] = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" };
+static const char * mux_aclk_perihp_parents[] = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" };
+static const char * mux_aclk_cci_parents[] = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" };
+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_uart3_parents[] = { "clk_uart3_div", "clk_uart3_frac", "xin24m" };
+static const char * mux_rmii_parents[] = { "clk_gmac", "clkin_gmac" };
+static const char * mux_aclk_gmac_parents[] = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" };
+
+static struct rk_cru_clk rk3399_cru_clks[] = {
+ RK3399_PLL(RK3399_PLL_APLLL, "lpll", pll_parents,
+ PLL_CON(0), /* con_base */
+ PLL_CON(3), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+ RK3399_PLL(RK3399_PLL_APLLB, "bpll", pll_parents,
+ PLL_CON(8), /* con_base */
+ PLL_CON(11), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+ RK3399_PLL(RK3399_PLL_DPLL, "dpll", pll_parents,
+ PLL_CON(16), /* con_base */
+ PLL_CON(19), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_norates),
+ RK3399_PLL(RK3399_PLL_CPLL, "cpll", pll_parents,
+ PLL_CON(24), /* con_base */
+ PLL_CON(27), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+ RK3399_PLL(RK3399_PLL_GPLL, "gpll", pll_parents,
+ PLL_CON(32), /* con_base */
+ PLL_CON(35), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+ RK3399_PLL(RK3399_PLL_NPLL, "npll", pll_parents,
+ PLL_CON(40), /* con_base */
+ PLL_CON(43), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+ RK3399_PLL(RK3399_PLL_VPLL, "vpll", pll_parents,
+ PLL_CON(43), /* con_base */
+ PLL_CON(51), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+
+ /*
+ * perilp0
+ */
+ RK_GATE(0, "gpll_aclk_perilp0_src", "gpll", CLKGATE_CON(7), 0),
+ RK_GATE(0, "cpll_aclk_perilp0_src", "cpll", CLKGATE_CON(7), 1),
+ RK_COMPOSITE(RK3399_ACLK_PERILP0, "aclk_perilp0", mux_aclk_perilp0_parents,
+ CLKSEL_CON(23), /* muxdiv_reg */
+ __BIT(7), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ CLKGATE_CON(7), /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(RK3399_HCLK_PERILP0, "hclk_perilp0", "aclk_perilp0",
+ CLKSEL_CON(23), /* div_reg */
+ __BITS(10,8), /* div_mask */
+ CLKGATE_CON(7), /* gate_reg */
+ __BIT(3), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(RK3399_PCLK_PERILP0, "pclk_perilp0", "aclk_perilp0",
+ CLKSEL_CON(23), /* div_reg */
+ __BITS(14,12), /* div_mask */
+ CLKGATE_CON(7), /* gate_reg */
+ __BIT(4), /* gate_mask */
+ 0),
+
+ /*
+ * perilp1
+ */
+ RK_GATE(0, "gpll_hclk_perilp1_src", "gpll", CLKGATE_CON(8), 0),
+ RK_GATE(0, "cpll_hclk_perilp1_src", "cpll", CLKGATE_CON(8), 1),
+ RK_COMPOSITE_NOGATE(RK3399_HCLK_PERILP1, "hclk_perilp1", mux_hclk_perilp1_parents,
+ CLKSEL_CON(25), /* muxdiv_reg */
+ __BITS(10,8), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(RK3399_PCLK_PERILP1, "pclk_perilp1", "hclk_perilp1",
+ CLKSEL_CON(25), /* div_reg */
+ __BITS(10,8), /* div_mask */
+ CLKGATE_CON(8), /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+
+ /*
+ * perihp
+ */
+ RK_GATE(0, "gpll_aclk_perihp_src", "gpll", CLKGATE_CON(5), 0),
+ RK_GATE(0, "cpll_aclk_perihp_src", "cpll", CLKGATE_CON(5), 1),
+ RK_COMPOSITE(RK3399_ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_parents,
+ CLKSEL_CON(14), /* muxdiv_reg */
+ __BIT(7), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ CLKGATE_CON(5), /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(RK3399_HCLK_PERIHP, "hclk_perihp", "aclk_perihp",
+ CLKSEL_CON(14), /* div_reg */
+ __BITS(10,8), /* div_mask */
+ CLKGATE_CON(5), /* gate_reg */
+ __BIT(3), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(RK3399_PCLK_PERIHP, "pclk_perihp", "aclk_perihp",
+ CLKSEL_CON(14), /* div_reg */
+ __BITS(14,12), /* div_mask */
+ CLKGATE_CON(5), /* gate_reg */
+ __BIT(4), /* gate_mask */
+ 0),
+
+ /*
+ * CCI
+ */
+ RK_GATE(0, "cpll_aclk_cci_src", "cpll", CLKGATE_CON(2), 0),
+ RK_GATE(0, "gpll_aclk_cci_src", "gpll", CLKGATE_CON(2), 1),
+ RK_GATE(0, "npll_aclk_cci_src", "npll", CLKGATE_CON(2), 2),
+ RK_GATE(0, "vpll_aclk_cci_src", "vpll", CLKGATE_CON(2), 3),
+ RK_COMPOSITE(0, "aclk_cci_pre", mux_aclk_cci_parents,
+ CLKSEL_CON(5), /* muxdiv_reg */
+ __BITS(7,6), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ CLKGATE_CON(2), /* gate_reg */
+ __BIT(4), /* gate_mask */
+ 0),
+ RK_GATE(RK3399_ACLK_CCI, "aclk_cci", "aclk_cci_pre", CLKGATE_CON(15), 2),
+
+ /*
+ * GIC
+ */
+ RK_COMPOSITE(RK3399_ACLK_GIC_PRE, "aclk_gic_pre", mux_pll_src_cpll_gpll_parents,
+ CLKSEL_CON(56), /* muxdiv_reg */
+ __BIT(15), /* mux_mask */
+ __BITS(12,8), /* div_mask */
+ CLKGATE_CON(12), /* gate_reg */
+ __BIT(12), /* gate_mask */
+ 0),
+
+ /*
+ * DDR
+ */
+ RK_COMPOSITE(RK3399_PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_parents,
+ CLKSEL_CON(6), /* muxdiv_reg */
+ __BIT(15), /* mux_mask */
+ __BITS(12,8), /* div_mask */
+ CLKGATE_CON(3), /* gate_reg */
+ __BIT(4), /* gate_mask */
+ 0),
+
+ /*
+ * alive
+ */
+ RK_DIV(RK3399_PCLK_ALIVE, "pclk_alive", "gpll", CLKSEL_CON(57), __BITS(4,0), 0),
+
+ /*
+ * GPIO
+ */
+ RK_GATE(RK3399_PCLK_GPIO2, "pclk_gpio2", "pclk_alive", CLKGATE_CON(31), 3),
+ RK_GATE(RK3399_PCLK_GPIO3, "pclk_gpio3", "pclk_alive", CLKGATE_CON(31), 4),
+ RK_GATE(RK3399_PCLK_GPIO4, "pclk_gpio4", "pclk_alive", CLKGATE_CON(31), 5),
+
+ /*
+ * UART
+ */
+ RK_MUX(0, "clk_uart0_src", mux_pll_src_cpll_gpll_upll_parents, CLKSEL_CON(33), __BITS(13,12)),
+ RK_MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_parents, CLKSEL_CON(33), __BIT(15)),
+ RK_COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src",
+ CLKSEL_CON(33), /* div_reg */
+ __BITS(6,0), /* div_mask */
+ CLKGATE_CON(9), /* gate_reg */
+ __BIT(0), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src",
+ CLKSEL_CON(34), /* div_reg */
+ __BITS(6,0), /* div_mask */
+ CLKGATE_CON(9), /* gate_reg */
+ __BIT(2), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src",
+ CLKSEL_CON(35), /* div_reg */
+ __BITS(6,0), /* div_mask */
+ CLKGATE_CON(9), /* gate_reg */
+ __BIT(4), /* gate_mask */
+ 0),
+ RK_COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src",
+ CLKSEL_CON(36), /* div_reg */
+ __BITS(6,0), /* div_mask */
+ CLKGATE_CON(9), /* gate_reg */
+ __BIT(6), /* gate_mask */
+ 0),
+ RK_MUX(RK3399_SCLK_UART0, "clk_uart0", mux_uart0_parents, CLKSEL_CON(33), __BITS(9,8)),
+ RK_MUX(RK3399_SCLK_UART1, "clk_uart1", mux_uart1_parents, CLKSEL_CON(34), __BITS(9,8)),
+ RK_MUX(RK3399_SCLK_UART2, "clk_uart2", mux_uart2_parents, CLKSEL_CON(35), __BITS(9,8)),
+ RK_MUX(RK3399_SCLK_UART3, "clk_uart3", mux_uart3_parents, CLKSEL_CON(36), __BITS(9,8)),
+ RK_GATE(RK3399_PCLK_UART0, "pclk_uart0", "pclk_perilp1", CLKGATE_CON(22), 0),
+ RK_GATE(RK3399_PCLK_UART1, "pclk_uart1", "pclk_perilp1", CLKGATE_CON(22), 1),
+ RK_GATE(RK3399_PCLK_UART2, "pclk_uart2", "pclk_perilp1", CLKGATE_CON(22), 2),
+ RK_GATE(RK3399_PCLK_UART3, "pclk_uart3", "pclk_perilp1", CLKGATE_CON(22), 3),
+
+ /*
+ * SDMMC/SDIO
+ */
+ RK_COMPOSITE(RK3399_HCLK_SD, "hclk_sd", mux_pll_src_cpll_gpll_parents,
+ CLKSEL_CON(13), /* muxdiv_reg */
+ __BIT(15), /* mux_mask */
+ __BITS(12,8), /* div_mask */
+ CLKGATE_CON(12), /* gate_reg */
+ __BIT(13), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3399_SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents,
+ CLKSEL_CON(15), /* muxdiv_reg */
+ __BITS(10,8), /* mux_mask */
+ __BITS(6,0), /* div_mask */
+ CLKGATE_CON(6), /* gate_reg */
+ __BIT(0), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3399_SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents,
+ CLKSEL_CON(16), /* muxdiv_reg */
+ __BITS(10,8), /* mux_mask */
+ __BITS(6,0), /* div_mask */
+ CLKGATE_CON(6), /* gate_reg */
+ __BIT(1), /* gate_mask */
+ 0),
+ RK_GATE(RK3399_HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", CLKGATE_CON(33), 8),
+ RK_GATE(RK3399_HCLK_SDIO, "hclk_sdio", "pclk_perilp1", CLKGATE_CON(34), 4),
+
+ /*
+ * GMAC
+ */
+ RK_COMPOSITE(RK3399_SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_parents,
+ CLKSEL_CON(20), /* muxdiv_reg */
+ __BITS(15,14), /* mux_mask */
+ __BITS(12,8), /* div_mask */
+ CLKGATE_CON(5), /* gate_reg */
+ __BIT(5), /* gate_mask */
+ 0),
+ RK_MUX(RK3399_SCLK_RMII_SRC, "clk_rmii_src", mux_rmii_parents, CLKSEL_CON(19), __BIT(4)),
+ RK_GATE(RK3399_SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", CLKGATE_CON(5), 6),
+ RK_GATE(RK3399_SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", CLKGATE_CON(5), 7),
+ RK_GATE(RK3399_SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", CLKGATE_CON(5), 8),
+ RK_GATE(RK3399_SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", CLKGATE_CON(5), 9),
+ RK_GATE(0, "gpll_aclk_gmac_src", "gpll", CLKGATE_CON(6), 8),
+ RK_GATE(0, "cpll_aclk_gmac_src", "cpll", CLKGATE_CON(6), 9),
+ RK_COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_parents,
+ CLKSEL_CON(20), /* muxdiv_reg */
+ __BIT(17), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ CLKGATE_CON(6), /* gate_reg */
+ __BIT(10), /* gate_mask */
+ 0),
+ RK_GATE(RK3399_ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", CLKGATE_CON(32), 0),
+ RK_COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre",
+ CLKSEL_CON(19), /* div_reg */
+ __BITS(10,8), /* div_mask */
+ CLKGATE_CON(6), /* gate_reg */
+ __BIT(11), /* gate_mask */
+ 0),
+ RK_GATE(RK3399_PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", CLKGATE_CON(32), 2),
+
+ /*
+ * USB2
+ */
+ RK_GATE(RK3399_HCLK_HOST0, "hclk_host0", "hclk_perihp", CLKGATE_CON(20), 5),
+ RK_GATE(RK3399_HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", CLKGATE_CON(20), 6),
+ RK_GATE(RK3399_HCLK_HOST1, "hclk_host1", "hclk_perihp", CLKGATE_CON(20), 7),
+ RK_GATE(RK3399_HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", CLKGATE_CON(20), 8),
+ RK_GATE(RK3399_SCLK_USB2PHY0_REF, "clk_usb2phy0_ref", "xin24m", CLKGATE_CON(6), 5),
+ RK_GATE(RK3399_SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLKGATE_CON(6), 6),
+
+ /*
+ * USB3
+ */
+ RK_GATE(RK3399_SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", CLKGATE_CON(12), 1),
+ RK_GATE(RK3399_SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", CLKGATE_CON(12), 2),
+ RK_COMPOSITE(RK3399_SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", pll_parents,
+ CLKSEL_CON(40), /* muxdiv_reg */
+ __BIT(15), /* mux_mask */
+ __BITS(9,0), /* div_mask */
+ CLKGATE_CON(12), /* gate_reg */
+ __BIT(3), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3399_SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", pll_parents,
+ CLKSEL_CON(41), /* muxdiv_reg */
+ __BIT(15), /* mux_mask */
+ __BITS(9,0), /* div_mask */
+ CLKGATE_CON(12), /* gate_reg */
+ __BIT(4), /* gate_mask */
+ 0),
+ RK_COMPOSITE(RK3399_ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_parents,
+ CLKSEL_CON(39), /* muxdiv_reg */
+ __BITS(7,6), /* mux_mask */
+ __BITS(4,0), /* div_mask */
+ CLKGATE_CON(12), /* gate_reg */
+ __BIT(0), /* gate_mask */
+ 0),
+ RK_GATE(RK3399_ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", CLKGATE_CON(30), 1),
+ RK_GATE(RK3399_ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", CLKGATE_CON(30), 2),
+ RK_GATE(RK3399_ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", CLKGATE_CON(30), 3),
+ RK_GATE(RK3399_ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", CLKGATE_CON(30), 4),
+};
+
+static int
+rk3399_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
+rk3399_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 = rk3399_cru_clks;
+ sc->sc_nclks = __arraycount(rk3399_cru_clks);
+
+ sc->sc_softrst_base = SOFTRST_CON(0);
+
+ if (rk_cru_attach(sc) != 0)
+ return;
+
+ aprint_naive("\n");
+ aprint_normal(": RK3399 CRU\n");
+
+ rk_cru_print(sc);
+}
Index: src/sys/arch/arm/rockchip/rk3399_cru.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3399_cru.h:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3399_cru.h Sun Aug 12 16:48:05 2018
@@ -0,0 +1,353 @@
+/* $NetBSD: rk3399_cru.h,v 1.1 2018/08/12 16:48:05 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RK3399_CRU_H
+#define _RK3399_CRU_H
+
+/*
+ * Clocks
+ */
+
+#define RK3399_PLL_APLLL 1
+#define RK3399_PLL_APLLB 2
+#define RK3399_PLL_DPLL 3
+#define RK3399_PLL_CPLL 4
+#define RK3399_PLL_GPLL 5
+#define RK3399_PLL_NPLL 6
+#define RK3399_PLL_VPLL 7
+#define RK3399_ARMCLKL 8
+#define RK3399_ARMCLKB 9
+#define RK3399_SCLK_I2C1 65
+#define RK3399_SCLK_I2C2 66
+#define RK3399_SCLK_I2C3 67
+#define RK3399_SCLK_I2C5 68
+#define RK3399_SCLK_I2C6 69
+#define RK3399_SCLK_I2C7 70
+#define RK3399_SCLK_SPI0 71
+#define RK3399_SCLK_SPI1 72
+#define RK3399_SCLK_SPI2 73
+#define RK3399_SCLK_SPI4 74
+#define RK3399_SCLK_SPI5 75
+#define RK3399_SCLK_SDMMC 76
+#define RK3399_SCLK_SDIO 77
+#define RK3399_SCLK_EMMC 78
+#define RK3399_SCLK_TSADC 79
+#define RK3399_SCLK_SARADC 80
+#define RK3399_SCLK_UART0 81
+#define RK3399_SCLK_UART1 82
+#define RK3399_SCLK_UART2 83
+#define RK3399_SCLK_UART3 84
+#define RK3399_SCLK_SPDIF_8CH 85
+#define RK3399_SCLK_I2S0_8CH 86
+#define RK3399_SCLK_I2S1_8CH 87
+#define RK3399_SCLK_I2S2_8CH 88
+#define RK3399_SCLK_I2S_8CH_OUT 89
+#define RK3399_SCLK_TIMER00 90
+#define RK3399_SCLK_TIMER01 91
+#define RK3399_SCLK_TIMER02 92
+#define RK3399_SCLK_TIMER03 93
+#define RK3399_SCLK_TIMER04 94
+#define RK3399_SCLK_TIMER05 95
+#define RK3399_SCLK_TIMER06 96
+#define RK3399_SCLK_TIMER07 97
+#define RK3399_SCLK_TIMER08 98
+#define RK3399_SCLK_TIMER09 99
+#define RK3399_SCLK_TIMER10 100
+#define RK3399_SCLK_TIMER11 101
+#define RK3399_SCLK_MACREF 102
+#define RK3399_SCLK_MAC_RX 103
+#define RK3399_SCLK_MAC_TX 104
+#define RK3399_SCLK_MAC 105
+#define RK3399_SCLK_MACREF_OUT 106
+#define RK3399_SCLK_VOP0_PWM 107
+#define RK3399_SCLK_VOP1_PWM 108
+#define RK3399_SCLK_RGA_CORE 109
+#define RK3399_SCLK_ISP0 110
+#define RK3399_SCLK_ISP1 111
+#define RK3399_SCLK_HDMI_CEC 112
+#define RK3399_SCLK_HDMI_SFR 113
+#define RK3399_SCLK_DP_CORE 114
+#define RK3399_SCLK_PVTM_CORE_L 115
+#define RK3399_SCLK_PVTM_CORE_B 116
+#define RK3399_SCLK_PVTM_GPU 117
+#define RK3399_SCLK_PVTM_DDR 118
+#define RK3399_SCLK_MIPIDPHY_REF 119
+#define RK3399_SCLK_MIPIDPHY_CFG 120
+#define RK3399_SCLK_HSICPHY 121
+#define RK3399_SCLK_USBPHY480M 122
+#define RK3399_SCLK_USB2PHY0_REF 123
+#define RK3399_SCLK_USB2PHY1_REF 124
+#define RK3399_SCLK_UPHY0_TCPDPHY_REF 125
+#define RK3399_SCLK_UPHY0_TCPDCORE 126
+#define RK3399_SCLK_UPHY1_TCPDPHY_REF 127
+#define RK3399_SCLK_UPHY1_TCPDCORE 128
+#define RK3399_SCLK_USB3OTG0_REF 129
+#define RK3399_SCLK_USB3OTG1_REF 130
+#define RK3399_SCLK_USB3OTG0_SUSPEND 131
+#define RK3399_SCLK_USB3OTG1_SUSPEND 132
+#define RK3399_SCLK_CRYPTO0 133
+#define RK3399_SCLK_CRYPTO1 134
+#define RK3399_SCLK_CCI_TRACE 135
+#define RK3399_SCLK_CS 136
+#define RK3399_SCLK_CIF_OUT 137
+#define RK3399_SCLK_PCIEPHY_REF 138
+#define RK3399_SCLK_PCIE_CORE 139
+#define RK3399_SCLK_M0_PERILP 140
+#define RK3399_SCLK_M0_PERILP_DEC 141
+#define RK3399_SCLK_CM0S 142
+#define RK3399_SCLK_DBG_NOC 143
+#define RK3399_SCLK_DBG_PD_CORE_B 144
+#define RK3399_SCLK_DBG_PD_CORE_L 145
+#define RK3399_SCLK_DFIMON0_TIMER 146
+#define RK3399_SCLK_DFIMON1_TIMER 147
+#define RK3399_SCLK_INTMEM0 148
+#define RK3399_SCLK_INTMEM1 149
+#define RK3399_SCLK_INTMEM2 150
+#define RK3399_SCLK_INTMEM3 151
+#define RK3399_SCLK_INTMEM4 152
+#define RK3399_SCLK_INTMEM5 153
+#define RK3399_SCLK_SDMMC_DRV 154
+#define RK3399_SCLK_SDMMC_SAMPLE 155
+#define RK3399_SCLK_SDIO_DRV 156
+#define RK3399_SCLK_SDIO_SAMPLE 157
+#define RK3399_SCLK_VDU_CORE 158
+#define RK3399_SCLK_VDU_CA 159
+#define RK3399_SCLK_PCIE_PM 160
+#define RK3399_SCLK_SPDIF_REC_DPTX 161
+#define RK3399_SCLK_DPHY_PLL 162
+#define RK3399_SCLK_DPHY_TX0_CFG 163
+#define RK3399_SCLK_DPHY_TX1RX1_CFG 164
+#define RK3399_SCLK_DPHY_RX0_CFG 165
+#define RK3399_SCLK_RMII_SRC 166
+#define RK3399_SCLK_PCIEPHY_REF100M 167
+#define RK3399_SCLK_DDRC 168
+#define RK3399_SCLK_TESTCLKOUT1 169
+#define RK3399_SCLK_TESTCLKOUT2 170
+#define RK3399_DCLK_VOP0 180
+#define RK3399_DCLK_VOP1 181
+#define RK3399_DCLK_VOP0_DIV 182
+#define RK3399_DCLK_VOP1_DIV 183
+#define RK3399_DCLK_M0_PERILP 184
+#define RK3399_DCLK_VOP0_FRAC 185
+#define RK3399_DCLK_VOP1_FRAC 186
+#define RK3399_FCLK_CM0S 190
+#define RK3399_ACLK_PERIHP 192
+#define RK3399_ACLK_PERIHP_NOC 193
+#define RK3399_ACLK_PERILP0 194
+#define RK3399_ACLK_PERILP0_NOC 195
+#define RK3399_ACLK_PERF_PCIE 196
+#define RK3399_ACLK_PCIE 197
+#define RK3399_ACLK_INTMEM 198
+#define RK3399_ACLK_TZMA 199
+#define RK3399_ACLK_DCF 200
+#define RK3399_ACLK_CCI 201
+#define RK3399_ACLK_CCI_NOC0 202
+#define RK3399_ACLK_CCI_NOC1 203
+#define RK3399_ACLK_CCI_GRF 204
+#define RK3399_ACLK_CENTER 205
+#define RK3399_ACLK_CENTER_MAIN_NOC 206
+#define RK3399_ACLK_CENTER_PERI_NOC 207
+#define RK3399_ACLK_GPU 208
+#define RK3399_ACLK_PERF_GPU 209
+#define RK3399_ACLK_GPU_GRF 210
+#define RK3399_ACLK_DMAC0_PERILP 211
+#define RK3399_ACLK_DMAC1_PERILP 212
+#define RK3399_ACLK_GMAC 213
+#define RK3399_ACLK_GMAC_NOC 214
+#define RK3399_ACLK_PERF_GMAC 215
+#define RK3399_ACLK_VOP0_NOC 216
+#define RK3399_ACLK_VOP0 217
+#define RK3399_ACLK_VOP1_NOC 218
+#define RK3399_ACLK_VOP1 219
+#define RK3399_ACLK_RGA 220
+#define RK3399_ACLK_RGA_NOC 221
+#define RK3399_ACLK_HDCP 222
+#define RK3399_ACLK_HDCP_NOC 223
+#define RK3399_ACLK_HDCP22 224
+#define RK3399_ACLK_IEP 225
+#define RK3399_ACLK_IEP_NOC 226
+#define RK3399_ACLK_VIO 227
+#define RK3399_ACLK_VIO_NOC 228
+#define RK3399_ACLK_ISP0 229
+#define RK3399_ACLK_ISP1 230
+#define RK3399_ACLK_ISP0_NOC 231
+#define RK3399_ACLK_ISP1_NOC 232
+#define RK3399_ACLK_ISP0_WRAPPER 233
+#define RK3399_ACLK_ISP1_WRAPPER 234
+#define RK3399_ACLK_VCODEC 235
+#define RK3399_ACLK_VCODEC_NOC 236
+#define RK3399_ACLK_VDU 237
+#define RK3399_ACLK_VDU_NOC 238
+#define RK3399_ACLK_PERI 239
+#define RK3399_ACLK_EMMC 240
+#define RK3399_ACLK_EMMC_CORE 241
+#define RK3399_ACLK_EMMC_NOC 242
+#define RK3399_ACLK_EMMC_GRF 243
+#define RK3399_ACLK_USB3 244
+#define RK3399_ACLK_USB3_NOC 245
+#define RK3399_ACLK_USB3OTG0 246
+#define RK3399_ACLK_USB3OTG1 247
+#define RK3399_ACLK_USB3_RKSOC_AXI_PERF 248
+#define RK3399_ACLK_USB3_GRF 249
+#define RK3399_ACLK_GIC 250
+#define RK3399_ACLK_GIC_NOC 251
+#define RK3399_ACLK_GIC_ADB400_CORE_L_2_GIC 252
+#define RK3399_ACLK_GIC_ADB400_CORE_B_2_GIC 253
+#define RK3399_ACLK_GIC_ADB400_GIC_2_CORE_L 254
+#define RK3399_ACLK_GIC_ADB400_GIC_2_CORE_B 255
+#define RK3399_ACLK_CORE_ADB400_CORE_L_2_CCI500 256
+#define RK3399_ACLK_CORE_ADB400_CORE_B_2_CCI500 257
+#define RK3399_ACLK_ADB400M_PD_CORE_L 258
+#define RK3399_ACLK_ADB400M_PD_CORE_B 259
+#define RK3399_ACLK_PERF_CORE_L 260
+#define RK3399_ACLK_PERF_CORE_B 261
+#define RK3399_ACLK_GIC_PRE 262
+#define RK3399_ACLK_VOP0_PRE 263
+#define RK3399_ACLK_VOP1_PRE 264
+#define RK3399_PCLK_PERIHP 320
+#define RK3399_PCLK_PERIHP_NOC 321
+#define RK3399_PCLK_PERILP0 322
+#define RK3399_PCLK_PERILP1 323
+#define RK3399_PCLK_PERILP1_NOC 324
+#define RK3399_PCLK_PERILP_SGRF 325
+#define RK3399_PCLK_PERIHP_GRF 326
+#define RK3399_PCLK_PCIE 327
+#define RK3399_PCLK_SGRF 328
+#define RK3399_PCLK_INTR_ARB 329
+#define RK3399_PCLK_CENTER_MAIN_NOC 330
+#define RK3399_PCLK_CIC 331
+#define RK3399_PCLK_COREDBG_B 332
+#define RK3399_PCLK_COREDBG_L 333
+#define RK3399_PCLK_DBG_CXCS_PD_CORE_B 334
+#define RK3399_PCLK_DCF 335
+#define RK3399_PCLK_GPIO2 336
+#define RK3399_PCLK_GPIO3 337
+#define RK3399_PCLK_GPIO4 338
+#define RK3399_PCLK_GRF 339
+#define RK3399_PCLK_HSICPHY 340
+#define RK3399_PCLK_I2C1 341
+#define RK3399_PCLK_I2C2 342
+#define RK3399_PCLK_I2C3 343
+#define RK3399_PCLK_I2C5 344
+#define RK3399_PCLK_I2C6 345
+#define RK3399_PCLK_I2C7 346
+#define RK3399_PCLK_SPI0 347
+#define RK3399_PCLK_SPI1 348
+#define RK3399_PCLK_SPI2 349
+#define RK3399_PCLK_SPI4 350
+#define RK3399_PCLK_SPI5 351
+#define RK3399_PCLK_UART0 352
+#define RK3399_PCLK_UART1 353
+#define RK3399_PCLK_UART2 354
+#define RK3399_PCLK_UART3 355
+#define RK3399_PCLK_TSADC 356
+#define RK3399_PCLK_SARADC 357
+#define RK3399_PCLK_GMAC 358
+#define RK3399_PCLK_GMAC_NOC 359
+#define RK3399_PCLK_TIMER0 360
+#define RK3399_PCLK_TIMER1 361
+#define RK3399_PCLK_EDP 362
+#define RK3399_PCLK_EDP_NOC 363
+#define RK3399_PCLK_EDP_CTRL 364
+#define RK3399_PCLK_VIO 365
+#define RK3399_PCLK_VIO_NOC 366
+#define RK3399_PCLK_VIO_GRF 367
+#define RK3399_PCLK_MIPI_DSI0 368
+#define RK3399_PCLK_MIPI_DSI1 369
+#define RK3399_PCLK_HDCP 370
+#define RK3399_PCLK_HDCP_NOC 371
+#define RK3399_PCLK_HDMI_CTRL 372
+#define RK3399_PCLK_DP_CTRL 373
+#define RK3399_PCLK_HDCP22 374
+#define RK3399_PCLK_GASKET 375
+#define RK3399_PCLK_DDR 376
+#define RK3399_PCLK_DDR_MON 377
+#define RK3399_PCLK_DDR_SGRF 378
+#define RK3399_PCLK_ISP1_WRAPPER 379
+#define RK3399_PCLK_WDT 380
+#define RK3399_PCLK_EFUSE1024NS 381
+#define RK3399_PCLK_EFUSE1024S 382
+#define RK3399_PCLK_PMU_INTR_ARB 383
+#define RK3399_PCLK_MAILBOX0 384
+#define RK3399_PCLK_USBPHY_MUX_G 385
+#define RK3399_PCLK_UPHY0_TCPHY_G 386
+#define RK3399_PCLK_UPHY0_TCPD_G 387
+#define RK3399_PCLK_UPHY1_TCPHY_G 388
+#define RK3399_PCLK_UPHY1_TCPD_G 389
+#define RK3399_PCLK_ALIVE 390
+#define RK3399_HCLK_PERIHP 448
+#define RK3399_HCLK_PERILP0 449
+#define RK3399_HCLK_PERILP1 450
+#define RK3399_HCLK_PERILP0_NOC 451
+#define RK3399_HCLK_PERILP1_NOC 452
+#define RK3399_HCLK_M0_PERILP 453
+#define RK3399_HCLK_M0_PERILP_NOC 454
+#define RK3399_HCLK_AHB1TOM 455
+#define RK3399_HCLK_HOST0 456
+#define RK3399_HCLK_HOST0_ARB 457
+#define RK3399_HCLK_HOST1 458
+#define RK3399_HCLK_HOST1_ARB 459
+#define RK3399_HCLK_HSIC 460
+#define RK3399_HCLK_SD 461
+#define RK3399_HCLK_SDMMC 462
+#define RK3399_HCLK_SDMMC_NOC 463
+#define RK3399_HCLK_M_CRYPTO0 464
+#define RK3399_HCLK_M_CRYPTO1 465
+#define RK3399_HCLK_S_CRYPTO0 466
+#define RK3399_HCLK_S_CRYPTO1 467
+#define RK3399_HCLK_I2S0_8CH 468
+#define RK3399_HCLK_I2S1_8CH 469
+#define RK3399_HCLK_I2S2_8CH 470
+#define RK3399_HCLK_SPDIF 471
+#define RK3399_HCLK_VOP0_NOC 472
+#define RK3399_HCLK_VOP0 473
+#define RK3399_HCLK_VOP1_NOC 474
+#define RK3399_HCLK_VOP1 475
+#define RK3399_HCLK_ROM 476
+#define RK3399_HCLK_IEP 477
+#define RK3399_HCLK_IEP_NOC 478
+#define RK3399_HCLK_ISP0 479
+#define RK3399_HCLK_ISP1 480
+#define RK3399_HCLK_ISP0_NOC 481
+#define RK3399_HCLK_ISP1_NOC 482
+#define RK3399_HCLK_ISP0_WRAPPER 483
+#define RK3399_HCLK_ISP1_WRAPPER 484
+#define RK3399_HCLK_RGA 485
+#define RK3399_HCLK_RGA_NOC 486
+#define RK3399_HCLK_HDCP 487
+#define RK3399_HCLK_HDCP_NOC 488
+#define RK3399_HCLK_HDCP22 489
+#define RK3399_HCLK_VCODEC 490
+#define RK3399_HCLK_VCODEC_NOC 491
+#define RK3399_HCLK_VDU 492
+#define RK3399_HCLK_VDU_NOC 493
+#define RK3399_HCLK_SDIO 494
+#define RK3399_HCLK_SDIO_NOC 495
+#define RK3399_HCLK_SDIOAUDIO_NOC 496
+
+#endif /* !_RK3399_CRU_H */
Index: src/sys/arch/arm/rockchip/rk3399_iomux.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3399_iomux.c:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3399_iomux.c Sun Aug 12 16:48:05 2018
@@ -0,0 +1,464 @@
+/* $NetBSD: rk3399_iomux.c,v 1.1 2018/08/12 16:48:05 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+//#define RK3399_IOMUX_DEBUG
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rk3399_iomux.c,v 1.1 2018/08/12 16:48:05 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/lwp.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/syscon.h>
+
+/* PU/PD control */
+#define GRF_GPIO_P_CTL(_idx) (0x3 << (((_idx) & 7) * 2))
+#define GRF_GPIO_P_WRITE_EN(_idx) (0x3 << (((_idx) & 7) * 2 + 16))
+/* Different bias value mapping for GRF and PMU registers */
+#define GRF_GPIO_P_CTL_Z 0
+#define GRF_GPIO_P_CTL_PULLDOWN 1
+#define GRF_GPIO_P_CTL_Z_ALT 2
+#define GRF_GPIO_P_CTL_PULLUP 3
+#define PMU_GPIO_P_CTL_Z 0
+#define PMU_GPIO_P_CTL_PULLUP 1
+#define PMU_GPIO_P_CTL_PULLDOWN 2
+#define PMU_GPIO_P_CTL_RESERVED 3
+
+/* Drive strength control */
+/* Different drive strength value mapping for GRF and PMU registers */
+#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 PMU_GPIO_E_CTL_5MA 0
+#define PMU_GPIO_E_CTL_10MA 1
+#define PMU_GPIO_E_CTL_15MA 2
+#define PMU_GPIO_E_CTL_20MA 3
+
+enum rk3399_drv_type {
+ RK3399_DRV_TYPE_IO_DEFAULT,
+ RK3399_DRV_TYPE_IO_1V8_3V0,
+ RK3399_DRV_TYPE_IO_1V8,
+ RK3399_DRV_TYPE_IO_1V8_3V0_AUTO,
+ RK3399_DRV_TYPE_IO_3V3,
+};
+
+static int rk3399_drv_strength[5][9] = {
+ [RK3399_DRV_TYPE_IO_DEFAULT] = { 2, 4, 8, 12, -1 },
+ [RK3399_DRV_TYPE_IO_1V8_3V0] = { 3, 6, 9, 12, -1 },
+ [RK3399_DRV_TYPE_IO_1V8] = { 5, 10, 15, 20, -1 },
+ [RK3399_DRV_TYPE_IO_1V8_3V0_AUTO] = { 4, 6, 8, 10, 12, 14, 16, 18, -1 },
+ [RK3399_DRV_TYPE_IO_3V3] = { 4, 7, 10, 13, 16, 19, 22, 26, -1 },
+};
+
+struct rk3399_iomux {
+ enum rk3399_drv_type drv_type;
+};
+
+struct rk3399_iomux_bank {
+ struct rk3399_iomux iomux[5];
+ u_int regs;
+#define RK_IOMUX_REGS_GRF 0
+#define RK_IOMUX_REGS_PMU 1
+};
+
+static const struct rk3399_iomux_bank rk3399_iomux_banks[] = {
+ [0] = {
+ .regs = RK_IOMUX_REGS_PMU,
+ .iomux = {
+ [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8 },
+ [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8 },
+ [2] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT },
+ [3] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT },
+ },
+ },
+ [1] = {
+ .regs = RK_IOMUX_REGS_PMU,
+ .iomux = {
+ [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ }
+ },
+ [2] = {
+ .regs = RK_IOMUX_REGS_GRF,
+ .iomux = {
+ [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8 },
+ [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8 },
+ },
+ },
+ [3] = {
+ .regs = RK_IOMUX_REGS_GRF,
+ .iomux = {
+ [0] = { .drv_type = RK3399_DRV_TYPE_IO_3V3 },
+ [1] = { .drv_type = RK3399_DRV_TYPE_IO_3V3 },
+ [2] = { .drv_type = RK3399_DRV_TYPE_IO_3V3 },
+ [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ },
+ },
+ [4] = {
+ .regs = RK_IOMUX_REGS_GRF,
+ .iomux = {
+ [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0_AUTO },
+ [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0 },
+ },
+ },
+};
+
+#define RK3399_IOMUX_BANK_IS_PMU(_bank) (rk3399_iomux_banks[(_bank)].regs == RK_IOMUX_REGS_PMU)
+
+struct rk3399_iomux_conf {
+ const struct rk3399_iomux_bank *banks;
+ u_int nbanks;
+};
+
+static const struct rk3399_iomux_conf rk3399_iomux_conf = {
+ .banks = rk3399_iomux_banks,
+ .nbanks = __arraycount(rk3399_iomux_banks),
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "rockchip,rk3399-pinctrl", (uintptr_t)&rk3399_iomux_conf },
+ { NULL }
+};
+
+struct rk3399_iomux_softc {
+ device_t sc_dev;
+ struct syscon *sc_syscon[2];
+
+ const struct rk3399_iomux_conf *sc_conf;
+};
+
+#define LOCK(syscon) \
+ syscon_lock(syscon)
+#define UNLOCK(syscon) \
+ syscon_unlock(syscon)
+#define RD4(syscon, reg) \
+ syscon_read_4(syscon, (reg))
+#define WR4(syscon, reg, val) \
+ syscon_write_4(syscon, (reg), (val))
+
+static int rk3399_iomux_match(device_t, cfdata_t, void *);
+static void rk3399_iomux_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(rk3399_iomux, sizeof(struct rk3399_iomux_softc),
+ rk3399_iomux_match, rk3399_iomux_attach, NULL, NULL);
+
+static void
+rk3399_iomux_set_bias(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, int flags)
+{
+ const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
+ bus_size_t reg;
+ u_int bias;
+
+ KASSERT(bank < sc->sc_conf->nbanks);
+
+ struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
+ if (RK3399_IOMUX_BANK_IS_PMU(bank)) {
+ reg = 0x00040 + (0x10 * bank);
+ } else {
+ reg = 0x0e040 + (0x10 * (bank - 2));
+ }
+ reg += 0x4 * (idx / 8);
+
+ if (flags == GPIO_PIN_PULLUP) {
+ bias = RK3399_IOMUX_BANK_IS_PMU(bank) ? PMU_GPIO_P_CTL_PULLUP : GRF_GPIO_P_CTL_PULLUP;
+ } else if (flags == GPIO_PIN_PULLDOWN) {
+ bias = RK3399_IOMUX_BANK_IS_PMU(bank) ? PMU_GPIO_P_CTL_PULLDOWN : GRF_GPIO_P_CTL_PULLDOWN;
+ } else {
+ bias = RK3399_IOMUX_BANK_IS_PMU(bank) ? PMU_GPIO_P_CTL_Z : GRF_GPIO_P_CTL_Z;
+ }
+
+ const uint32_t bias_val = __SHIFTIN(bias, GRF_GPIO_P_CTL(idx));
+ const uint32_t bias_mask = GRF_GPIO_P_WRITE_EN(idx);
+
+#ifdef RK3399_IOMUX_DEBUG
+ printf("%s: bank %d idx %d flags %#x: %08x -> ", __func__, bank, idx, flags, RD4(syscon, reg));
+#endif
+ WR4(syscon, reg, bias_val | bias_mask);
+#ifdef RK3399_IOMUX_DEBUG
+ printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg);
+#endif
+}
+
+static int
+rk3399_iomux_map_drive_strength(struct rk3399_iomux_softc *sc, enum rk3399_drv_type drv_type, u_int val)
+{
+ for (int n = 0; rk3399_drv_strength[drv_type][n] != -1; n++)
+ if (rk3399_drv_strength[drv_type][n] == val)
+ return n;
+ return -1;
+}
+
+static int
+rk3399_iomux_set_drive_strength(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int val)
+{
+ const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
+ uint32_t drv_mask, drv_val;
+ bus_size_t reg;
+
+ KASSERT(bank < sc->sc_conf->nbanks);
+
+ if (idx >= 32)
+ return EINVAL;
+
+ const int drv = rk3399_iomux_map_drive_strength(sc, banks[bank].iomux[idx / 8].drv_type, val);
+ if (drv == -1)
+ return EINVAL;
+
+ struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
+ switch (bank) {
+ case 0:
+ case 1:
+ reg = 0x00040 + (0x10 * bank) + 0x4 * (idx / 4);
+ drv_mask = 0x3 << ((idx & 7) * 2);
+ break;
+ case 2:
+ reg = 0x0e100 + 0x4 * (idx / 4);
+ drv_mask = 0x3 << ((idx & 7) * 2);
+ break;
+ case 3:
+ switch (idx / 8) {
+ case 0:
+ case 1:
+ case 2:
+ reg = 0x0e110 + 0x8 * (idx / 4);
+ drv_mask = 0x7 << ((idx & 7) * 3);
+ break;
+ case 3:
+ reg = 0x0e128;
+ drv_mask = 0x3 << ((idx & 7) * 2);
+ break;
+ default:
+ return EINVAL;
+ }
+ break;
+ case 4:
+ switch (idx / 8) {
+ case 0:
+ reg = 0x0e12c;
+ drv_mask = 0x3 << ((idx & 7) * 2);
+ break;
+ case 1:
+ reg = 0x0e130;
+ drv_mask = 0x7 << ((idx & 7) * 3);
+ break;
+ case 2:
+ reg = 0x0e138;
+ drv_mask = 0x3 << ((idx & 7) * 2);
+ break;
+ case 3:
+ reg = 0x0e13c;
+ drv_mask = 0x3 << ((idx & 7) * 2);
+ break;
+ default:
+ return EINVAL;
+ }
+ break;
+ default:
+ return EINVAL;
+ }
+ drv_val = __SHIFTIN(val, drv_mask);
+
+ while (drv_mask) {
+ const uint32_t write_val = drv_val & 0xffff;
+ const uint32_t write_mask = (drv_mask & 0xffff) << 16;
+ if (write_mask) {
+#ifdef RK3399_IOMUX_DEBUG
+ printf("%s: bank %d idx %d val %d: %08x -> ", __func__, bank, idx, val, RD4(syscon, reg));
+#endif
+ WR4(syscon, reg, write_val | write_mask);
+#ifdef RK3399_IOMUX_DEBUG
+ printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg);
+#endif
+ }
+ reg += 0x4;
+ drv_val >>= 16;
+ drv_mask >>= 16;
+ }
+
+ return 0;
+}
+
+static void
+rk3399_iomux_set_mux(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int mux)
+{
+ const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
+ bus_size_t reg;
+ uint32_t mask;
+
+ KASSERT(bank < sc->sc_conf->nbanks);
+
+ struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
+ if (RK3399_IOMUX_BANK_IS_PMU(bank)) {
+ reg = 0x00000 + (0x10 * bank);
+ } else {
+ reg = 0x0e000 + (0x10 * (bank - 2));
+ }
+ reg += 0x4 * (idx / 4);
+ mask = 3 << ((idx & 7) * 2);
+
+#ifdef RK3399_IOMUX_DEBUG
+ printf("%s: bank %d idx %d mux %#x: %08x -> ", __func__, bank, idx, mux, RD4(syscon, reg));
+#endif
+ WR4(syscon, reg, (mask << 16) | __SHIFTIN(mux, mask));
+#ifdef RK3399_IOMUX_DEBUG
+ printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg);
+#endif
+}
+
+static int
+rk3399_iomux_config(struct rk3399_iomux_softc *sc, const int phandle, u_int bank, u_int idx, u_int mux)
+{
+ u_int drv;
+
+ if (of_hasprop(phandle, "bias-disable"))
+ rk3399_iomux_set_bias(sc, bank, idx, 0);
+ else if (of_hasprop(phandle, "bias-pull-up"))
+ rk3399_iomux_set_bias(sc, bank, idx, GPIO_PIN_PULLUP);
+ else if (of_hasprop(phandle, "bias-pull-down"))
+ rk3399_iomux_set_bias(sc, bank, idx, GPIO_PIN_PULLDOWN);
+
+ if (of_getprop_uint32(phandle, "drive-strength", &drv) == 0) {
+ if (rk3399_iomux_set_drive_strength(sc, bank, idx, drv) != 0)
+ return EINVAL;
+ }
+
+#if notyet
+ if (of_hasprop(phandle, "input-enable"))
+ rk3399_iomux_set_direction(sc, bank, idx, GPIO_PIN_INPUT, -1);
+ else if (of_hasprop(phandle, "output-high"))
+ rk3399_iomux_set_direction(sc, bank, idx, GPIO_PIN_OUTPUT, GPIO_PIN_HIGH);
+ else if (of_hasprop(phandle, "output-low"))
+ rk3399_iomux_set_direction(sc, bank, idx, GPIO_PIN_OUTPUT, GPIO_PIN_LOW);
+#endif
+
+ rk3399_iomux_set_mux(sc, bank, idx, mux);
+
+ return 0;
+}
+
+static int
+rk3399_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len)
+{
+ struct rk3399_iomux_softc * const sc = device_private(dev);
+ const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
+ 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]));
+
+ struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
+ LOCK(syscon);
+ rk3399_iomux_config(sc, cfg, bank, idx, mux);
+ UNLOCK(syscon);
+
+ pins_len -= 16;
+ pins += 4;
+ }
+
+ return 0;
+}
+
+static struct fdtbus_pinctrl_controller_func rk3399_iomux_pinctrl_funcs = {
+ .set_config = rk3399_iomux_pinctrl_set_config,
+};
+
+static int
+rk3399_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
+rk3399_iomux_attach(device_t parent, device_t self, void *aux)
+{
+ struct rk3399_iomux_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ int child, sub;
+
+ sc->sc_dev = self;
+ sc->sc_syscon[RK_IOMUX_REGS_GRF] = fdtbus_syscon_acquire(phandle, "rockchip,grf");
+ if (sc->sc_syscon[RK_IOMUX_REGS_GRF] == NULL) {
+ aprint_error(": couldn't acquire grf syscon\n");
+ return;
+ }
+ sc->sc_syscon[RK_IOMUX_REGS_PMU] = fdtbus_syscon_acquire(phandle, "rockchip,pmu");
+ if (sc->sc_syscon[RK_IOMUX_REGS_PMU] == NULL) {
+ aprint_error(": couldn't acquire pmu syscon\n");
+ return;
+ }
+ sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data;
+
+ aprint_naive("\n");
+ aprint_normal(": RK3399 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, &rk3399_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/rk3399_platform.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3399_platform.h:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3399_platform.h Sun Aug 12 16:48:05 2018
@@ -0,0 +1,40 @@
+/* $NetBSD: rk3399_platform.h,v 1.1 2018/08/12 16:48:05 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_RK3399_PLATFORM_H
+#define _ARM_RK3399_PLATFORM_H
+
+#include <arch/evbarm/fdt/platform.h>
+
+#define RK3399_CORE_VBASE KERNEL_IO_VBASE
+#define RK3399_CORE_PBASE 0xf8000000
+#define RK3399_CORE_SIZE 0x08000000
+
+#define RK3399_UART_FREQ 24000000
+
+#endif /* _ARM_RK3399_PLATFORM_H */
Index: src/sys/arch/arm/rockchip/rk3399_pmucru.c
diff -u /dev/null src/sys/arch/arm/rockchip/rk3399_pmucru.c:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3399_pmucru.c Sun Aug 12 16:48:05 2018
@@ -0,0 +1,333 @@
+/* $NetBSD: rk3399_pmucru.c,v 1.1 2018/08/12 16:48:05 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: rk3399_pmucru.c,v 1.1 2018/08/12 16:48:05 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/rk3399_pmucru.h>
+
+#define PLL_CON(n) (0x0000 + (n) * 4)
+#define CLKSEL_CON(n) (0x0080 + (n) * 4)
+#define CLKGATE_CON(n) (0x0100 + (n) * 4)
+#define SOFTRST_CON(n) (0x0110 + (n) * 4)
+
+static int rk3399_pmucru_match(device_t, cfdata_t, void *);
+static void rk3399_pmucru_attach(device_t, device_t, void *);
+
+static const char * const compatible[] = {
+ "rockchip,rk3399-pmucru",
+ NULL
+};
+
+CFATTACH_DECL_NEW(rk3399_pmucru, sizeof(struct rk_cru_softc),
+ rk3399_pmucru_match, rk3399_pmucru_attach, NULL, NULL);
+
+static const struct rk_cru_pll_rate pll_rates[] = {
+ RK_PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0),
+ RK_PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0),
+ RK_PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0),
+ RK_PLL_RATE(2136000000, 1, 89, 1, 1, 1, 0),
+ RK_PLL_RATE(2112000000, 1, 88, 1, 1, 1, 0),
+ RK_PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0),
+ RK_PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0),
+ RK_PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0),
+ RK_PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0),
+ RK_PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0),
+ RK_PLL_RATE(1968000000, 1, 82, 1, 1, 1, 0),
+ RK_PLL_RATE(1944000000, 1, 81, 1, 1, 1, 0),
+ RK_PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0),
+ RK_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
+ RK_PLL_RATE(1872000000, 1, 78, 1, 1, 1, 0),
+ RK_PLL_RATE(1848000000, 1, 77, 1, 1, 1, 0),
+ RK_PLL_RATE(1824000000, 1, 76, 1, 1, 1, 0),
+ RK_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
+ RK_PLL_RATE(1776000000, 1, 74, 1, 1, 1, 0),
+ RK_PLL_RATE(1752000000, 1, 73, 1, 1, 1, 0),
+ RK_PLL_RATE(1728000000, 1, 72, 1, 1, 1, 0),
+ RK_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
+ RK_PLL_RATE(1680000000, 1, 70, 1, 1, 1, 0),
+ RK_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0),
+ RK_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0),
+ RK_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK_PLL_RATE(1600000000, 3, 200, 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, 1, 125, 3, 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, 1, 100, 3, 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( 676000000, 3, 169, 2, 1, 1, 0),
+ RK_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+ RK_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0),
+ RK_PLL_RATE( 533250000, 8, 711, 4, 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( 297000000, 1, 99, 4, 2, 1, 0),
+ RK_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+ RK_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0),
+ RK_PLL_RATE( 106500000, 1, 71, 4, 4, 1, 0),
+ RK_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
+ RK_PLL_RATE( 74250000, 2, 99, 4, 4, 1, 0),
+ RK_PLL_RATE( 65000000, 1, 65, 6, 4, 1, 0),
+ RK_PLL_RATE( 54000000, 1, 54, 6, 4, 1, 0),
+ RK_PLL_RATE( 27000000, 1, 27, 6, 4, 1, 0),
+};
+
+#define PLL_CON0 0x00
+#define PLL_FBDIV __BITS(11,0)
+
+#define PLL_CON1 0x04
+#define PLL_POSTDIV2 __BITS(14,12)
+#define PLL_POSTDIV1 __BITS(10,8)
+#define PLL_REFDIV __BITS(5,0)
+
+#define PLL_CON2 0x08
+#define PLL_LOCK __BIT(31)
+#define PLL_FRACDIV __BITS(23,0)
+
+#define PLL_CON3 0x0c
+#define PLL_WORK_MODE __BITS(9,8)
+#define PLL_WORK_MODE_SLOW 0
+#define PLL_WORK_MODE_NORMAL 1
+#define PLL_WORK_MODE_DEEP_SLOW 2
+#define PLL_DSMPD __BIT(3)
+
+#define PLL_WRITE_MASK 0xffff0000
+
+static u_int
+rk3399_pmucru_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 uint32_t con3 = CRU_READ(sc, pll->con_base + PLL_CON3);
+
+ const u_int fbdiv = __SHIFTOUT(con0, PLL_FBDIV);
+ const u_int postdiv2 = __SHIFTOUT(con1, PLL_POSTDIV2);
+ const u_int postdiv1 = __SHIFTOUT(con1, PLL_POSTDIV1);
+ const u_int refdiv = __SHIFTOUT(con1, PLL_REFDIV);
+ const u_int fracdiv = __SHIFTOUT(con2, PLL_FRACDIV);
+ const u_int dsmpd = __SHIFTOUT(con3, PLL_DSMPD);
+
+ if (dsmpd == 1) {
+ /* integer mode */
+ foutvco = fref / refdiv * fbdiv;
+ } else {
+ /* fractional mode */
+ foutvco = fref / refdiv * fbdiv + ((fref * fracdiv) >> 24);
+ }
+ foutpostdiv = foutvco / postdiv1 / postdiv2;
+
+ return foutpostdiv;
+}
+
+static int
+rk3399_pmucru_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)
+ 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;
+
+ val = __SHIFTIN(PLL_WORK_MODE_SLOW, PLL_WORK_MODE) | (PLL_WORK_MODE << 16);
+ CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
+
+ CRU_WRITE(sc, pll->con_base + PLL_CON0,
+ __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) |
+ PLL_WRITE_MASK);
+
+ CRU_WRITE(sc, pll->con_base + PLL_CON1,
+ __SHIFTIN(pll_rate->postdiv2, PLL_POSTDIV2) |
+ __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) |
+ __SHIFTIN(pll_rate->refdiv, PLL_REFDIV) |
+ PLL_WRITE_MASK);
+
+ 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);
+
+ val = __SHIFTIN(pll_rate->dsmpd, PLL_DSMPD) | (PLL_DSMPD << 16);
+ CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
+
+ /* Set PLL work mode to normal */
+ const uint32_t write_mask = pll->mode_mask << 16;
+ const uint32_t write_val = pll->mode_mask;
+ CRU_WRITE(sc, pll->mode_reg, write_mask | write_val);
+
+ for (retry = 1000; retry > 0; retry--) {
+ if (CRU_READ(sc, pll->con_base + PLL_CON2) & pll->lock_mask)
+ break;
+ delay(1);
+ }
+
+ if (retry == 0)
+ device_printf(sc->sc_dev, "WARNING: %s failed to lock\n",
+ clk->base.name);
+
+ val = __SHIFTIN(PLL_WORK_MODE_NORMAL, PLL_WORK_MODE) | (PLL_WORK_MODE << 16);
+ CRU_WRITE(sc, pll->con_base + PLL_CON3, val);
+
+ return 0;
+}
+
+#define RK3399_PLL(_id, _name, _parents, _con_base, _mode_reg, _mode_mask, _lock_mask, _rates) \
+ { \
+ .id = (_id), \
+ .type = RK_CRU_PLL, \
+ .base.name = (_name), \
+ .base.flags = 0, \
+ .u.pll.parents = (_parents), \
+ .u.pll.nparents = __arraycount(_parents), \
+ .u.pll.con_base = (_con_base), \
+ .u.pll.mode_reg = (_mode_reg), \
+ .u.pll.mode_mask = (_mode_mask), \
+ .u.pll.lock_mask = (_lock_mask), \
+ .u.pll.rates = (_rates), \
+ .u.pll.nrates = __arraycount(_rates), \
+ .get_rate = rk3399_pmucru_pll_get_rate, \
+ .set_rate = rk3399_pmucru_pll_set_rate, \
+ .get_parent = rk_cru_pll_get_parent, \
+ }
+
+static const char * pll_parents[] = { "xin24m", "xin32k" };
+
+static struct rk_cru_clk rk3399_pmucru_clks[] = {
+ RK3399_PLL(RK3399_PLL_PPLL, "ppll", pll_parents,
+ PLL_CON(0), /* con_base */
+ PLL_CON(3), /* mode_reg */
+ __BIT(8), /* mode_mask */
+ __BIT(31), /* lock_mask */
+ pll_rates),
+
+ RK_DIV(RK3399_PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLKSEL_CON(0), __BITS(4,0), 0),
+
+ RK_GATE(RK3399_PCLK_PMU, "pclk_pmu", "pclk_pmu_src", CLKGATE_CON(1), 0),
+ RK_GATE(RK3399_PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", CLKGATE_CON(1), 3),
+ RK_GATE(RK3399_PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", CLKGATE_CON(1), 4),
+};
+
+static int
+rk3399_pmucru_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
+rk3399_pmucru_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 = rk3399_pmucru_clks;
+ sc->sc_nclks = __arraycount(rk3399_pmucru_clks);
+
+ sc->sc_softrst_base = SOFTRST_CON(0);
+
+ if (rk_cru_attach(sc) != 0)
+ return;
+
+ aprint_naive("\n");
+ aprint_normal(": RK3399 PMU CRU\n");
+
+ rk_cru_print(sc);
+}
Index: src/sys/arch/arm/rockchip/rk3399_pmucru.h
diff -u /dev/null src/sys/arch/arm/rockchip/rk3399_pmucru.h:1.1
--- /dev/null Sun Aug 12 16:48:05 2018
+++ src/sys/arch/arm/rockchip/rk3399_pmucru.h Sun Aug 12 16:48:05 2018
@@ -0,0 +1,72 @@
+/* $NetBSD: rk3399_pmucru.h,v 1.1 2018/08/12 16:48:05 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RK3399_PMUCRU_H
+#define _RK3399_PMUCRU_H
+
+/*
+ * Clocks
+ */
+
+#define RK3399_PLL_PPLL 1
+#define RK3399_SCLK_32K_SUSPEND_PMU 2
+#define RK3399_SCLK_SPI3_PMU 3
+#define RK3399_SCLK_TIMER12_PMU 4
+#define RK3399_SCLK_TIMER13_PMU 5
+#define RK3399_SCLK_UART4_PMU 6
+#define RK3399_SCLK_PVTM_PMU 7
+#define RK3399_SCLK_WIFI_PMU 8
+#define RK3399_SCLK_I2C0_PMU 9
+#define RK3399_SCLK_I2C4_PMU 10
+#define RK3399_SCLK_I2C8_PMU 11
+#define RK3399_PCLK_SRC_PMU 19
+#define RK3399_PCLK_PMU 20
+#define RK3399_PCLK_PMUGRF_PMU 21
+#define RK3399_PCLK_INTMEM1_PMU 22
+#define RK3399_PCLK_GPIO0_PMU 23
+#define RK3399_PCLK_GPIO1_PMU 24
+#define RK3399_PCLK_SGRF_PMU 25
+#define RK3399_PCLK_NOC_PMU 26
+#define RK3399_PCLK_I2C0_PMU 27
+#define RK3399_PCLK_I2C4_PMU 28
+#define RK3399_PCLK_I2C8_PMU 29
+#define RK3399_PCLK_RKPWM_PMU 30
+#define RK3399_PCLK_SPI3_PMU 31
+#define RK3399_PCLK_TIMER_PMU 32
+#define RK3399_PCLK_MAILBOX_PMU 33
+#define RK3399_PCLK_UART4_PMU 34
+#define RK3399_PCLK_WDT_M0_PMU 35
+#define RK3399_FCLK_CM0S_SRC_PMU 44
+#define RK3399_FCLK_CM0S_PMU 45
+#define RK3399_SCLK_CM0S_PMU 46
+#define RK3399_HCLK_CM0S_PMU 47
+#define RK3399_DCLK_CM0S_PMU 48
+#define RK3399_PCLK_INTR_ARB_PMU 49
+#define RK3399_HCLK_NOC_PMU 50
+
+#endif /* !_RK3399_PMUCRU_H */