Module Name:    src
Committed By:   jmcneill
Date:           Wed Jan 15 01:09:57 UTC 2020

Modified Files:
        src/sys/arch/arm/imx: if_enet.c if_enet_imx6.c if_enet_imx7.c
            if_enetvar.h imx6_board.c imx6_pcie.c imx6_usdhc.c imx7_usdhc.c
            imxgpio.c imxgpiovar.h imxuart.c
        src/sys/arch/arm/imx/fdt: files.imx6 if_enet_imx.c imx6_com.c
            imx6_gpio.c imx6_iomux.c imx6_sdhc.c
        src/sys/arch/evbarm/conf: GENERIC64 files.generic64
        src/sys/dev/fdt: dwc3_fdt.c
Added Files:
        src/sys/arch/arm/imx/fdt: imx7_gpc.c imx8mq_ccm.c imx8mq_ccm.h
            imx8mq_usbphy.c imx_ccm.c imx_ccm.h imx_ccm_composite.c
            imx_ccm_extclk.c imx_ccm_fixed.c imx_ccm_fixed_factor.c
            imx_ccm_gate.c

Log Message:
Add support for NXP i.MX 8M Dual/8M QuadLite/8M Quad family SoCs.


To generate a diff of this commit:
cvs rdiff -u -r1.29 -r1.30 src/sys/arch/arm/imx/if_enet.c
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/imx/if_enet_imx6.c \
    src/sys/arch/arm/imx/imx6_usdhc.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/imx/if_enet_imx7.c
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/imx/if_enetvar.h
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/arm/imx/imx6_board.c \
    src/sys/arch/arm/imx/imx6_pcie.c
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/imx/imx7_usdhc.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/imx/imxgpio.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/imx/imxgpiovar.h
cvs rdiff -u -r1.23 -r1.24 src/sys/arch/arm/imx/imxuart.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/imx/fdt/files.imx6
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/imx/fdt/if_enet_imx.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/imx/fdt/imx6_com.c \
    src/sys/arch/arm/imx/fdt/imx6_iomux.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/imx/fdt/imx6_gpio.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/imx/fdt/imx6_sdhc.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx7_gpc.c \
    src/sys/arch/arm/imx/fdt/imx8mq_ccm.c \
    src/sys/arch/arm/imx/fdt/imx8mq_ccm.h \
    src/sys/arch/arm/imx/fdt/imx8mq_usbphy.c \
    src/sys/arch/arm/imx/fdt/imx_ccm.c src/sys/arch/arm/imx/fdt/imx_ccm.h \
    src/sys/arch/arm/imx/fdt/imx_ccm_composite.c \
    src/sys/arch/arm/imx/fdt/imx_ccm_extclk.c \
    src/sys/arch/arm/imx/fdt/imx_ccm_fixed.c \
    src/sys/arch/arm/imx/fdt/imx_ccm_fixed_factor.c \
    src/sys/arch/arm/imx/fdt/imx_ccm_gate.c
cvs rdiff -u -r1.131 -r1.132 src/sys/arch/evbarm/conf/GENERIC64
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/evbarm/conf/files.generic64
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/fdt/dwc3_fdt.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/imx/if_enet.c
diff -u src/sys/arch/arm/imx/if_enet.c:1.29 src/sys/arch/arm/imx/if_enet.c:1.30
--- src/sys/arch/arm/imx/if_enet.c:1.29	Fri Nov 29 17:20:30 2019
+++ src/sys/arch/arm/imx/if_enet.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_enet.c,v 1.29 2019/11/29 17:20:30 ryo Exp $	*/
+/*	$NetBSD: if_enet.c,v 1.30 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org>
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_enet.c,v 1.29 2019/11/29 17:20:30 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_enet.c,v 1.30 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "vlan.h"
 
@@ -247,7 +247,7 @@ enet_attach_common(device_t self)
 	ifmedia_init(&mii->mii_media, 0, ether_mediachange, enet_mediastatus);
 
 	/* try to attach PHY */
-	mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+	mii_attach(self, mii, 0xffffffff, sc->sc_phyid, MII_OFFSET_ANY, 0);
 	if (LIST_FIRST(&mii->mii_phys) == NULL) {
 		ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL);

Index: src/sys/arch/arm/imx/if_enet_imx6.c
diff -u src/sys/arch/arm/imx/if_enet_imx6.c:1.8 src/sys/arch/arm/imx/if_enet_imx6.c:1.9
--- src/sys/arch/arm/imx/if_enet_imx6.c:1.8	Mon Nov 25 00:54:47 2019
+++ src/sys/arch/arm/imx/if_enet_imx6.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_enet_imx6.c,v 1.8 2019/11/25 00:54:47 hkenken Exp $	*/
+/*	$NetBSD: if_enet_imx6.c,v 1.9 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_enet_imx6.c,v 1.8 2019/11/25 00:54:47 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_enet_imx6.c,v 1.9 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "locators.h"
 #include "imxccm.h"
@@ -88,6 +88,7 @@ enet_attach(device_t parent, device_t se
 	sc->sc_dmat = aa->aa_dmat;
 
 	sc->sc_imxtype = 6;	/* i.MX6 */
+	sc->sc_phyid = MII_PHY_ANY;
 	if (IMX6_CHIPID_MAJOR(imx6_chip_id()) == CHIPID_MAJOR_IMX6UL)
 		sc->sc_rgmii = 0;
 	else
Index: src/sys/arch/arm/imx/imx6_usdhc.c
diff -u src/sys/arch/arm/imx/imx6_usdhc.c:1.8 src/sys/arch/arm/imx/imx6_usdhc.c:1.9
--- src/sys/arch/arm/imx/imx6_usdhc.c:1.8	Wed Jul 24 12:33:18 2019
+++ src/sys/arch/arm/imx/imx6_usdhc.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_usdhc.c,v 1.8 2019/07/24 12:33:18 hkenken Exp $ */
+/*	$NetBSD: imx6_usdhc.c,v 1.9 2020/01/15 01:09:56 jmcneill Exp $ */
 /*-
  * Copyright (c) 2012  Genetec Corporation.  All rights reserved.
  * Written by Hiroyuki Bessho for Genetec Corporation.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx6_usdhc.c,v 1.8 2019/07/24 12:33:18 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx6_usdhc.c,v 1.9 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "imxgpio.h"
 
@@ -184,7 +184,7 @@ imx6_sdhc_card_detect(struct sdhc_softc 
 
 	sc = device_private(ssc->sc_dev);
 	if (sc->sc_gpio_cd >= 0) {
-		detect = gpio_data_read(sc->sc_gpio_cd);
+		detect = imxgpio_data_read(sc->sc_gpio_cd);
 		if (sc->sc_gpio_cd_active == GPIO_PIN_LOW)
 			detect = !detect;
 	} else

Index: src/sys/arch/arm/imx/if_enet_imx7.c
diff -u src/sys/arch/arm/imx/if_enet_imx7.c:1.5 src/sys/arch/arm/imx/if_enet_imx7.c:1.6
--- src/sys/arch/arm/imx/if_enet_imx7.c:1.5	Tue Nov 12 05:09:29 2019
+++ src/sys/arch/arm/imx/if_enet_imx7.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_enet_imx7.c,v 1.5 2019/11/12 05:09:29 hkenken Exp $	*/
+/*	$NetBSD: if_enet_imx7.c,v 1.6 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_enet_imx7.c,v 1.5 2019/11/12 05:09:29 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_enet_imx7.c,v 1.6 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "locators.h"
 #include "imxccm.h"
@@ -84,6 +84,7 @@ enet_attach(device_t parent, device_t se
 
 	sc->sc_imxtype = 7;	/* i.MX7 */
 	sc->sc_rgmii = 1;
+	sc->sc_phyid = MII_PHY_ANY;
 
 	switch (aa->aa_addr) {
 	case (IMX7_AIPS_BASE + AIPS3_ENET1_BASE):

Index: src/sys/arch/arm/imx/if_enetvar.h
diff -u src/sys/arch/arm/imx/if_enetvar.h:1.6 src/sys/arch/arm/imx/if_enetvar.h:1.7
--- src/sys/arch/arm/imx/if_enetvar.h:1.6	Tue Nov 12 05:09:29 2019
+++ src/sys/arch/arm/imx/if_enetvar.h	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_enetvar.h,v 1.6 2019/11/12 05:09:29 hkenken Exp $	*/
+/*	$NetBSD: if_enetvar.h,v 1.7 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org>
@@ -58,6 +58,7 @@ struct enet_softc {
 	int sc_unit;
 	int sc_imxtype;
 	int sc_rgmii;
+	int sc_phyid;
 	unsigned int sc_clock;
 
 	struct clk *sc_clk_ipg;

Index: src/sys/arch/arm/imx/imx6_board.c
diff -u src/sys/arch/arm/imx/imx6_board.c:1.14 src/sys/arch/arm/imx/imx6_board.c:1.15
--- src/sys/arch/arm/imx/imx6_board.c:1.14	Sat Jul 27 08:02:04 2019
+++ src/sys/arch/arm/imx/imx6_board.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_board.c,v 1.14 2019/07/27 08:02:04 skrll Exp $	*/
+/*	$NetBSD: imx6_board.c,v 1.15 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2012  Genetec Corporation.  All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: imx6_board.c,v 1.14 2019/07/27 08:02:04 skrll Exp $");
+__KERNEL_RCSID(1, "$NetBSD: imx6_board.c,v 1.15 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "arml2cc.h"
 #include "imxgpio.h"
@@ -281,6 +281,6 @@ imx6_set_gpio(device_t self, const char 
 
 	*gpio = GPIO_NO(grp, pin);
 #if NIMXGPIO > 0
-	gpio_set_direction(*gpio, dir);
+	imxgpio_set_direction(*gpio, dir);
 #endif
 }
Index: src/sys/arch/arm/imx/imx6_pcie.c
diff -u src/sys/arch/arm/imx/imx6_pcie.c:1.14 src/sys/arch/arm/imx/imx6_pcie.c:1.15
--- src/sys/arch/arm/imx/imx6_pcie.c:1.14	Wed Oct 16 11:16:30 2019
+++ src/sys/arch/arm/imx/imx6_pcie.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_pcie.c,v 1.14 2019/10/16 11:16:30 hkenken Exp $	*/
+/*	$NetBSD: imx6_pcie.c,v 1.15 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2016  Genetec Corporation.  All rights reserved.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx6_pcie.c,v 1.14 2019/10/16 11:16:30 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx6_pcie.c,v 1.15 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_pci.h"
 
@@ -231,9 +231,9 @@ imx6_pcie_reset(void *cookie)
 
 #if NIMXGPIO > 0
 	if (ipsc->sc_gpio_reset >= 0) {
-		gpio_data_write(ipsc->sc_gpio_reset, ipsc->sc_gpio_reset_active);
+		imxgpio_data_write(ipsc->sc_gpio_reset, ipsc->sc_gpio_reset_active);
 		delay(100 * 1000);
-		gpio_data_write(ipsc->sc_gpio_reset, !ipsc->sc_gpio_reset_active);
+		imxgpio_data_write(ipsc->sc_gpio_reset, !ipsc->sc_gpio_reset_active);
 	}
 #endif
 }

Index: src/sys/arch/arm/imx/imx7_usdhc.c
diff -u src/sys/arch/arm/imx/imx7_usdhc.c:1.3 src/sys/arch/arm/imx/imx7_usdhc.c:1.4
--- src/sys/arch/arm/imx/imx7_usdhc.c:1.3	Wed Jul 24 12:33:18 2019
+++ src/sys/arch/arm/imx/imx7_usdhc.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx7_usdhc.c,v 1.3 2019/07/24 12:33:18 hkenken Exp $	*/
+/*	$NetBSD: imx7_usdhc.c,v 1.4 2020/01/15 01:09:56 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2012  Genetec Corporation.  All rights reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx7_usdhc.c,v 1.3 2019/07/24 12:33:18 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx7_usdhc.c,v 1.4 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "imxgpio.h"
 
@@ -93,7 +93,7 @@ imx7_sdhc_card_detect(struct sdhc_softc 
 	sc = device_private(ssc->sc_dev);
 #if NIMXGPIO > 0
 	if (sc->sc_gpio_cd >= 0) {
-		detect = gpio_data_read(sc->sc_gpio_cd);
+		detect = imxgpio_data_read(sc->sc_gpio_cd);
 	} else
 #endif
 		detect = 1;
@@ -143,7 +143,7 @@ sdhc_set_gpio_cd(struct sdhc_axi_softc *
 
 	sc->sc_gpio_cd = GPIO_NO(grp, pin);
 #if NIMXGPIO > 0
-	gpio_set_direction(sc->sc_gpio_cd, GPIO_PIN_INPUT);
+	imxgpio_set_direction(sc->sc_gpio_cd, GPIO_PIN_INPUT);
 #endif
 }
 

Index: src/sys/arch/arm/imx/imxgpio.c
diff -u src/sys/arch/arm/imx/imxgpio.c:1.7 src/sys/arch/arm/imx/imxgpio.c:1.8
--- src/sys/arch/arm/imx/imxgpio.c:1.7	Wed Nov 27 07:26:08 2019
+++ src/sys/arch/arm/imx/imxgpio.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imxgpio.c,v 1.7 2019/11/27 07:26:08 hkenken Exp $ */
+/*	$NetBSD: imxgpio.c,v 1.8 2020/01/15 01:09:56 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imxgpio.c,v 1.7 2019/11/27 07:26:08 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imxgpio.c,v 1.8 2020/01/15 01:09:56 jmcneill Exp $");
 
 #define	_INTR_PRIVATE
 
@@ -327,25 +327,26 @@ imxgpio_attach_common(device_t self)
 {
 	struct imxgpio_softc * const gpio = device_private(self);
 
-	KASSERT(gpio->gpio_unit < MAX_NGROUP);
-
 	gpio->gpio_dev = self;
 
-	if (gpio->gpio_irqbase > 0) {
-		aprint_normal_dev(gpio->gpio_dev, "interrupts %d..%d\n",
-		    gpio->gpio_irqbase, gpio->gpio_irqbase + GPIO_NPINS - 1);
-
+	if (gpio->gpio_irqbase == PIC_IRQBASE_ALLOC || gpio->gpio_irqbase > 0) {
 		gpio->gpio_pic.pic_ops = &imxgpio_pic_ops;
 		strlcpy(gpio->gpio_pic.pic_name, device_xname(self),
 		    sizeof(gpio->gpio_pic.pic_name));
-		gpio->gpio_pic.pic_maxsources = 32;
+		gpio->gpio_pic.pic_maxsources = GPIO_NPINS;
 
-		pic_add(&gpio->gpio_pic, gpio->gpio_irqbase);
+		gpio->gpio_irqbase = pic_add(&gpio->gpio_pic, gpio->gpio_irqbase);
+
+		aprint_normal_dev(gpio->gpio_dev, "interrupts %d..%d\n",
+		    gpio->gpio_irqbase, gpio->gpio_irqbase + GPIO_NPINS - 1);
 	}
 
 	mutex_init(&gpio->gpio_lock, MUTEX_DEFAULT, IPL_VM);
 
-	imxgpio_handles[gpio->gpio_unit] = gpio;
+	if (gpio->gpio_unit != -1) {
+		KASSERT(gpio->gpio_unit < MAX_NGROUP);
+		imxgpio_handles[gpio->gpio_unit] = gpio;
+	}
 
 #if NGPIO > 0
 	imxgpio_attach_ports(gpio);
@@ -354,7 +355,7 @@ imxgpio_attach_common(device_t self)
 
 /* in-kernel GPIO access utility functions */
 void
-gpio_set_direction(u_int gpio, int dir)
+imxgpio_set_direction(u_int gpio, int dir)
 {
 	int index = gpio / GPIO_NPINS;
 	int pin = gpio % GPIO_NPINS;
@@ -366,7 +367,7 @@ gpio_set_direction(u_int gpio, int dir)
 }
 
 void
-gpio_data_write(u_int gpio, u_int value)
+imxgpio_data_write(u_int gpio, u_int value)
 {
 	int index = gpio / GPIO_NPINS;
 	int pin = gpio % GPIO_NPINS;
@@ -378,7 +379,7 @@ gpio_data_write(u_int gpio, u_int value)
 }
 
 bool
-gpio_data_read(u_int gpio)
+imxgpio_data_read(u_int gpio)
 {
 	int index = gpio / GPIO_NPINS;
 	int pin = gpio % GPIO_NPINS;

Index: src/sys/arch/arm/imx/imxgpiovar.h
diff -u src/sys/arch/arm/imx/imxgpiovar.h:1.2 src/sys/arch/arm/imx/imxgpiovar.h:1.3
--- src/sys/arch/arm/imx/imxgpiovar.h:1.2	Wed Jul 24 12:33:18 2019
+++ src/sys/arch/arm/imx/imxgpiovar.h	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imxgpiovar.h,v 1.2 2019/07/24 12:33:18 hkenken Exp $ */
+/*	$NetBSD: imxgpiovar.h,v 1.3 2020/01/15 01:09:56 jmcneill Exp $ */
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -45,8 +45,8 @@ struct imxgpio_softc {
 	void *gpio_is;
 	void *gpio_is_high;
 
-	uint gpio_unit;
-	uint gpio_irqbase;
+	int gpio_unit;
+	int gpio_irqbase;
 	uint32_t gpio_enable_mask;
 	uint32_t gpio_edge_mask;
 	uint32_t gpio_level_mask;
@@ -75,9 +75,9 @@ void imxgpio_pin_write(void *, int, int)
 void imxgpio_pin_ctl(void *, int, int);
 
 /* in-kernel GPIO access utility functions */
-void gpio_set_direction(u_int, int);
-void gpio_data_write(u_int, u_int);
-bool gpio_data_read(u_int);
+void imxgpio_set_direction(u_int, int);
+void imxgpio_data_write(u_int, u_int);
+bool imxgpio_data_read(u_int);
 
 #define	GPIO_NO(group, pin)	(((group) - 1) * GPIO_NPINS + (pin))
 #define	GPIO_MODULE(pin)	((pin) / GPIO_NPINS)

Index: src/sys/arch/arm/imx/imxuart.c
diff -u src/sys/arch/arm/imx/imxuart.c:1.23 src/sys/arch/arm/imx/imxuart.c:1.24
--- src/sys/arch/arm/imx/imxuart.c:1.23	Sun Jan 12 00:35:11 2020
+++ src/sys/arch/arm/imx/imxuart.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: imxuart.c,v 1.23 2020/01/12 00:35:11 jmcneill Exp $ */
+/* $NetBSD: imxuart.c,v 1.24 2020/01/15 01:09:56 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2009, 2010  Genetec Corporation.  All rights reserved.
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imxuart.c,v 1.23 2020/01/12 00:35:11 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imxuart.c,v 1.24 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_imxuart.h"
 #include "opt_ddb.h"
@@ -1459,9 +1459,11 @@ imxustart(struct tty *tp)
 	space = imxuart_txfifo_space(sc);
 	n = MIN(sc->sc_tbc, space);
 
-	bus_space_write_multi_1(iot, ioh, IMX_UTXD, sc->sc_tba, n);
-	sc->sc_tbc -= n;
-	sc->sc_tba += n;
+	if (n > 0) {
+		bus_space_write_multi_1(iot, ioh, IMX_UTXD, sc->sc_tba, n);
+		sc->sc_tbc -= n;
+		sc->sc_tba += n;
+	}
 
 	/* Enable transmit completion interrupts */
 	imxuart_control_txint(sc, true);

Index: src/sys/arch/arm/imx/fdt/files.imx6
diff -u src/sys/arch/arm/imx/fdt/files.imx6:1.7 src/sys/arch/arm/imx/fdt/files.imx6:1.8
--- src/sys/arch/arm/imx/fdt/files.imx6:1.7	Sat Oct 12 06:46:13 2019
+++ src/sys/arch/arm/imx/fdt/files.imx6	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-#	$NetBSD: files.imx6,v 1.7 2019/10/12 06:46:13 skrll Exp $
+#	$NetBSD: files.imx6,v 1.8 2020/01/15 01:09:56 jmcneill Exp $
 #
 # Configuration info for the Freescale i.MX6
 #
@@ -15,11 +15,30 @@ attach	imxccm at fdt
 file	arch/arm/imx/imx6_ccm.c		imxccm
 file	arch/arm/imx/fdt/imx6_clk.c	imxccm
 
+
+# Common FDT clock framework
+define	imx_ccm
+file	arch/arm/imx/fdt/imx_ccm.c		imx_ccm
+file	arch/arm/imx/fdt/imx_ccm_extclk.c	imx_ccm
+file	arch/arm/imx/fdt/imx_ccm_gate.c		imx_ccm
+file	arch/arm/imx/fdt/imx_ccm_composite.c	imx_ccm
+file	arch/arm/imx/fdt/imx_ccm_fixed.c	imx_ccm
+file	arch/arm/imx/fdt/imx_ccm_fixed_factor.c	imx_ccm
+
+# CCM (iMX8MQ)
+device	imx8mqccm: imx_ccm
+attach	imx8mqccm at fdt with imx8mq_ccm
+file	arch/arm/imx/fdt/imx8mq_ccm.c	imx8mq_ccm
+
 # GPC
 device	imxgpc
 attach	imxgpc at fdt
 file	arch/arm/imx/fdt/imx6_gpc.c	imxgpc
 
+device	imx7gpc
+attach	imx7gpc at fdt
+file	arch/arm/imx/fdt/imx7_gpc.c	imx7gpc
+
 # IOMUX
 device	imxiomux
 attach	imxiomux at fdt
@@ -61,6 +80,11 @@ device	imxusbphy
 attach	imxusbphy at fdt
 file	arch/arm/imx/fdt/imx6_usbphy.c	imxusbphy
 
+device	imx8mqusbphy
+attach	imx8mqusbphy at fdt
+file	arch/arm/imx/fdt/imx8mq_usbphy.c	imx8mqusbphy
+
+
 # SDMMC
 attach	sdhc at fdt with imx6_sdhc
 file	arch/arm/imx/fdt/imx6_sdhc.c	imx6_sdhc

Index: src/sys/arch/arm/imx/fdt/if_enet_imx.c
diff -u src/sys/arch/arm/imx/fdt/if_enet_imx.c:1.8 src/sys/arch/arm/imx/fdt/if_enet_imx.c:1.9
--- src/sys/arch/arm/imx/fdt/if_enet_imx.c:1.8	Thu Nov 14 06:00:16 2019
+++ src/sys/arch/arm/imx/fdt/if_enet_imx.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_enet_imx.c,v 1.8 2019/11/14 06:00:16 hkenken Exp $	*/
+/*	$NetBSD: if_enet_imx.c,v 1.9 2020/01/15 01:09:56 jmcneill Exp $	*/
 /*-
  * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
  * Written by Hashimoto Kenichi for Genetec Corporation.
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_enet_imx.c,v 1.8 2019/11/14 06:00:16 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_enet_imx.c,v 1.9 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_fdt.h"
 
@@ -49,20 +49,24 @@ struct enet_fdt_softc {
 CFATTACH_DECL_NEW(enet_fdt, sizeof(struct enet_fdt_softc),
     enet_match, enet_attach, NULL, NULL);
 
-static const char * const compatible[] = {
-	"fsl,imx6q-fec",
-	NULL
+static const struct of_compat_data compat_data[] = {
+	/* compatible			imxtype */
+	{ "fsl,imx6q-fec",		6 },
+	{ "fsl,imx6sx-fec",		7 },
+	{ NULL }
 };
 
 static int enet_init_clocks(struct enet_softc *);
 static void enet_phy_reset(struct enet_fdt_softc *, const int);
+static int enet_phy_id(struct enet_softc *, const int);
+static void *enet_intr_establish(struct enet_softc *, int, u_int);
 
 int
 enet_match(device_t parent, cfdata_t cf, void *aux)
 {
 	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);
 }
 
 void
@@ -100,12 +104,21 @@ enet_attach(device_t parent, device_t se
 		aprint_error(": couldn't get clock ahb\n");
 		goto failure;
 	}
-	sc->sc_clk_enet_ref= fdtbus_clock_get(phandle, "ptp");
+	sc->sc_clk_enet_ref = fdtbus_clock_get(phandle, "ptp");
 	if (sc->sc_clk_enet_ref == NULL) {
 		aprint_error(": couldn't get clock ptp\n");
 		goto failure;
 	}
 
+	if (fdtbus_clock_enable(phandle, "enet_clk_ref", false) != 0) {
+		aprint_error(": couldn't enable clock enet_clk_ref\n");
+		goto failure;
+	}
+	if (fdtbus_clock_enable(phandle, "enet_out", false) != 0) {
+		aprint_error(": couldn't enable clock enet_out\n");
+		goto failure;
+	}
+
 	aprint_naive("\n");
 	aprint_normal(": Gigabit Ethernet Controller\n");
 
@@ -114,8 +127,9 @@ enet_attach(device_t parent, device_t se
 	sc->sc_ioh = bsh;
 	sc->sc_dmat = faa->faa_dmat;
 
-	sc->sc_imxtype = 6;	/* i.MX6 */
+	sc->sc_imxtype = of_search_compatible(phandle, compat_data)->data;
 	sc->sc_unit = 0;
+	sc->sc_phyid = enet_phy_id(sc, phandle);
 
 	const char *phy_mode = fdtbus_get_string(phandle, "phy-mode");
 	if (phy_mode == NULL) {
@@ -139,19 +153,16 @@ enet_attach(device_t parent, device_t se
 		sc->sc_rgmii = 0;
 	}
 
-	char intrstr[128];
-	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
-		aprint_error_dev(self, "failed to decode interrupt\n");
-		goto failure;
-	}
-	sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_NET,
-	    FDT_INTR_MPSAFE, enet_intr, sc);
-	if (sc->sc_ih == NULL) {
-		aprint_error_dev(self, "failed to establish interrupt on %s\n",
-		    intrstr);
+	sc->sc_ih = enet_intr_establish(sc, phandle, 0);
+	if (sc->sc_ih == NULL)
 		goto failure;
+
+	if (sc->sc_imxtype == 7) {
+		sc->sc_ih2 = enet_intr_establish(sc, phandle, 1);
+		sc->sc_ih3 = enet_intr_establish(sc, phandle, 2);
+		if (sc->sc_ih2 == NULL || sc->sc_ih3 == NULL)
+			goto failure;
 	}
-	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
 
 	enet_init_clocks(sc);
 	sc->sc_clock = clk_get_rate(sc->sc_clk_ipg);
@@ -168,6 +179,29 @@ failure:
 	return;
 }
 
+static void *
+enet_intr_establish(struct enet_softc *sc, int phandle, u_int index)
+{
+	char intrstr[128];
+	void *ih;
+
+	if (!fdtbus_intr_str(phandle, index, intrstr, sizeof(intrstr))) {
+		aprint_error_dev(sc->sc_dev, "failed to decode interrupt %d\n",
+		    index);
+		return NULL;
+	}
+
+	ih = fdtbus_intr_establish(phandle, index, IPL_NET, 0, enet_intr, sc);
+	if (ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "failed to establish interrupt on %s\n",
+		    intrstr);
+		return NULL;
+	}
+	aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr);
+
+	return ih;
+}
+
 static int
 enet_init_clocks(struct enet_softc *sc)
 {
@@ -198,8 +232,10 @@ enet_phy_reset(struct enet_fdt_softc *sc
 	u_int msec;
 
 	sc->sc_pin_reset = fdtbus_gpio_acquire(phandle, "phy-reset-gpios", GPIO_PIN_OUTPUT);
-	if (sc->sc_pin_reset == NULL)
+	if (sc->sc_pin_reset == NULL) {
+		aprint_error_dev(sc->sc_enet.sc_dev, "couldn't find phy reset gpios\n");
 		return;
+	}
 
 	if (of_getprop_uint32(phandle, "phy-reset-duration", &msec))
 		msec = 1;
@@ -215,3 +251,19 @@ enet_phy_reset(struct enet_fdt_softc *sc
 
 	delay(msec * 1000);
 }
+
+static int
+enet_phy_id(struct enet_softc *sc, const int phandle)
+{
+	int phy_phandle;
+	bus_addr_t addr;
+
+	phy_phandle = fdtbus_get_phandle(phandle, "phy-handle");
+	if (phy_phandle == -1)
+		return MII_PHY_ANY;
+
+	if (fdtbus_get_reg(phy_phandle, 0, &addr, NULL) != 0)
+		return MII_PHY_ANY;
+
+	return (int)addr;
+}

Index: src/sys/arch/arm/imx/fdt/imx6_com.c
diff -u src/sys/arch/arm/imx/fdt/imx6_com.c:1.2 src/sys/arch/arm/imx/fdt/imx6_com.c:1.3
--- src/sys/arch/arm/imx/fdt/imx6_com.c:1.2	Thu Nov 28 14:13:37 2019
+++ src/sys/arch/arm/imx/fdt/imx6_com.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_com.c,v 1.2 2019/11/28 14:13:37 hkenken Exp $	*/
+/*	$NetBSD: imx6_com.c,v 1.3 2020/01/15 01:09:56 jmcneill Exp $	*/
 /*-
  * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
  * Written by Hashimoto Kenichi for Genetec Corporation.
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx6_com.c,v 1.2 2019/11/28 14:13:37 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx6_com.c,v 1.3 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_fdt.h"
 #include "opt_imxuart.h"
@@ -70,6 +70,7 @@ imx6_com_attach(device_t parent, device_
 	bus_space_tag_t bst = faa->faa_bst;
 	bus_space_handle_t bsh;
 	char intrstr[128];
+	struct clk *per;
 	bus_addr_t addr;
 	bus_size_t size;
 
@@ -83,11 +84,28 @@ imx6_com_attach(device_t parent, device_
 		return;
 	}
 
+	if (fdtbus_clock_enable(phandle, "ipg", false) != 0) {
+		aprint_error(": couldn't enable ipg clock\n");
+		return;
+	}
+
+	per = fdtbus_clock_get(phandle, "per");
+	if (per != NULL && clk_enable(per) != 0) {
+		aprint_error(": couldn't enable per clock\n");
+		return;
+	}
+
 	sc->sc_dev = self;
 	regsp->ur_iot = bst;
 	regsp->ur_iobase = addr;
 	regsp->ur_ioh = bsh;
 
+	if (per != NULL) {
+		aprint_normal(", %u Hz", clk_get_rate(per));
+		/* XXX */
+		imxuart_set_frequency(clk_get_rate(per), 2);
+	}
+
 	if (imxuart_is_console(regsp->ur_iot, regsp->ur_iobase, &regsp->ur_ioh))
 		aprint_normal(" (console)");
 
@@ -108,7 +126,6 @@ imx6_com_attach(device_t parent, device_
 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
 
 	imxuart_attach_subr(sc);
-
 }
 
 /*
Index: src/sys/arch/arm/imx/fdt/imx6_iomux.c
diff -u src/sys/arch/arm/imx/fdt/imx6_iomux.c:1.2 src/sys/arch/arm/imx/fdt/imx6_iomux.c:1.3
--- src/sys/arch/arm/imx/fdt/imx6_iomux.c:1.2	Wed Oct  2 01:34:09 2019
+++ src/sys/arch/arm/imx/fdt/imx6_iomux.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_iomux.c,v 1.2 2019/10/02 01:34:09 hkenken Exp $	*/
+/*	$NetBSD: imx6_iomux.c,v 1.3 2020/01/15 01:09:56 jmcneill Exp $	*/
 /*-
  * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
  * Written by Hashimoto Kenichi for Genetec Corporation.
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx6_iomux.c,v 1.2 2019/10/02 01:34:09 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx6_iomux.c,v 1.3 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_fdt.h"
 
@@ -132,7 +132,11 @@ CFATTACH_DECL_NEW(imxiomux, sizeof(struc
 static int
 imxiomux_match(device_t parent, cfdata_t cf, void *aux)
 {
-	const char * const compatible[] = { "fsl,imx6q-iomuxc", NULL };
+	const char * const compatible[] = {
+		"fsl,imx6q-iomuxc",
+		"fsl,imx8mq-iomuxc",
+		NULL
+	};
 	struct fdt_attach_args * const faa = aux;
 
 	return of_match_compatible(faa->faa_phandle, compatible);
@@ -166,10 +170,14 @@ imxiomux_attach(device_t parent, device_
 	aprint_normal(": IOMUX Controller\n");
 
 	for (int child = OF_child(phandle); child; child = OF_peer(child)) {
-		for (int sub = OF_child(child); sub; sub = OF_peer(sub)) {
-			if (!of_hasprop(sub, "fsl,pins"))
-				continue;
-			fdtbus_register_pinctrl_config(self, sub, &imx6_pinctrl_funcs);
+		if (of_hasprop(child, "fsl,pins")) {
+			fdtbus_register_pinctrl_config(self, child, &imx6_pinctrl_funcs);
+		} else {
+			for (int sub = OF_child(child); sub; sub = OF_peer(sub)) {
+				if (!of_hasprop(sub, "fsl,pins"))
+					continue;
+				fdtbus_register_pinctrl_config(self, sub, &imx6_pinctrl_funcs);
+			}
 		}
 	}
 }

Index: src/sys/arch/arm/imx/fdt/imx6_gpio.c
diff -u src/sys/arch/arm/imx/fdt/imx6_gpio.c:1.4 src/sys/arch/arm/imx/fdt/imx6_gpio.c:1.5
--- src/sys/arch/arm/imx/fdt/imx6_gpio.c:1.4	Wed Nov 27 07:26:08 2019
+++ src/sys/arch/arm/imx/fdt/imx6_gpio.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_gpio.c,v 1.4 2019/11/27 07:26:08 hkenken Exp $	*/
+/*	$NetBSD: imx6_gpio.c,v 1.5 2020/01/15 01:09:56 jmcneill Exp $	*/
 /*-
  * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
  * Written by Hashimoto Kenichi for Genetec Corporation.
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx6_gpio.c,v 1.4 2019/11/27 07:26:08 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx6_gpio.c,v 1.5 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_fdt.h"
 #include "gpio.h"
@@ -80,7 +80,7 @@ int
 imxgpio_match(device_t parent, cfdata_t cf, void *aux)
 {
 	const char * const compatible[] = {
-		"fsl,imx6q-gpio",
+		"fsl,imx35-gpio",
 		NULL
 	};
 	struct fdt_attach_args * const faa = aux;
@@ -116,8 +116,8 @@ imxgpio_attach(device_t parent, device_t
 
 	sc->gpio_memt = faa->faa_bst;
 	sc->gpio_memh = ioh;
-	sc->gpio_unit = (addr - IMX6_AIPS1_BASE - AIPS1_GPIO1_BASE) / 0x4000;
-	sc->gpio_irqbase = PIC_MAXSOURCES + sc->gpio_unit * GPIO_NPINS;
+	sc->gpio_unit = -1;
+	sc->gpio_irqbase = PIC_IRQBASE_ALLOC;
 
 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
 		aprint_error_dev(self, "failed to decode interrupt\n");

Index: src/sys/arch/arm/imx/fdt/imx6_sdhc.c
diff -u src/sys/arch/arm/imx/fdt/imx6_sdhc.c:1.5 src/sys/arch/arm/imx/fdt/imx6_sdhc.c:1.6
--- src/sys/arch/arm/imx/fdt/imx6_sdhc.c:1.5	Sun Nov 24 11:07:19 2019
+++ src/sys/arch/arm/imx/fdt/imx6_sdhc.c	Wed Jan 15 01:09:56 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: imx6_sdhc.c,v 1.5 2019/11/24 11:07:19 skrll Exp $	*/
+/*	$NetBSD: imx6_sdhc.c,v 1.6 2020/01/15 01:09:56 jmcneill Exp $	*/
 /*-
  * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
  * Written by Hashimoto Kenichi for Genetec Corporation.
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx6_sdhc.c,v 1.5 2019/11/24 11:07:19 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx6_sdhc.c,v 1.6 2020/01/15 01:09:56 jmcneill Exp $");
 
 #include "opt_fdt.h"
 
@@ -63,6 +63,7 @@ struct imx6_sdhc_softc {
 	void			*sc_ih;
 
 	struct clk		*sc_clk_per;
+	struct fdtbus_regulator	*sc_vmmc_supply;
 
 	struct fdtbus_gpio_pin	*sc_pin_cd;
 	struct fdtbus_gpio_pin	*sc_pin_wp;
@@ -71,9 +72,23 @@ struct imx6_sdhc_softc {
 CFATTACH_DECL_NEW(imx6_sdhc, sizeof(struct imx6_sdhc_softc),
 	imx6_sdhc_match, imx6_sdhc_attach, NULL, NULL);
 
-static const char * const compatible[] = {
-	"fsl,imx6q-usdhc",
-	NULL
+struct imx6_sdhc_config {
+	uint32_t		flags;
+};
+
+static const struct imx6_sdhc_config imx6q_config = {
+	.flags = SDHC_FLAG_BROKEN_ADMA2_ZEROLEN |
+		 SDHC_FLAG_NO_BUSY_INTR,
+};
+
+static const struct imx6_sdhc_config imx7d_config = {
+	.flags = 0
+};
+
+static const struct of_compat_data compat_data[] = {
+	{ "fsl,imx6q-usdhc",	(uintptr_t)&imx6q_config },
+	{ "fsl,imx7d-usdhc",	(uintptr_t)&imx7d_config },
+	{ NULL }
 };
 
 static int
@@ -81,7 +96,7 @@ imx6_sdhc_match(device_t parent, cfdata_
 {
 	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
@@ -89,26 +104,34 @@ imx6_sdhc_attach(device_t parent, device
 {
 	struct imx6_sdhc_softc * const sc = device_private(self);
 	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+	const struct imx6_sdhc_config *conf;
 	char intrstr[128];
 	bus_addr_t addr;
 	bus_size_t size;
 	u_int bus_width;
 	int error;
 
-	if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
+	fdtbus_clock_assign(phandle);
+
+	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
 		aprint_error(": couldn't get registers\n");
 		return;
 	}
 
-	if (of_getprop_uint32(faa->faa_phandle, "bus-width", &bus_width))
-		bus_width = 4;
-
-	sc->sc_clk_per = fdtbus_clock_get(faa->faa_phandle, "per");
+	sc->sc_clk_per = fdtbus_clock_get(phandle, "per");
 	if (sc->sc_clk_per == NULL) {
 		aprint_error(": couldn't get clock\n");
 		return;
 	}
 
+	if (of_getprop_uint32(phandle, "bus-width", &bus_width))
+		bus_width = 4;
+
+	sc->sc_vmmc_supply = fdtbus_regulator_acquire(phandle, "vmmc-supply");
+
+	conf = (void *)of_search_compatible(phandle, compat_data)->data;
+
 	sc->sc_sdhc.sc_dev = self;
 	sc->sc_sdhc.sc_dmat = faa->faa_dmat;
 
@@ -119,13 +142,12 @@ imx6_sdhc_attach(device_t parent, device
 	    SDHC_FLAG_HAVE_DVS |
 	    SDHC_FLAG_32BIT_ACCESS |
 	    SDHC_FLAG_USE_ADMA2 |
-	    SDHC_FLAG_USDHC |
-	    SDHC_FLAG_NO_BUSY_INTR |
-	    SDHC_FLAG_BROKEN_ADMA2_ZEROLEN;
+	    SDHC_FLAG_USDHC;
+	sc->sc_sdhc.sc_flags |= conf->flags;
 
 	if (bus_width == 8)
 		sc->sc_sdhc.sc_flags |= SDHC_FLAG_8BIT_MODE;
-	if (of_hasprop(faa->faa_phandle, "no-1-8-v"))
+	if (of_hasprop(phandle, "no-1-8-v"))
 		sc->sc_sdhc.sc_flags |= SDHC_FLAG_NO_1_8_V;
 
 	sc->sc_sdhc.sc_host = &sc->sc_host;
@@ -138,14 +160,14 @@ imx6_sdhc_attach(device_t parent, device
 	}
 	sc->sc_bsz = size;
 
-	sc->sc_pin_cd = fdtbus_gpio_acquire(faa->faa_phandle,
+	sc->sc_pin_cd = fdtbus_gpio_acquire(phandle,
 	    "cd-gpios", GPIO_PIN_INPUT);
 	if (sc->sc_pin_cd) {
 		sc->sc_sdhc.sc_vendor_card_detect = imx6_sdhc_card_detect;
 		sc->sc_sdhc.sc_flags |= SDHC_FLAG_POLL_CARD_DET;
 	}
 
-	sc->sc_pin_wp = fdtbus_gpio_acquire(faa->faa_phandle,
+	sc->sc_pin_wp = fdtbus_gpio_acquire(phandle,
 	    "wp-gpios", GPIO_PIN_INPUT);
 	if (sc->sc_pin_wp) {
 		sc->sc_sdhc.sc_vendor_write_protect = imx6_sdhc_write_protect;
@@ -157,6 +179,14 @@ imx6_sdhc_attach(device_t parent, device
 		return;
 	}
 
+	if (sc->sc_vmmc_supply != NULL) {
+		error = fdtbus_regulator_enable(sc->sc_vmmc_supply);
+		if (error) {
+			aprint_error(": couldn't enable vmmc supply: %d\n", error);
+			return;
+		}
+	}
+
 	aprint_naive("\n");
 	aprint_normal(": SDMMC (%u kHz)\n", sc->sc_sdhc.sc_clkbase);
 
@@ -165,12 +195,12 @@ imx6_sdhc_attach(device_t parent, device
 		return;
 	}
 
-	if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) {
+	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
 		aprint_error_dev(self, "failed to decode interrupt\n");
 		return;
 	}
 
-	sc->sc_ih = fdtbus_intr_establish(faa->faa_phandle, 0, IPL_SDMMC,
+	sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_SDMMC,
 	    FDT_INTR_MPSAFE, sdhc_intr, &sc->sc_sdhc);
 	if (sc->sc_ih == NULL) {
 		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
@@ -183,7 +213,7 @@ imx6_sdhc_attach(device_t parent, device
 	if (error) {
 		aprint_error_dev(self, "couldn't initialize host, error = %d\n",
 		    error);
-		fdtbus_intr_disestablish(faa->faa_phandle, sc->sc_ih);
+		fdtbus_intr_disestablish(phandle, sc->sc_ih);
 		sc->sc_ih = NULL;
 		return;
 	}

Index: src/sys/arch/evbarm/conf/GENERIC64
diff -u src/sys/arch/evbarm/conf/GENERIC64:1.131 src/sys/arch/evbarm/conf/GENERIC64:1.132
--- src/sys/arch/evbarm/conf/GENERIC64:1.131	Sun Jan 12 21:52:36 2020
+++ src/sys/arch/evbarm/conf/GENERIC64	Wed Jan 15 01:09:57 2020
@@ -1,5 +1,5 @@
 #
-#	$NetBSD: GENERIC64,v 1.131 2020/01/12 21:52:36 riastradh Exp $
+#	$NetBSD: GENERIC64,v 1.132 2020/01/15 01:09:57 jmcneill Exp $
 #
 #	GENERIC ARM (aarch64) kernel
 #
@@ -16,7 +16,7 @@ maxusers	64
 #
 makeoptions 	DTSARCH="arm aarch64"
 makeoptions	DTSGNUARCH="arm arm64"
-makeoptions	DTSSUBDIR="allwinner amlogic broadcom nvidia rockchip"
+makeoptions	DTSSUBDIR="allwinner amlogic broadcom freescale nvidia rockchip"
 makeoptions	DTS="
 	bcm2711-rpi-4-b.dts
 	bcm2837-rpi-3-a-plus.dts
@@ -24,6 +24,14 @@ makeoptions	DTS="
 	bcm2837-rpi-3-b.dts
 	bcm2837-rpi-cm3-io3.dts
 
+	imx8mq-evk.dts
+	imx8mq-hummingboard-pulse.dts
+	imx8mq-librem5-devkit.dts
+	imx8mq-nitrogen.dts
+	imx8mq-pico-pi.dts
+	imx8mq-zii-ultra-rmb3.dts
+	imx8mq-zii-ultra-zest.dts
+
 	meson-gxbb-nanopi-k2.dts
 	meson-gxbb-nexbox-a95x.dts
 	meson-gxbb-odroidc2.dts
@@ -234,6 +242,7 @@ gic*		at acpi?
 armgic0		at gic?
 gicvthree*	at fdt? pass 1		# ARM GICv3
 gicvthree*	at acpi?
+imx7gpc*	at fdt? pass 2		# IMX GPCv2
 sunxinmi*	at fdt? pass 2		# Allwinner NMI / R_INTC
 
 # Memory controller
@@ -263,6 +272,7 @@ bcmcprman*	at fdt? pass 1		# Broadcom BC
 bcmaux*		at fdt? pass 1		# Broadcom BCM283x Aux Periph Clocks
 gxbbaoclkc*	at fdt? pass 2		# Amlogic Meson GXBB AO clock controller
 gxbbclkc*	at fdt? pass 2		# Amlogic Meson GXBB/GXL EE clock controller
+imx8mqccm*	at fdt? pass 2		# NXP iMX8MQ CCM
 mesonresets*	at fdt? pass 2		# Amlogic Meson misc. clock resets
 rkcru*		at fdt? pass 2		# Rockchip RK3328 CRU
 sun8ih3ccu*	at fdt? pass 2		# Allwinner H3/H5 CCU
@@ -279,6 +289,7 @@ tegra210car*	at fdt? pass 3		# NVIDIA Te
 
 # GPIO controller
 bcmgpio*	at fdt?			# Broadcom BCM283x GPIO
+imxgpio*	at fdt? pass 3		# IMX GPIO
 mesonpinctrl*	at fdt? pass 2		# Amlogic Meson GPIO
 plgpio*		at fdt?			# ARM PrimeCell PL061 GPIO
 plgpio*		at acpi?
@@ -292,6 +303,7 @@ rkpwm*		at fdt? pass 3		# Rockchip PWM
 sunxipwm*	at fdt? pass 3		# Allwinner PWM
 
 # MPIO / Pinmux
+imxiomux*	at fdt? pass 2		# IMX IOMUX
 rkiomux*	at fdt?	pass 3		# Rockchip IOMUX
 tegrapinmux*	at fdt?			# NVIDIA Tegra MPIO
 
@@ -312,6 +324,7 @@ pci*		at ppb?
 # Ethernet
 awge*		at fdt?				# DesignWare Gigabit Ethernet
 emac*		at fdt?				# Allwinner Gigabit Ethernet (EMAC)
+enet*		at fdt?				# IMX FEC
 aq*		at pci? dev ? function ?	# Aquantia AQC 10 gigabit
 ena*		at pci? dev ? function ?	# Amazon.com Elastic Network Adapter
 mcx*		at pci? dev ? function ?	# Mellanox 5th generation Ethernet
@@ -321,6 +334,7 @@ re*		at pci? dev ? function ?	# Realtek 
 wm*		at pci? dev ? function ?	# Intel Gigabit Ethernet
 
 # MII/PHY support
+atphy*		at mii? phy ?		# Attansic/Atheros PHYs
 exphy* 		at mii? phy ?		# 3Com internal PHYs
 gentbi* 	at mii? phy ?		# Generic Ten-Bit 1000BASE-[CLS]X PHYs
 glxtphy*	at mii? phy ?		# Level One LXT-1000 PHYs
@@ -354,6 +368,8 @@ ukphy*		at mii? phy ?		# generic unknown
 # UART
 com*		at fdt?	pass 4			# UART
 com*		at acpi?
+imxuart*	at fdt? pass 4			# IMX UART
+options 	IMXUARTCONSOLE
 mesonuart*	at fdt? pass 4			# Amlogic Meson UART
 plcom*		at fdt?	pass 4			# ARM PL011 UART
 plcom*		at acpi?
@@ -513,6 +529,7 @@ tegrasoctherm*	at fdt?			# NVIDIA Tegra 
 rktsadc*	at fdt?			# RockChip TSASC
 
 # USB
+imx8mqusbphy*	at fdt? pass 9		# IMX USB PHY
 mesonusbphy*	at fdt? pass 9		# Amlogic Meson USB2 PHY
 mesongxlu2phy*	at fdt? pass 9		# Amlogic Meson GXL USB2 PHY
 mesongxlu3phy*	at fdt? pass 9		# Amlogic Meson GXL USB3 PHY

Index: src/sys/arch/evbarm/conf/files.generic64
diff -u src/sys/arch/evbarm/conf/files.generic64:1.14 src/sys/arch/evbarm/conf/files.generic64:1.15
--- src/sys/arch/evbarm/conf/files.generic64:1.14	Sun Jan  5 17:26:31 2020
+++ src/sys/arch/evbarm/conf/files.generic64	Wed Jan 15 01:09:57 2020
@@ -1,4 +1,4 @@
-#	$NetBSD: files.generic64,v 1.14 2020/01/05 17:26:31 jmcneill Exp $
+#	$NetBSD: files.generic64,v 1.15 2020/01/15 01:09:57 jmcneill Exp $
 #
 # A generic (aarch64) kernel configuration info
 #
@@ -13,6 +13,7 @@ include "arch/evbarm/conf/files.fdt"
 include "arch/arm/acpi/files.acpi"
 include "arch/arm/amlogic/files.meson"
 include "arch/arm/broadcom/files.bcm2835"
+include "arch/arm/imx/fdt/files.imx6"
 include "arch/arm/nvidia/files.tegra"
 include "arch/arm/rockchip/files.rockchip"
 include "arch/arm/sunxi/files.sunxi"

Index: src/sys/dev/fdt/dwc3_fdt.c
diff -u src/sys/dev/fdt/dwc3_fdt.c:1.8 src/sys/dev/fdt/dwc3_fdt.c:1.9
--- src/sys/dev/fdt/dwc3_fdt.c:1.8	Thu Dec 12 00:45:59 2019
+++ src/sys/dev/fdt/dwc3_fdt.c	Wed Jan 15 01:09:57 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc3_fdt.c,v 1.8 2019/12/12 00:45:59 jmcneill Exp $ */
+/* $NetBSD: dwc3_fdt.c,v 1.9 2020/01/15 01:09:57 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc3_fdt.c,v 1.8 2019/12/12 00:45:59 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc3_fdt.c,v 1.9 2020/01/15 01:09:57 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -208,6 +208,7 @@ dwc3_fdt_match(device_t parent, cfdata_t
 	const char * const compatible[] = {
 		"allwinner,sun50i-h6-dwc3",
 		"amlogic,meson-gxl-dwc3",
+		"fsl,imx8mq-dwc3",
 		"rockchip,rk3328-dwc3",
 		"rockchip,rk3399-dwc3",
 		"samsung,exynos5250-dwusb3",
@@ -221,6 +222,7 @@ dwc3_fdt_match(device_t parent, cfdata_t
 static void
 dwc3_fdt_attach(device_t parent, device_t self, void *aux)
 {
+	const char * const dwc3_compatible[] = { "snps,dwc3", NULL };
 	struct xhci_softc * const sc = device_private(self);
 	struct fdt_attach_args * const faa = aux;
 	const int phandle = faa->faa_phandle;
@@ -230,12 +232,16 @@ dwc3_fdt_attach(device_t parent, device_
 	char intrstr[128];
 	bus_addr_t addr;
 	bus_size_t size;
-	int error;
+	int error, dwc3_phandle;
 	void *ih;
 	u_int n;
 
 	/* Find dwc3 sub-node */
-	const int dwc3_phandle = of_find_firstchild_byname(phandle, "dwc3");
+	if (of_match_compatible(phandle, dwc3_compatible) > 0) {
+		dwc3_phandle = phandle;
+	} else {
+		dwc3_phandle = of_find_firstchild_byname(phandle, "dwc3");
+	}
 	if (dwc3_phandle <= 0) {
 		aprint_error(": couldn't find dwc3 child node\n");
 		return;
@@ -249,6 +255,7 @@ dwc3_fdt_attach(device_t parent, device_
 	}
 
 	/* Enable clocks */
+	fdtbus_clock_assign(phandle);
 	for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++)
 		if (clk_enable(clk) != 0) {
 			aprint_error(": couldn't enable clock #%d\n", n);

Added files:

Index: src/sys/arch/arm/imx/fdt/imx7_gpc.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx7_gpc.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx7_gpc.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,264 @@
+/*	$NetBSD: imx7_gpc.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $	*/
+/*-
+ * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
+ * Written by Hashimoto Kenichi for Genetec Corporation.
+ *
+ * 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: imx7_gpc.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include "opt_fdt.h"
+
+#define	_INTR_PRIVATE
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+
+#include <arm/imx/imx6var.h>
+#include <arm/imx/imx6_reg.h>
+#include <arm/imx/imx6_gpcreg.h>
+
+#include <arm/cortex/gic_intr.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#define	GPC_PCG_CPU_0_1_MAPPING		0xec
+#define	 OTG2_A53_DOMAIN		__BIT(5)
+#define	 OTG1_A53_DOMAIN		__BIT(4)
+
+#define	GPC_PU_PGC_SW_PUP_REQ		0xf8
+#define	 USB_OTG2_SW_PUP_REQ		__BIT(3)
+#define	 USB_OTG1_SW_PUP_REQ		__BIT(2)
+
+#define	IMXGPC_MAXCPUS	4
+
+/* Mapping of CPU number to GPC_IMR1_COREx base offset */
+static const bus_size_t imx7gpc_imr_base[IMXGPC_MAXCPUS] = {
+	0x30,
+	0x40,
+	0x1c0,
+	0x1d0,
+};
+
+#define	GPC_IMRn_COREx(n,x)	(imx7gpc_imr_base[(x)] + (n) * 0x4)
+
+struct imx7gpc_softc {
+	device_t sc_dev;
+
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+};
+
+static int imx7gpc_match(device_t, struct cfdata *, void *);
+static void imx7gpc_attach(device_t, device_t, void *);
+
+static void imx7gpc_powerup(struct imx7gpc_softc *, uint32_t, uint32_t);
+static void imx7gpc_mask(struct imx7gpc_softc *, u_int, bool);
+static void imx7gpc_unmask(struct imx7gpc_softc *, u_int, bool);
+
+static void *imx7gpc_establish(device_t, u_int *, int, int,
+    int (*)(void *), void *);
+static void imx7gpc_disestablish(device_t, void *);
+static bool imx7gpc_intrstr(device_t, u_int *, char *, size_t);
+
+struct fdtbus_interrupt_controller_func imx7gpc_funcs = {
+	.establish = imx7gpc_establish,
+	.disestablish = imx7gpc_disestablish,
+	.intrstr = imx7gpc_intrstr
+};
+
+CFATTACH_DECL_NEW(imx7gpc, sizeof(struct imx7gpc_softc),
+    imx7gpc_match, imx7gpc_attach, NULL, NULL);
+
+static int
+imx7gpc_match(device_t parent, cfdata_t cf, void *aux)
+{
+	const char * const compatible[] = {
+		"fsl,imx7d-gpc",
+		"fsl,imx8mq-gpc",
+		NULL
+	};
+	struct fdt_attach_args * const faa = aux;
+
+	return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+imx7gpc_attach(device_t parent, device_t self, void *aux)
+{
+	struct imx7gpc_softc * const sc = device_private(self);
+	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+	bus_addr_t gpc_addr;
+	bus_size_t gpc_size;
+	int error;
+
+	KASSERT(ncpu <= IMXGPC_MAXCPUS);
+
+	if (fdtbus_get_reg(phandle, 0, &gpc_addr, &gpc_size) != 0) {
+		aprint_error(": couldn't get gpc registers\n");
+		return;
+	}
+
+	sc->sc_dev = self;
+	sc->sc_iot = faa->faa_bst;
+
+	error = bus_space_map(sc->sc_iot, gpc_addr, gpc_size, 0,
+	    &sc->sc_ioh);
+	if (error) {
+		aprint_error(": couldn't map gpc registers: %d\n", error);
+		return;
+	}
+
+	error = fdtbus_register_interrupt_controller(self, faa->faa_phandle,
+	    &imx7gpc_funcs);
+	if (error) {
+		aprint_error(": couldn't register with fdtbus: %d\n", error);
+		return;
+	}
+
+	aprint_naive("\n");
+	aprint_normal(": General Power Controller\n");
+
+	/* XXX enable OTG power domains */
+	imx7gpc_powerup(sc, USB_OTG2_SW_PUP_REQ | USB_OTG1_SW_PUP_REQ,
+	    OTG2_A53_DOMAIN | OTG1_A53_DOMAIN);
+}
+
+static void
+imx7gpc_powerup(struct imx7gpc_softc *sc, uint32_t req, uint32_t map)
+{
+	uint32_t val;
+
+	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPC_PCG_CPU_0_1_MAPPING);
+	val |= map;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPC_PCG_CPU_0_1_MAPPING, val);
+
+	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPC_PU_PGC_SW_PUP_REQ);
+	val |= req;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPC_PU_PGC_SW_PUP_REQ, val);
+
+	delay(5000);
+
+	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPC_PCG_CPU_0_1_MAPPING);
+	val &= ~map;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPC_PCG_CPU_0_1_MAPPING, val);
+}
+
+static void
+imx7gpc_mask(struct imx7gpc_softc *sc, u_int irq, bool mpsafe)
+{
+	const u_int reg = irq / 32;
+	const u_int bit = irq % 32;
+	uint32_t val;
+
+	for (u_int cpu = 0; cpu < (mpsafe ? ncpu : 1); cpu++) {
+		val = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+		    GPC_IMRn_COREx(reg, cpu));
+		val |= __BIT(bit);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    GPC_IMRn_COREx(reg, cpu), val);
+	}
+}
+
+static void
+imx7gpc_unmask(struct imx7gpc_softc *sc, u_int irq, bool mpsafe)
+{
+	const u_int reg = irq / 32;
+	const u_int bit = irq % 32;
+	uint32_t val;
+
+	for (u_int cpu = 0; cpu < (mpsafe ? ncpu : 1); cpu++) {
+		val = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+		    GPC_IMRn_COREx(reg, cpu));
+		val &= ~__BIT(bit);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    GPC_IMRn_COREx(reg, cpu), val);
+	}
+}
+
+
+static void *
+imx7gpc_establish(device_t dev, u_int *specifier, int ipl, int flags,
+    int (*func)(void *), void *arg)
+{
+	struct imx7gpc_softc * const sc = device_private(dev);
+	void *ih;
+
+	/* 1st cell is the interrupt type; 0 is SPI, 1 is PPI */
+	/* 2nd cell is the interrupt number */
+	/* 3rd cell is flags */
+
+	const u_int type = be32toh(specifier[0]);
+	const u_int intr = be32toh(specifier[1]);
+	const u_int irq = type == 0 ? IRQ_SPI(intr) : IRQ_PPI(intr);
+	const u_int trig = be32toh(specifier[2]) & 0xf;
+	const u_int level = (trig & 0x3) ? IST_EDGE : IST_LEVEL;
+
+	const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
+
+	if (type != 0)
+		return NULL;	/* Only SPIs are supported */
+
+	KASSERT(irq >= 32);
+
+	aprint_debug_dev(dev, "intr establish irq %d, level %d\n", irq, level);
+
+	ih = intr_establish(irq, ipl, level | mpsafe, func, arg);
+	if (ih != NULL)
+		imx7gpc_unmask(sc, irq - 32, mpsafe == IST_MPSAFE);
+
+	return ih;
+}
+
+static void
+imx7gpc_disestablish(device_t dev, void *ih)
+{
+	struct imx7gpc_softc * const sc = device_private(dev);
+	struct intrsource *is = ih;
+	const u_int irq = is->is_irq;
+	const bool mpsafe = is->is_mpsafe;
+
+	intr_disestablish(ih);
+	imx7gpc_mask(sc, irq - 32, mpsafe);
+}
+
+static bool
+imx7gpc_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
+{
+	/* 1st cell is the interrupt type; 0 is SPI, 1 is PPI */
+	/* 2nd cell is the interrupt number */
+	/* 3rd cell is flags */
+
+	if (!specifier)
+		return false;
+
+	const u_int type = be32toh(specifier[0]);
+	const u_int intr = be32toh(specifier[1]);
+	const u_int irq = type == 0 ? IRQ_SPI(intr) : IRQ_PPI(intr);
+
+	snprintf(buf, buflen, "irq %d", irq);
+
+	return true;
+}
Index: src/sys/arch/arm/imx/fdt/imx8mq_ccm.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx8mq_ccm.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx8mq_ccm.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,194 @@
+/* $NetBSD: imx8mq_ccm.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(0, "$NetBSD: imx8mq_ccm.c,v 1.1 2020/01/15 01:09:56 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/imx/fdt/imx_ccm.h>
+#include <arm/imx/fdt/imx8mq_ccm.h>
+
+static int imx8mq_ccm_match(device_t, cfdata_t, void *);
+static void imx8mq_ccm_attach(device_t, device_t, void *);
+
+static const char * const compatible[] = {
+	"fsl,imx8mq-ccm",
+	NULL
+};
+
+static const char *uart_p[] = {
+	"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m", "sys3_pll_out", "clk_ext2", "clk_ext4", "audio_pll2_out"
+};
+static const char *usdhc_p[] = {
+	"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m", "audio_pll2_out", "sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m"
+};
+static const char *enet_axi_p[] = {
+	"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", "sys2_pll_200m", "audio_pll1_out", "video_pll1_out", "sys3_pll_out"
+};
+static const char *enet_ref_p[] = {
+	"osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m", "sys1_pll_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4"
+};
+static const char *enet_timer_p[] = {
+	"osc_25m", "sys2_pll_100m", "audio_pll1_out", "clk_ext1", "clk_ext2", "clk_ext3", "clk_ext4", "video_pll1_out"
+};
+static const char *enet_phy_ref_p[] = {
+	"osc_25m", "sys2_pll_50m", "sys2_pll_125m", "sys2_pll_500m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out"
+};
+static const char *usb_bus_p[] = {
+	"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m", "sys2_pll_200m", "clk_ext2", "clk_ext4", "audio_pll2_out"
+};
+static const char *usb_core_phy_p[] = {
+	"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m", "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out"
+};
+
+CFATTACH_DECL_NEW(imx8mq_ccm, sizeof(struct imx_ccm_softc),
+	imx8mq_ccm_match, imx8mq_ccm_attach, NULL, NULL);
+
+static struct imx_ccm_clk imx8mq_ccm_clks[] = {
+
+	IMX_FIXED(CLK_DUMMY, "dummy", 0),
+	IMX_EXTCLK(CLK_32K, "ckil"),
+	IMX_EXTCLK(CLK_25M, "osc_25m"),
+	IMX_EXTCLK(CLK_27M, "osc_27m"),
+	IMX_EXTCLK(CLK_EXT1, "clk_ext1"),
+	IMX_EXTCLK(CLK_EXT2, "clk_ext2"),
+	IMX_EXTCLK(CLK_EXT3, "clk_ext3"),
+	IMX_EXTCLK(CLK_EXT4, "clk_ext4"),
+
+	IMX_FIXED(SYS1_PLL_OUT, "sys1_pll_out", 800000000),
+	IMX_FIXED(SYS2_PLL_OUT, "sys2_pll_out", 1000000000),
+
+	IMX_GATE(SYS1_PLL_40M_CG, "sys1_pll_40m_cg", "sys1_pll_out", 0x30, __BIT(9)),
+	IMX_GATE(SYS1_PLL_80M_CG, "sys1_pll_80m_cg", "sys1_pll_out", 0x30, __BIT(11)),
+	IMX_GATE(SYS1_PLL_100M_CG, "sys1_pll_100m_cg", "sys1_pll_out", 0x30, __BIT(13)),
+	IMX_GATE(SYS1_PLL_133M_CG, "sys1_pll_133m_cg", "sys1_pll_out", 0x30, __BIT(15)),
+	IMX_GATE(SYS1_PLL_160M_CG, "sys1_pll_160m_cg", "sys1_pll_out", 0x30, __BIT(17)),
+	IMX_GATE(SYS1_PLL_200M_CG, "sys1_pll_200m_cg", "sys1_pll_out", 0x30, __BIT(19)),
+	IMX_GATE(SYS1_PLL_266M_CG, "sys1_pll_266m_cg", "sys1_pll_out", 0x30, __BIT(21)),
+	IMX_GATE(SYS1_PLL_400M_CG, "sys1_pll_400m_cg", "sys1_pll_out", 0x30, __BIT(23)),
+	IMX_GATE(SYS1_PLL_800M_CG, "sys1_pll_800m_cg", "sys1_pll_out", 0x30, __BIT(25)),
+
+	IMX_FIXED_FACTOR(SYS1_PLL_40M, "sys1_pll_40m", "sys1_pll_40m_cg", 1, 20),
+	IMX_FIXED_FACTOR(SYS1_PLL_80M, "sys1_pll_80m", "sys1_pll_80m_cg", 1, 10),
+	IMX_FIXED_FACTOR(SYS1_PLL_100M, "sys1_pll_100m", "sys1_pll_100m_cg", 1, 8),
+	IMX_FIXED_FACTOR(SYS1_PLL_133M, "sys1_pll_133m", "sys1_pll_133m_cg", 1, 6),
+	IMX_FIXED_FACTOR(SYS1_PLL_160M, "sys1_pll_160m", "sys1_pll_160m_cg", 1, 5),
+	IMX_FIXED_FACTOR(SYS1_PLL_200M, "sys1_pll_200m", "sys1_pll_200m_cg", 1, 4),
+	IMX_FIXED_FACTOR(SYS1_PLL_266M, "sys1_pll_266m", "sys1_pll_266m_cg", 1, 3),
+	IMX_FIXED_FACTOR(SYS1_PLL_400M, "sys1_pll_400m", "sys1_pll_400m_cg", 1, 2),
+	IMX_FIXED_FACTOR(SYS1_PLL_800M, "sys1_pll_800m", "sys1_pll_800m_cg", 1, 1),
+
+	IMX_GATE(SYS2_PLL_50M_CG, "sys2_pll_50m_cg", "sys2_pll_out", 0x3c, __BIT(9)),
+	IMX_GATE(SYS2_PLL_100M_CG, "sys2_pll_100m_cg", "sys2_pll_out", 0x3c, __BIT(11)),
+	IMX_GATE(SYS2_PLL_125M_CG, "sys2_pll_125m_cg", "sys2_pll_out", 0x3c, __BIT(13)),
+	IMX_GATE(SYS2_PLL_166M_CG, "sys2_pll_166m_cg", "sys2_pll_out", 0x3c, __BIT(15)),
+	IMX_GATE(SYS2_PLL_200M_CG, "sys2_pll_200m_cg", "sys2_pll_out", 0x3c, __BIT(17)),
+	IMX_GATE(SYS2_PLL_250M_CG, "sys2_pll_250m_cg", "sys2_pll_out", 0x3c, __BIT(19)),
+	IMX_GATE(SYS2_PLL_333M_CG, "sys2_pll_333m_cg", "sys2_pll_out", 0x3c, __BIT(21)),
+	IMX_GATE(SYS2_PLL_500M_CG, "sys2_pll_500m_cg", "sys2_pll_out", 0x3c, __BIT(23)),
+	IMX_GATE(SYS2_PLL_1000M_CG, "sys2_pll_1000m_cg", "sys2_pll_out", 0x3c, __BIT(25)),
+
+	IMX_FIXED_FACTOR(SYS2_PLL_50M, "sys2_pll_50m", "sys2_pll_50m_cg", 1, 20),
+	IMX_FIXED_FACTOR(SYS2_PLL_100M, "sys2_pll_100m", "sys2_pll_100m_cg", 1, 10),
+	IMX_FIXED_FACTOR(SYS2_PLL_125M, "sys2_pll_125m", "sys2_pll_125m_cg", 1, 8),
+	IMX_FIXED_FACTOR(SYS2_PLL_166M, "sys2_pll_166m", "sys2_pll_166m_cg", 1, 6),
+	IMX_FIXED_FACTOR(SYS2_PLL_200M, "sys2_pll_200m", "sys2_pll_200m_cg", 1, 5),
+	IMX_FIXED_FACTOR(SYS2_PLL_250M, "sys2_pll_250m", "sys2_pll_250m_cg", 1, 4),
+	IMX_FIXED_FACTOR(SYS2_PLL_333M, "sys2_pll_333m", "sys2_pll_333m_cg", 1, 3),
+	IMX_FIXED_FACTOR(SYS2_PLL_500M, "sys2_pll_500m", "sys2_pll_500m_cg", 1, 2),
+	IMX_FIXED_FACTOR(SYS2_PLL_1000M, "sys2_pll_1000m", "sys2_pll_1000m_cg", 1, 1),
+
+	IMX_COMPOSITE(CLK_UART1, "uart1", uart_p, 0xaf00, 0),
+	IMX_COMPOSITE(CLK_UART2, "uart2", uart_p, 0xaf80, 0),
+	IMX_COMPOSITE(CLK_UART3, "uart3", uart_p, 0xb000, 0),
+	IMX_COMPOSITE(CLK_UART4, "uart4", uart_p, 0xb080, 0),
+
+	IMX_ROOT_GATE(CLK_UART1_ROOT, "uart1_root_clk", "uart1", 0x4490),
+	IMX_ROOT_GATE(CLK_UART2_ROOT, "uart2_root_clk", "uart2", 0x44a0),
+	IMX_ROOT_GATE(CLK_UART3_ROOT, "uart3_root_clk", "uart3", 0x44b0),
+	IMX_ROOT_GATE(CLK_UART4_ROOT, "uart4_root_clk", "uart4", 0x44c0),
+
+	IMX_COMPOSITE(CLK_USDHC1, "usdhc1", usdhc_p, 0xac00, IMX_COMPOSITE_ROUND_DOWN),
+	IMX_COMPOSITE(CLK_USDHC2, "usdhc2", usdhc_p, 0xac80, IMX_COMPOSITE_ROUND_DOWN),
+
+	IMX_ROOT_GATE(CLK_USDHC1_ROOT, "usdhc1_root_clk", "usdhc1", 0x4510),
+	IMX_ROOT_GATE(CLK_USDHC2_ROOT, "usdhc2_root_clk", "usdhc2", 0x4520),
+
+	IMX_COMPOSITE(CLK_ENET_AXI, "enet_axi", enet_axi_p, 0x8800, 0),
+	IMX_COMPOSITE(CLK_ENET_REF, "enet_ref", enet_ref_p, 0xa980, 0),
+	IMX_COMPOSITE(CLK_ENET_TIMER, "enet_timer", enet_timer_p, 0xaa00, 0),
+	IMX_COMPOSITE(CLK_ENET_PHY_REF, "enet_phy_ref", enet_phy_ref_p, 0xaa80, 0),
+
+	IMX_ROOT_GATE(CLK_ENET1_ROOT, "enet1_root_clk", "enet_axi", 0x40a0),
+
+	IMX_COMPOSITE(CLK_USB_BUS, "usb_bus", usb_bus_p, 0x8b80, 0),
+	IMX_COMPOSITE(CLK_USB_CORE_REF, "usb_core_ref", usb_core_phy_p, 0xb100, 0),
+	IMX_COMPOSITE(CLK_USB_PHY_REF, "usb_phy_ref", usb_core_phy_p, 0xb180, 0),
+
+	IMX_ROOT_GATE(CLK_USB1_CTRL_ROOT, "usb1_ctrl_root_clk", "usb_bus", 0x44d0),
+	IMX_ROOT_GATE(CLK_USB2_CTRL_ROOT, "usb2_ctrl_root_clk", "usb_bus", 0x44e0),
+	IMX_ROOT_GATE(CLK_USB1_PHY_ROOT, "usb1_phy_root_clk", "usb_phy_ref", 0x44f0),
+	IMX_ROOT_GATE(CLK_USB2_PHY_ROOT, "usb2_phy_root_clk", "usb_phy_ref", 0x4500),
+};
+
+static int
+imx8mq_ccm_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
+imx8mq_ccm_attach(device_t parent, device_t self, void *aux)
+{
+	struct imx_ccm_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 = imx8mq_ccm_clks;
+	sc->sc_nclks = __arraycount(imx8mq_ccm_clks);
+
+	if (imx_ccm_attach(sc) != 0)
+		return;
+
+	aprint_naive("\n");
+	aprint_normal(": Clock Control Module\n");
+
+	imx_ccm_print(sc);
+}
Index: src/sys/arch/arm/imx/fdt/imx8mq_ccm.h
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx8mq_ccm.h:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx8mq_ccm.h	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,321 @@
+/* $NetBSD: imx8mq_ccm.h,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _IMX8MQ_CCM_H
+#define _IMX8MQ_CCM_H
+
+/*
+ * Clocks
+ */
+
+#define	CLK_DUMMY 0
+#define	CLK_32K 1
+#define	CLK_25M 2
+#define	CLK_27M 3
+#define	CLK_EXT1 4
+#define	CLK_EXT2 5
+#define	CLK_EXT3 6
+#define	CLK_EXT4 7
+#define	ARM_PLL_REF_SEL 8
+#define	ARM_PLL_REF_DIV 9
+#define	ARM_PLL 10
+#define	ARM_PLL_BYPASS 11
+#define	ARM_PLL_OUT 12
+#define	GPU_PLL_REF_SEL 13
+#define	GPU_PLL_REF_DIV 14
+#define	GPU_PLL 15
+#define	GPU_PLL_BYPASS 16
+#define	GPU_PLL_OUT 17
+#define	VPU_PLL_REF_SEL 18
+#define	VPU_PLL_REF_DIV 19
+#define	VPU_PLL 20
+#define	VPU_PLL_BYPASS 21
+#define	VPU_PLL_OUT 22
+#define	AUDIO_PLL1_REF_SEL 23
+#define	AUDIO_PLL1_REF_DIV 24
+#define	AUDIO_PLL1 25
+#define	AUDIO_PLL1_BYPASS 26
+#define	AUDIO_PLL1_OUT 27
+#define	AUDIO_PLL2_REF_SEL 28
+#define	AUDIO_PLL2_REF_DIV 29
+#define	AUDIO_PLL2 30
+#define	AUDIO_PLL2_BYPASS 31
+#define	AUDIO_PLL2_OUT 32
+#define	VIDEO_PLL1_REF_SEL 33
+#define	VIDEO_PLL1_REF_DIV 34
+#define	VIDEO_PLL1 35
+#define	VIDEO_PLL1_BYPASS 36
+#define	VIDEO_PLL1_OUT 37
+#define	SYS1_PLL1_REF_SEL 38
+#define	SYS1_PLL1_REF_DIV 39
+#define	SYS1_PLL1 40
+#define	SYS1_PLL1_OUT 41
+#define	SYS1_PLL1_OUT_DIV 42
+#define	SYS1_PLL2 43
+#define	SYS1_PLL2_DIV 44
+#define	SYS1_PLL2_OUT 45
+#define	SYS2_PLL1_REF_SEL 46
+#define	SYS2_PLL1_REF_DIV 47
+#define	SYS2_PLL1 48
+#define	SYS2_PLL1_OUT 49
+#define	SYS2_PLL1_OUT_DIV 50
+#define	SYS2_PLL2 51
+#define	SYS2_PLL2_DIV 52
+#define	SYS2_PLL2_OUT 53
+#define	SYS3_PLL1_REF_SEL 54
+#define	SYS3_PLL1_REF_DIV 55
+#define	SYS3_PLL1 56
+#define	SYS3_PLL1_OUT 57
+#define	SYS3_PLL1_OUT_DIV 58
+#define	SYS3_PLL2 59
+#define	SYS3_PLL2_DIV 60
+#define	SYS3_PLL2_OUT 61
+#define	DRAM_PLL1_REF_SEL 62
+#define	DRAM_PLL1_REF_DIV 63
+#define	DRAM_PLL1 64
+#define	DRAM_PLL1_OUT 65
+#define	DRAM_PLL1_OUT_DIV 66
+#define	DRAM_PLL2 67
+#define	DRAM_PLL2_DIV 68
+#define	DRAM_PLL2_OUT 69
+#define	SYS1_PLL_40M 70
+#define	SYS1_PLL_80M 71
+#define	SYS1_PLL_100M 72
+#define	SYS1_PLL_133M 73
+#define	SYS1_PLL_160M 74
+#define	SYS1_PLL_200M 75
+#define	SYS1_PLL_266M 76
+#define	SYS1_PLL_400M 77
+#define	SYS1_PLL_800M 78
+#define	SYS2_PLL_50M 79
+#define	SYS2_PLL_100M 80
+#define	SYS2_PLL_125M 81
+#define	SYS2_PLL_166M 82
+#define	SYS2_PLL_200M 83
+#define	SYS2_PLL_250M 84
+#define	SYS2_PLL_333M 85
+#define	SYS2_PLL_500M 86
+#define	SYS2_PLL_1000M 87
+#define	CLK_A53_SRC 88
+#define	CLK_A53_CG 89
+#define	CLK_A53_DIV 90
+#define	CLK_M4_SRC 91
+#define	CLK_M4_CG 92
+#define	CLK_M4_DIV 93
+#define	CLK_VPU_SRC 94
+#define	CLK_VPU_CG 95
+#define	CLK_VPU_DIV 96
+#define	CLK_GPU_CORE_SRC 97
+#define	CLK_GPU_CORE_CG 98
+#define	CLK_GPU_CORE_DIV 99
+#define	CLK_GPU_SHADER_SRC 100
+#define	CLK_GPU_SHADER_CG 101
+#define	CLK_GPU_SHADER_DIV 102
+#define	CLK_MAIN_AXI 103
+#define	CLK_ENET_AXI 104
+#define	CLK_NAND_USDHC_BUS 105
+#define	CLK_VPU_BUS 106
+#define	CLK_DISP_AXI 107
+#define	CLK_DISP_APB 108
+#define	CLK_DISP_RTRM 109
+#define	CLK_USB_BUS 110
+#define	CLK_GPU_AXI 111
+#define	CLK_GPU_AHB 112
+#define	CLK_NOC 113
+#define	CLK_NOC_APB 115
+#define	CLK_AHB 116
+#define	CLK_AUDIO_AHB 117
+#define	CLK_DRAM_ALT 118
+#define	CLK_DRAM_APB 119
+#define	CLK_VPU_G1 120
+#define	CLK_VPU_G2 121
+#define	CLK_DISP_DTRC 122
+#define	CLK_DISP_DC8000 123
+#define	CLK_PCIE1_CTRL 124
+#define	CLK_PCIE1_PHY 125
+#define	CLK_PCIE1_AUX 126
+#define	CLK_DC_PIXEL 127
+#define	CLK_LCDIF_PIXEL 128
+#define	CLK_SAI1 129
+#define	CLK_SAI2 130
+#define	CLK_SAI3 131
+#define	CLK_SAI4 132
+#define	CLK_SAI5 133
+#define	CLK_SAI6 134
+#define	CLK_SPDIF1 135
+#define	CLK_SPDIF2 136
+#define	CLK_ENET_REF 137
+#define	CLK_ENET_TIMER 138
+#define	CLK_ENET_PHY_REF 139
+#define	CLK_NAND 140
+#define	CLK_QSPI 141
+#define	CLK_USDHC1 142
+#define	CLK_USDHC2 143
+#define	CLK_I2C1 144
+#define	CLK_I2C2 145
+#define	CLK_I2C3 146
+#define	CLK_I2C4 147
+#define	CLK_UART1 148
+#define	CLK_UART2 149
+#define	CLK_UART3 150
+#define	CLK_UART4 151
+#define	CLK_USB_CORE_REF 152
+#define	CLK_USB_PHY_REF 153
+#define	CLK_ECSPI1 154
+#define	CLK_ECSPI2 155
+#define	CLK_PWM1 156
+#define	CLK_PWM2 157
+#define	CLK_PWM3 158
+#define	CLK_PWM4 159
+#define	CLK_GPT1 160
+#define	CLK_WDOG 161
+#define	CLK_WRCLK 162
+#define	CLK_DSI_CORE 163
+#define	CLK_DSI_PHY_REF 164
+#define	CLK_DSI_DBI 165
+#define	CLK_DSI_ESC 166
+#define	CLK_CSI1_CORE 167
+#define	CLK_CSI1_PHY_REF 168
+#define	CLK_CSI1_ESC 169
+#define	CLK_CSI2_CORE 170
+#define	CLK_CSI2_PHY_REF 171
+#define	CLK_CSI2_ESC 172
+#define	CLK_PCIE2_CTRL 173
+#define	CLK_PCIE2_PHY 174
+#define	CLK_PCIE2_AUX 175
+#define	CLK_ECSPI3 176
+#define	CLK_A53_ROOT 177
+#define	CLK_DRAM_ROOT 178
+#define	CLK_ECSPI1_ROOT 179
+#define	CLK_ECSPI2_ROOT 180
+#define	CLK_ECSPI3_ROOT 181
+#define	CLK_ENET1_ROOT 182
+#define	CLK_GPT1_ROOT 183
+#define	CLK_I2C1_ROOT 184
+#define	CLK_I2C2_ROOT 185
+#define	CLK_I2C3_ROOT 186
+#define	CLK_I2C4_ROOT 187
+#define	CLK_M4_ROOT 188
+#define	CLK_PCIE1_ROOT 189
+#define	CLK_PCIE2_ROOT 190
+#define	CLK_PWM1_ROOT 191
+#define	CLK_PWM2_ROOT 192
+#define	CLK_PWM3_ROOT 193
+#define	CLK_PWM4_ROOT 194
+#define	CLK_QSPI_ROOT 195
+#define	CLK_SAI1_ROOT 196
+#define	CLK_SAI2_ROOT 197
+#define	CLK_SAI3_ROOT 198
+#define	CLK_SAI4_ROOT 199
+#define	CLK_SAI5_ROOT 200
+#define	CLK_SAI6_ROOT 201
+#define	CLK_UART1_ROOT 202
+#define	CLK_UART2_ROOT 203
+#define	CLK_UART3_ROOT 204
+#define	CLK_UART4_ROOT 205
+#define	CLK_USB1_CTRL_ROOT 206
+#define	CLK_USB2_CTRL_ROOT 207
+#define	CLK_USB1_PHY_ROOT 208
+#define	CLK_USB2_PHY_ROOT 209
+#define	CLK_USDHC1_ROOT 210
+#define	CLK_USDHC2_ROOT 211
+#define	CLK_WDOG1_ROOT 212
+#define	CLK_WDOG2_ROOT 213
+#define	CLK_WDOG3_ROOT 214
+#define	CLK_GPU_ROOT 215
+#define	CLK_HEVC_ROOT 216
+#define	CLK_AVC_ROOT 217
+#define	CLK_VP9_ROOT 218
+#define	CLK_HEVC_INTER_ROOT 219
+#define	CLK_DISP_ROOT 220
+#define	CLK_HDMI_ROOT 221
+#define	CLK_HDMI_PHY_ROOT 222
+#define	CLK_VPU_DEC_ROOT 223
+#define	CLK_CSI1_ROOT 224
+#define	CLK_CSI2_ROOT 225
+#define	CLK_RAWNAND_ROOT 226
+#define	CLK_SDMA1_ROOT 227
+#define	CLK_SDMA2_ROOT 228
+#define	CLK_VPU_G1_ROOT 229
+#define	CLK_VPU_G2_ROOT 230
+#define	SYS1_PLL_OUT 231
+#define	SYS2_PLL_OUT 232
+#define	SYS3_PLL_OUT 233
+#define	DRAM_PLL_OUT 234
+#define	GPT_3M_CLK 235
+#define	CLK_IPG_ROOT 236
+#define	CLK_IPG_AUDIO_ROOT 237
+#define	CLK_SAI1_IPG 238
+#define	CLK_SAI2_IPG 239
+#define	CLK_SAI3_IPG 240
+#define	CLK_SAI4_IPG 241
+#define	CLK_SAI5_IPG 242
+#define	CLK_SAI6_IPG 243
+#define	CLK_DSI_AHB 244
+#define	CLK_DSI_IPG_DIV 245
+#define	CLK_TMU_ROOT 246
+#define	CLK_DISP_AXI_ROOT 247
+#define	CLK_DISP_APB_ROOT 248
+#define	CLK_DISP_RTRM_ROOT 249
+#define	CLK_OCOTP_ROOT 250
+#define	CLK_DRAM_ALT_ROOT 251
+#define	CLK_DRAM_CORE 252
+#define	CLK_MU_ROOT 253
+#define	VIDEO2_PLL_OUT 254
+#define	CLK_CLKO2 255
+#define	CLK_NAND_USDHC_BUS_RAWNAND_CLK 256
+#define	CLK_CLKO1 257
+#define	CLK_ARM 258
+#define	CLK_GPIO1_ROOT 259
+#define	CLK_GPIO2_ROOT 260
+#define	CLK_GPIO3_ROOT 261
+#define	CLK_GPIO4_ROOT 262
+#define	CLK_GPIO5_ROOT 263
+#define	CLK_SNVS_ROOT 264
+#define	CLK_GIC 265
+#define	VIDEO2_PLL1_REF_SEL 266
+#define	SYS1_PLL_40M_CG 267
+#define	SYS1_PLL_80M_CG 268
+#define	SYS1_PLL_100M_CG 269
+#define	SYS1_PLL_133M_CG 270
+#define	SYS1_PLL_160M_CG 271
+#define	SYS1_PLL_200M_CG 272
+#define	SYS1_PLL_266M_CG 273
+#define	SYS1_PLL_400M_CG 274
+#define	SYS1_PLL_800M_CG 275
+#define	SYS2_PLL_50M_CG 276
+#define	SYS2_PLL_100M_CG 277
+#define	SYS2_PLL_125M_CG 278
+#define	SYS2_PLL_166M_CG 279
+#define	SYS2_PLL_200M_CG 280
+#define	SYS2_PLL_250M_CG 281
+#define	SYS2_PLL_333M_CG 282
+#define	SYS2_PLL_500M_CG 283
+#define	SYS2_PLL_1000M_CG 284
+
+#endif /* !_IMX8MQ_CCM_H */
Index: src/sys/arch/arm/imx/fdt/imx8mq_usbphy.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx8mq_usbphy.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx8mq_usbphy.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,184 @@
+/* $NetBSD: imx8mq_usbphy.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(0, "$NetBSD: imx8mq_usbphy.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#define	PHY_CTL0_ADDR		0x00
+#define	 REF_SSP_EN		__BIT(2)
+
+#define	PHY_CTL1_ADDR		0x04
+#define	 PHY_VDATDATENB0	__BIT(20)
+#define	 PHY_VDATSRCENB0	__BIT(19)
+#define	 PHY_ATERESET		__BIT(3)
+#define	 PHY_COMMONONN		__BIT(1)
+#define	 PHY_RESET		__BIT(0)
+
+#define	PHY_CTL2_ADDR		0x08
+#define	 PHY_TXENABLEN0		__BIT(8)
+
+static int imx8mq_usbphy_match(device_t, cfdata_t, void *);
+static void imx8mq_usbphy_attach(device_t, device_t, void *);
+
+static const struct of_compat_data compat_data[] = {
+	{ "fsl,imx8mq-usb-phy",			0 },
+	{ NULL }
+};
+
+struct imx8mq_usbphy_softc {
+	device_t		sc_dev;
+	bus_space_tag_t		sc_bst;
+	bus_space_handle_t	sc_bsh;
+	int			sc_phandle;
+};
+
+#define	PHY_READ(sc, reg)				\
+	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define	PHY_WRITE(sc, reg, val)			\
+	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+CFATTACH_DECL_NEW(imx8mqusbphy, sizeof(struct imx8mq_usbphy_softc),
+	imx8mq_usbphy_match, imx8mq_usbphy_attach, NULL, NULL);
+
+static void *
+imx8mq_usbphy_acquire(device_t dev, const void *data, size_t len)
+{
+	if (len != 0)
+		return NULL;
+
+	return (void *)(uintptr_t)1;
+}
+
+static void
+imx8mq_usbphy_release(device_t dev, void *priv)
+{
+}
+
+static int
+imx8mq_usbphy_enable(device_t dev, void *priv, bool enable)
+{
+	struct imx8mq_usbphy_softc * const sc = device_private(dev);
+	struct fdtbus_regulator *reg;
+	uint32_t val;
+	int error;
+
+	if (enable) {
+		if (of_hasprop(sc->sc_phandle, "vbus-supply")) {
+			reg = fdtbus_regulator_acquire(sc->sc_phandle, "vbus-supply");
+			if (reg != NULL) {
+				error = fdtbus_regulator_enable(reg);
+				if (error != 0)
+					device_printf(dev, "WARNING: couldn't enable vbus-supply: %d\n", error);
+			} else {
+				device_printf(dev, "WARNING: couldn't acquire vbus-supply\n");
+			}
+		}
+
+		val = PHY_READ(sc, PHY_CTL1_ADDR);
+		val &= ~PHY_VDATDATENB0;
+		val &= ~PHY_VDATSRCENB0;
+		val &= ~PHY_COMMONONN;
+		val |= PHY_RESET;
+		val |= PHY_ATERESET;
+		PHY_WRITE(sc, PHY_CTL1_ADDR, val);
+
+		val = PHY_READ(sc, PHY_CTL0_ADDR);
+		val |= REF_SSP_EN;
+		PHY_WRITE(sc, PHY_CTL0_ADDR, val);
+
+		val = PHY_READ(sc, PHY_CTL2_ADDR);
+		val |= PHY_TXENABLEN0;
+		PHY_WRITE(sc, PHY_CTL2_ADDR, val);
+
+		val = PHY_READ(sc, PHY_CTL1_ADDR);
+		val &= ~PHY_RESET;
+		val &= ~PHY_ATERESET;
+		PHY_WRITE(sc, PHY_CTL1_ADDR, val);
+	}
+
+	return 0;
+}
+
+const struct fdtbus_phy_controller_func imx8mq_usbphy_funcs = {
+	.acquire = imx8mq_usbphy_acquire,
+	.release = imx8mq_usbphy_release,
+	.enable = imx8mq_usbphy_enable,
+};
+
+static int
+imx8mq_usbphy_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
+imx8mq_usbphy_attach(device_t parent, device_t self, void *aux)
+{
+	struct imx8mq_usbphy_softc * const sc = device_private(self);
+	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+	bus_addr_t addr;
+	bus_size_t size;
+
+	sc->sc_dev = self;
+	sc->sc_bst = faa->faa_bst;
+	sc->sc_phandle = phandle;
+
+	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+		aprint_error(": couldn't get registers\n");
+		return;
+	}
+	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+		aprint_error(": couldn't map registers\n");
+		return;
+	}
+
+	/* Enable clocks */
+	fdtbus_clock_assign(phandle);
+	if (fdtbus_clock_enable(phandle, "phy", true) != 0) {
+		aprint_error(": couldn't enable phy clock\n");
+		return;
+	}
+
+	aprint_naive("\n");
+	aprint_normal(": USB PHY\n");
+
+	fdtbus_register_phy_controller(self, phandle, &imx8mq_usbphy_funcs);
+}
Index: src/sys/arch/arm/imx/fdt/imx_ccm.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,306 @@
+/* $NetBSD: imx_ccm.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx_ccm.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/imx/fdt/imx_ccm.h>
+
+static struct clk *
+imx_ccm_clock_decode(device_t dev, int cc_phandle, const void *data, size_t len)
+{
+	struct imx_ccm_softc * const sc = device_private(dev);
+	struct imx_ccm_clk *clk;
+
+	if (len != 4)
+		return NULL;
+
+	const u_int clock_id = be32dec(data);
+
+	for (int i = 0; i < sc->sc_nclks; i++) {
+		clk = &sc->sc_clks[i];
+		if (clk->id == clock_id)
+			return &clk->base;
+	}
+
+	return NULL;
+}
+
+static const struct fdtbus_clock_controller_func imx_ccm_fdtclock_funcs = {
+	.decode = imx_ccm_clock_decode,
+};
+
+static struct clk *
+imx_ccm_clock_get(void *priv, const char *name)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk;
+
+	clk = imx_ccm_clock_find(sc, name);
+	if (clk == NULL)
+		return NULL;
+
+	return &clk->base;
+}
+
+static void
+imx_ccm_clock_put(void *priv, struct clk *clk)
+{
+}
+
+static u_int
+imx_ccm_clock_get_rate(void *priv, struct clk *clkp)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+	struct clk *clkp_parent;
+
+	if (clk->get_rate)
+		return clk->get_rate(sc, clk);
+
+	clkp_parent = clk_get_parent(clkp);
+	if (clkp_parent == NULL) {
+		aprint_debug("%s: no parent for %s\n", __func__, clk->base.name);
+		return 0;
+	}
+
+	return clk_get_rate(clkp_parent);
+}
+
+static int
+imx_ccm_clock_set_rate(void *priv, struct clk *clkp, u_int rate)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+	struct clk *clkp_parent;
+
+	if (clkp->flags & CLK_SET_RATE_PARENT) {
+		clkp_parent = clk_get_parent(clkp);
+		if (clkp_parent == NULL) {
+			aprint_error("%s: no parent for %s\n", __func__, clk->base.name);
+			return ENXIO;
+		}
+		return clk_set_rate(clkp_parent, rate);
+	}
+
+	if (clk->set_rate)
+		return clk->set_rate(sc, clk, rate);
+
+	return ENXIO;
+}
+
+static u_int
+imx_ccm_clock_round_rate(void *priv, struct clk *clkp, u_int rate)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+	struct clk *clkp_parent;
+
+	if (clkp->flags & CLK_SET_RATE_PARENT) {
+		clkp_parent = clk_get_parent(clkp);
+		if (clkp_parent == NULL) {
+			aprint_error("%s: no parent for %s\n", __func__, clk->base.name);
+			return 0;
+		}
+		return clk_round_rate(clkp_parent, rate);
+	}
+
+	if (clk->round_rate)
+		return clk->round_rate(sc, clk, rate);
+
+	return 0;
+}
+
+static int
+imx_ccm_clock_enable(void *priv, struct clk *clkp)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+	struct clk *clkp_parent;
+	int error = 0;
+
+	clkp_parent = clk_get_parent(clkp);
+	if (clkp_parent != NULL) {
+		error = clk_enable(clkp_parent);
+		if (error != 0)
+			return error;
+	}
+
+	if (clk->enable)
+		error = clk->enable(sc, clk, 1);
+
+	return error;
+}
+
+static int
+imx_ccm_clock_disable(void *priv, struct clk *clkp)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+	int error = EINVAL;
+
+	if (clk->enable)
+		error = clk->enable(sc, clk, 0);
+
+	return error;
+}
+
+static int
+imx_ccm_clock_set_parent(void *priv, struct clk *clkp,
+    struct clk *clkp_parent)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+
+	if (clk->set_parent == NULL)
+		return EINVAL;
+
+	return clk->set_parent(sc, clk, clkp_parent->name);
+}
+
+static struct clk *
+imx_ccm_clock_get_parent(void *priv, struct clk *clkp)
+{
+	struct imx_ccm_softc * const sc = priv;
+	struct imx_ccm_clk *clk = (struct imx_ccm_clk *)clkp;
+	struct imx_ccm_clk *clk_parent;
+	const char *parent;
+
+	if (clk->get_parent == NULL)
+		return NULL;
+
+	parent = clk->get_parent(sc, clk);
+	if (parent == NULL)
+		return NULL;
+
+	clk_parent = imx_ccm_clock_find(sc, parent);
+	if (clk_parent != NULL)
+		return &clk_parent->base;
+
+	/* No parent in this domain, try FDT */
+	return fdtbus_clock_byname(parent);
+}
+
+static const struct clk_funcs imx_ccm_clock_funcs = {
+	.get = imx_ccm_clock_get,
+	.put = imx_ccm_clock_put,
+	.get_rate = imx_ccm_clock_get_rate,
+	.set_rate = imx_ccm_clock_set_rate,
+	.round_rate = imx_ccm_clock_round_rate,
+	.enable = imx_ccm_clock_enable,
+	.disable = imx_ccm_clock_disable,
+	.set_parent = imx_ccm_clock_set_parent,
+	.get_parent = imx_ccm_clock_get_parent,
+};
+
+struct imx_ccm_clk *
+imx_ccm_clock_find(struct imx_ccm_softc *sc, const char *name)
+{
+	for (int i = 0; i < sc->sc_nclks; i++) {
+		if (sc->sc_clks[i].base.name == NULL)
+			continue;
+		if (strcmp(sc->sc_clks[i].base.name, name) == 0)
+			return &sc->sc_clks[i];
+	}
+
+	return NULL;
+}
+
+int
+imx_ccm_attach(struct imx_ccm_softc *sc)
+{
+	bus_addr_t addr;
+	bus_size_t size;
+	int i;
+
+	if (fdtbus_get_reg(sc->sc_phandle, 0, &addr, &size) != 0) {
+		aprint_error(": couldn't get registers\n");
+		return ENXIO;
+	}
+	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+		aprint_error(": couldn't map registers\n");
+		return ENXIO;
+	}
+
+	sc->sc_clkdom.name = device_xname(sc->sc_dev);
+	sc->sc_clkdom.funcs = &imx_ccm_clock_funcs;
+	sc->sc_clkdom.priv = sc;
+	for (i = 0; i < sc->sc_nclks; i++) {
+		sc->sc_clks[i].base.domain = &sc->sc_clkdom;
+		clk_attach(&sc->sc_clks[i].base);
+	}
+
+	fdtbus_register_clock_controller(sc->sc_dev, sc->sc_phandle,
+	    &imx_ccm_fdtclock_funcs);
+
+	return 0;
+}
+
+void
+imx_ccm_print(struct imx_ccm_softc *sc)
+{
+	struct imx_ccm_clk *clk;
+	struct clk *clkp_parent;
+	const char *type;
+	int i;
+
+	for (i = 0; i < sc->sc_nclks; i++) {
+		clk = &sc->sc_clks[i];
+		if (clk->type == IMX_CCM_UNKNOWN)
+			continue;
+
+		clkp_parent = clk_get_parent(&clk->base);
+
+		switch (clk->type) {
+		case IMX_CCM_EXTCLK:		type = "extclk"; break;
+		case IMX_CCM_GATE:		type = "gate"; break;
+		case IMX_CCM_COMPOSITE:		type = "comp"; break;
+		case IMX_CCM_FIXED:		type = "fixed"; break;
+		case IMX_CCM_FIXED_FACTOR:	type = "fixed-factor"; break;
+		default:			type = "???"; break;
+		}
+
+        	aprint_debug_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));
+	}
+}
Index: src/sys/arch/arm/imx/fdt/imx_ccm.h
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm.h:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm.h	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,234 @@
+/* $NetBSD: imx_ccm.h,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_IMX_CCM_H
+#define _ARM_IMX_CCM_H
+
+#include <dev/clk/clk_backend.h>
+#include <dev/fdt/syscon.h>
+
+struct imx_ccm_softc;
+struct imx_ccm_clk;
+
+/*
+ * Clocks
+ */
+
+enum imx_ccm_clktype {
+	IMX_CCM_UNKNOWN,
+	IMX_CCM_EXTCLK,
+	IMX_CCM_GATE,
+	IMX_CCM_COMPOSITE,
+	IMX_CCM_FIXED,
+	IMX_CCM_FIXED_FACTOR,
+};
+
+/* External clocks */
+
+int	imx_ccm_extclk_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int);
+u_int	imx_ccm_extclk_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
+int	imx_ccm_extclk_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
+const char *imx_ccm_extclk_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
+
+#define	IMX_EXTCLK(_id, _name)					\
+	{							\
+		.id = (_id),					\
+		.type = IMX_CCM_EXTCLK,				\
+		.base.name = (_name),				\
+		.base.flags = 0,				\
+		.u.extclk = (_name),				\
+		.enable = imx_ccm_extclk_enable,		\
+		.get_rate = imx_ccm_extclk_get_rate,		\
+		.set_rate = imx_ccm_extclk_set_rate,		\
+		.get_parent = imx_ccm_extclk_get_parent,	\
+	}
+
+/* Gate clocks */
+
+struct imx_ccm_gate {
+	bus_size_t	reg;
+	uint32_t	mask;
+	const char	*parent;
+};
+
+int	imx_ccm_gate_enable(struct imx_ccm_softc *,
+			   struct imx_ccm_clk *, int);
+const char *imx_ccm_gate_get_parent(struct imx_ccm_softc *,
+				   struct imx_ccm_clk *);
+
+#define	IMX_GATE(_id, _name, _pname, _reg, _mask)		\
+	{							\
+		.id = (_id),					\
+		.type = IMX_CCM_GATE,				\
+		.base.name = (_name),				\
+		.base.flags = CLK_SET_RATE_PARENT,		\
+		.u.gate.parent = (_pname),			\
+		.u.gate.reg = (_reg),				\
+		.u.gate.mask = (_mask),				\
+		.enable = imx_ccm_gate_enable,			\
+		.get_parent = imx_ccm_gate_get_parent,		\
+	}
+#define	IMX_ROOT_GATE(_id, _name, _pname, _reg)			\
+	IMX_GATE(_id, _name, _pname, _reg, __BITS(1,0))
+
+/* Composite clocks */
+
+struct imx_ccm_composite {
+	bus_size_t	reg;
+	const char	**parents;
+	u_int		nparents;
+	u_int		flags;
+#define	IMX_COMPOSITE_ROUND_DOWN	0x01
+#define	IMX_COMPOSITE_SET_RATE_PARENT	0x02
+};
+
+int	imx_ccm_composite_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int);
+u_int	imx_ccm_composite_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
+int	imx_ccm_composite_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
+const char *imx_ccm_composite_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
+int	imx_ccm_composite_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *);
+
+#define	IMX_COMPOSITE(_id, _name, _parents, _reg, _flags)	\
+	{							\
+		.id = (_id),					\
+		.type = IMX_CCM_COMPOSITE,			\
+		.base.name = (_name),				\
+		.base.flags = 0,				\
+		.u.composite.parents = (_parents),		\
+		.u.composite.nparents = __arraycount(_parents),	\
+		.u.composite.reg = (_reg),			\
+		.u.composite.flags = (_flags),			\
+		.enable = imx_ccm_composite_enable,		\
+		.get_rate = imx_ccm_composite_get_rate,		\
+		.set_rate = imx_ccm_composite_set_rate,		\
+		.set_parent = imx_ccm_composite_set_parent,	\
+		.get_parent = imx_ccm_composite_get_parent,	\
+	}
+
+/* Fixed clocks */
+
+struct imx_ccm_fixed {
+	u_int		rate;
+};
+
+u_int	imx_ccm_fixed_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
+
+#define	IMX_FIXED(_id, _name, _rate)				\
+	{							\
+		.id = (_id),					\
+		.type = IMX_CCM_FIXED,				\
+		.base.name = (_name),				\
+		.base.flags = 0,				\
+		.u.fixed.rate = (_rate),			\
+		.get_rate = imx_ccm_fixed_get_rate,		\
+	}
+
+/* Fixed factor clocks */
+
+struct imx_ccm_fixed_factor {
+	const char	*parent;
+	u_int		mult;
+	u_int		div;
+};
+
+u_int	imx_ccm_fixed_factor_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
+int	imx_ccm_fixed_factor_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
+const char *imx_ccm_fixed_factor_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
+
+#define	IMX_FIXED_FACTOR(_id, _name, _parent, _mult, _div)	\
+	{							\
+		.id = (_id),					\
+		.type = IMX_CCM_FIXED_FACTOR,			\
+		.base.name = (_name),				\
+		.base.flags = 0,				\
+		.u.fixed_factor.parent = (_parent),		\
+		.u.fixed_factor.mult = (_mult),			\
+		.u.fixed_factor.div = (_div),			\
+		.get_rate = imx_ccm_fixed_factor_get_rate,	\
+		.set_rate = imx_ccm_fixed_factor_set_rate,	\
+		.get_parent = imx_ccm_fixed_factor_get_parent,	\
+	}
+
+/*
+ * IMX clock definition
+ */
+
+struct imx_ccm_clk {
+	struct clk	base;
+	u_int		id;
+	enum imx_ccm_clktype type;
+	union {
+		struct imx_ccm_gate gate;
+		struct imx_ccm_composite composite;
+		struct imx_ccm_fixed fixed;
+		struct imx_ccm_fixed_factor fixed_factor;
+		const char *extclk;
+	} u;
+
+	int		(*enable)(struct imx_ccm_softc *,
+				  struct imx_ccm_clk *, int);
+	u_int		(*get_rate)(struct imx_ccm_softc *,
+				    struct imx_ccm_clk *);
+	int		(*set_rate)(struct imx_ccm_softc *,
+				    struct imx_ccm_clk *, u_int);
+	u_int		(*round_rate)(struct imx_ccm_softc *,
+				    struct imx_ccm_clk *, u_int);
+	const char *	(*get_parent)(struct imx_ccm_softc *,
+				      struct imx_ccm_clk *);
+	int		(*set_parent)(struct imx_ccm_softc *,
+				      struct imx_ccm_clk *,
+				      const char *);
+};
+
+/*
+ * Driver state
+ */
+
+struct imx_ccm_softc {
+	device_t		sc_dev;
+	int			sc_phandle;
+	bus_space_tag_t		sc_bst;
+	bus_space_handle_t	sc_bsh;
+
+	struct clk_domain	sc_clkdom;
+
+	struct imx_ccm_clk	*sc_clks;
+	u_int			sc_nclks;
+};
+
+int	imx_ccm_attach(struct imx_ccm_softc *);
+struct imx_ccm_clk *imx_ccm_clock_find(struct imx_ccm_softc *,
+				     const char *);
+void	imx_ccm_print(struct imx_ccm_softc *);
+
+#define CCM_READ(sc, reg)	\
+	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define CCM_WRITE(sc, reg, val)	\
+	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+#endif /* _ARM_IMX_CCM_H */
Index: src/sys/arch/arm/imx/fdt/imx_ccm_composite.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm_composite.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm_composite.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,201 @@
+/* $NetBSD: imx_ccm_composite.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx_ccm_composite.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/imx/fdt/imx_ccm.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#define	CCM_TARGET_ROOT		0x00
+#define	 TARGET_ROOT_ENABLE	__BIT(28)
+#define	 TARGET_ROOT_MUX	__BITS(26,24)
+#define	 TARGET_ROOT_PRE_PODF	__BITS(18,16)
+#define	 TARGET_ROOT_POST_PODF	__BITS(5,0)
+
+int
+imx_ccm_composite_enable(struct imx_ccm_softc *sc, struct imx_ccm_clk *clk,
+    int enable)
+{
+	struct imx_ccm_composite *composite = &clk->u.composite;
+	uint32_t val;
+
+	KASSERT(clk->type == IMX_CCM_COMPOSITE);
+
+	val = CCM_READ(sc, composite->reg + CCM_TARGET_ROOT);
+	if (enable)
+		val |= TARGET_ROOT_ENABLE;
+	else
+		val &= ~TARGET_ROOT_ENABLE;
+	CCM_WRITE(sc, composite->reg + CCM_TARGET_ROOT, val);
+
+	return 0;
+}
+
+u_int
+imx_ccm_composite_get_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct imx_ccm_composite *composite = &clk->u.composite;
+	struct clk *clkp, *clkp_parent;
+
+	KASSERT(clk->type == IMX_CCM_COMPOSITE);
+
+	clkp = &clk->base;
+	clkp_parent = clk_get_parent(clkp);
+	if (clkp_parent == NULL)
+		return 0;
+
+	const u_int prate = clk_get_rate(clkp_parent);
+	if (prate == 0)
+		return 0;
+
+	const uint32_t val = CCM_READ(sc, composite->reg + CCM_TARGET_ROOT);
+	const u_int pre_div = __SHIFTOUT(val, TARGET_ROOT_PRE_PODF) + 1;
+	const u_int post_div = __SHIFTOUT(val, TARGET_ROOT_POST_PODF) + 1;
+
+	return prate / pre_div / post_div;
+}
+
+int
+imx_ccm_composite_set_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk, u_int rate)
+{
+	struct imx_ccm_composite *composite = &clk->u.composite;
+	u_int best_prediv, best_postdiv, best_diff;
+	struct imx_ccm_clk *rclk_parent;
+	struct clk *clk_parent;
+	uint32_t val;
+
+	KASSERT(clk->type == IMX_CCM_COMPOSITE);
+
+	if (composite->flags & IMX_COMPOSITE_SET_RATE_PARENT) {
+		clk_parent = clk_get_parent(&clk->base);
+		if (clk_parent == NULL)
+			return ENXIO;
+		return clk_set_rate(clk_parent, rate);
+	}
+
+	best_prediv = 0;
+	best_postdiv = 0;
+	best_diff = INT_MAX;
+
+	val = CCM_READ(sc, composite->reg + CCM_TARGET_ROOT);
+	const u_int mux = __SHIFTOUT(val, TARGET_ROOT_MUX);
+
+	if (mux >= composite->nparents)
+		return EIO;
+
+	rclk_parent = imx_ccm_clock_find(sc, composite->parents[mux]);
+	if (rclk_parent != NULL)
+		clk_parent = &rclk_parent->base;
+	else
+		clk_parent = fdtbus_clock_byname(composite->parents[mux]);
+	if (clk_parent == NULL)
+		return EIO;
+
+	const u_int prate = clk_get_rate(clk_parent);
+	if (prate == 0)
+		return ERANGE;
+
+	for (u_int prediv = 1; prediv <= __SHIFTOUT_MASK(TARGET_ROOT_PRE_PODF) + 1; prediv++) {
+		for (u_int postdiv = 1; postdiv <= __SHIFTOUT_MASK(TARGET_ROOT_POST_PODF) + 1; postdiv++) {
+			const u_int cur_rate = prate / prediv / postdiv;
+			const int diff = (int)rate - (int)cur_rate;
+			if (composite->flags & IMX_COMPOSITE_ROUND_DOWN) {
+				if (diff >= 0 && diff < best_diff) {
+					best_diff = diff;
+					best_prediv = prediv;
+					best_postdiv = postdiv;
+				}
+			} else {
+				if (abs(diff) < best_diff) {
+					best_diff = abs(diff);
+					best_prediv = prediv;
+					best_postdiv = postdiv;
+				}
+			}
+		}
+	}
+	if (best_diff == INT_MAX)
+		return ERANGE;
+
+	val = CCM_READ(sc, composite->reg + CCM_TARGET_ROOT);
+	val &= ~TARGET_ROOT_PRE_PODF;
+	val |= __SHIFTIN(best_prediv - 1, TARGET_ROOT_PRE_PODF);
+	val &= ~TARGET_ROOT_POST_PODF;
+	val |= __SHIFTIN(best_postdiv - 1, TARGET_ROOT_POST_PODF);
+	CCM_WRITE(sc, composite->reg + CCM_TARGET_ROOT, val);
+
+	return 0;
+}
+
+const char *
+imx_ccm_composite_get_parent(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct imx_ccm_composite *composite = &clk->u.composite;
+
+	KASSERT(clk->type == IMX_CCM_COMPOSITE);
+
+	const uint32_t val = CCM_READ(sc, composite->reg + CCM_TARGET_ROOT);
+	const u_int mux = __SHIFTOUT(val, TARGET_ROOT_MUX);
+
+	if (mux >= composite->nparents)
+		return NULL;
+
+	return composite->parents[mux];
+}
+
+int
+imx_ccm_composite_set_parent(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk, const char *parent)
+{
+	struct imx_ccm_composite *composite = &clk->u.composite;
+	uint32_t val;
+
+	KASSERT(clk->type == IMX_CCM_COMPOSITE);
+
+	for (u_int mux = 0; mux < composite->nparents; mux++) {
+		if (strcmp(composite->parents[mux], parent) == 0) {
+			val = CCM_READ(sc, composite->reg + CCM_TARGET_ROOT);
+			val &= ~TARGET_ROOT_MUX;
+			val |= __SHIFTIN(mux, TARGET_ROOT_MUX);
+			CCM_WRITE(sc, composite->reg + CCM_TARGET_ROOT, val);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
Index: src/sys/arch/arm/imx/fdt/imx_ccm_extclk.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm_extclk.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm_extclk.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,99 @@
+/* $NetBSD: imx_ccm_extclk.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx_ccm_extclk.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/imx/fdt/imx_ccm.h>
+
+#include <dev/fdt/fdtvar.h>
+
+int
+imx_ccm_extclk_enable(struct imx_ccm_softc *sc, struct imx_ccm_clk *clk,
+    int enable)
+{
+	struct clk *extclk;
+
+	KASSERT(clk->type == IMX_CCM_EXTCLK);
+
+	if ((extclk = fdtbus_clock_byname(clk->u.extclk)) == NULL)
+		return ENXIO;
+
+	return clk_enable(extclk);
+}
+
+u_int
+imx_ccm_extclk_get_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct clk *extclk;
+
+	KASSERT(clk->type == IMX_CCM_EXTCLK);
+
+	if ((extclk = fdtbus_clock_byname(clk->u.extclk)) == NULL)
+		return 0;
+
+	return clk_get_rate(extclk);
+}
+
+int
+imx_ccm_extclk_set_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk, u_int rate)
+{
+	struct clk *extclk;
+
+	KASSERT(clk->type == IMX_CCM_EXTCLK);
+
+	if ((extclk = fdtbus_clock_byname(clk->u.extclk)) == NULL)
+		return ENXIO;
+
+	return clk_set_rate(extclk, rate);
+}
+
+const char *
+imx_ccm_extclk_get_parent(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct clk *extclk, *clkp;
+
+	KASSERT(clk->type == IMX_CCM_EXTCLK);
+
+	if ((extclk = fdtbus_clock_byname(clk->u.extclk)) == NULL)
+		return NULL;
+
+	clkp = clk_get_parent(extclk);
+	if (clkp == NULL)
+		return NULL;
+
+	return clkp->name;
+}
Index: src/sys/arch/arm/imx/fdt/imx_ccm_fixed.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm_fixed.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm_fixed.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,48 @@
+/* $NetBSD: imx_ccm_fixed.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx_ccm_fixed.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/imx/fdt/imx_ccm.h>
+
+u_int
+imx_ccm_fixed_get_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct imx_ccm_fixed *fixed = &clk->u.fixed;
+
+	KASSERT(clk->type == IMX_CCM_FIXED);
+
+	return fixed->rate;
+}
Index: src/sys/arch/arm/imx/fdt/imx_ccm_fixed_factor.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm_fixed_factor.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm_fixed_factor.c	Wed Jan 15 01:09:56 2020
@@ -0,0 +1,103 @@
+/* $NetBSD: imx_ccm_fixed_factor.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx_ccm_fixed_factor.c,v 1.1 2020/01/15 01:09:56 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/imx/fdt/imx_ccm.h>
+
+static u_int
+imx_ccm_fixed_factor_get_parent_rate(struct clk *clkp)
+{
+	struct clk *clkp_parent;
+
+	clkp_parent = clk_get_parent(clkp);
+	if (clkp_parent == NULL)
+		return 0;
+
+	return clk_get_rate(clkp_parent);
+}
+
+u_int
+imx_ccm_fixed_factor_get_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct imx_ccm_fixed_factor *fixed_factor = &clk->u.fixed_factor;
+	struct clk *clkp = &clk->base;
+
+	KASSERT(clk->type == IMX_CCM_FIXED_FACTOR);
+
+	const u_int p_rate = imx_ccm_fixed_factor_get_parent_rate(clkp);
+	if (p_rate == 0)
+		return 0;
+
+	return (u_int)(((uint64_t)p_rate * fixed_factor->mult) / fixed_factor->div);
+}
+
+static int
+imx_ccm_fixed_factor_set_parent_rate(struct clk *clkp, u_int rate)
+{
+	struct clk *clkp_parent;
+
+	clkp_parent = clk_get_parent(clkp);
+	if (clkp_parent == NULL)
+		return ENXIO;
+
+	return clk_set_rate(clkp_parent, rate);
+}
+
+int
+imx_ccm_fixed_factor_set_rate(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk, u_int rate)
+{
+	struct imx_ccm_fixed_factor *fixed_factor = &clk->u.fixed_factor;
+	struct clk *clkp = &clk->base;
+
+	KASSERT(clk->type == IMX_CCM_FIXED_FACTOR);
+
+	rate *= fixed_factor->div;
+	rate /= fixed_factor->mult;
+
+	return imx_ccm_fixed_factor_set_parent_rate(clkp, rate);
+}
+
+const char *
+imx_ccm_fixed_factor_get_parent(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct imx_ccm_fixed_factor *fixed_factor = &clk->u.fixed_factor;
+
+	KASSERT(clk->type == IMX_CCM_FIXED_FACTOR);
+
+	return fixed_factor->parent;
+}
Index: src/sys/arch/arm/imx/fdt/imx_ccm_gate.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx_ccm_gate.c:1.1
--- /dev/null	Wed Jan 15 01:09:57 2020
+++ src/sys/arch/arm/imx/fdt/imx_ccm_gate.c	Wed Jan 15 01:09:57 2020
@@ -0,0 +1,67 @@
+/* $NetBSD: imx_ccm_gate.c,v 1.1 2020/01/15 01:09:57 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx_ccm_gate.c,v 1.1 2020/01/15 01:09:57 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <dev/clk/clk_backend.h>
+
+#include <arm/imx/fdt/imx_ccm.h>
+
+int
+imx_ccm_gate_enable(struct imx_ccm_softc *sc, struct imx_ccm_clk *clk,
+    int enable)
+{
+	struct imx_ccm_gate *gate = &clk->u.gate;
+	uint32_t val;
+
+	KASSERT(clk->type == IMX_CCM_GATE);
+
+	val = CCM_READ(sc, gate->reg);
+	if (enable)
+		val |= gate->mask;
+	else
+		val &= ~gate->mask;
+	CCM_WRITE(sc, gate->reg, val);
+
+	return 0;
+}
+
+const char *
+imx_ccm_gate_get_parent(struct imx_ccm_softc *sc,
+    struct imx_ccm_clk *clk)
+{
+	struct imx_ccm_gate *gate = &clk->u.gate;
+
+	KASSERT(clk->type == IMX_CCM_GATE);
+
+	return gate->parent;
+}

Reply via email to