Wed Jul 24 13:12:34 2019 UTC ()
Add support for device tree.

+ CCM (clk)
+ COM (uart)
+ GPIO
+ IOMUX (pin control)
+ PCIe
+ SDHC
+ USB Host
+ USB phy


(hkenken)
diff -r0 -r1.1 src/sys/arch/arm/imx/imx6_gpcreg.h
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/files.imx6
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/if_enet_imx.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_ahcisata.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_clk.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_com.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_gpc.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_gpio.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_iomux.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_pcie.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_platform.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_platform.h
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_sdhc.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_usb.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_usbphy.c
diff -r0 -r1.1 src/sys/arch/evbarm/conf/IMX
diff -r0 -r1.1 src/sys/arch/evbarm/conf/files.imx
diff -r0 -r1.1 src/sys/arch/evbarm/conf/mk.imx
diff -r0 -r1.1 src/sys/arch/evbarm/conf/std.imx

File Added: src/sys/arch/arm/imx/Attic/imx6_gpcreg.h
/*	$NetBSD: imx6_gpcreg.h,v 1.1 2019/07/24 13:12:33 hkenken 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.
 */
#ifndef _ARM_IMX_IMX6_GPCREG_H_
#define _ARM_IMX_IMX6_GPCREG_H_

#define GPC_CNTR	0x00000000
#define GPC_PGR		0x00000004
#define GPC_IMR1	0x00000008
#define GPC_IMR2	0x0000000C
#define GPC_IMR3	0x00000010
#define GPC_IMR4	0x00000014
#define GPC_ISR1	0x00000018
#define GPC_ISR2	0x0000001C
#define GPC_ISR3	0x00000020
#define GPC_ISR4	0x00000024

#endif /* _ARM_IMX_IMX6_GPCREG_H_ */

File Added: src/sys/arch/arm/imx/fdt/Attic/files.imx6
#	$NetBSD: files.imx6,v 1.1 2019/07/24 13:12:33 hkenken Exp $
#
# Configuration info for the Freescale i.MX6
#

file	arch/arm/arm32/arm32_boot.c
file	arch/arm/arm32/arm32_kvminit.c
file	arch/arm/arm32/arm32_reboot.c
file	arch/arm/arm32/irq_dispatch.S
file	arch/arm/arm32/armv7_generic_space.c
file	arch/arm/arm/arm_generic_dma.c
file	arch/arm/arm/bus_space_a4x.S

file	arch/arm/imx/fdt/imx6_platform.c	soc_imx

# SOC parameters
defflag	opt_soc.h			SOC_IMX
defflag	opt_soc.h			SOC_IMX6QDL: SOC_IMX

# Clock
device	imxccm : clk
attach	imxccm at fdt
file	arch/arm/imx/imx6_ccm.c		imxccm
file	arch/arm/imx/fdt/imx6_clk.c	imxccm

# GPC
device	imxgpc
attach	imxgpc at fdt
file	arch/arm/imx/fdt/imx6_gpc.c	imxgpc

# IOMUX
device	imxiomux
attach	imxiomux at fdt
file	arch/arm/imx/fdt/imx6_iomux.c	imxiomux

# GPIO controller
device	imxgpio: gpiobus
attach	imxgpio at fdt
file	arch/arm/imx/imxgpio.c		imxgpio
file	arch/arm/imx/fdt/imx6_gpio.c	imxgpio

# UART
device	imxuart { } : bus_space_generic
attach	imxuart at fdt with imx6_com
file	arch/arm/imx/imxuart.c		imxuart	needs-flag
file	arch/arm/imx/fdt/imx6_com.c	imx6_com needs-flag
defflag opt_imxuart.h			IMXUARTCONSOLE

# FEC
device	enet: ether, ifnet, arp, mii, bus_dma_generic
attach	enet at fdt
file	arch/arm/imx/if_enet.c		enet
file	arch/arm/imx/fdt/if_enet_imx.c	enet

# SATA
attach	ahcisata at fdt with imx6_ahcisata
file	arch/arm/imx/fdt/imx6_ahcisata.c	imx6_ahcisata

# USB Controller
device	imxusbc { [unit=-1], [irq=-1] } : bus_dma_generic
attach	imxusbc at fdt with imxusbc_fdt
file	arch/arm/imx/fdt/imx6_usb.c		imxusbc_fdt

attach	ehci at imxusbc with imxehci
file	arch/arm/imx/imxusb.c			imxehci

# USB PHY
device	imxusbphy
attach	imxusbphy at fdt
file	arch/arm/imx/fdt/imx6_usbphy.c	imxusbphy

# SDMMC
attach	sdhc at fdt with imx6_sdhc
file	arch/arm/imx/fdt/imx6_sdhc.c	imx6_sdhc

# PCIe
device	imxpcie: pcibus
attach	imxpcie at fdt with imxpcie_fdt
file	arch/arm/imx/imxpcie.c			imxpcie
file	arch/arm/imx/fdt/imx6_pcie.c		imxpcie_fdt

File Added: src/sys/arch/arm/imx/fdt/Attic/if_enet_imx.c
/*	$NetBSD: if_enet_imx.c,v 1.1 2019/07/24 13:12:33 hkenken 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: if_enet_imx.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#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/if_enetreg.h>
#include <arm/imx/if_enetvar.h>

#include <dev/fdt/fdtvar.h>

static const char * const compatible[] = {
	"fsl,imx6q-fec",
	NULL
};

static int enet_init_clocks(struct enet_softc *);
static void enet_phy_reset(const 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);
}

void
enet_attach(device_t parent, device_t self, void *aux)
{
	struct enet_softc *sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	const int phandle = faa->faa_phandle;
	bus_space_tag_t bst = faa->faa_bst;
	bus_space_handle_t bsh;
	bus_addr_t addr;
	bus_size_t size;
	int error;

	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get enet registers\n");
		return;
	}

	error = bus_space_map(bst, addr, size, 0, &bsh);
	if (error) {
		aprint_error(": couldn't map enet registers: %d\n", error);
		return;
	}

	sc->sc_clk_enet = fdtbus_clock_get(phandle, "ahb");
	if (sc->sc_clk_enet == NULL) {
		aprint_error(": couldn't get clock ahb\n");
		goto failure;
	}
	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;
	}

	aprint_naive("\n");
	aprint_normal(": Gigabit Ethernet Controller\n");

	enet_phy_reset(phandle);

	sc->sc_dev = self;
	sc->sc_iot = bst;
	sc->sc_ioh = bsh;
	sc->sc_dmat = faa->faa_dmat;

	sc->sc_imxtype = 6;	/* i.MX6 */
	sc->sc_rgmii = 1;

	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, 0,
	    enet_intr, sc);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "failed to establish interrupt on %s\n",
		    intrstr);
		goto failure;
	}
	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	enet_init_clocks(sc);
	sc->sc_pllclock = clk_get_rate(sc->sc_clk_enet);

	if (enet_attach_common(self) != 0)
		goto failure;

	return;

failure:
	bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
	return;
}

static int
enet_init_clocks(struct enet_softc *sc)
{
	int error;

	error = clk_enable(sc->sc_clk_enet);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable enet: %d\n", error);
		return error;
	}
	error = clk_enable(sc->sc_clk_enet_ref);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable enet_ref: %d\n", error);
		return error;
	}

	return 0;
}

static void
enet_phy_reset(const int phandle)
{
	struct fdtbus_gpio_pin *reset;
	int error;

	reset = fdtbus_gpio_acquire(phandle, "phy-reset-gpios", GPIO_PIN_OUTPUT);
	if (reset == NULL)
		return;

	u_int msec;
	error = of_getprop_uint32(phandle, "phy-reset-duration", &msec);
	if (error)
		msec = 1;

	/* Reset */
	fdtbus_gpio_write(reset, 1);
	delay(msec * 1000);
	fdtbus_gpio_write(reset, 0);

	fdtbus_gpio_release(reset);
}

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_ahcisata.c
/*	$NetBSD: imx6_ahcisata.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_ahcisata.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>

#include <dev/ata/atavar.h>
#include <dev/ic/ahcisatavar.h>

#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_ahcisatareg.h>
#include <arm/imx/imx6_iomuxreg.h>
#include <arm/imx/imx6_ccmreg.h>
#include <arm/imx/imx6_ccmvar.h>

#include <dev/fdt/fdtvar.h>

static int imx6_ahcisata_match(device_t, cfdata_t, void *);
static void imx6_ahcisata_attach(device_t, device_t, void *);

struct imx6_ahcisata_softc {
	struct ahci_softc sc;

	device_t sc_dev;
	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;
	bus_space_handle_t sc_gpr_ioh;
	void *sc_ih;

	u_int sc_tx_level;
	u_int sc_tx_boost;
	u_int sc_tx_atten;
	u_int sc_rx_eq;
	u_int sc_ss;

	struct clk *sc_clk_sata;
	struct clk *sc_clk_sata_ref;
	struct clk *sc_clk_ahb;
};

static int imx6_ahcisata_init(struct imx6_ahcisata_softc *);
static int imx6_ahcisata_phy_ctrl(struct imx6_ahcisata_softc *, uint32_t, int);
static int imx6_ahcisata_phy_addr(struct imx6_ahcisata_softc *, uint32_t);
static int imx6_ahcisata_phy_write(struct imx6_ahcisata_softc *, uint32_t, uint16_t);
static int imx6_ahcisata_phy_read(struct imx6_ahcisata_softc *, uint32_t);
static int imx6_ahcisata_init_clocks(struct imx6_ahcisata_softc *);

CFATTACH_DECL_NEW(imx6_ahcisata, sizeof(struct imx6_ahcisata_softc),
	imx6_ahcisata_match, imx6_ahcisata_attach, NULL, NULL);

static int
imx6_ahcisata_match(device_t parent, cfdata_t cf, void *aux)
{
	const char * const compatible[] = { "fsl,imx6q-ahci", NULL };
	struct fdt_attach_args * const faa = aux;

	return of_match_compatible(faa->faa_phandle, compatible);
}

static void
imx6_ahcisata_attach(device_t parent, device_t self, void *aux)
{
	struct imx6_ahcisata_softc * const sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	const int phandle = faa->faa_phandle;
	bus_addr_t ahci_addr;
	bus_size_t ahci_size;
	bus_addr_t addr;
	bus_size_t size;
	char intrstr[128];
	int error;

	if (fdtbus_get_reg(phandle, 0, &ahci_addr, &ahci_size) != 0) {
		aprint_error(": couldn't get ahci registers\n");
		return;
	}

	if (of_getprop_uint32(phandle, "fsl,transmit-level-mV", &sc->sc_tx_level) != 0)
		sc->sc_tx_level = 1104;
	if (of_getprop_uint32(phandle, "fsl,transmit-boost-mdB", &sc->sc_tx_boost) != 0)
		sc->sc_tx_boost = 3330;
	if (of_getprop_uint32(phandle, "fsl,transmit-atten-16ths", &sc->sc_tx_atten) != 0)
		sc->sc_tx_atten = 9;
	if (of_getprop_uint32(phandle, "fsl,receive-eq-mdB", &sc->sc_rx_eq) != 0)
		sc->sc_rx_eq = 3000;
	if (of_getprop_bool(phandle, "fsl,no-spread-spectrum") == false)
		sc->sc_ss = 1;

	sc->sc_clk_sata = fdtbus_clock_get(phandle, "sata");
	if (sc->sc_clk_sata == NULL) {
		aprint_error(": couldn't get clock sata\n");
		return;
	}
	sc->sc_clk_sata_ref = fdtbus_clock_get(phandle, "sata_ref");
	if (sc->sc_clk_sata_ref == NULL) {
		aprint_error(": couldn't get clock sata_ref\n");
		return;
	}
	sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
	if (sc->sc_clk_ahb == NULL) {
		aprint_error(": couldn't get clock ahb\n");
		return;
	}

	aprint_naive("\n");
	aprint_normal(": AHCI Controller\n");

	aprint_debug_dev(self, "tx level %d [mV]\n", sc->sc_tx_level);
	aprint_debug_dev(self, "tx boost %d [mdB]\n", sc->sc_tx_boost);
	aprint_debug_dev(self, "tx atten %d [16ths]\n", sc->sc_tx_atten);
	aprint_debug_dev(self, "rx eq    %d [mdB]\n", sc->sc_rx_eq);
	aprint_debug_dev(self, "ss       %d\n", sc->sc_ss);

	sc->sc_dev = self;

	sc->sc.sc_atac.atac_dev = self;
	sc->sc.sc_ahci_ports = 1;
	sc->sc.sc_dmat = faa->faa_dmat;
	sc->sc.sc_ahcit = faa->faa_bst;
	sc->sc.sc_ahcis = ahci_size;
	error = bus_space_map(sc->sc.sc_ahcit, ahci_addr, ahci_size, 0,
	    &sc->sc.sc_ahcih);
	if (error) {
		aprint_error(": couldn't map ahci registers: %d\n", error);
		return;
	}

	sc->sc_iot = sc->sc.sc_ahcit;
	sc->sc_ioh = sc->sc.sc_ahcih;

	const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
	fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
		aprint_error_dev(self, "Cannot map registers\n");
		return;
	}

	if (imx6_ahcisata_init_clocks(sc) != 0) {
		aprint_error_dev(self, "couldn't init clocks\n");
		return;
	}

	if (imx6_ahcisata_init(sc) != 0) {
		aprint_error_dev(self, "couldn't init ahci\n");
		return;
	}

	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(phandle, 0, IPL_BIO, 0,
	    ahci_intr, &sc->sc);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "failed to establish interrupt on %s\n",
		    intrstr);
		return;
	}
	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	ahci_attach(&sc->sc);
}

static int
imx6_ahcisata_phy_ctrl(struct imx6_ahcisata_softc *sc, uint32_t bitmask, int on)
{
	uint32_t v;
	int timeout;

	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR);
	if (on)
		v |= bitmask;
	else
		v &= ~bitmask;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, v);

	for (timeout = 5000; timeout > 0; --timeout) {
		v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
		if (!!(v & SATA_P0PHYSR_CR_ACK) == !!on)
			break;
		delay(100);
	}

	if (timeout > 0)
		return 0;

	return -1;
}

static int
imx6_ahcisata_phy_addr(struct imx6_ahcisata_softc *sc, uint32_t addr)
{
	delay(100);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, addr);

	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 1) != 0)
		return -1;
	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 0) != 0)
		return -1;

	return 0;
}

static int
imx6_ahcisata_phy_write(struct imx6_ahcisata_softc *sc, uint32_t addr,
                        uint16_t data)
{
	if (imx6_ahcisata_phy_addr(sc, addr) != 0)
		return -1;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, data);

	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 1) != 0)
		return -1;
	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 0) != 0)
		return -1;

	if ((addr == SATA_PHY_CLOCK_RESET) && data) {
		/* we can't check ACK after RESET */
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
		    data | SATA_P0PHYCR_CR_WRITE);
		return 0;
	}

	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 1) != 0)
		return -1;
	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 0) != 0)
		return -1;

	return 0;
}

static int
imx6_ahcisata_phy_read(struct imx6_ahcisata_softc *sc, uint32_t addr)
{
	uint32_t v;

	if (imx6_ahcisata_phy_addr(sc, addr) != 0)
		return -1;

	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 1) != 0)
		return -1;

	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);

	if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 0) != 0)
		return -1;

	return SATA_P0PHYSR_CR_DATA_OUT(v);
}

const static int tx_level[] = {
	 937,
	 947,
	 957,
	 966,
	 976,
	 986,
	 996,
	1005,
	1015,
	1025,
	1035,
	1045,
	1054,
	1064,
	1074,
	1084,
	1094,
	1104,
	1113,
	1123,
	1133,
	1143,
	1152,
	1162,
	1172,
	1182,
	1191,
	1201,
	1211,
	1221,
	1230,
	1240,
};

const static int tx_boots[] = {
	   0,
	 370,
	 740,
	1110,
	1480,
	1850,
	2220,
	2590,
	2960,
	3330,
	3700,
	4070,
	4440,
	4810,
	5280,
	5750,
};

const static int tx_atten[] = {
	  16,
	  14,
	  12,
	  10,
	   9,
	   8,
};

const static int rx_eq[] = {
	 500,
	1000,
	1500,
	2000,
	2500,
	3000,
	3500,
	4000,
};

static int
imx6_ahcisata_search_regval(const int *values, int count, int val)
{
	for (int i = 0; i < count; i++)
		if (values[i] == val)
			return i;

	return -1;
}

static int
imx6_ahcisata_init(struct imx6_ahcisata_softc *sc)
{
	uint32_t v;
	int timeout;
	int pllstat;

	v = bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13);
	/* clear */
	v &= ~(IOMUX_GPR13_SATA_PHY_8 |
	    IOMUX_GPR13_SATA_PHY_7 |
	    IOMUX_GPR13_SATA_PHY_6 |
	    IOMUX_GPR13_SATA_SPEED |
	    IOMUX_GPR13_SATA_PHY_5 |
	    IOMUX_GPR13_SATA_PHY_4 |
	    IOMUX_GPR13_SATA_PHY_3 |
	    IOMUX_GPR13_SATA_PHY_2 |
	    IOMUX_GPR13_SATA_PHY_1 |
	    IOMUX_GPR13_SATA_PHY_0);
	/* setting */
	struct {
		const int *array;
		int count;
		int val;
		int def_val;
		int mask;
	} gpr13_sata_phy_settings[] = {
		{ tx_level, __arraycount(tx_level), sc->sc_tx_level,
		  0x11, IOMUX_GPR13_SATA_PHY_2 },
		{ tx_boots, __arraycount(tx_boots), sc->sc_tx_boost,
		  0x09, IOMUX_GPR13_SATA_PHY_3 },
		{ tx_atten, __arraycount(tx_atten), sc->sc_tx_atten,
		  0x04, IOMUX_GPR13_SATA_PHY_4 },
		{ rx_eq, __arraycount(rx_eq), sc->sc_rx_eq,
		  0x05, IOMUX_GPR13_SATA_PHY_8 }
	};
	for (int i = 0; i < __arraycount(gpr13_sata_phy_settings); i++) {
		int val;
		val = imx6_ahcisata_search_regval(
			gpr13_sata_phy_settings[i].array,
			gpr13_sata_phy_settings[i].count,
			gpr13_sata_phy_settings[i].val);
		if (val == -1)
			val = gpr13_sata_phy_settings[i].def_val;
		v |= __SHIFTIN(val, gpr13_sata_phy_settings[i].mask);
	}
	v |= __SHIFTIN(sc->sc_ss, IOMUX_GPR13_SATA_PHY_5);
	v |= __SHIFTIN(0x12, IOMUX_GPR13_SATA_PHY_7);	/* Rx SATA2m */
	v |= __SHIFTIN(3, IOMUX_GPR13_SATA_PHY_6);	/* Rx DPLL mode */
	v |= __SHIFTIN(1, IOMUX_GPR13_SATA_SPEED);	/* 3.0GHz */
	v |= __SHIFTIN(1, IOMUX_GPR13_SATA_PHY_1);	/* PLL clock enable */
	bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13, v);

	/* phy reset */
	if (imx6_ahcisata_phy_write(sc, SATA_PHY_CLOCK_RESET,
	    SATA_PHY_CLOCK_RESET_RST) < 0) {
		aprint_error_dev(sc->sc_dev, "cannot reset PHY\n");
		return -1;
	}

	for (timeout = 50; timeout > 0; --timeout) {
		delay(100);
		pllstat = imx6_ahcisata_phy_read(sc, SATA_PHY_LANE0_OUT_STAT);
		if (pllstat < 0) {
			aprint_error_dev(sc->sc_dev,
			    "cannot read LANE0 status\n");
			break;
		}
		if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE)
			break;
	}
	if (timeout <= 0)
		return -1;

	/* Support Staggered Spin-up */
	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, v | SATA_CAP_SSS);

	/* Ports Implmented. must set 1 */
	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_PI);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, v | SATA_PI_PI);

	/* set 1ms-timer = AHB clock / 1000 */
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS,
	    clk_get_rate(sc->sc_clk_ahb) / 1000);

	return 0;
}

static int
imx6_ahcisata_init_clocks(struct imx6_ahcisata_softc *sc)
{
	int error;

	error = clk_enable(sc->sc_clk_sata);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error);
		return error;
	}
	error = clk_enable(sc->sc_clk_sata_ref);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error);
		return error;
	}
	error = clk_enable(sc->sc_clk_ahb);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error);
		return error;
	}

	return 0;
}

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_clk.c
/*	$NetBSD: imx6_clk.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_clk.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#include <sys/types.h>
#include <sys/time.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/sysctl.h>
#include <sys/cpufreq.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/param.h>

#include <arm/imx/imx6_ccmvar.h>

#include <dev/clk/clk_backend.h>
#include <dev/fdt/fdtvar.h>

static struct clk *imx6_clk_decode(device_t, int, const void *, size_t);

static const struct fdtbus_clock_controller_func imx6_ccm_fdtclock_funcs = {
	.decode = imx6_clk_decode
};

static struct clk *
imx6_clk_decode(device_t dev, int cc_phandle, const void *data, size_t len)
{
	struct clk *clk;

	/* #clock-cells should be 1 */
	if (len != 4)
		return NULL;

	const u_int clock_id = be32dec(data);

	clk = imx6_get_clock_by_id(clock_id);
	if (clk)
		return clk;

	return NULL;
}

static void
imx6_clk_fixed_from_fdt(const char *name)
{
	struct imx6_clk *iclk = (struct imx6_clk *)imx6_get_clock(name);

	KASSERT(iclk != NULL);

	char *path = kmem_asprintf("/clocks/%s", name);
	int phandle = OF_finddevice(path);
	kmem_free(path, strlen(path) + 1);

	if (of_getprop_uint32(phandle, "clock-frequency", &iclk->clk.fixed.rate) != 0)
		iclk->clk.fixed.rate = 0;
}

static int imxccm_match(device_t, cfdata_t, void *);
static void imxccm_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(imxccm, sizeof(struct imxccm_softc),
    imxccm_match, imxccm_attach, NULL, NULL);

static int
imxccm_match(device_t parent, cfdata_t cfdata, void *aux)
{
	const char * const compatible[] = { "fsl,imx6q-ccm", NULL };
	struct fdt_attach_args * const faa = aux;

	return of_match_compatible(faa->faa_phandle, compatible);
}

static void
imxccm_attach(device_t parent, device_t self, void *aux)
{
	struct imxccm_softc * const sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	bus_addr_t addr;
	bus_size_t size;

	if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get registers\n");
		return;
	}

	sc->sc_dev = self;
	sc->sc_iot = faa->faa_bst;

	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
		aprint_error(": can't map ccm registers\n");
		return;
	}

	int phandle = OF_finddevice("/soc/aips-bus/anatop");
	fdtbus_get_reg(phandle, 0, &addr, &size);

	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh_analog)) {
		aprint_error(": can't map anatop registers\n");
		return;
	}

	imxccm_attach_common(self);

	imx6_clk_fixed_from_fdt("ckil");
	imx6_clk_fixed_from_fdt("ckih");
	imx6_clk_fixed_from_fdt("osc");
	imx6_clk_fixed_from_fdt("anaclk1");
	imx6_clk_fixed_from_fdt("anaclk2");

	fdtbus_register_clock_controller(self, faa->faa_phandle,
	    &imx6_ccm_fdtclock_funcs);
}


File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_com.c
/*	$NetBSD: imx6_com.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_com.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"
#include "opt_imxuart.h"

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>

#include <dev/fdt/fdtvar.h>

#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imxuartreg.h>
#include <arm/imx/imxuartvar.h>

static int imx6_com_match(device_t, struct cfdata *, void *);
static void imx6_com_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(imx6_com, sizeof(struct imxuart_softc),
    imx6_com_match, imx6_com_attach, NULL, NULL);

static const char * const compatible[] = {
	"fsl,imx6q-uart",
	NULL
};

static int
imx6_com_match(device_t parent, struct cfdata *cf, void *aux)
{
	struct fdt_attach_args * const faa = aux;

	return of_match_compatible(faa->faa_phandle, compatible);
}

static void
imx6_com_attach(device_t parent, device_t self, void *aux)
{
	struct imxuart_softc *sc = device_private(self);
	struct imxuart_regs *regsp = &sc->sc_regs;
	struct fdt_attach_args *faa = aux;
	const int phandle = faa->faa_phandle;
	bus_space_tag_t bst = faa->faa_bst;
	bus_space_handle_t bsh;
	char intrstr[128];
	bus_addr_t addr;
	bus_size_t size;

	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get registers\n");
		return;
	}

	if (bus_space_map(bst, addr, size, 0, &bsh) != 0) {
		aprint_error(": couldn't map registers\n");
		return;
	}

	sc->sc_dev = self;
	regsp->ur_iot = bst;
	regsp->ur_iobase = addr;
	regsp->ur_ioh = bsh;

	if (imxuart_is_console(regsp->ur_iot, regsp->ur_iobase, &regsp->ur_ioh))
		aprint_normal(" (console)");

	aprint_normal("\n");

	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(phandle, 0, IPL_SERIAL,
	    FDT_INTR_MPSAFE, imxuintr, sc);
	if (sc->sc_ih == NULL)
		aprint_error_dev(self, "failed to establish interrupt\n");

	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	imxuart_attach_subr(sc);

}

/*
 * Console support
 */

static int
imx6_com_console_match(int phandle)
{
	return of_match_compatible(phandle, compatible);
}

static void
imx6_com_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
{
	const int phandle = faa->faa_phandle;
	bus_space_tag_t bst = faa->faa_bst;
	bus_addr_t addr;
	bus_size_t size;
	tcflag_t flags;
	int speed;

	fdtbus_get_reg(phandle, 0, &addr, &size);
	speed = fdtbus_get_stdout_speed();
	if (speed < 0)
		speed = 115200;	/* default */
	flags = fdtbus_get_stdout_flags();

	imxuart_set_frequency(uart_freq, 2);
	if (imxuart_cnattach(bst, addr, speed, flags) != 0)
		panic("cannot attach console UART");
}

static const struct fdt_console imx6_com_console = {
	.match = imx6_com_console_match,
	.consinit = imx6_com_console_consinit,
};

FDT_CONSOLE(imx6_com, &imx6_com_console);

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_gpc.c
/*	$NetBSD: imx6_gpc.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_gpc.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#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>

struct imxgpc_softc {
	device_t sc_dev;

	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;
};

static int imxgpc_match(device_t, struct cfdata *, void *);
static void imxgpc_attach(device_t, device_t, void *);

static void *imxgpc_establish(device_t, u_int *, int, int,
    int (*)(void *), void *);
static void imxgpc_disestablish(device_t, void *);
static bool imxgpc_intrstr(device_t, u_int *, char *, size_t);

struct fdtbus_interrupt_controller_func imxgpc_funcs = {
	.establish = imxgpc_establish,
	.disestablish = imxgpc_disestablish,
	.intrstr = imxgpc_intrstr
};

CFATTACH_DECL_NEW(imxgpc, sizeof(struct imxgpc_softc),
    imxgpc_match, imxgpc_attach, NULL, NULL);

static int
imxgpc_match(device_t parent, cfdata_t cf, void *aux)
{
	const char * const compatible[] = { "fsl,imx6q-gpc", NULL };
	struct fdt_attach_args * const faa = aux;

	return of_match_compatible(faa->faa_phandle, compatible);
}

static void
imxgpc_attach(device_t parent, device_t self, void *aux)
{
	struct imxgpc_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;

	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,
	    &imxgpc_funcs);
	if (error) {
		aprint_error(": couldn't register with fdtbus: %d\n", error);
		return;
	}

	aprint_naive("\n");
	aprint_normal(": General Power Controller\n");

	return;
}

static void *
imxgpc_establish(device_t dev, u_int *specifier, int ipl, int flags,
    int (*func)(void *), void *arg)
{
	/* 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;

	aprint_debug_dev(dev, "intr establish irq %d, level %d\n", irq, level);
	return intr_establish(irq, ipl, level | mpsafe, func, arg);
}

static void
imxgpc_disestablish(device_t dev, void *ih)
{
	intr_disestablish(ih);
}

static bool
imxgpc_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;
}

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_gpio.c
/*	$NetBSD: imx6_gpio.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_gpio.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"
#include "gpio.h"

#define	_INTR_PRIVATE

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/gpio.h>

#include <dev/gpio/gpiovar.h>

#include <arm/pic/picvar.h>
#include <arm/imx/imx6_reg.h>

#include <arm/imx/imxgpioreg.h>
#include <arm/imx/imxgpiovar.h>

#include <dev/fdt/fdtvar.h>

static void *imx6_gpio_fdt_acquire(device_t, const void *, size_t, int);
static void imx6_gpio_fdt_release(device_t, void *);
static int imx6_gpio_fdt_read(device_t, void *, bool);
static void imx6_gpio_fdt_write(device_t, void *, int, bool);

static void *imxgpio_establish(device_t, u_int *, int, int,
    int (*)(void *), void *);
static void imxgpio_disestablish(device_t, void *);
static bool imxgpio_intrstr(device_t, u_int *, char *, size_t);

static struct fdtbus_interrupt_controller_func imxgpio_funcs = {
	.establish = imxgpio_establish,
	.disestablish = imxgpio_disestablish,
	.intrstr = imxgpio_intrstr
};

static struct fdtbus_gpio_controller_func imx6_gpio_funcs = {
	.acquire = imx6_gpio_fdt_acquire,
	.release = imx6_gpio_fdt_release,
	.read = imx6_gpio_fdt_read,
	.write = imx6_gpio_fdt_write
};

const int imxgpio_ngroups = GPIO_NGROUPS;

int
imxgpio_match(device_t parent, cfdata_t cf, void *aux)
{
	const char * const compatible[] = {
		"fsl,imx6q-gpio",
		NULL
	};
	struct fdt_attach_args * const faa = aux;

	return of_match_compatible(faa->faa_phandle, compatible);
}

void
imxgpio_attach(device_t parent, device_t self, void *aux)
{
	struct imxgpio_softc * const sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	char intrstr[128];
	const int phandle = faa->faa_phandle;
	bus_space_handle_t ioh;
	bus_addr_t addr;
	bus_size_t size;
	int error;

	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get registers\n");
		return;
	}

	error = bus_space_map(faa->faa_bst, addr, size, 0, &ioh);
	if (error) {
		aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
		return;
	}

	aprint_naive("\n");
	aprint_normal(": GPIO (%s)\n", fdtbus_get_string(phandle, "name"));

	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;

	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
		aprint_error_dev(self, "failed to decode interrupt\n");
		return;
	}
	sc->gpio_is = fdtbus_intr_establish(phandle, 0, IPL_HIGH, 0,
	    pic_handle_intr, &sc->gpio_pic);
	if (sc->gpio_is == NULL) {
		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
		    intrstr);
		return;
	}
	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	if (!fdtbus_intr_str(phandle, 1, intrstr, sizeof(intrstr))) {
		aprint_error_dev(self, "failed to decode interrupt\n");
		return;
	}
	sc->gpio_is_high = fdtbus_intr_establish(phandle, 1, IPL_HIGH, 0,
	    pic_handle_intr, &sc->gpio_pic);
	if (sc->gpio_is_high == NULL) {
		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
		    intrstr);
		return;
	}
	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	fdtbus_register_gpio_controller(self, phandle, &imx6_gpio_funcs);

	error = fdtbus_register_interrupt_controller(self, phandle,
	    &imxgpio_funcs);
	if (error) {
		aprint_error(": couldn't register with fdtbus: %d\n", error);
		return;
	}

	imxgpio_attach_common(self);
}

static void *
imx6_gpio_fdt_acquire(device_t dev, const void *data, size_t len, int flags)
{
	struct imxgpio_softc * const sc = device_private(dev);
	struct imxgpio_pin *gpin;
	const u_int *gpio = data;

	if (len != 12)
		return NULL;

	const u_int pin = be32toh(gpio[1]);
	const bool actlo = be32toh(gpio[2]) & 1;

	gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP);
	gpin->pin_no = pin;
	gpin->pin_flags = flags;
	gpin->pin_actlo = actlo;

	imxgpio_pin_ctl(sc, gpin->pin_no, gpin->pin_flags);

	return gpin;
}

static void
imx6_gpio_fdt_release(device_t dev, void *priv)
{
	struct imxgpio_softc * const sc = device_private(dev);
	struct imxgpio_pin *gpin = priv;

	imxgpio_pin_ctl(sc, gpin->pin_no, GPIO_PIN_INPUT);
	kmem_free(gpin, sizeof(*gpin));
}

static int
imx6_gpio_fdt_read(device_t dev, void *priv, bool raw)
{
	struct imxgpio_softc * const sc = device_private(dev);
	struct imxgpio_pin *gpin = priv;
	int val;

	val = imxgpio_pin_read(sc, gpin->pin_no);

	if (!raw && gpin->pin_actlo)
		val = !val;

	return val;
}

static void
imx6_gpio_fdt_write(device_t dev, void *priv, int val, bool raw)
{
	struct imxgpio_softc * const sc = device_private(dev);
	struct imxgpio_pin *gpin = priv;

	if (!raw && gpin->pin_actlo)
		val = !val;

	imxgpio_pin_write(sc, gpin->pin_no, val);
}

static void *
imxgpio_establish(device_t dev, u_int *specifier, int ipl, int flags,
    int (*func)(void *), void *arg)
{
	struct imxgpio_softc * const sc = device_private(dev);

	/* 1st cell is the interrupt number */
	/* 2nd cell is flags */

	const u_int intr = be32toh(specifier[0]);
	const u_int trig = be32toh(specifier[1]) & 0xf;
	u_int level;

	if ((trig & 0x1) && (trig & 0x2))
		level = IST_EDGE_BOTH;
	else if (trig & 0x1)
		level = IST_EDGE_RISING;
	else if (trig & 0x2)
		level = IST_EDGE_FALLING;
	else if (trig & 0x4)
		level = IST_LEVEL_HIGH;
	else
		level = IST_LEVEL_LOW;

	const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;

	aprint_debug_dev(dev, "intr establish irq %d, level %d\n",
	    sc->gpio_irqbase + intr, level);
	return intr_establish(sc->gpio_irqbase + intr, ipl, level | mpsafe, func, arg);
}

static void
imxgpio_disestablish(device_t dev, void *ih)
{
	intr_disestablish(ih);
}

static bool
imxgpio_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
{
	struct imxgpio_softc * const sc = device_private(dev);

	/* 1st cell is the interrupt number */
	/* 2nd cell is flags */

	if (!specifier)
		return false;

	const u_int intr = be32toh(specifier[0]);

	snprintf(buf, buflen, "irq %d (gpio%d %d)",
	    sc->gpio_irqbase + intr, sc->gpio_unit, intr);

	return true;
}

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_iomux.c
/*	$NetBSD: imx6_iomux.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_iomux.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#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_iomuxreg.h>

#include <dev/fdt/fdtvar.h>

struct imxiomux_softc {
	device_t sc_dev;

	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;

	int sc_phandle;
};

#define CONFIG_NO_PAD_CTL	__BIT(31)
#define CONFIG_SION		__BIT(30)

static int
imx6_pinctrl_set_config(device_t dev, const void *data, size_t len)
{
	struct imxiomux_softc * const sc = device_private(dev);
	int pins_len;
	uint32_t reg;

	if (len != 4)
		return -1;

	const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
	const u_int *pins = fdtbus_get_prop(phandle, "fsl,pins", &pins_len);

	aprint_debug_dev(sc->sc_dev, "name %s\n", fdtbus_get_string(phandle, "name"));
	while (pins_len >= 24) {
		u_int mux_reg   = be32toh(pins[0]);
		u_int conf_reg  = be32toh(pins[1]);
		u_int input_reg = be32toh(pins[2]);
		u_int mux_mode  = be32toh(pins[3]);
		u_int input_val = be32toh(pins[4]);
		u_int config    = be32toh(pins[5]);

		if (config & CONFIG_SION)
			mux_mode |= IOMUX_CONFIG_SION;
		config &= ~CONFIG_SION;

		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, mux_reg);
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, mux_reg, mux_mode);
		aprint_debug_dev(sc->sc_dev,
		    "mux    offset 0x%08x, val 0x%08x -> 0x%08x\n",
		    mux_reg, reg, mux_mode);

		if (!(config & CONFIG_NO_PAD_CTL)) {
			reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, conf_reg);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, conf_reg, config);
			aprint_debug_dev(sc->sc_dev,
			    "config offset 0x%08x, val 0x%08x -> 0x%08x\n",
			    conf_reg, reg, config);
		}

		if (__SHIFTOUT(input_val, __BITS(31, 24)) == 0xff) {
			uint8_t sel   = __SHIFTOUT(input_val, __BITS(7, 0));
			uint8_t width = __SHIFTOUT(input_val, __BITS(15, 8));
			uint8_t shift = __SHIFTOUT(input_val, __BITS(23, 16));
			uint32_t mask = __BITS(shift + (width - 1), shift);

			reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, input_reg);
			reg &= ~mask;
			reg |= __SHIFTIN(sel, mask);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, input_reg, reg);
			aprint_debug_dev(sc->sc_dev,
			    "+input offset 0x%08x, val 0x%08x\n",
			    input_reg, reg);
		} else if (input_reg != 0) {
			reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, input_reg);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, input_reg, input_val);
			aprint_debug_dev(sc->sc_dev,
			    "input  offset 0x%08x, val 0x%08x -> 0x%08x\n",
			    input_reg, reg, input_val);
		}

		pins_len -= 24;
		pins += 6;
	}

	return 0;
}

static struct fdtbus_pinctrl_controller_func imx6_pinctrl_funcs = {
	.set_config = imx6_pinctrl_set_config,
};

static int imxiomux_match(device_t, struct cfdata *, void *);
static void imxiomux_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(imxiomux, sizeof(struct imxiomux_softc),
    imxiomux_match, imxiomux_attach, NULL, NULL);

static int
imxiomux_match(device_t parent, cfdata_t cf, void *aux)
{
	const char * const compatible[] = { "fsl,imx6q-iomuxc", NULL };
	struct fdt_attach_args * const faa = aux;

	return of_match_compatible(faa->faa_phandle, compatible);
}

static void
imxiomux_attach(device_t parent, device_t self, void *aux)
{
	struct imxiomux_softc * const sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	const int phandle = faa->faa_phandle;
	bus_addr_t addr;
	bus_size_t size;
	int error;

	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get iomux registers\n");
		return;
	}

	sc->sc_dev = self;
	sc->sc_iot = faa->faa_bst;

	error = bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh);
	if (error) {
		aprint_error(": couldn't map iomux registers: %d\n", error);
		return;
	}

	aprint_naive("\n");
	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);
		}
	}

	fdtbus_pinctrl_configure();
}


File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_pcie.c
/*	$NetBSD: imx6_pcie.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_pcie.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_pci.h"
#include "opt_fdt.h"

#include "pci.h"
#include "imxgpio.h"
#include "locators.h"

#define	_INTR_PRIVATE

#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/extent.h>
#include <sys/queue.h>
#include <sys/mutex.h>
#include <sys/kmem.h>
#include <sys/gpio.h>

#include <machine/frame.h>
#include <arm/cpufunc.h>

#include <dev/fdt/fdtvar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pciconf.h>

#include <arm/imx/imxpcievar.h>
#include <arm/imx/imxgpioreg.h>
#include <arm/imx/imxgpiovar.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_iomuxreg.h>
#include <arm/imx/imx6_ccmreg.h>
#include <arm/imx/imx6_ccmvar.h>

struct imxpcie_fdt_softc {
	struct imxpcie_softc sc_imxpcie;

	struct fdtbus_gpio_pin	*sc_pin_reset;
};

static int imx6_pcie_match(device_t, cfdata_t, void *);
static void imx6_pcie_attach(device_t, device_t, void *);

static void imx6_pcie_configure(void *);
static uint32_t imx6_pcie_gpr_read(void *, uint32_t);
static void imx6_pcie_gpr_write(void *, uint32_t, uint32_t);
static void imx6_pcie_reset(void *);

#define IMX6_PCIE_MEM_BASE	0x01000000
#define IMX6_PCIE_MEM_SIZE	0x00f00000 /* 15MB */
#define IMX6_PCIE_ROOT_BASE	0x01f00000
#define IMX6_PCIE_ROOT_SIZE	0x00080000 /* 512KB */
#define IMX6_PCIE_IO_BASE	0x01f80000
#define IMX6_PCIE_IO_SIZE	0x00010000 /* 64KB */

CFATTACH_DECL_NEW(imxpcie_fdt, sizeof(struct imxpcie_fdt_softc),
    imx6_pcie_match, imx6_pcie_attach, NULL, NULL);

static const char * const compatible[] = {
	"fsl,imx6q-pcie",
	NULL
};

static int
imx6_pcie_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
imx6_pcie_attach(device_t parent, device_t self, void *aux)
{
	struct imxpcie_fdt_softc * const ifsc = device_private(self);
	struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
	struct fdt_attach_args * const faa = aux;
	const int phandle = faa->faa_phandle;
	bus_space_tag_t bst = faa->faa_bst;
	char intrstr[128];
	bus_addr_t addr;
	bus_size_t size;

	aprint_naive("\n");
	aprint_normal(": PCI Express Controller\n");

	sc->sc_dev = self;
	sc->sc_iot = bst;
	sc->sc_dmat = faa->faa_dmat;
	sc->sc_cookie = ifsc;
	sc->sc_pci_netbsd_configure = imx6_pcie_configure;
	sc->sc_gpr_read = imx6_pcie_gpr_read;
	sc->sc_gpr_write = imx6_pcie_gpr_write;
	sc->sc_reset = imx6_pcie_reset;

	if (fdtbus_get_reg_byname(phandle, "dbi", &addr, &size) != 0) {
		aprint_error(": couldn't get registers\n");
		return;
	}
	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
		aprint_error_dev(self, "Cannot map registers\n");
		return;
	}
	if (fdtbus_get_reg_byname(phandle, "config", &addr, &size) != 0) {
		aprint_error(": couldn't get registers\n");
		return;
	}
	sc->sc_root_addr = addr;
	sc->sc_root_size = size;

	const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
	fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
		aprint_error_dev(self, "Cannot map registers\n");
		return;
	}

	ifsc->sc_pin_reset = fdtbus_gpio_acquire(phandle, "reset-gpio",
	    GPIO_PIN_OUTPUT);
	if (!ifsc->sc_pin_reset) {
		aprint_error(": couldn't acquire reset gpio\n");
		return;
	}

	sc->sc_clk_pcie_axi = fdtbus_clock_get(phandle, "pcie");
	if (sc->sc_clk_pcie_axi == NULL) {
		aprint_error(": couldn't get clock pcie_axi\n");
		return;
	}
	sc->sc_clk_lvds1_gate = fdtbus_clock_get(phandle, "pcie_bus");
	if (sc->sc_clk_lvds1_gate == NULL) {
		aprint_error(": couldn't get clock lvds1_gate\n");
		return;
	}
	sc->sc_clk_pcie_ref = fdtbus_clock_get(phandle, "pcie_phy");
	if (sc->sc_clk_pcie_ref == NULL) {
		aprint_error(": couldn't get clock pcie_ref\n");
		return;
	}

	TAILQ_INIT(&sc->sc_intrs);
	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);

	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(phandle, 0, IPL_VM, 0, imxpcie_intr, sc);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "failed to establish interrupt on %s\n",
		    intrstr);
		return;
	}
	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	imxpcie_attach_common(sc);
}

static void
imx6_pcie_configure(void *cookie)
{
	struct imxpcie_fdt_softc * const ifsc = cookie;
	struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;

#ifdef PCI_NETBSD_CONFIGURE
	struct extent *ioext, *memext;
	int error;

	ioext = extent_create("pciio", IMX6_PCIE_IO_BASE,
	    IMX6_PCIE_IO_BASE + IMX6_PCIE_IO_SIZE - 1,
	    NULL, 0, EX_NOWAIT);
	memext = extent_create("pcimem", IMX6_PCIE_MEM_BASE,
	    IMX6_PCIE_MEM_BASE + IMX6_PCIE_MEM_SIZE - 1,
	    NULL, 0, EX_NOWAIT);

	error = pci_configure_bus(&sc->sc_pc, ioext, memext, NULL, 0,
	    arm_dcache_align);

	extent_destroy(ioext);
	extent_destroy(memext);

	if (error) {
		aprint_error_dev(sc->sc_dev, "configuration failed (%d)\n",
		    error);
	}
#endif
}

static uint32_t
imx6_pcie_gpr_read(void *cookie, uint32_t reg)
{
	struct imxpcie_fdt_softc * const ifsc = cookie;
	struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
	return bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, reg);
}

static void
imx6_pcie_gpr_write(void *cookie, uint32_t reg, uint32_t val)
{
	struct imxpcie_fdt_softc * const ifsc = cookie;
	struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
	bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, reg, val);
}

static void
imx6_pcie_reset(void *cookie)
{
	struct imxpcie_fdt_softc * const ifsc = cookie;

	fdtbus_gpio_write(ifsc->sc_pin_reset, 1);
	delay(20 * 1000);
	fdtbus_gpio_write(ifsc->sc_pin_reset, 0);
}

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_platform.c
/*	$NetBSD: imx6_platform.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_platform.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_soc.h"
#include "arml2cc.h"
#include "opt_multiprocessor.h"
#include "opt_fdt.h"
#include "opt_fdt_arm.h"

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/termios.h>

#include <dev/fdt/fdtvar.h>
#include <arm/fdt/arm_fdtvar.h>

#include <uvm/uvm_extern.h>

#include <arm/arm32/machdep.h>

#include <machine/bootconfig.h>
#include <arm/cpufunc.h>

#include <arm/cortex/a9tmr_var.h>
#include <arm/cortex/scu_reg.h>
#include <arm/cortex/gic_reg.h>
#include <arm/cortex/pl310_var.h>

#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_srcreg.h>
#include <arm/imx/imxuartreg.h>

#include <arm/imx/fdt/imx6_platform.h>

#include <libfdt.h>

#define	IMX_REF_FREQ	80000000

#ifdef VERBOSE_INIT_ARM
#define VPRINTF(...)	printf(__VA_ARGS__)
#else
#define VPRINTF(...)	__nothing
#endif

extern struct bus_space armv7_generic_bs_tag;
extern struct bus_space armv7_generic_a4x_bs_tag;
extern struct arm32_bus_dma_tag arm_generic_dma_tag;

static const struct pmap_devmap *
imx_platform_devmap(void)
{
	static const struct pmap_devmap devmap[] = {
		DEVMAP_ENTRY(KERNEL_IO_IOREG_VBASE, IMX6_IOREG_PBASE, IMX6_IOREG_SIZE),
		DEVMAP_ENTRY(KERNEL_IO_ARMCORE_VBASE, IMX6_ARMCORE_PBASE, IMX6_ARMCORE_SIZE),
		DEVMAP_ENTRY_END
};

	return devmap;
}

static void
imx_platform_init_attach_args(struct fdt_attach_args *faa)
{
	faa->faa_bst = &armv7_generic_bs_tag;
	faa->faa_a4x_bst = &armv7_generic_a4x_bs_tag;
	faa->faa_dmat = &arm_generic_dma_tag;
}

void imx_platform_early_putchar(char);

void
imx_platform_early_putchar(char c)
{
#ifdef CONSADDR
#define CONSADDR_VA	((CONSADDR - IMX6_IOREG_PBASE) + KERNEL_IO_IOREG_VBASE)

	volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
	    (volatile uint32_t *)CONSADDR_VA :
	    (volatile uint32_t *)CONSADDR;

	while ((le32toh(uartaddr[(IMX_USR2/4)]) & IMX_USR2_TXDC) == 0)
		;

	uartaddr[(IMX_UTXD/4)] = htole32(c);
#endif
}

static void
imx_platform_device_register(device_t self, void *aux)
{
}

static u_int
imx_platform_uart_freq(void)
{
	return IMX_REF_FREQ;
}

static void
imx_platform_bootstrap(void)
{
#if NARML2CC > 0
	bus_space_tag_t bst = &armv7_generic_bs_tag;
	bus_space_handle_t bsh;
	if (bus_space_map(bst, IMX6_ARMCORE_PBASE, IMX6_ARMCORE_SIZE, 0, &bsh))
		panic("couldn't map armcore registers");
	arml2cc_init(bst, bsh, ARMCORE_L2C_BASE);
	bus_space_unmap(bst, bsh, IMX6_ARMCORE_SIZE);
#endif

	arm_fdt_cpu_bootstrap();
}

static int
imx_platform_mpstart(void)
{
#if defined(MULTIPROCESSOR)
	bus_space_tag_t bst = &armv7_generic_bs_tag;
	bus_space_handle_t bsh;

	if (bus_space_map(bst, IMX6_ARMCORE_PBASE, IMX6_ARMCORE_SIZE, 0, &bsh) != 0)
		panic("couldn't map armcore registers");

	/* Enable Snoop Control Unit */
	bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xff);
	bus_space_write_4(bst, bsh, SCU_CTL,
	    bus_space_read_4(bst, bsh, SCU_CTL) | SCU_CTL_SCU_ENA);

	bus_space_unmap(bst, bsh, AIPS1_SRC_SIZE);

	if (bus_space_map(bst, IMX6_AIPS1_BASE + AIPS1_SRC_BASE, AIPS1_SRC_SIZE, 0, &bsh) != 0)
		panic("couldn't map SRC");


	uint32_t srcctl = bus_space_read_4(bst, bsh, SRC_SCR);
	const paddr_t mpstart = KERN_VTOPHYS((vaddr_t)cpu_mpstart);

	srcctl &= ~(SRC_SCR_CORE1_ENABLE | SRC_SCR_CORE2_ENABLE	 |
	    SRC_SCR_CORE3_ENABLE);
	bus_space_write_4(bst, bsh, SRC_SCR, srcctl);

	for (int i = 1; i < arm_cpu_max; i++) {
		bus_space_write_4(bst, bsh, SRC_GPRN_ENTRY(i), mpstart);
		srcctl |= SRC_SCR_COREN_RST(i);
		srcctl |= SRC_SCR_COREN_ENABLE(i);
	}
	bus_space_write_4(bst, bsh, SRC_SCR, srcctl);

	bus_space_unmap(bst, bsh, AIPS1_SRC_SIZE);

	return arm_fdt_cpu_mpstart();
#endif
}

static void
imx6_platform_reset(void)
{
}

const struct arm_platform imx6_platform = {
	.ap_devmap = imx_platform_devmap,
	.ap_bootstrap = imx_platform_bootstrap,
	.ap_init_attach_args = imx_platform_init_attach_args,
	.ap_device_register = imx_platform_device_register,
	.ap_reset = imx6_platform_reset,
	.ap_delay = a9tmr_delay,
	.ap_uart_freq = imx_platform_uart_freq,
	.ap_mpstart = imx_platform_mpstart,
};

ARM_PLATFORM(imx6, "fsl,imx6q", &imx6_platform);


File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_platform.h
/*	$NetBSD: imx6_platform.h,v 1.1 2019/07/24 13:12:33 hkenken 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.
 */
#ifndef _ARM_IMX_FDT_IMX6_PLATFORM_H
#define _ARM_IMX_FDT_IMX6_PLATFORM_H

#include <arch/evbarm/fdt/platform.h>

#define	KERNEL_IO_IOREG_VBASE		KERNEL_IO_VBASE
#define	KERNEL_IO_ARMCORE_VBASE		(KERNEL_IO_IOREG_VBASE + IMX6_IOREG_SIZE)

#endif /* _ARM_IMX_FDT_IMX6_PLATFORM_H */

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_sdhc.c
/*	$NetBSD: imx6_sdhc.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_sdhc.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/gpio.h>

#include <dev/sdmmc/sdhcreg.h>
#include <dev/sdmmc/sdhcvar.h>
#include <dev/sdmmc/sdmmcvar.h>

#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6var.h>

#include <dev/fdt/fdtvar.h>

static int imx6_sdhc_match(device_t, cfdata_t, void *);
static void imx6_sdhc_attach(device_t, device_t, void *);

static int imx6_sdhc_card_detect(struct sdhc_softc *);

struct imx6_sdhc_softc {
	struct sdhc_softc sc_sdhc;

	bus_space_tag_t		sc_bst;
	bus_space_handle_t	sc_bsh;
	bus_size_t		sc_bsz;

	struct sdhc_host	*sc_host;
	void			*sc_ih;

	struct clk		*sc_clk_per;

	struct fdtbus_gpio_pin	*sc_pin_cd;
};

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
};

static int
imx6_sdhc_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
imx6_sdhc_attach(device_t parent, device_t self, void *aux)
{
	struct imx6_sdhc_softc * const sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	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) {
		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");
	if (sc->sc_clk_per == NULL) {
		aprint_error(": couldn't get clock\n");
		return;
	}

	sc->sc_sdhc.sc_dev = self;
	sc->sc_sdhc.sc_dmat = faa->faa_dmat;

	sc->sc_sdhc.sc_clkbase = clk_get_rate(sc->sc_clk_per) / 1000;
	sc->sc_sdhc.sc_flags =
	    SDHC_FLAG_USE_DMA |
	    SDHC_FLAG_NO_PWR0 |
	    SDHC_FLAG_HAVE_DVS |
	    SDHC_FLAG_32BIT_ACCESS |
	    SDHC_FLAG_8BIT_MODE |
	    SDHC_FLAG_USE_ADMA2 |
	    SDHC_FLAG_USDHC;

	if (bus_width == 8) {
		sc->sc_sdhc.sc_flags |= SDHC_FLAG_8BIT_MODE;
	}
	sc->sc_sdhc.sc_host = &sc->sc_host;

	sc->sc_bst = faa->faa_bst;
	error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
	if (error) {
		aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
		return;
	}
	sc->sc_bsz = size;

	sc->sc_pin_cd = fdtbus_gpio_acquire(faa->faa_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;
	}

	error = clk_enable(sc->sc_clk_per);
	if (error) {
		aprint_error(": couldn't enable clock: %d\n", error);
		return;
	}

	aprint_naive("\n");
	aprint_normal(": SDMMC (%u kHz)\n", sc->sc_sdhc.sc_clkbase);

	if (sc->sc_sdhc.sc_clkbase == 0) {
		aprint_error_dev(self, "couldn't determine frequency\n");
		return;
	}

	if (!fdtbus_intr_str(faa->faa_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, 0,
	    sdhc_intr, &sc->sc_sdhc);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
		    intrstr);
		return;
	}
	aprint_normal_dev(self, "interrupting on %s\n", intrstr);

	error = sdhc_host_found(&sc->sc_sdhc, sc->sc_bst, sc->sc_bsh, sc->sc_bsz);
	if (error) {
		aprint_error_dev(self, "couldn't initialize host, error = %d\n",
		    error);
		fdtbus_intr_disestablish(faa->faa_phandle, sc->sc_ih);
		sc->sc_ih = NULL;
		return;
	}
}

static int
imx6_sdhc_card_detect(struct sdhc_softc *ssc)
{
	struct imx6_sdhc_softc *sc = device_private(ssc->sc_dev);

	KASSERT(sc->sc_pin_cd != NULL);

	return fdtbus_gpio_read(sc->sc_pin_cd);
}


File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_usb.c
/*	$NetBSD: imx6_usb.c,v 1.1 2019/07/24 13:12:33 hkenken 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: imx6_usb.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#include <locators.h>

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/bus.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>

#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>

#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_usbreg.h>
#include <arm/imx/imxusbvar.h>

#include <dev/fdt/fdtvar.h>

struct imxusbc_fdt_softc {
	struct imxusbc_softc sc_imxusbc; /* Must be first */

	int sc_phandle;
};

static int imx6_usb_match(device_t, struct cfdata *, void *);
static void imx6_usb_attach(device_t, device_t, void *);
static int imx6_usb_init_clocks(struct imxusbc_softc *);
static void imx6_usb_init(struct imxehci_softc *);
static void init_otg(struct imxehci_softc *);
static void init_h1(struct imxehci_softc *);
static int imxusbc_print(void *, const char *);
static void *imx6_usb_intr_establish(struct imxehci_softc *);

/* attach structures */
CFATTACH_DECL_NEW(imxusbc_fdt, sizeof(struct imxusbc_fdt_softc),
    imx6_usb_match, imx6_usb_attach, NULL, NULL);

static const char * const compatible[] = {
	"fsl,imx6q-usb",
	NULL
};

static int
imx6_usb_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
imx6_usb_attach(device_t parent, device_t self, void *aux)
{
	struct imxusbc_fdt_softc *ifsc = device_private(self);
	struct imxusbc_softc *sc = &ifsc->sc_imxusbc;
	struct fdt_attach_args * const faa = aux;
	const int phandle = faa->faa_phandle;
	bus_space_tag_t bst = faa->faa_bst;
	bus_space_handle_t bsh;
	bus_addr_t addr;
	bus_size_t size;
	int error;

	aprint_naive("\n");
	aprint_normal("\n");

	ifsc->sc_phandle = phandle;

	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get imxusbc registers\n");
		return;
	}

	error = bus_space_map(bst, addr, size, 0, &bsh);
	if (error) {
		aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
		return;
	}

	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
	if (sc->sc_clk == NULL) {
		aprint_error(": couldn't get clock\n");
		return;
	}

	sc->sc_init_md_hook = imx6_usb_init;
	sc->sc_intr_establish_md_hook = imx6_usb_intr_establish;
	sc->sc_setup_md_hook = NULL;

	sc->sc_dev = self;
	sc->sc_iot = bst;
	sc->sc_ioh = bsh;
	sc->sc_ehci_size = size;
	sc->sc_ehci_offset = 0;

	struct fdt_phandle_data data;
	error = fdtbus_get_phandle_with_data(phandle, "fsl,usbmisc",
	    "#index-cells", 0, &data);
	if (error) {
		aprint_error(": couldn't get usbmisc property\n");
		return;
	}
	int unit = be32toh(data.values[0]);

	if (fdtbus_get_reg(data.phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get usbmisc registers\n");
		return;
	}
	error = bus_space_map(bst, addr, size, 0, &bsh);
	if (error) {
		aprint_error(": couldn't map usbmisc registers: %d\n", error);
		return;
	}
	sc->sc_ioh_usbnc = bsh;

	if (imx6_usb_init_clocks(sc) != 0) {
		aprint_error_dev(self, "couldn't init clocks\n");
		return;
	}

	/* attach OTG/EHCI host controllers */
	struct imxusbc_attach_args iaa;
	iaa.aa_iot = sc->sc_iot;
	iaa.aa_ioh = sc->sc_ioh;
	iaa.aa_dmat = faa->faa_dmat;
	iaa.aa_unit = unit;
	iaa.aa_irq = IMXUSBCCF_IRQ_DEFAULT;
	config_found_sm_loc(self, "imxusbc", NULL, &iaa, imxusbc_print, NULL);

	return;
}

static int
imxusbc_print(void *aux, const char *name __unused)
{
	struct imxusbc_attach_args *iaa;

	iaa = (struct imxusbc_attach_args *)aux;

	aprint_normal(" unit %d intr %d", iaa->aa_unit, iaa->aa_irq);
	return UNCONF;
}


static int
imx6_usb_init_clocks(struct imxusbc_softc *sc)
{
	int error;

	error = clk_enable(sc->sc_clk);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error);
		return error;
	}

	return 0;
}

static void
imx6_usb_init(struct imxehci_softc *sc)
{
	switch (sc->sc_unit) {
	case 0:	/* OTG controller */
		init_otg(sc);
		break;
	case 1:	/* EHCI Host 1 */
		init_h1(sc);
		break;
	case 2:	/* EHCI Host 2 */
	case 3:	/* EHCI Host 3 */
	default:
		aprint_error_dev(sc->sc_dev, "unit %d not supported\n",
		    sc->sc_unit);
	}
}

static void
init_otg(struct imxehci_softc *sc)
{
	struct imxusbc_softc *usbc = sc->sc_usbc;
	uint32_t v;

	sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE;

	imxehci_reset(sc);

	v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_OTG_CTRL);
	v |= USBNC_USB_OTG_CTRL_WKUP_VBUS_EN;
	v |= USBNC_USB_OTG_CTRL_OVER_CUR_DIS;
	v |= USBNC_USB_OTG_CTRL_PWR_POL;
	v &= ~USBNC_USB_OTG_CTRL_UTMI_ON_CLOCK;
	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_OTG_CTRL, v);
}

static void
init_h1(struct imxehci_softc *sc)
{
	struct imxusbc_softc *usbc = sc->sc_usbc;
	uint32_t v;

	sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE;

	v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_UH1_CTRL);
	v |= USBNC_USB_UH1_CTRL_OVER_CUR_POL;
	v |= USBNC_USB_UH1_CTRL_OVER_CUR_DIS;
	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_UH1_CTRL, v);

	/* do reset */
	imxehci_reset(sc);

	/* set mode */
	v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBC_UH1_USBMODE);
	v &= ~USBC_UH_USBMODE_CM;
	v |= __SHIFTIN(USBC_UH_USBMODE_CM, USBC_UH_USBMODE_CM_HOST_CONTROLLER);
	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBC_UH1_USBMODE, v);
}

static void *
imx6_usb_intr_establish(struct imxehci_softc *sc)
{
	struct imxusbc_fdt_softc *ifsc = (struct imxusbc_fdt_softc *)sc->sc_usbc;
	ehci_softc_t *hsc = &sc->sc_hsc;
	void *ih;

	char intrstr[128];
	if (!fdtbus_intr_str(ifsc->sc_phandle, 0, intrstr, sizeof(intrstr))) {
		aprint_error_dev(sc->sc_dev, "failed to decode interrupt\n");
		return NULL;
	}
	ih = fdtbus_intr_establish(ifsc->sc_phandle, 0, IPL_USB, 0, ehci_intr, hsc);
	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;
}

File Added: src/sys/arch/arm/imx/fdt/Attic/imx6_usbphy.c
/*	$NetBSD: imx6_usbphy.c,v 1.1 2019/07/24 13:12:33 hkenken 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(1, "$NetBSD: imx6_usbphy.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");

#include "opt_fdt.h"

#include "locators.h"
#include "ohci.h"
#include "ehci.h"

#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_usbphyreg.h>

#include <dev/fdt/fdtvar.h>

struct imx6_usbphy_softc {
	device_t sc_dev;

	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;

	struct clk *sc_clk;
};

static int imx6_usbphy_match(device_t, cfdata_t, void *);
static void imx6_usbphy_attach(device_t, device_t, void *);

static int imx6_usbphy_init_clocks(device_t);
static int imx6_usbphy_enable(device_t, void *, bool);

CFATTACH_DECL_NEW(imxusbphy, sizeof(struct imx6_usbphy_softc),
    imx6_usbphy_match, imx6_usbphy_attach, NULL, NULL);

static const char * const compatible[] = {
	"fsl,imx6q-usbphy",
	NULL
};

static int
imx6_usbphy_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
imx6_usbphy_attach(device_t parent, device_t self, void *aux)
{
	struct imx6_usbphy_softc *sc = device_private(self);
	struct fdt_attach_args * const faa = aux;
	const int phandle = faa->faa_phandle;
	bus_space_tag_t bst = faa->faa_bst;
	bus_space_handle_t bsh;
	bus_addr_t addr;
	bus_size_t size;
	int error;

	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
		aprint_error(": couldn't get iomux registers\n");
		return;
	}

	error = bus_space_map(bst, addr, size, 0, &bsh);
	if (error) {
		aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
		return;
	}

	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
	if (sc->sc_clk == NULL) {
		aprint_error(": couldn't get clock\n");
		return;
	}

	sc->sc_dev = self;
	sc->sc_iot = bst;
	sc->sc_ioh = bsh;

	aprint_naive("\n");
	aprint_normal(": USB PHY\n");

	imx6_usbphy_init_clocks(self);
	imx6_usbphy_enable(self, NULL, true);
}

static int
imx6_usbphy_init_clocks(device_t dev)
{
	struct imx6_usbphy_softc * const sc = device_private(dev);
	int error;

	error = clk_enable(sc->sc_clk);
	if (error) {
		aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error);
		return error;
	}

	return 0;
}

#define	USBPHY_READ(sc, reg)						      \
	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
#define	USBPHY_WRITE(sc, reg, val)					      \
	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))

static int
imx6_usbphy_enable(device_t dev, void *priv, bool enable)
{
	struct imx6_usbphy_softc * const sc = device_private(dev);

	/* USBPHY enable */
	USBPHY_WRITE(sc, USBPHY_CTRL, USBPHY_CTRL_CLKGATE);

	/* do reset */
	USBPHY_WRITE(sc, USBPHY_CTRL_SET, USBPHY_CTRL_SFTRST);
	delay(100);

	/* clear reset, and run clocks */
	USBPHY_WRITE(sc, USBPHY_CTRL_CLR,
	    USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE);
	delay(100);

	/* power on */
	USBPHY_WRITE(sc, USBPHY_PWD, 0);

	/* UTMI+Level2, Level3 */
	USBPHY_WRITE(sc, USBPHY_CTRL_SET,
	    USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3);

	return 0;
}


File Added: src/sys/arch/evbarm/conf/Attic/IMX
#
#	$NetBSD: IMX,v 1.1 2019/07/24 13:12:34 hkenken Exp $
#
#	NXP(Freescale) I.MX family SoCs
#

include	"arch/evbarm/conf/std.imx"
include	"arch/evbarm/conf/files.imx"
include	"arch/evbarm/conf/GENERIC.common"

makeoptions	DTSGNUARCH="arm"
makeoptions	DTSSUBDIR="fsl"
makeoptions	DTS="
	imx6q-hummingboard.dts
	imx6dl-hummingboard.dts
	imx6q-hummingboard2.dts
	imx6dl-hummingboard2.dts
"

options 	MULTIPROCESSOR

options 	CPU_CORTEXA9

options 	SOC_IMX6Q
options 	SOC_IMX6DL
options 	SOC_IMX6QDL

pseudo-device 	openfirm	# /dev/openfirm

#options 	DIAGNOSTIC	# internal consistency checks
#options 	DEBUG
#options 	LOCKDEBUG
#options 	PMAP_DEBUG	# Enable pmap_debug_level code
#options 	IPKDB		# remote kernel debugging
#options 	VERBOSE_INIT_ARM # verbose bootstrapping messages
# CONSADDR is required for early init messages from VERBOSE_INIT_ARM.
options 	CONSADDR=0x02020000
options 	EARLYCONS=imx
options 	BOOT_ARGS="\"verbose debug\""

makeoptions	DEBUG="-g"	# compile full symbol table
makeoptions	COPY_SYMTAB=1

config		netbsd		root on ? type ?

# Device tree support
armfdt0		at root
simplebus*	at fdt? pass 0

# CPUs
cpus*		at fdt? pass 0
cpu*		at fdt? pass 0

# Timer
a9tmr*		at fdt? pass 2		# A9 Global Timer
arma9tmr0	at a9tmr?

# Interrupt controller
gic*		at fdt? pass 1		# ARM Generic Interrupt Controller
armgic0		at gic?

l2cc*		at fdt? pass 1		# ARM Cortex A9 L2 Cache Controller
arml2cc*	at l2cc?

# Clock
fclock*		at fdt? pass 1
ffclock*	at fdt? pass 1
fregulator*	at fdt? pass 5
gregulator*	at fdt? pass 4
imxccm*		at fdt? pass 1		# i.MX6 ccm

# IOMUX
imxiomux*	at fdt? pass 2

# GPC
imxgpc*		at fdt? pass 2

# GPIO
imxgpio*	at fdt? pass 3
gpio*		at gpiobus?

# UART
imxuart*	at fdt?
options		IMXUARTCONSOLE

# Network Interfaces
enet*		at fdt?			# FEC

# MII/PHY support
atphy*	at mii? phy ?			# Attansic/Atheros PHYs
ukphy*	at mii? phy ?			# generic unknown PHYs

# SATA
ahcisata*	at fdt?			# SATA
atabus* 	at ahcisata? channel ?
wd*		at atabus? drive ?

# ATAPI bus support
atapibus*	at atapi?

# ATAPI devices
# flags have the same meaning as for IDE drives.
cd*		at atapibus? drive ? flags 0x0000	# ATAPI CD-ROM drives
sd*		at atapibus? drive ? flags 0x0000	# ATAPI disk drives
st*		at atapibus? drive ? flags 0x0000	# ATAPI tape drives
uk*		at atapibus? drive ? flags 0x0000	# ATAPI unknown

# SDMMC
sdhc*		at fdt?			# SDMMC
sdmmc*		at sdhc?
ld*		at sdmmc?

# USB
imxusbphy*	at fdt?
imxusbc*	at fdt?
ehci*		at imxusbc?
usb*		at ehci?

# USB device drivers
include "dev/usb/usbdevices.config"

midi*		at midibus?

# PCIe
imxpcie*	at fdt?
#options PCIVERBOSE
#options PCI_CONFIG_DUMP

pci*		at imxpcie?
ppb*		at pci? dev ? function ?
pci*		at ppb?

cinclude "arch/evbarm/conf/IMX.local"


File Added: src/sys/arch/evbarm/conf/Attic/files.imx
#	$NetBSD: files.imx,v 1.1 2019/07/24 13:12:34 hkenken Exp $
#
# NXP(Freescale) i.MX configuration info
#

include "arch/arm/pic/files.pic"
include "arch/arm/cortex/files.cortex"

include "arch/evbarm/conf/files.fdt"

include "arch/arm/imx/fdt/files.imx6"


File Added: src/sys/arch/evbarm/conf/Attic/mk.imx
#	$NetBSD: mk.imx,v 1.1 2019/07/24 13:12:34 hkenken Exp $

.if !empty(MACHINE_ARCH:M*eb)
EXTRA_LINKFLAGS+=	--be8
.endif

ENTRYPOINT=		generic_start

SYSTEM_FIRST_OBJ=	armv6_start.o
SYSTEM_FIRST_SFILE=	${ARM}/arm/armv6_start.S

_OSRELEASE!=		${HOST_SH} $S/conf/osrelease.sh

MKUBOOTIMAGEARGS=	-A arm -T kernel -O linux
MKUBOOTIMAGEARGS+=	-e 0
MKUBOOTIMAGEARGS+=	-n "NetBSD/${BOARDTYPE:U${MACHINE_ARCH}} ${_OSRELEASE}"
MKUBOOTIMAGEARGS+=	-a $(KERNEL_BASE_PHYS) -e $(KERNEL_BASE_PHYS)
MKUBOOTIMAGEARGS_NONE=	${MKUBOOTIMAGEARGS} -C none
MKUBOOTIMAGEARGS_GZ=	${MKUBOOTIMAGEARGS} -C gz

SYSTEM_LD_TAIL_EXTRA+=; \
	echo ${OBJCOPY} -S -O binary $@ $@.bin; \
	${OBJCOPY} -S -O binary $@ $@.bin; \
	echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \
	${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \
	echo ${TOOL_GZIP} -c $@.bin > $@.bin.gz; \
	${TOOL_GZIP} -c $@.bin > $@.bin.gz; \
	echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub; \
	${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub

EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin@}
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.ub@}
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin.gz@}
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.gz.ub@}

File Added: src/sys/arch/evbarm/conf/Attic/std.imx
#	$NetBSD: std.imx,v 1.1 2019/07/24 13:12:34 hkenken Exp $
#

machine		evbarm arm
include		"arch/arm/conf/std.arm"		# arch standard options
include 	"arch/evbarm/conf/std.evbarm"

# Architecture opions
options		ARM_GENERIC_TODR
options 	ARM_HAS_VBAR
options 	ARM_INTR_IMPL="<arch/arm/fdt/fdt_intr.h>"
options 	DRAM_BLOCKS=256
options 	EVBARM_BOARDTYPE="evbarm"
options 	FDT				# Flattened Device Tree support
options 	FPU_VFP
options 	MODULAR
options 	MODULAR_DEFAULT_AUTOLOAD
options 	PCI_NETBSD_CONFIGURE
options 	TPIDRPRW_IS_CURCPU
options 	__BUS_SPACE_HAS_STREAM_METHODS
options 	__HAVE_CPU_COUNTER
options 	__HAVE_CPU_UAREA_ALLOC_IDLELWP
options 	__HAVE_GENERIC_START
options 	__HAVE_GENERIC_CPU_INITCLOCKS
options 	__HAVE_FAST_SOFTINTS		# should be in types.h
options 	__HAVE_PCI_CONF_HOOK
#options 	__HAVE_PCI_MSI_MSIX

makeoptions	BOARDMKFRAG="${THISARM}/conf/mk.imx"

makeoptions 	KERNEL_BASE_PHYS="0x18000000"
makeoptions 	KERNEL_BASE_VIRT="0x80000000"