[Midnightbsd-cvs] src [12402] trunk/sys/arm/allwinner: sync with freebsd 11 stable

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Mar 8 13:23:22 EDT 2020


Revision: 12402
          http://svnweb.midnightbsd.org/src/?rev=12402
Author:   laffer1
Date:     2020-03-08 13:23:22 -0400 (Sun, 08 Mar 2020)
Log Message:
-----------
sync with freebsd 11 stable

Modified Paths:
--------------
    trunk/sys/arm/allwinner/a10_common.c
    trunk/sys/arm/allwinner/a10_ehci.c
    trunk/sys/arm/allwinner/a10_gpio.c
    trunk/sys/arm/allwinner/a10_gpio.h
    trunk/sys/arm/allwinner/a10_sramc.c
    trunk/sys/arm/allwinner/a10_sramc.h
    trunk/sys/arm/allwinner/console.c
    trunk/sys/arm/allwinner/if_emac.c
    trunk/sys/arm/allwinner/if_emacreg.h
    trunk/sys/arm/allwinner/timer.c

Added Paths:
-----------
    trunk/sys/arm/allwinner/a10_ahci.c
    trunk/sys/arm/allwinner/a10_codec.c
    trunk/sys/arm/allwinner/a10_dmac.c
    trunk/sys/arm/allwinner/a10_dmac.h
    trunk/sys/arm/allwinner/a10_fb.c
    trunk/sys/arm/allwinner/a10_hdmi.c
    trunk/sys/arm/allwinner/a10_hdmiaudio.c
    trunk/sys/arm/allwinner/a10_mmc.c
    trunk/sys/arm/allwinner/a10_mmc.h
    trunk/sys/arm/allwinner/a31/
    trunk/sys/arm/allwinner/a31/a31_padconf.c
    trunk/sys/arm/allwinner/a31/a31_r_padconf.c
    trunk/sys/arm/allwinner/a31/a31s_padconf.c
    trunk/sys/arm/allwinner/a31/files.a31
    trunk/sys/arm/allwinner/a31/std.a31
    trunk/sys/arm/allwinner/a83t/
    trunk/sys/arm/allwinner/a83t/a83t_padconf.c
    trunk/sys/arm/allwinner/a83t/a83t_r_padconf.c
    trunk/sys/arm/allwinner/a83t/files.a83t
    trunk/sys/arm/allwinner/a83t/std.a83t
    trunk/sys/arm/allwinner/allwinner_pinctrl.h
    trunk/sys/arm/allwinner/aw_ccu.c
    trunk/sys/arm/allwinner/aw_if_dwc.c
    trunk/sys/arm/allwinner/aw_machdep.c
    trunk/sys/arm/allwinner/aw_machdep.h
    trunk/sys/arm/allwinner/aw_mp.c
    trunk/sys/arm/allwinner/aw_mp.h
    trunk/sys/arm/allwinner/aw_nmi.c
    trunk/sys/arm/allwinner/aw_reset.c
    trunk/sys/arm/allwinner/aw_rsb.c
    trunk/sys/arm/allwinner/aw_rtc.c
    trunk/sys/arm/allwinner/aw_sid.c
    trunk/sys/arm/allwinner/aw_sid.h
    trunk/sys/arm/allwinner/aw_thermal.c
    trunk/sys/arm/allwinner/aw_ts.c
    trunk/sys/arm/allwinner/aw_usbphy.c
    trunk/sys/arm/allwinner/aw_wdog.c
    trunk/sys/arm/allwinner/aw_wdog.h
    trunk/sys/arm/allwinner/axp209.c
    trunk/sys/arm/allwinner/axp209reg.h
    trunk/sys/arm/allwinner/axp81x.c
    trunk/sys/arm/allwinner/files.allwinner
    trunk/sys/arm/allwinner/files.allwinner_up
    trunk/sys/arm/allwinner/h3/
    trunk/sys/arm/allwinner/h3/files.h3
    trunk/sys/arm/allwinner/h3/h3_padconf.c
    trunk/sys/arm/allwinner/h3/h3_r_padconf.c
    trunk/sys/arm/allwinner/h3/std.h3
    trunk/sys/arm/allwinner/if_awg.c
    trunk/sys/arm/allwinner/if_awgreg.h
    trunk/sys/arm/allwinner/std.allwinner
    trunk/sys/arm/allwinner/std.allwinner_up
    trunk/sys/arm/allwinner/sunxi_dma_if.m

Removed Paths:
-------------
    trunk/sys/arm/allwinner/files.a10
    trunk/sys/arm/allwinner/std.a10

Added: trunk/sys/arm/allwinner/a10_ahci.c
===================================================================
--- trunk/sys/arm/allwinner/a10_ahci.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_ahci.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,396 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014-2015 M. Warner Losh <imp at freebsd.org>
+ * Copyright (c) 2015 Luiz Otavio O Souza <loos at freebsd.org>
+ * 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 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 AUTHOR 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.
+ *
+ * The magic-bit-bang sequence used in this code may be based on a linux
+ * platform driver in the Allwinner SDK from Allwinner Technology Co., Ltd.
+ * www.allwinnertech.com, by Daniel Wang <danielwang at allwinnertech.com>
+ * though none of the original code was copied.
+ */
+
+#include "opt_bus.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_ahci.c 346524 2019-04-22 04:56:41Z ian $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <dev/ofw/ofw_bus.h> 
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/ahci/ahci.h>
+#include <dev/extres/clk/clk.h>
+
+/*
+ * Allwinner a1x/a2x/a8x SATA attachment.  This is just the AHCI register
+ * set with a few extra implementation-specific registers that need to
+ * be accounted for.  There's only one PHY in the system, and it needs
+ * to be trained to bring the link up.  In addition, there's some DMA
+ * specific things that need to be done as well.  These things are also
+ * just about completely undocumented, except in ugly code in the Linux
+ * SDK Allwinner releases.
+ */
+
+/* BITx -- Unknown bit that needs to be set/cleared at position x */
+/* UFx -- Uknown multi-bit field frobbed during init */
+#define	AHCI_BISTAFR	0x00A0
+#define	AHCI_BISTCR	0x00A4
+#define	AHCI_BISTFCTR	0x00A8
+#define	AHCI_BISTSR	0x00AC
+#define	AHCI_BISTDECR	0x00B0
+#define	AHCI_DIAGNR	0x00B4
+#define	AHCI_DIAGNR1	0x00B8
+#define	AHCI_OOBR	0x00BC
+#define	AHCI_PHYCS0R	0x00C0
+/* Bits 0..17 are a mystery */
+#define	 PHYCS0R_BIT18			(1 << 18)
+#define	 PHYCS0R_POWER_ENABLE		(1 << 19)
+#define	 PHYCS0R_UF1_MASK		(7 << 20)	/* Unknown Field 1 */
+#define	  PHYCS0R_UF1_INIT		(3 << 20)
+#define	 PHYCS0R_BIT23			(1 << 23)
+#define	 PHYCS0R_UF2_MASK		(7 << 24)	/* Uknown Field 2 */
+#define	  PHYCS0R_UF2_INIT		(5 << 24)
+/* Bit 27 mystery */
+#define	 PHYCS0R_POWER_STATUS_MASK	(7 << 28)
+#define	  PHYCS0R_PS_GOOD		(2 << 28)
+/* Bit 31 mystery */
+#define	AHCI_PHYCS1R	0x00C4
+/* Bits 0..5 are a mystery */
+#define	 PHYCS1R_UF1_MASK		(3 << 6)
+#define	  PHYCS1R_UF1_INIT		(2 << 6)
+#define	 PHYCS1R_UF2_MASK		(0x1f << 8)
+#define	  PHYCS1R_UF2_INIT		(6 << 8)
+/* Bits 13..14 are a mystery */
+#define	 PHYCS1R_BIT15			(1 << 15)
+#define	 PHYCS1R_UF3_MASK		(3 << 16)
+#define	  PHYCS1R_UF3_INIT		(2 << 16)
+/* Bit 18 mystery */
+#define	 PHYCS1R_HIGHZ			(1 << 19)
+/* Bits 20..27 mystery */
+#define	 PHYCS1R_BIT28			(1 << 28)
+/* Bits 29..31 mystery */
+#define	AHCI_PHYCS2R	0x00C8
+/* bits 0..4 mystery */
+#define	 PHYCS2R_UF1_MASK		(0x1f << 5)
+#define	  PHYCS2R_UF1_INIT		(0x19 << 5)
+/* Bits 10..23 mystery */
+#define	 PHYCS2R_CALIBRATE		(1 << 24)
+/* Bits 25..31 mystery */
+#define	AHCI_TIMER1MS	0x00E0
+#define	AHCI_GPARAM1R	0x00E8
+#define	AHCI_GPARAM2R	0x00EC
+#define	AHCI_PPARAMR	0x00F0
+#define	AHCI_TESTR	0x00F4
+#define	AHCI_VERSIONR	0x00F8
+#define	AHCI_IDR	0x00FC
+#define	AHCI_RWCR	0x00FC
+
+#define	AHCI_P0DMACR	0x0070
+#define	AHCI_P0PHYCR	0x0078
+#define	AHCI_P0PHYSR	0x007C
+
+#define	PLL_FREQ	100000000
+
+static void inline
+ahci_set(struct resource *m, bus_size_t off, uint32_t set)
+{
+	uint32_t val = ATA_INL(m, off);
+
+	val |= set;
+	ATA_OUTL(m, off, val);
+}
+
+static void inline
+ahci_clr(struct resource *m, bus_size_t off, uint32_t clr)
+{
+	uint32_t val = ATA_INL(m, off);
+
+	val &= ~clr;
+	ATA_OUTL(m, off, val);
+}
+
+static void inline
+ahci_mask_set(struct resource *m, bus_size_t off, uint32_t mask, uint32_t set)
+{
+	uint32_t val = ATA_INL(m, off);
+
+	val &= mask;
+	val |= set;
+	ATA_OUTL(m, off, val);
+}
+
+/*
+ * Should this be phy_reset or phy_init
+ */
+#define	PHY_RESET_TIMEOUT	1000
+static void
+ahci_a10_phy_reset(device_t dev)
+{
+	uint32_t to, val;
+	struct ahci_controller *ctlr = device_get_softc(dev);
+
+	/*
+	 * Here starts the magic -- most of the comments are based
+	 * on guesswork, names of routines and printf error
+	 * messages.  The code works, but it will do that even if the
+	 * comments are 100% BS.
+	 */
+
+	/*
+	 * Lock out other access while we initialize.  Or at least that
+	 * seems to be the case based on Linux SDK #defines.  Maybe this
+	 * put things into reset?
+	 */
+	ATA_OUTL(ctlr->r_mem, AHCI_RWCR, 0);
+	DELAY(100);
+
+	/*
+	 * Set bit 19 in PHYCS1R.  Guessing this disables driving the PHY
+	 * port for a bit while we reset things.
+	 */
+	ahci_set(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_HIGHZ);
+
+	/*
+	 * Frob PHYCS0R...
+	 */
+	ahci_mask_set(ctlr->r_mem, AHCI_PHYCS0R,
+	    ~PHYCS0R_UF2_MASK,
+	    PHYCS0R_UF2_INIT | PHYCS0R_BIT23 | PHYCS0R_BIT18);
+
+	/*
+	 * Set three fields in PHYCS1R
+	 */
+	ahci_mask_set(ctlr->r_mem, AHCI_PHYCS1R,
+	    ~(PHYCS1R_UF1_MASK | PHYCS1R_UF2_MASK | PHYCS1R_UF3_MASK),
+	    PHYCS1R_UF1_INIT | PHYCS1R_UF2_INIT | PHYCS1R_UF3_INIT);
+
+	/*
+	 * Two more mystery bits in PHYCS1R. -- can these be combined above?
+	 */
+	ahci_set(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_BIT15 | PHYCS1R_BIT28);
+
+	/*
+	 * Now clear that first mysery bit.  Perhaps this starts
+	 * driving the PHY again so we can power it up and start
+	 * talking to the SATA drive, if any below.
+	 */
+	ahci_clr(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_HIGHZ);
+
+	/*
+	 * Frob PHYCS0R again...
+	 */
+	ahci_mask_set(ctlr->r_mem, AHCI_PHYCS0R,
+	    ~PHYCS0R_UF1_MASK, PHYCS0R_UF1_INIT);
+
+	/*
+	 * Frob PHYCS2R, because 25 means something?
+	 */
+	ahci_mask_set(ctlr->r_mem, AHCI_PHYCS2R, ~PHYCS2R_UF1_MASK,
+	    PHYCS2R_UF1_INIT);
+
+	DELAY(100);		/* WAG */
+
+	/*
+	 * Turn on the power to the PHY and wait for it to report back
+	 * good?
+	 */
+	ahci_set(ctlr->r_mem, AHCI_PHYCS0R, PHYCS0R_POWER_ENABLE);
+	for (to = PHY_RESET_TIMEOUT; to > 0; to--) {
+		val = ATA_INL(ctlr->r_mem, AHCI_PHYCS0R);
+		if ((val & PHYCS0R_POWER_STATUS_MASK) == PHYCS0R_PS_GOOD)
+			break;
+		DELAY(10);
+	}
+	if (to == 0 && bootverbose)
+		device_printf(dev, "PHY Power Failed PHYCS0R = %#x\n", val);
+
+	/*
+	 * Calibrate the clocks between the device and the host.  This appears
+	 * to be an automated process that clears the bit when it is done.
+	 */
+	ahci_set(ctlr->r_mem, AHCI_PHYCS2R, PHYCS2R_CALIBRATE);
+	for (to = PHY_RESET_TIMEOUT; to > 0; to--) {
+		val = ATA_INL(ctlr->r_mem, AHCI_PHYCS2R);
+		if ((val & PHYCS2R_CALIBRATE) == 0)
+			break;
+		DELAY(10);
+	}
+	if (to == 0 && bootverbose)
+		device_printf(dev, "PHY Cal Failed PHYCS2R %#x\n", val);
+
+	/*
+	 * OK, let things settle down a bit.
+	 */
+	DELAY(1000);
+
+	/*
+	 * Go back into normal mode now that we've calibrated the PHY.
+	 */
+	ATA_OUTL(ctlr->r_mem, AHCI_RWCR, 7);
+}
+
+static void
+ahci_a10_ch_start(struct ahci_channel *ch)
+{
+	uint32_t reg;
+
+	/*
+	 * Magical values from Allwinner SDK, setup the DMA before start
+	 * operations on this channel.
+	 */
+	reg = ATA_INL(ch->r_mem, AHCI_P0DMACR);
+	reg &= ~0xff00;
+	reg |= 0x4400;
+	ATA_OUTL(ch->r_mem, AHCI_P0DMACR, reg);
+}
+
+static int
+ahci_a10_ctlr_reset(device_t dev)
+{
+
+	ahci_a10_phy_reset(dev);
+
+	return (ahci_ctlr_reset(dev));
+}
+
+static int
+ahci_a10_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-ahci"))
+		return (ENXIO);
+	device_set_desc(dev, "Allwinner Integrated AHCI controller");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ahci_a10_attach(device_t dev)
+{
+	int error;
+	struct ahci_controller *ctlr;
+	clk_t clk_pll, clk_gate;
+
+	ctlr = device_get_softc(dev);
+	clk_pll = clk_gate = NULL;
+
+	ctlr->quirks = AHCI_Q_NOPMP;
+	ctlr->vendorid = 0;
+	ctlr->deviceid = 0;
+	ctlr->subvendorid = 0;
+	ctlr->subdeviceid = 0;
+	ctlr->r_rid = 0;
+	if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &ctlr->r_rid, RF_ACTIVE)))
+		return (ENXIO);
+
+	/* Enable clocks */
+	error = clk_get_by_ofw_index(dev, 0, 0, &clk_pll);
+	if (error != 0) {
+		device_printf(dev, "Cannot get PLL clock\n");
+		goto fail;
+	}
+	error = clk_get_by_ofw_index(dev, 0, 1, &clk_gate);
+	if (error != 0) {
+		device_printf(dev, "Cannot get gate clock\n");
+		goto fail;
+	}
+	error = clk_set_freq(clk_pll, PLL_FREQ, CLK_SET_ROUND_DOWN);
+	if (error != 0) {
+		device_printf(dev, "Cannot set PLL frequency\n");
+		goto fail;
+	}
+	error = clk_enable(clk_pll);
+	if (error != 0) {
+		device_printf(dev, "Cannot enable PLL\n");
+		goto fail;
+	}
+	error = clk_enable(clk_gate);
+	if (error != 0) {
+		device_printf(dev, "Cannot enable clk gate\n");
+		goto fail;
+	}
+	
+	/* Reset controller */
+	if ((error = ahci_a10_ctlr_reset(dev)) != 0)
+		goto fail;
+
+	/*
+	 * No MSI registers on this platform.
+	 */
+	ctlr->msi = 0;
+	ctlr->numirqs = 1;
+
+	/* Channel start callback(). */
+	ctlr->ch_start = ahci_a10_ch_start;
+
+	/*
+	 * Note: ahci_attach will release ctlr->r_mem on errors automatically
+	 */
+	return (ahci_attach(dev));
+
+fail:
+	if (clk_gate != NULL)
+		clk_release(clk_gate);
+	if (clk_pll != NULL)
+		clk_release(clk_pll);
+	bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
+	return (error);
+}
+
+static int
+ahci_a10_detach(device_t dev)
+{
+
+	return (ahci_detach(dev));
+}
+
+static device_method_t ahci_ata_methods[] = {
+	DEVMETHOD(device_probe,     ahci_a10_probe),
+	DEVMETHOD(device_attach,    ahci_a10_attach),
+	DEVMETHOD(device_detach,    ahci_a10_detach),
+	DEVMETHOD(bus_print_child,  ahci_print_child),
+	DEVMETHOD(bus_alloc_resource,       ahci_alloc_resource),
+	DEVMETHOD(bus_release_resource,     ahci_release_resource),
+	DEVMETHOD(bus_setup_intr,   ahci_setup_intr),
+	DEVMETHOD(bus_teardown_intr,ahci_teardown_intr),
+	DEVMETHOD(bus_child_location_str, ahci_child_location_str),
+	DEVMETHOD_END
+};
+
+static driver_t ahci_ata_driver = {
+        "ahci",
+        ahci_ata_methods,
+        sizeof(struct ahci_controller)
+};
+
+DRIVER_MODULE(a10_ahci, simplebus, ahci_ata_driver, ahci_devclass, 0, 0);


Property changes on: trunk/sys/arm/allwinner/a10_ahci.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a10_codec.c
===================================================================
--- trunk/sys/arm/allwinner/a10_codec.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_codec.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,886 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_codec.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner A10/A20 Audio Codec
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_codec.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/chip.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include "sunxi_dma_if.h"
+#include "mixer_if.h"
+#include "gpio_if.h"
+
+#define	TX_TRIG_LEVEL	0xf
+#define	RX_TRIG_LEVEL	0x7
+#define	DRQ_CLR_CNT	0x3
+
+#define	AC_DAC_DPC	0x00
+#define	 DAC_DPC_EN_DA			0x80000000
+#define	AC_DAC_FIFOC	0x04
+#define	 DAC_FIFOC_FS_SHIFT		29
+#define	 DAC_FIFOC_FS_MASK		(7U << DAC_FIFOC_FS_SHIFT)
+#define	  DAC_FS_48KHZ			0
+#define	  DAC_FS_32KHZ			1
+#define	  DAC_FS_24KHZ			2
+#define	  DAC_FS_16KHZ			3
+#define	  DAC_FS_12KHZ			4
+#define	  DAC_FS_8KHZ			5
+#define	  DAC_FS_192KHZ			6
+#define	  DAC_FS_96KHZ			7
+#define	 DAC_FIFOC_FIFO_MODE_SHIFT	24
+#define	 DAC_FIFOC_FIFO_MODE_MASK	(3U << DAC_FIFOC_FIFO_MODE_SHIFT)
+#define	  FIFO_MODE_24_31_8		0
+#define	  FIFO_MODE_16_31_16		0
+#define	  FIFO_MODE_16_15_0		1
+#define	 DAC_FIFOC_DRQ_CLR_CNT_SHIFT	21
+#define	 DAC_FIFOC_DRQ_CLR_CNT_MASK	(3U << DAC_FIFOC_DRQ_CLR_CNT_SHIFT)
+#define	 DAC_FIFOC_TX_TRIG_LEVEL_SHIFT	8
+#define	 DAC_FIFOC_TX_TRIG_LEVEL_MASK	(0x7f << DAC_FIFOC_TX_TRIG_LEVEL_SHIFT)
+#define	 DAC_FIFOC_MONO_EN		(1U << 6)
+#define	 DAC_FIFOC_TX_BITS		(1U << 5)
+#define	 DAC_FIFOC_DRQ_EN		(1U << 4)
+#define	 DAC_FIFOC_FIFO_FLUSH		(1U << 0)
+#define	AC_DAC_FIFOS	0x08
+#define	AC_DAC_TXDATA	0x0c
+#define	AC_DAC_ACTL	0x10
+#define	 DAC_ACTL_DACAREN		(1U << 31)
+#define	 DAC_ACTL_DACALEN		(1U << 30)
+#define	 DAC_ACTL_MIXEN			(1U << 29)
+#define	 DAC_ACTL_DACPAS		(1U << 8)
+#define	 DAC_ACTL_PAMUTE		(1U << 6)
+#define	 DAC_ACTL_PAVOL_SHIFT		0
+#define	 DAC_ACTL_PAVOL_MASK		(0x3f << DAC_ACTL_PAVOL_SHIFT)
+#define	AC_ADC_FIFOC	0x1c
+#define	 ADC_FIFOC_FS_SHIFT		29
+#define	 ADC_FIFOC_FS_MASK		(7U << ADC_FIFOC_FS_SHIFT)
+#define	  ADC_FS_48KHZ		0
+#define	 ADC_FIFOC_EN_AD		(1U << 28)
+#define	 ADC_FIFOC_RX_FIFO_MODE		(1U << 24)
+#define	 ADC_FIFOC_RX_TRIG_LEVEL_SHIFT	8
+#define	 ADC_FIFOC_RX_TRIG_LEVEL_MASK	(0x1f << ADC_FIFOC_RX_TRIG_LEVEL_SHIFT)
+#define	 ADC_FIFOC_MONO_EN		(1U << 7)
+#define	 ADC_FIFOC_RX_BITS		(1U << 6)
+#define	 ADC_FIFOC_DRQ_EN		(1U << 4)
+#define	 ADC_FIFOC_FIFO_FLUSH		(1U << 1)
+#define	AC_ADC_FIFOS	0x20
+#define	AC_ADC_RXDATA	0x24
+#define	AC_ADC_ACTL	0x28
+#define	 ADC_ACTL_ADCREN		(1U << 31)
+#define	 ADC_ACTL_ADCLEN		(1U << 30)
+#define	 ADC_ACTL_PREG1EN		(1U << 29)
+#define	 ADC_ACTL_PREG2EN		(1U << 28)
+#define	 ADC_ACTL_VMICEN		(1U << 27)
+#define	 ADC_ACTL_ADCG_SHIFT		20
+#define	 ADC_ACTL_ADCG_MASK		(7U << ADC_ACTL_ADCG_SHIFT)
+#define	 ADC_ACTL_ADCIS_SHIFT		17
+#define	 ADC_ACTL_ADCIS_MASK		(7U << ADC_ACTL_ADCIS_SHIFT)
+#define	  ADC_IS_LINEIN			0
+#define	  ADC_IS_FMIN			1
+#define	  ADC_IS_MIC1			2
+#define	  ADC_IS_MIC2			3
+#define	  ADC_IS_MIC1_L_MIC2_R		4
+#define	  ADC_IS_MIC1_LR_MIC2_LR	5
+#define	  ADC_IS_OMIX			6
+#define	  ADC_IS_LINEIN_L_MIC1_R	7
+#define	 ADC_ACTL_LNRDF			(1U << 16)
+#define	 ADC_ACTL_LNPREG_SHIFT		13
+#define	 ADC_ACTL_LNPREG_MASK		(7U << ADC_ACTL_LNPREG_SHIFT)
+#define	 ADC_ACTL_PA_EN			(1U << 4)
+#define	 ADC_ACTL_DDE			(1U << 3)
+#define	AC_DAC_CNT	0x30
+#define	AC_ADC_CNT	0x34
+
+static uint32_t a10codec_fmt[] = {
+	SND_FORMAT(AFMT_S16_LE, 1, 0),
+	SND_FORMAT(AFMT_S16_LE, 2, 0),
+	0
+};
+
+static struct pcmchan_caps a10codec_pcaps = { 8000, 192000, a10codec_fmt, 0 };
+static struct pcmchan_caps a10codec_rcaps = { 8000, 48000, a10codec_fmt, 0 };
+
+struct a10codec_info;
+
+struct a10codec_chinfo {
+	struct snd_dbuf		*buffer;
+	struct pcm_channel	*channel;	
+	struct a10codec_info	*parent;
+	bus_dmamap_t		dmamap;
+	void			*dmaaddr;
+	bus_addr_t		physaddr;
+	bus_size_t		fifo;
+	device_t		dmac;
+	void			*dmachan;
+
+	int			dir;
+	int			run;
+	uint32_t		pos;
+	uint32_t		format;
+	uint32_t		blocksize;
+	uint32_t		speed;
+};
+
+struct a10codec_info {
+	device_t		dev;
+	struct resource		*res[2];
+	struct mtx		*lock;
+	bus_dma_tag_t		dmat;
+	unsigned		dmasize;
+	void			*ih;
+
+	unsigned		drqtype_codec;
+	unsigned		drqtype_sdram;
+
+	struct a10codec_chinfo	play;
+	struct a10codec_chinfo	rec;
+};
+
+static struct resource_spec a10codec_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	CODEC_READ(sc, reg)		bus_read_4((sc)->res[0], (reg))
+#define	CODEC_WRITE(sc, reg, val)	bus_write_4((sc)->res[0], (reg), (val))
+
+/*
+ * Mixer interface
+ */
+
+static int
+a10codec_mixer_init(struct snd_mixer *m)
+{
+	struct a10codec_info *sc = mix_getdevinfo(m);
+	pcell_t prop[4];
+	phandle_t node;
+	device_t gpio;
+	uint32_t val;
+	ssize_t len;
+	int pin;
+
+	mix_setdevs(m, SOUND_MASK_VOLUME | SOUND_MASK_LINE | SOUND_MASK_RECLEV);
+	mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC);
+
+	/* Unmute input source to PA */
+	val = CODEC_READ(sc, AC_DAC_ACTL);
+	val |= DAC_ACTL_PAMUTE;
+	CODEC_WRITE(sc, AC_DAC_ACTL, val);
+
+	/* Enable PA */
+	val = CODEC_READ(sc, AC_ADC_ACTL);
+	val |= ADC_ACTL_PA_EN;
+	CODEC_WRITE(sc, AC_ADC_ACTL, val);
+
+	/* Unmute PA */
+	node = ofw_bus_get_node(sc->dev);
+	len = OF_getencprop(node, "allwinner,pa-gpios", prop, sizeof(prop));
+	if (len > 0 && (len / sizeof(prop[0])) == 4) {
+		gpio = OF_device_from_xref(prop[0]);
+		if (gpio != NULL) {
+			pin = prop[1] * 32 + prop[2];
+			GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT);
+			GPIO_PIN_SET(gpio, pin, GPIO_PIN_LOW);
+		}
+	}
+
+	return (0);
+}
+
+static const struct a10codec_mixer {
+	unsigned reg;
+	unsigned mask;
+	unsigned shift;
+} a10codec_mixers[SOUND_MIXER_NRDEVICES] = {
+	[SOUND_MIXER_VOLUME]	= { AC_DAC_ACTL, DAC_ACTL_PAVOL_MASK,
+				    DAC_ACTL_PAVOL_SHIFT },
+	[SOUND_MIXER_LINE]	= { AC_ADC_ACTL, ADC_ACTL_LNPREG_MASK,
+				    ADC_ACTL_LNPREG_SHIFT },
+	[SOUND_MIXER_RECLEV]	= { AC_ADC_ACTL, ADC_ACTL_ADCG_MASK,
+				    ADC_ACTL_ADCG_SHIFT },
+}; 
+
+static int
+a10codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left,
+    unsigned right)
+{
+	struct a10codec_info *sc = mix_getdevinfo(m);
+	uint32_t val;
+	unsigned nvol, max;
+
+	max = a10codec_mixers[dev].mask >> a10codec_mixers[dev].shift;
+	nvol = (left * max) / 100;
+
+	val = CODEC_READ(sc, a10codec_mixers[dev].reg);
+	val &= ~a10codec_mixers[dev].mask;
+	val |= (nvol << a10codec_mixers[dev].shift);
+	CODEC_WRITE(sc, a10codec_mixers[dev].reg, val);
+
+	left = right = (left * 100) / max;
+	return (left | (right << 8));
+}
+
+static uint32_t
+a10codec_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
+{
+	struct a10codec_info *sc = mix_getdevinfo(m);
+	uint32_t val;
+
+	val = CODEC_READ(sc, AC_ADC_ACTL);
+
+	switch (src) {
+	case SOUND_MASK_LINE:	/* line-in */
+		val &= ~ADC_ACTL_ADCIS_MASK;
+		val |= (ADC_IS_LINEIN << ADC_ACTL_ADCIS_SHIFT);
+		break;
+	case SOUND_MASK_MIC:	/* MIC1 */
+		val &= ~ADC_ACTL_ADCIS_MASK;
+		val |= (ADC_IS_MIC1 << ADC_ACTL_ADCIS_SHIFT);
+		break;
+	case SOUND_MASK_LINE1:	/* MIC2 */
+		val &= ~ADC_ACTL_ADCIS_MASK;
+		val |= (ADC_IS_MIC2 << ADC_ACTL_ADCIS_SHIFT);
+		break;
+	default:
+		break;
+	}
+
+	CODEC_WRITE(sc, AC_ADC_ACTL, val);
+
+	switch ((val & ADC_ACTL_ADCIS_MASK) >> ADC_ACTL_ADCIS_SHIFT) {
+	case ADC_IS_LINEIN:
+		return (SOUND_MASK_LINE);
+	case ADC_IS_MIC1:
+		return (SOUND_MASK_MIC);
+	case ADC_IS_MIC2:
+		return (SOUND_MASK_LINE1);
+	default:
+		return (0);
+	}
+}
+
+static kobj_method_t a10codec_mixer_methods[] = {
+	KOBJMETHOD(mixer_init,		a10codec_mixer_init),
+	KOBJMETHOD(mixer_set,		a10codec_mixer_set),
+	KOBJMETHOD(mixer_setrecsrc,	a10codec_mixer_setrecsrc),
+	KOBJMETHOD_END
+};
+MIXER_DECLARE(a10codec_mixer);
+
+
+/*
+ * Channel interface
+ */
+
+static void
+a10codec_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	struct a10codec_chinfo *ch = arg;
+
+	if (error != 0)
+		return;
+
+	ch->physaddr = segs[0].ds_addr;
+}
+
+static void
+a10codec_transfer(struct a10codec_chinfo *ch)
+{
+	bus_addr_t src, dst;
+	int error;
+
+	if (ch->dir == PCMDIR_PLAY) {
+		src = ch->physaddr + ch->pos;
+		dst = ch->fifo;
+	} else {
+		src = ch->fifo;
+		dst = ch->physaddr + ch->pos;
+	}
+
+	error = SUNXI_DMA_TRANSFER(ch->dmac, ch->dmachan, src, dst,
+	    ch->blocksize);
+	if (error) {
+		ch->run = 0;
+		device_printf(ch->parent->dev, "DMA transfer failed: %d\n",
+		    error);
+	}
+}
+
+static void
+a10codec_dmaconfig(struct a10codec_chinfo *ch)
+{
+	struct a10codec_info *sc = ch->parent;
+	struct sunxi_dma_config conf;
+
+	memset(&conf, 0, sizeof(conf));
+	conf.src_width = conf.dst_width = 16;
+	conf.src_burst_len = conf.dst_burst_len = 4;
+
+	if (ch->dir == PCMDIR_PLAY) {
+		conf.dst_noincr = true;
+		conf.src_drqtype = sc->drqtype_sdram;
+		conf.dst_drqtype = sc->drqtype_codec;
+	} else {
+		conf.src_noincr = true;
+		conf.src_drqtype = sc->drqtype_codec;
+		conf.dst_drqtype = sc->drqtype_sdram;
+	}
+
+	SUNXI_DMA_SET_CONFIG(ch->dmac, ch->dmachan, &conf);
+}
+
+static void
+a10codec_dmaintr(void *priv)
+{
+	struct a10codec_chinfo *ch = priv;
+	unsigned bufsize;
+
+	bufsize = sndbuf_getsize(ch->buffer);
+
+	ch->pos += ch->blocksize;
+	if (ch->pos >= bufsize)
+		ch->pos -= bufsize;
+
+	if (ch->run) {
+		chn_intr(ch->channel);
+		a10codec_transfer(ch);
+	}
+}
+
+static unsigned
+a10codec_fs(struct a10codec_chinfo *ch)
+{
+	switch (ch->speed) {
+	case 48000:
+		return (DAC_FS_48KHZ);
+	case 24000:
+		return (DAC_FS_24KHZ);
+	case 12000:
+		return (DAC_FS_12KHZ);
+	case 192000:
+		return (DAC_FS_192KHZ);
+	case 32000:
+		return (DAC_FS_32KHZ);
+	case 16000:
+		return (DAC_FS_16KHZ);
+	case 8000:
+		return (DAC_FS_8KHZ);
+	case 96000:
+		return (DAC_FS_96KHZ);
+	default:
+		return (DAC_FS_48KHZ);
+	}
+}
+
+static void
+a10codec_start(struct a10codec_chinfo *ch)
+{
+	struct a10codec_info *sc = ch->parent;
+	uint32_t val;
+
+	ch->pos = 0;
+
+	if (ch->dir == PCMDIR_PLAY) {
+		/* Flush DAC FIFO */
+		CODEC_WRITE(sc, AC_DAC_FIFOC, DAC_FIFOC_FIFO_FLUSH);
+
+		/* Clear DAC FIFO status */
+		CODEC_WRITE(sc, AC_DAC_FIFOS, CODEC_READ(sc, AC_DAC_FIFOS));
+
+		/* Enable DAC analog left/right channels and output mixer */
+		val = CODEC_READ(sc, AC_DAC_ACTL);
+		val |= DAC_ACTL_DACAREN;
+		val |= DAC_ACTL_DACALEN;
+		val |= DAC_ACTL_DACPAS;
+		CODEC_WRITE(sc, AC_DAC_ACTL, val);
+
+		/* Configure DAC DMA channel */
+		a10codec_dmaconfig(ch);
+
+		/* Configure DAC FIFO */
+		CODEC_WRITE(sc, AC_DAC_FIFOC,
+		    (AFMT_CHANNEL(ch->format) == 1 ? DAC_FIFOC_MONO_EN : 0) |
+		    (a10codec_fs(ch) << DAC_FIFOC_FS_SHIFT) |
+		    (FIFO_MODE_16_15_0 << DAC_FIFOC_FIFO_MODE_SHIFT) |
+		    (DRQ_CLR_CNT << DAC_FIFOC_DRQ_CLR_CNT_SHIFT) |
+		    (TX_TRIG_LEVEL << DAC_FIFOC_TX_TRIG_LEVEL_SHIFT));
+
+		/* Enable DAC DRQ */
+		val = CODEC_READ(sc, AC_DAC_FIFOC);
+		val |= DAC_FIFOC_DRQ_EN;
+		CODEC_WRITE(sc, AC_DAC_FIFOC, val);
+	} else {
+		/* Flush ADC FIFO */
+		CODEC_WRITE(sc, AC_ADC_FIFOC, ADC_FIFOC_FIFO_FLUSH);
+
+		/* Clear ADC FIFO status */
+		CODEC_WRITE(sc, AC_ADC_FIFOS, CODEC_READ(sc, AC_ADC_FIFOS));
+
+		/* Enable ADC analog left/right channels, MIC1 preamp,
+		 * and VMIC pin voltage
+		 */
+		val = CODEC_READ(sc, AC_ADC_ACTL);
+		val |= ADC_ACTL_ADCREN;
+		val |= ADC_ACTL_ADCLEN;
+		val |= ADC_ACTL_PREG1EN;
+		val |= ADC_ACTL_VMICEN;
+		CODEC_WRITE(sc, AC_ADC_ACTL, val);
+
+		/* Configure ADC DMA channel */
+		a10codec_dmaconfig(ch);
+
+		/* Configure ADC FIFO */
+		CODEC_WRITE(sc, AC_ADC_FIFOC,
+		    ADC_FIFOC_EN_AD |
+		    ADC_FIFOC_RX_FIFO_MODE |
+		    (AFMT_CHANNEL(ch->format) == 1 ? ADC_FIFOC_MONO_EN : 0) |
+		    (a10codec_fs(ch) << ADC_FIFOC_FS_SHIFT) |
+		    (RX_TRIG_LEVEL << ADC_FIFOC_RX_TRIG_LEVEL_SHIFT));
+
+		/* Enable ADC DRQ */
+		val = CODEC_READ(sc, AC_ADC_FIFOC);
+		val |= ADC_FIFOC_DRQ_EN;
+		CODEC_WRITE(sc, AC_ADC_FIFOC, val);
+	}
+
+	/* Start DMA transfer */
+	a10codec_transfer(ch);
+}
+
+static void
+a10codec_stop(struct a10codec_chinfo *ch)
+{
+	struct a10codec_info *sc = ch->parent;
+	uint32_t val;
+
+	/* Disable DMA channel */
+	SUNXI_DMA_HALT(ch->dmac, ch->dmachan);
+
+	if (ch->dir == PCMDIR_PLAY) {
+		/* Disable DAC analog left/right channels and output mixer */
+		val = CODEC_READ(sc, AC_DAC_ACTL);
+		val &= ~DAC_ACTL_DACAREN;
+		val &= ~DAC_ACTL_DACALEN;
+		val &= ~DAC_ACTL_DACPAS;
+		CODEC_WRITE(sc, AC_DAC_ACTL, val);
+
+		/* Disable DAC DRQ */
+		CODEC_WRITE(sc, AC_DAC_FIFOC, 0);
+	} else {
+		/* Disable ADC analog left/right channels, MIC1 preamp,
+		 * and VMIC pin voltage
+		 */
+		val = CODEC_READ(sc, AC_ADC_ACTL);
+		val &= ~ADC_ACTL_ADCREN;
+		val &= ~ADC_ACTL_ADCLEN;
+		val &= ~ADC_ACTL_PREG1EN;
+		val &= ~ADC_ACTL_VMICEN;
+		CODEC_WRITE(sc, AC_ADC_ACTL, val);
+
+		/* Disable ADC DRQ */
+		CODEC_WRITE(sc, AC_ADC_FIFOC, 0);
+	}
+}
+
+static void *
+a10codec_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
+    struct pcm_channel *c, int dir)
+{
+	struct a10codec_info *sc = devinfo;
+	struct a10codec_chinfo *ch = dir == PCMDIR_PLAY ? &sc->play : &sc->rec;
+	int error;
+
+	ch->parent = sc;
+	ch->channel = c;
+	ch->buffer = b;
+	ch->dir = dir;
+	ch->fifo = rman_get_start(sc->res[0]) +
+	    (dir == PCMDIR_REC ? AC_ADC_RXDATA : AC_DAC_TXDATA);
+
+	ch->dmac = devclass_get_device(devclass_find("a10dmac"), 0);
+	if (ch->dmac == NULL) {
+		device_printf(sc->dev, "cannot find DMA controller\n");
+		return (NULL);
+	}
+	ch->dmachan = SUNXI_DMA_ALLOC(ch->dmac, false, a10codec_dmaintr, ch);
+	if (ch->dmachan == NULL) {
+		device_printf(sc->dev, "cannot allocate DMA channel\n");
+		return (NULL);
+	}
+
+	error = bus_dmamem_alloc(sc->dmat, &ch->dmaaddr,
+	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &ch->dmamap);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot allocate channel buffer\n");
+		return (NULL);
+	}
+	error = bus_dmamap_load(sc->dmat, ch->dmamap, ch->dmaaddr,
+	    sc->dmasize, a10codec_dmamap_cb, ch, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot load DMA map\n");
+		return (NULL);
+	}
+	memset(ch->dmaaddr, 0, sc->dmasize);
+
+	if (sndbuf_setup(ch->buffer, ch->dmaaddr, sc->dmasize) != 0) {
+		device_printf(sc->dev, "cannot setup sndbuf\n");
+		return (NULL);
+	}
+
+	return (ch);
+}
+
+static int
+a10codec_chan_free(kobj_t obj, void *data)
+{
+	struct a10codec_chinfo *ch = data;
+	struct a10codec_info *sc = ch->parent;
+
+	SUNXI_DMA_FREE(ch->dmac, ch->dmachan);
+	bus_dmamap_unload(sc->dmat, ch->dmamap);
+	bus_dmamem_free(sc->dmat, ch->dmaaddr, ch->dmamap);
+
+	return (0);
+}
+
+static int
+a10codec_chan_setformat(kobj_t obj, void *data, uint32_t format)
+{
+	struct a10codec_chinfo *ch = data;
+
+	ch->format = format;
+
+	return (0);
+}
+
+static uint32_t
+a10codec_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
+{
+	struct a10codec_chinfo *ch = data;
+
+	/*
+	 * The codec supports full duplex operation but both DAC and ADC
+	 * use the same source clock (PLL2). Limit the available speeds to
+	 * those supported by a 24576000 Hz input.
+	 */
+	switch (speed) {
+	case 8000:
+	case 12000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+		ch->speed = speed;
+		break;
+	case 96000:
+	case 192000:
+		/* 96 KHz / 192 KHz mode only supported for playback */
+		if (ch->dir == PCMDIR_PLAY) {
+			ch->speed = speed;
+		} else {
+			ch->speed = 48000;
+		}
+		break;
+	case 44100:
+		ch->speed = 48000;
+		break;
+	case 22050:
+		ch->speed = 24000;
+		break;
+	case 11025:
+		ch->speed = 12000;
+		break;
+	default:
+		ch->speed = 48000;
+		break;
+	}
+
+	return (ch->speed);
+}
+
+static uint32_t
+a10codec_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
+{
+	struct a10codec_chinfo *ch = data;
+
+	ch->blocksize = blocksize & ~3;
+
+	return (ch->blocksize);
+}
+
+static int
+a10codec_chan_trigger(kobj_t obj, void *data, int go)
+{
+	struct a10codec_chinfo *ch = data;
+	struct a10codec_info *sc = ch->parent;
+
+	if (!PCMTRIG_COMMON(go))
+		return (0);
+
+	snd_mtxlock(sc->lock);
+	switch (go) {
+	case PCMTRIG_START:
+		ch->run = 1;
+		a10codec_start(ch);
+		break;
+	case PCMTRIG_STOP:
+	case PCMTRIG_ABORT:
+		ch->run = 0;
+		a10codec_stop(ch);
+		break;
+	default:
+		break;
+	}
+	snd_mtxunlock(sc->lock);
+
+	return (0);
+}
+
+static uint32_t
+a10codec_chan_getptr(kobj_t obj, void *data)
+{
+	struct a10codec_chinfo *ch = data;
+
+	return (ch->pos);
+}
+
+static struct pcmchan_caps *
+a10codec_chan_getcaps(kobj_t obj, void *data)
+{
+	struct a10codec_chinfo *ch = data;
+
+	if (ch->dir == PCMDIR_PLAY) {
+		return (&a10codec_pcaps);
+	} else {
+		return (&a10codec_rcaps);
+	}
+}
+
+static kobj_method_t a10codec_chan_methods[] = {
+	KOBJMETHOD(channel_init,		a10codec_chan_init),
+	KOBJMETHOD(channel_free,		a10codec_chan_free),
+	KOBJMETHOD(channel_setformat,		a10codec_chan_setformat),
+	KOBJMETHOD(channel_setspeed,		a10codec_chan_setspeed),
+	KOBJMETHOD(channel_setblocksize,	a10codec_chan_setblocksize),
+	KOBJMETHOD(channel_trigger,		a10codec_chan_trigger),
+	KOBJMETHOD(channel_getptr,		a10codec_chan_getptr),
+	KOBJMETHOD(channel_getcaps,		a10codec_chan_getcaps),
+	KOBJMETHOD_END
+};
+CHANNEL_DECLARE(a10codec_chan);
+
+
+/*
+ * Device interface
+ */
+
+static struct ofw_compat_data compat_data[] = {
+	{"allwinner,sun4i-a10-codec", 1},
+	{"allwinner,sun7i-a20-codec", 1},
+	{NULL, 0},
+};
+
+static int
+a10codec_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Audio Codec");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10codec_attach(device_t dev)
+{
+	struct a10codec_info *sc;
+	char status[SND_STATUSLEN];
+	clk_t clk_apb, clk_codec;
+	uint32_t val;
+	int error;
+
+	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
+	sc->dev = dev;
+	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "a10codec softc");
+
+	if (bus_alloc_resources(dev, a10codec_spec, sc->res)) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	/* XXX DRQ types should come from FDT, but how? */
+	if (ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-codec") ||
+	    ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-codec")) {
+		sc->drqtype_codec = 19;
+		sc->drqtype_sdram = 22;
+	} else {
+		device_printf(dev, "DRQ types not known for this SoC\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	sc->dmasize = 131072;
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),
+	    4, sc->dmasize,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    sc->dmasize, 1,		/* maxsize, nsegs */
+	    sc->dmasize, 0,		/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->dmat);
+	if (error != 0) {
+		device_printf(dev, "cannot create DMA tag\n");
+		goto fail;
+	}
+
+	/* Get clocks */
+	error = clk_get_by_ofw_name(dev, 0, "apb", &clk_apb);
+	if (error != 0) {
+		device_printf(dev, "cannot find apb clock\n");
+		goto fail;
+	}
+	error = clk_get_by_ofw_name(dev, 0, "codec", &clk_codec);
+	if (error != 0) {
+		device_printf(dev, "cannot find codec clock\n");
+		goto fail;
+	}
+
+	/* Gating APB clock for codec */
+	error = clk_enable(clk_apb);
+	if (error != 0) {
+		device_printf(dev, "cannot enable apb clock\n");
+		goto fail;
+	}
+	/* Activate audio codec clock. According to the A10 and A20 user
+	 * manuals, Audio_pll can be either 24.576MHz or 22.5792MHz. Most
+	 * audio sampling rates require an 24.576MHz input clock with the
+	 * exception of 44.1kHz, 22.05kHz, and 11.025kHz. Unfortunately,
+	 * both capture and playback use the same clock source so to
+	 * safely support independent full duplex operation, we use a fixed
+	 * 24.576MHz clock source and don't advertise native support for
+	 * the three sampling rates that require a 22.5792MHz input.
+	 */
+	error = clk_set_freq(clk_codec, 24576000, CLK_SET_ROUND_DOWN);
+	if (error != 0) {
+		device_printf(dev, "cannot set codec clock frequency\n");
+		goto fail;
+	}
+	/* Enable audio codec clock */
+	error = clk_enable(clk_codec);
+	if (error != 0) {
+		device_printf(dev, "cannot enable codec clock\n");
+		goto fail;
+	}
+
+	/* Enable DAC */
+	val = CODEC_READ(sc, AC_DAC_DPC);
+	val |= DAC_DPC_EN_DA;
+	CODEC_WRITE(sc, AC_DAC_DPC, val);
+
+#ifdef notdef
+	error = snd_setup_intr(dev, sc->irq, INTR_MPSAFE, a10codec_intr, sc,
+	    &sc->ih);
+	if (error != 0) {
+		device_printf(dev, "could not setup interrupt handler\n");
+		goto fail;
+	}
+#endif
+
+	if (mixer_init(dev, &a10codec_mixer_class, sc)) {
+		device_printf(dev, "mixer_init failed\n");
+		goto fail;
+	}
+
+	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
+
+	if (pcm_register(dev, sc, 1, 1)) {
+		device_printf(dev, "pcm_register failed\n");
+		goto fail;
+	}
+
+	pcm_addchan(dev, PCMDIR_PLAY, &a10codec_chan_class, sc);
+	pcm_addchan(dev, PCMDIR_REC, &a10codec_chan_class, sc);
+
+	snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
+	pcm_setstatus(dev, status);
+
+	return (0);
+
+fail:
+	bus_release_resources(dev, a10codec_spec, sc->res);
+	snd_mtxfree(sc->lock);
+	free(sc, M_DEVBUF);
+
+	return (error);
+}
+
+static device_method_t a10codec_pcm_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a10codec_probe),
+	DEVMETHOD(device_attach,	a10codec_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t a10codec_pcm_driver = {
+	"pcm",
+	a10codec_pcm_methods,
+	PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(a10codec, simplebus, a10codec_pcm_driver, pcm_devclass, 0, 0);
+MODULE_DEPEND(a10codec, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
+MODULE_VERSION(a10codec, 1);


Property changes on: trunk/sys/arm/allwinner/a10_codec.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/a10_common.c
===================================================================
--- trunk/sys/arm/allwinner/a10_common.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/a10_common.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/a10_common.c 266337 2014-05-17 18:53:36Z ian $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_common.c 314506 2017-03-01 19:55:04Z ian $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -37,12 +37,9 @@
 #include <dev/ofw/openfirm.h>
 
 #include <machine/bus.h>
-#include <machine/fdt.h>
 #include <machine/vmparam.h>
 
-struct fdt_fixup_entry fdt_fixup_table[] = {
-	{ NULL, NULL }
-};
+#ifndef INTRNG
 
 static int
 fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
@@ -50,7 +47,7 @@
 {
 	int offset;
 
-	if (fdt_is_compatible(node, "allwinner,sun4i-ic"))
+	if (fdt_is_compatible(node, "allwinner,sun4i-a10-ic"))
 		offset = 0;
 	else if (fdt_is_compatible(node, "arm,gic"))
 		offset = 32;
@@ -68,3 +65,5 @@
 	&fdt_aintc_decode_ic,
 	NULL
 };
+
+#endif /* INTRNG */

Added: trunk/sys/arm/allwinner/a10_dmac.c
===================================================================
--- trunk/sys/arm/allwinner/a10_dmac.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_dmac.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,472 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill at 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.
+ *
+ */
+
+/*
+ * Allwinner A10/A20 DMA controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_dmac.c 309759 2016-12-09 20:21:48Z manu $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/a10_dmac.h>
+#include <dev/extres/clk/clk.h>
+
+#include "sunxi_dma_if.h"
+
+#define	NDMA_CHANNELS	8
+#define	DDMA_CHANNELS	8
+
+enum a10dmac_type {
+	CH_NDMA,
+	CH_DDMA
+};
+
+struct a10dmac_softc;
+
+struct a10dmac_channel {
+	struct a10dmac_softc *	ch_sc;
+	uint8_t			ch_index;
+	enum a10dmac_type	ch_type;
+	void			(*ch_callback)(void *);
+	void *			ch_callbackarg;
+	uint32_t		ch_regoff;
+};
+
+struct a10dmac_softc {
+	struct resource *	sc_res[2];
+	struct mtx		sc_mtx;
+	void *			sc_ih;
+
+	struct a10dmac_channel	sc_ndma_channels[NDMA_CHANNELS];
+	struct a10dmac_channel	sc_ddma_channels[DDMA_CHANNELS];
+};
+
+static struct resource_spec a10dmac_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	DMA_READ(sc, reg)	bus_read_4((sc)->sc_res[0], (reg))
+#define	DMA_WRITE(sc, reg, val)	bus_write_4((sc)->sc_res[0], (reg), (val))
+#define	DMACH_READ(ch, reg)		\
+    DMA_READ((ch)->ch_sc, (reg) + (ch)->ch_regoff)
+#define	DMACH_WRITE(ch, reg, val)	\
+    DMA_WRITE((ch)->ch_sc, (reg) + (ch)->ch_regoff, (val))
+
+static void a10dmac_intr(void *);
+
+static int
+a10dmac_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-dma"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner DMA controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10dmac_attach(device_t dev)
+{
+	struct a10dmac_softc *sc;
+	unsigned int index;
+	clk_t clk;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (bus_alloc_resources(dev, a10dmac_spec, sc->sc_res)) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	mtx_init(&sc->sc_mtx, "a10 dmac", NULL, MTX_SPIN);
+
+	/* Activate DMA controller clock */
+	error = clk_get_by_ofw_index(dev, 0, 0, &clk);
+	if (error != 0) {
+		device_printf(dev, "cannot get clock\n");
+		return (error);
+	}
+	error = clk_enable(clk);
+	if (error != 0) {
+		device_printf(dev, "cannot enable clock\n");
+		return (error);
+	}
+
+	/* Disable all interrupts and clear pending status */
+	DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, 0);
+	DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, ~0);
+
+	/* Initialize channels */
+	for (index = 0; index < NDMA_CHANNELS; index++) {
+		sc->sc_ndma_channels[index].ch_sc = sc;
+		sc->sc_ndma_channels[index].ch_index = index;
+		sc->sc_ndma_channels[index].ch_type = CH_NDMA;
+		sc->sc_ndma_channels[index].ch_callback = NULL;
+		sc->sc_ndma_channels[index].ch_callbackarg = NULL;
+		sc->sc_ndma_channels[index].ch_regoff = AWIN_NDMA_REG(index);
+		DMACH_WRITE(&sc->sc_ndma_channels[index], AWIN_NDMA_CTL_REG, 0);
+	}
+	for (index = 0; index < DDMA_CHANNELS; index++) {
+		sc->sc_ddma_channels[index].ch_sc = sc;
+		sc->sc_ddma_channels[index].ch_index = index;
+		sc->sc_ddma_channels[index].ch_type = CH_DDMA;
+		sc->sc_ddma_channels[index].ch_callback = NULL;
+		sc->sc_ddma_channels[index].ch_callbackarg = NULL;
+		sc->sc_ddma_channels[index].ch_regoff = AWIN_DDMA_REG(index);
+		DMACH_WRITE(&sc->sc_ddma_channels[index], AWIN_DDMA_CTL_REG, 0);
+	}
+
+	error = bus_setup_intr(dev, sc->sc_res[1], INTR_MPSAFE | INTR_TYPE_MISC,
+	    NULL, a10dmac_intr, sc, &sc->sc_ih);
+	if (error != 0) {
+		device_printf(dev, "could not setup interrupt handler\n");
+		bus_release_resources(dev, a10dmac_spec, sc->sc_res);
+		mtx_destroy(&sc->sc_mtx);
+		return (ENXIO);
+	}
+
+	OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
+	return (0);
+}
+
+static void
+a10dmac_intr(void *priv)
+{
+	struct a10dmac_softc *sc = priv;
+	uint32_t sta, bit, mask;
+	uint8_t index;
+
+	sta = DMA_READ(sc, AWIN_DMA_IRQ_PEND_STA_REG);
+	DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, sta);
+
+	while ((bit = ffs(sta & AWIN_DMA_IRQ_END_MASK)) != 0) {
+		mask = (1U << (bit - 1));
+		sta &= ~mask;
+		/*
+		 * Map status bit to channel number. The status register is
+		 * encoded with two bits of status per channel (lowest bit
+		 * is half transfer pending, highest bit is end transfer
+		 * pending). The 8 normal DMA channel status are in the lower
+		 * 16 bits and the 8 dedicated DMA channel status are in
+		 * the upper 16 bits. The output is a channel number from 0-7.
+		 */
+		index = ((bit - 1) / 2) & 7;
+		if (mask & AWIN_DMA_IRQ_NDMA) {
+			if (sc->sc_ndma_channels[index].ch_callback == NULL)
+				continue;
+			sc->sc_ndma_channels[index].ch_callback(
+			    sc->sc_ndma_channels[index].ch_callbackarg);
+		} else {
+			if (sc->sc_ddma_channels[index].ch_callback == NULL)
+				continue;
+			sc->sc_ddma_channels[index].ch_callback(
+			    sc->sc_ddma_channels[index].ch_callbackarg);
+		}
+	}
+}
+
+static uint32_t
+a10dmac_read_ctl(struct a10dmac_channel *ch)
+{
+	if (ch->ch_type == CH_NDMA) {
+		return (DMACH_READ(ch, AWIN_NDMA_CTL_REG));
+	} else {
+		return (DMACH_READ(ch, AWIN_DDMA_CTL_REG));
+	}
+}
+
+static void
+a10dmac_write_ctl(struct a10dmac_channel *ch, uint32_t val)
+{
+	if (ch->ch_type == CH_NDMA) {
+		DMACH_WRITE(ch, AWIN_NDMA_CTL_REG, val);
+	} else {
+		DMACH_WRITE(ch, AWIN_DDMA_CTL_REG, val);
+	}
+}
+
+static int
+a10dmac_set_config(device_t dev, void *priv, const struct sunxi_dma_config *cfg)
+{
+	struct a10dmac_channel *ch = priv;
+	uint32_t val;
+	unsigned int dst_dw, dst_bl, dst_bs, dst_wc, dst_am;
+	unsigned int src_dw, src_bl, src_bs, src_wc, src_am;
+
+	switch (cfg->dst_width) {
+	case 8:
+		dst_dw = AWIN_DMA_CTL_DATA_WIDTH_8;
+		break;
+	case 16:
+		dst_dw = AWIN_DMA_CTL_DATA_WIDTH_16;
+		break;
+	case 32:
+		dst_dw = AWIN_DMA_CTL_DATA_WIDTH_32;
+		break;
+	default:
+		return (EINVAL);
+	}
+	switch (cfg->dst_burst_len) {
+	case 1:
+		dst_bl = AWIN_DMA_CTL_BURST_LEN_1;
+		break;
+	case 4:
+		dst_bl = AWIN_DMA_CTL_BURST_LEN_4;
+		break;
+	case 8:
+		dst_bl = AWIN_DMA_CTL_BURST_LEN_8;
+		break;
+	default:
+		return (EINVAL);
+	}
+	switch (cfg->src_width) {
+	case 8:
+		src_dw = AWIN_DMA_CTL_DATA_WIDTH_8;
+		break;
+	case 16:
+		src_dw = AWIN_DMA_CTL_DATA_WIDTH_16;
+		break;
+	case 32:
+		src_dw = AWIN_DMA_CTL_DATA_WIDTH_32;
+		break;
+	default:
+		return (EINVAL);
+	}
+	switch (cfg->src_burst_len) {
+	case 1:
+		src_bl = AWIN_DMA_CTL_BURST_LEN_1;
+		break;
+	case 4:
+		src_bl = AWIN_DMA_CTL_BURST_LEN_4;
+		break;
+	case 8:
+		src_bl = AWIN_DMA_CTL_BURST_LEN_8;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	val = (dst_dw << AWIN_DMA_CTL_DST_DATA_WIDTH_SHIFT) |
+	      (dst_bl << AWIN_DMA_CTL_DST_BURST_LEN_SHIFT) |
+	      (cfg->dst_drqtype << AWIN_DMA_CTL_DST_DRQ_TYPE_SHIFT) |
+	      (src_dw << AWIN_DMA_CTL_SRC_DATA_WIDTH_SHIFT) |
+	      (src_bl << AWIN_DMA_CTL_SRC_BURST_LEN_SHIFT) |
+	      (cfg->src_drqtype << AWIN_DMA_CTL_SRC_DRQ_TYPE_SHIFT);
+
+	if (ch->ch_type == CH_NDMA) {
+		if (cfg->dst_noincr)
+			val |= AWIN_NDMA_CTL_DST_ADDR_NOINCR;
+		if (cfg->src_noincr)
+			val |= AWIN_NDMA_CTL_SRC_ADDR_NOINCR;
+
+		DMACH_WRITE(ch, AWIN_NDMA_CTL_REG, val);
+	} else {
+		dst_am = cfg->dst_noincr ? AWIN_DDMA_CTL_DMA_ADDR_IO :
+		    AWIN_DDMA_CTL_DMA_ADDR_LINEAR;
+		src_am = cfg->src_noincr ? AWIN_DDMA_CTL_DMA_ADDR_IO :
+		    AWIN_DDMA_CTL_DMA_ADDR_LINEAR;
+
+		val |= (dst_am << AWIN_DDMA_CTL_DST_ADDR_MODE_SHIFT);
+		val |= (src_am << AWIN_DDMA_CTL_SRC_ADDR_MODE_SHIFT);
+
+		DMACH_WRITE(ch, AWIN_DDMA_CTL_REG, val);
+
+		dst_bs = cfg->dst_blksize - 1;
+		dst_wc = cfg->dst_wait_cyc - 1;
+		src_bs = cfg->src_blksize - 1;
+		src_wc = cfg->src_wait_cyc - 1;
+
+		DMACH_WRITE(ch, AWIN_DDMA_PARA_REG,
+		    (dst_bs << AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_SHIFT) |
+		    (dst_wc << AWIN_DDMA_PARA_DST_WAIT_CYC_SHIFT) |
+		    (src_bs << AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_SHIFT) |
+		    (src_wc << AWIN_DDMA_PARA_SRC_WAIT_CYC_SHIFT));
+	}
+
+	return (0);
+}
+
+static void *
+a10dmac_alloc(device_t dev, bool dedicated, void (*cb)(void *), void *cbarg)
+{
+	struct a10dmac_softc *sc = device_get_softc(dev);
+	struct a10dmac_channel *ch_list;
+	struct a10dmac_channel *ch = NULL;
+	uint32_t irqen;
+	uint8_t ch_count, index;
+
+	if (dedicated) {
+		ch_list = sc->sc_ddma_channels;
+		ch_count = DDMA_CHANNELS;
+	} else {
+		ch_list = sc->sc_ndma_channels;
+		ch_count = NDMA_CHANNELS;
+	}
+
+	mtx_lock_spin(&sc->sc_mtx);
+	for (index = 0; index < ch_count; index++) {
+		if (ch_list[index].ch_callback == NULL) {
+			ch = &ch_list[index];
+			ch->ch_callback = cb;
+			ch->ch_callbackarg = cbarg;
+
+			irqen = DMA_READ(sc, AWIN_DMA_IRQ_EN_REG);
+			if (ch->ch_type == CH_NDMA)
+				irqen |= AWIN_DMA_IRQ_NDMA_END(index);
+			else
+				irqen |= AWIN_DMA_IRQ_DDMA_END(index);
+			DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, irqen);
+
+			break;
+		}
+	}
+	mtx_unlock_spin(&sc->sc_mtx);
+
+	return (ch);
+}
+
+static void
+a10dmac_free(device_t dev, void *priv)
+{
+	struct a10dmac_channel *ch = priv;
+	struct a10dmac_softc *sc = ch->ch_sc;
+	uint32_t irqen, sta, cfg;
+
+	mtx_lock_spin(&sc->sc_mtx);
+
+	irqen = DMA_READ(sc, AWIN_DMA_IRQ_EN_REG);
+	cfg = a10dmac_read_ctl(ch);
+	if (ch->ch_type == CH_NDMA) {
+		sta = AWIN_DMA_IRQ_NDMA_END(ch->ch_index);
+		cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
+	} else {
+		sta = AWIN_DMA_IRQ_DDMA_END(ch->ch_index);
+		cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
+	}
+	irqen &= ~sta;
+	a10dmac_write_ctl(ch, cfg);
+	DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, irqen);
+	DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, sta);
+
+	ch->ch_callback = NULL;
+	ch->ch_callbackarg = NULL;
+
+	mtx_unlock_spin(&sc->sc_mtx);
+}
+
+static int
+a10dmac_transfer(device_t dev, void *priv, bus_addr_t src, bus_addr_t dst,
+    size_t nbytes)
+{
+	struct a10dmac_channel *ch = priv;
+	uint32_t cfg;
+
+	cfg = a10dmac_read_ctl(ch);
+	if (ch->ch_type == CH_NDMA) {
+		if (cfg & AWIN_NDMA_CTL_DMA_LOADING)
+			return (EBUSY);
+
+		DMACH_WRITE(ch, AWIN_NDMA_SRC_ADDR_REG, src);
+		DMACH_WRITE(ch, AWIN_NDMA_DEST_ADDR_REG, dst);
+		DMACH_WRITE(ch, AWIN_NDMA_BC_REG, nbytes);
+
+		cfg |= AWIN_NDMA_CTL_DMA_LOADING;
+		a10dmac_write_ctl(ch, cfg);
+	} else {
+		if (cfg & AWIN_DDMA_CTL_DMA_LOADING)
+			return (EBUSY);
+
+		DMACH_WRITE(ch, AWIN_DDMA_SRC_START_ADDR_REG, src);
+		DMACH_WRITE(ch, AWIN_DDMA_DEST_START_ADDR_REG, dst);
+		DMACH_WRITE(ch, AWIN_DDMA_BC_REG, nbytes);
+
+		cfg |= AWIN_DDMA_CTL_DMA_LOADING;
+		a10dmac_write_ctl(ch, cfg);
+	}
+
+	return (0);
+}
+
+static void
+a10dmac_halt(device_t dev, void *priv)
+{
+	struct a10dmac_channel *ch = priv;
+	uint32_t cfg;
+
+	cfg = a10dmac_read_ctl(ch);
+	if (ch->ch_type == CH_NDMA) {
+		cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
+	} else {
+		cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
+	}
+	a10dmac_write_ctl(ch, cfg);
+}
+
+static device_method_t a10dmac_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a10dmac_probe),
+	DEVMETHOD(device_attach,	a10dmac_attach),
+
+	/* sunxi DMA interface */
+	DEVMETHOD(sunxi_dma_alloc,	a10dmac_alloc),
+	DEVMETHOD(sunxi_dma_free,	a10dmac_free),
+	DEVMETHOD(sunxi_dma_set_config,	a10dmac_set_config),
+	DEVMETHOD(sunxi_dma_transfer,	a10dmac_transfer),
+	DEVMETHOD(sunxi_dma_halt,	a10dmac_halt),
+
+	DEVMETHOD_END
+};
+
+static driver_t a10dmac_driver = {
+	"a10dmac",
+	a10dmac_methods,
+	sizeof(struct a10dmac_softc)
+};
+
+static devclass_t a10dmac_devclass;
+
+DRIVER_MODULE(a10dmac, simplebus, a10dmac_driver, a10dmac_devclass, 0, 0);


Property changes on: trunk/sys/arm/allwinner/a10_dmac.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a10_dmac.h
===================================================================
--- trunk/sys/arm/allwinner/a10_dmac.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_dmac.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,159 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_dmac.h 295635 2016-02-15 19:56:35Z andrew $
+ */
+
+#ifndef _A10_DMAC_H_
+#define	_A10_DMAC_H_
+
+#define	AWIN_DMA_IRQ_EN_REG		0x0000
+#define	AWIN_DMA_IRQ_PEND_STA_REG	0x0004
+#define	AWIN_NDMA_AUTO_GATE_REG		0x0008
+#define	AWIN_NDMA_REG(n)		(0x100+0x20*(n))
+#define	AWIN_NDMA_CTL_REG		0x0000
+#define	AWIN_NDMA_SRC_ADDR_REG		0x0004
+#define	AWIN_NDMA_DEST_ADDR_REG		0x0008
+#define	AWIN_NDMA_BC_REG		0x000c
+#define	AWIN_DDMA_REG(n)		(0x300+0x20*(n))
+#define	AWIN_DDMA_CTL_REG		0x0000
+#define	AWIN_DDMA_SRC_START_ADDR_REG	0x0004
+#define	AWIN_DDMA_DEST_START_ADDR_REG	0x0008
+#define	AWIN_DDMA_BC_REG		0x000c
+#define	AWIN_DDMA_PARA_REG		0x0018
+#define	AWIN_DMA_IRQ_END_MASK		0xaaaaaaaa
+#define	AWIN_DMA_IRQ_HF_MASK		0x55555555
+#define	AWIN_DMA_IRQ_DDMA		0xffff0000
+#define	AWIN_DMA_IRQ_DDMA_END(n)	(1U << (17+2*(n)))
+#define	AWIN_DMA_IRQ_DDMA_HF(n)		(1U << (16+2*(n)))
+#define	AWIN_DMA_IRQ_NDMA		0x0000ffff
+#define	AWIN_DMA_IRQ_NDMA_END(n)	(1U << (1+2*(n)))
+#define	AWIN_DMA_IRQ_NDMA_HF(n)		(1U << (0+2*(n)))
+#define	AWIN_NDMA_AUTO_GATING_DIS	(1U << 16)
+#define	AWIN_DMA_CTL_DST_DATA_WIDTH_SHIFT 25
+#define	AWIN_DMA_CTL_DST_DATA_WIDTH_MASK (3U << AWIN_DMA_CTL_DST_DATA_WIDTH_SHIFT)
+#define	AWIN_DMA_CTL_DATA_WIDTH_8	0
+#define	AWIN_DMA_CTL_DATA_WIDTH_16	1
+#define	AWIN_DMA_CTL_DATA_WIDTH_32	2
+#define	AWIN_DMA_CTL_DST_BURST_LEN_SHIFT 23
+#define	AWIN_DMA_CTL_DST_BURST_LEN_MASK	(3 << AWIN_DMA_CTL_DST_BURST_LEN_SHIFT)
+#define	AWIN_DMA_CTL_BURST_LEN_1	0
+#define	AWIN_DMA_CTL_BURST_LEN_4	1
+#define	AWIN_DMA_CTL_BURST_LEN_8	2
+#define	AWIN_DMA_CTL_DST_DRQ_TYPE_SHIFT	16
+#define	AWIN_DMA_CTL_DST_DRQ_TYPE_MASK	(0x1f << AWIN_DMA_CTL_DST_DRQ_TYPE_SHIFT)
+#define	AWIN_DMA_CTL_BC_REMAINING	(1U << 15)
+#define	AWIN_DMA_CTL_SRC_DATA_WIDTH_SHIFT 9
+#define	AWIN_DMA_CTL_SRC_DATA_WIDTH_MASK (3U << AWIN_DMA_CTL_SRC_DATA_WIDTH_SHIFT)
+#define	AWIN_DMA_CTL_SRC_BURST_LEN_SHIFT 7
+#define	AWIN_DMA_CTL_SRC_BURST_LEN_MASK	(3U << AWIN_DMA_CTL_SRC_BURST_LEN_SHIFT)
+#define	AWIN_DMA_CTL_SRC_DRQ_TYPE_SHIFT	0
+#define	AWIN_DMA_CTL_SRC_DRQ_TYPE_MASK	(0x1f << AWIN_DMA_CTL_SRC_DRQ_TYPE_SHIFT)
+#define	AWIN_NDMA_CTL_DMA_LOADING	(1U << 31)
+#define	AWIN_NDMA_CTL_DMA_CONTIN_MODE	(1U << 30)
+#define	AWIN_NDMA_CTL_WAIT_STATE_LOG2_SHIFT 27
+#define	AWIN_NDMA_CTL_WAIT_STATE_LOG2_MASK (7U << AWIN_NDMA_CTL_WAIT_STATE_LOG2_SHIFT)
+#define	AWIN_NDMA_CTL_DST_NON_SECURE	(1U << 22)
+#define	AWIN_NDMA_CTL_DST_ADDR_NOINCR	(1U << 21)
+#define	AWIN_NDMA_CTL_DRQ_IRO		0
+#define	AWIN_NDMA_CTL_DRQ_IR1		1
+#define	AWIN_NDMA_CTL_DRQ_SPDIF		2
+#define	AWIN_NDMA_CTL_DRQ_IISO		3
+#define	AWIN_NDMA_CTL_DRQ_IIS1		4
+#define	AWIN_NDMA_CTL_DRQ_AC97		5
+#define	AWIN_NDMA_CTL_DRQ_IIS2		6
+#define	AWIN_NDMA_CTL_DRQ_UARTO		8
+#define	AWIN_NDMA_CTL_DRQ_UART1		9
+#define	AWIN_NDMA_CTL_DRQ_UART2		10
+#define	AWIN_NDMA_CTL_DRQ_UART3		11
+#define	AWIN_NDMA_CTL_DRQ_UART4		12
+#define	AWIN_NDMA_CTL_DRQ_UART5		13
+#define	AWIN_NDMA_CTL_DRQ_UART6		14
+#define	AWIN_NDMA_CTL_DRQ_UART7		15
+#define	AWIN_NDMA_CTL_DRQ_DDC		16
+#define	AWIN_NDMA_CTL_DRQ_USB_EP1	17
+#define	AWIN_NDMA_CTL_DRQ_CODEC		19
+#define	AWIN_NDMA_CTL_DRQ_SRAM		21
+#define	AWIN_NDMA_CTL_DRQ_SDRAM		22
+#define	AWIN_NDMA_CTL_DRQ_TP_AD		23
+#define	AWIN_NDMA_CTL_DRQ_SPI0		24
+#define	AWIN_NDMA_CTL_DRQ_SPI1		25
+#define	AWIN_NDMA_CTL_DRQ_SPI2		26
+#define	AWIN_NDMA_CTL_DRQ_SPI3		27
+#define	AWIN_NDMA_CTL_DRQ_USB_EP2	28
+#define	AWIN_NDMA_CTL_DRQ_USB_EP3	29
+#define	AWIN_NDMA_CTL_DRQ_USB_EP4	30
+#define	AWIN_NDMA_CTL_DRQ_USB_EP5	31
+#define	AWIN_NDMA_CTL_SRC_NON_SECURE	(1U << 6)
+#define	AWIN_NDMA_CTL_SRC_ADDR_NOINCR	(1U << 5)
+#define	AWIN_NDMA_BC_COUNT		0x0003ffff
+#define	AWIN_DDMA_CTL_DMA_LOADING	(1U << 31)
+#define	AWIN_DDMA_CTL_BUSY		(1U << 30)
+#define	AWIN_DDMA_CTL_DMA_CONTIN_MODE	(1U << 29)
+#define	AWIN_DDMA_CTL_DST_NON_SECURE	(1U << 28)
+#define	AWIN_DDMA_CTL_DST_ADDR_MODE_SHIFT 21
+#define	AWIN_DDMA_CTL_DST_ADDR_MODE_MASK (3U << AWIN_DDMA_CTL_DST_ADDR_MODE_SHIFT)
+#define	AWIN_DDMA_CTL_DMA_ADDR_LINEAR	0
+#define	AWIN_DDMA_CTL_DMA_ADDR_IO	1
+#define	AWIN_DDMA_CTL_DMA_ADDR_HPAGE	2
+#define	AWIN_DDMA_CTL_DMA_ADDR_VPAGE	3
+#define	AWIN_DDMA_CTL_DST_DRQ_TYPE_SHIFT 16
+#define	AWIN_DDMA_CTL_DST_DRQ_TYPE_MASK	(0x1f << AWIN_DDMA_CTL_DST_DRQ_TYPE_SHIFT)
+#define	AWIN_DDMA_CTL_DRQ_SRAM		0
+#define	AWIN_DDMA_CTL_DRQ_SDRAM		1
+#define	AWIN_DDMA_CTL_DRQ_NFC		3
+#define	AWIN_DDMA_CTL_DRQ_USB0		4
+#define	AWIN_DDMA_CTL_DRQ_EMAC_TX	6
+#define	AWIN_DDMA_CTL_DRQ_EMAC_RX	7
+#define	AWIN_DDMA_CTL_DRQ_SPI1_TX	8
+#define	AWIN_DDMA_CTL_DRQ_SPI1_RX	9
+#define	AWIN_DDMA_CTL_DRQ_SS_TX		10
+#define	AWIN_DDMA_CTL_DRQ_SS_RX		11
+#define	AWIN_DDMA_CTL_DRQ_TCON0		14
+#define	AWIN_DDMA_CTL_DRQ_TCON1		15
+#define	AWIN_DDMA_CTL_DRQ_MS_TX		23
+#define	AWIN_DDMA_CTL_DRQ_MS_RX		23
+#define	AWIN_DDMA_CTL_DRQ_HDMI_AUDIO	24
+#define	AWIN_DDMA_CTL_DRQ_SPI0_TX	26
+#define	AWIN_DDMA_CTL_DRQ_SPI0_RX	27
+#define	AWIN_DDMA_CTL_DRQ_SPI2_TX	28
+#define	AWIN_DDMA_CTL_DRQ_SPI2_RX	29
+#define	AWIN_DDMA_CTL_DRQ_SPI3_TX	30
+#define	AWIN_DDMA_CTL_DRQ_SPI3_RX	31
+#define	AWIN_DDMA_CTL_SRC_NON_SECURE	(1U << 12)
+#define	AWIN_DDMA_CTL_SRC_ADDR_MODE_SHIFT 5
+#define	AWIN_DDMA_CTL_SRC_ADDR_MODE_MASK (3U << AWIN_DDMA_CTL_SRC_ADDR_MODE_SHIFT)
+#define	AWIN_DDMA_BC_COUNT		0x00003fff
+#define	AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_SHIFT 24
+#define	AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_MASK (0xff << AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_SHIFT)
+#define	AWIN_DDMA_PARA_DST_WAIT_CYC_SHIFT 16
+#define	AWIN_DDMA_PARA_DST_WAIT_CYC_MASK (0xff << AWIN_DDMA_PARA_DST_WAIT_CYC_SHIFT)
+#define	AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_SHIFT 8
+#define	AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_MASK (0xff << AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_SHIFT)
+#define	AWIN_DDMA_PARA_SRC_WAIT_CYC_SHIFT 0
+#define	AWIN_DDMA_PARA_SRC_WAIT_CYC_MASK (0xff << AWIN_DDMA_PARA_SRC_WAIT_CYC_SHIFT)
+
+#endif /* !_A10_DMAC_H_ */


Property changes on: trunk/sys/arm/allwinner/a10_dmac.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/a10_ehci.c
===================================================================
--- trunk/sys/arm/allwinner/a10_ehci.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/a10_ehci.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/a10_ehci.c 308402 2016-11-07 09:19:04Z hselasky $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_ehci.c 346524 2019-04-22 04:56:41Z ian $");
 
 #include "opt_bus.h"
 
@@ -41,13 +41,12 @@
 #include <sys/condvar.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
-#include <sys/gpio.h>
 
 #include <machine/bus.h>
-#include <dev/ofw/ofw_bus.h> 
+#include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
-#include <dev/usb/usb.h> 
+#include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 
 #include <dev/usb/usb_core.h>
@@ -60,10 +59,11 @@
 #include <dev/usb/controller/ehci.h>
 #include <dev/usb/controller/ehcireg.h>
 
-#include "gpio_if.h"
+#include <arm/allwinner/aw_machdep.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/phy/phy.h>
 
-#include "a10_clk.h"
-
 #define EHCI_HC_DEVSTR			"Allwinner Integrated USB 2.0 controller"
 
 #define SW_USB_PMU_IRQ_ENABLE		0x800
@@ -76,9 +76,10 @@
 #define SW_AHB_INCRX_ALIGN		(1 << 8)
 #define SW_AHB_INCR4			(1 << 9)
 #define SW_AHB_INCR8			(1 << 10)
-#define GPIO_USB1_PWR			230
-#define GPIO_USB2_PWR			227
 
+#define	USB_CONF(d)			\
+	(void *)ofw_bus_search_compatible((d), compat_data)->ocd_data
+
 #define A10_READ_4(sc, reg)		\
 	bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
 
@@ -88,9 +89,35 @@
 static device_attach_t a10_ehci_attach;
 static device_detach_t a10_ehci_detach;
 
-bs_r_1_proto(reversed);
-bs_w_1_proto(reversed);
+struct aw_ehci_softc {
+	ehci_softc_t	sc;
+	clk_t		clk;
+	hwreset_t	rst;
+	phy_t		phy;
+};
 
+struct aw_ehci_conf {
+	bool		sdram_init;
+};
+
+static const struct aw_ehci_conf a10_ehci_conf = {
+	.sdram_init = true,
+};
+
+static const struct aw_ehci_conf a31_ehci_conf = {
+	.sdram_init = false,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-ehci",	(uintptr_t)&a10_ehci_conf },
+	{ "allwinner,sun5i-a13-ehci",	(uintptr_t)&a10_ehci_conf },
+	{ "allwinner,sun6i-a31-ehci",	(uintptr_t)&a31_ehci_conf },
+	{ "allwinner,sun7i-a20-ehci",	(uintptr_t)&a10_ehci_conf },
+	{ "allwinner,sun8i-a83t-ehci",	(uintptr_t)&a31_ehci_conf },
+	{ "allwinner,sun8i-h3-ehci",	(uintptr_t)&a31_ehci_conf },
+	{ NULL,				(uintptr_t)NULL }
+};
+
 static int
 a10_ehci_probe(device_t self)
 {
@@ -98,7 +125,7 @@
 	if (!ofw_bus_status_okay(self))
 		return (ENXIO);
 
-	if (!ofw_bus_is_compatible(self, "allwinner,usb-ehci")) 
+	if (ofw_bus_search_compatible(self, compat_data)->ocd_data == 0)
 		return (ENXIO);
 
 	device_set_desc(self, EHCI_HC_DEVSTR);
@@ -109,13 +136,16 @@
 static int
 a10_ehci_attach(device_t self)
 {
-	ehci_softc_t *sc = device_get_softc(self);
+	struct aw_ehci_softc *aw_sc = device_get_softc(self);
+	ehci_softc_t *sc = &aw_sc->sc;
+	const struct aw_ehci_conf *conf;
 	bus_space_handle_t bsh;
-	device_t sc_gpio_dev;
 	int err;
 	int rid;
 	uint32_t reg_value = 0;
 
+	conf = USB_CONF(self);
+
 	/* initialise some bus fields */
 	sc->sc_bus.parent = self;
 	sc->sc_bus.devices = sc->sc_devices;
@@ -165,13 +195,6 @@
 
 	sprintf(sc->sc_vendor, "Allwinner");
 
-        /* Get the GPIO device, we need this to give power to USB */
-	sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
-	if (sc_gpio_dev == NULL) {
-		device_printf(self, "Error: failed to get the GPIO device\n");
-		goto error;
-	}
-
 	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
 	    NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
 	if (err) {
@@ -182,17 +205,39 @@
 
 	sc->sc_flags |= EHCI_SCFLG_DONTRESET;
 
+	/* De-assert reset */
+	if (hwreset_get_by_ofw_idx(self, 0, 0, &aw_sc->rst) == 0) {
+		err = hwreset_deassert(aw_sc->rst);
+		if (err != 0) {
+			device_printf(self, "Could not de-assert reset\n");
+			goto error;
+		}
+	}
+
 	/* Enable clock for USB */
-	a10_clk_usb_activate();
+	err = clk_get_by_ofw_index(self, 0, 0, &aw_sc->clk);
+	if (err != 0) {
+		device_printf(self, "Could not get clock\n");
+		goto error;
+	}
+	err = clk_enable(aw_sc->clk);
+	if (err != 0) {
+		device_printf(self, "Could not enable clock\n");
+		goto error;
+	}
 
-	/* Give power to USB */
-	GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB2_PWR, GPIO_PIN_OUTPUT);
-	GPIO_PIN_SET(sc_gpio_dev, GPIO_USB2_PWR, GPIO_PIN_HIGH);
+	/* Enable USB PHY */
+	err = phy_get_by_ofw_name(self, 0, "usb", &aw_sc->phy);
+	if (err != 0) {
+		device_printf(self, "Could not get phy\n");
+		goto error;
+	}
+	err = phy_enable(aw_sc->phy);
+	if (err != 0) {
+		device_printf(self, "Could not enable phy\n");
+		goto error;
+	}
 
-	/* Give power to USB */
-	GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB1_PWR, GPIO_PIN_OUTPUT);
-	GPIO_PIN_SET(sc_gpio_dev, GPIO_USB1_PWR, GPIO_PIN_HIGH);
-
 	/* Enable passby */
 	reg_value = A10_READ_4(sc, SW_USB_PMU_IRQ_ENABLE);
 	reg_value |= SW_AHB_INCR8; /* AHB INCR8 enable */
@@ -202,9 +247,11 @@
 	A10_WRITE_4(sc, SW_USB_PMU_IRQ_ENABLE, reg_value);
 
 	/* Configure port */
-	reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
-	reg_value |= SW_SDRAM_BP_HPCR_ACCESS;
-	A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+	if (conf->sdram_init) {
+		reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
+		reg_value |= SW_SDRAM_BP_HPCR_ACCESS;
+		A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+	}
 
 	err = ehci_init(sc);
 	if (!err) {
@@ -217,6 +264,10 @@
 	return (0);
 
 error:
+	if (aw_sc->clk != NULL) {
+		clk_disable(aw_sc->clk);
+		clk_release(aw_sc->clk);
+	}
 	a10_ehci_detach(self);
 	return (ENXIO);
 }
@@ -224,10 +275,14 @@
 static int
 a10_ehci_detach(device_t self)
 {
-	ehci_softc_t *sc = device_get_softc(self);
+	struct aw_ehci_softc *aw_sc = device_get_softc(self);
+	ehci_softc_t *sc = &aw_sc->sc;
+	const struct aw_ehci_conf *conf;
 	int err;
 	uint32_t reg_value = 0;
 
+	conf = USB_CONF(self);
+
 	/* during module unload there are lots of children leftover */
 	device_delete_children(self);
 
@@ -258,9 +313,11 @@
 	usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
 
 	/* Disable configure port */
-	reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
-	reg_value &= ~SW_SDRAM_BP_HPCR_ACCESS;
-	A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+	if (conf->sdram_init) {
+		reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
+		reg_value &= ~SW_SDRAM_BP_HPCR_ACCESS;
+		A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+	}
 
 	/* Disable passby */
 	reg_value = A10_READ_4(sc, SW_USB_PMU_IRQ_ENABLE);
@@ -271,8 +328,17 @@
 	A10_WRITE_4(sc, SW_USB_PMU_IRQ_ENABLE, reg_value);
 
 	/* Disable clock for USB */
-	a10_clk_usb_deactivate();
+	if (aw_sc->clk != NULL) {
+		clk_disable(aw_sc->clk);
+		clk_release(aw_sc->clk);
+	}
 
+	/* Assert reset */
+	if (aw_sc->rst != NULL) {
+		hwreset_assert(aw_sc->rst);
+		hwreset_release(aw_sc->rst);
+	}
+
 	return (0);
 }
 
@@ -291,10 +357,10 @@
 static driver_t ehci_driver = {
 	.name = "ehci",
 	.methods = ehci_methods,
-	.size = sizeof(ehci_softc_t),
+	.size = sizeof(struct aw_ehci_softc),
 };
 
 static devclass_t ehci_devclass;
 
-DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
-MODULE_DEPEND(ehci, usb, 1, 1, 1);
+DRIVER_MODULE(a10_ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
+MODULE_DEPEND(a10_ehci, usb, 1, 1, 1);

Added: trunk/sys/arm/allwinner/a10_fb.c
===================================================================
--- trunk/sys/arm/allwinner/a10_fb.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_fb.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,663 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_fb.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner A10/A20 Framebuffer
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_fb.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/fbio.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "fb_if.h"
+#include "hdmi_if.h"
+
+#define	FB_DEFAULT_W	800
+#define	FB_DEFAULT_H	600
+#define	FB_DEFAULT_REF	60
+#define	FB_BPP		32
+#define	FB_ALIGN	0x1000
+
+#define	HDMI_ENABLE_DELAY	20000
+#define	DEBE_FREQ		300000000
+
+#define	DOT_CLOCK_TO_HZ(c)	((c) * 1000)
+
+/* Display backend */
+#define	DEBE_REG_START		0x800
+#define	DEBE_REG_END		0x1000
+#define	DEBE_REG_WIDTH		4
+#define	DEBE_MODCTL		0x800
+#define	MODCTL_ITLMOD_EN	(1 << 28)
+#define	MODCTL_OUT_SEL_MASK	(0x7 << 20)
+#define	MODCTL_OUT_SEL(sel)	((sel) << 20)
+#define	OUT_SEL_LCD		0
+#define	MODCTL_LAY0_EN		(1 << 8)
+#define	MODCTL_START_CTL	(1 << 1)
+#define	MODCTL_EN		(1 << 0)
+#define	DEBE_DISSIZE		0x808
+#define	DIS_HEIGHT(h)		(((h) - 1) << 16)
+#define	DIS_WIDTH(w)		(((w) - 1) << 0)
+#define	DEBE_LAYSIZE0		0x810
+#define	LAY_HEIGHT(h)		(((h) - 1) << 16)
+#define	LAY_WIDTH(w)		(((w) - 1) << 0)
+#define	DEBE_LAYCOOR0		0x820
+#define	LAY_XCOOR(x)		((x) << 16)
+#define	LAY_YCOOR(y)		((y) << 0)
+#define	DEBE_LAYLINEWIDTH0	0x840
+#define	DEBE_LAYFB_L32ADD0	0x850
+#define	LAYFB_L32ADD(pa)	((pa) << 3)
+#define	DEBE_LAYFB_H4ADD	0x860
+#define	LAY0FB_H4ADD(pa)	((pa) >> 29)
+#define	DEBE_REGBUFFCTL		0x870
+#define	REGBUFFCTL_LOAD		(1 << 0)
+#define	DEBE_ATTCTL1		0x8a0
+#define	ATTCTL1_FBFMT(fmt)	((fmt) << 8)
+#define	FBFMT_XRGB8888		9
+#define	ATTCTL1_FBPS(ps)	((ps) << 0)
+#define	FBPS_32BPP_ARGB		0
+
+/* Timing controller */
+#define	TCON_GCTL		0x000
+#define	GCTL_TCON_EN		(1 << 31)
+#define	GCTL_IO_MAP_SEL_TCON1	(1 << 0)
+#define	TCON_GINT1		0x008
+#define	GINT1_TCON1_LINENO(n)	(((n) + 2) << 0)
+#define	TCON0_DCLK		0x044
+#define	DCLK_EN			0xf0000000
+#define	TCON1_CTL		0x090
+#define	TCON1_EN		(1 << 31)
+#define	INTERLACE_EN		(1 << 20)
+#define	TCON1_SRC_SEL(src)	((src) << 0)
+#define	TCON1_SRC_CH1		0
+#define	TCON1_SRC_CH2		1
+#define	TCON1_SRC_BLUE		2
+#define	TCON1_START_DELAY(sd)	((sd) << 4)
+#define	TCON1_BASIC0		0x094
+#define	TCON1_BASIC1		0x098
+#define	TCON1_BASIC2		0x09c
+#define	TCON1_BASIC3		0x0a0
+#define	TCON1_BASIC4		0x0a4
+#define	TCON1_BASIC5		0x0a8
+#define	BASIC_X(x)		(((x) - 1) << 16)
+#define	BASIC_Y(y)		(((y) - 1) << 0)
+#define	BASIC3_HT(ht)		(((ht) - 1) << 16)
+#define	BASIC3_HBP(hbp)		(((hbp) - 1) << 0)
+#define	BASIC4_VT(vt)		((vt) << 16)
+#define	BASIC4_VBP(vbp)		(((vbp) - 1) << 0)
+#define	BASIC5_HSPW(hspw)	(((hspw) - 1) << 16)
+#define	BASIC5_VSPW(vspw)	(((vspw) - 1) << 0)
+#define	TCON1_IO_POL		0x0f0
+#define	IO_POL_IO2_INV		(1 << 26)
+#define	IO_POL_PHSYNC		(1 << 25)
+#define	IO_POL_PVSYNC		(1 << 24)
+#define	TCON1_IO_TRI		0x0f4
+#define	IO0_OUTPUT_TRI_EN	(1 << 24)
+#define	IO1_OUTPUT_TRI_EN	(1 << 25)
+#define	IO_TRI_MASK		0xffffffff
+#define	START_DELAY(vbl)	(MIN(32, (vbl)) - 2)
+#define	VBLANK_LEN(vt, vd, i)	((((vt) << (i)) >> 1) - (vd) - 2)
+#define	VTOTAL(vt)		((vt) * 2)
+#define	DIVIDE(x, y)		(((x) + ((y) / 2)) / (y))
+
+struct a10fb_softc {
+	device_t		dev;
+	device_t		fbdev;
+	struct resource		*res[2];
+
+	/* Framebuffer */
+	struct fb_info		info;
+	size_t			fbsize;
+	bus_addr_t		paddr;
+	vm_offset_t		vaddr;
+
+	/* HDMI */
+	eventhandler_tag	hdmi_evh;
+};
+
+static struct resource_spec a10fb_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* DEBE */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* TCON */
+	{ -1, 0 }
+};
+
+#define	DEBE_READ(sc, reg)		bus_read_4((sc)->res[0], (reg))
+#define	DEBE_WRITE(sc, reg, val)	bus_write_4((sc)->res[0], (reg), (val))
+
+#define	TCON_READ(sc, reg)		bus_read_4((sc)->res[1], (reg))
+#define	TCON_WRITE(sc, reg, val)	bus_write_4((sc)->res[1], (reg), (val))
+
+static int
+a10fb_allocfb(struct a10fb_softc *sc)
+{
+	sc->vaddr = kmem_alloc_contig(kernel_arena, sc->fbsize,
+	    M_NOWAIT | M_ZERO, 0, ~0, FB_ALIGN, 0, VM_MEMATTR_WRITE_COMBINING);
+	if (sc->vaddr == 0) {
+		device_printf(sc->dev, "failed to allocate FB memory\n");
+		return (ENOMEM);
+	}
+	sc->paddr = pmap_kextract(sc->vaddr);
+
+	return (0);
+}
+
+static void
+a10fb_freefb(struct a10fb_softc *sc)
+{
+	kmem_free(kernel_arena, sc->vaddr, sc->fbsize);
+}
+
+static int
+a10fb_setup_debe(struct a10fb_softc *sc, const struct videomode *mode)
+{
+	int width, height, interlace, reg;
+	clk_t clk_ahb, clk_dram, clk_debe;
+	hwreset_t rst;
+	uint32_t val;
+	int error;
+
+	interlace = !!(mode->flags & VID_INTERLACE);
+	width = mode->hdisplay;
+	height = mode->vdisplay << interlace;
+
+	/* Leave reset */
+	error = hwreset_get_by_ofw_name(sc->dev, 0, "de_be", &rst);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find reset 'de_be'\n");
+		return (error);
+	}
+	error = hwreset_deassert(rst);
+	if (error != 0) {
+		device_printf(sc->dev, "couldn't de-assert reset 'de_be'\n");
+		return (error);
+	}
+	/* Gating AHB clock for BE */
+	error = clk_get_by_ofw_name(sc->dev, 0, "ahb_de_be", &clk_ahb);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find clk 'ahb_de_be'\n");
+		return (error);
+	}
+	error = clk_enable(clk_ahb);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot enable clk 'ahb_de_be'\n");
+		return (error);
+	}
+	/* Enable DRAM clock to BE */
+	error = clk_get_by_ofw_name(sc->dev, 0, "dram_de_be", &clk_dram);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find clk 'dram_de_be'\n");
+		return (error);
+	}
+	error = clk_enable(clk_dram);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot enable clk 'dram_de_be'\n");
+		return (error);
+	}
+	/* Set BE clock to 300MHz and enable */
+	error = clk_get_by_ofw_name(sc->dev, 0, "de_be", &clk_debe);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find clk 'de_be'\n");
+		return (error);
+	}
+	error = clk_set_freq(clk_debe, DEBE_FREQ, CLK_SET_ROUND_DOWN);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot set 'de_be' frequency\n");
+		return (error);
+	}
+	error = clk_enable(clk_debe);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot enable clk 'de_be'\n");
+		return (error);
+	}
+
+	/* Initialize all registers to 0 */
+	for (reg = DEBE_REG_START; reg < DEBE_REG_END; reg += DEBE_REG_WIDTH)
+		DEBE_WRITE(sc, reg, 0);
+
+	/* Enable display backend */
+	DEBE_WRITE(sc, DEBE_MODCTL, MODCTL_EN);
+
+	/* Set display size */
+	DEBE_WRITE(sc, DEBE_DISSIZE, DIS_HEIGHT(height) | DIS_WIDTH(width));
+
+	/* Set layer 0 size, position, and stride */
+	DEBE_WRITE(sc, DEBE_LAYSIZE0, LAY_HEIGHT(height) | LAY_WIDTH(width));
+	DEBE_WRITE(sc, DEBE_LAYCOOR0, LAY_XCOOR(0) | LAY_YCOOR(0));
+	DEBE_WRITE(sc, DEBE_LAYLINEWIDTH0, width * FB_BPP);
+
+	/* Point layer 0 to FB memory */
+	DEBE_WRITE(sc, DEBE_LAYFB_L32ADD0, LAYFB_L32ADD(sc->paddr));
+	DEBE_WRITE(sc, DEBE_LAYFB_H4ADD, LAY0FB_H4ADD(sc->paddr));
+
+	/* Set backend format and pixel sequence */
+	DEBE_WRITE(sc, DEBE_ATTCTL1, ATTCTL1_FBFMT(FBFMT_XRGB8888) |
+	    ATTCTL1_FBPS(FBPS_32BPP_ARGB));
+
+	/* Enable layer 0, output to LCD, setup interlace */
+	val = DEBE_READ(sc, DEBE_MODCTL);
+	val |= MODCTL_LAY0_EN;
+	val &= ~MODCTL_OUT_SEL_MASK;
+	val |= MODCTL_OUT_SEL(OUT_SEL_LCD);
+	if (interlace)
+		val |= MODCTL_ITLMOD_EN;
+	else
+		val &= ~MODCTL_ITLMOD_EN;
+	DEBE_WRITE(sc, DEBE_MODCTL, val);
+
+	/* Commit settings */
+	DEBE_WRITE(sc, DEBE_REGBUFFCTL, REGBUFFCTL_LOAD);
+
+	/* Start DEBE */
+	val = DEBE_READ(sc, DEBE_MODCTL);
+	val |= MODCTL_START_CTL;
+	DEBE_WRITE(sc, DEBE_MODCTL, val);
+
+	return (0);
+}
+
+static int
+a10fb_setup_pll(struct a10fb_softc *sc, uint64_t freq)
+{
+	clk_t clk_sclk1, clk_sclk2;
+	int error;
+
+	error = clk_get_by_ofw_name(sc->dev, 0, "lcd_ch1_sclk1", &clk_sclk1);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find clk 'lcd_ch1_sclk1'\n");
+		return (error);
+	}
+	error = clk_get_by_ofw_name(sc->dev, 0, "lcd_ch1_sclk2", &clk_sclk2);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find clk 'lcd_ch1_sclk2'\n");
+		return (error);
+	}
+
+	error = clk_set_freq(clk_sclk2, freq, 0);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot set lcd ch1 frequency\n");
+		return (error);
+	}
+	error = clk_enable(clk_sclk2);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot enable lcd ch1 sclk2\n");
+		return (error);
+	}
+	error = clk_enable(clk_sclk1);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot enable lcd ch1 sclk1\n");
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+a10fb_setup_tcon(struct a10fb_softc *sc, const struct videomode *mode)
+{
+	u_int interlace, hspw, hbp, vspw, vbp, vbl, width, height, start_delay;
+	u_int vtotal, framerate, clk;
+	clk_t clk_ahb;
+	hwreset_t rst;
+	uint32_t val;
+	int error;
+
+	interlace = !!(mode->flags & VID_INTERLACE);
+	width = mode->hdisplay;
+	height = mode->vdisplay;
+	hspw = mode->hsync_end - mode->hsync_start;
+	hbp = mode->htotal - mode->hsync_start;
+	vspw = mode->vsync_end - mode->vsync_start;
+	vbp = mode->vtotal - mode->vsync_start;
+	vbl = VBLANK_LEN(mode->vtotal, mode->vdisplay, interlace);
+	start_delay = START_DELAY(vbl);
+
+	/* Leave reset */
+	error = hwreset_get_by_ofw_name(sc->dev, 0, "lcd", &rst);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find reset 'lcd'\n");
+		return (error);
+	}
+	error = hwreset_deassert(rst);
+	if (error != 0) {
+		device_printf(sc->dev, "couldn't de-assert reset 'lcd'\n");
+		return (error);
+	}
+	/* Gating AHB clock for LCD */
+	error = clk_get_by_ofw_name(sc->dev, 0, "ahb_lcd", &clk_ahb);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot find clk 'ahb_lcd'\n");
+		return (error);
+	}
+	error = clk_enable(clk_ahb);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot enable clk 'ahb_lcd'\n");
+		return (error);
+	}
+
+	/* Disable TCON and TCON1 */
+	TCON_WRITE(sc, TCON_GCTL, 0);
+	TCON_WRITE(sc, TCON1_CTL, 0);
+
+	/* Enable clocks */
+	TCON_WRITE(sc, TCON0_DCLK, DCLK_EN);
+
+	/* Disable IO and data output ports */
+	TCON_WRITE(sc, TCON1_IO_TRI, IO_TRI_MASK);
+
+	/* Disable TCON and select TCON1 */
+	TCON_WRITE(sc, TCON_GCTL, GCTL_IO_MAP_SEL_TCON1);
+
+	/* Source width and height */
+	TCON_WRITE(sc, TCON1_BASIC0, BASIC_X(width) | BASIC_Y(height));
+	/* Scaler width and height */
+	TCON_WRITE(sc, TCON1_BASIC1, BASIC_X(width) | BASIC_Y(height));
+	/* Output width and height */
+	TCON_WRITE(sc, TCON1_BASIC2, BASIC_X(width) | BASIC_Y(height));
+	/* Horizontal total and back porch */
+	TCON_WRITE(sc, TCON1_BASIC3, BASIC3_HT(mode->htotal) | BASIC3_HBP(hbp));
+	/* Vertical total and back porch */
+	vtotal = VTOTAL(mode->vtotal);
+	if (interlace) {
+		framerate = DIVIDE(DIVIDE(DOT_CLOCK_TO_HZ(mode->dot_clock),
+		    mode->htotal), mode->vtotal);
+		clk = mode->htotal * (VTOTAL(mode->vtotal) + 1) * framerate;
+		if ((clk / 2) == DOT_CLOCK_TO_HZ(mode->dot_clock))
+			vtotal += 1;
+	}
+	TCON_WRITE(sc, TCON1_BASIC4, BASIC4_VT(vtotal) | BASIC4_VBP(vbp));
+	/* Horizontal and vertical sync */
+	TCON_WRITE(sc, TCON1_BASIC5, BASIC5_HSPW(hspw) | BASIC5_VSPW(vspw));
+	/* Polarity */
+	val = IO_POL_IO2_INV;
+	if (mode->flags & VID_PHSYNC)
+		val |= IO_POL_PHSYNC;
+	if (mode->flags & VID_PVSYNC)
+		val |= IO_POL_PVSYNC;
+	TCON_WRITE(sc, TCON1_IO_POL, val);
+
+	/* Set scan line for TCON1 line trigger */
+	TCON_WRITE(sc, TCON_GINT1, GINT1_TCON1_LINENO(start_delay));
+
+	/* Enable TCON1 */
+	val = TCON1_EN;
+	if (interlace)
+		val |= INTERLACE_EN;
+	val |= TCON1_START_DELAY(start_delay);
+	val |= TCON1_SRC_SEL(TCON1_SRC_CH1);
+	TCON_WRITE(sc, TCON1_CTL, val);
+
+	/* Setup PLL */
+	return (a10fb_setup_pll(sc, DOT_CLOCK_TO_HZ(mode->dot_clock)));
+}
+
+static void
+a10fb_enable_tcon(struct a10fb_softc *sc, int onoff)
+{
+	uint32_t val;
+
+	/* Enable TCON */
+	val = TCON_READ(sc, TCON_GCTL);
+	if (onoff)
+		val |= GCTL_TCON_EN;
+	else
+		val &= ~GCTL_TCON_EN;
+	TCON_WRITE(sc, TCON_GCTL, val);
+
+	/* Enable TCON1 IO0/IO1 outputs */
+	val = TCON_READ(sc, TCON1_IO_TRI);
+	if (onoff)
+		val &= ~(IO0_OUTPUT_TRI_EN | IO1_OUTPUT_TRI_EN);
+	else
+		val |= (IO0_OUTPUT_TRI_EN | IO1_OUTPUT_TRI_EN);
+	TCON_WRITE(sc, TCON1_IO_TRI, val);
+}
+
+static int
+a10fb_configure(struct a10fb_softc *sc, const struct videomode *mode)
+{
+	size_t fbsize;
+	int error;
+
+	fbsize = round_page(mode->hdisplay * mode->vdisplay * (FB_BPP / NBBY));
+
+	/* Detach the old FB device */
+	if (sc->fbdev != NULL) {
+		device_delete_child(sc->dev, sc->fbdev);
+		sc->fbdev = NULL;
+	}
+
+	/* If the FB size has changed, free the old FB memory */
+	if (sc->fbsize > 0 && sc->fbsize != fbsize) {
+		a10fb_freefb(sc);
+		sc->vaddr = 0;
+	}
+
+	/* Allocate the FB if necessary */
+	sc->fbsize = fbsize;
+	if (sc->vaddr == 0) {
+		error = a10fb_allocfb(sc);
+		if (error != 0) {
+			device_printf(sc->dev, "failed to allocate FB memory\n");
+			return (ENXIO);
+		}
+	}
+
+	/* Setup display backend */
+	error = a10fb_setup_debe(sc, mode);
+	if (error != 0)
+		return (error);
+
+	/* Setup display timing controller */
+	error = a10fb_setup_tcon(sc, mode);
+	if (error != 0)
+		return (error);
+
+	/* Attach framebuffer device */
+	sc->info.fb_name = device_get_nameunit(sc->dev);
+	sc->info.fb_vbase = (intptr_t)sc->vaddr;
+	sc->info.fb_pbase = sc->paddr;
+	sc->info.fb_size = sc->fbsize;
+	sc->info.fb_bpp = sc->info.fb_depth = FB_BPP;
+	sc->info.fb_stride = mode->hdisplay * (FB_BPP / NBBY);
+	sc->info.fb_width = mode->hdisplay;
+	sc->info.fb_height = mode->vdisplay;
+
+	sc->fbdev = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
+	if (sc->fbdev == NULL) {
+		device_printf(sc->dev, "failed to add fbd child\n");
+		return (ENOENT);
+	}
+
+	error = device_probe_and_attach(sc->fbdev);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to attach fbd device\n");
+		return (error);
+	}
+
+	return (0);
+}
+
+static void
+a10fb_hdmi_event(void *arg, device_t hdmi_dev)
+{
+	const struct videomode *mode;
+	struct videomode hdmi_mode;
+	struct a10fb_softc *sc;
+	struct edid_info ei;
+	uint8_t *edid;
+	uint32_t edid_len;
+	int error;
+
+	sc = arg;
+	edid = NULL;
+	edid_len = 0;
+	mode = NULL;
+
+	error = HDMI_GET_EDID(hdmi_dev, &edid, &edid_len);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to get EDID: %d\n", error);
+	} else {
+		error = edid_parse(edid, &ei);
+		if (error != 0) {
+			device_printf(sc->dev, "failed to parse EDID: %d\n",
+			    error);
+		} else {
+			if (bootverbose)
+				edid_print(&ei);
+			mode = ei.edid_preferred_mode;
+		}
+	}
+
+	/* If the preferred mode could not be determined, use the default */
+	if (mode == NULL)
+		mode = pick_mode_by_ref(FB_DEFAULT_W, FB_DEFAULT_H,
+		    FB_DEFAULT_REF);
+
+	if (mode == NULL) {
+		device_printf(sc->dev, "failed to find usable video mode\n");
+		return;
+	}
+
+	if (bootverbose)
+		device_printf(sc->dev, "using %dx%d\n",
+		    mode->hdisplay, mode->vdisplay);
+
+	/* Disable HDMI */
+	HDMI_ENABLE(hdmi_dev, 0);
+
+	/* Disable timing controller */
+	a10fb_enable_tcon(sc, 0);
+
+	/* Configure DEBE and TCON */
+	error = a10fb_configure(sc, mode);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to configure FB: %d\n", error);
+		return;
+	}
+
+	hdmi_mode = *mode;
+	hdmi_mode.hskew = mode->hsync_end - mode->hsync_start;
+	hdmi_mode.flags |= VID_HSKEW;
+	HDMI_SET_VIDEOMODE(hdmi_dev, &hdmi_mode);
+
+	/* Enable timing controller */
+	a10fb_enable_tcon(sc, 1);
+
+	DELAY(HDMI_ENABLE_DELAY);
+
+	/* Enable HDMI */
+	HDMI_ENABLE(hdmi_dev, 1);
+}
+
+static int
+a10fb_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-fb"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Framebuffer");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10fb_attach(device_t dev)
+{
+	struct a10fb_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, a10fb_spec, sc->res)) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	sc->hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event,
+	    a10fb_hdmi_event, sc, 0);
+
+	return (0);
+}
+
+static struct fb_info *
+a10fb_fb_getinfo(device_t dev)
+{
+	struct a10fb_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (&sc->info);
+}
+
+static device_method_t a10fb_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a10fb_probe),
+	DEVMETHOD(device_attach,	a10fb_attach),
+
+	/* FB interface */
+	DEVMETHOD(fb_getinfo,		a10fb_fb_getinfo),
+
+	DEVMETHOD_END
+};
+
+static driver_t a10fb_driver = {
+	"fb",
+	a10fb_methods,
+	sizeof(struct a10fb_softc),
+};
+
+static devclass_t a10fb_devclass;
+
+DRIVER_MODULE(fb, simplebus, a10fb_driver, a10fb_devclass, 0, 0);


Property changes on: trunk/sys/arm/allwinner/a10_fb.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/a10_gpio.c
===================================================================
--- trunk/sys/arm/allwinner/a10_gpio.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/a10_gpio.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -28,7 +28,7 @@
  *
  */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/a10_gpio.c 278786 2015-02-14 21:16:19Z loos $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_gpio.c 331722 2018-03-29 02:50:57Z eadler $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -42,40 +42,112 @@
 #include <sys/gpio.h>
 
 #include <machine/bus.h>
-#include <machine/cpu.h>
-#include <machine/cpufunc.h>
 #include <machine/resource.h>
-#include <machine/fdt.h>
 #include <machine/intr.h>
 
 #include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/gpio/gpiobusvar.h>
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <arm/allwinner/aw_machdep.h>
+#include <arm/allwinner/allwinner_pinctrl.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+
 #include "gpio_if.h"
-#include "a10_gpio.h"
 
-/*
- * A10 have 9 banks of gpio.
- * 32 pins per bank:
- * PA0 - PA17 | PB0 - PB23 | PC0 - PC24
- * PD0 - PD27 | PE0 - PE31 | PF0 - PF5
- * PG0 - PG9 | PH0 - PH27 | PI0 - PI12
- */
-
-#define	A10_GPIO_PINS		288
 #define	A10_GPIO_DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |	\
     GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
 
-#define A10_GPIO_NONE		0
-#define A10_GPIO_PULLUP		1
-#define A10_GPIO_PULLDOWN	2
+#define	A10_GPIO_NONE		0
+#define	A10_GPIO_PULLUP		1
+#define	A10_GPIO_PULLDOWN	2
 
-#define A10_GPIO_INPUT		0
-#define A10_GPIO_OUTPUT		1
+#define	A10_GPIO_INPUT		0
+#define	A10_GPIO_OUTPUT		1
 
+#define	AW_GPIO_DRV_MASK	0x3
+#define	AW_GPIO_PUD_MASK	0x3
+
+#define	AW_PINCTRL	1
+#define	AW_R_PINCTRL	2
+
+/* Defined in a10_padconf.c */
+#ifdef SOC_ALLWINNER_A10
+extern const struct allwinner_padconf a10_padconf;
+#endif
+
+/* Defined in a13_padconf.c */
+#ifdef SOC_ALLWINNER_A13
+extern const struct allwinner_padconf a13_padconf;
+#endif
+
+/* Defined in a20_padconf.c */
+#ifdef SOC_ALLWINNER_A20
+extern const struct allwinner_padconf a20_padconf;
+#endif
+
+/* Defined in a31_padconf.c */
+#ifdef SOC_ALLWINNER_A31
+extern const struct allwinner_padconf a31_padconf;
+#endif
+
+/* Defined in a31s_padconf.c */
+#ifdef SOC_ALLWINNER_A31S
+extern const struct allwinner_padconf a31s_padconf;
+#endif
+
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+extern const struct allwinner_padconf a31_r_padconf;
+#endif
+
+/* Defined in h3_padconf.c */
+#ifdef SOC_ALLWINNER_H3
+extern const struct allwinner_padconf h3_padconf;
+extern const struct allwinner_padconf h3_r_padconf;
+#endif
+
+/* Defined in a83t_padconf.c */
+#ifdef SOC_ALLWINNER_A83T
+extern const struct allwinner_padconf a83t_padconf;
+extern const struct allwinner_padconf a83t_r_padconf;
+#endif
+
+static struct ofw_compat_data compat_data[] = {
+#ifdef SOC_ALLWINNER_A10
+	{"allwinner,sun4i-a10-pinctrl",		(uintptr_t)&a10_padconf},
+#endif
+#ifdef SOC_ALLWINNER_A13
+	{"allwinner,sun5i-a13-pinctrl",		(uintptr_t)&a13_padconf},
+#endif
+#ifdef SOC_ALLWINNER_A20
+	{"allwinner,sun7i-a20-pinctrl",		(uintptr_t)&a20_padconf},
+#endif
+#ifdef SOC_ALLWINNER_A31
+	{"allwinner,sun6i-a31-pinctrl",		(uintptr_t)&a31_padconf},
+#endif
+#ifdef SOC_ALLWINNER_A31S
+	{"allwinner,sun6i-a31s-pinctrl",	(uintptr_t)&a31s_padconf},
+#endif
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+	{"allwinner,sun6i-a31-r-pinctrl",	(uintptr_t)&a31_r_padconf},
+#endif
+#ifdef SOC_ALLWINNER_A83T
+	{"allwinner,sun8i-a83t-pinctrl",	(uintptr_t)&a83t_padconf},
+	{"allwinner,sun8i-a83t-r-pinctrl",	(uintptr_t)&a83t_r_padconf},
+#endif
+#ifdef SOC_ALLWINNER_H3
+	{"allwinner,sun8i-h3-pinctrl",		(uintptr_t)&h3_padconf},
+	{"allwinner,sun8i-h3-r-pinctrl",	(uintptr_t)&h3_r_padconf},
+#endif
+	{NULL,	0}
+};
+
 struct a10_gpio_softc {
 	device_t		sc_dev;
+	device_t		sc_busdev;
 	struct mtx		sc_mtx;
 	struct resource *	sc_mem_res;
 	struct resource *	sc_irq_res;
@@ -82,18 +154,17 @@
 	bus_space_tag_t		sc_bst;
 	bus_space_handle_t	sc_bsh;
 	void *			sc_intrhand;
-	int			sc_gpio_npins;
-	struct gpio_pin		sc_gpio_pins[A10_GPIO_PINS];
+	const struct allwinner_padconf *	padconf;
 };
 
-#define	A10_GPIO_LOCK(_sc)		mtx_lock(&_sc->sc_mtx)
-#define	A10_GPIO_UNLOCK(_sc)		mtx_unlock(&_sc->sc_mtx)
-#define	A10_GPIO_LOCK_ASSERT(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED)
+#define	A10_GPIO_LOCK(_sc)		mtx_lock_spin(&(_sc)->sc_mtx)
+#define	A10_GPIO_UNLOCK(_sc)		mtx_unlock_spin(&(_sc)->sc_mtx)
+#define	A10_GPIO_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
 
-#define	A10_GPIO_GP_CFG(_bank, _pin)	0x00 + ((_bank) * 0x24) + ((_pin)<<2)
+#define	A10_GPIO_GP_CFG(_bank, _idx)	0x00 + ((_bank) * 0x24) + ((_idx) << 2)
 #define	A10_GPIO_GP_DAT(_bank)		0x10 + ((_bank) * 0x24)
-#define	A10_GPIO_GP_DRV(_bank, _pin)	0x14 + ((_bank) * 0x24) + ((_pin)<<2)
-#define	A10_GPIO_GP_PUL(_bank, _pin)	0x1c + ((_bank) * 0x24) + ((_pin)<<2)
+#define	A10_GPIO_GP_DRV(_bank, _idx)	0x14 + ((_bank) * 0x24) + ((_idx) << 2)
+#define	A10_GPIO_GP_PUL(_bank, _idx)	0x1c + ((_bank) * 0x24) + ((_idx) << 2)
 
 #define	A10_GPIO_GP_INT_CFG0		0x200
 #define	A10_GPIO_GP_INT_CFG1		0x204
@@ -104,7 +175,8 @@
 #define	A10_GPIO_GP_INT_STA		0x214
 #define	A10_GPIO_GP_INT_DEB		0x218
 
-static struct a10_gpio_softc *a10_gpio_sc;
+static int a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value);
+static int a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
 
 #define	A10_GPIO_WRITE(_sc, _off, _val)		\
     bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
@@ -116,113 +188,178 @@
 {
 	uint32_t bank, func, offset;
 
-	bank = pin / 32;
-	pin = pin - 32 * bank;
-	func = pin >> 3;
+	/* Must be called with lock held. */
+	A10_GPIO_LOCK_ASSERT(sc);
+
+	if (pin > sc->padconf->npins)
+		return (0);
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
 	offset = ((pin & 0x07) << 2);
 
-	A10_GPIO_LOCK(sc);
-	func = (A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, func)) >> offset) & 7;
-	A10_GPIO_UNLOCK(sc);
+	func = A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, pin >> 3));
 
-	return (func);
+	return ((func >> offset) & 0x7);
 }
 
-static uint32_t
-a10_gpio_func_flag(uint32_t nfunc)
+static int
+a10_gpio_set_function(struct a10_gpio_softc *sc, uint32_t pin, uint32_t f)
 {
+	uint32_t bank, data, offset;
 
-	switch (nfunc) {
-	case A10_GPIO_INPUT:
-		return (GPIO_PIN_INPUT);
-	case A10_GPIO_OUTPUT:
-		return (GPIO_PIN_OUTPUT);
-	}
+	/* Check if the function exists in the padconf data */
+	if (sc->padconf->pins[pin].functions[f] == NULL)
+		return (EINVAL);
+
+	/* Must be called with lock held. */
+	A10_GPIO_LOCK_ASSERT(sc);
+
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
+	offset = ((pin & 0x07) << 2);
+
+	data = A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, pin >> 3));
+	data &= ~(7 << offset);
+	data |= (f << offset);
+	A10_GPIO_WRITE(sc, A10_GPIO_GP_CFG(bank, pin >> 3), data);
+
 	return (0);
 }
 
-static void
-a10_gpio_set_function(struct a10_gpio_softc *sc, uint32_t pin, uint32_t f)
+static uint32_t
+a10_gpio_get_pud(struct a10_gpio_softc *sc, uint32_t pin)
 {
-	uint32_t bank, func, data, offset;
+	uint32_t bank, offset, val;
 
 	/* Must be called with lock held. */
 	A10_GPIO_LOCK_ASSERT(sc);
 
-	bank = pin / 32;
-	pin = pin - 32 * bank;
-	func = pin >> 3;
-	offset = ((pin & 0x07) << 2);
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
+	offset = ((pin & 0x0f) << 1);
 
-	data = A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, func));
-	data &= ~(7 << offset);
-	data |= (f << offset);
-	A10_GPIO_WRITE(sc, A10_GPIO_GP_CFG(bank, func), data);
+	val = A10_GPIO_READ(sc, A10_GPIO_GP_PUL(bank, pin >> 4));
+
+	return ((val >> offset) & AW_GPIO_PUD_MASK);
 }
 
 static void
 a10_gpio_set_pud(struct a10_gpio_softc *sc, uint32_t pin, uint32_t state)
 {
-	uint32_t bank, offset, pull, val;
+	uint32_t bank, offset, val;
 
 	/* Must be called with lock held. */
 	A10_GPIO_LOCK_ASSERT(sc);
 
-	bank = pin / 32;
-	pin = pin - 32 * bank;
-	pull = pin >> 4;
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
 	offset = ((pin & 0x0f) << 1);
 
-	val = A10_GPIO_READ(sc, A10_GPIO_GP_PUL(bank, pull));
-	val &= ~(0x03 << offset);
+	val = A10_GPIO_READ(sc, A10_GPIO_GP_PUL(bank, pin >> 4));
+	val &= ~(AW_GPIO_PUD_MASK << offset);
 	val |= (state << offset);
-	A10_GPIO_WRITE(sc, A10_GPIO_GP_PUL(bank, pull), val);
+	A10_GPIO_WRITE(sc, A10_GPIO_GP_PUL(bank, pin >> 4), val);
 }
 
+static uint32_t
+a10_gpio_get_drv(struct a10_gpio_softc *sc, uint32_t pin)
+{
+	uint32_t bank, offset, val;
+
+	/* Must be called with lock held. */
+	A10_GPIO_LOCK_ASSERT(sc);
+
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
+	offset = ((pin & 0x0f) << 1);
+
+	val = A10_GPIO_READ(sc, A10_GPIO_GP_DRV(bank, pin >> 4));
+
+	return ((val >> offset) & AW_GPIO_DRV_MASK);
+}
+
 static void
-a10_gpio_pin_configure(struct a10_gpio_softc *sc, struct gpio_pin *pin,
-    unsigned int flags)
+a10_gpio_set_drv(struct a10_gpio_softc *sc, uint32_t pin, uint32_t drive)
 {
+	uint32_t bank, offset, val;
 
-	A10_GPIO_LOCK(sc);
+	/* Must be called with lock held. */
+	A10_GPIO_LOCK_ASSERT(sc);
 
-	/*
-	 * Manage input/output.
-	 */
-	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
-		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
-		if (flags & GPIO_PIN_OUTPUT) {
-			pin->gp_flags |= GPIO_PIN_OUTPUT;
-			a10_gpio_set_function(sc, pin->gp_pin,
-			    A10_GPIO_OUTPUT);
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
+	offset = ((pin & 0x0f) << 1);
+
+	val = A10_GPIO_READ(sc, A10_GPIO_GP_DRV(bank, pin >> 4));
+	val &= ~(AW_GPIO_DRV_MASK << offset);
+	val |= (drive << offset);
+	A10_GPIO_WRITE(sc, A10_GPIO_GP_DRV(bank, pin >> 4), val);
+}
+
+static int
+a10_gpio_pin_configure(struct a10_gpio_softc *sc, uint32_t pin, uint32_t flags)
+{
+	u_int val;
+	int err = 0;
+
+	/* Must be called with lock held. */
+	A10_GPIO_LOCK_ASSERT(sc);
+
+	if (pin > sc->padconf->npins)
+		return (EINVAL);
+
+	/* Manage input/output. */
+	if (flags & GPIO_PIN_INPUT) {
+		err = a10_gpio_set_function(sc, pin, A10_GPIO_INPUT);
+	} else if (flags & GPIO_PIN_OUTPUT) {
+		if (flags & GPIO_PIN_PRESET_LOW) {
+			a10_gpio_pin_set(sc->sc_dev, pin, 0);
+		} else if (flags & GPIO_PIN_PRESET_HIGH) {
+			a10_gpio_pin_set(sc->sc_dev, pin, 1);
 		} else {
-			pin->gp_flags |= GPIO_PIN_INPUT;
-			a10_gpio_set_function(sc, pin->gp_pin,
-			    A10_GPIO_INPUT);
+			/* Read the pin and preset output to current state. */
+			err = a10_gpio_set_function(sc, pin, A10_GPIO_INPUT);
+			if (err == 0) {
+				a10_gpio_pin_get(sc->sc_dev, pin, &val);
+				a10_gpio_pin_set(sc->sc_dev, pin, val); 
+			}
 		}
+		if (err == 0)
+			err = a10_gpio_set_function(sc, pin, A10_GPIO_OUTPUT);
 	}
 
+	if (err)
+		return (err);
+
 	/* Manage Pull-up/pull-down. */
-	pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN);
-	if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {
-		if (flags & GPIO_PIN_PULLUP) {
-			pin->gp_flags |= GPIO_PIN_PULLUP;
-			a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_PULLUP);
-		} else {
-			pin->gp_flags |= GPIO_PIN_PULLDOWN;
-			a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_PULLDOWN);
-		}
-	} else 
-		a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_NONE);
+	if (flags & GPIO_PIN_PULLUP)
+		a10_gpio_set_pud(sc, pin, A10_GPIO_PULLUP);
+	else if (flags & GPIO_PIN_PULLDOWN)
+		a10_gpio_set_pud(sc, pin, A10_GPIO_PULLDOWN);
+	else
+		a10_gpio_set_pud(sc, pin, A10_GPIO_NONE);
 
-	A10_GPIO_UNLOCK(sc);
+	return (0);
 }
 
+static device_t
+a10_gpio_get_bus(device_t dev)
+{
+	struct a10_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (sc->sc_busdev);
+}
+
 static int
 a10_gpio_pin_max(device_t dev, int *maxpin)
 {
+	struct a10_gpio_softc *sc;
 
-	*maxpin = A10_GPIO_PINS - 1;
+	sc = device_get_softc(dev);
+
+	*maxpin = sc->padconf->npins - 1;
 	return (0);
 }
 
@@ -229,20 +366,13 @@
 static int
 a10_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	int i;
+	struct a10_gpio_softc *sc;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
-	}
-
-	if (i >= sc->sc_gpio_npins)
+	sc = device_get_softc(dev);
+	if (pin >= sc->padconf->npins)
 		return (EINVAL);
 
-	A10_GPIO_LOCK(sc);
-	*caps = sc->sc_gpio_pins[i].gp_caps;
-	A10_GPIO_UNLOCK(sc);
+	*caps = A10_GPIO_DEFAULT_CAPS;
 
 	return (0);
 }
@@ -250,19 +380,40 @@
 static int
 a10_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	int i;
+	struct a10_gpio_softc *sc;
+	uint32_t func;
+	uint32_t pud;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
+	sc = device_get_softc(dev);
+	if (pin >= sc->padconf->npins)
+		return (EINVAL);
+
+	A10_GPIO_LOCK(sc);
+	func = a10_gpio_get_function(sc, pin);
+	switch (func) {
+	case A10_GPIO_INPUT:
+		*flags = GPIO_PIN_INPUT;
+		break;
+	case A10_GPIO_OUTPUT:
+		*flags = GPIO_PIN_OUTPUT;
+		break;
+	default:
+		*flags = 0;
+		break;
 	}
 
-	if (i >= sc->sc_gpio_npins)
-		return (EINVAL);
+	pud = a10_gpio_get_pud(sc, pin);
+	switch (pud) {
+	case A10_GPIO_PULLDOWN:
+		*flags |= GPIO_PIN_PULLDOWN;
+		break;
+	case A10_GPIO_PULLUP:
+		*flags |= GPIO_PIN_PULLUP;
+		break;
+	default:
+		break;
+	}
 
-	A10_GPIO_LOCK(sc);
-	*flags = sc->sc_gpio_pins[i].gp_flags;
 	A10_GPIO_UNLOCK(sc);
 
 	return (0);
@@ -271,20 +422,15 @@
 static int
 a10_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	int i;
+	struct a10_gpio_softc *sc;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
-	}
-
-	if (i >= sc->sc_gpio_npins)
+	sc = device_get_softc(dev);
+	if (pin >= sc->padconf->npins)
 		return (EINVAL);
 
-	A10_GPIO_LOCK(sc);
-	memcpy(name, sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME);
-	A10_GPIO_UNLOCK(sc);
+	snprintf(name, GPIOMAXNAME - 1, "%s",
+	    sc->padconf->pins[pin].name);
+	name[GPIOMAXNAME - 1] = '\0';
 
 	return (0);
 }
@@ -292,47 +438,39 @@
 static int
 a10_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	int i;
+	struct a10_gpio_softc *sc;
+	int err;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
-	}
-
-	if (i >= sc->sc_gpio_npins)
+	sc = device_get_softc(dev);
+	if (pin > sc->padconf->npins)
 		return (EINVAL);
 
-	a10_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags);
+	A10_GPIO_LOCK(sc);
+	err = a10_gpio_pin_configure(sc, pin, flags);
+	A10_GPIO_UNLOCK(sc);
 
-	return (0);
+	return (err);
 }
 
 static int
 a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	uint32_t bank, offset, data;
-	int i;
+	struct a10_gpio_softc *sc;
+	uint32_t bank, data;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
-	}
-
-	if (i >= sc->sc_gpio_npins)
+	sc = device_get_softc(dev);
+	if (pin > sc->padconf->npins)
 		return (EINVAL);
 
-	bank = pin / 32;
-	pin = pin - 32 * bank;
-	offset = pin & 0x1f;
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
 
 	A10_GPIO_LOCK(sc);
 	data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
 	if (value)
-		data |= (1 << offset);
+		data |= (1 << pin);
 	else
-		data &= ~(1 << offset);
+		data &= ~(1 << pin);
 	A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
 	A10_GPIO_UNLOCK(sc);
 
@@ -342,26 +480,20 @@
 static int
 a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	uint32_t bank, offset, reg_data;
-	int i;
+	struct a10_gpio_softc *sc;
+	uint32_t bank, reg_data;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
-	}
-
-	if (i >= sc->sc_gpio_npins)
+	sc = device_get_softc(dev);
+	if (pin > sc->padconf->npins)
 		return (EINVAL);
 
-	bank = pin / 32;
-	pin = pin - 32 * bank;
-	offset = pin & 0x1f;
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
 
 	A10_GPIO_LOCK(sc);
 	reg_data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
 	A10_GPIO_UNLOCK(sc);
-	*val = (reg_data & (1 << offset)) ? 1 : 0;
+	*val = (reg_data & (1 << pin)) ? 1 : 0;
 
 	return (0);
 }
@@ -369,28 +501,22 @@
 static int
 a10_gpio_pin_toggle(device_t dev, uint32_t pin)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	uint32_t bank, data, offset;
-	int i;
+	struct a10_gpio_softc *sc;
+	uint32_t bank, data;
 
-	for (i = 0; i < sc->sc_gpio_npins; i++) {
-		if (sc->sc_gpio_pins[i].gp_pin == pin)
-			break;
-	}
-
-	if (i >= sc->sc_gpio_npins)
+	sc = device_get_softc(dev);
+	if (pin > sc->padconf->npins)
 		return (EINVAL);
 
-	bank = pin / 32;
-	pin = pin - 32 * bank;
-	offset = pin & 0x1f;
+	bank = sc->padconf->pins[pin].port;
+	pin = sc->padconf->pins[pin].pin;
 
 	A10_GPIO_LOCK(sc);
 	data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
-	if (data & (1 << offset))
-		data &= ~(1 << offset);
+	if (data & (1 << pin))
+		data &= ~(1 << pin);
 	else
-		data |= (1 << offset);
+		data |= (1 << pin);
 	A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
 	A10_GPIO_UNLOCK(sc);
 
@@ -398,6 +524,165 @@
 }
 
 static int
+a10_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
+    uint32_t change_pins, uint32_t *orig_pins)
+{
+	struct a10_gpio_softc *sc;
+	uint32_t bank, data, pin;
+
+	sc = device_get_softc(dev);
+	if (first_pin > sc->padconf->npins)
+		return (EINVAL);
+
+	/*
+	 * We require that first_pin refers to the first pin in a bank, because
+	 * this API is not about convenience, it's for making a set of pins
+	 * change simultaneously (required) with reasonably high performance
+	 * (desired); we need to do a read-modify-write on a single register.
+	 */
+	bank = sc->padconf->pins[first_pin].port;
+	pin = sc->padconf->pins[first_pin].pin;
+	if (pin != 0)
+		return (EINVAL);
+
+	A10_GPIO_LOCK(sc);
+	data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
+	if ((clear_pins | change_pins) != 0) 
+		A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank),
+		    (data & ~clear_pins) ^ change_pins);
+	A10_GPIO_UNLOCK(sc);
+
+	if (orig_pins != NULL)
+		*orig_pins = data;
+
+	return (0);
+}
+
+static int
+a10_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
+    uint32_t *pin_flags)
+{
+	struct a10_gpio_softc *sc;
+	uint32_t bank, pin;
+	int err;
+
+	sc = device_get_softc(dev);
+	if (first_pin > sc->padconf->npins)
+		return (EINVAL);
+
+	bank = sc->padconf->pins[first_pin].port;
+	if (sc->padconf->pins[first_pin].pin != 0)
+		return (EINVAL);
+
+	/*
+	 * The configuration for a bank of pins is scattered among several
+	 * registers; we cannot g'tee to simultaneously change the state of all
+	 * the pins in the flags array.  So just loop through the array
+	 * configuring each pin for now.  If there was a strong need, it might
+	 * be possible to support some limited simultaneous config, such as
+	 * adjacent groups of 8 pins that line up the same as the config regs.
+	 */
+	for (err = 0, pin = first_pin; err == 0 && pin < num_pins; ++pin) {
+		if (pin_flags[pin] & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
+			err = a10_gpio_pin_configure(sc, pin, pin_flags[pin]);
+	}
+
+	return (err);
+}
+
+static int
+aw_find_pinnum_by_name(struct a10_gpio_softc *sc, const char *pinname)
+{
+	int i;
+
+	for (i = 0; i < sc->padconf->npins; i++)
+		if (!strcmp(pinname, sc->padconf->pins[i].name))
+			return i;
+
+	return (-1);
+}
+
+static int
+aw_find_pin_func(struct a10_gpio_softc *sc, int pin, const char *func)
+{
+	int i;
+
+	for (i = 0; i < AW_MAX_FUNC_BY_PIN; i++)
+		if (sc->padconf->pins[pin].functions[i] &&
+		    !strcmp(func, sc->padconf->pins[pin].functions[i]))
+			return (i);
+
+	return (-1);
+}
+
+static int
+aw_fdt_configure_pins(device_t dev, phandle_t cfgxref)
+{
+	struct a10_gpio_softc *sc;
+	phandle_t node;
+	const char **pinlist = NULL;
+	char *pin_function = NULL;
+	uint32_t pin_drive, pin_pull;
+	int pins_nb, pin_num, pin_func, i, ret;
+
+	sc = device_get_softc(dev);
+	node = OF_node_from_xref(cfgxref);
+	ret = 0;
+
+	/* Getting all prop for configuring pins */
+	pins_nb = ofw_bus_string_list_to_array(node, "allwinner,pins", &pinlist);
+	if (pins_nb <= 0)
+		return (ENOENT);
+	if (OF_getprop_alloc(node, "allwinner,function",
+			     sizeof(*pin_function),
+			     (void **)&pin_function) == -1) {
+		ret = ENOENT;
+		goto out;
+	}
+	if (OF_getencprop(node, "allwinner,drive",
+			  &pin_drive, sizeof(pin_drive)) == -1) {
+		ret = ENOENT;
+		goto out;
+	}
+	if (OF_getencprop(node, "allwinner,pull",
+			  &pin_pull, sizeof(pin_pull)) == -1) {
+		ret = ENOENT;
+		goto out;
+	}
+
+	/* Configure each pin to the correct function, drive and pull */
+	for (i = 0; i < pins_nb; i++) {
+		pin_num = aw_find_pinnum_by_name(sc, pinlist[i]);
+		if (pin_num == -1) {
+			ret = ENOENT;
+			goto out;
+		}
+		pin_func = aw_find_pin_func(sc, pin_num, pin_function);
+		if (pin_func == -1) {
+			ret = ENOENT;
+			goto out;
+		}
+
+		A10_GPIO_LOCK(sc);
+
+		if (a10_gpio_get_function(sc, pin_num) != pin_func)
+			a10_gpio_set_function(sc, pin_num, pin_func);
+		if (a10_gpio_get_drv(sc, pin_num) != pin_drive)
+			a10_gpio_set_drv(sc, pin_num, pin_drive);
+		if (a10_gpio_get_pud(sc, pin_num) != pin_pull &&
+			(pin_pull == A10_GPIO_PULLUP ||
+			    pin_pull == A10_GPIO_PULLDOWN))
+			a10_gpio_set_pud(sc, pin_num, pin_pull);
+		A10_GPIO_UNLOCK(sc);
+	}
+
+ out:
+	OF_prop_free(pinlist);
+	OF_prop_free(pin_function);
+	return (ret);
+}
+
+static int
 a10_gpio_probe(device_t dev)
 {
 
@@ -404,10 +689,10 @@
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
-	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-gpio"))
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
 		return (ENXIO);
 
-	device_set_desc(dev, "Allwinner GPIO controller");
+	device_set_desc(dev, "Allwinner GPIO/Pinmux controller");
 	return (BUS_PROBE_DEFAULT);
 }
 
@@ -414,14 +699,16 @@
 static int
 a10_gpio_attach(device_t dev)
 {
-	struct a10_gpio_softc *sc = device_get_softc(dev);
-	uint32_t func;
-	int i, rid;
+	int rid, error;
 	phandle_t gpio;
+	struct a10_gpio_softc *sc;
+	clk_t clk;
+	hwreset_t rst;
 
+	sc = device_get_softc(dev);
 	sc->sc_dev = dev;
 
-	mtx_init(&sc->sc_mtx, "a10 gpio", "gpio", MTX_DEF);
+	mtx_init(&sc->sc_mtx, "a10 gpio", "gpio", MTX_SPIN);
 
 	rid = 0;
 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
@@ -428,7 +715,7 @@
 	    RF_ACTIVE);
 	if (!sc->sc_mem_res) {
 		device_printf(dev, "cannot allocate memory window\n");
-		return (ENXIO);
+		goto fail;
 	}
 
 	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
@@ -438,41 +725,55 @@
 	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
 	    RF_ACTIVE);
 	if (!sc->sc_irq_res) {
-		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
 		device_printf(dev, "cannot allocate interrupt\n");
-		return (ENXIO);
+		goto fail;
 	}
 
 	/* Find our node. */
 	gpio = ofw_bus_get_node(sc->sc_dev);
-
 	if (!OF_hasprop(gpio, "gpio-controller"))
 		/* Node is not a GPIO controller. */
 		goto fail;
 
-	/* Initialize the software controlled pins. */
-	for (i = 0; i < A10_GPIO_PINS; i++) {
-		snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
-		    "pin %d", i);
-		func = a10_gpio_get_function(sc, i);
-		sc->sc_gpio_pins[i].gp_pin = i;
-		sc->sc_gpio_pins[i].gp_caps = A10_GPIO_DEFAULT_CAPS;
-		sc->sc_gpio_pins[i].gp_flags = a10_gpio_func_flag(func);
+	/* Use the right pin data for the current SoC */
+	sc->padconf = (struct allwinner_padconf *)ofw_bus_search_compatible(dev,
+	    compat_data)->ocd_data;
+
+	if (hwreset_get_by_ofw_idx(dev, 0, 0, &rst) == 0) {
+		error = hwreset_deassert(rst);
+		if (error != 0) {
+			device_printf(dev, "cannot de-assert reset\n");
+			return (error);
+		}
 	}
-	sc->sc_gpio_npins = i;
 
-	device_add_child(dev, "gpioc", -1);
-	device_add_child(dev, "gpiobus", -1);
+	if (clk_get_by_ofw_index(dev, 0, 0, &clk) == 0) {
+		error = clk_enable(clk);
+		if (error != 0) {
+			device_printf(dev, "could not enable clock\n");
+			return (error);
+		}
+	}
 
-	a10_gpio_sc = sc;
+	sc->sc_busdev = gpiobus_attach_bus(dev);
+	if (sc->sc_busdev == NULL)
+		goto fail;
 
-	return (bus_generic_attach(dev));
+	/*
+	 * Register as a pinctrl device
+	 */
+	fdt_pinctrl_register(dev, "allwinner,pins");
+	fdt_pinctrl_configure_tree(dev);
 
+	return (0);
+
 fail:
 	if (sc->sc_irq_res)
 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
 	if (sc->sc_mem_res)
 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+	mtx_destroy(&sc->sc_mtx);
+
 	return (ENXIO);
 }
 
@@ -483,6 +784,35 @@
 	return (EBUSY);
 }
 
+static phandle_t
+a10_gpio_get_node(device_t dev, device_t bus)
+{
+
+	/* We only have one child, the GPIO bus, which needs our own node. */
+	return (ofw_bus_get_node(dev));
+}
+
+static int
+a10_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
+    pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+	struct a10_gpio_softc *sc;
+	int i;
+
+	sc = device_get_softc(bus);
+
+	/* The GPIO pins are mapped as: <gpio-phandle bank pin flags>. */
+	for (i = 0; i < sc->padconf->npins; i++)
+		if (sc->padconf->pins[i].port == gpios[0] &&
+		    sc->padconf->pins[i].pin == gpios[1]) {
+			*pin = i;
+			break;
+		}
+	*flags = gpios[gcells - 1];
+
+	return (0);
+}
+
 static device_method_t a10_gpio_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		a10_gpio_probe),
@@ -490,6 +820,7 @@
 	DEVMETHOD(device_detach,	a10_gpio_detach),
 
 	/* GPIO protocol */
+	DEVMETHOD(gpio_get_bus,		a10_gpio_get_bus),
 	DEVMETHOD(gpio_pin_max,		a10_gpio_pin_max),
 	DEVMETHOD(gpio_pin_getname,	a10_gpio_pin_getname),
 	DEVMETHOD(gpio_pin_getflags,	a10_gpio_pin_getflags),
@@ -498,7 +829,16 @@
 	DEVMETHOD(gpio_pin_get,		a10_gpio_pin_get),
 	DEVMETHOD(gpio_pin_set,		a10_gpio_pin_set),
 	DEVMETHOD(gpio_pin_toggle,	a10_gpio_pin_toggle),
+	DEVMETHOD(gpio_pin_access_32,	a10_gpio_pin_access_32),
+	DEVMETHOD(gpio_pin_config_32,	a10_gpio_pin_config_32),
+	DEVMETHOD(gpio_map_gpios,	a10_gpio_map_gpios),
 
+	/* ofw_bus interface */
+	DEVMETHOD(ofw_bus_get_node,	a10_gpio_get_node),
+
+        /* fdt_pinctrl interface */
+	DEVMETHOD(fdt_pinctrl_configure,aw_fdt_configure_pins),
+
 	DEVMETHOD_END
 };
 
@@ -510,20 +850,5 @@
 	sizeof(struct a10_gpio_softc),
 };
 
-DRIVER_MODULE(a10_gpio, simplebus, a10_gpio_driver, a10_gpio_devclass, 0, 0);
-
-int
-a10_emac_gpio_config(uint32_t pin)
-{
-	struct a10_gpio_softc *sc = a10_gpio_sc;
-
-	if (sc == NULL)
-		return (ENXIO);
-
-	/* Configure pin mux settings for MII. */
-	A10_GPIO_LOCK(sc);
-	a10_gpio_set_function(sc, pin, A10_GPIO_PULLDOWN);
-	A10_GPIO_UNLOCK(sc);
-
-	return (0);
-}
+EARLY_DRIVER_MODULE(a10_gpio, simplebus, a10_gpio_driver, a10_gpio_devclass, 0, 0,
+    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);

Modified: trunk/sys/arm/allwinner/a10_gpio.h
===================================================================
--- trunk/sys/arm/allwinner/a10_gpio.h	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/a10_gpio.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -24,12 +24,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: stable/10/sys/arm/allwinner/a10_gpio.h 266337 2014-05-17 18:53:36Z ian $
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_gpio.h 285105 2015-07-03 17:54:41Z loos $
  */
 
 #ifndef	_A10_GPIO_H_
 #define	_A10_GPIO_H_
 
-int a10_emac_gpio_config(uint32_t pin);
+#define	A10_GPIO_FUNC_MII	2
+#define	A10_GPIO_FUNC_RGMII	5
 
+int a10_gpio_ethernet_activate(uint32_t);
+
 #endif

Added: trunk/sys/arm/allwinner/a10_hdmi.c
===================================================================
--- trunk/sys/arm/allwinner/a10_hdmi.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_hdmi.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,719 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_hdmi.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner A10/A20 HDMI TX 
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_hdmi.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include "hdmi_if.h"
+
+#define	HDMI_CTRL		0x004
+#define	CTRL_MODULE_EN		(1 << 31)
+#define	HDMI_INT_STATUS		0x008
+#define	HDMI_HPD		0x00c
+#define	HPD_DET			(1 << 0)
+#define	HDMI_VID_CTRL		0x010
+#define	VID_CTRL_VIDEO_EN	(1 << 31)
+#define	VID_CTRL_HDMI_MODE	(1 << 30)
+#define	VID_CTRL_INTERLACE	(1 << 4)
+#define	VID_CTRL_REPEATER_2X	(1 << 0)
+#define	HDMI_VID_TIMING0	0x014
+#define	VID_ACT_V(v)		(((v) - 1) << 16)
+#define	VID_ACT_H(h)		(((h) - 1) << 0)
+#define	HDMI_VID_TIMING1	0x018
+#define	VID_VBP(vbp)		(((vbp) - 1) << 16)
+#define	VID_HBP(hbp)		(((hbp) - 1) << 0)
+#define	HDMI_VID_TIMING2	0x01c
+#define	VID_VFP(vfp)		(((vfp) - 1) << 16)
+#define	VID_HFP(hfp)		(((hfp) - 1) << 0)
+#define	HDMI_VID_TIMING3	0x020
+#define	VID_VSPW(vspw)		(((vspw) - 1) << 16)
+#define	VID_HSPW(hspw)		(((hspw) - 1) << 0)
+#define	HDMI_VID_TIMING4	0x024
+#define	TX_CLOCK_NORMAL		0x03e00000
+#define	VID_VSYNC_ACTSEL	(1 << 1)
+#define	VID_HSYNC_ACTSEL	(1 << 0)
+#define	HDMI_AUD_CTRL		0x040
+#define	AUD_CTRL_EN		(1 << 31)
+#define	AUD_CTRL_RST		(1 << 30)
+#define	HDMI_ADMA_CTRL		0x044
+#define	HDMI_ADMA_MODE		(1 << 31)
+#define	HDMI_ADMA_MODE_DDMA	(0 << 31)
+#define	HDMI_ADMA_MODE_NDMA	(1 << 31)
+#define	HDMI_AUD_FMT		0x048
+#define	AUD_FMT_CH(n)		((n) - 1)
+#define	HDMI_PCM_CTRL		0x04c
+#define	HDMI_AUD_CTS		0x050
+#define	HDMI_AUD_N		0x054
+#define	HDMI_AUD_CH_STATUS0	0x058
+#define	CH_STATUS0_FS_FREQ	(0xf << 24)
+#define	CH_STATUS0_FS_FREQ_48	(2 << 24)
+#define	HDMI_AUD_CH_STATUS1	0x05c
+#define	CH_STATUS1_WORD_LEN	(0x7 << 1)
+#define	CH_STATUS1_WORD_LEN_16	(1 << 1)
+#define	HDMI_AUDIO_RESET_RETRY	1000
+#define	HDMI_AUDIO_CHANNELS	2
+#define	HDMI_AUDIO_CHANNELMAP	0x76543210
+#define	HDMI_AUDIO_N		6144	/* 48 kHz */
+#define	HDMI_AUDIO_CTS(r, n)	((((r) * 10) * ((n) / 128)) / 480)
+#define	HDMI_PADCTRL0		0x200
+#define	PADCTRL0_BIASEN		(1 << 31)
+#define	PADCTRL0_LDOCEN		(1 << 30)
+#define	PADCTRL0_LDODEN		(1 << 29)
+#define	PADCTRL0_PWENC		(1 << 28)
+#define	PADCTRL0_PWEND		(1 << 27)
+#define	PADCTRL0_PWENG		(1 << 26)
+#define	PADCTRL0_CKEN		(1 << 25)
+#define	PADCTRL0_SEN		(1 << 24)
+#define	PADCTRL0_TXEN		(1 << 23)
+#define	HDMI_PADCTRL1		0x204
+#define	PADCTRL1_AMP_OPT	(1 << 23)
+#define	PADCTRL1_AMPCK_OPT	(1 << 22)
+#define	PADCTRL1_DMP_OPT	(1 << 21)
+#define	PADCTRL1_EMP_OPT	(1 << 20)
+#define	PADCTRL1_EMPCK_OPT	(1 << 19)
+#define	PADCTRL1_PWSCK		(1 << 18)
+#define	PADCTRL1_PWSDT		(1 << 17)
+#define	PADCTRL1_REG_CSMPS	(1 << 16)
+#define	PADCTRL1_REG_DEN	(1 << 15)
+#define	PADCTRL1_REG_DENCK	(1 << 14)
+#define	PADCTRL1_REG_PLRCK	(1 << 13)
+#define	PADCTRL1_REG_EMP	(0x7 << 10)
+#define	PADCTRL1_REG_EMP_EN	(0x2 << 10)
+#define	PADCTRL1_REG_CD		(0x3 << 8)
+#define	PADCTRL1_REG_CKSS	(0x3 << 6)
+#define	PADCTRL1_REG_CKSS_1X	(0x1 << 6)
+#define	PADCTRL1_REG_CKSS_2X	(0x0 << 6)
+#define	PADCTRL1_REG_AMP	(0x7 << 3)
+#define	PADCTRL1_REG_AMP_EN	(0x6 << 3)
+#define	PADCTRL1_REG_PLR	(0x7 << 0)
+#define	HDMI_PLLCTRL0		0x208
+#define	PLLCTRL0_PLL_EN		(1 << 31)
+#define	PLLCTRL0_BWS		(1 << 30)
+#define	PLLCTRL0_HV_IS_33	(1 << 29)
+#define	PLLCTRL0_LDO1_EN	(1 << 28)
+#define	PLLCTRL0_LDO2_EN	(1 << 27)
+#define	PLLCTRL0_SDIV2		(1 << 25)
+#define	PLLCTRL0_VCO_GAIN	(0x1 << 22)
+#define	PLLCTRL0_S		(0x7 << 17)
+#define	PLLCTRL0_CP_S		(0xf << 12)
+#define	PLLCTRL0_CS		(0x7 << 8)
+#define	PLLCTRL0_PREDIV(x)	((x) << 4)
+#define	PLLCTRL0_VCO_S		(0x8 << 0)
+#define	HDMI_PLLDBG0		0x20c
+#define	PLLDBG0_CKIN_SEL	(1 << 21)
+#define	PLLDBG0_CKIN_SEL_PLL3	(0 << 21)
+#define	PLLDBG0_CKIN_SEL_PLL7	(1 << 21)
+#define	HDMI_PKTCTRL0		0x2f0
+#define	HDMI_PKTCTRL1		0x2f4
+#define	PKTCTRL_PACKET(n,t)	((t) << ((n) << 2))
+#define	PKT_NULL		0
+#define	PKT_GC			1
+#define	PKT_AVI			2
+#define	PKT_AI			3
+#define	PKT_SPD			5
+#define	PKT_END			15
+#define	DDC_CTRL		0x500
+#define	CTRL_DDC_EN		(1 << 31)
+#define	CTRL_DDC_ACMD_START	(1 << 30)
+#define	CTRL_DDC_FIFO_DIR	(1 << 8)
+#define	CTRL_DDC_FIFO_DIR_READ	(0 << 8)
+#define	CTRL_DDC_FIFO_DIR_WRITE	(1 << 8)
+#define	CTRL_DDC_SWRST		(1 << 0)
+#define	DDC_SLAVE_ADDR		0x504
+#define	SLAVE_ADDR_SEG_SHIFT	24
+#define	SLAVE_ADDR_EDDC_SHIFT	16
+#define	SLAVE_ADDR_OFFSET_SHIFT	8
+#define	SLAVE_ADDR_SHIFT	0
+#define	DDC_INT_STATUS		0x50c
+#define	INT_STATUS_XFER_DONE	(1 << 0)
+#define	DDC_FIFO_CTRL		0x510
+#define	FIFO_CTRL_CLEAR		(1 << 31)
+#define	DDC_BYTE_COUNTER	0x51c
+#define	DDC_COMMAND		0x520
+#define	COMMAND_EOREAD		(4 << 0)
+#define	DDC_CLOCK		0x528
+#define	DDC_CLOCK_M		(1 << 3)
+#define	DDC_CLOCK_N		(5 << 0)
+#define	DDC_FIFO		0x518
+#define	SWRST_DELAY		1000
+#define	DDC_DELAY		1000
+#define	DDC_RETRY		1000
+#define	DDC_BLKLEN		16
+#define	DDC_ADDR		0x50
+#define	EDDC_ADDR		0x60
+#define	EDID_LENGTH		128
+#define	HDMI_ENABLE_DELAY	50000
+#define	DDC_READ_RETRY		4
+#define	EXT_TAG			0x00
+#define	CEA_TAG_ID		0x02
+#define	CEA_DTD			0x03
+#define	DTD_BASIC_AUDIO		(1 << 6)
+#define	CEA_REV			0x02
+#define	CEA_DATA_OFF		0x03
+#define	CEA_DATA_START		4
+#define	BLOCK_TAG(x)		(((x) >> 5) & 0x7)
+#define	BLOCK_TAG_VSDB		3
+#define	BLOCK_LEN(x)		((x) & 0x1f)
+#define	HDMI_VSDB_MINLEN	5
+#define	HDMI_OUI		"\x03\x0c\x00"
+#define	HDMI_OUI_LEN		3
+#define	HDMI_DEFAULT_FREQ	297000000
+
+struct a10hdmi_softc {
+	struct resource		*res;
+
+	struct intr_config_hook	mode_hook;
+
+	uint8_t			edid[EDID_LENGTH];
+
+	int			has_hdmi;
+	int			has_audio;
+
+	clk_t			clk_ahb;
+	clk_t			clk_hdmi;
+	clk_t			clk_lcd;
+};
+
+static struct resource_spec a10hdmi_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	HDMI_READ(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	HDMI_WRITE(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static void
+a10hdmi_init(struct a10hdmi_softc *sc)
+{
+	/* Enable the HDMI module */
+	HDMI_WRITE(sc, HDMI_CTRL, CTRL_MODULE_EN);
+
+	/* Configure PLL/DRV settings */
+	HDMI_WRITE(sc, HDMI_PADCTRL0, PADCTRL0_BIASEN | PADCTRL0_LDOCEN |
+	    PADCTRL0_LDODEN | PADCTRL0_PWENC | PADCTRL0_PWEND |
+	    PADCTRL0_PWENG | PADCTRL0_CKEN | PADCTRL0_TXEN);
+	HDMI_WRITE(sc, HDMI_PADCTRL1, PADCTRL1_AMP_OPT | PADCTRL1_AMPCK_OPT |
+	    PADCTRL1_EMP_OPT | PADCTRL1_EMPCK_OPT | PADCTRL1_REG_DEN |
+	    PADCTRL1_REG_DENCK | PADCTRL1_REG_EMP_EN | PADCTRL1_REG_AMP_EN);
+
+	/* Select PLL3 as input clock */
+	HDMI_WRITE(sc, HDMI_PLLDBG0, PLLDBG0_CKIN_SEL_PLL3);
+
+	DELAY(HDMI_ENABLE_DELAY);
+}
+
+static void
+a10hdmi_hpd(void *arg)
+{
+	struct a10hdmi_softc *sc;
+	device_t dev;
+	uint32_t hpd;
+
+	dev = arg;
+	sc = device_get_softc(dev);
+
+	hpd = HDMI_READ(sc, HDMI_HPD);
+	if ((hpd & HPD_DET) == HPD_DET)
+		EVENTHANDLER_INVOKE(hdmi_event, dev, HDMI_EVENT_CONNECTED);
+
+	config_intrhook_disestablish(&sc->mode_hook);
+}
+
+static int
+a10hdmi_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-hdmi"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner HDMI TX");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10hdmi_attach(device_t dev)
+{
+	struct a10hdmi_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (bus_alloc_resources(dev, a10hdmi_spec, &sc->res)) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	/* Setup clocks */
+	error = clk_get_by_ofw_name(dev, 0, "ahb", &sc->clk_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot find ahb clock\n");
+		return (error);
+	}
+	error = clk_get_by_ofw_name(dev, 0, "hdmi", &sc->clk_hdmi);
+	if (error != 0) {
+		device_printf(dev, "cannot find hdmi clock\n");
+		return (error);
+	}
+	error = clk_get_by_ofw_name(dev, 0, "lcd", &sc->clk_lcd);
+	if (error != 0) {
+		device_printf(dev, "cannot find lcd clock\n");
+	}
+	/* Enable HDMI clock */
+	error = clk_enable(sc->clk_hdmi);
+	if (error != 0) {
+		device_printf(dev, "cannot enable hdmi clock\n");
+		return (error);
+	}
+	/* Gating AHB clock for HDMI */
+	error = clk_enable(sc->clk_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot enable ahb gate\n");
+		return (error);
+	}
+
+	a10hdmi_init(sc);
+
+	sc->mode_hook.ich_func = a10hdmi_hpd;
+	sc->mode_hook.ich_arg = dev;
+
+	error = config_intrhook_establish(&sc->mode_hook);
+	if (error != 0)
+		return (error);
+
+	return (0);
+}
+
+static int
+a10hdmi_ddc_xfer(struct a10hdmi_softc *sc, uint16_t addr, uint8_t seg,
+    uint8_t off, int len)
+{
+	uint32_t val;
+	int retry;
+
+	/* Set FIFO direction to read */
+	val = HDMI_READ(sc, DDC_CTRL);
+	val &= ~CTRL_DDC_FIFO_DIR;
+	val |= CTRL_DDC_FIFO_DIR_READ;
+	HDMI_WRITE(sc, DDC_CTRL, val);
+
+	/* Setup DDC slave address */
+	val = (addr << SLAVE_ADDR_SHIFT) | (seg << SLAVE_ADDR_SEG_SHIFT) |
+	    (EDDC_ADDR << SLAVE_ADDR_EDDC_SHIFT) |
+	    (off << SLAVE_ADDR_OFFSET_SHIFT);
+	HDMI_WRITE(sc, DDC_SLAVE_ADDR, val);
+
+	/* Clear FIFO */
+	val = HDMI_READ(sc, DDC_FIFO_CTRL);
+	val |= FIFO_CTRL_CLEAR;
+	HDMI_WRITE(sc, DDC_FIFO_CTRL, val);
+
+	/* Set transfer length */
+	HDMI_WRITE(sc, DDC_BYTE_COUNTER, len);
+
+	/* Set command to "Explicit Offset Address Read" */
+	HDMI_WRITE(sc, DDC_COMMAND, COMMAND_EOREAD);
+
+	/* Start transfer */
+	val = HDMI_READ(sc, DDC_CTRL);
+	val |= CTRL_DDC_ACMD_START;
+	HDMI_WRITE(sc, DDC_CTRL, val);
+
+	/* Wait for command to start */
+	retry = DDC_RETRY;
+	while (--retry > 0) {
+		val = HDMI_READ(sc, DDC_CTRL);
+		if ((val & CTRL_DDC_ACMD_START) == 0)
+			break;
+		DELAY(DDC_DELAY);
+	}
+	if (retry == 0)
+		return (ETIMEDOUT);
+
+	/* Ensure that the transfer completed */
+	val = HDMI_READ(sc, DDC_INT_STATUS);
+	if ((val & INT_STATUS_XFER_DONE) == 0)
+		return (EIO);
+
+	return (0);
+}
+
+static int
+a10hdmi_ddc_read(struct a10hdmi_softc *sc, int block, uint8_t *edid)
+{
+	int resid, off, len, error;
+	uint8_t *pbuf;
+
+	pbuf = edid;
+	resid = EDID_LENGTH;
+	off = (block & 1) ? EDID_LENGTH : 0;
+
+	while (resid > 0) {
+		len = min(resid, DDC_BLKLEN);
+		error = a10hdmi_ddc_xfer(sc, DDC_ADDR, block >> 1, off, len);
+		if (error != 0)
+			return (error);
+
+		bus_read_multi_1(sc->res, DDC_FIFO, pbuf, len);
+
+		pbuf += len;
+		off += len;
+		resid -= len;
+	}
+
+	return (0);
+}
+
+static int
+a10hdmi_detect_hdmi_vsdb(uint8_t *edid)
+{
+	int off, p, btag, blen;
+
+	if (edid[EXT_TAG] != CEA_TAG_ID)
+		return (0);
+
+	off = edid[CEA_DATA_OFF];
+
+	/* CEA data block collection starts at byte 4 */
+	if (off <= CEA_DATA_START)
+		return (0);
+
+	/* Parse the CEA data blocks */
+	for (p = CEA_DATA_START; p < off;) {
+		btag = BLOCK_TAG(edid[p]);
+		blen = BLOCK_LEN(edid[p]);
+
+		/* Make sure the length is sane */
+		if (p + blen + 1 > off)
+			break;
+
+		/* Look for a VSDB with the HDMI 24-bit IEEE registration ID */
+		if (btag == BLOCK_TAG_VSDB && blen >= HDMI_VSDB_MINLEN &&
+		    memcmp(&edid[p + 1], HDMI_OUI, HDMI_OUI_LEN) == 0)
+			return (1);
+
+		/* Next data block */
+		p += (1 + blen);
+	}
+
+	return (0);
+}
+
+static void
+a10hdmi_detect_hdmi(struct a10hdmi_softc *sc, int *phdmi, int *paudio)
+{
+	struct edid_info ei;
+	uint8_t edid[EDID_LENGTH];
+	int block;
+
+	*phdmi = *paudio = 0;
+
+	if (edid_parse(sc->edid, &ei) != 0)
+		return;
+
+	/* Scan through extension blocks, looking for a CEA-861 block. */
+	for (block = 1; block <= ei.edid_ext_block_count; block++) {
+		if (a10hdmi_ddc_read(sc, block, edid) != 0)
+			return;
+
+		if (a10hdmi_detect_hdmi_vsdb(edid) != 0) {
+			*phdmi = 1;
+			*paudio = ((edid[CEA_DTD] & DTD_BASIC_AUDIO) != 0);
+			return;
+		}
+	}
+}
+
+static int
+a10hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
+{
+	struct a10hdmi_softc *sc;
+	int error, retry;
+
+	sc = device_get_softc(dev);
+	retry = DDC_READ_RETRY;
+
+	while (--retry > 0) {
+		/* I2C software reset */
+		HDMI_WRITE(sc, DDC_FIFO_CTRL, 0);
+		HDMI_WRITE(sc, DDC_CTRL, CTRL_DDC_EN | CTRL_DDC_SWRST);
+		DELAY(SWRST_DELAY);
+		if (HDMI_READ(sc, DDC_CTRL) & CTRL_DDC_SWRST) {
+			device_printf(dev, "DDC software reset failed\n");
+			return (ENXIO);
+		}
+
+		/* Configure DDC clock */
+		HDMI_WRITE(sc, DDC_CLOCK, DDC_CLOCK_M | DDC_CLOCK_N);
+
+		/* Read EDID block */
+		error = a10hdmi_ddc_read(sc, 0, sc->edid);
+		if (error == 0) {
+			*edid = sc->edid;
+			*edid_len = sizeof(sc->edid);
+			break;
+		}
+	}
+
+	if (error == 0)
+		a10hdmi_detect_hdmi(sc, &sc->has_hdmi, &sc->has_audio);
+	else
+		sc->has_hdmi = sc->has_audio = 0;
+
+	return (error);
+}
+
+static void
+a10hdmi_set_audiomode(device_t dev, const struct videomode *mode)
+{
+	struct a10hdmi_softc *sc;
+	uint32_t val;
+	int retry;
+
+	sc = device_get_softc(dev);
+
+	/* Disable and reset audio module and wait for reset bit to clear */
+	HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_RST);
+	for (retry = HDMI_AUDIO_RESET_RETRY; retry > 0; retry--) {
+		val = HDMI_READ(sc, HDMI_AUD_CTRL);
+		if ((val & AUD_CTRL_RST) == 0)
+			break;
+	}
+	if (retry == 0) {
+		device_printf(dev, "timeout waiting for audio module\n");
+		return;
+	}
+
+	if (!sc->has_audio)
+		return;
+
+	/* DMA and FIFO control */
+	HDMI_WRITE(sc, HDMI_ADMA_CTRL, HDMI_ADMA_MODE_DDMA);
+
+	/* Audio format control (LPCM, S16LE, stereo) */
+	HDMI_WRITE(sc, HDMI_AUD_FMT, AUD_FMT_CH(HDMI_AUDIO_CHANNELS));
+
+	/* Channel mappings */
+	HDMI_WRITE(sc, HDMI_PCM_CTRL, HDMI_AUDIO_CHANNELMAP);
+
+	/* Clocks */
+	HDMI_WRITE(sc, HDMI_AUD_CTS,
+	    HDMI_AUDIO_CTS(mode->dot_clock, HDMI_AUDIO_N));
+	HDMI_WRITE(sc, HDMI_AUD_N, HDMI_AUDIO_N);
+
+	/* Set sampling frequency to 48 kHz, word length to 16-bit */
+	HDMI_WRITE(sc, HDMI_AUD_CH_STATUS0, CH_STATUS0_FS_FREQ_48);
+	HDMI_WRITE(sc, HDMI_AUD_CH_STATUS1, CH_STATUS1_WORD_LEN_16);
+
+	/* Enable */
+	HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_EN);
+}
+
+static int
+a10hdmi_get_tcon_config(struct a10hdmi_softc *sc, int *div, int *dbl)
+{
+	uint64_t lcd_fin, lcd_fout;
+	clk_t clk_lcd_parent;
+	const char *pname;
+	int error;
+
+	error = clk_get_parent(sc->clk_lcd, &clk_lcd_parent);
+	if (error != 0)
+		return (error);
+
+	/* Get the LCD CH1 special clock 2 divider */
+	error = clk_get_freq(sc->clk_lcd, &lcd_fout);
+	if (error != 0)
+		return (error);
+	error = clk_get_freq(clk_lcd_parent, &lcd_fin);
+	if (error != 0)
+		return (error);
+	*div = lcd_fin / lcd_fout;
+
+	/* Detect LCD CH1 special clock using a 1X or 2X source */
+	/* XXX */
+	pname = clk_get_name(clk_lcd_parent);
+	if (strcmp(pname, "pll3-1x") == 0 || strcmp(pname, "pll7-1x") == 0)
+		*dbl = 0;
+	else
+		*dbl = 1;
+
+	return (0);
+}
+
+static int
+a10hdmi_set_videomode(device_t dev, const struct videomode *mode)
+{
+	struct a10hdmi_softc *sc;
+	int error, clk_div, clk_dbl;
+	int dblscan, hfp, hspw, hbp, vfp, vspw, vbp;
+	uint32_t val;
+
+	sc = device_get_softc(dev);
+	dblscan = !!(mode->flags & VID_DBLSCAN);
+	hfp = mode->hsync_start - mode->hdisplay;
+	hspw = mode->hsync_end - mode->hsync_start;
+	hbp = mode->htotal - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vspw = mode->vsync_end - mode->vsync_start;
+	vbp = mode->vtotal - mode->vsync_start;
+
+	error = a10hdmi_get_tcon_config(sc, &clk_div, &clk_dbl);
+	if (error != 0) {
+		device_printf(dev, "couldn't get tcon config: %d\n", error);
+		return (error);
+	}
+
+	/* Clear interrupt status */
+	HDMI_WRITE(sc, HDMI_INT_STATUS, HDMI_READ(sc, HDMI_INT_STATUS));
+
+	/* Clock setup */
+	val = HDMI_READ(sc, HDMI_PADCTRL1);
+	val &= ~PADCTRL1_REG_CKSS;
+	val |= (clk_dbl ? PADCTRL1_REG_CKSS_2X : PADCTRL1_REG_CKSS_1X);
+	HDMI_WRITE(sc, HDMI_PADCTRL1, val);
+	HDMI_WRITE(sc, HDMI_PLLCTRL0, PLLCTRL0_PLL_EN | PLLCTRL0_BWS |
+	    PLLCTRL0_HV_IS_33 | PLLCTRL0_LDO1_EN | PLLCTRL0_LDO2_EN |
+	    PLLCTRL0_SDIV2 | PLLCTRL0_VCO_GAIN | PLLCTRL0_S |
+	    PLLCTRL0_CP_S | PLLCTRL0_CS | PLLCTRL0_PREDIV(clk_div) |
+	    PLLCTRL0_VCO_S);
+
+	/* Setup display settings */
+	if (bootverbose)
+		device_printf(dev, "HDMI: %s, Audio: %s\n",
+		    sc->has_hdmi ? "yes" : "no", sc->has_audio ? "yes" : "no");
+	val = 0;
+	if (sc->has_hdmi)
+		val |= VID_CTRL_HDMI_MODE;
+	if (mode->flags & VID_INTERLACE)
+		val |= VID_CTRL_INTERLACE;
+	if (mode->flags & VID_DBLSCAN)
+		val |= VID_CTRL_REPEATER_2X;
+	HDMI_WRITE(sc, HDMI_VID_CTRL, val);
+
+	/* Setup display timings */
+	HDMI_WRITE(sc, HDMI_VID_TIMING0,
+	    VID_ACT_V(mode->vdisplay) | VID_ACT_H(mode->hdisplay << dblscan));
+	HDMI_WRITE(sc, HDMI_VID_TIMING1,
+	    VID_VBP(vbp) | VID_HBP(hbp << dblscan));
+	HDMI_WRITE(sc, HDMI_VID_TIMING2,
+	    VID_VFP(vfp) | VID_HFP(hfp << dblscan));
+	HDMI_WRITE(sc, HDMI_VID_TIMING3,
+	    VID_VSPW(vspw) | VID_HSPW(hspw << dblscan));
+	val = TX_CLOCK_NORMAL;
+	if (mode->flags & VID_PVSYNC)
+		val |= VID_VSYNC_ACTSEL;
+	if (mode->flags & VID_PHSYNC)
+		val |= VID_HSYNC_ACTSEL;
+	HDMI_WRITE(sc, HDMI_VID_TIMING4, val);
+
+	/* This is an ordered list of infoframe packets that the HDMI
+	 * transmitter will send. Transmit packets in the following order:
+	 *  1. General control packet
+	 *  2. AVI infoframe
+	 *  3. Audio infoframe
+	 * There are 2 registers with 4 slots each. The list is terminated
+	 * with the special PKT_END marker.
+	 */
+	HDMI_WRITE(sc, HDMI_PKTCTRL0,
+	    PKTCTRL_PACKET(0, PKT_GC) | PKTCTRL_PACKET(1, PKT_AVI) |
+	    PKTCTRL_PACKET(2, PKT_AI) | PKTCTRL_PACKET(3, PKT_END));
+	HDMI_WRITE(sc, HDMI_PKTCTRL1, 0);
+
+	/* Setup audio */
+	a10hdmi_set_audiomode(dev, mode);
+
+	return (0);
+}
+
+static int
+a10hdmi_enable(device_t dev, int onoff)
+{
+	struct a10hdmi_softc *sc;
+	uint32_t val;
+
+	sc = device_get_softc(dev);
+
+	/* Enable or disable video output */
+	val = HDMI_READ(sc, HDMI_VID_CTRL);
+	if (onoff)
+		val |= VID_CTRL_VIDEO_EN;
+	else
+		val &= ~VID_CTRL_VIDEO_EN;
+	HDMI_WRITE(sc, HDMI_VID_CTRL, val);
+
+	return (0);
+}
+
+static device_method_t a10hdmi_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a10hdmi_probe),
+	DEVMETHOD(device_attach,	a10hdmi_attach),
+
+	/* HDMI interface */
+	DEVMETHOD(hdmi_get_edid,	a10hdmi_get_edid),
+	DEVMETHOD(hdmi_set_videomode,	a10hdmi_set_videomode),
+	DEVMETHOD(hdmi_enable,		a10hdmi_enable),
+
+	DEVMETHOD_END
+};
+
+static driver_t a10hdmi_driver = {
+	"a10hdmi",
+	a10hdmi_methods,
+	sizeof(struct a10hdmi_softc),
+};
+
+static devclass_t a10hdmi_devclass;
+
+DRIVER_MODULE(a10hdmi, simplebus, a10hdmi_driver, a10hdmi_devclass, 0, 0);
+MODULE_VERSION(a10hdmi, 1);


Property changes on: trunk/sys/arm/allwinner/a10_hdmi.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a10_hdmiaudio.c
===================================================================
--- trunk/sys/arm/allwinner/a10_hdmiaudio.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_hdmiaudio.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,439 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_hdmiaudio.c 296064 2016-02-25 20:17:18Z jmcneill $
+ */
+
+/*
+ * Allwinner A10/A20 HDMI Audio
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_hdmiaudio.c 296064 2016-02-25 20:17:18Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/chip.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "sunxi_dma_if.h"
+#include "mixer_if.h"
+
+#define	DRQTYPE_HDMIAUDIO	24
+#define	DRQTYPE_SDRAM		1
+
+#define	DMA_WIDTH		32
+#define	DMA_BURST_LEN		8
+#define	DDMA_BLKSIZE		32
+#define	DDMA_WAIT_CYC		8
+
+#define	DMABUF_MIN		4096
+#define	DMABUF_DEFAULT		65536
+#define	DMABUF_MAX		131072
+
+#define	HDMI_SAMPLERATE		48000
+
+#define	TX_FIFO			0x01c16400
+
+static uint32_t a10hdmiaudio_fmt[] = {
+	SND_FORMAT(AFMT_S16_LE, 2, 0),
+	0
+};
+
+static struct pcmchan_caps a10hdmiaudio_pcaps = {
+    HDMI_SAMPLERATE, HDMI_SAMPLERATE, a10hdmiaudio_fmt, 0
+};
+
+struct a10hdmiaudio_info;
+
+struct a10hdmiaudio_chinfo {
+	struct snd_dbuf		*buffer;
+	struct pcm_channel	*channel;	
+	struct a10hdmiaudio_info	*parent;
+	bus_dmamap_t		dmamap;
+	void			*dmaaddr;
+	bus_addr_t		physaddr;
+	device_t		dmac;
+	void			*dmachan;
+
+	int			run;
+	uint32_t		pos;
+	uint32_t		blocksize;
+};
+
+struct a10hdmiaudio_info {
+	device_t		dev;
+	struct mtx		*lock;
+	bus_dma_tag_t		dmat;
+	unsigned		dmasize;
+
+	struct a10hdmiaudio_chinfo	play;
+};
+
+/*
+ * Mixer interface
+ */
+
+static int
+a10hdmiaudio_mixer_init(struct snd_mixer *m)
+{
+	mix_setdevs(m, SOUND_MASK_PCM);
+
+	return (0);
+}
+
+static int
+a10hdmiaudio_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left,
+    unsigned right)
+{
+	return (-1);
+}
+
+static kobj_method_t a10hdmiaudio_mixer_methods[] = {
+	KOBJMETHOD(mixer_init,		a10hdmiaudio_mixer_init),
+	KOBJMETHOD(mixer_set,		a10hdmiaudio_mixer_set),
+	KOBJMETHOD_END
+};
+MIXER_DECLARE(a10hdmiaudio_mixer);
+
+
+/*
+ * Channel interface
+ */
+
+static void
+a10hdmiaudio_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	struct a10hdmiaudio_chinfo *ch = arg;
+
+	if (error != 0)
+		return;
+
+	ch->physaddr = segs[0].ds_addr;
+}
+
+static void
+a10hdmiaudio_transfer(struct a10hdmiaudio_chinfo *ch)
+{
+	int error;
+
+	error = SUNXI_DMA_TRANSFER(ch->dmac, ch->dmachan,
+	    ch->physaddr + ch->pos, TX_FIFO, ch->blocksize);
+	if (error) {
+		ch->run = 0;
+		device_printf(ch->parent->dev, "DMA transfer failed: %d\n",
+		    error);
+	}
+}
+
+static void
+a10hdmiaudio_dmaconfig(struct a10hdmiaudio_chinfo *ch)
+{
+	struct sunxi_dma_config conf;
+
+	memset(&conf, 0, sizeof(conf));
+	conf.src_width = conf.dst_width = DMA_WIDTH;
+	conf.src_burst_len = conf.dst_burst_len = DMA_BURST_LEN;
+	conf.src_blksize = conf.dst_blksize = DDMA_BLKSIZE;
+	conf.src_wait_cyc = conf.dst_wait_cyc = DDMA_WAIT_CYC;
+	conf.src_drqtype = DRQTYPE_SDRAM;
+	conf.dst_drqtype = DRQTYPE_HDMIAUDIO;
+	conf.dst_noincr = true;
+
+	SUNXI_DMA_SET_CONFIG(ch->dmac, ch->dmachan, &conf);
+}
+
+static void
+a10hdmiaudio_dmaintr(void *priv)
+{
+	struct a10hdmiaudio_chinfo *ch = priv;
+	unsigned bufsize;
+
+	bufsize = sndbuf_getsize(ch->buffer);
+
+	ch->pos += ch->blocksize;
+	if (ch->pos >= bufsize)
+		ch->pos -= bufsize;
+
+	if (ch->run) {
+		chn_intr(ch->channel);
+		a10hdmiaudio_transfer(ch);
+	}
+}
+
+static void
+a10hdmiaudio_start(struct a10hdmiaudio_chinfo *ch)
+{
+	ch->pos = 0;
+
+	/* Configure DMA channel */
+	a10hdmiaudio_dmaconfig(ch);
+
+	/* Start DMA transfer */
+	a10hdmiaudio_transfer(ch);
+}
+
+static void
+a10hdmiaudio_stop(struct a10hdmiaudio_chinfo *ch)
+{
+	/* Disable DMA channel */
+	SUNXI_DMA_HALT(ch->dmac, ch->dmachan);
+}
+
+static void *
+a10hdmiaudio_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
+    struct pcm_channel *c, int dir)
+{
+	struct a10hdmiaudio_info *sc = devinfo;
+	struct a10hdmiaudio_chinfo *ch = &sc->play;
+	int error;
+
+	ch->parent = sc;
+	ch->channel = c;
+	ch->buffer = b;
+
+	ch->dmac = devclass_get_device(devclass_find("a10dmac"), 0);
+	if (ch->dmac == NULL) {
+		device_printf(sc->dev, "cannot find DMA controller\n");
+		return (NULL);
+	}
+	ch->dmachan = SUNXI_DMA_ALLOC(ch->dmac, true, a10hdmiaudio_dmaintr, ch);
+	if (ch->dmachan == NULL) {
+		device_printf(sc->dev, "cannot allocate DMA channel\n");
+		return (NULL);
+	}
+
+	error = bus_dmamem_alloc(sc->dmat, &ch->dmaaddr,
+	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &ch->dmamap);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot allocate channel buffer\n");
+		return (NULL);
+	}
+	error = bus_dmamap_load(sc->dmat, ch->dmamap, ch->dmaaddr,
+	    sc->dmasize, a10hdmiaudio_dmamap_cb, ch, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		device_printf(sc->dev, "cannot load DMA map\n");
+		return (NULL);
+	}
+	memset(ch->dmaaddr, 0, sc->dmasize);
+
+	if (sndbuf_setup(ch->buffer, ch->dmaaddr, sc->dmasize) != 0) {
+		device_printf(sc->dev, "cannot setup sndbuf\n");
+		return (NULL);
+	}
+
+	return (ch);
+}
+
+static int
+a10hdmiaudio_chan_free(kobj_t obj, void *data)
+{
+	struct a10hdmiaudio_chinfo *ch = data;
+	struct a10hdmiaudio_info *sc = ch->parent;
+
+	SUNXI_DMA_FREE(ch->dmac, ch->dmachan);
+	bus_dmamap_unload(sc->dmat, ch->dmamap);
+	bus_dmamem_free(sc->dmat, ch->dmaaddr, ch->dmamap);
+
+	return (0);
+}
+
+static int
+a10hdmiaudio_chan_setformat(kobj_t obj, void *data, uint32_t format)
+{
+	return (0);
+}
+
+static uint32_t
+a10hdmiaudio_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
+{
+	return (HDMI_SAMPLERATE);
+}
+
+static uint32_t
+a10hdmiaudio_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
+{
+	struct a10hdmiaudio_chinfo *ch = data;
+
+	ch->blocksize = blocksize & ~3;
+
+	return (ch->blocksize);
+}
+
+static int
+a10hdmiaudio_chan_trigger(kobj_t obj, void *data, int go)
+{
+	struct a10hdmiaudio_chinfo *ch = data;
+	struct a10hdmiaudio_info *sc = ch->parent;
+
+	if (!PCMTRIG_COMMON(go))
+		return (0);
+
+	snd_mtxlock(sc->lock);
+	switch (go) {
+	case PCMTRIG_START:
+		ch->run = 1;
+		a10hdmiaudio_start(ch);
+		break;
+	case PCMTRIG_STOP:
+	case PCMTRIG_ABORT:
+		ch->run = 0;
+		a10hdmiaudio_stop(ch);
+		break;
+	default:
+		break;
+	}
+	snd_mtxunlock(sc->lock);
+
+	return (0);
+}
+
+static uint32_t
+a10hdmiaudio_chan_getptr(kobj_t obj, void *data)
+{
+	struct a10hdmiaudio_chinfo *ch = data;
+
+	return (ch->pos);
+}
+
+static struct pcmchan_caps *
+a10hdmiaudio_chan_getcaps(kobj_t obj, void *data)
+{
+	return (&a10hdmiaudio_pcaps);
+}
+
+static kobj_method_t a10hdmiaudio_chan_methods[] = {
+	KOBJMETHOD(channel_init,		a10hdmiaudio_chan_init),
+	KOBJMETHOD(channel_free,		a10hdmiaudio_chan_free),
+	KOBJMETHOD(channel_setformat,		a10hdmiaudio_chan_setformat),
+	KOBJMETHOD(channel_setspeed,		a10hdmiaudio_chan_setspeed),
+	KOBJMETHOD(channel_setblocksize,	a10hdmiaudio_chan_setblocksize),
+	KOBJMETHOD(channel_trigger,		a10hdmiaudio_chan_trigger),
+	KOBJMETHOD(channel_getptr,		a10hdmiaudio_chan_getptr),
+	KOBJMETHOD(channel_getcaps,		a10hdmiaudio_chan_getcaps),
+	KOBJMETHOD_END
+};
+CHANNEL_DECLARE(a10hdmiaudio_chan);
+
+
+/*
+ * Device interface
+ */
+
+static int
+a10hdmiaudio_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-hdmiaudio"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner HDMI Audio");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10hdmiaudio_attach(device_t dev)
+{
+	struct a10hdmiaudio_info *sc;
+	char status[SND_STATUSLEN];
+	int error;
+
+	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
+	sc->dev = dev;
+	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "a10hdmiaudio softc");
+
+	sc->dmasize = pcm_getbuffersize(dev, DMABUF_MIN,
+	    DMABUF_DEFAULT, DMABUF_MAX);
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),
+	    4, sc->dmasize,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    sc->dmasize, 1,		/* maxsize, nsegs */
+	    sc->dmasize, 0,		/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->dmat);
+	if (error != 0) {
+		device_printf(dev, "cannot create DMA tag\n");
+		goto fail;
+	}
+
+	if (mixer_init(dev, &a10hdmiaudio_mixer_class, sc)) {
+		device_printf(dev, "mixer_init failed\n");
+		goto fail;
+	}
+
+	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
+	pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
+
+	if (pcm_register(dev, sc, 1, 0)) {
+		device_printf(dev, "pcm_register failed\n");
+		goto fail;
+	}
+
+	pcm_addchan(dev, PCMDIR_PLAY, &a10hdmiaudio_chan_class, sc);
+
+	snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
+	pcm_setstatus(dev, status);
+
+	return (0);
+
+fail:
+	snd_mtxfree(sc->lock);
+	free(sc, M_DEVBUF);
+
+	return (error);
+}
+
+static device_method_t a10hdmiaudio_pcm_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a10hdmiaudio_probe),
+	DEVMETHOD(device_attach,	a10hdmiaudio_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t a10hdmiaudio_pcm_driver = {
+	"pcm",
+	a10hdmiaudio_pcm_methods,
+	PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(a10hdmiaudio, simplebus, a10hdmiaudio_pcm_driver, pcm_devclass, 0, 0);
+MODULE_DEPEND(a10hdmiaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
+MODULE_VERSION(a10hdmiaudio, 1);


Property changes on: trunk/sys/arm/allwinner/a10_hdmiaudio.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a10_mmc.c
===================================================================
--- trunk/sys/arm/allwinner/a10_mmc.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_mmc.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,921 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Alexander Fedorov
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_mmc.c 318197 2017-05-11 20:55:11Z marius $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcbrvar.h>
+
+#include <arm/allwinner/a10_mmc.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#define	A10_MMC_MEMRES		0
+#define	A10_MMC_IRQRES		1
+#define	A10_MMC_RESSZ		2
+#define	A10_MMC_DMA_SEGS		((MAXPHYS / PAGE_SIZE) + 1)
+#define	A10_MMC_DMA_MAX_SIZE	0x2000
+#define	A10_MMC_DMA_FTRGLEVEL	0x20070008
+#define	A10_MMC_RESET_RETRY	1000
+
+#define	CARD_ID_FREQUENCY	400000
+
+static struct ofw_compat_data compat_data[] = {
+	{"allwinner,sun4i-a10-mmc", 1},
+	{"allwinner,sun5i-a13-mmc", 1},
+	{NULL,             0}
+};
+
+struct a10_mmc_softc {
+	device_t		a10_dev;
+	clk_t			a10_clk_ahb;
+	clk_t			a10_clk_mmc;
+	hwreset_t		a10_rst_ahb;
+	int			a10_bus_busy;
+	int			a10_resid;
+	int			a10_timeout;
+	struct callout		a10_timeoutc;
+	struct mmc_host		a10_host;
+	struct mmc_request *	a10_req;
+	struct mtx		a10_mtx;
+	struct resource *	a10_res[A10_MMC_RESSZ];
+	uint32_t		a10_intr;
+	uint32_t		a10_intr_wait;
+	void *			a10_intrhand;
+
+	/* Fields required for DMA access. */
+	bus_addr_t	  	a10_dma_desc_phys;
+	bus_dmamap_t		a10_dma_map;
+	bus_dma_tag_t 		a10_dma_tag;
+	void * 			a10_dma_desc;
+	bus_dmamap_t		a10_dma_buf_map;
+	bus_dma_tag_t		a10_dma_buf_tag;
+	int			a10_dma_map_err;
+};
+
+static struct resource_spec a10_mmc_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE | RF_SHAREABLE },
+	{ -1,			0,	0 }
+};
+
+static int a10_mmc_probe(device_t);
+static int a10_mmc_attach(device_t);
+static int a10_mmc_detach(device_t);
+static int a10_mmc_setup_dma(struct a10_mmc_softc *);
+static int a10_mmc_reset(struct a10_mmc_softc *);
+static void a10_mmc_intr(void *);
+static int a10_mmc_update_clock(struct a10_mmc_softc *, uint32_t);
+
+static int a10_mmc_update_ios(device_t, device_t);
+static int a10_mmc_request(device_t, device_t, struct mmc_request *);
+static int a10_mmc_get_ro(device_t, device_t);
+static int a10_mmc_acquire_host(device_t, device_t);
+static int a10_mmc_release_host(device_t, device_t);
+
+#define	A10_MMC_LOCK(_sc)	mtx_lock(&(_sc)->a10_mtx)
+#define	A10_MMC_UNLOCK(_sc)	mtx_unlock(&(_sc)->a10_mtx)
+#define	A10_MMC_READ_4(_sc, _reg)					\
+	bus_read_4((_sc)->a10_res[A10_MMC_MEMRES], _reg)
+#define	A10_MMC_WRITE_4(_sc, _reg, _value)				\
+	bus_write_4((_sc)->a10_res[A10_MMC_MEMRES], _reg, _value)
+
+static int
+a10_mmc_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Integrated MMC/SD controller");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10_mmc_attach(device_t dev)
+{
+	device_t child;
+	struct a10_mmc_softc *sc;
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid_list *tree;
+	uint32_t bus_width;
+	phandle_t node;
+	int error;
+
+	node = ofw_bus_get_node(dev);
+	sc = device_get_softc(dev);
+	sc->a10_dev = dev;
+	sc->a10_req = NULL;
+	if (bus_alloc_resources(dev, a10_mmc_res_spec, sc->a10_res) != 0) {
+		device_printf(dev, "cannot allocate device resources\n");
+		return (ENXIO);
+	}
+	if (bus_setup_intr(dev, sc->a10_res[A10_MMC_IRQRES],
+	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, a10_mmc_intr, sc,
+	    &sc->a10_intrhand)) {
+		bus_release_resources(dev, a10_mmc_res_spec, sc->a10_res);
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (ENXIO);
+	}
+	mtx_init(&sc->a10_mtx, device_get_nameunit(sc->a10_dev), "a10_mmc",
+	    MTX_DEF);
+	callout_init_mtx(&sc->a10_timeoutc, &sc->a10_mtx, 0);
+
+	/* De-assert reset */
+	if (hwreset_get_by_ofw_name(dev, 0, "ahb", &sc->a10_rst_ahb) == 0) {
+		error = hwreset_deassert(sc->a10_rst_ahb);
+		if (error != 0) {
+			device_printf(dev, "cannot de-assert reset\n");
+			goto fail;
+		}
+	}
+
+	/* Activate the module clock. */
+	error = clk_get_by_ofw_name(dev, 0, "ahb", &sc->a10_clk_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot get ahb clock\n");
+		goto fail;
+	}
+	error = clk_enable(sc->a10_clk_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot enable ahb clock\n");
+		goto fail;
+	}
+	error = clk_get_by_ofw_name(dev, 0, "mmc", &sc->a10_clk_mmc);
+	if (error != 0) {
+		device_printf(dev, "cannot get mmc clock\n");
+		goto fail;
+	}
+	error = clk_set_freq(sc->a10_clk_mmc, CARD_ID_FREQUENCY,
+	    CLK_SET_ROUND_DOWN);
+	if (error != 0) {
+		device_printf(dev, "cannot init mmc clock\n");
+		goto fail;
+	}
+	error = clk_enable(sc->a10_clk_mmc);
+	if (error != 0) {
+		device_printf(dev, "cannot enable mmc clock\n");
+		goto fail;
+	}
+
+	sc->a10_timeout = 10;
+	ctx = device_get_sysctl_ctx(dev);
+	tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+	SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "req_timeout", CTLFLAG_RW,
+	    &sc->a10_timeout, 0, "Request timeout in seconds");
+
+	/* Hardware reset */
+	A10_MMC_WRITE_4(sc, A10_MMC_HWRST, 1);
+	DELAY(100);
+	A10_MMC_WRITE_4(sc, A10_MMC_HWRST, 0);
+	DELAY(500);
+
+	/* Soft Reset controller. */
+	if (a10_mmc_reset(sc) != 0) {
+		device_printf(dev, "cannot reset the controller\n");
+		goto fail;
+	}
+
+	if (a10_mmc_setup_dma(sc) != 0) {
+		device_printf(sc->a10_dev, "Couldn't setup DMA!\n");
+		goto fail;
+	}
+
+	if (OF_getencprop(node, "bus-width", &bus_width, sizeof(uint32_t)) <= 0)
+		bus_width = 4;
+
+	sc->a10_host.f_min = 400000;
+	sc->a10_host.f_max = 52000000;
+	sc->a10_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
+	sc->a10_host.mode = mode_sd;
+	sc->a10_host.caps = MMC_CAP_HSPEED;
+	if (bus_width >= 4)
+		sc->a10_host.caps |= MMC_CAP_4_BIT_DATA;
+	if (bus_width >= 8)
+		sc->a10_host.caps |= MMC_CAP_8_BIT_DATA;
+
+	child = device_add_child(dev, "mmc", -1);
+	if (child == NULL) {
+		device_printf(dev, "attaching MMC bus failed!\n");
+		goto fail;
+	}
+	if (device_probe_and_attach(child) != 0) {
+		device_printf(dev, "attaching MMC child failed!\n");
+		device_delete_child(dev, child);
+		goto fail;
+	}
+
+	return (0);
+
+fail:
+	callout_drain(&sc->a10_timeoutc);
+	mtx_destroy(&sc->a10_mtx);
+	bus_teardown_intr(dev, sc->a10_res[A10_MMC_IRQRES], sc->a10_intrhand);
+	bus_release_resources(dev, a10_mmc_res_spec, sc->a10_res);
+
+	return (ENXIO);
+}
+
+static int
+a10_mmc_detach(device_t dev)
+{
+
+	return (EBUSY);
+}
+
+static void
+a10_dma_desc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
+{
+	struct a10_mmc_softc *sc;
+
+	sc = (struct a10_mmc_softc *)arg;
+	if (err) {
+		sc->a10_dma_map_err = err;
+		return;
+	}
+	sc->a10_dma_desc_phys = segs[0].ds_addr;
+}
+
+static int
+a10_mmc_setup_dma(struct a10_mmc_softc *sc)
+{
+	int dma_desc_size, error;
+
+	/* Allocate the DMA descriptor memory. */
+	dma_desc_size = sizeof(struct a10_mmc_dma_desc) * A10_MMC_DMA_SEGS;
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->a10_dev),
+	    A10_MMC_DMA_ALIGN, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    dma_desc_size, 1, dma_desc_size, 0, NULL, NULL, &sc->a10_dma_tag);
+	if (error)
+		return (error);
+	error = bus_dmamem_alloc(sc->a10_dma_tag, &sc->a10_dma_desc,
+	    BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->a10_dma_map);
+	if (error)
+		return (error);
+
+	error = bus_dmamap_load(sc->a10_dma_tag, sc->a10_dma_map,
+	    sc->a10_dma_desc, dma_desc_size, a10_dma_desc_cb, sc, 0);
+	if (error)
+		return (error);
+	if (sc->a10_dma_map_err)
+		return (sc->a10_dma_map_err);
+
+	/* Create the DMA map for data transfers. */
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->a10_dev),
+	    A10_MMC_DMA_ALIGN, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    A10_MMC_DMA_MAX_SIZE * A10_MMC_DMA_SEGS, A10_MMC_DMA_SEGS,
+	    A10_MMC_DMA_MAX_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL,
+	    &sc->a10_dma_buf_tag);
+	if (error)
+		return (error);
+	error = bus_dmamap_create(sc->a10_dma_buf_tag, 0,
+	    &sc->a10_dma_buf_map);
+	if (error)
+		return (error);
+
+	return (0);
+}
+
+static void
+a10_dma_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
+{
+	int i;
+	struct a10_mmc_dma_desc *dma_desc;
+	struct a10_mmc_softc *sc;
+
+	sc = (struct a10_mmc_softc *)arg;
+	sc->a10_dma_map_err = err;
+
+	if (err)
+		return;
+
+	dma_desc = sc->a10_dma_desc;
+	for (i = 0; i < nsegs; i++) {
+		dma_desc[i].buf_size = segs[i].ds_len;
+		dma_desc[i].buf_addr = segs[i].ds_addr;
+		dma_desc[i].config = A10_MMC_DMA_CONFIG_CH |
+		    A10_MMC_DMA_CONFIG_OWN;
+		if (i == 0)
+			dma_desc[i].config |= A10_MMC_DMA_CONFIG_FD;
+		if (i < (nsegs - 1)) {
+			dma_desc[i].config |= A10_MMC_DMA_CONFIG_DIC;
+			dma_desc[i].next = sc->a10_dma_desc_phys +
+			    ((i + 1) * sizeof(struct a10_mmc_dma_desc));
+		} else {
+			dma_desc[i].config |= A10_MMC_DMA_CONFIG_LD |
+			    A10_MMC_DMA_CONFIG_ER;
+			dma_desc[i].next = 0;
+		}
+	}
+}
+
+static int
+a10_mmc_prepare_dma(struct a10_mmc_softc *sc)
+{
+	bus_dmasync_op_t sync_op;
+	int error;
+	struct mmc_command *cmd;
+	uint32_t val;
+
+	cmd = sc->a10_req->cmd;
+	if (cmd->data->len > A10_MMC_DMA_MAX_SIZE * A10_MMC_DMA_SEGS)
+		return (EFBIG);
+	error = bus_dmamap_load(sc->a10_dma_buf_tag, sc->a10_dma_buf_map,
+	    cmd->data->data, cmd->data->len, a10_dma_cb, sc, 0);
+	if (error)
+		return (error);
+	if (sc->a10_dma_map_err)
+		return (sc->a10_dma_map_err);
+
+	if (cmd->data->flags & MMC_DATA_WRITE)
+		sync_op = BUS_DMASYNC_PREWRITE;
+	else
+		sync_op = BUS_DMASYNC_PREREAD;
+	bus_dmamap_sync(sc->a10_dma_buf_tag, sc->a10_dma_buf_map, sync_op);
+	bus_dmamap_sync(sc->a10_dma_tag, sc->a10_dma_map, BUS_DMASYNC_PREWRITE);
+
+	/* Enable DMA */
+	val = A10_MMC_READ_4(sc, A10_MMC_GCTL);
+	val &= ~A10_MMC_CTRL_FIFO_AC_MOD;
+	val |= A10_MMC_CTRL_DMA_ENB;
+	A10_MMC_WRITE_4(sc, A10_MMC_GCTL, val);
+
+	/* Reset DMA */
+	val |= A10_MMC_CTRL_DMA_RST;
+	A10_MMC_WRITE_4(sc, A10_MMC_GCTL, val);
+
+	A10_MMC_WRITE_4(sc, A10_MMC_DMAC, A10_MMC_DMAC_IDMAC_SOFT_RST);
+	A10_MMC_WRITE_4(sc, A10_MMC_DMAC,
+	    A10_MMC_DMAC_IDMAC_IDMA_ON | A10_MMC_DMAC_IDMAC_FIX_BURST);
+
+	/* Enable RX or TX DMA interrupt */
+	if (cmd->data->flags & MMC_DATA_WRITE)
+		val |= A10_MMC_IDST_TX_INT;
+	else
+		val |= A10_MMC_IDST_RX_INT;
+	A10_MMC_WRITE_4(sc, A10_MMC_IDIE, val);
+
+	/* Set DMA descritptor list address */
+	A10_MMC_WRITE_4(sc, A10_MMC_DLBA, sc->a10_dma_desc_phys);
+
+	/* FIFO trigger level */
+	A10_MMC_WRITE_4(sc, A10_MMC_FWLR, A10_MMC_DMA_FTRGLEVEL);
+
+	return (0);
+}
+
+static int
+a10_mmc_reset(struct a10_mmc_softc *sc)
+{
+	int timeout;
+
+	A10_MMC_WRITE_4(sc, A10_MMC_GCTL, A10_MMC_RESET);
+	timeout = 1000;
+	while (--timeout > 0) {
+		if ((A10_MMC_READ_4(sc, A10_MMC_GCTL) & A10_MMC_RESET) == 0)
+			break;
+		DELAY(100);
+	}
+	if (timeout == 0)
+		return (ETIMEDOUT);
+
+	/* Set the timeout. */
+	A10_MMC_WRITE_4(sc, A10_MMC_TMOR,
+	    A10_MMC_TMOR_DTO_LMT_SHIFT(A10_MMC_TMOR_DTO_LMT_MASK) |
+	    A10_MMC_TMOR_RTO_LMT_SHIFT(A10_MMC_TMOR_RTO_LMT_MASK));
+
+	/* Clear pending interrupts. */
+	A10_MMC_WRITE_4(sc, A10_MMC_RISR, 0xffffffff);
+	A10_MMC_WRITE_4(sc, A10_MMC_IDST, 0xffffffff);
+	/* Unmask interrupts. */
+	A10_MMC_WRITE_4(sc, A10_MMC_IMKR,
+	    A10_MMC_INT_CMD_DONE | A10_MMC_INT_ERR_BIT |
+	    A10_MMC_INT_DATA_OVER | A10_MMC_INT_AUTO_STOP_DONE);
+	/* Enable interrupts and AHB access. */
+	A10_MMC_WRITE_4(sc, A10_MMC_GCTL,
+	    A10_MMC_READ_4(sc, A10_MMC_GCTL) | A10_MMC_CTRL_INT_ENB);
+
+	return (0);
+}
+
+static void
+a10_mmc_req_done(struct a10_mmc_softc *sc)
+{
+	struct mmc_command *cmd;
+	struct mmc_request *req;
+	uint32_t val, mask;
+	int retry;
+
+	cmd = sc->a10_req->cmd;
+	if (cmd->error != MMC_ERR_NONE) {
+		/* Reset the FIFO and DMA engines. */
+		mask = A10_MMC_CTRL_FIFO_RST | A10_MMC_CTRL_DMA_RST;
+		val = A10_MMC_READ_4(sc, A10_MMC_GCTL);
+		A10_MMC_WRITE_4(sc, A10_MMC_GCTL, val | mask);
+
+		retry = A10_MMC_RESET_RETRY;
+		while (--retry > 0) {
+			val = A10_MMC_READ_4(sc, A10_MMC_GCTL);
+			if ((val & mask) == 0)
+				break;
+			DELAY(10);
+		}
+		if (retry == 0)
+			device_printf(sc->a10_dev,
+			    "timeout resetting DMA/FIFO\n");
+		a10_mmc_update_clock(sc, 1);
+	}
+
+	req = sc->a10_req;
+	callout_stop(&sc->a10_timeoutc);
+	sc->a10_req = NULL;
+	sc->a10_intr = 0;
+	sc->a10_resid = 0;
+	sc->a10_dma_map_err = 0;
+	sc->a10_intr_wait = 0;
+	req->done(req);
+}
+
+static void
+a10_mmc_req_ok(struct a10_mmc_softc *sc)
+{
+	int timeout;
+	struct mmc_command *cmd;
+	uint32_t status;
+
+	timeout = 1000;
+	while (--timeout > 0) {
+		status = A10_MMC_READ_4(sc, A10_MMC_STAR);
+		if ((status & A10_MMC_STAR_CARD_BUSY) == 0)
+			break;
+		DELAY(1000);
+	}
+	cmd = sc->a10_req->cmd;
+	if (timeout == 0) {
+		cmd->error = MMC_ERR_FAILED;
+		a10_mmc_req_done(sc);
+		return;
+	}
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136) {
+			cmd->resp[0] = A10_MMC_READ_4(sc, A10_MMC_RESP3);
+			cmd->resp[1] = A10_MMC_READ_4(sc, A10_MMC_RESP2);
+			cmd->resp[2] = A10_MMC_READ_4(sc, A10_MMC_RESP1);
+			cmd->resp[3] = A10_MMC_READ_4(sc, A10_MMC_RESP0);
+		} else
+			cmd->resp[0] = A10_MMC_READ_4(sc, A10_MMC_RESP0);
+	}
+	/* All data has been transferred ? */
+	if (cmd->data != NULL && (sc->a10_resid << 2) < cmd->data->len)
+		cmd->error = MMC_ERR_FAILED;
+	a10_mmc_req_done(sc);
+}
+
+static void
+a10_mmc_timeout(void *arg)
+{
+	struct a10_mmc_softc *sc;
+
+	sc = (struct a10_mmc_softc *)arg;
+	if (sc->a10_req != NULL) {
+		device_printf(sc->a10_dev, "controller timeout\n");
+		sc->a10_req->cmd->error = MMC_ERR_TIMEOUT;
+		a10_mmc_req_done(sc);
+	} else
+		device_printf(sc->a10_dev,
+		    "Spurious timeout - no active request\n");
+}
+
+static void
+a10_mmc_intr(void *arg)
+{
+	bus_dmasync_op_t sync_op;
+	struct a10_mmc_softc *sc;
+	struct mmc_data *data;
+	uint32_t idst, imask, rint;
+
+	sc = (struct a10_mmc_softc *)arg;
+	A10_MMC_LOCK(sc);
+	rint = A10_MMC_READ_4(sc, A10_MMC_RISR);
+	idst = A10_MMC_READ_4(sc, A10_MMC_IDST);
+	imask = A10_MMC_READ_4(sc, A10_MMC_IMKR);
+	if (idst == 0 && imask == 0 && rint == 0) {
+		A10_MMC_UNLOCK(sc);
+		return;
+	}
+#ifdef DEBUG
+	device_printf(sc->a10_dev, "idst: %#x, imask: %#x, rint: %#x\n",
+	    idst, imask, rint);
+#endif
+	if (sc->a10_req == NULL) {
+		device_printf(sc->a10_dev,
+		    "Spurious interrupt - no active request, rint: 0x%08X\n",
+		    rint);
+		goto end;
+	}
+	if (rint & A10_MMC_INT_ERR_BIT) {
+		device_printf(sc->a10_dev, "error rint: 0x%08X\n", rint);
+		if (rint & A10_MMC_INT_RESP_TIMEOUT)
+			sc->a10_req->cmd->error = MMC_ERR_TIMEOUT;
+		else
+			sc->a10_req->cmd->error = MMC_ERR_FAILED;
+		a10_mmc_req_done(sc);
+		goto end;
+	}
+	if (idst & A10_MMC_IDST_ERROR) {
+		device_printf(sc->a10_dev, "error idst: 0x%08x\n", idst);
+		sc->a10_req->cmd->error = MMC_ERR_FAILED;
+		a10_mmc_req_done(sc);
+		goto end;
+	}
+
+	sc->a10_intr |= rint;
+	data = sc->a10_req->cmd->data;
+	if (data != NULL && (idst & A10_MMC_IDST_COMPLETE) != 0) {
+		if (data->flags & MMC_DATA_WRITE)
+			sync_op = BUS_DMASYNC_POSTWRITE;
+		else
+			sync_op = BUS_DMASYNC_POSTREAD;
+		bus_dmamap_sync(sc->a10_dma_buf_tag, sc->a10_dma_buf_map,
+		    sync_op);
+		bus_dmamap_sync(sc->a10_dma_tag, sc->a10_dma_map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(sc->a10_dma_buf_tag, sc->a10_dma_buf_map);
+		sc->a10_resid = data->len >> 2;
+	}
+	if ((sc->a10_intr & sc->a10_intr_wait) == sc->a10_intr_wait)
+		a10_mmc_req_ok(sc);
+
+end:
+	A10_MMC_WRITE_4(sc, A10_MMC_IDST, idst);
+	A10_MMC_WRITE_4(sc, A10_MMC_RISR, rint);
+	A10_MMC_UNLOCK(sc);
+}
+
+static int
+a10_mmc_request(device_t bus, device_t child, struct mmc_request *req)
+{
+	int blksz;
+	struct a10_mmc_softc *sc;
+	struct mmc_command *cmd;
+	uint32_t cmdreg;
+	int err;
+
+	sc = device_get_softc(bus);
+	A10_MMC_LOCK(sc);
+	if (sc->a10_req) {
+		A10_MMC_UNLOCK(sc);
+		return (EBUSY);
+	}
+	sc->a10_req = req;
+	cmd = req->cmd;
+	cmdreg = A10_MMC_CMDR_LOAD;
+	if (cmd->opcode == MMC_GO_IDLE_STATE)
+		cmdreg |= A10_MMC_CMDR_SEND_INIT_SEQ;
+	if (cmd->flags & MMC_RSP_PRESENT)
+		cmdreg |= A10_MMC_CMDR_RESP_RCV;
+	if (cmd->flags & MMC_RSP_136)
+		cmdreg |= A10_MMC_CMDR_LONG_RESP;
+	if (cmd->flags & MMC_RSP_CRC)
+		cmdreg |= A10_MMC_CMDR_CHK_RESP_CRC;
+
+	sc->a10_intr = 0;
+	sc->a10_resid = 0;
+	sc->a10_intr_wait = A10_MMC_INT_CMD_DONE;
+	cmd->error = MMC_ERR_NONE;
+	if (cmd->data != NULL) {
+		sc->a10_intr_wait |= A10_MMC_INT_DATA_OVER;
+		cmdreg |= A10_MMC_CMDR_DATA_TRANS | A10_MMC_CMDR_WAIT_PRE_OVER;
+		if (cmd->data->flags & MMC_DATA_MULTI) {
+			cmdreg |= A10_MMC_CMDR_STOP_CMD_FLAG;
+			sc->a10_intr_wait |= A10_MMC_INT_AUTO_STOP_DONE;
+		}
+		if (cmd->data->flags & MMC_DATA_WRITE)
+			cmdreg |= A10_MMC_CMDR_DIR_WRITE;
+		blksz = min(cmd->data->len, MMC_SECTOR_SIZE);
+		A10_MMC_WRITE_4(sc, A10_MMC_BKSR, blksz);
+		A10_MMC_WRITE_4(sc, A10_MMC_BYCR, cmd->data->len);
+
+		err = a10_mmc_prepare_dma(sc);
+		if (err != 0)
+			device_printf(sc->a10_dev, "prepare_dma failed: %d\n", err);
+	}
+
+	A10_MMC_WRITE_4(sc, A10_MMC_CAGR, cmd->arg);
+	A10_MMC_WRITE_4(sc, A10_MMC_CMDR, cmdreg | cmd->opcode);
+	callout_reset(&sc->a10_timeoutc, sc->a10_timeout * hz,
+	    a10_mmc_timeout, sc);
+	A10_MMC_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+a10_mmc_read_ivar(device_t bus, device_t child, int which,
+    uintptr_t *result)
+{
+	struct a10_mmc_softc *sc;
+
+	sc = device_get_softc(bus);
+	switch (which) {
+	default:
+		return (EINVAL);
+	case MMCBR_IVAR_BUS_MODE:
+		*(int *)result = sc->a10_host.ios.bus_mode;
+		break;
+	case MMCBR_IVAR_BUS_WIDTH:
+		*(int *)result = sc->a10_host.ios.bus_width;
+		break;
+	case MMCBR_IVAR_CHIP_SELECT:
+		*(int *)result = sc->a10_host.ios.chip_select;
+		break;
+	case MMCBR_IVAR_CLOCK:
+		*(int *)result = sc->a10_host.ios.clock;
+		break;
+	case MMCBR_IVAR_F_MIN:
+		*(int *)result = sc->a10_host.f_min;
+		break;
+	case MMCBR_IVAR_F_MAX:
+		*(int *)result = sc->a10_host.f_max;
+		break;
+	case MMCBR_IVAR_HOST_OCR:
+		*(int *)result = sc->a10_host.host_ocr;
+		break;
+	case MMCBR_IVAR_MODE:
+		*(int *)result = sc->a10_host.mode;
+		break;
+	case MMCBR_IVAR_OCR:
+		*(int *)result = sc->a10_host.ocr;
+		break;
+	case MMCBR_IVAR_POWER_MODE:
+		*(int *)result = sc->a10_host.ios.power_mode;
+		break;
+	case MMCBR_IVAR_VDD:
+		*(int *)result = sc->a10_host.ios.vdd;
+		break;
+	case MMCBR_IVAR_CAPS:
+		*(int *)result = sc->a10_host.caps;
+		break;
+	case MMCBR_IVAR_MAX_DATA:
+		*(int *)result = 65535;
+		break;
+	}
+
+	return (0);
+}
+
+static int
+a10_mmc_write_ivar(device_t bus, device_t child, int which,
+    uintptr_t value)
+{
+	struct a10_mmc_softc *sc;
+
+	sc = device_get_softc(bus);
+	switch (which) {
+	default:
+		return (EINVAL);
+	case MMCBR_IVAR_BUS_MODE:
+		sc->a10_host.ios.bus_mode = value;
+		break;
+	case MMCBR_IVAR_BUS_WIDTH:
+		sc->a10_host.ios.bus_width = value;
+		break;
+	case MMCBR_IVAR_CHIP_SELECT:
+		sc->a10_host.ios.chip_select = value;
+		break;
+	case MMCBR_IVAR_CLOCK:
+		sc->a10_host.ios.clock = value;
+		break;
+	case MMCBR_IVAR_MODE:
+		sc->a10_host.mode = value;
+		break;
+	case MMCBR_IVAR_OCR:
+		sc->a10_host.ocr = value;
+		break;
+	case MMCBR_IVAR_POWER_MODE:
+		sc->a10_host.ios.power_mode = value;
+		break;
+	case MMCBR_IVAR_VDD:
+		sc->a10_host.ios.vdd = value;
+		break;
+	/* These are read-only */
+	case MMCBR_IVAR_CAPS:
+	case MMCBR_IVAR_HOST_OCR:
+	case MMCBR_IVAR_F_MIN:
+	case MMCBR_IVAR_F_MAX:
+	case MMCBR_IVAR_MAX_DATA:
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+a10_mmc_update_clock(struct a10_mmc_softc *sc, uint32_t clkon)
+{
+	uint32_t cmdreg;
+	int retry;
+	uint32_t ckcr;
+
+	ckcr = A10_MMC_READ_4(sc, A10_MMC_CKCR);
+	ckcr &= ~(A10_MMC_CKCR_CCLK_ENB | A10_MMC_CKCR_CCLK_CTRL);
+
+	if (clkon)
+		ckcr |= A10_MMC_CKCR_CCLK_ENB;
+
+	A10_MMC_WRITE_4(sc, A10_MMC_CKCR, ckcr);
+
+	cmdreg = A10_MMC_CMDR_LOAD | A10_MMC_CMDR_PRG_CLK |
+	    A10_MMC_CMDR_WAIT_PRE_OVER;
+	A10_MMC_WRITE_4(sc, A10_MMC_CMDR, cmdreg);
+	retry = 0xfffff;
+	while (--retry > 0) {
+		if ((A10_MMC_READ_4(sc, A10_MMC_CMDR) & A10_MMC_CMDR_LOAD) == 0) {
+			A10_MMC_WRITE_4(sc, A10_MMC_RISR, 0xffffffff);
+			return (0);
+		}
+		DELAY(10);
+	}
+	A10_MMC_WRITE_4(sc, A10_MMC_RISR, 0xffffffff);
+	device_printf(sc->a10_dev, "timeout updating clock\n");
+
+	return (ETIMEDOUT);
+}
+
+static int
+a10_mmc_update_ios(device_t bus, device_t child)
+{
+	int error;
+	struct a10_mmc_softc *sc;
+	struct mmc_ios *ios;
+	uint32_t ckcr;
+
+	sc = device_get_softc(bus);
+
+	ios = &sc->a10_host.ios;
+
+	/* Set the bus width. */
+	switch (ios->bus_width) {
+	case bus_width_1:
+		A10_MMC_WRITE_4(sc, A10_MMC_BWDR, A10_MMC_BWDR1);
+		break;
+	case bus_width_4:
+		A10_MMC_WRITE_4(sc, A10_MMC_BWDR, A10_MMC_BWDR4);
+		break;
+	case bus_width_8:
+		A10_MMC_WRITE_4(sc, A10_MMC_BWDR, A10_MMC_BWDR8);
+		break;
+	}
+
+	if (ios->clock) {
+
+		/* Disable clock */
+		error = a10_mmc_update_clock(sc, 0);
+		if (error != 0)
+			return (error);
+
+		/* Reset the divider. */
+		ckcr = A10_MMC_READ_4(sc, A10_MMC_CKCR);
+		ckcr &= ~A10_MMC_CKCR_CCLK_DIV;
+		A10_MMC_WRITE_4(sc, A10_MMC_CKCR, ckcr);
+
+		/* Set the MMC clock. */
+		error = clk_set_freq(sc->a10_clk_mmc, ios->clock,
+		    CLK_SET_ROUND_DOWN);
+		if (error != 0) {
+			device_printf(sc->a10_dev,
+			    "failed to set frequency to %u Hz: %d\n",
+			    ios->clock, error);
+			return (error);
+		}
+
+		/* Enable clock. */
+		error = a10_mmc_update_clock(sc, 1);
+		if (error != 0)
+			return (error);
+	}
+
+
+	return (0);
+}
+
+static int
+a10_mmc_get_ro(device_t bus, device_t child)
+{
+
+	return (0);
+}
+
+static int
+a10_mmc_acquire_host(device_t bus, device_t child)
+{
+	struct a10_mmc_softc *sc;
+	int error;
+
+	sc = device_get_softc(bus);
+	A10_MMC_LOCK(sc);
+	while (sc->a10_bus_busy) {
+		error = msleep(sc, &sc->a10_mtx, PCATCH, "mmchw", 0);
+		if (error != 0) {
+			A10_MMC_UNLOCK(sc);
+			return (error);
+		}
+	}
+	sc->a10_bus_busy++;
+	A10_MMC_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+a10_mmc_release_host(device_t bus, device_t child)
+{
+	struct a10_mmc_softc *sc;
+
+	sc = device_get_softc(bus);
+	A10_MMC_LOCK(sc);
+	sc->a10_bus_busy--;
+	wakeup(sc);
+	A10_MMC_UNLOCK(sc);
+
+	return (0);
+}
+
+static device_method_t a10_mmc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a10_mmc_probe),
+	DEVMETHOD(device_attach,	a10_mmc_attach),
+	DEVMETHOD(device_detach,	a10_mmc_detach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_read_ivar,	a10_mmc_read_ivar),
+	DEVMETHOD(bus_write_ivar,	a10_mmc_write_ivar),
+
+	/* MMC bridge interface */
+	DEVMETHOD(mmcbr_update_ios,	a10_mmc_update_ios),
+	DEVMETHOD(mmcbr_request,	a10_mmc_request),
+	DEVMETHOD(mmcbr_get_ro,		a10_mmc_get_ro),
+	DEVMETHOD(mmcbr_acquire_host,	a10_mmc_acquire_host),
+	DEVMETHOD(mmcbr_release_host,	a10_mmc_release_host),
+
+	DEVMETHOD_END
+};
+
+static devclass_t a10_mmc_devclass;
+
+static driver_t a10_mmc_driver = {
+	"a10_mmc",
+	a10_mmc_methods,
+	sizeof(struct a10_mmc_softc),
+};
+
+DRIVER_MODULE(a10_mmc, simplebus, a10_mmc_driver, a10_mmc_devclass, NULL,
+    NULL);
+MMC_DECLARE_BRIDGE(a10_mmc);


Property changes on: trunk/sys/arm/allwinner/a10_mmc.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a10_mmc.h
===================================================================
--- trunk/sys/arm/allwinner/a10_mmc.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/a10_mmc.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,205 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Alexander Fedorov <alexander.fedorov at rtlservice.com>
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_mmc.h 308280 2016-11-04 01:56:29Z manu $
+ */
+
+#ifndef	_A10_MMC_H_
+#define	_A10_MMC_H_
+
+#define	A10_MMC_GCTL		0x00	/* Control Register */
+#define	A10_MMC_CKCR		0x04	/* Clock Control Register */
+#define	A10_MMC_TMOR		0x08	/* Timeout Register */
+#define	A10_MMC_BWDR		0x0C	/* Bus Width Register */
+#define	A10_MMC_BKSR		0x10	/* Block Size Register */
+#define	A10_MMC_BYCR		0x14	/* Byte Count Register */
+#define	A10_MMC_CMDR		0x18	/* Command Register */
+#define	A10_MMC_CAGR		0x1C	/* Argument Register */
+#define	A10_MMC_RESP0		0x20	/* Response Register 0 */
+#define	A10_MMC_RESP1		0x24	/* Response Register 1 */
+#define	A10_MMC_RESP2		0x28	/* Response Register 2 */
+#define	A10_MMC_RESP3		0x2C	/* Response Register 3 */
+#define	A10_MMC_IMKR		0x30	/* Interrupt Mask Register */
+#define	A10_MMC_MISR		0x34	/* Masked Interrupt Status Register */
+#define	A10_MMC_RISR		0x38	/* Raw Interrupt Status Register */
+#define	A10_MMC_STAR		0x3C	/* Status Register */
+#define	A10_MMC_FWLR		0x40	/* FIFO Threshold Watermark Register */
+#define	A10_MMC_FUNS		0x44	/* Function Select Register */
+#define	A10_MMC_HWRST		0x78	/* Hardware reset (not documented) */
+#define	A10_MMC_DMAC		0x80	/* IDMAC Control Register */
+#define	A10_MMC_DLBA		0x84	/* IDMAC Desc List Base Address Reg */
+#define	A10_MMC_IDST		0x88	/* IDMAC Status Register */
+#define	A10_MMC_IDIE		0x8C	/* IDMAC Interrupt Enable Register */
+#define	A10_MMC_FIFO		0x100   /* FIFO Access Address (A10/A20) */
+#define	A31_MMC_FIFO		0x200   /* FIFO Access Address (A31) */
+
+/* A10_MMC_GCTL */
+#define	A10_MMC_CTRL_SOFT_RST		(1U << 0)
+#define	A10_MMC_CTRL_FIFO_RST		(1U << 1)
+#define	A10_MMC_CTRL_DMA_RST		(1U << 2)
+#define	A10_MMC_CTRL_INT_ENB		(1U << 4)
+#define	A10_MMC_CTRL_DMA_ENB		(1U << 5)
+#define	A10_MMC_CTRL_CD_DBC_ENB		(1U << 8)
+#define	A10_MMC_CTRL_DDR_MOD_SEL		(1U << 10)
+#define	A10_MMC_CTRL_FIFO_AC_MOD		(1U << 31)
+#define	A10_MMC_RESET					\
+	(A10_MMC_CTRL_SOFT_RST | A10_MMC_CTRL_FIFO_RST | A10_MMC_CTRL_DMA_RST)
+
+/* A10_MMC_CKCR */
+#define	A10_MMC_CKCR_CCLK_ENB		(1U << 16)
+#define	A10_MMC_CKCR_CCLK_CTRL		(1U << 17)
+#define	A10_MMC_CKCR_CCLK_DIV		0xff
+
+/* A10_MMC_TMOR */
+#define	A10_MMC_TMOR_RTO_LMT_SHIFT(x)	x		/* Response timeout limit */
+#define	A10_MMC_TMOR_RTO_LMT_MASK	0xff
+#define	A10_MMC_TMOR_DTO_LMT_SHIFT(x)	(x << 8)	/* Data timeout limit */
+#define	A10_MMC_TMOR_DTO_LMT_MASK	0xffffff
+
+/* A10_MMC_BWDR */
+#define	A10_MMC_BWDR1			0
+#define	A10_MMC_BWDR4			1
+#define	A10_MMC_BWDR8			2
+
+/* A10_MMC_CMDR */
+#define	A10_MMC_CMDR_RESP_RCV		(1U << 6)
+#define	A10_MMC_CMDR_LONG_RESP		(1U << 7)
+#define	A10_MMC_CMDR_CHK_RESP_CRC	(1U << 8)
+#define	A10_MMC_CMDR_DATA_TRANS		(1U << 9)
+#define	A10_MMC_CMDR_DIR_WRITE		(1U << 10)
+#define	A10_MMC_CMDR_TRANS_MODE_STREAM	(1U << 11)
+#define	A10_MMC_CMDR_STOP_CMD_FLAG	(1U << 12)
+#define	A10_MMC_CMDR_WAIT_PRE_OVER	(1U << 13)
+#define	A10_MMC_CMDR_STOP_ABT_CMD	(1U << 14)
+#define	A10_MMC_CMDR_SEND_INIT_SEQ	(1U << 15)
+#define	A10_MMC_CMDR_PRG_CLK		(1U << 21)
+#define	A10_MMC_CMDR_RD_CEDATA_DEV	(1U << 22)
+#define	A10_MMC_CMDR_CCS_EXP		(1U << 23)
+#define	A10_MMC_CMDR_BOOT_MOD_SHIFT	24
+#define	A10_MMC_CMDR_BOOT_MOD_NORMAL	0
+#define	A10_MMC_CMDR_BOOT_MOD_MANDATORY	1
+#define	A10_MMC_CMDR_BOOT_MOD_ALT	2
+#define	A10_MMC_CMDR_EXP_BOOT_ACK	(1U << 26)
+#define	A10_MMC_CMDR_BOOT_ABT		(1U << 27)
+#define	A10_MMC_CMDR_VOL_SW		(1U << 28)
+#define	A10_MMC_CMDR_LOAD		(1U << 31)
+
+/* A10_MMC_IMKR and A10_MMC_RISR */
+#define	A10_MMC_INT_RESP_ERR	(1U << 1)
+#define	A10_MMC_INT_CMD_DONE		(1U << 2)
+#define	A10_MMC_INT_DATA_OVER		(1U << 3)
+#define	A10_MMC_INT_TX_DATA_REQ		(1U << 4)
+#define	A10_MMC_INT_RX_DATA_REQ		(1U << 5)
+#define	A10_MMC_INT_RESP_CRC_ERR		(1U << 6)
+#define	A10_MMC_INT_DATA_CRC_ERR		(1U << 7)
+#define	A10_MMC_INT_RESP_TIMEOUT		(1U << 8)
+#define	A10_MMC_INT_BOOT_ACK_RECV	(1U << 8)
+#define	A10_MMC_INT_DATA_TIMEOUT		(1U << 9)
+#define	A10_MMC_INT_BOOT_START		(1U << 9)
+#define	A10_MMC_INT_DATA_STARVE		(1U << 10)
+#define	A10_MMC_INT_VOL_CHG_DONE		(1U << 10)
+#define	A10_MMC_INT_FIFO_RUN_ERR		(1U << 11)
+#define	A10_MMC_INT_CMD_BUSY		(1U << 12)
+#define	A10_MMC_INT_DATA_START_ERR	(1U << 13)
+#define	A10_MMC_INT_AUTO_STOP_DONE	(1U << 14)
+#define	A10_MMC_INT_DATA_END_BIT_ERR	(1U << 15)
+#define	A10_MMC_INT_SDIO			(1U << 16)
+#define	A10_MMC_INT_CARD_INSERT		(1U << 30)
+#define	A10_MMC_INT_CARD_REMOVE		(1U << 31)
+#define	A10_MMC_INT_ERR_BIT				\
+	(A10_MMC_INT_RESP_ERR | A10_MMC_INT_RESP_CRC_ERR |	\
+	 A10_MMC_INT_DATA_CRC_ERR | A10_MMC_INT_RESP_TIMEOUT |	\
+	 A10_MMC_INT_FIFO_RUN_ERR |	A10_MMC_INT_CMD_BUSY |	\
+	 A10_MMC_INT_DATA_START_ERR | A10_MMC_INT_DATA_END_BIT_ERR)
+
+/* A10_MMC_STAR */
+#define	A10_MMC_STAR_FIFO_RX_LEVEL	(1U << 0)
+#define	A10_MMC_STAR_FIFO_TX_LEVEL	(1U << 1)
+#define	A10_MMC_STAR_FIFO_EMPTY		(1U << 2)
+#define	A10_MMC_STAR_FIFO_FULL		(1U << 3)
+#define	A10_MMC_STAR_CARD_PRESENT	(1U << 8)
+#define	A10_MMC_STAR_CARD_BUSY		(1U << 9)
+#define	A10_MMC_STAR_FSM_BUSY		(1U << 10)
+#define	A10_MMC_STAR_DMA_REQ			(1U << 31)
+
+/* A10_MMC_FUNS */
+#define	A10_MMC_CE_ATA_ON		(0xceaaU << 16)
+#define	A10_MMC_SEND_IRQ_RESP		(1U << 0)
+#define	A10_MMC_SDIO_RD_WAIT		(1U << 1)
+#define	A10_MMC_ABT_RD_DATA		(1U << 2)
+#define	A10_MMC_SEND_CC_SD		(1U << 8)
+#define	A10_MMC_SEND_AUTOSTOP_CC_SD	(1U << 9)
+#define	A10_MMC_CE_ATA_DEV_INT_ENB	(1U << 10)
+
+/* IDMA CONTROLLER BUS MOD BIT FIELD */
+#define	A10_MMC_DMAC_IDMAC_SOFT_RST	(1U << 0)
+#define	A10_MMC_DMAC_IDMAC_FIX_BURST	(1U << 1)
+#define	A10_MMC_DMAC_IDMAC_IDMA_ON	(1U << 7)
+#define	A10_MMC_DMAC_IDMAC_REFETCH_DES	(1U << 31)
+
+/* A10_MMC_IDST */
+#define	A10_MMC_IDST_TX_INT		(1U << 0)
+#define	A10_MMC_IDST_RX_INT		(1U << 1)
+#define	A10_MMC_IDST_FATAL_BERR_INT	(1U << 2)
+#define	A10_MMC_IDST_DES_UNAVL_INT	(1U << 4)
+#define	A10_MMC_IDST_ERR_FLAG_SUM	(1U << 5)
+#define	A10_MMC_IDST_NOR_INT_SUM		(1U << 8)
+#define	A10_MMC_IDST_ABN_INT_SUM		(1U << 9)
+#define	A10_MMC_IDST_HOST_ABT_INTX	(1U << 10)
+#define	A10_MMC_IDST_HOST_ABT_INRX	(1U << 10)
+#define	A10_MMC_IDST_IDLE		(0U << 13)
+#define	A10_MMC_IDST_SUSPEND		(1U << 13)
+#define	A10_MMC_IDST_DESC_RD		(2U << 13)
+#define	A10_MMC_IDST_DESC_CHECK		(3U << 13)
+#define	A10_MMC_IDST_RD_REQ_WAIT		(4U << 13)
+#define	A10_MMC_IDST_WR_REQ_WAIT		(5U << 13)
+#define	A10_MMC_IDST_RD			(6U << 13)
+#define	A10_MMC_IDST_WR			(7U << 13)
+#define	A10_MMC_IDST_DESC_CLOSE		(8U << 13)
+#define	A10_MMC_IDST_ERROR				\
+	(A10_MMC_IDST_FATAL_BERR_INT | A10_MMC_IDST_ERR_FLAG_SUM |	\
+	 A10_MMC_IDST_DES_UNAVL_INT | A10_MMC_IDST_ABN_INT_SUM)
+#define	A10_MMC_IDST_COMPLETE				\
+	(A10_MMC_IDST_TX_INT | A10_MMC_IDST_RX_INT)
+
+/* The DMA descriptor table. */
+struct a10_mmc_dma_desc {
+	uint32_t config;
+#define	A10_MMC_DMA_CONFIG_DIC		(1U << 1)	/* Disable Interrupt Completion */
+#define	A10_MMC_DMA_CONFIG_LD		(1U << 2)	/* Last DES */
+#define	A10_MMC_DMA_CONFIG_FD		(1U << 3)	/* First DES */
+#define	A10_MMC_DMA_CONFIG_CH		(1U << 4)	/* CHAIN MOD */
+#define	A10_MMC_DMA_CONFIG_ER		(1U << 5)	/* End of Ring (undocumented register) */
+#define	A10_MMC_DMA_CONFIG_CES		(1U << 30)	/* Card Error Summary */
+#define	A10_MMC_DMA_CONFIG_OWN		(1U << 31)	/* DES Own Flag */
+	uint32_t buf_size;
+	uint32_t buf_addr;
+	uint32_t next;
+};
+
+#define	A10_MMC_DMA_ALIGN	4
+
+#endif /* _A10_MMC_H_ */


Property changes on: trunk/sys/arm/allwinner/a10_mmc.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/a10_sramc.c
===================================================================
--- trunk/sys/arm/allwinner/a10_sramc.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/a10_sramc.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -24,11 +24,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: stable/10/sys/arm/allwinner/a10_sramc.c 266337 2014-05-17 18:53:36Z ian $
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_sramc.c 331722 2018-03-29 02:50:57Z eadler $
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/a10_sramc.c 266337 2014-05-17 18:53:36Z ian $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_sramc.c 331722 2018-03-29 02:50:57Z eadler $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -44,7 +44,6 @@
 #include <machine/cpu.h>
 #include <machine/frame.h>
 #include <machine/intr.h>
-#include <machine/fdt.h>
 
 #include <dev/fdt/fdt_common.h>
 #include <dev/ofw/openfirm.h>
@@ -54,6 +53,7 @@
 #include "a10_sramc.h"
 
 #define	SRAM_CTL1_CFG		0x04
+#define	CTL1_CFG_SRAMD_MAP_USB0	(1 << 0)
 
 struct a10_sramc_softc {
 	struct resource		*res;
@@ -73,7 +73,7 @@
 a10_sramc_probe(device_t dev)
 {
 
-	if (ofw_bus_is_compatible(dev, "allwinner,sun4i-sramc")) {
+	if (ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-sram-controller")) {
 		device_set_desc(dev, "Allwinner sramc module");
 		return (BUS_PROBE_DEFAULT);
 	}
@@ -115,7 +115,8 @@
 
 static devclass_t a10_sramc_devclass;
 
-DRIVER_MODULE(a10_sramc, simplebus, a10_sramc_driver, a10_sramc_devclass, 0, 0);
+EARLY_DRIVER_MODULE(a10_sramc, simplebus, a10_sramc_driver, a10_sramc_devclass,
+    0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_EARLY);
 
 int
 a10_map_to_emac(void)
@@ -133,3 +134,20 @@
 
 	return (0);
 }
+
+int
+a10_map_to_otg(void)
+{
+	struct a10_sramc_softc *sc = a10_sramc_sc;
+	uint32_t reg_value;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	/* Map SRAM to OTG */
+	reg_value = sramc_read_4(sc, SRAM_CTL1_CFG);
+	reg_value |= CTL1_CFG_SRAMD_MAP_USB0;
+	sramc_write_4(sc, SRAM_CTL1_CFG, reg_value);
+
+	return (0);
+}

Modified: trunk/sys/arm/allwinner/a10_sramc.h
===================================================================
--- trunk/sys/arm/allwinner/a10_sramc.h	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/a10_sramc.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: stable/10/sys/arm/allwinner/a10_sramc.h 266337 2014-05-17 18:53:36Z ian $
+ * $FreeBSD: stable/11/sys/arm/allwinner/a10_sramc.h 331722 2018-03-29 02:50:57Z eadler $
  */
 
 #ifndef	_A10_SRAMC_H_
@@ -31,5 +31,6 @@
 #define	_A10_SRAMC_H_
 
 int	a10_map_to_emac(void);
+int	a10_map_to_otg(void);
 
 #endif

Added: trunk/sys/arm/allwinner/a31/a31_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/a31/a31_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a31/a31_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,221 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at bidouilliste.com>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a31/a31_padconf.c 298422 2016-04-21 16:49:04Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#ifdef SOC_ALLWINNER_A31
+
+const static struct allwinner_pins a31_pins[] = {
+	{"PA0",  0, 0,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA1",  0, 1,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA2",  0, 2,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA3",  0, 3,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA4",  0, 4,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA5",  0, 5,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA6",  0, 6,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA7",  0, 7,  {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, NULL, NULL}},
+	{"PA8",  0, 8,  {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, NULL, NULL}},
+	{"PA9",  0, 9,  {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, NULL, NULL}},
+	{"PA10", 0, 10, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", NULL, NULL}},
+	{"PA11", 0, 11, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", NULL, NULL}},
+	{"PA12", 0, 12, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", NULL, NULL}},
+	{"PA13", 0, 13, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", NULL, NULL}},
+	{"PA14", 0, 14, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", NULL, NULL}},
+	{"PA15", 0, 15, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_a", NULL, NULL, NULL}},
+	{"PA16", 0, 16, {"gpio_in", "gpio_out", "gmac", "lcd1", "dmic", NULL, NULL, NULL}},
+	{"PA17", 0, 17, {"gpio_in", "gpio_out", "gmac", "lcd1", "dmic", NULL, NULL, NULL}},
+	{"PA18", 0, 18, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_b", NULL, NULL, NULL}},
+	{"PA19", 0, 19, {"gpio_in", "gpio_out", "gmac", "lcd1", "pwm3", NULL, NULL, NULL}},
+	{"PA20", 0, 20, {"gpio_in", "gpio_out", "gmac", "lcd1", "pwm3", NULL, NULL, NULL}},
+	{"PA21", 0, 21, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, NULL, NULL}},
+	{"PA22", 0, 22, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, NULL, NULL}},
+	{"PA23", 0, 23, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, NULL, NULL}},
+	{"PA24", 0, 24, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, NULL, NULL}},
+	{"PA25", 0, 25, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, NULL, NULL}},
+	{"PA26", 0, 26, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_c", NULL, NULL, NULL}},
+	{"PA27", 0, 27, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, NULL, NULL}},
+
+	{"PB0",  1, 0,  {"gpio_in", "gpio_out", "i2s0", "uart3", "csi", NULL, NULL, NULL}},
+	{"PB1",  1, 1,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+	{"PB2",  1, 2,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+	{"PB3",  1, 3,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+	{"PB4",  1, 4,  {"gpio_in", "gpio_out", "i2s0", "uart3", NULL, NULL, NULL, NULL}},
+	{"PB5",  1, 5,  {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, NULL, NULL}},
+	{"PB6",  1, 6,  {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, NULL, NULL}},
+	{"PB7",  1, 7,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PC0",  2, 0,  {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC1",  2, 1,  {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC2",  2, 2,  {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC3",  2, 3,  {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC4",  2, 4,  {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC5",  2, 5,  {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC6",  2, 6,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC7",  2, 7,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC8",  2, 8,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC9",  2, 9,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC16", 2, 16, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC17", 2, 17, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC18", 2, 18, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC19", 2, 19, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC20", 2, 20, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC21", 2, 21, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC22", 2, 22, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC23", 2, 23, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}},
+	{"PC24", 2, 24, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC25", 2, 24, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC26", 2, 24, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC27", 2, 24, {"gpio_in", "gpio_out", NULL, "spi0",NULL, NULL, NULL, NULL}},
+
+	{"PD0",  3, 0,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD1",  3, 1,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD2",  3, 2,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD3",  3, 3,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD4",  3, 4,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD5",  3, 5,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD6",  3, 6,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD7",  3, 7,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD8",  3, 8,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD9",  3, 9,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}},
+	{"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PE0",  4, 0,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE1",  4, 1,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE2",  4, 2,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE3",  4, 3,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE4",  4, 4,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE5",  4, 5,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE6",  4, 6,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE7",  4, 7,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE8",  4, 8,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE9",  4, 9,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE14", 4, 14, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE15", 4, 15, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE16", 4, 16, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PF0",  5, 0,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+	{"PF1",  5, 1,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+	{"PF2",  5, 2,  {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}},
+	{"PF3",  5, 3,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+	{"PF4",  5, 4,  {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}},
+	{"PF5",  5, 5,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+
+	{"PG0",  6, 0,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG1",  6, 1,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG2",  6, 2,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG3",  6, 3,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG4",  6, 4,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG5",  6, 5,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG6",  6, 6,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG7",  6, 7,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG8",  6, 8,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG9",  6, 9,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG10", 6, 10, {"gpio_in", "gpio_out", "i2c3", "usb", NULL, NULL, NULL, NULL}},
+	{"PG11", 6, 11, {"gpio_in", "gpio_out", "i2c3", "usb", NULL, NULL, NULL, NULL}},
+	{"PG12", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG13", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG14", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG15", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG16", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG17", 6, 11, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, NULL, NULL}},
+	{"PG18", 6, 11, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PH0",  7, 0,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH1",  7, 1,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH2",  7, 2,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH3",  7, 3,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH4",  7, 4,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH5",  7, 5,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH6",  7, 6,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH7",  7, 7,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH8",  7, 8,  {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH9",  7, 9,  {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}},
+	{"PH10", 7, 10, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}},
+	{"PH11", 7, 11, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}},
+	{"PH12", 7, 12, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}},
+	{"PH13", 7, 13, {"gpio_in", "gpio_out", "pwm0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH14", 7, 14, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH15", 7, 15, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH16", 7, 16, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH17", 7, 17, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH18", 7, 18, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}},
+	{"PH19", 7, 19, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}},
+	{"PH20", 7, 20, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH21", 7, 21, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH22", 7, 22, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH23", 7, 23, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH24", 7, 24, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH25", 7, 25, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH26", 7, 26, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH27", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH28", 7, 28, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH29", 7, 29, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH30", 7, 30, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}},
+};
+
+const struct allwinner_padconf a31_padconf = {
+	.npins = nitems(a31_pins),
+	.pins = a31_pins,
+};
+
+#endif /* SOC_ALLWINNER_A31 */


Property changes on: trunk/sys/arm/allwinner/a31/a31_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a31/a31_r_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/a31/a31_r_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a31/a31_r_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,67 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at bidouilliste.com>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a31/a31_r_padconf.c 298513 2016-04-23 13:59:18Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+
+const static struct allwinner_pins a31_r_pins[] = {
+	{"PL0",  0, 0,  {"gpio_in", "gpio_out", "s_twi", "s_p2wi", NULL, NULL, NULL, NULL}},
+	{"PL1",  0, 1,  {"gpio_in", "gpio_out", "s_twi", "s_p2wi", NULL, NULL, NULL, NULL}},
+	{"PL2",  0, 2,  {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, NULL}},
+	{"PL3",  0, 3,  {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, NULL}},
+	{"PL4",  0, 4,  {"gpio_in", "gpio_out", "s_ir", NULL, NULL, NULL, NULL, NULL}},
+	{"PL5",  0, 5,  {"gpio_in", "gpio_out", "pl_eint0", "s_jtag", NULL, NULL, NULL, NULL}},
+	{"PL6",  0, 6,  {"gpio_in", "gpio_out", "pl_eint1", "s_jtag", NULL, NULL, NULL, NULL}},
+	{"PL7",  0, 7,  {"gpio_in", "gpio_out", "pl_eint2", "s_jtag", NULL, NULL, NULL, NULL}},
+	{"PL8",  0, 8,  {"gpio_in", "gpio_out", "pl_eint3", "s_jtag", NULL, NULL, NULL, NULL}},
+
+	{"PM0",  1, 0,  {"gpio_in", "gpio_out", "pm_eint0", NULL, NULL, NULL, NULL, NULL}},
+	{"PM1",  1, 1,  {"gpio_in", "gpio_out", "pm_eint1", NULL, NULL, NULL, NULL, NULL}},
+	{"PM2",  1, 2,  {"gpio_in", "gpio_out", "pm_eint2", "1wire", NULL, NULL, NULL, NULL}},
+	{"PM3",  1, 3,  {"gpio_in", "gpio_out", "pm_eint3", NULL, NULL, NULL, NULL, NULL}},
+	{"PM4",  1, 4,  {"gpio_in", "gpio_out", "pm_eint4", NULL, NULL, NULL, NULL, NULL}},
+	{"PM5",  1, 5,  {"gpio_in", "gpio_out", "pm_eint5", NULL, NULL, NULL, NULL, NULL}},
+	{"PM6",  1, 6,  {"gpio_in", "gpio_out", "pm_eint6", NULL, NULL, NULL, NULL, NULL}},
+	{"PM7",  1, 7,  {"gpio_in", "gpio_out", "pm_eint7", "rtc", NULL, NULL, NULL, NULL}},
+};
+
+const struct allwinner_padconf a31_r_padconf = {
+	.npins = nitems(a31_r_pins),
+	.pins = a31_r_pins,
+};
+
+#endif


Property changes on: trunk/sys/arm/allwinner/a31/a31_r_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a31/a31s_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/a31/a31s_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a31/a31s_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,201 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at bidouilliste.com>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a31/a31s_padconf.c 298422 2016-04-21 16:49:04Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#ifdef SOC_ALLWINNER_A31S
+
+const static struct allwinner_pins a31s_pins[] = {
+	{"PA0",  0, 0,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA1",  0, 1,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA2",  0, 2,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA3",  0, 3,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA4",  0, 4,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA5",  0, 5,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA6",  0, 6,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA7",  0, 7,  {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, NULL, NULL}},
+	{"PA8",  0, 8,  {"gpio_in", "gpio_out", "gmac", NULL, NULL, NULL, NULL, NULL}},
+	{"PA9",  0, 9,  {"gpio_in", "gpio_out", "gmac", NULL, NULL, NULL, NULL, NULL}},
+	{"PA10", 0, 10, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", NULL, NULL}},
+	{"PA11", 0, 11, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", NULL, NULL}},
+	{"PA12", 0, 12, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", NULL, NULL}},
+	{"PA13", 0, 13, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", NULL, NULL}},
+	{"PA14", 0, 14, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", NULL, NULL}},
+	{"PA15", 0, 15, {"gpio_in", "gpio_out", "gmac", NULL, "dmic", NULL, NULL, NULL}},
+	{"PA16", 0, 16, {"gpio_in", "gpio_out", "gmac", NULL, "dmic", NULL, NULL, NULL}},
+	{"PA17", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "clk_out_b", NULL, NULL, NULL}},
+	{"PA18", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "pwm3", NULL, NULL, NULL}},
+	{"PA19", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "pwm3", NULL, NULL, NULL}},
+	{"PA20", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, NULL, NULL}},
+	{"PA21", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, NULL, NULL}},
+	{"PA22", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, NULL, NULL}},
+	{"PA23", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, NULL, NULL}},
+	{"PA24", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, NULL, NULL}},
+	{"PA25", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, NULL, NULL}},
+	{"PA26", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "clk_out_c", NULL, NULL, NULL}},
+	{"PA27", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PB0",  1, 0,  {"gpio_in", "gpio_out", "i2s0", "uart3", NULL , NULL, NULL, NULL}},
+	{"PB1",  1, 1,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+	{"PB2",  1, 2,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+	{"PB3",  1, 3,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+	{"PB4",  1, 4,  {"gpio_in", "gpio_out", "i2s0", "uart3", NULL, NULL, NULL, NULL}},
+	{"PB5",  1, 5,  {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, NULL, NULL}},
+	{"PB6",  1, 6,  {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, NULL, NULL}},
+	{"PB7",  1, 7,  {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PC0",  2, 0,  {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC1",  2, 1,  {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC2",  2, 2,  {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC3",  2, 3,  {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC4",  2, 4,  {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC5",  2, 5,  {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC6",  2, 6,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC7",  2, 7,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC8",  2, 8,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC9",  2, 9,  {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC24", 2, 24, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}},
+	{"PC25", 2, 24, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC26", 2, 24, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}},
+	{"PC27", 2, 24, {"gpio_in", "gpio_out", NULL, "spi0",NULL, NULL, NULL, NULL}},
+
+	{"PD0",  3, 0,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD1",  3, 1,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD2",  3, 2,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD3",  3, 3,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD4",  3, 4,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD5",  3, 5,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD6",  3, 6,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD7",  3, 7,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD8",  3, 8,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD9",  3, 9,  {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}},
+	{"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+	{"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PE0",  4, 0,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE1",  4, 1,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE2",  4, 2,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE3",  4, 3,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE4",  4, 4,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE5",  4, 5,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE6",  4, 6,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE7",  4, 7,  {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, NULL, NULL}},
+	{"PE8",  4, 8,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE9",  4, 9,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE12", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE13", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE14", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE15", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+
+	{"PF0",  5, 0,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+	{"PF1",  5, 1,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+	{"PF2",  5, 2,  {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}},
+	{"PF3",  5, 3,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+	{"PF4",  5, 4,  {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}},
+	{"PF5",  5, 5,  {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}},
+
+	{"PG0",  6, 0,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG1",  6, 1,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG2",  6, 2,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG3",  6, 3,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG4",  6, 4,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG5",  6, 5,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, NULL}},
+	{"PG6",  6, 6,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG7",  6, 7,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG8",  6, 8,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG9",  6, 9,  {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, NULL, NULL}},
+	{"PG10", 6, 10, {"gpio_in", "gpio_out", "i2c3", NULL, NULL, NULL, NULL, NULL}},
+	{"PG11", 6, 11, {"gpio_in", "gpio_out", "i2c3", NULL, NULL, NULL, NULL, NULL}},
+	{"PG12", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG13", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG14", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG15", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG16", 6, 11, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, NULL, NULL}},
+	{"PG17", 6, 11, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, NULL, NULL}},
+	{"PG18", 6, 11, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PH9",  7, 9,  {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}},
+	{"PH10", 7, 10, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}},
+	{"PH11", 7, 11, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}},
+	{"PH12", 7, 12, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}},
+	{"PH13", 7, 13, {"gpio_in", "gpio_out", "pwm0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH14", 7, 14, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH15", 7, 15, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH16", 7, 16, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH17", 7, 17, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}},
+	{"PH18", 7, 18, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}},
+	{"PH19", 7, 19, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}},
+	{"PH20", 7, 20, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH21", 7, 21, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}},
+	{"PH22", 7, 22, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH23", 7, 23, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH24", 7, 24, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH25", 7, 25, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH26", 7, 26, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH27", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PH28", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+};
+
+const struct allwinner_padconf a31s_padconf = {
+	.npins = nitems(a31s_pins),
+	.pins = a31s_pins,
+};
+
+#endif /* SOC_ALLWINNER_A31S */


Property changes on: trunk/sys/arm/allwinner/a31/a31s_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a31/files.a31
===================================================================
--- trunk/sys/arm/allwinner/a31/files.a31	                        (rev 0)
+++ trunk/sys/arm/allwinner/a31/files.a31	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,5 @@
+# $MidnightBSD$
+
+arm/allwinner/a31/a31_padconf.c		standard
+arm/allwinner/a31/a31_r_padconf.c	standard
+arm/allwinner/a31/a31s_padconf.c	standard


Property changes on: trunk/sys/arm/allwinner/a31/files.a31
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a31/std.a31
===================================================================
--- trunk/sys/arm/allwinner/a31/std.a31	                        (rev 0)
+++ trunk/sys/arm/allwinner/a31/std.a31	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,15 @@
+# Allwinner A31 common options
+# $MidnightBSD$
+
+cpu		CPU_CORTEXA
+machine 	arm armv6
+makeoptions	CONF_CFLAGS="-march=armv7a"
+
+makeoptions	KERNVIRTADDR=0xc0200000
+options 	KERNVIRTADDR=0xc0200000
+
+options 	IPI_IRQ_START=0
+options 	IPI_IRQ_END=15
+
+files		"../allwinner/files.allwinner"
+files		"../allwinner/a31/files.a31"


Property changes on: trunk/sys/arm/allwinner/a31/std.a31
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a83t/a83t_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/a83t/a83t_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a83t/a83t_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,163 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a83t/a83t_padconf.c 299113 2016-05-05 09:41:57Z jmcneill $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a83t/a83t_padconf.c 299113 2016-05-05 09:41:57Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#ifdef SOC_ALLWINNER_A83T
+
+static const struct allwinner_pins a83t_pins[] = {
+	{ "PB0",  1, 0,   { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } },
+	{ "PB1",  1, 1,   { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } },
+	{ "PB2",  1, 2,   { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } },
+	{ "PB3",  1, 3,   { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } },
+	{ "PB4",  1, 4,   { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } },
+	{ "PB5",  1, 5,   { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } },
+	{ "PB6",  1, 6,   { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } },
+	{ "PB7",  1, 7,   { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } },
+	{ "PB8",  1, 8,   { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } },
+	{ "PB9",  1, 9,   { "gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint" } },
+	{ "PB10", 1, 10,  { "gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint" } },
+
+	{ "PC0",  2, 0,   { "gpio_in", "gpio_out", "nand", "spi0" } },
+	{ "PC1",  2, 1,   { "gpio_in", "gpio_out", "nand", "spi0" } },
+	{ "PC2",  2, 2,   { "gpio_in", "gpio_out", "nand", "spi0" } },
+	{ "PC3",  2, 3,   { "gpio_in", "gpio_out", "nand", "spi0" } },
+	{ "PC4",  2, 4,   { "gpio_in", "gpio_out", "nand" } },
+	{ "PC5",  2, 5,   { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC6",  2, 6,   { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC7",  2, 7,   { "gpio_in", "gpio_out", "nand" } },
+	{ "PC8",  2, 8,   { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC9",  2, 9,   { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC10", 2, 10,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC11", 2, 11,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC12", 2, 12,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC13", 2, 13,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC14", 2, 14,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC15", 2, 15,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC16", 2, 16,  { "gpio_in", "gpio_out", "nand", "mmc2" } },
+	{ "PC17", 2, 17,  { "gpio_in", "gpio_out", "nand" } },
+	{ "PC18", 2, 18,  { "gpio_in", "gpio_out", "nand" } },
+
+	{ "PD2",  3, 2,   { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD3",  3, 3,   { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD4",  3, 4,   { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD5",  3, 5,   { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD6",  3, 6,   { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD7",  3, 7,   { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD10", 3, 10,  { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD11", 3, 11,  { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD12", 3, 12,  { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD13", 3, 13,  { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD14", 3, 14,  { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD15", 3, 15,  { "gpio_in", "gpio_out", "lcd", NULL, "emac" } },
+	{ "PD18", 3, 18,  { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } },
+	{ "PD19", 3, 19,  { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } },
+	{ "PD20", 3, 20,  { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } },
+	{ "PD21", 3, 21,  { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } },
+	{ "PD22", 3, 22,  { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } },
+	{ "PD23", 3, 23,  { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } },
+	{ "PD24", 3, 24,  { "gpio_in", "gpio_out", "lcd", "lvds" } },
+	{ "PD25", 3, 25,  { "gpio_in", "gpio_out", "lcd", "lvds" } },
+	{ "PD26", 3, 26,  { "gpio_in", "gpio_out", "lcd", "lvds" } },
+	{ "PD27", 3, 27,  { "gpio_in", "gpio_out", "lcd", "lvds" } },
+	{ "PD28", 3, 28,  { "gpio_in", "gpio_out", "pwm" } },
+	{ "PD29", 3, 29,  { "gpio_in", "gpio_out" } },
+
+	{ "PE0",  4, 0,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE1",  4, 1,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE2",  4, 2,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE3",  4, 3,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE4",  4, 4,   { "gpio_in", "gpio_out", "csi" } },
+	{ "PE5",  4, 5,   { "gpio_in", "gpio_out", "csi" } },
+	{ "PE6",  4, 6,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE7",  4, 7,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE8",  4, 8,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE9",  4, 9,   { "gpio_in", "gpio_out", "csi", NULL, "ccir" } },
+	{ "PE10", 4, 10,  { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } },
+	{ "PE11", 4, 11,  { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } },
+	{ "PE12", 4, 12,  { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } },
+	{ "PE13", 4, 13,  { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } },
+	{ "PE14", 4, 14,  { "gpio_in", "gpio_out", "csi", "twi2" } },
+	{ "PE15", 4, 15,  { "gpio_in", "gpio_out", "csi", "twi2" } },
+	{ "PE16", 4, 16,  { "gpio_in", "gpio_out" } },
+	{ "PE17", 4, 17,  { "gpio_in", "gpio_out" } },
+	{ "PE18", 4, 18,  { "gpio_in", "gpio_out", NULL, "owa" } },
+	{ "PE19", 4, 19,  { "gpio_in", "gpio_out" } },
+
+	{ "PF0",  5, 0,   { "gpio_in", "gpio_out", "mmc0", "jtag" } },
+	{ "PF1",  5, 1,   { "gpio_in", "gpio_out", "mmc0", "jtag" } },
+	{ "PF2",  5, 2,   { "gpio_in", "gpio_out", "mmc0", "uart0" } },
+	{ "PF3",  5, 3,   { "gpio_in", "gpio_out", "mmc0", "jtag" } },
+	{ "PF4",  5, 4,   { "gpio_in", "gpio_out", "mmc0", "uart0" } },
+	{ "PF5",  5, 5,   { "gpio_in", "gpio_out", "mmc0", "jtag" } },
+	{ "PF6",  5, 6,   { "gpio_in", "gpio_out" } },
+
+	{ "PG0",  6, 0,   { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } },
+	{ "PG1",  6, 1,   { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } },
+	{ "PG2",  6, 2,   { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } },
+	{ "PG3",  6, 3,   { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } },
+	{ "PG4",  6, 4,   { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } },
+	{ "PG5",  6, 5,   { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } },
+	{ "PG6",  6, 6,   { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } },
+	{ "PG7",  6, 7,   { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } },
+	{ "PG8",  6, 8,   { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } },
+	{ "PG9",  6, 9,   { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } },
+	{ "PG10", 6, 10,  { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } },
+	{ "PG11", 6, 11,  { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } },
+	{ "PG12", 6, 12,  { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } },
+	{ "PG13", 6, 13,  { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } },
+
+	{ "PH0",  7, 0,   { "gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, "eint" } },
+	{ "PH1",  7, 1,   { "gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, "eint" } },
+	{ "PH2",  7, 2,   { "gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, "eint" } },
+	{ "PH3",  7, 3,   { "gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, "eint" } },
+	{ "PH4",  7, 4,   { "gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, "eint" } },
+	{ "PH5",  7, 5,   { "gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, "eint" } },
+	{ "PH6",  7, 6,   { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } },
+	{ "PH7",  7, 7,   { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } },
+	{ "PH8",  7, 8,   { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } },
+	{ "PH9",  7, 9,   { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } },
+	{ "PH10", 7, 10,  { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } },
+	{ "PH11", 7, 11,  { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } },
+};
+
+const struct allwinner_padconf a83t_padconf = {
+	.npins = nitems(a83t_pins),
+	.pins = a83t_pins,
+};
+
+#endif /* !SOC_ALLWINNER_A83T */


Property changes on: trunk/sys/arm/allwinner/a83t/a83t_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a83t/a83t_r_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/a83t/a83t_r_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/a83t/a83t_r_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,63 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/a83t/a83t_r_padconf.c 299113 2016-05-05 09:41:57Z jmcneill $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a83t/a83t_r_padconf.c 299113 2016-05-05 09:41:57Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#ifdef SOC_ALLWINNER_A83T
+
+static const struct allwinner_pins a83t_r_pins[] = {
+	{ "PL0",   0, 0,  { "gpio_in", "gpio_out", "s_rsb", "s_i2c", NULL, NULL, "eint" } },
+	{ "PL1",   0, 1,  { "gpio_in", "gpio_out", "s_rsb", "s_i2c", NULL, NULL, "eint" } },
+	{ "PL2",   0, 2,  { "gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "eint" } },
+	{ "PL3",   0, 3,  { "gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "eint" } },
+	{ "PL4",   0, 4,  { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } },
+	{ "PL5",   0, 5,  { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } },
+	{ "PL6",   0, 6,  { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } },
+	{ "PL7",   0, 7,  { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } },
+	{ "PL8",   0, 8,  { "gpio_in", "gpio_out", "s_i2c", NULL, NULL, NULL, "eint" } },
+	{ "PL9",   0, 9,  { "gpio_in", "gpio_out", "s_i2c", NULL, NULL, NULL, "eint" } },
+	{ "PL10",  0, 10, { "gpio_in", "gpio_out", "s_pwm", NULL, NULL, NULL, "eint" } },
+	{ "PL11",  0, 11, { "gpio_in", "gpio_out", NULL, NULL, NULL, "eint" } },
+	{ "PL12",  0, 12, { "gpio_in", "gpio_out", "s_cir", NULL, NULL, NULL, "eint" } },
+};
+
+const struct allwinner_padconf a83t_r_padconf = {
+	.npins = nitems(a83t_r_pins),
+	.pins = a83t_r_pins,
+};
+
+#endif /* !SOC_ALLWINNER_A83T */


Property changes on: trunk/sys/arm/allwinner/a83t/a83t_r_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a83t/files.a83t
===================================================================
--- trunk/sys/arm/allwinner/a83t/files.a83t	                        (rev 0)
+++ trunk/sys/arm/allwinner/a83t/files.a83t	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,4 @@
+# $MidnightBSD$
+
+arm/allwinner/a83t/a83t_padconf.c	standard
+arm/allwinner/a83t/a83t_r_padconf.c	standard


Property changes on: trunk/sys/arm/allwinner/a83t/files.a83t
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/a83t/std.a83t
===================================================================
--- trunk/sys/arm/allwinner/a83t/std.a83t	                        (rev 0)
+++ trunk/sys/arm/allwinner/a83t/std.a83t	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,15 @@
+# Allwinner A83T common options
+# $MidnightBSD$
+
+cpu		CPU_CORTEXA
+machine 	arm armv6
+makeoptions	CONF_CFLAGS="-march=armv7a"
+
+makeoptions	KERNVIRTADDR=0xc0200000
+options 	KERNVIRTADDR=0xc0200000
+
+options 	IPI_IRQ_START=0
+options 	IPI_IRQ_END=15
+
+files		"../allwinner/files.allwinner"
+files		"../allwinner/a83t/files.a83t"


Property changes on: trunk/sys/arm/allwinner/a83t/std.a83t
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/allwinner_pinctrl.h
===================================================================
--- trunk/sys/arm/allwinner/allwinner_pinctrl.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/allwinner_pinctrl.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,47 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/allwinner_pinctrl.h 331182 2018-03-19 06:40:11Z eadler $
+ */
+
+#ifndef _ALLWINNER_PINCTRL_H_
+#define	_ALLWINNER_PINCTRL_H_
+
+#define AW_MAX_FUNC_BY_PIN	8
+
+struct allwinner_pins {
+	const char *name;
+	uint8_t port;
+	uint8_t pin;
+	const char *functions[8];
+};
+
+struct allwinner_padconf {
+	uint32_t			npins;
+	const struct allwinner_pins *	pins;
+};
+
+#endif /* _ALLWINNER_PINCTRL_H_ */


Property changes on: trunk/sys/arm/allwinner/allwinner_pinctrl.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_ccu.c
===================================================================
--- trunk/sys/arm/allwinner/aw_ccu.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_ccu.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,302 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_ccu.c 305436 2016-09-05 20:17:18Z manu $
+ */
+
+/*
+ * Allwinner oscillator clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_ccu.c 305436 2016-09-05 20:17:18Z manu $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include "clkdev_if.h"
+
+#define	CCU_BASE	0x01c20000
+#define	CCU_SIZE	0x400
+
+#define	PRCM_BASE	0x01f01400
+#define	PRCM_SIZE	0x200
+
+#define	SYSCTRL_BASE	0x01c00000
+#define	SYSCTRL_SIZE	0x34
+
+struct aw_ccu_softc {
+	struct simplebus_softc	sc;
+	bus_space_tag_t		bst;
+	bus_space_handle_t	ccu_bsh;
+	bus_space_handle_t	prcm_bsh;
+	bus_space_handle_t	sysctrl_bsh;
+	struct mtx		mtx;
+	int			flags;
+};
+
+#define	CLOCK_CCU	(1 << 0)
+#define	CLOCK_PRCM	(1 << 1)
+#define	CLOCK_SYSCTRL	(1 << 2)
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10",	CLOCK_CCU },
+	{ "allwinner,sun5i-a13",	CLOCK_CCU },
+	{ "allwinner,sun7i-a20",	CLOCK_CCU },
+	{ "allwinner,sun6i-a31",	CLOCK_CCU },
+	{ "allwinner,sun6i-a31s",	CLOCK_CCU },
+	{ "allwinner,sun8i-a83t",	CLOCK_CCU|CLOCK_PRCM|CLOCK_SYSCTRL },
+	{ "allwinner,sun8i-h3",		CLOCK_CCU },
+	{ NULL, 0 }
+};
+
+static int
+aw_ccu_check_addr(struct aw_ccu_softc *sc, bus_addr_t addr,
+    bus_space_handle_t *pbsh, bus_size_t *poff)
+{
+	if (addr >= CCU_BASE && addr < (CCU_BASE + CCU_SIZE) &&
+	    (sc->flags & CLOCK_CCU) != 0) {
+		*poff = addr - CCU_BASE;
+		*pbsh = sc->ccu_bsh;
+		return (0);
+	}
+	if (addr >= PRCM_BASE && addr < (PRCM_BASE + PRCM_SIZE) &&
+	    (sc->flags & CLOCK_PRCM) != 0) {
+		*poff = addr - PRCM_BASE;
+		*pbsh = sc->prcm_bsh;
+		return (0);
+	}
+	if (addr >= SYSCTRL_BASE && addr < (SYSCTRL_BASE + SYSCTRL_SIZE) &&
+	    (sc->flags & CLOCK_SYSCTRL) != 0) {
+		*poff = addr - SYSCTRL_BASE;
+		*pbsh = sc->sysctrl_bsh;
+		return (0);
+	}
+	return (EINVAL);
+}
+
+static int
+aw_ccu_write_4(device_t dev, bus_addr_t addr, uint32_t val)
+{
+	struct aw_ccu_softc *sc;
+	bus_space_handle_t bsh;
+	bus_size_t reg;
+
+	sc = device_get_softc(dev);
+
+	if (aw_ccu_check_addr(sc, addr, &bsh, &reg) != 0)
+		return (EINVAL);
+
+	mtx_assert(&sc->mtx, MA_OWNED);
+	bus_space_write_4(sc->bst, bsh, reg, val);
+
+	return (0);
+}
+
+static int
+aw_ccu_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+{
+	struct aw_ccu_softc *sc;
+	bus_space_handle_t bsh;
+	bus_size_t reg;
+
+	sc = device_get_softc(dev);
+
+	if (aw_ccu_check_addr(sc, addr, &bsh, &reg) != 0)
+		return (EINVAL);
+
+	mtx_assert(&sc->mtx, MA_OWNED);
+	*val = bus_space_read_4(sc->bst, bsh, reg);
+
+	return (0);
+}
+
+static int
+aw_ccu_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
+{
+	struct aw_ccu_softc *sc;
+	bus_space_handle_t bsh;
+	bus_size_t reg;
+	uint32_t val;
+
+	sc = device_get_softc(dev);
+
+	if (aw_ccu_check_addr(sc, addr, &bsh, &reg) != 0)
+		return (EINVAL);
+
+	mtx_assert(&sc->mtx, MA_OWNED);
+	val = bus_space_read_4(sc->bst, bsh, reg);
+	val &= ~clr;
+	val |= set;
+	bus_space_write_4(sc->bst, bsh, reg, val);
+
+	return (0);
+}
+
+static void
+aw_ccu_device_lock(device_t dev)
+{
+	struct aw_ccu_softc *sc;
+
+	sc = device_get_softc(dev);
+	mtx_lock(&sc->mtx);
+}
+
+static void
+aw_ccu_device_unlock(device_t dev)
+{
+	struct aw_ccu_softc *sc;
+
+	sc = device_get_softc(dev);
+	mtx_unlock(&sc->mtx);
+}
+
+static const struct ofw_compat_data *
+aw_ccu_search_compatible(void) 
+{
+	const struct ofw_compat_data *compat;
+	phandle_t root;
+
+	root = OF_finddevice("/");
+	for (compat = compat_data; compat->ocd_str != NULL; compat++)
+		if (fdt_is_compatible(root, compat->ocd_str))
+			break;
+
+	return (compat);
+}
+
+static int
+aw_ccu_probe(device_t dev)
+{
+	const char *name;
+
+	name = ofw_bus_get_name(dev);
+
+	if (name == NULL || strcmp(name, "clocks") != 0)
+		return (ENXIO);
+
+	if (aw_ccu_search_compatible()->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Clock Control Unit");
+	return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+aw_ccu_attach(device_t dev)
+{
+	struct aw_ccu_softc *sc;
+	phandle_t node, child;
+	device_t cdev;
+	int error;
+
+	sc = device_get_softc(dev);
+	node = ofw_bus_get_node(dev);
+
+	simplebus_init(dev, node);
+
+	sc->flags = aw_ccu_search_compatible()->ocd_data;
+
+	/*
+	 * Map registers. The DT doesn't have a "reg" property
+	 * for the /clocks node and child nodes have conflicting "reg"
+	 * properties.
+	 */
+	sc->bst = bus_get_bus_tag(dev);
+	if (sc->flags & CLOCK_CCU) {
+		error = bus_space_map(sc->bst, CCU_BASE, CCU_SIZE, 0,
+		    &sc->ccu_bsh);
+		if (error != 0) {
+			device_printf(dev, "couldn't map CCU: %d\n", error);
+			return (error);
+		}
+	}
+	if (sc->flags & CLOCK_PRCM) {
+		error = bus_space_map(sc->bst, PRCM_BASE, PRCM_SIZE, 0,
+		    &sc->prcm_bsh);
+		if (error != 0) {
+			device_printf(dev, "couldn't map PRCM: %d\n", error);
+			return (error);
+		}
+	}
+	if (sc->flags & CLOCK_SYSCTRL) {
+		error = bus_space_map(sc->bst, SYSCTRL_BASE, SYSCTRL_SIZE, 0,
+		    &sc->sysctrl_bsh);
+		if (error != 0) {
+			device_printf(dev, "couldn't map SYSCTRL: %d\n", error);
+			return (error);
+		}
+	}
+
+	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+	/* Attach child devices */
+	for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+		cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL);
+		if (cdev != NULL)
+			device_probe_and_attach(cdev);
+	}
+
+	return (bus_generic_attach(dev));
+}
+
+static device_method_t aw_ccu_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_ccu_probe),
+	DEVMETHOD(device_attach,	aw_ccu_attach),
+
+	/* clkdev interface */
+	DEVMETHOD(clkdev_write_4,	aw_ccu_write_4),
+	DEVMETHOD(clkdev_read_4,	aw_ccu_read_4),
+	DEVMETHOD(clkdev_modify_4,	aw_ccu_modify_4),
+	DEVMETHOD(clkdev_device_lock,	aw_ccu_device_lock),
+	DEVMETHOD(clkdev_device_unlock,	aw_ccu_device_unlock),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(aw_ccu, aw_ccu_driver, aw_ccu_methods,
+    sizeof(struct aw_ccu_softc), simplebus_driver);
+
+static devclass_t aw_ccu_devclass;
+
+EARLY_DRIVER_MODULE(aw_ccu, simplebus, aw_ccu_driver, aw_ccu_devclass,
+    0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+
+MODULE_VERSION(aw_ccu, 1);


Property changes on: trunk/sys/arm/allwinner/aw_ccu.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_if_dwc.c
===================================================================
--- trunk/sys/arm/allwinner/aw_if_dwc.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_if_dwc.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,146 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015 Luiz Otavio O Souza <loos at FreeBSD.org>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_if_dwc.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/dwc/if_dwc.h>
+#include <dev/dwc/if_dwcvar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/aw_machdep.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/regulator/regulator.h>
+
+#include "if_dwc_if.h"
+
+static int
+a20_if_dwc_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-gmac"))
+		return (ENXIO);
+	device_set_desc(dev, "A20 Gigabit Ethernet Controller");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a20_if_dwc_init(device_t dev)
+{
+	const char *tx_parent_name;
+	char *phy_type;
+	clk_t clk_tx, clk_tx_parent;
+	regulator_t reg;
+	phandle_t node;
+	int error;
+
+	node = ofw_bus_get_node(dev);
+
+	/* Configure PHY for MII or RGMII mode */
+	if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type)) {
+		error = clk_get_by_ofw_name(dev, 0, "allwinner_gmac_tx", &clk_tx);
+		if (error != 0) {
+			device_printf(dev, "could not get tx clk\n");
+			return (error);
+		}
+
+		if (strcmp(phy_type, "rgmii") == 0)
+			tx_parent_name = "gmac_int_tx";
+		else
+			tx_parent_name = "mii_phy_tx";
+
+		error = clk_get_by_name(dev, tx_parent_name, &clk_tx_parent);
+		if (error != 0) {
+			device_printf(dev, "could not get clock '%s'\n",
+			    tx_parent_name);
+			return (error);
+		}
+
+		error = clk_set_parent_by_clk(clk_tx, clk_tx_parent);
+		if (error != 0) {
+			device_printf(dev, "could not set tx clk parent\n");
+			return (error);
+		}
+	}
+
+	/* Enable PHY regulator if applicable */
+	if (regulator_get_by_ofw_property(dev, 0, "phy-supply", &reg) == 0) {
+		error = regulator_enable(reg);
+		if (error != 0) {
+			device_printf(dev, "could not enable PHY regulator\n");
+			return (error);
+		}
+	}
+
+	return (0);
+}
+
+static int
+a20_if_dwc_mac_type(device_t dev)
+{
+
+	return (DWC_GMAC_ALT_DESC);
+}
+
+static int
+a20_if_dwc_mii_clk(device_t dev)
+{
+
+	return (GMAC_MII_CLK_150_250M_DIV102);
+}
+
+static device_method_t a20_dwc_methods[] = {
+	DEVMETHOD(device_probe,		a20_if_dwc_probe),
+
+	DEVMETHOD(if_dwc_init,		a20_if_dwc_init),
+	DEVMETHOD(if_dwc_mac_type,	a20_if_dwc_mac_type),
+	DEVMETHOD(if_dwc_mii_clk,	a20_if_dwc_mii_clk),
+
+	DEVMETHOD_END
+};
+
+static devclass_t a20_dwc_devclass;
+
+extern driver_t dwc_driver;
+
+DEFINE_CLASS_1(dwc, a20_dwc_driver, a20_dwc_methods, sizeof(struct dwc_softc),
+    dwc_driver);
+DRIVER_MODULE(a20_dwc, simplebus, a20_dwc_driver, a20_dwc_devclass, 0, 0);
+
+MODULE_DEPEND(a20_dwc, dwc, 1, 1, 1);


Property changes on: trunk/sys/arm/allwinner/aw_if_dwc.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_machdep.c
===================================================================
--- trunk/sys/arm/allwinner/aw_machdep.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_machdep.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,272 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold at freebsd.org>
+ * Copyright (c) 2015-2016 Emmanuel Vadot <manu at freebsd.org>
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 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 AUTHOR 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.
+ *
+
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/ti/ti_machdep.c
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_machdep.c 331893 2018-04-02 23:19:07Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/devmap.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/machdep.h>
+#include <machine/platformvar.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#include <arm/allwinner/aw_mp.h>
+#include <arm/allwinner/aw_wdog.h>
+#include <arm/allwinner/aw_machdep.h>
+
+#include "platform_if.h"
+
+static u_int soc_type;
+static u_int soc_family;
+
+static int
+a10_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_A10;
+	soc_family = ALLWINNERSOC_SUN4I;
+	return (0);
+}
+
+static int
+a13_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_A13;
+	soc_family = ALLWINNERSOC_SUN5I;
+	return (0);
+}
+
+static int
+a20_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_A20;
+	soc_family = ALLWINNERSOC_SUN7I;
+
+	return (0);
+}
+
+static int
+a31_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_A31;
+	soc_family = ALLWINNERSOC_SUN6I;
+
+	return (0);
+}
+
+static int
+a31s_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_A31S;
+	soc_family = ALLWINNERSOC_SUN6I;
+
+	return (0);
+}
+
+static int
+a83t_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_A83T;
+	soc_family = ALLWINNERSOC_SUN8I;
+
+	return (0);
+}
+
+static int
+h3_attach(platform_t plat)
+{
+	soc_type = ALLWINNERSOC_H3;
+	soc_family = ALLWINNERSOC_SUN8I;
+
+	return (0);
+}
+
+static vm_offset_t
+allwinner_lastaddr(platform_t plat)
+{
+
+	return (devmap_lastaddr());
+}
+
+/*
+ * Set up static device mappings.
+ *
+ * This covers all the on-chip device with 1MB section mappings, which is good
+ * for performance (uses fewer TLB entries for device access).
+ *
+ * XXX It also covers a block of SRAM and some GPU (mali400) stuff that maybe
+ * shouldn't be device-mapped.  The original code mapped a 4MB block, but
+ * perhaps a 1MB block would be more appropriate.
+ */
+static int
+allwinner_devmap_init(platform_t plat)
+{
+
+	devmap_add_entry(0x01C00000, 0x00400000); /* 4MB */
+
+	return (0);
+}
+
+static void
+allwinner_cpu_reset(platform_t plat)
+{
+	aw_wdog_watchdog_reset();
+	printf("Reset failed!\n");
+	while (1);
+}
+
+#if defined(SOC_ALLWINNER_A10)
+static platform_method_t a10_methods[] = {
+	PLATFORMMETHOD(platform_attach,         a10_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(a10, "a10", 0, "allwinner,sun4i-a10", 200);
+#endif
+
+#if defined(SOC_ALLWINNER_A13)
+static platform_method_t a13_methods[] = {
+	PLATFORMMETHOD(platform_attach,         a13_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(a13, "a13", 0, "allwinner,sun5i-a13", 200);
+#endif
+
+#if defined(SOC_ALLWINNER_A20)
+static platform_method_t a20_methods[] = {
+	PLATFORMMETHOD(platform_attach,         a20_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+#ifdef SMP
+	PLATFORMMETHOD(platform_mp_start_ap,	aw_mp_start_ap),
+	PLATFORMMETHOD(platform_mp_setmaxid,	aw_mp_setmaxid),
+#endif
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(a20, "a20", 0, "allwinner,sun7i-a20", 200);
+#endif
+
+#if defined(SOC_ALLWINNER_A31)
+static platform_method_t a31_methods[] = {
+	PLATFORMMETHOD(platform_attach,         a31_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+#ifdef SMP
+	PLATFORMMETHOD(platform_mp_start_ap,	aw_mp_start_ap),
+	PLATFORMMETHOD(platform_mp_setmaxid,	aw_mp_setmaxid),
+#endif
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(a31, "a31", 0, "allwinner,sun6i-a31", 200);
+#endif
+
+#if defined(SOC_ALLWINNER_A31S)
+static platform_method_t a31s_methods[] = {
+	PLATFORMMETHOD(platform_attach,         a31s_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+#ifdef SMP
+	PLATFORMMETHOD(platform_mp_start_ap,	aw_mp_start_ap),
+	PLATFORMMETHOD(platform_mp_setmaxid,	aw_mp_setmaxid),
+#endif
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(a31s, "a31s", 0, "allwinner,sun6i-a31s", 200);
+#endif
+
+#if defined(SOC_ALLWINNER_A83T)
+static platform_method_t a83t_methods[] = {
+	PLATFORMMETHOD(platform_attach,         a83t_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+#ifdef SMP
+	PLATFORMMETHOD(platform_mp_start_ap,	a83t_mp_start_ap),
+	PLATFORMMETHOD(platform_mp_setmaxid,	aw_mp_setmaxid),
+#endif
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(a83t, "a83t", 0, "allwinner,sun8i-a83t", 200);
+#endif
+
+#if defined(SOC_ALLWINNER_H3)
+static platform_method_t h3_methods[] = {
+	PLATFORMMETHOD(platform_attach,         h3_attach),
+	PLATFORMMETHOD(platform_lastaddr,       allwinner_lastaddr),
+	PLATFORMMETHOD(platform_devmap_init,    allwinner_devmap_init),
+	PLATFORMMETHOD(platform_cpu_reset,	allwinner_cpu_reset),
+
+#ifdef SMP
+	PLATFORMMETHOD(platform_mp_start_ap,	aw_mp_start_ap),
+	PLATFORMMETHOD(platform_mp_setmaxid,	aw_mp_setmaxid),
+#endif
+	PLATFORMMETHOD_END,
+};
+FDT_PLATFORM_DEF(h3, "h3", 0, "allwinner,sun8i-h3", 200);
+#endif
+
+u_int
+allwinner_soc_type(void)
+{
+	return (soc_type);
+}
+
+u_int
+allwinner_soc_family(void)
+{
+	return (soc_family);
+}


Property changes on: trunk/sys/arm/allwinner/aw_machdep.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_machdep.h
===================================================================
--- trunk/sys/arm/allwinner/aw_machdep.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_machdep.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,52 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_machdep.h 308274 2016-11-04 00:54:21Z manu $
+ *
+ */
+
+#ifndef AW_MACHDEP_H
+#define	AW_MACHDEP_H
+
+#define	ALLWINNERSOC_A10	0x10000000
+#define	ALLWINNERSOC_A13	0x13000000
+#define	ALLWINNERSOC_A10S	0x10000001
+#define	ALLWINNERSOC_A20	0x20000000
+#define	ALLWINNERSOC_H3		0x30000000
+#define	ALLWINNERSOC_A31	0x31000000
+#define	ALLWINNERSOC_A31S	0x31000001
+#define	ALLWINNERSOC_A83T	0x83000000
+
+#define	ALLWINNERSOC_SUN4I	0x40000000
+#define	ALLWINNERSOC_SUN5I	0x50000000
+#define	ALLWINNERSOC_SUN6I	0x60000000
+#define	ALLWINNERSOC_SUN7I	0x70000000
+#define	ALLWINNERSOC_SUN8I	0x80000000
+
+u_int allwinner_soc_type(void);
+u_int allwinner_soc_family(void);
+
+#endif /* AW_MACHDEP_H */


Property changes on: trunk/sys/arm/allwinner/aw_machdep.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_mp.c
===================================================================
--- trunk/sys/arm/allwinner/aw_mp.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_mp.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,289 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold at freebsd.org>
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_mp.c 331182 2018-03-19 06:40:11Z eadler $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/cpu.h>
+#include <machine/cpu-v6.h>
+#include <machine/smp.h>
+#include <machine/fdt.h>
+#include <machine/intr.h>
+#include <machine/platformvar.h>
+
+#include <arm/allwinner/aw_mp.h>
+#include <arm/allwinner/aw_machdep.h>
+
+/* Register for all dual-core SoC */
+#define	A20_CPUCFG_BASE		0x01c25c00
+/* Register for all quad-core SoC */
+#define	CPUCFG_BASE		0x01f01c00
+#define	CPUCFG_SIZE		0x400
+#define	PRCM_BASE		0x01f01400
+#define	PRCM_SIZE		0x800
+/* Register for multi-cluster SoC */
+#define	CPUXCFG_BASE		0x01700000
+#define	CPUXCFG_SIZE		0x400
+
+#define	CPU_OFFSET		0x40
+#define	CPU_OFFSET_CTL		0x04
+#define	CPU_OFFSET_STATUS	0x08
+#define	CPU_RST_CTL(cpuid)	((cpuid + 1) * CPU_OFFSET)
+#define	CPU_CTL(cpuid)		(((cpuid + 1) * CPU_OFFSET) + CPU_OFFSET_CTL)
+#define	CPU_STATUS(cpuid)	(((cpuid + 1) * CPU_OFFSET) + CPU_OFFSET_STATUS)
+
+#define	CPU_RESET		(1 << 0)
+#define	CPU_CORE_RESET		(1 << 1)
+
+#define	CPUCFG_GENCTL		0x184
+#define	CPUCFG_P_REG0		0x1a4
+
+#define	A20_CPU1_PWR_CLAMP	0x1b0
+#define	CPU_PWR_CLAMP_REG	0x140
+#define	CPU_PWR_CLAMP(cpu)	((cpu * 4) + CPU_PWR_CLAMP_REG)
+#define	CPU_PWR_CLAMP_STEPS	8
+
+#define	A20_CPU1_PWROFF_REG	0x1b4
+#define	CPU_PWROFF		0x100
+
+#define	CPUCFG_DBGCTL0		0x1e0
+#define	CPUCFG_DBGCTL1		0x1e4
+
+#define	CPUS_CL_RST(cl)		(0x30 + (cluster) * 0x4)
+#define	CPUX_CL_CTRL0(cl)	(0x0 + (cluster) * 0x10)
+#define	CPUX_CL_CTRL1(cl)	(0x4 + (cluster) * 0x10)
+#define	CPUX_CL_CPU_STATUS(cl)	(0x30 + (cluster) * 0x4)
+#define	CPUX_CL_RST(cl)		(0x80 + (cluster) * 0x4)
+#define	PRCM_CL_PWROFF(cl)	(0x100 + (cluster) * 0x4)
+#define	PRCM_CL_PWR_CLAMP(cl, cpu)	(0x140 + (cluster) * 0x4 + (cpu) * 0x4)
+
+void
+aw_mp_setmaxid(platform_t plat)
+{
+	int ncpu;
+	uint32_t reg;
+
+	if (mp_ncpus != 0)
+		return;
+
+	reg = cp15_l2ctlr_get();
+	ncpu = CPUV7_L2CTLR_NPROC(reg);
+
+	mp_ncpus = ncpu;
+	mp_maxid = ncpu - 1;
+}
+
+void
+aw_mp_start_ap(platform_t plat)
+{
+	bus_space_handle_t cpucfg;
+	bus_space_handle_t prcm;
+	int i, j, soc_family;
+	uint32_t val;
+
+	soc_family = allwinner_soc_family();
+	if (soc_family == ALLWINNERSOC_SUN7I) {
+		if (bus_space_map(fdtbus_bs_tag, A20_CPUCFG_BASE, CPUCFG_SIZE,
+		    0, &cpucfg) != 0)
+			panic("Couldn't map the CPUCFG\n");
+	} else {
+		if (bus_space_map(fdtbus_bs_tag, CPUCFG_BASE, CPUCFG_SIZE,
+		    0, &cpucfg) != 0)
+			panic("Couldn't map the CPUCFG\n");
+		if (bus_space_map(fdtbus_bs_tag, PRCM_BASE, PRCM_SIZE, 0,
+		    &prcm) != 0)
+			panic("Couldn't map the PRCM\n");
+	}
+
+	dcache_wbinv_poc_all();
+
+	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_P_REG0,
+	    pmap_kextract((vm_offset_t)mpentry));
+
+	/*
+	 * Assert nCOREPORESET low and set L1RSTDISABLE low.
+	 * Ensure DBGPWRDUP is set to LOW to prevent any external
+	 * debug access to the processor.
+	 */
+	for (i = 1; i < mp_ncpus; i++)
+		bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU_RST_CTL(i), 0);
+
+	/* Set L1RSTDISABLE low */
+	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_GENCTL);
+	for (i = 1; i < mp_ncpus; i++)
+		val &= ~(1 << i);
+	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_GENCTL, val);
+
+	/* Set DBGPWRDUP low */
+	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1);
+	for (i = 1; i < mp_ncpus; i++)
+		val &= ~(1 << i);
+	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1, val);
+
+	/* Release power clamp */
+	for (i = 1; i < mp_ncpus; i++)
+		for (j = 0; j <= CPU_PWR_CLAMP_STEPS; j++) {
+			if (soc_family != ALLWINNERSOC_SUN7I) {
+				bus_space_write_4(fdtbus_bs_tag, prcm,
+				    CPU_PWR_CLAMP(i), 0xff >> j);
+			} else {
+				bus_space_write_4(fdtbus_bs_tag,
+				    cpucfg, A20_CPU1_PWR_CLAMP, 0xff >> j);
+			}
+		}
+	DELAY(10000);
+
+	/* Clear power-off gating */
+	if (soc_family != ALLWINNERSOC_SUN7I) {
+		val = bus_space_read_4(fdtbus_bs_tag, prcm, CPU_PWROFF);
+		for (i = 0; i < mp_ncpus; i++)
+			val &= ~(1 << i);
+		bus_space_write_4(fdtbus_bs_tag, prcm, CPU_PWROFF, val);
+	} else {
+		val = bus_space_read_4(fdtbus_bs_tag,
+		    cpucfg, A20_CPU1_PWROFF_REG);
+		val &= ~(1 << 0);
+		bus_space_write_4(fdtbus_bs_tag, cpucfg,
+		    A20_CPU1_PWROFF_REG, val);
+	}
+	DELAY(1000);
+
+	/* De-assert cpu core reset */
+	for (i = 1; i < mp_ncpus; i++)
+		bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU_RST_CTL(i),
+		    CPU_RESET | CPU_CORE_RESET);
+
+	/* Assert DBGPWRDUP signal */
+	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1);
+	for (i = 1; i < mp_ncpus; i++)
+		val |= (1 << i);
+	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1, val);
+
+	dsb();
+	sev();
+	bus_space_unmap(fdtbus_bs_tag, cpucfg, CPUCFG_SIZE);
+	if (soc_family != ALLWINNERSOC_SUN7I)
+		bus_space_unmap(fdtbus_bs_tag, prcm, PRCM_SIZE);
+}
+
+static void
+aw_mc_mp_start_cpu(bus_space_handle_t cpuscfg, bus_space_handle_t cpuxcfg,
+    bus_space_handle_t prcm, int cluster, int cpu)
+{
+	uint32_t val;
+	int i;
+
+	/* Assert core reset */
+	val = bus_space_read_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster));
+	val &= ~(1 << cpu);
+	bus_space_write_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster), val);
+
+	/* Assert power-on reset */
+	val = bus_space_read_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster));
+	val &= ~(1 << cpu);
+	bus_space_write_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster), val);
+
+	/* Disable automatic L1 cache invalidate at reset */
+	val = bus_space_read_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_CTRL0(cluster));
+	val &= ~(1 << cpu);
+	bus_space_write_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_CTRL0(cluster), val);
+
+	/* Release power clamp */
+	for (i = 0; i <= CPU_PWR_CLAMP_STEPS; i++)
+		bus_space_write_4(fdtbus_bs_tag, prcm,
+		    PRCM_CL_PWR_CLAMP(cluster, cpu), 0xff >> i);
+	while (bus_space_read_4(fdtbus_bs_tag, prcm,
+	    PRCM_CL_PWR_CLAMP(cluster, cpu)) != 0)
+		;
+
+	/* Clear power-off gating */
+	val = bus_space_read_4(fdtbus_bs_tag, prcm, PRCM_CL_PWROFF(cluster));
+	val &= ~(1 << cpu);
+	bus_space_write_4(fdtbus_bs_tag, prcm, PRCM_CL_PWROFF(cluster), val);
+
+	/* De-assert power-on reset */
+	val = bus_space_read_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster));
+	val |= (1 << cpu);
+	bus_space_write_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster), val);
+
+	/* De-assert core reset */
+	val = bus_space_read_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster));
+	val |= (1 << cpu);
+	bus_space_write_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster), val);
+}
+
+static void
+aw_mc_mp_start_ap(bus_space_handle_t cpuscfg, bus_space_handle_t cpuxcfg,
+    bus_space_handle_t prcm)
+{
+	int cluster, cpu;
+
+	KASSERT(mp_ncpus <= 4, ("multiple clusters not yet supported"));
+
+	dcache_wbinv_poc_all();
+
+	bus_space_write_4(fdtbus_bs_tag, cpuscfg, CPUCFG_P_REG0,
+	    pmap_kextract((vm_offset_t)mpentry));
+
+	cluster = 0;
+	for (cpu = 1; cpu < mp_ncpus; cpu++)
+		aw_mc_mp_start_cpu(cpuscfg, cpuxcfg, prcm, cluster, cpu);
+}
+
+void
+a83t_mp_start_ap(platform_t plat)
+{
+	bus_space_handle_t cpuscfg, cpuxcfg, prcm;
+
+	if (bus_space_map(fdtbus_bs_tag, CPUCFG_BASE, CPUCFG_SIZE,
+	    0, &cpuscfg) != 0)
+		panic("Couldn't map the CPUCFG\n");
+	if (bus_space_map(fdtbus_bs_tag, CPUXCFG_BASE, CPUXCFG_SIZE,
+	    0, &cpuxcfg) != 0)
+		panic("Couldn't map the CPUXCFG\n");
+	if (bus_space_map(fdtbus_bs_tag, PRCM_BASE, PRCM_SIZE, 0,
+	    &prcm) != 0)
+		panic("Couldn't map the PRCM\n");
+
+	aw_mc_mp_start_ap(cpuscfg, cpuxcfg, prcm);
+	dsb();
+	sev();
+	bus_space_unmap(fdtbus_bs_tag, cpuxcfg, CPUXCFG_SIZE);
+	bus_space_unmap(fdtbus_bs_tag, cpuscfg, CPUCFG_SIZE);
+	bus_space_unmap(fdtbus_bs_tag, prcm, PRCM_SIZE);
+}


Property changes on: trunk/sys/arm/allwinner/aw_mp.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_mp.h
===================================================================
--- trunk/sys/arm/allwinner/aw_mp.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_mp.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,36 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_mp.h 331182 2018-03-19 06:40:11Z eadler $
+ */
+
+#ifndef _AW_MP_H_
+#define	_AW_MP_H_
+
+void aw_mp_setmaxid(platform_t plat);
+void aw_mp_start_ap(platform_t plat);
+void a83t_mp_start_ap(platform_t plat);
+
+#endif /* _AW_MP_H_ */


Property changes on: trunk/sys/arm/allwinner/aw_mp.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_nmi.c
===================================================================
--- trunk/sys/arm/allwinner/aw_nmi.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_nmi.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,405 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_nmi.c 309765 2016-12-09 20:48:47Z manu $");
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "pic_if.h"
+
+#define	NMI_IRQ_CTRL_REG	0x0
+#define	 NMI_IRQ_LOW_LEVEL	0x0
+#define	 NMI_IRQ_LOW_EDGE	0x1
+#define	 NMI_IRQ_HIGH_LEVEL	0x2
+#define	 NMI_IRQ_HIGH_EDGE	0x3
+#define	NMI_IRQ_PENDING_REG	0x4
+#define	 NMI_IRQ_ACK		(1U << 0)
+#define	A20_NMI_IRQ_ENABLE_REG	0x8
+#define	A31_NMI_IRQ_ENABLE_REG	0x34
+#define	 NMI_IRQ_ENABLE		(1U << 0)
+
+#define	SC_NMI_READ(_sc, _reg)		bus_read_4(_sc->res[0], _reg)
+#define	SC_NMI_WRITE(_sc, _reg, _val)	bus_write_4(_sc->res[0], _reg, _val)
+
+static struct resource_spec aw_nmi_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1,			0,	0 }
+};
+
+struct aw_nmi_intr {
+	struct intr_irqsrc	isrc;
+	u_int			irq;
+	enum intr_polarity	pol;
+	enum intr_trigger	tri;
+};
+
+struct aw_nmi_softc {
+	device_t		dev;
+	struct resource *	res[2];
+	void *			intrcookie;
+	struct aw_nmi_intr	intr;
+	uint8_t			enable_reg;
+};
+
+#define	A20_NMI	1
+#define	A31_NMI	2
+
+static struct ofw_compat_data compat_data[] = {
+	{"allwinner,sun7i-a20-sc-nmi", A20_NMI},
+	{"allwinner,sun6i-a31-sc-nmi", A31_NMI},
+
+	{NULL, 0},
+};
+
+static int
+aw_nmi_intr(void *arg)
+{
+	struct aw_nmi_softc *sc;
+
+	sc = arg;
+
+	if (SC_NMI_READ(sc, NMI_IRQ_PENDING_REG) == 0) {
+		device_printf(sc->dev, "Spurious interrupt\n");
+		return (FILTER_HANDLED);
+	}
+
+	if (intr_isrc_dispatch(&sc->intr.isrc, curthread->td_intr_frame) != 0) {
+		SC_NMI_WRITE(sc, sc->enable_reg, !NMI_IRQ_ENABLE);
+		device_printf(sc->dev, "Stray interrupt, NMI disabled\n");
+	}
+
+	return (FILTER_HANDLED);
+}
+
+static void
+aw_nmi_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct aw_nmi_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	SC_NMI_WRITE(sc, sc->enable_reg, NMI_IRQ_ENABLE);
+}
+
+static void
+aw_nmi_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct aw_nmi_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	SC_NMI_WRITE(sc, sc->enable_reg, !NMI_IRQ_ENABLE);
+}
+
+static int
+aw_nmi_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp,
+    enum intr_polarity *polp, enum intr_trigger *trigp)
+{
+	u_int irq, tripol;
+	enum intr_polarity pol;
+	enum intr_trigger trig;
+
+	if (ncells != 2) {
+		device_printf(dev, "Invalid #interrupt-cells\n");
+		return (EINVAL);
+	}
+
+	irq = cells[0];
+	if (irq != 0) {
+		device_printf(dev, "Controller only support irq 0\n");
+		return (EINVAL);
+	}
+
+	tripol = cells[1];
+
+	switch (tripol) {
+	case IRQ_TYPE_EDGE_RISING:
+		trig = INTR_TRIGGER_EDGE;
+		pol  = INTR_POLARITY_HIGH;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		trig = INTR_TRIGGER_EDGE;
+		pol  = INTR_POLARITY_LOW;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		trig = INTR_TRIGGER_LEVEL;
+		pol  = INTR_POLARITY_HIGH;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		trig = INTR_TRIGGER_LEVEL;
+		pol  = INTR_POLARITY_LOW;
+		break;
+	default:
+		device_printf(dev, "unsupported trigger/polarity 0x%2x\n",
+		    tripol);
+		return (ENOTSUP);
+	}
+
+	*irqp = irq;
+	if (polp != NULL)
+		*polp = pol;
+	if (trigp != NULL)
+		*trigp = trig;
+	return (0);
+}
+
+static int
+aw_nmi_map_intr(device_t dev, struct intr_map_data *data,
+    struct intr_irqsrc **isrcp)
+{
+	struct intr_map_data_fdt *daf;
+	struct aw_nmi_softc *sc;
+	int error;
+	u_int irq;
+
+	if (data->type != INTR_MAP_DATA_FDT)
+		return (ENOTSUP);
+
+	sc = device_get_softc(dev);
+	daf = (struct intr_map_data_fdt *)data;
+
+	error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, NULL, NULL);
+	if (error == 0)
+		*isrcp = &sc->intr.isrc;
+
+	return (error);
+}
+
+static int
+aw_nmi_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct intr_map_data_fdt *daf;
+	struct aw_nmi_softc *sc;
+	struct aw_nmi_intr *nmi_intr;
+	int error, icfg;
+	u_int irq;
+	enum intr_trigger trig;
+	enum intr_polarity pol;
+
+	/* Get config for interrupt. */
+	if (data == NULL || data->type != INTR_MAP_DATA_FDT)
+		return (ENOTSUP);
+
+	sc = device_get_softc(dev);
+	nmi_intr = (struct aw_nmi_intr *)isrc;
+	daf = (struct intr_map_data_fdt *)data;
+
+	error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, &trig);
+	if (error != 0)
+		return (error);
+	if (nmi_intr->irq != irq)
+		return (EINVAL);
+
+	/* Compare config if this is not first setup. */
+	if (isrc->isrc_handlers != 0) {
+		if (pol != nmi_intr->pol || trig != nmi_intr->tri)
+			return (EINVAL);
+		else
+			return (0);
+	}
+
+	nmi_intr->pol = pol;
+	nmi_intr->tri = trig;
+
+	if (trig == INTR_TRIGGER_LEVEL) {
+		if (pol == INTR_POLARITY_LOW)
+			icfg = NMI_IRQ_LOW_LEVEL;
+		else
+			icfg = NMI_IRQ_HIGH_LEVEL;
+	} else {
+		if (pol == INTR_POLARITY_HIGH)
+			icfg = NMI_IRQ_HIGH_EDGE;
+		else
+			icfg = NMI_IRQ_LOW_EDGE;
+	}
+
+	SC_NMI_WRITE(sc, NMI_IRQ_CTRL_REG, icfg);
+
+	return (0);
+}
+
+static int
+aw_nmi_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct aw_nmi_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (isrc->isrc_handlers == 0) {
+		sc->intr.pol = INTR_POLARITY_CONFORM;
+		sc->intr.tri = INTR_TRIGGER_CONFORM;
+
+		SC_NMI_WRITE(sc, sc->enable_reg, !NMI_IRQ_ENABLE);
+	}
+
+	return (0);
+}
+
+static void
+aw_nmi_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct aw_nmi_softc *sc;
+
+	sc = device_get_softc(dev);
+	aw_nmi_disable_intr(dev, isrc);
+	SC_NMI_WRITE(sc, NMI_IRQ_PENDING_REG, NMI_IRQ_ACK);
+}
+
+static void
+aw_nmi_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+	arm_irq_memory_barrier(0);
+	aw_nmi_enable_intr(dev, isrc);
+}
+
+static void
+aw_nmi_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct aw_nmi_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	arm_irq_memory_barrier(0);
+	SC_NMI_WRITE(sc, NMI_IRQ_PENDING_REG, NMI_IRQ_ACK);
+}
+
+static int
+aw_nmi_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+	device_set_desc(dev, "Allwinner NMI Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_nmi_attach(device_t dev)
+{
+	struct aw_nmi_softc *sc;
+	phandle_t xref;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, aw_nmi_res_spec, sc->res) != 0) {
+		device_printf(dev, "can't allocate device resources\n");
+		return (ENXIO);
+	}
+	if ((bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC,
+	    aw_nmi_intr, NULL, sc, &sc->intrcookie))) {
+		device_printf(dev, "unable to register interrupt handler\n");
+		bus_release_resources(dev, aw_nmi_res_spec, sc->res);
+		return (ENXIO);
+	}
+
+	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
+	case A20_NMI:
+		sc->enable_reg = A20_NMI_IRQ_ENABLE_REG;
+		break;
+	case A31_NMI:
+		sc->enable_reg = A31_NMI_IRQ_ENABLE_REG;
+		break;
+	}
+
+	/* Disable and clear interrupts */
+	SC_NMI_WRITE(sc, sc->enable_reg, !NMI_IRQ_ENABLE);
+	SC_NMI_WRITE(sc, NMI_IRQ_PENDING_REG, NMI_IRQ_ACK);
+
+	xref = OF_xref_from_node(ofw_bus_get_node(dev));
+	/* Register our isrc */
+	sc->intr.irq = 0;
+	sc->intr.pol = INTR_POLARITY_CONFORM;
+	sc->intr.tri = INTR_TRIGGER_CONFORM;
+	if (intr_isrc_register(&sc->intr.isrc, sc->dev, 0, "%s,%u",
+	      device_get_nameunit(sc->dev), sc->intr.irq) != 0)
+		goto error;
+
+	if (intr_pic_register(dev, (intptr_t)xref) == NULL) {
+		device_printf(dev, "could not register pic\n");
+		goto error;
+	}
+	return (0);
+
+error:
+	bus_teardown_intr(dev, sc->res[1], sc->intrcookie);
+	bus_release_resources(dev, aw_nmi_res_spec, sc->res);
+	return (ENXIO);
+}
+
+static device_method_t aw_nmi_methods[] = {
+	DEVMETHOD(device_probe,		aw_nmi_probe),
+	DEVMETHOD(device_attach,	aw_nmi_attach),
+
+	/* Interrupt controller interface */
+	DEVMETHOD(pic_disable_intr,	aw_nmi_disable_intr),
+	DEVMETHOD(pic_enable_intr,	aw_nmi_enable_intr),
+	DEVMETHOD(pic_map_intr,		aw_nmi_map_intr),
+	DEVMETHOD(pic_setup_intr,	aw_nmi_setup_intr),
+	DEVMETHOD(pic_teardown_intr,	aw_nmi_teardown_intr),
+	DEVMETHOD(pic_post_filter,	aw_nmi_post_filter),
+	DEVMETHOD(pic_post_ithread,	aw_nmi_post_ithread),
+	DEVMETHOD(pic_pre_ithread,	aw_nmi_pre_ithread),
+
+	{0, 0},
+};
+
+static driver_t aw_nmi_driver = {
+	"aw_nmi",
+	aw_nmi_methods,
+	sizeof(struct aw_nmi_softc),
+};
+
+static devclass_t aw_nmi_devclass;
+
+EARLY_DRIVER_MODULE(aw_nmi, simplebus, aw_nmi_driver,
+    aw_nmi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);


Property changes on: trunk/sys/arm/allwinner/aw_nmi.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_reset.c
===================================================================
--- trunk/sys/arm/allwinner/aw_reset.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_reset.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,165 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_reset.c 297725 2016-04-08 23:07:16Z jmcneill $
+ */
+
+/*
+ * Allwinner module software reset registers
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_reset.c 297725 2016-04-08 23:07:16Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "hwreset_if.h"
+
+#define	RESET_OFFSET(index)	((index / 32) * 4)
+#define	RESET_SHIFT(index)	(index % 32)
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun6i-a31-ahb1-reset",	1 },
+	{ "allwinner,sun6i-a31-clock-reset",	1 },
+	{ NULL,					0 }
+};
+
+struct aw_reset_softc {
+	struct resource		*res;
+	struct mtx		mtx;
+};
+
+static struct resource_spec aw_reset_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	RESET_READ(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	RESET_WRITE(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static int
+aw_reset_assert(device_t dev, intptr_t id, bool reset)
+{
+	struct aw_reset_softc *sc;
+	uint32_t reg_value;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mtx);
+	reg_value = RESET_READ(sc, RESET_OFFSET(id));
+	if (reset)
+		reg_value &= ~(1 << RESET_SHIFT(id));
+	else
+		reg_value |= (1 << RESET_SHIFT(id));
+	RESET_WRITE(sc, RESET_OFFSET(id), reg_value);
+	mtx_unlock(&sc->mtx);
+
+	return (0);
+}
+
+static int
+aw_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
+{
+	struct aw_reset_softc *sc;
+	uint32_t reg_value;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mtx);
+	reg_value = RESET_READ(sc, RESET_OFFSET(id));
+	mtx_unlock(&sc->mtx);
+
+	*reset = (reg_value & (1 << RESET_SHIFT(id))) != 0 ? false : true;
+
+	return (0);
+}
+
+static int
+aw_reset_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Module Resets");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_reset_attach(device_t dev)
+{
+	struct aw_reset_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (bus_alloc_resources(dev, aw_reset_spec, &sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+	hwreset_register_ofw_provider(dev);
+
+	return (0);
+}
+
+static device_method_t aw_reset_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_reset_probe),
+	DEVMETHOD(device_attach,	aw_reset_attach),
+
+	/* Reset interface */
+	DEVMETHOD(hwreset_assert,	aw_reset_assert),
+	DEVMETHOD(hwreset_is_asserted,	aw_reset_is_asserted),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_reset_driver = {
+	"aw_reset",
+	aw_reset_methods,
+	sizeof(struct aw_reset_softc),
+};
+
+static devclass_t aw_reset_devclass;
+
+EARLY_DRIVER_MODULE(aw_reset, simplebus, aw_reset_driver, aw_reset_devclass,
+    0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(aw_reset, 1);


Property changes on: trunk/sys/arm/allwinner/aw_reset.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_rsb.c
===================================================================
--- trunk/sys/arm/allwinner/aw_rsb.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_rsb.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,480 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_rsb.c 309763 2016-12-09 20:37:34Z manu $
+ */
+
+/*
+ * Allwinner RSB (Reduced Serial Bus)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_rsb.c 309763 2016-12-09 20:37:34Z manu $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "iicbus_if.h"
+
+#define	RSB_CTRL		0x00
+#define	 START_TRANS		(1 << 7)
+#define	 GLOBAL_INT_ENB		(1 << 1)
+#define	 SOFT_RESET		(1 << 0)
+#define	RSB_CCR		0x04
+#define	RSB_INTE		0x08
+#define	RSB_INTS		0x0c
+#define	 INT_TRANS_ERR_ID(x)	(((x) >> 8) & 0xf)
+#define	 INT_LOAD_BSY		(1 << 2)
+#define	 INT_TRANS_ERR		(1 << 1)
+#define	 INT_TRANS_OVER		(1 << 0)
+#define	 INT_MASK		(INT_LOAD_BSY|INT_TRANS_ERR|INT_TRANS_OVER)
+#define	RSB_DADDR0		0x10
+#define	RSB_DADDR1		0x14
+#define	RSB_DLEN		0x18
+#define	 DLEN_READ		(1 << 4)
+#define	RSB_DATA0		0x1c
+#define	RSB_DATA1		0x20
+#define	RSB_CMD			0x2c
+#define	 CMD_SRTA		0xe8
+#define	 CMD_RD8		0x8b
+#define	 CMD_RD16		0x9c
+#define	 CMD_RD32		0xa6
+#define	 CMD_WR8		0x4e
+#define	 CMD_WR16		0x59
+#define	 CMD_WR32		0x63
+#define	RSB_DAR			0x30
+#define	 DAR_RTA		(0xff << 16)
+#define	 DAR_RTA_SHIFT		16
+#define	 DAR_DA			(0xffff << 0)
+#define	 DAR_DA_SHIFT		0
+
+#define	RSB_MAXLEN		8
+#define	RSB_RESET_RETRY		100
+#define	RSB_I2C_TIMEOUT		hz
+
+#define	RSB_ADDR_PMIC_PRIMARY	0x3a3
+#define	RSB_ADDR_PMIC_SECONDARY	0x745
+#define	RSB_ADDR_PERIPH_IC	0xe89
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun8i-a23-rsb",		1 },
+	{ NULL,					0 }
+};
+
+static struct resource_spec rsb_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+/*
+ * Device address to Run-time address mappings.
+ *
+ * Run-time address (RTA) is an 8-bit value used to address the device during
+ * a read or write transaction. The following are valid RTAs:
+ *  0x17 0x2d 0x3a 0x4e 0x59 0x63 0x74 0x8b 0x9c 0xa6 0xb1 0xc5 0xd2 0xe8 0xff
+ *
+ * Allwinner uses RTA 0x2d for the primary PMIC, 0x3a for the secondary PMIC,
+ * and 0x4e for the peripheral IC (where applicable).
+ */
+static const struct {
+	uint16_t	addr;
+	uint8_t		rta;
+} rsb_rtamap[] = {
+	{ .addr = RSB_ADDR_PMIC_PRIMARY,	.rta = 0x2d },
+	{ .addr = RSB_ADDR_PMIC_SECONDARY,	.rta = 0x3a },
+	{ .addr = RSB_ADDR_PERIPH_IC,		.rta = 0x4e },
+	{ .addr = 0,				.rta = 0 }
+};
+
+struct rsb_softc {
+	struct resource	*res;
+	struct mtx	mtx;
+	clk_t		clk;
+	hwreset_t	rst;
+	device_t	iicbus;
+	int		busy;
+	uint32_t	status;
+	uint16_t	cur_addr;
+
+	struct iic_msg	*msg;
+};
+
+#define	RSB_LOCK(sc)			mtx_lock(&(sc)->mtx)
+#define	RSB_UNLOCK(sc)			mtx_unlock(&(sc)->mtx)
+#define	RSB_ASSERT_LOCKED(sc)		mtx_assert(&(sc)->mtx, MA_OWNED)
+#define	RSB_READ(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	RSB_WRITE(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static phandle_t
+rsb_get_node(device_t bus, device_t dev)
+{
+	return (ofw_bus_get_node(bus));
+}
+
+static int
+rsb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+	struct rsb_softc *sc;
+	int retry;
+
+	sc = device_get_softc(dev);
+
+	RSB_LOCK(sc);
+
+	/* Write soft-reset bit and wait for it to self-clear. */
+	RSB_WRITE(sc, RSB_CTRL, SOFT_RESET);
+	for (retry = RSB_RESET_RETRY; retry > 0; retry--)
+		if ((RSB_READ(sc, RSB_CTRL) & SOFT_RESET) == 0)
+			break;
+
+	RSB_UNLOCK(sc);
+
+	if (retry == 0) {
+		device_printf(dev, "soft reset timeout\n");
+		return (ETIMEDOUT);
+	}
+
+	return (IIC_ENOADDR);
+}
+
+static uint32_t
+rsb_encode(const uint8_t *buf, u_int len, u_int off)
+{
+	uint32_t val;
+	u_int n;
+
+	val = 0;
+	for (n = off; n < MIN(len, 4 + off); n++)
+		val |= ((uint32_t)buf[n] << ((n - off) * NBBY));
+
+	return val;
+}
+
+static void
+rsb_decode(const uint32_t val, uint8_t *buf, u_int len, u_int off)
+{
+	u_int n;
+
+	for (n = off; n < MIN(len, 4 + off); n++)
+		buf[n] = (val >> ((n - off) * NBBY)) & 0xff;
+}
+
+static int
+rsb_start(device_t dev)
+{
+	struct rsb_softc *sc;
+	int error, retry;
+
+	sc = device_get_softc(dev);
+
+	RSB_ASSERT_LOCKED(sc);
+
+	/* Start the transfer */
+	RSB_WRITE(sc, RSB_CTRL, GLOBAL_INT_ENB | START_TRANS);
+
+	/* Wait for transfer to complete */
+	error = ETIMEDOUT;
+	for (retry = RSB_I2C_TIMEOUT; retry > 0; retry--) {
+		sc->status |= RSB_READ(sc, RSB_INTS);
+		if ((sc->status & INT_TRANS_OVER) != 0) {
+			error = 0;
+			break;
+		}
+		DELAY((1000 * hz) / RSB_I2C_TIMEOUT);
+	}
+	if (error == 0 && (sc->status & INT_TRANS_OVER) == 0) {
+		device_printf(dev, "transfer error, status 0x%08x\n",
+		    sc->status);
+		error = EIO;
+	}
+
+	return (error);
+
+}
+
+static int
+rsb_set_rta(device_t dev, uint16_t addr)
+{
+	struct rsb_softc *sc;
+	uint8_t rta;
+	int i;
+
+	sc = device_get_softc(dev);
+
+	RSB_ASSERT_LOCKED(sc);
+
+	/* Lookup run-time address for given device address */
+	for (rta = 0, i = 0; rsb_rtamap[i].rta != 0; i++)
+		if (rsb_rtamap[i].addr == addr) {
+			rta = rsb_rtamap[i].rta;
+			break;
+		}
+	if (rta == 0) {
+		device_printf(dev, "RTA not known for address %#x\n", addr);
+		return (ENXIO);
+	}
+
+	/* Set run-time address */
+	RSB_WRITE(sc, RSB_INTS, RSB_READ(sc, RSB_INTS));
+	RSB_WRITE(sc, RSB_DAR, (addr << DAR_DA_SHIFT) | (rta << DAR_RTA_SHIFT));
+	RSB_WRITE(sc, RSB_CMD, CMD_SRTA);
+
+	return (rsb_start(dev));
+}
+
+static int
+rsb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+	struct rsb_softc *sc;
+	uint32_t daddr[2], data[2], dlen;
+	uint16_t device_addr;
+	uint8_t cmd;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	/*
+	 * RSB is not really an I2C or SMBus controller, so there are some
+	 * restrictions imposed by the driver.
+	 *
+	 * Transfers must contain exactly two messages. The first is always
+	 * a write, containing a single data byte offset. Data will either
+	 * be read from or written to the corresponding data byte in the
+	 * second message. The slave address in both messages must be the
+	 * same.
+	 */
+	if (nmsgs != 2 || (msgs[0].flags & IIC_M_RD) == IIC_M_RD ||
+	    (msgs[0].slave >> 1) != (msgs[1].slave >> 1) ||
+	    msgs[0].len != 1 || msgs[1].len > RSB_MAXLEN)
+		return (EINVAL);
+
+	/* The controller can read or write 1, 2, or 4 bytes at a time. */
+	if ((msgs[1].flags & IIC_M_RD) != 0) {
+		switch (msgs[1].len) {
+		case 1:
+			cmd = CMD_RD8;
+			break;
+		case 2:
+			cmd = CMD_RD16;
+			break;
+		case 4:
+			cmd = CMD_RD32;
+			break;
+		default:
+			return (EINVAL);
+		}
+	} else {
+		switch (msgs[1].len) {
+		case 1:
+			cmd = CMD_WR8;
+			break;
+		case 2:
+			cmd = CMD_WR16;
+			break;
+		case 4:	
+			cmd = CMD_WR32;
+			break;
+		default:
+			return (EINVAL);
+		}
+	}
+
+	RSB_LOCK(sc);
+	while (sc->busy)
+		mtx_sleep(sc, &sc->mtx, 0, "i2cbuswait", 0);
+	sc->busy = 1;
+	sc->status = 0;
+
+	/* Select current run-time address if necessary */
+	device_addr = msgs[0].slave >> 1;
+	if (sc->cur_addr != device_addr) {
+		error = rsb_set_rta(dev, device_addr);
+		if (error != 0)
+			goto done;
+		sc->cur_addr = device_addr;
+		sc->status = 0;
+	}
+
+	/* Clear interrupt status */
+	RSB_WRITE(sc, RSB_INTS, RSB_READ(sc, RSB_INTS));
+
+	/* Program data access address registers */
+	daddr[0] = rsb_encode(msgs[0].buf, msgs[0].len, 0);
+	RSB_WRITE(sc, RSB_DADDR0, daddr[0]);
+
+	/* Write data */
+	if ((msgs[1].flags & IIC_M_RD) == 0) {
+		data[0] = rsb_encode(msgs[1].buf, msgs[1].len, 0);
+		RSB_WRITE(sc, RSB_DATA0, data[0]);
+	}
+
+	/* Set command type */
+	RSB_WRITE(sc, RSB_CMD, cmd);
+
+	/* Program data length register and transfer direction */
+	dlen = msgs[0].len - 1;
+	if ((msgs[1].flags & IIC_M_RD) == IIC_M_RD)
+		dlen |= DLEN_READ;
+	RSB_WRITE(sc, RSB_DLEN, dlen);
+
+	/* Start transfer */
+	error = rsb_start(dev);
+	if (error != 0)
+		goto done;
+
+	/* Read data */
+	if ((msgs[1].flags & IIC_M_RD) == IIC_M_RD) {
+		data[0] = RSB_READ(sc, RSB_DATA0);
+		rsb_decode(data[0], msgs[1].buf, msgs[1].len, 0);
+	}
+
+done:
+	sc->msg = NULL;
+	sc->busy = 0;
+	wakeup(sc);
+	RSB_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+rsb_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner RSB");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rsb_attach(device_t dev)
+{
+	struct rsb_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+	mtx_init(&sc->mtx, device_get_nameunit(dev), "rsb", MTX_DEF);
+
+	if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) == 0) {
+		error = clk_enable(sc->clk);
+		if (error != 0) {
+			device_printf(dev, "cannot enable clock\n");
+			goto fail;
+		}
+	}
+	if (hwreset_get_by_ofw_idx(dev, 0, 0, &sc->rst) == 0) {
+		error = hwreset_deassert(sc->rst);
+		if (error != 0) {
+			device_printf(dev, "cannot de-assert reset\n");
+			goto fail;
+		}
+	}
+
+	if (bus_alloc_resources(dev, rsb_spec, &sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	sc->iicbus = device_add_child(dev, "iicbus", -1);
+	if (sc->iicbus == NULL) {
+		device_printf(dev, "cannot add iicbus child device\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	bus_generic_attach(dev);
+
+	return (0);
+
+fail:
+	bus_release_resources(dev, rsb_spec, &sc->res);
+	if (sc->rst != NULL)
+		hwreset_release(sc->rst);
+	if (sc->clk != NULL)
+		clk_release(sc->clk);
+	mtx_destroy(&sc->mtx);
+	return (error);
+}
+
+static device_method_t rsb_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		rsb_probe),
+	DEVMETHOD(device_attach,	rsb_attach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
+	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
+	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
+	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
+	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
+
+	/* OFW methods */
+	DEVMETHOD(ofw_bus_get_node,	rsb_get_node),
+
+	/* iicbus interface */
+	DEVMETHOD(iicbus_callback,	iicbus_null_callback),
+	DEVMETHOD(iicbus_reset,		rsb_reset),
+	DEVMETHOD(iicbus_transfer,	rsb_transfer),
+
+	DEVMETHOD_END
+};
+
+static driver_t rsb_driver = {
+	"iichb",
+	rsb_methods,
+	sizeof(struct rsb_softc),
+};
+
+static devclass_t rsb_devclass;
+
+EARLY_DRIVER_MODULE(iicbus, rsb, iicbus_driver, iicbus_devclass, 0, 0,
+    BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(rsb, simplebus, rsb_driver, rsb_devclass, 0, 0,
+    BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(rsb, 1);


Property changes on: trunk/sys/arm/allwinner/aw_rsb.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_rtc.c
===================================================================
--- trunk/sys/arm/allwinner/aw_rtc.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_rtc.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,299 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Vladimir Belian <fate10 at gmail.com>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_rtc.c 309754 2016-12-09 19:40:33Z manu $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/time.h>
+#include <sys/rman.h>
+#include <sys/clock.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/aw_machdep.h>
+
+#include "clock_if.h"
+
+#define	LOSC_CTRL_REG			0x00
+#define	A10_RTC_DATE_REG		0x04
+#define	A10_RTC_TIME_REG		0x08
+#define	A31_LOSC_AUTO_SWT_STA		0x04
+#define	A31_RTC_DATE_REG		0x10
+#define	A31_RTC_TIME_REG		0x14
+
+#define	TIME_MASK			0x001f3f3f
+
+#define	LOSC_OSC_SRC			(1 << 0)
+#define	LOSC_GSM			(1 << 3)
+#define	LOSC_AUTO_SW_EN			(1 << 14)
+#define	LOSC_MAGIC			0x16aa0000
+#define	LOSC_BUSY_MASK			0x00000380
+
+#define	IS_SUN7I			(sc->type == A20_RTC)
+
+#define	YEAR_MIN			(IS_SUN7I ? 1970 : 2010)
+#define	YEAR_MAX			(IS_SUN7I ? 2100 : 2073)
+#define	YEAR_OFFSET			(IS_SUN7I ? 1900 : 2010)
+#define	YEAR_MASK			(IS_SUN7I ? 0xff : 0x3f)
+#define	LEAP_BIT			(IS_SUN7I ? 24 : 22)
+
+#define	GET_SEC_VALUE(x)		((x)  & 0x0000003f)
+#define	GET_MIN_VALUE(x)		(((x) & 0x00003f00) >> 8)
+#define	GET_HOUR_VALUE(x)		(((x) & 0x001f0000) >> 16)
+#define	GET_DAY_VALUE(x)		((x)  & 0x0000001f)
+#define	GET_MON_VALUE(x)		(((x) & 0x00000f00) >> 8)
+#define	GET_YEAR_VALUE(x)		(((x) >> 16) & YEAR_MASK)
+
+#define	SET_DAY_VALUE(x)		GET_DAY_VALUE(x)
+#define	SET_MON_VALUE(x)		(((x) & 0x0000000f) << 8)
+#define	SET_YEAR_VALUE(x)		(((x) & YEAR_MASK)  << 16)
+#define	SET_LEAP_VALUE(x)		(((x) & 0x00000001) << LEAP_BIT)
+#define	SET_SEC_VALUE(x)		GET_SEC_VALUE(x)
+#define	SET_MIN_VALUE(x)		(((x) & 0x0000003f) << 8)
+#define	SET_HOUR_VALUE(x)		(((x) & 0x0000001f) << 16)
+
+#define	HALF_OF_SEC_NS			500000000
+#define	RTC_RES_US			1000000
+#define	RTC_TIMEOUT			70
+
+#define	RTC_READ(sc, reg) 		bus_read_4((sc)->res, (reg))
+#define	RTC_WRITE(sc, reg, val)		bus_write_4((sc)->res, (reg), (val))
+
+#define	IS_LEAP_YEAR(y) \
+	(((y) % 400) == 0 || (((y) % 100) != 0 && ((y) % 4) == 0))
+
+#define	A10_RTC	1
+#define	A20_RTC	2
+#define	A31_RTC	3
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-rtc", A10_RTC },
+	{ "allwinner,sun7i-a20-rtc", A20_RTC },
+	{ "allwinner,sun6i-a31-rtc", A31_RTC },
+	{ NULL, 0 }
+};
+
+struct aw_rtc_softc {
+	struct resource		*res;
+	int			type;
+	bus_size_t		rtc_date;
+	bus_size_t		rtc_time;
+};
+
+static int aw_rtc_probe(device_t dev);
+static int aw_rtc_attach(device_t dev);
+static int aw_rtc_detach(device_t dev);
+
+static int aw_rtc_gettime(device_t dev, struct timespec *ts);
+static int aw_rtc_settime(device_t dev, struct timespec *ts);
+
+static device_method_t aw_rtc_methods[] = {
+	DEVMETHOD(device_probe,		aw_rtc_probe),
+	DEVMETHOD(device_attach,	aw_rtc_attach),
+	DEVMETHOD(device_detach,	aw_rtc_detach),
+
+	DEVMETHOD(clock_gettime,	aw_rtc_gettime),
+	DEVMETHOD(clock_settime,	aw_rtc_settime),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_rtc_driver = {
+	"rtc",
+	aw_rtc_methods,
+	sizeof(struct aw_rtc_softc),
+};
+
+static devclass_t aw_rtc_devclass;
+
+EARLY_DRIVER_MODULE(aw_rtc, simplebus, aw_rtc_driver, aw_rtc_devclass, 0, 0,
+    BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
+
+
+static int
+aw_rtc_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner RTC");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_rtc_attach(device_t dev)
+{
+	struct aw_rtc_softc *sc  = device_get_softc(dev);
+	bus_size_t rtc_losc_sta;
+	uint32_t val;
+	int rid = 0;
+
+	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!sc->res) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	switch (sc->type) {
+	case A10_RTC:
+	case A20_RTC:
+		sc->rtc_date = A10_RTC_DATE_REG;
+		sc->rtc_time = A10_RTC_TIME_REG;
+		rtc_losc_sta = LOSC_CTRL_REG;
+		break;
+	case A31_RTC:
+		sc->rtc_date = A31_RTC_DATE_REG;
+		sc->rtc_time = A31_RTC_TIME_REG;
+		rtc_losc_sta = A31_LOSC_AUTO_SWT_STA;
+		break;
+	}
+	val = RTC_READ(sc, LOSC_CTRL_REG);
+	val |= LOSC_AUTO_SW_EN;
+	val |= LOSC_MAGIC | LOSC_GSM | LOSC_OSC_SRC;
+	RTC_WRITE(sc, LOSC_CTRL_REG, val);
+
+	DELAY(100);
+
+	if (bootverbose) {
+		val = RTC_READ(sc, rtc_losc_sta);
+		if ((val & LOSC_OSC_SRC) == 0)
+			device_printf(dev, "Using internal oscillator\n");
+		else
+			device_printf(dev, "Using external oscillator\n");
+	}
+
+	clock_register(dev, RTC_RES_US);
+	
+	return (0);
+}
+
+static int
+aw_rtc_detach(device_t dev)
+{
+	/* can't support detach, since there's no clock_unregister function */
+	return (EBUSY);
+}
+
+static int
+aw_rtc_gettime(device_t dev, struct timespec *ts)
+{
+	struct aw_rtc_softc *sc  = device_get_softc(dev);
+	struct clocktime ct;
+	uint32_t rdate, rtime;
+
+	rdate = RTC_READ(sc, sc->rtc_date);
+	rtime = RTC_READ(sc, sc->rtc_time);
+	
+	if ((rtime & TIME_MASK) == 0)
+		rdate = RTC_READ(sc, sc->rtc_date);
+
+	ct.sec = GET_SEC_VALUE(rtime);
+	ct.min = GET_MIN_VALUE(rtime);
+	ct.hour = GET_HOUR_VALUE(rtime);
+	ct.day = GET_DAY_VALUE(rdate);
+	ct.mon = GET_MON_VALUE(rdate);
+	ct.year = GET_YEAR_VALUE(rdate) + YEAR_OFFSET;
+	ct.dow = -1;
+	/* RTC resolution is 1 sec */
+	ct.nsec = 0;
+	
+	return (clock_ct_to_ts(&ct, ts));
+}
+
+static int
+aw_rtc_settime(device_t dev, struct timespec *ts)
+{
+	struct aw_rtc_softc *sc  = device_get_softc(dev);
+	struct clocktime ct;
+	uint32_t clk, rdate, rtime;
+
+	/* RTC resolution is 1 sec */
+	if (ts->tv_nsec >= HALF_OF_SEC_NS)
+		ts->tv_sec++;
+	ts->tv_nsec = 0;
+
+	clock_ts_to_ct(ts, &ct);
+	
+	if ((ct.year < YEAR_MIN) || (ct.year > YEAR_MAX)) {
+		device_printf(dev, "could not set time, year out of range\n");
+		return (EINVAL);
+	}
+
+	for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) {
+		if (clk > RTC_TIMEOUT) {
+			device_printf(dev, "could not set time, RTC busy\n");
+			return (EINVAL);
+		}
+		DELAY(1);
+	}
+	/* reset time register to avoid unexpected date increment */
+	RTC_WRITE(sc, sc->rtc_time, 0);
+
+	rdate = SET_DAY_VALUE(ct.day) | SET_MON_VALUE(ct.mon) |
+		SET_YEAR_VALUE(ct.year - YEAR_OFFSET) | 
+		SET_LEAP_VALUE(IS_LEAP_YEAR(ct.year));
+			
+	rtime = SET_SEC_VALUE(ct.sec) | SET_MIN_VALUE(ct.min) |
+		SET_HOUR_VALUE(ct.hour);
+
+	for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) {
+		if (clk > RTC_TIMEOUT) {
+			device_printf(dev, "could not set date, RTC busy\n");
+			return (EINVAL);
+		}
+		DELAY(1);
+	}
+	RTC_WRITE(sc, sc->rtc_date, rdate);
+
+	for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) {
+		if (clk > RTC_TIMEOUT) {
+			device_printf(dev, "could not set time, RTC busy\n");
+			return (EINVAL);
+		}
+		DELAY(1);
+	}
+	RTC_WRITE(sc, sc->rtc_time, rtime);
+
+	DELAY(RTC_TIMEOUT);
+
+	return (0);
+}


Property changes on: trunk/sys/arm/allwinner/aw_rtc.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_sid.c
===================================================================
--- trunk/sys/arm/allwinner/aw_sid.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_sid.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,214 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_sid.c 309757 2016-12-09 20:13:31Z manu $
+ */
+
+/*
+ * Allwinner secure ID controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_sid.c 309757 2016-12-09 20:13:31Z manu $");
+
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/aw_sid.h>
+
+#define	SID_SRAM		0x200
+#define	SID_THERMAL_CALIB0	(SID_SRAM + 0x34)
+#define	SID_THERMAL_CALIB1	(SID_SRAM + 0x38)
+
+#define	A10_ROOT_KEY_OFF	0x0
+#define	A83T_ROOT_KEY_OFF	SID_SRAM
+
+#define	ROOT_KEY_SIZE		4
+
+enum sid_type {
+	A10_SID = 1,
+	A20_SID,
+	A83T_SID,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-sid",		A10_SID},
+	{ "allwinner,sun7i-a20-sid",		A20_SID},
+	{ "allwinner,sun8i-a83t-sid",		A83T_SID},
+	{ NULL,					0 }
+};
+
+struct aw_sid_softc {
+	struct resource		*res;
+	int			type;
+	bus_size_t		root_key_off;
+};
+
+static struct aw_sid_softc *aw_sid_sc;
+
+static struct resource_spec aw_sid_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+enum sid_keys {
+	AW_SID_ROOT_KEY,
+};
+
+#define	RD4(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static int aw_sid_sysctl(SYSCTL_HANDLER_ARGS);
+
+static int
+aw_sid_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Secure ID Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_sid_attach(device_t dev)
+{
+	struct aw_sid_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (bus_alloc_resources(dev, aw_sid_spec, &sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	aw_sid_sc = sc;
+
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	switch (sc->type) {
+	case A83T_SID:
+		sc->root_key_off = A83T_ROOT_KEY_OFF;
+		break;
+	default:
+		sc->root_key_off = A10_ROOT_KEY_OFF;
+		break;
+	}
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "rootkey",
+	    CTLTYPE_STRING | CTLFLAG_RD,
+	    dev, AW_SID_ROOT_KEY, aw_sid_sysctl, "A", "Root Key");
+
+	return (0);
+}
+
+int
+aw_sid_read_tscalib(uint32_t *calib0, uint32_t *calib1)
+{
+	struct aw_sid_softc *sc;
+
+	sc = aw_sid_sc;
+	if (sc == NULL)
+		return (ENXIO);
+	if (sc->type != A83T_SID)
+		return (ENXIO);
+
+	*calib0 = RD4(sc, SID_THERMAL_CALIB0);
+	*calib1 = RD4(sc, SID_THERMAL_CALIB1);
+
+	return (0);
+}
+
+int
+aw_sid_get_rootkey(u_char *out)
+{
+	struct aw_sid_softc *sc;
+	int i;
+	u_int tmp;
+
+	sc = aw_sid_sc;
+	if (sc == NULL)
+		return (ENXIO);
+
+	for (i = 0; i < ROOT_KEY_SIZE ; i++) {
+		tmp = RD4(aw_sid_sc, aw_sid_sc->root_key_off + (i * 4));
+		be32enc(&out[i * 4], tmp);
+	}
+
+	return (0);
+}
+
+static int
+aw_sid_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	enum sid_keys key = arg2;
+	u_char rootkey[16];
+	char out[33];
+
+	if (key != AW_SID_ROOT_KEY)
+		return (ENOENT);
+
+	if (aw_sid_get_rootkey(rootkey) != 0)
+		return (ENOENT);
+	snprintf(out, sizeof(out),
+	  "%16D", rootkey, "");
+
+	return sysctl_handle_string(oidp, out, sizeof(out), req);
+}
+
+static device_method_t aw_sid_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_sid_probe),
+	DEVMETHOD(device_attach,	aw_sid_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_sid_driver = {
+	"aw_sid",
+	aw_sid_methods,
+	sizeof(struct aw_sid_softc),
+};
+
+static devclass_t aw_sid_devclass;
+
+EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, aw_sid_devclass, 0, 0,
+    BUS_PASS_RESOURCE + BUS_PASS_ORDER_FIRST);
+MODULE_VERSION(aw_sid, 1);


Property changes on: trunk/sys/arm/allwinner/aw_sid.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_sid.h
===================================================================
--- trunk/sys/arm/allwinner/aw_sid.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_sid.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,36 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_sid.h 305440 2016-09-05 21:11:27Z manu $
+ */
+
+#ifndef __AW_SID_H__
+#define __AW_SID_H__
+
+int	aw_sid_read_tscalib(uint32_t *, uint32_t *);
+int	aw_sid_get_rootkey(u_char *out);
+
+#endif /* !__AW_SID_H__ */


Property changes on: trunk/sys/arm/allwinner/aw_sid.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_thermal.c
===================================================================
--- trunk/sys/arm/allwinner/aw_thermal.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_thermal.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,233 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_thermal.c 299871 2016-05-15 22:36:55Z jmcneill $
+ */
+
+/*
+ * Allwinner thermal sensor controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_thermal.c 299871 2016-05-15 22:36:55Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/aw_sid.h>
+
+#define	THS_CTRL0		0x00
+#define	THS_CTRL2		0x40
+#define	 SENSOR_ACQ1_SHIFT	16
+#define	 SENSOR2_EN		(1 << 2)
+#define	 SENSOR1_EN		(1 << 1)
+#define	 SENSOR0_EN		(1 << 0)
+#define	THS_INTC		0x44
+#define	THS_INTS		0x48
+#define	THS_FILTER		0x70
+#define	 FILTER_EN		(1 << 2)
+#define	THS_CALIB0		0x74
+#define	THS_CALIB1		0x78
+#define	THS_DATA0		0x80
+#define	THS_DATA1		0x84
+#define	THS_DATA2		0x88
+#define	 DATA_MASK		0xfff
+
+#define	TEMP_BASE		2719
+#define	TEMP_MUL		1000
+#define	TEMP_DIV		14186
+#define	TEMP_TO_K		273
+#define	ADC_ACQUIRE_TIME	(24 - 1)
+#define	SENSOR_ENABLE_ALL	(SENSOR0_EN|SENSOR1_EN|SENSOR2_EN)
+
+enum aw_thermal_sensor {
+	THS_SENSOR_CPU_CLUSTER0,
+	THS_SENSOR_CPU_CLUSTER1,
+	THS_SENSOR_GPU,
+	THS_SENSOR_END = -1
+};
+
+struct aw_thermal_sensor_config {
+	enum aw_thermal_sensor	sensor;
+	const char		*name;
+	const char		*desc;
+};
+
+static const struct aw_thermal_sensor_config a83t_sensor_config[] = {
+	{ .sensor = THS_SENSOR_CPU_CLUSTER0,
+	  .name = "cluster0",	.desc = "CPU cluster 0 temperature" },
+	{ .sensor = THS_SENSOR_CPU_CLUSTER1,
+	  .name = "cluster1",	.desc = "CPU cluster 1 temperature" },
+	{ .sensor = THS_SENSOR_GPU,
+	  .name = "gpu",	.desc = "GPU temperature" },
+	{ .sensor = THS_SENSOR_END }
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun8i-a83t-ts",	(uintptr_t)&a83t_sensor_config },
+	{ NULL,				(uintptr_t)NULL }
+};
+
+#define	THS_CONF(d)		\
+	(void *)ofw_bus_search_compatible((d), compat_data)->ocd_data
+
+struct aw_thermal_softc {
+	struct resource			*res;
+	struct aw_thermal_sensor_config	*conf;
+};
+
+static struct resource_spec aw_thermal_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	RD4(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static int
+aw_thermal_init(struct aw_thermal_softc *sc)
+{
+	uint32_t calib0, calib1;
+	int error;
+
+	/* Read calibration settings from SRAM */
+	error = aw_sid_read_tscalib(&calib0, &calib1);
+	if (error != 0)
+		return (error);
+
+	/* Write calibration settings to thermal controller */
+	WR4(sc, THS_CALIB0, calib0);
+	WR4(sc, THS_CALIB1, calib1);
+
+	/* Configure ADC acquire time (CLK_IN/(N+1)) and enable sensors */
+	WR4(sc, THS_CTRL0, ADC_ACQUIRE_TIME);
+	WR4(sc, THS_CTRL2, (ADC_ACQUIRE_TIME << SENSOR_ACQ1_SHIFT) |
+	    SENSOR_ENABLE_ALL);
+
+	/* Disable interrupts */
+	WR4(sc, THS_INTC, 0);
+	WR4(sc, THS_INTS, RD4(sc, THS_INTS));
+
+	/* Enable average filter */
+	WR4(sc, THS_FILTER, RD4(sc, THS_FILTER) | FILTER_EN);
+
+	return (0);
+}
+
+static int
+aw_thermal_gettemp(uint32_t val)
+{
+	int raw;
+
+	raw = val & DATA_MASK;
+	return (((TEMP_BASE - raw) * TEMP_MUL) / TEMP_DIV) + TEMP_TO_K;
+}
+
+static int
+aw_thermal_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct aw_thermal_softc *sc;
+	enum aw_thermal_sensor sensor;
+	int val;
+
+	sc = arg1;
+	sensor = arg2;
+
+	val = aw_thermal_gettemp(RD4(sc, THS_DATA0 + (sensor * 4)));
+
+	return sysctl_handle_opaque(oidp, &val, sizeof(val), req);
+}
+
+static int
+aw_thermal_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (THS_CONF(dev) == NULL)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Thermal Sensor Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_thermal_attach(device_t dev)
+{
+	struct aw_thermal_softc *sc;
+	int i;
+
+	sc = device_get_softc(dev);
+
+	sc->conf = THS_CONF(dev);
+
+	if (bus_alloc_resources(dev, aw_thermal_spec, &sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	if (aw_thermal_init(sc) != 0)
+		return (ENXIO);
+
+	for (i = 0; sc->conf[i].sensor != THS_SENSOR_END; i++)
+		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		    OID_AUTO, sc->conf[i].name,
+		    CTLTYPE_INT | CTLFLAG_RD,
+		    sc, sc->conf[i].sensor, aw_thermal_sysctl, "IK0",
+		    sc->conf[i].desc);
+
+	return (0);
+}
+
+static device_method_t aw_thermal_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_thermal_probe),
+	DEVMETHOD(device_attach,	aw_thermal_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_thermal_driver = {
+	"aw_thermal",
+	aw_thermal_methods,
+	sizeof(struct aw_thermal_softc),
+};
+
+static devclass_t aw_thermal_devclass;
+
+DRIVER_MODULE(aw_thermal, simplebus, aw_thermal_driver, aw_thermal_devclass,
+    0, 0);
+MODULE_VERSION(aw_thermal, 1);


Property changes on: trunk/sys/arm/allwinner/aw_thermal.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_ts.c
===================================================================
--- trunk/sys/arm/allwinner/aw_ts.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_ts.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,231 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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.
+ */
+
+/*
+ * Allwinner Touch Sreen driver
+ * Touch screen part is not done, only the thermal sensor part is.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_ts.c 308276 2016-11-04 01:06:14Z manu $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#define	READ(_sc, _r) bus_read_4((_sc)->res[0], (_r))
+#define	WRITE(_sc, _r, _v) bus_write_4((_sc)->res[0], (_r), (_v))
+
+/* Control register 0 */
+#define	TP_CTRL0	0x00
+#define	 TP_CTRL0_TACQ(x)	((x & 0xFF) << 0)
+#define	 TP_CTRL0_FS_DIV(x)	((x & 0xF) << 16)
+#define	 TP_CTRL0_CLK_DIV(x)	((x & 0x3) << 20)
+#define	 TP_CTRL0_CLK_SELECT(x)	((x & 0x1) << 22)
+
+/* Control register 1 */
+#define	TP_CTRL1	0x04
+#define	 TP_CTRL1_MODE_EN	(1 << 4)
+
+/* Control register 2 */
+#define	TP_CTRL2	0x08
+
+/* Control register 3 */
+#define	TP_CTRL3	0x0C
+
+/* Int/FIFO control register */
+#define	TP_FIFOC	0x10
+#define	 TP_FIFOC_TEMP_IRQ_ENABLE	(1 << 18)
+
+/* Int/FIFO status register */
+#define	TP_FIFOS	0x14
+#define	 TP_FIFOS_TEMP_IRQ_PENDING	(1 << 18)
+
+/* Temperature Period Register */
+#define	TP_TPR		0x18
+#define	 TP_TPR_TEMP_EN		(1 << 16)
+#define	 TP_TPR_TEMP_PERIOD(x)	(x << 0)
+
+/* Common data register */
+#define	TP_CDAT		0x1C
+
+/* Temperature data register */
+#define	TEMP_DATA	0x20
+
+/* TP Data register*/
+#define	TP_DATA		0x24
+
+/* TP IO config register */
+#define	TP_IO_CONFIG	0x28
+
+/* TP IO port data register */
+#define	TP_IO_DATA	0x2C
+
+struct aw_ts_softc {
+	device_t		dev;
+	struct resource *	res[2];
+	void *			intrhand;
+	int			temp_data;
+	int			temp_offset;
+	int			temp_step;
+};
+
+static struct resource_spec aw_ts_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE | RF_SHAREABLE },
+	{ -1, 0 }
+};
+
+#define	A10_TS	1
+#define	A13_TS	2
+
+#define	AW_TS_TEMP_SYSCTL	1
+
+static struct ofw_compat_data compat_data[] = {
+	{"allwinner,sun4i-a10-ts", A10_TS},
+	{"allwinner,sun5i-a13-ts", A13_TS},
+	{NULL,             0}
+};
+
+static void
+aw_ts_intr(void *arg)
+{
+	struct aw_ts_softc *sc;
+	int val;
+
+	sc= (struct aw_ts_softc *)arg;
+
+	val = READ(sc, TP_FIFOS);
+	if (val & TP_FIFOS_TEMP_IRQ_PENDING) {
+		/* Convert the value to millicelsius then millikelvin */
+		sc->temp_data = (READ(sc, TEMP_DATA) * sc->temp_step - sc->temp_offset)
+			+ 273150;
+	}
+
+	WRITE(sc, TP_FIFOS, val);
+}
+
+static int
+aw_ts_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Touch Screen controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_ts_attach(device_t dev)
+{
+	struct aw_ts_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, aw_ts_spec, sc->res) != 0) {
+		device_printf(dev, "could not allocate memory resource\n");
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(dev, sc->res[1],
+	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, aw_ts_intr, sc,
+	    &sc->intrhand)) {
+		bus_release_resources(dev, aw_ts_spec, sc->res);
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (ENXIO);
+	}
+
+	/*
+	 * Thoses magic values were taken from linux which take them from
+	 * the allwinner SDK or found them by deduction
+	 */
+	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
+	case A10_TS:
+		sc->temp_offset = 257000;
+		sc->temp_step = 133;
+		break;
+	case A13_TS:
+		sc->temp_offset = 144700;
+		sc->temp_step = 100;
+		break;
+	}
+
+	/* Enable clock and set divisers */
+	WRITE(sc, TP_CTRL0, TP_CTRL0_CLK_SELECT(0) |
+	  TP_CTRL0_CLK_DIV(2) |
+	  TP_CTRL0_FS_DIV(7) |
+	  TP_CTRL0_TACQ(63));
+
+	/* Enable TS module */
+	WRITE(sc, TP_CTRL1, TP_CTRL1_MODE_EN);
+
+	/* Enable Temperature, period is ~2s */
+	WRITE(sc, TP_TPR, TP_TPR_TEMP_EN | TP_TPR_TEMP_PERIOD(1953));
+
+	/* Enable temp irq */
+	WRITE(sc, TP_FIFOC, TP_FIFOC_TEMP_IRQ_ENABLE);
+
+	/* Add sysctl */
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
+	    &sc->temp_data, 0, sysctl_handle_int,
+	    "IK3", "CPU Temperature");
+
+	return (0);
+}
+
+static device_method_t aw_ts_methods[] = {
+	DEVMETHOD(device_probe, aw_ts_probe),
+	DEVMETHOD(device_attach, aw_ts_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_ts_driver = {
+	"aw_ts",
+	aw_ts_methods,
+	sizeof(struct aw_ts_softc),
+};
+static devclass_t aw_ts_devclass;
+
+DRIVER_MODULE(aw_ts, simplebus, aw_ts_driver, aw_ts_devclass, 0, 0);


Property changes on: trunk/sys/arm/allwinner/aw_ts.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_usbphy.c
===================================================================
--- trunk/sys/arm/allwinner/aw_usbphy.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_usbphy.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,272 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_usbphy.c 332025 2018-04-04 13:23:06Z mmel $
+ */
+
+/*
+ * Allwinner USB PHY
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_usbphy.c 332025 2018-04-04 13:23:06Z mmel $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/gpio.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/gpio/gpiobusvar.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/regulator/regulator.h>
+#include <dev/extres/phy/phy.h>
+
+#include "phynode_if.h"
+
+#define	USBPHY_NPHYS	4
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-usb-phy",	1 },
+	{ "allwinner,sun5i-a13-usb-phy",	1 },
+	{ "allwinner,sun6i-a31-usb-phy",	1 },
+	{ "allwinner,sun7i-a20-usb-phy",	1 },
+	{ "allwinner,sun8i-a83t-usb-phy",	1 },
+	{ "allwinner,sun8i-h3-usb-phy",		1 },
+	{ NULL,					0 }
+};
+
+struct awusbphy_softc {
+	regulator_t		reg[USBPHY_NPHYS];
+	gpio_pin_t		id_det_pin;
+	int			id_det_valid;
+	gpio_pin_t		vbus_det_pin;
+	int			vbus_det_valid;
+};
+
+ /* Phy class and methods. */
+static int awusbphy_phy_enable(struct phynode *phy, bool enable);
+static phynode_method_t awusbphy_phynode_methods[] = {
+	PHYNODEMETHOD(phynode_enable, awusbphy_phy_enable),
+
+	PHYNODEMETHOD_END
+};
+DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_methods,
+    0, phynode_class);
+
+static int
+awusbphy_init(device_t dev)
+{
+	struct awusbphy_softc *sc;
+	phandle_t node;
+	char pname[20];
+	int error, off;
+	regulator_t reg;
+	hwreset_t rst;
+	clk_t clk;
+
+	sc = device_get_softc(dev);
+	node = ofw_bus_get_node(dev);
+
+	/* Enable clocks */
+	for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
+		error = clk_enable(clk);
+		if (error != 0) {
+			device_printf(dev, "couldn't enable clock %s\n",
+			    clk_get_name(clk));
+			return (error);
+		}
+	}
+
+	/* De-assert resets */
+	for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) {
+		error = hwreset_deassert(rst);
+		if (error != 0) {
+			device_printf(dev, "couldn't de-assert reset %d\n",
+			    off);
+			return (error);
+		}
+	}
+
+	/* Get regulators */
+	for (off = 0; off < USBPHY_NPHYS; off++) {
+		snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off);
+		if (regulator_get_by_ofw_property(dev, 0, pname, &reg) == 0)
+			sc->reg[off] = reg;
+	}
+
+	/* Get GPIOs */
+	error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios",
+	    &sc->id_det_pin);
+	if (error == 0)
+		sc->id_det_valid = 1;
+	error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios",
+	    &sc->vbus_det_pin);
+	if (error == 0)
+		sc->vbus_det_valid = 1;
+
+	return (0);
+}
+
+static int
+awusbphy_vbus_detect(device_t dev, int *val)
+{
+	struct awusbphy_softc *sc;
+	bool active;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (sc->vbus_det_valid) {
+		error = gpio_pin_is_active(sc->vbus_det_pin, &active);
+		if (error != 0)
+			return (error);
+		*val = active;
+		return (0);
+	}
+
+	*val = 1;
+	return (0);
+}
+
+static int
+awusbphy_phy_enable(struct phynode *phynode, bool enable)
+{
+	device_t dev;
+	intptr_t phy;
+	struct awusbphy_softc *sc;
+	regulator_t reg;
+	int error, vbus_det;
+
+	dev = phynode_get_device(phynode);
+	phy = phynode_get_id(phynode);
+	sc = device_get_softc(dev);
+
+	if (phy < 0 || phy >= USBPHY_NPHYS)
+		return (ERANGE);
+
+	sc = device_get_softc(dev);
+
+	/* Regulators are optional. If not found, return success. */
+	reg = sc->reg[phy];
+	if (reg == NULL)
+		return (0);
+
+	if (enable) {
+		/* If an external vbus is detected, do not enable phy 0 */
+		if (phy == 0) {
+			error = awusbphy_vbus_detect(dev, &vbus_det);
+			if (error == 0 && vbus_det == 1)
+				return (0);
+		} else
+			error = 0;
+		if (error == 0)
+			error = regulator_enable(reg);
+	} else
+		error = regulator_disable(reg);
+	if (error != 0) {
+		device_printf(dev,
+		    "couldn't %s regulator for phy %jd\n",
+		    enable ? "enable" : "disable", (intmax_t)phy);
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+awusbphy_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner USB PHY");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+awusbphy_attach(device_t dev)
+{
+	int error;
+	struct phynode *phynode;
+	struct phynode_init_def phy_init;
+	int i;
+
+	error = awusbphy_init(dev);
+	if (error) {
+		device_printf(dev, "failed to initialize USB PHY, error %d\n",
+		    error);
+		return (error);
+	}
+
+	/* Create and register phys. */
+	for (i = 0; i < USBPHY_NPHYS; i++) {
+		bzero(&phy_init, sizeof(phy_init));
+		phy_init.id = i;
+		phy_init.ofw_node = ofw_bus_get_node(dev);
+		phynode = phynode_create(dev, &awusbphy_phynode_class,
+		    &phy_init);
+		if (phynode == NULL) {
+			device_printf(dev, "failed to create USB PHY\n");
+			return (ENXIO);
+		}
+		if (phynode_register(phynode) == NULL) {
+			device_printf(dev, "failed to create USB PHY\n");
+			return (ENXIO);
+		}
+	}
+
+	return (error);
+}
+
+static device_method_t awusbphy_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		awusbphy_probe),
+	DEVMETHOD(device_attach,	awusbphy_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t awusbphy_driver = {
+	"awusbphy",
+	awusbphy_methods,
+	sizeof(struct awusbphy_softc)
+};
+
+static devclass_t awusbphy_devclass;
+
+EARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass,
+    0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(awusbphy, 1);


Property changes on: trunk/sys/arm/allwinner/aw_usbphy.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_wdog.c
===================================================================
--- trunk/sys/arm/allwinner/aw_wdog.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_wdog.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,277 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_wdog.c 331182 2018-03-19 06:40:11Z eadler $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/watchdog.h>
+#include <sys/reboot.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/machdep.h>
+
+#include <arm/allwinner/aw_wdog.h>
+
+#define	READ(_sc, _r) bus_read_4((_sc)->res, (_r))
+#define	WRITE(_sc, _r, _v) bus_write_4((_sc)->res, (_r), (_v))
+
+#define	A10_WDOG_CTRL		0x00
+#define	A31_WDOG_CTRL		0x10
+#define	 WDOG_CTRL_RESTART	(1 << 0)
+#define	 A31_WDOG_CTRL_KEY	(0xa57 << 1)
+#define	A10_WDOG_MODE		0x04
+#define	A31_WDOG_MODE		0x18
+#define	 A10_WDOG_MODE_INTVL_SHIFT	3
+#define	 A31_WDOG_MODE_INTVL_SHIFT	4
+#define	 A10_WDOG_MODE_RST_EN	(1 << 1)
+#define	 WDOG_MODE_EN		(1 << 0)
+#define	A31_WDOG_CONFIG		0x14
+#define	 A31_WDOG_CONFIG_RST_EN_SYSTEM	(1 << 0)
+#define	 A31_WDOG_CONFIG_RST_EN_INT	(2 << 0)
+
+struct aw_wdog_interval {
+	uint64_t	milliseconds;
+	unsigned int	value;
+};
+
+struct aw_wdog_interval wd_intervals[] = {
+	{   500,	 0 },
+	{  1000,	 1 },
+	{  2000,	 2 },
+	{  3000,	 3 },
+	{  4000,	 4 },
+	{  5000,	 5 },
+	{  6000,	 6 },
+	{  8000,	 7 },
+	{ 10000,	 8 },
+	{ 12000,	 9 },
+	{ 14000,	10 },
+	{ 16000,	11 },
+	{ 0,		 0 } /* sentinel */
+};
+
+static struct aw_wdog_softc *aw_wdog_sc = NULL;
+
+struct aw_wdog_softc {
+	device_t		dev;
+	struct resource *	res;
+	struct mtx		mtx;
+	uint8_t			wdog_ctrl;
+	uint32_t		wdog_ctrl_key;
+	uint8_t			wdog_mode;
+	uint8_t			wdog_mode_intvl_shift;
+	uint8_t			wdog_mode_en;
+	uint8_t			wdog_config;
+	uint8_t			wdog_config_value;
+};
+
+#define	A10_WATCHDOG	1
+#define	A31_WATCHDOG	2
+
+static struct ofw_compat_data compat_data[] = {
+	{"allwinner,sun4i-a10-wdt", A10_WATCHDOG},
+	{"allwinner,sun6i-a31-wdt", A31_WATCHDOG},
+	{NULL,             0}
+};
+
+static void aw_wdog_watchdog_fn(void *, u_int, int *);
+static void aw_wdog_shutdown_fn(void *, int);
+
+static int
+aw_wdog_probe(device_t dev)
+{
+	struct aw_wdog_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
+	case A10_WATCHDOG:
+		device_set_desc(dev, "Allwinner A10 Watchdog");
+		return (BUS_PROBE_DEFAULT);
+	case A31_WATCHDOG:
+		device_set_desc(dev, "Allwinner A31 Watchdog");
+		return (BUS_PROBE_DEFAULT);
+	}
+	return (ENXIO);
+}
+
+static int
+aw_wdog_attach(device_t dev)
+{
+	struct aw_wdog_softc *sc;
+	int rid;
+
+	if (aw_wdog_sc != NULL)
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	rid = 0;
+	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (sc->res == NULL) {
+		device_printf(dev, "could not allocate memory resource\n");
+		return (ENXIO);
+	}
+
+	aw_wdog_sc = sc;
+
+	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
+	case A10_WATCHDOG:
+		sc->wdog_ctrl = A10_WDOG_CTRL;
+		sc->wdog_mode = A10_WDOG_MODE;
+		sc->wdog_mode_intvl_shift = A10_WDOG_MODE_INTVL_SHIFT;
+		sc->wdog_mode_en = A10_WDOG_MODE_RST_EN | WDOG_MODE_EN;
+		break;
+	case A31_WATCHDOG:
+		sc->wdog_ctrl = A31_WDOG_CTRL;
+		sc->wdog_ctrl_key = A31_WDOG_CTRL_KEY;
+		sc->wdog_mode = A31_WDOG_MODE;
+		sc->wdog_mode_intvl_shift = A31_WDOG_MODE_INTVL_SHIFT;
+		sc->wdog_mode_en = WDOG_MODE_EN;
+		sc->wdog_config = A31_WDOG_CONFIG;
+		sc->wdog_config_value = A31_WDOG_CONFIG_RST_EN_SYSTEM;
+		break;
+	default:
+		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->res);
+		return (ENXIO);
+	}
+
+	mtx_init(&sc->mtx, "AW Watchdog", "aw_wdog", MTX_DEF);
+	EVENTHANDLER_REGISTER(watchdog_list, aw_wdog_watchdog_fn, sc, 0);
+	EVENTHANDLER_REGISTER(shutdown_final, aw_wdog_shutdown_fn, sc,
+	    SHUTDOWN_PRI_LAST - 1);
+	
+	return (0);
+}
+
+static void
+aw_wdog_watchdog_fn(void *private, u_int cmd, int *error)
+{
+	struct aw_wdog_softc *sc;
+	uint64_t ms;
+	int i;
+
+	sc = private;
+	mtx_lock(&sc->mtx);
+
+	cmd &= WD_INTERVAL;
+
+	if (cmd > 0) {
+		ms = ((uint64_t)1 << (cmd & WD_INTERVAL)) / 1000000;
+		i = 0;
+		while (wd_intervals[i].milliseconds &&
+		    (ms > wd_intervals[i].milliseconds))
+			i++;
+		if (wd_intervals[i].milliseconds) {
+			WRITE(sc, sc->wdog_mode,
+			  (wd_intervals[i].value << sc->wdog_mode_intvl_shift) |
+			    sc->wdog_mode_en);
+			WRITE(sc, sc->wdog_ctrl,
+			    WDOG_CTRL_RESTART | sc->wdog_ctrl_key);
+			if (sc->wdog_config)
+				WRITE(sc, sc->wdog_config,
+				    sc->wdog_config_value);
+			*error = 0;
+		}
+		else {
+			/*
+			 * Can't arm
+			 * disable watchdog as watchdog(9) requires
+			 */
+			device_printf(sc->dev,
+			    "Can't arm, timeout is more than 16 sec\n");
+			mtx_unlock(&sc->mtx);
+			WRITE(sc, sc->wdog_mode, 0);
+			return;
+		}
+	}
+	else
+		WRITE(sc, sc->wdog_mode, 0);
+
+	mtx_unlock(&sc->mtx);
+}
+
+static void
+aw_wdog_shutdown_fn(void *private, int howto)
+{
+	if ((howto & (RB_POWEROFF|RB_HALT)) == 0)
+		aw_wdog_watchdog_reset();
+}
+
+void
+aw_wdog_watchdog_reset(void)
+{
+
+	if (aw_wdog_sc == NULL) {
+		printf("Reset: watchdog device has not been initialized\n");
+		return;
+	}
+
+	WRITE(aw_wdog_sc, aw_wdog_sc->wdog_mode,
+	    (wd_intervals[0].value << aw_wdog_sc->wdog_mode_intvl_shift) |
+	    aw_wdog_sc->wdog_mode_en);
+	if (aw_wdog_sc->wdog_config)
+		WRITE(aw_wdog_sc, aw_wdog_sc->wdog_config,
+		      aw_wdog_sc->wdog_config_value);
+	WRITE(aw_wdog_sc, aw_wdog_sc->wdog_ctrl,
+	    WDOG_CTRL_RESTART | aw_wdog_sc->wdog_ctrl_key);
+	while(1)
+		;
+
+}
+
+static device_method_t aw_wdog_methods[] = {
+	DEVMETHOD(device_probe, aw_wdog_probe),
+	DEVMETHOD(device_attach, aw_wdog_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_wdog_driver = {
+	"aw_wdog",
+	aw_wdog_methods,
+	sizeof(struct aw_wdog_softc),
+};
+static devclass_t aw_wdog_devclass;
+
+DRIVER_MODULE(aw_wdog, simplebus, aw_wdog_driver, aw_wdog_devclass, 0, 0);


Property changes on: trunk/sys/arm/allwinner/aw_wdog.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/aw_wdog.h
===================================================================
--- trunk/sys/arm/allwinner/aw_wdog.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/aw_wdog.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,36 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/aw_wdog.h 296041 2016-02-25 16:50:36Z andrew $
+ *
+ */
+#ifndef __AW_WDOG_H__
+#define	__AW_WDOG_H__
+
+void aw_wdog_watchdog_reset(void);
+
+#endif /*__AW_WDOG_H__*/
+


Property changes on: trunk/sys/arm/allwinner/aw_wdog.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/axp209.c
===================================================================
--- trunk/sys/arm/allwinner/axp209.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/axp209.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,1409 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015-2016 Emmanuel Vadot <manu at freebsd.org>
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/axp209.c 323467 2017-09-11 22:21:15Z ian $");
+
+/*
+* X-Power AXP209/AXP211 PMU for Allwinner SoCs
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/clock.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/proc.h>
+#include <sys/gpio.h>
+#include <sys/reboot.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/gpio/gpiobusvar.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/regulator/regulator.h>
+
+#include <arm/allwinner/axp209reg.h>
+
+#include "gpio_if.h"
+#include "regdev_if.h"
+
+MALLOC_DEFINE(M_AXP2XX_REG, "Axp2XX regulator", "Axp2XX power regulator");
+
+struct axp2xx_regdef {
+	intptr_t		id;
+	char			*name;
+	uint8_t			enable_reg;
+	uint8_t			enable_mask;
+	uint8_t			voltage_reg;
+	uint8_t			voltage_mask;
+	uint8_t			voltage_shift;
+	int			voltage_min;
+	int			voltage_max;
+	int			voltage_step;
+	int			voltage_nstep;
+};
+
+static struct axp2xx_regdef axp209_regdefs[] = {
+	{
+		.id = AXP209_REG_ID_DCDC2,
+		.name = "dcdc2",
+		.enable_reg = AXP209_POWERCTL,
+		.enable_mask = AXP209_POWERCTL_DCDC2,
+		.voltage_reg = AXP209_REG_DCDC2_VOLTAGE,
+		.voltage_mask = 0x3f,
+		.voltage_min = 700,
+		.voltage_max = 2275,
+		.voltage_step = 25,
+		.voltage_nstep = 64,
+	},
+	{
+		.id = AXP209_REG_ID_DCDC3,
+		.name = "dcdc3",
+		.enable_reg = AXP209_POWERCTL,
+		.enable_mask = AXP209_POWERCTL_DCDC3,
+		.voltage_reg = AXP209_REG_DCDC3_VOLTAGE,
+		.voltage_mask = 0x7f,
+		.voltage_min = 700,
+		.voltage_max = 3500,
+		.voltage_step = 25,
+		.voltage_nstep = 128,
+	},
+	{
+		.id = AXP209_REG_ID_LDO2,
+		.name = "ldo2",
+		.enable_reg = AXP209_POWERCTL,
+		.enable_mask = AXP209_POWERCTL_LDO2,
+		.voltage_reg = AXP209_REG_LDO24_VOLTAGE,
+		.voltage_mask = 0xf0,
+		.voltage_shift = 4,
+		.voltage_min = 1800,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 16,
+	},
+	{
+		.id = AXP209_REG_ID_LDO3,
+		.name = "ldo3",
+		.enable_reg = AXP209_POWERCTL,
+		.enable_mask = AXP209_POWERCTL_LDO3,
+		.voltage_reg = AXP209_REG_LDO3_VOLTAGE,
+		.voltage_mask = 0x7f,
+		.voltage_min = 700,
+		.voltage_max = 2275,
+		.voltage_step = 25,
+		.voltage_nstep = 128,
+	},
+};
+
+static struct axp2xx_regdef axp221_regdefs[] = {
+	{
+		.id = AXP221_REG_ID_DLDO1,
+		.name = "dldo1",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_DLDO1,
+		.voltage_reg = AXP221_REG_DLDO1_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_DLDO2,
+		.name = "dldo2",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_DLDO2,
+		.voltage_reg = AXP221_REG_DLDO2_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_DLDO3,
+		.name = "dldo3",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_DLDO3,
+		.voltage_reg = AXP221_REG_DLDO3_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_DLDO4,
+		.name = "dldo4",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_DLDO4,
+		.voltage_reg = AXP221_REG_DLDO4_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_ELDO1,
+		.name = "eldo1",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_ELDO1,
+		.voltage_reg = AXP221_REG_ELDO1_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_ELDO2,
+		.name = "eldo2",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_ELDO2,
+		.voltage_reg = AXP221_REG_ELDO2_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_ELDO3,
+		.name = "eldo3",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_ELDO3,
+		.voltage_reg = AXP221_REG_ELDO3_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_DC5LDO,
+		.name = "dc5ldo",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_DC5LDO,
+		.voltage_reg = AXP221_REG_DC5LDO_VOLTAGE,
+		.voltage_mask = 0x3,
+		.voltage_min = 700,
+		.voltage_max = 1400,
+		.voltage_step = 100,
+		.voltage_nstep = 7,
+	},
+	{
+		.id = AXP221_REG_ID_DCDC1,
+		.name = "dcdc1",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_DCDC1,
+		.voltage_reg = AXP221_REG_DCDC1_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 1600,
+		.voltage_max = 3400,
+		.voltage_step = 100,
+		.voltage_nstep = 18,
+	},
+	{
+		.id = AXP221_REG_ID_DCDC2,
+		.name = "dcdc2",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_DCDC2,
+		.voltage_reg = AXP221_REG_DCDC2_VOLTAGE,
+		.voltage_mask = 0x3f,
+		.voltage_min = 600,
+		.voltage_max = 1540,
+		.voltage_step = 20,
+		.voltage_nstep = 47,
+	},
+	{
+		.id = AXP221_REG_ID_DCDC3,
+		.name = "dcdc3",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_DCDC3,
+		.voltage_reg = AXP221_REG_DCDC3_VOLTAGE,
+		.voltage_mask = 0x3f,
+		.voltage_min = 600,
+		.voltage_max = 1860,
+		.voltage_step = 20,
+		.voltage_nstep = 63,
+	},
+	{
+		.id = AXP221_REG_ID_DCDC4,
+		.name = "dcdc4",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_DCDC4,
+		.voltage_reg = AXP221_REG_DCDC4_VOLTAGE,
+		.voltage_mask = 0x3f,
+		.voltage_min = 600,
+		.voltage_max = 1540,
+		.voltage_step = 20,
+		.voltage_nstep = 47,
+	},
+	{
+		.id = AXP221_REG_ID_DCDC5,
+		.name = "dcdc5",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_DCDC5,
+		.voltage_reg = AXP221_REG_DCDC5_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 1000,
+		.voltage_max = 2550,
+		.voltage_step = 50,
+		.voltage_nstep = 31,
+	},
+	{
+		.id = AXP221_REG_ID_ALDO1,
+		.name = "aldo1",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_ALDO1,
+		.voltage_reg = AXP221_REG_ALDO1_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_ALDO2,
+		.name = "aldo2",
+		.enable_reg = AXP221_POWERCTL_1,
+		.enable_mask = AXP221_POWERCTL1_ALDO2,
+		.voltage_reg = AXP221_REG_ALDO2_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_ALDO3,
+		.name = "aldo3",
+		.enable_reg = AXP221_POWERCTL_3,
+		.enable_mask = AXP221_POWERCTL3_ALDO3,
+		.voltage_reg = AXP221_REG_ALDO3_VOLTAGE,
+		.voltage_mask = 0x1f,
+		.voltage_min = 700,
+		.voltage_max = 3300,
+		.voltage_step = 100,
+		.voltage_nstep = 26,
+	},
+	{
+		.id = AXP221_REG_ID_DC1SW,
+		.name = "dc1sw",
+		.enable_reg = AXP221_POWERCTL_2,
+		.enable_mask = AXP221_POWERCTL2_DC1SW,
+	},
+};
+
+struct axp2xx_reg_sc {
+	struct regnode		*regnode;
+	device_t		base_dev;
+	struct axp2xx_regdef	*def;
+	phandle_t		xref;
+	struct regnode_std_param *param;
+};
+
+struct axp2xx_pins {
+	const char	*name;
+	uint8_t		ctrl_reg;
+	uint8_t		status_reg;
+	uint8_t		status_mask;
+	uint8_t		status_shift;
+};
+
+/* GPIO3 is different, don't expose it for now */
+static const struct axp2xx_pins axp209_pins[] = {
+	{
+		.name = "GPIO0",
+		.ctrl_reg = AXP2XX_GPIO0_CTRL,
+		.status_reg = AXP2XX_GPIO_STATUS,
+		.status_mask = 0x10,
+		.status_shift = 4,
+	},
+	{
+		.name = "GPIO1",
+		.ctrl_reg = AXP2XX_GPIO1_CTRL,
+		.status_reg = AXP2XX_GPIO_STATUS,
+		.status_mask = 0x20,
+		.status_shift = 5,
+	},
+	{
+		.name = "GPIO2",
+		.ctrl_reg = AXP209_GPIO2_CTRL,
+		.status_reg = AXP2XX_GPIO_STATUS,
+		.status_mask = 0x40,
+		.status_shift = 6,
+	},
+};
+
+static const struct axp2xx_pins axp221_pins[] = {
+	{
+		.name = "GPIO0",
+		.ctrl_reg = AXP2XX_GPIO0_CTRL,
+		.status_reg = AXP2XX_GPIO_STATUS,
+		.status_mask = 0x1,
+		.status_shift = 0x0,
+	},
+	{
+		.name = "GPIO1",
+		.ctrl_reg = AXP2XX_GPIO0_CTRL,
+		.status_reg = AXP2XX_GPIO_STATUS,
+		.status_mask = 0x2,
+		.status_shift = 0x1,
+	},
+};
+
+struct axp2xx_sensors {
+	int		id;
+	const char	*name;
+	const char	*desc;
+	const char	*format;
+	uint8_t		enable_reg;
+	uint8_t		enable_mask;
+	uint8_t		value_reg;
+	uint8_t		value_size;
+	uint8_t		h_value_mask;
+	uint8_t		h_value_shift;
+	uint8_t		l_value_mask;
+	uint8_t		l_value_shift;
+	int		value_step;
+	int		value_convert;
+};
+
+static const struct axp2xx_sensors axp209_sensors[] = {
+	{
+		.id = AXP209_ACVOLT,
+		.name = "acvolt",
+		.desc = "AC Voltage (microvolt)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP209_ADC1_ACVOLT,
+		.value_reg = AXP209_ACIN_VOLTAGE,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = AXP209_VOLT_STEP,
+	},
+	{
+		.id = AXP209_ACCURRENT,
+		.name = "accurrent",
+		.desc = "AC Current (microAmpere)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP209_ADC1_ACCURRENT,
+		.value_reg = AXP209_ACIN_CURRENT,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = AXP209_ACCURRENT_STEP,
+	},
+	{
+		.id = AXP209_VBUSVOLT,
+		.name = "vbusvolt",
+		.desc = "VBUS Voltage (microVolt)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP209_ADC1_VBUSVOLT,
+		.value_reg = AXP209_VBUS_VOLTAGE,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = AXP209_VOLT_STEP,
+	},
+	{
+		.id = AXP209_VBUSCURRENT,
+		.name = "vbuscurrent",
+		.desc = "VBUS Current (microAmpere)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP209_ADC1_VBUSCURRENT,
+		.value_reg = AXP209_VBUS_CURRENT,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = AXP209_VBUSCURRENT_STEP,
+	},
+	{
+		.id = AXP2XX_BATVOLT,
+		.name = "batvolt",
+		.desc = "Battery Voltage (microVolt)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP2XX_ADC1_BATVOLT,
+		.value_reg = AXP2XX_BAT_VOLTAGE,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = AXP2XX_BATVOLT_STEP,
+	},
+	{
+		.id = AXP2XX_BATCHARGECURRENT,
+		.name = "batchargecurrent",
+		.desc = "Battery Charging Current (microAmpere)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP2XX_ADC1_BATCURRENT,
+		.value_reg = AXP2XX_BAT_CHARGE_CURRENT,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 5,
+		.l_value_mask = 0x1f,
+		.l_value_shift = 0,
+		.value_step = AXP2XX_BATCURRENT_STEP,
+	},
+	{
+		.id = AXP2XX_BATDISCHARGECURRENT,
+		.name = "batdischargecurrent",
+		.desc = "Battery Discharging Current (microAmpere)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP2XX_ADC1_BATCURRENT,
+		.value_reg = AXP2XX_BAT_DISCHARGE_CURRENT,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 5,
+		.l_value_mask = 0x1f,
+		.l_value_shift = 0,
+		.value_step = AXP2XX_BATCURRENT_STEP,
+	},
+	{
+		.id = AXP2XX_TEMP,
+		.name = "temp",
+		.desc = "Internal Temperature",
+		.format = "IK",
+		.enable_reg = AXP209_ADC_ENABLE2,
+		.enable_mask = AXP209_ADC2_TEMP,
+		.value_reg = AXP209_TEMPMON,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = 1,
+		.value_convert = -(AXP209_TEMPMON_MIN - AXP209_0C_TO_K),
+	},
+};
+
+static const struct axp2xx_sensors axp221_sensors[] = {
+	{
+		.id = AXP2XX_BATVOLT,
+		.name = "batvolt",
+		.desc = "Battery Voltage (microVolt)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP2XX_ADC1_BATVOLT,
+		.value_reg = AXP2XX_BAT_VOLTAGE,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = AXP2XX_BATVOLT_STEP,
+	},
+	{
+		.id = AXP2XX_BATCHARGECURRENT,
+		.name = "batchargecurrent",
+		.desc = "Battery Charging Current (microAmpere)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP2XX_ADC1_BATCURRENT,
+		.value_reg = AXP2XX_BAT_CHARGE_CURRENT,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 5,
+		.l_value_mask = 0x1f,
+		.l_value_shift = 0,
+		.value_step = AXP2XX_BATCURRENT_STEP,
+	},
+	{
+		.id = AXP2XX_BATDISCHARGECURRENT,
+		.name = "batdischargecurrent",
+		.desc = "Battery Discharging Current (microAmpere)",
+		.format = "I",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP2XX_ADC1_BATCURRENT,
+		.value_reg = AXP2XX_BAT_DISCHARGE_CURRENT,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 5,
+		.l_value_mask = 0x1f,
+		.l_value_shift = 0,
+		.value_step = AXP2XX_BATCURRENT_STEP,
+	},
+	{
+		.id = AXP2XX_TEMP,
+		.name = "temp",
+		.desc = "Internal Temperature",
+		.format = "IK",
+		.enable_reg = AXP2XX_ADC_ENABLE1,
+		.enable_mask = AXP221_ADC1_TEMP,
+		.value_reg = AXP221_TEMPMON,
+		.value_size = 2,
+		.h_value_mask = 0xff,
+		.h_value_shift = 4,
+		.l_value_mask = 0xf,
+		.l_value_shift = 0,
+		.value_step = 1,
+		.value_convert = -(AXP221_TEMPMON_MIN - AXP209_0C_TO_K),
+	},
+};
+
+enum AXP2XX_TYPE {
+	AXP209 = 1,
+	AXP221,
+};
+
+struct axp2xx_softc {
+	device_t		dev;
+	struct resource *	res[1];
+	void *			intrcookie;
+	struct intr_config_hook	intr_hook;
+	struct mtx		mtx;
+	uint8_t			type;
+
+	/* GPIO */
+	device_t		gpiodev;
+	int			npins;
+	const struct axp2xx_pins	*pins;
+
+	/* Sensors */
+	const struct axp2xx_sensors	*sensors;
+	int				nsensors;
+
+	/* Regulators */
+	struct axp2xx_reg_sc	**regs;
+	int			nregs;
+	struct axp2xx_regdef	*regdefs;
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "x-powers,axp209",		AXP209 },
+	{ "x-powers,axp221",		AXP221 },
+	{ NULL,				0 }
+};
+
+static struct resource_spec axp_res_spec[] = {
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1,			0,	0 }
+};
+
+#define	AXP_LOCK(sc)	mtx_lock(&(sc)->mtx)
+#define	AXP_UNLOCK(sc)	mtx_unlock(&(sc)->mtx)
+
+static int
+axp2xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
+{
+
+	return (iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT));
+}
+
+static int
+axp2xx_write(device_t dev, uint8_t reg, uint8_t data)
+{
+
+	return (iicdev_writeto(dev, reg, &data, sizeof(data), IIC_INTRWAIT));
+}
+
+static int
+axp2xx_regnode_init(struct regnode *regnode)
+{
+	return (0);
+}
+
+static int
+axp2xx_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
+{
+	struct axp2xx_reg_sc *sc;
+	uint8_t val;
+
+	sc = regnode_get_softc(regnode);
+
+	axp2xx_read(sc->base_dev, sc->def->enable_reg, &val, 1);
+	if (enable)
+		val |= sc->def->enable_mask;
+	else
+		val &= ~sc->def->enable_mask;
+	axp2xx_write(sc->base_dev, sc->def->enable_reg, val);
+
+	*udelay = 0;
+
+	return (0);
+}
+
+static void
+axp2xx_regnode_reg_to_voltage(struct axp2xx_reg_sc *sc, uint8_t val, int *uv)
+{
+	if (val < sc->def->voltage_nstep)
+		*uv = sc->def->voltage_min + val * sc->def->voltage_step;
+	else
+		*uv = sc->def->voltage_min +
+		       (sc->def->voltage_nstep * sc->def->voltage_step);
+	*uv *= 1000;
+}
+
+static int
+axp2xx_regnode_voltage_to_reg(struct axp2xx_reg_sc *sc, int min_uvolt,
+    int max_uvolt, uint8_t *val)
+{
+	uint8_t nval;
+	int nstep, uvolt;
+
+	nval = 0;
+	uvolt = sc->def->voltage_min * 1000;
+
+	for (nstep = 0; nstep < sc->def->voltage_nstep && uvolt < min_uvolt;
+	     nstep++) {
+		++nval;
+		uvolt += (sc->def->voltage_step * 1000);
+	}
+	if (uvolt > max_uvolt)
+		return (EINVAL);
+
+	*val = nval;
+	return (0);
+}
+
+static int
+axp2xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
+    int max_uvolt, int *udelay)
+{
+	struct axp2xx_reg_sc *sc;
+	uint8_t val;
+
+	sc = regnode_get_softc(regnode);
+
+	if (!sc->def->voltage_step)
+		return (ENXIO);
+
+	if (axp2xx_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0)
+		return (ERANGE);
+
+	axp2xx_write(sc->base_dev, sc->def->voltage_reg, val);
+
+	*udelay = 0;
+
+	return (0);
+}
+
+static int
+axp2xx_regnode_get_voltage(struct regnode *regnode, int *uvolt)
+{
+	struct axp2xx_reg_sc *sc;
+	uint8_t val;
+
+	sc = regnode_get_softc(regnode);
+
+	if (!sc->def->voltage_step)
+		return (ENXIO);
+
+	axp2xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1);
+	axp2xx_regnode_reg_to_voltage(sc, val & sc->def->voltage_mask, uvolt);
+
+	return (0);
+}
+
+static regnode_method_t axp2xx_regnode_methods[] = {
+	/* Regulator interface */
+	REGNODEMETHOD(regnode_init,		axp2xx_regnode_init),
+	REGNODEMETHOD(regnode_enable,		axp2xx_regnode_enable),
+	REGNODEMETHOD(regnode_set_voltage,	axp2xx_regnode_set_voltage),
+	REGNODEMETHOD(regnode_get_voltage,	axp2xx_regnode_get_voltage),
+	REGNODEMETHOD_END
+};
+DEFINE_CLASS_1(axp2xx_regnode, axp2xx_regnode_class, axp2xx_regnode_methods,
+    sizeof(struct axp2xx_reg_sc), regnode_class);
+
+static int
+axp2xx_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct axp2xx_softc *sc;
+	device_t dev = arg1;
+	enum axp2xx_sensor sensor = arg2;
+	uint8_t data[2];
+	int val, error, i, found;
+
+	sc = device_get_softc(dev);
+
+	for (found = 0, i = 0; i < sc->nsensors; i++) {
+		if (sc->sensors[i].id == sensor) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0)
+		return (ENOENT);
+
+	error = axp2xx_read(dev, sc->sensors[i].value_reg, data, 2);
+	if (error != 0)
+		return (error);
+
+	val = ((data[0] & sc->sensors[i].h_value_mask) <<
+	    sc->sensors[i].h_value_shift);
+	val |= ((data[1] & sc->sensors[i].l_value_mask) <<
+	    sc->sensors[i].l_value_shift);
+	val *= sc->sensors[i].value_step;
+	val += sc->sensors[i].value_convert;
+
+	return sysctl_handle_opaque(oidp, &val, sizeof(val), req);
+}
+
+static void
+axp2xx_shutdown(void *devp, int howto)
+{
+	device_t dev;
+
+	if (!(howto & RB_POWEROFF))
+		return;
+	dev = (device_t)devp;
+
+	if (bootverbose)
+		device_printf(dev, "Shutdown AXP2xx\n");
+
+	axp2xx_write(dev, AXP2XX_SHUTBAT, AXP2XX_SHUTBAT_SHUTDOWN);
+}
+
+static void
+axp2xx_intr(void *arg)
+{
+	struct axp2xx_softc *sc;
+	uint8_t reg;
+
+	sc = arg;
+
+	axp2xx_read(sc->dev, AXP2XX_IRQ1_STATUS, &reg, 1);
+	if (reg) {
+		if (reg & AXP2XX_IRQ1_AC_OVERVOLT)
+			devctl_notify("PMU", "AC", "overvoltage", NULL);
+		if (reg & AXP2XX_IRQ1_VBUS_OVERVOLT)
+			devctl_notify("PMU", "USB", "overvoltage", NULL);
+		if (reg & AXP2XX_IRQ1_VBUS_LOW)
+			devctl_notify("PMU", "USB", "undervoltage", NULL);
+		if (reg & AXP2XX_IRQ1_AC_CONN)
+			devctl_notify("PMU", "AC", "plugged", NULL);
+		if (reg & AXP2XX_IRQ1_AC_DISCONN)
+			devctl_notify("PMU", "AC", "unplugged", NULL);
+		if (reg & AXP2XX_IRQ1_VBUS_CONN)
+			devctl_notify("PMU", "USB", "plugged", NULL);
+		if (reg & AXP2XX_IRQ1_VBUS_DISCONN)
+			devctl_notify("PMU", "USB", "unplugged", NULL);
+		axp2xx_write(sc->dev, AXP2XX_IRQ1_STATUS, AXP2XX_IRQ_ACK);
+	}
+
+	axp2xx_read(sc->dev, AXP2XX_IRQ2_STATUS, &reg, 1);
+	if (reg) {
+		if (reg & AXP2XX_IRQ2_BATT_CHARGED)
+			devctl_notify("PMU", "Battery", "charged", NULL);
+		if (reg & AXP2XX_IRQ2_BATT_CHARGING)
+			devctl_notify("PMU", "Battery", "charging", NULL);
+		if (reg & AXP2XX_IRQ2_BATT_CONN)
+			devctl_notify("PMU", "Battery", "connected", NULL);
+		if (reg & AXP2XX_IRQ2_BATT_DISCONN)
+			devctl_notify("PMU", "Battery", "disconnected", NULL);
+		if (reg & AXP2XX_IRQ2_BATT_TEMP_LOW)
+			devctl_notify("PMU", "Battery", "low temp", NULL);
+		if (reg & AXP2XX_IRQ2_BATT_TEMP_OVER)
+			devctl_notify("PMU", "Battery", "high temp", NULL);
+		axp2xx_write(sc->dev, AXP2XX_IRQ2_STATUS, AXP2XX_IRQ_ACK);
+	}
+
+	axp2xx_read(sc->dev, AXP2XX_IRQ3_STATUS, &reg, 1);
+	if (reg) {
+		if (reg & AXP2XX_IRQ3_PEK_SHORT)
+			shutdown_nice(RB_POWEROFF);
+		axp2xx_write(sc->dev, AXP2XX_IRQ3_STATUS, AXP2XX_IRQ_ACK);
+	}
+
+	axp2xx_read(sc->dev, AXP2XX_IRQ4_STATUS, &reg, 1);
+	if (reg) {
+		axp2xx_write(sc->dev, AXP2XX_IRQ4_STATUS, AXP2XX_IRQ_ACK);
+	}
+
+	axp2xx_read(sc->dev, AXP2XX_IRQ5_STATUS, &reg, 1);
+	if (reg) {
+		axp2xx_write(sc->dev, AXP2XX_IRQ5_STATUS, AXP2XX_IRQ_ACK);
+	}
+}
+
+static device_t
+axp2xx_gpio_get_bus(device_t dev)
+{
+	struct axp2xx_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (sc->gpiodev);
+}
+
+static int
+axp2xx_gpio_pin_max(device_t dev, int *maxpin)
+{
+	struct axp2xx_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	*maxpin = sc->npins - 1;
+
+	return (0);
+}
+
+static int
+axp2xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	struct axp2xx_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	snprintf(name, GPIOMAXNAME, "%s", axp209_pins[pin].name);
+
+	return (0);
+}
+
+static int
+axp2xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	struct axp2xx_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	*caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+
+	return (0);
+}
+
+static int
+axp2xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct axp2xx_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	AXP_LOCK(sc);
+	error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = data & AXP2XX_GPIO_FUNC_MASK;
+		if (func == AXP2XX_GPIO_FUNC_INPUT)
+			*flags = GPIO_PIN_INPUT;
+		else if (func == AXP2XX_GPIO_FUNC_DRVLO ||
+		    func == AXP2XX_GPIO_FUNC_DRVHI)
+			*flags = GPIO_PIN_OUTPUT;
+		else
+			*flags = 0;
+	}
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp2xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	struct axp2xx_softc *sc;
+	uint8_t data;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	AXP_LOCK(sc);
+	error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		data &= ~AXP2XX_GPIO_FUNC_MASK;
+		if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) {
+			if ((flags & GPIO_PIN_OUTPUT) == 0)
+				data |= AXP2XX_GPIO_FUNC_INPUT;
+		}
+		error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data);
+	}
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp2xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+	struct axp2xx_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	AXP_LOCK(sc);
+	error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = data & AXP2XX_GPIO_FUNC_MASK;
+		switch (func) {
+		case AXP2XX_GPIO_FUNC_DRVLO:
+			*val = 0;
+			break;
+		case AXP2XX_GPIO_FUNC_DRVHI:
+			*val = 1;
+			break;
+		case AXP2XX_GPIO_FUNC_INPUT:
+			error = axp2xx_read(dev, sc->pins[pin].status_reg,
+			    &data, 1);
+			if (error == 0) {
+				*val = (data & sc->pins[pin].status_mask);
+				*val >>= sc->pins[pin].status_shift;
+			}
+			break;
+		default:
+			error = EIO;
+			break;
+		}
+	}
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp2xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
+{
+	struct axp2xx_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	AXP_LOCK(sc);
+	error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = data & AXP2XX_GPIO_FUNC_MASK;
+		switch (func) {
+		case AXP2XX_GPIO_FUNC_DRVLO:
+		case AXP2XX_GPIO_FUNC_DRVHI:
+			/* GPIO2 can't be set to 1 */
+			if (pin == 2 && val == 1) {
+				error = EINVAL;
+				break;
+			}
+			data &= ~AXP2XX_GPIO_FUNC_MASK;
+			data |= val;
+			break;
+		default:
+			error = EIO;
+			break;
+		}
+	}
+	if (error == 0)
+		error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data);
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+
+static int
+axp2xx_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	struct axp2xx_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (pin >= sc->npins)
+		return (EINVAL);
+
+	AXP_LOCK(sc);
+	error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = data & AXP2XX_GPIO_FUNC_MASK;
+		switch (func) {
+		case AXP2XX_GPIO_FUNC_DRVLO:
+			/* Pin 2 can't be set to 1*/
+			if (pin == 2) {
+				error = EINVAL;
+				break;
+			}
+			data &= ~AXP2XX_GPIO_FUNC_MASK;
+			data |= AXP2XX_GPIO_FUNC_DRVHI;
+			break;
+		case AXP2XX_GPIO_FUNC_DRVHI:
+			data &= ~AXP2XX_GPIO_FUNC_MASK;
+			data |= AXP2XX_GPIO_FUNC_DRVLO;
+			break;
+		default:
+			error = EIO;
+			break;
+		}
+	}
+	if (error == 0)
+		error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data);
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp2xx_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent,
+    int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+	struct axp2xx_softc *sc;
+
+	sc = device_get_softc(bus);
+
+	if (gpios[0] >= sc->npins)
+		return (EINVAL);
+
+	*pin = gpios[0];
+	*flags = gpios[1];
+
+	return (0);
+}
+
+static phandle_t
+axp2xx_get_node(device_t dev, device_t bus)
+{
+	return (ofw_bus_get_node(dev));
+}
+
+static struct axp2xx_reg_sc *
+axp2xx_reg_attach(device_t dev, phandle_t node,
+    struct axp2xx_regdef *def)
+{
+	struct axp2xx_reg_sc *reg_sc;
+	struct regnode_init_def initdef;
+	struct regnode *regnode;
+
+	memset(&initdef, 0, sizeof(initdef));
+	if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) {
+		device_printf(dev, "cannot create regulator\n");
+		return (NULL);
+	}
+	if (initdef.std_param.min_uvolt == 0)
+		initdef.std_param.min_uvolt = def->voltage_min * 1000;
+	if (initdef.std_param.max_uvolt == 0)
+		initdef.std_param.max_uvolt = def->voltage_max * 1000;
+	initdef.id = def->id;
+	initdef.ofw_node = node;
+	regnode = regnode_create(dev, &axp2xx_regnode_class, &initdef);
+	if (regnode == NULL) {
+		device_printf(dev, "cannot create regulator\n");
+		return (NULL);
+	}
+
+	reg_sc = regnode_get_softc(regnode);
+	reg_sc->regnode = regnode;
+	reg_sc->base_dev = dev;
+	reg_sc->def = def;
+	reg_sc->xref = OF_xref_from_node(node);
+	reg_sc->param = regnode_get_stdparam(regnode);
+
+	regnode_register(regnode);
+
+	return (reg_sc);
+}
+
+static int
+axp2xx_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells,
+    intptr_t *num)
+{
+	struct axp2xx_softc *sc;
+	int i;
+
+	sc = device_get_softc(dev);
+	for (i = 0; i < sc->nregs; i++) {
+		if (sc->regs[i] == NULL)
+			continue;
+		if (sc->regs[i]->xref == xref) {
+			*num = sc->regs[i]->def->id;
+			return (0);
+		}
+	}
+
+	return (ENXIO);
+}
+
+static void
+axp2xx_start(void *pdev)
+{
+	device_t dev;
+	struct axp2xx_softc *sc;
+	const char *pwr_name[] = {"Battery", "AC", "USB", "AC and USB"};
+	int i;
+	uint8_t reg, data;
+	uint8_t pwr_src;
+
+	dev = pdev;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	if (bootverbose) {
+		/*
+		 * Read the Power State register.
+		 * Shift the AC presence into bit 0.
+		 * Shift the Battery presence into bit 1.
+		 */
+		axp2xx_read(dev, AXP2XX_PSR, &data, 1);
+		pwr_src = ((data & AXP2XX_PSR_ACIN) >> AXP2XX_PSR_ACIN_SHIFT) |
+		    ((data & AXP2XX_PSR_VBUS) >> (AXP2XX_PSR_VBUS_SHIFT - 1));
+
+		device_printf(dev, "Powered by %s\n",
+		    pwr_name[pwr_src]);
+	}
+
+	/* Only enable interrupts that we are interested in */
+	axp2xx_write(dev, AXP2XX_IRQ1_ENABLE,
+	    AXP2XX_IRQ1_AC_OVERVOLT |
+	    AXP2XX_IRQ1_AC_DISCONN |
+	    AXP2XX_IRQ1_AC_CONN |
+	    AXP2XX_IRQ1_VBUS_OVERVOLT |
+	    AXP2XX_IRQ1_VBUS_DISCONN |
+	    AXP2XX_IRQ1_VBUS_CONN);
+	axp2xx_write(dev, AXP2XX_IRQ2_ENABLE,
+	    AXP2XX_IRQ2_BATT_CONN |
+	    AXP2XX_IRQ2_BATT_DISCONN |
+	    AXP2XX_IRQ2_BATT_CHARGE_ACCT_ON |
+	    AXP2XX_IRQ2_BATT_CHARGE_ACCT_OFF |
+	    AXP2XX_IRQ2_BATT_CHARGING |
+	    AXP2XX_IRQ2_BATT_CHARGED |
+	    AXP2XX_IRQ2_BATT_TEMP_OVER |
+	    AXP2XX_IRQ2_BATT_TEMP_LOW);
+	axp2xx_write(dev, AXP2XX_IRQ3_ENABLE,
+	    AXP2XX_IRQ3_PEK_SHORT | AXP2XX_IRQ3_PEK_LONG);
+	axp2xx_write(dev, AXP2XX_IRQ4_ENABLE, AXP2XX_IRQ4_APS_LOW_2);
+	axp2xx_write(dev, AXP2XX_IRQ5_ENABLE, 0x0);
+
+	EVENTHANDLER_REGISTER(shutdown_final, axp2xx_shutdown, dev,
+	    SHUTDOWN_PRI_LAST);
+
+	/* Enable ADC sensors */
+	for (i = 0; i < sc->nsensors; i++) {
+		if (axp2xx_read(dev, sc->sensors[i].enable_reg, &reg, 1) == -1) {
+			device_printf(dev, "Cannot enable sensor '%s'\n",
+			    sc->sensors[i].name);
+			continue;
+		}
+		reg |= sc->sensors[i].enable_mask;
+		if (axp2xx_write(dev, sc->sensors[i].enable_reg, reg) == -1) {
+			device_printf(dev, "Cannot enable sensor '%s'\n",
+			    sc->sensors[i].name);
+			continue;
+		}
+		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		    OID_AUTO, sc->sensors[i].name,
+		    CTLTYPE_INT | CTLFLAG_RD,
+		    dev, sc->sensors[i].id, axp2xx_sysctl,
+		    sc->sensors[i].format,
+		    sc->sensors[i].desc);
+	}
+
+	if ((bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE,
+	      NULL, axp2xx_intr, sc, &sc->intrcookie)))
+		device_printf(dev, "unable to register interrupt handler\n");
+
+	config_intrhook_disestablish(&sc->intr_hook);
+}
+
+static int
+axp2xx_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+	{
+	case AXP209:
+		device_set_desc(dev, "X-Powers AXP209 Power Management Unit");
+		break;
+	case AXP221:
+		device_set_desc(dev, "X-Powers AXP221 Power Management Unit");
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+axp2xx_attach(device_t dev)
+{
+	struct axp2xx_softc *sc;
+	struct axp2xx_reg_sc *reg;
+	struct axp2xx_regdef *regdefs;
+	phandle_t rnode, child;
+	int i;
+
+	sc = device_get_softc(dev);
+	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+	if (bus_alloc_resources(dev, axp_res_spec, sc->res) != 0) {
+		device_printf(dev, "can't allocate device resources\n");
+		return (ENXIO);
+	}
+
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	switch (sc->type) {
+	case AXP209:
+		sc->pins = axp209_pins;
+		sc->npins = nitems(axp209_pins);
+		sc->gpiodev = gpiobus_attach_bus(dev);
+
+		sc->sensors = axp209_sensors;
+		sc->nsensors = nitems(axp209_sensors);
+
+		regdefs = axp209_regdefs;
+		sc->nregs = nitems(axp209_regdefs);
+		break;
+	case AXP221:
+		sc->pins = axp221_pins;
+		sc->npins = nitems(axp221_pins);
+		sc->gpiodev = gpiobus_attach_bus(dev);
+
+		sc->sensors = axp221_sensors;
+		sc->nsensors = nitems(axp221_sensors);
+
+		regdefs = axp221_regdefs;
+		sc->nregs = nitems(axp221_regdefs);
+		break;
+	}
+
+	sc->regs = malloc(sizeof(struct axp2xx_reg_sc *) * sc->nregs,
+	    M_AXP2XX_REG, M_WAITOK | M_ZERO);
+
+	sc->intr_hook.ich_func = axp2xx_start;
+	sc->intr_hook.ich_arg = dev;
+
+	if (config_intrhook_establish(&sc->intr_hook) != 0)
+		return (ENOMEM);
+
+	/* Attach known regulators that exist in the DT */
+	rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators");
+	if (rnode > 0) {
+		for (i = 0; i < sc->nregs; i++) {
+			child = ofw_bus_find_child(rnode,
+			    regdefs[i].name);
+			if (child == 0)
+				continue;
+			reg = axp2xx_reg_attach(dev, child, &regdefs[i]);
+			if (reg == NULL) {
+				device_printf(dev,
+				    "cannot attach regulator %s\n",
+				    regdefs[i].name);
+				continue;
+			}
+			sc->regs[i] = reg;
+			if (bootverbose)
+				device_printf(dev, "Regulator %s attached\n",
+				    regdefs[i].name);
+		}
+	}
+
+	return (0);
+}
+
+static device_method_t axp2xx_methods[] = {
+	DEVMETHOD(device_probe,		axp2xx_probe),
+	DEVMETHOD(device_attach,	axp2xx_attach),
+
+	/* GPIO interface */
+	DEVMETHOD(gpio_get_bus,		axp2xx_gpio_get_bus),
+	DEVMETHOD(gpio_pin_max,		axp2xx_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getname,	axp2xx_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_getcaps,	axp2xx_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_getflags,	axp2xx_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_setflags,	axp2xx_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_get,		axp2xx_gpio_pin_get),
+	DEVMETHOD(gpio_pin_set,		axp2xx_gpio_pin_set),
+	DEVMETHOD(gpio_pin_toggle,	axp2xx_gpio_pin_toggle),
+	DEVMETHOD(gpio_map_gpios,	axp2xx_gpio_map_gpios),
+
+	/* Regdev interface */
+	DEVMETHOD(regdev_map,		axp2xx_regdev_map),
+
+	/* OFW bus interface */
+	DEVMETHOD(ofw_bus_get_node,	axp2xx_get_node),
+
+	DEVMETHOD_END
+};
+
+static driver_t axp2xx_driver = {
+	"axp2xx_pmu",
+	axp2xx_methods,
+	sizeof(struct axp2xx_softc),
+};
+
+static devclass_t axp2xx_devclass;
+extern devclass_t ofwgpiobus_devclass, gpioc_devclass;
+extern driver_t ofw_gpiobus_driver, gpioc_driver;
+
+EARLY_DRIVER_MODULE(axp2xx, iicbus, axp2xx_driver, axp2xx_devclass,
+  0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
+EARLY_DRIVER_MODULE(ofw_gpiobus, axp2xx_pmu, ofw_gpiobus_driver,
+    ofwgpiobus_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
+DRIVER_MODULE(gpioc, axp2xx_pmu, gpioc_driver, gpioc_devclass,
+    0, 0);
+MODULE_VERSION(axp2xx, 1);
+MODULE_DEPEND(axp2xx, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);


Property changes on: trunk/sys/arm/allwinner/axp209.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/axp209reg.h
===================================================================
--- trunk/sys/arm/allwinner/axp209reg.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/axp209reg.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,249 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freeebsd.org>
+ * 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/axp209reg.h 309758 2016-12-09 20:17:07Z manu $
+ */
+
+#ifndef _AXP209REG_H_
+#define	_AXP209REG_H_
+
+/* Power State Register */
+#define	AXP2XX_PSR		0x00
+#define	AXP2XX_PSR_ACIN		0x80
+#define	AXP2XX_PSR_ACIN_SHIFT	7
+#define	AXP2XX_PSR_VBUS		0x20
+#define	AXP2XX_PSR_VBUS_SHIFT	5
+
+/* Shutdown and battery control */
+#define	AXP2XX_SHUTBAT		0x32
+#define	AXP2XX_SHUTBAT_SHUTDOWN	0x80
+
+/* Voltage/Current Monitor */
+#define	AXP209_ACIN_VOLTAGE		0x56
+#define	AXP209_ACIN_CURRENT		0x58
+#define	AXP209_VBUS_VOLTAGE		0x5A
+#define	AXP209_VBUS_CURRENT		0x5C
+#define	AXP2XX_BAT_VOLTAGE		0x78
+#define	AXP2XX_BAT_CHARGE_CURRENT	0x7A
+#define	AXP2XX_BAT_DISCHARGE_CURRENT	0x7C
+
+#define	AXP209_VOLT_STEP	1700
+#define	AXP2XX_BATVOLT_STEP	1100
+#define	AXP209_ACCURRENT_STEP	625
+#define	AXP209_VBUSCURRENT_STEP	375
+#define	AXP2XX_BATCURRENT_STEP	500
+
+/* Temperature monitor */
+#define	AXP209_TEMPMON		0x5e
+#define	AXP209_TEMPMON_MIN	1447	/* -144.7C */
+#define	AXP221_TEMPMON_MIN	2437	/* -243.7C */
+
+#define	AXP221_TEMPMON		0x56
+
+/* Sensors conversion macros */
+#define	AXP209_SENSOR_H(a)	((a) << 4)
+#define	AXP209_SENSOR_L(a)	((a) & 0xf)
+#define	AXP209_SENSOR_BAT_H(a)	((a) << 5)
+#define	AXP209_SENSOR_BAT_L(a)	((a) & 0x1f)
+
+#define	AXP209_0C_TO_K		2732
+
+/* ADC Sensors */
+#define	AXP2XX_ADC_ENABLE1	0x82
+#define	AXP209_ADC_ENABLE2	0x83
+
+#define	AXP2XX_ADC1_BATVOLT	(1 << 7)
+#define	AXP2XX_ADC1_BATCURRENT	(1 << 6)
+#define	AXP209_ADC1_ACVOLT	(1 << 5)
+#define	AXP221_ADC1_TEMP	(1 << 5)
+#define	AXP209_ADC1_ACCURRENT	(1 << 4)
+#define	AXP209_ADC1_VBUSVOLT	(1 << 3)
+#define	AXP209_ADC1_VBUSCURRENT	(1 << 2)
+#define	AXP221_ADC1_TS_PIN	(1 << 0)
+
+#define	AXP209_ADC2_TEMP	(1 << 7)
+
+/* Interrupt related registers */
+#define	AXP2XX_IRQ1_ENABLE	0x40
+#define	AXP2XX_IRQ1_STATUS	0x48
+#define	 AXP2XX_IRQ1_AC_OVERVOLT	(1 << 7)
+#define	 AXP2XX_IRQ1_AC_CONN		(1 << 6)
+#define	 AXP2XX_IRQ1_AC_DISCONN		(1 << 5)
+#define	 AXP2XX_IRQ1_VBUS_OVERVOLT	(1 << 4)
+#define	 AXP2XX_IRQ1_VBUS_CONN		(1 << 3)
+#define	 AXP2XX_IRQ1_VBUS_DISCONN	(1 << 2)
+#define	 AXP2XX_IRQ1_VBUS_LOW		(1 << 1)
+
+#define	AXP2XX_IRQ2_ENABLE	0x41
+#define	AXP2XX_IRQ2_STATUS	0x49
+#define	 AXP2XX_IRQ2_BATT_CONN			(1 << 7)
+#define	 AXP2XX_IRQ2_BATT_DISCONN		(1 << 6)
+#define	 AXP2XX_IRQ2_BATT_CHARGE_ACCT_ON	(1 << 5)
+#define	 AXP2XX_IRQ2_BATT_CHARGE_ACCT_OFF	(1 << 4)
+#define	 AXP2XX_IRQ2_BATT_CHARGING		(1 << 3)
+#define	 AXP2XX_IRQ2_BATT_CHARGED		(1 << 2)
+#define	 AXP2XX_IRQ2_BATT_TEMP_OVER		(1 << 1)
+#define	 AXP2XX_IRQ2_BATT_TEMP_LOW		(1 << 0)
+
+#define	AXP2XX_IRQ3_ENABLE	0x42
+#define	AXP2XX_IRQ3_STATUS	0x4A
+#define	 AXP2XX_IRQ3_TEMP_OVER		(1 << 7)
+#define	 AXP2XX_IRQ3_CHARGE_CURRENT_LOW	(1 << 6)
+#define	 AXP2XX_IRQ3_DCDC2_LOW		(1 << 4)
+#define	 AXP2XX_IRQ3_DCDC3_LOW		(1 << 3)
+#define	 AXP2XX_IRQ3_LDO3_LOW		(1 << 2)
+#define	 AXP2XX_IRQ3_PEK_SHORT		(1 << 1)
+#define	 AXP2XX_IRQ3_PEK_LONG		(1 << 0)
+
+#define	AXP2XX_IRQ4_ENABLE	0x43
+#define	AXP2XX_IRQ4_STATUS	0x4B
+#define	 AXP2XX_IRQ4_NOE_START		(1 << 7)
+#define	 AXP2XX_IRQ4_NOE_SHUT		(1 << 6)
+#define	 AXP2XX_IRQ4_VBUS_VALID		(1 << 5)
+#define	 AXP2XX_IRQ4_VBUS_INVALID	(1 << 4)
+#define	 AXP2XX_IRQ4_VBUS_SESSION	(1 << 3)
+#define	 AXP2XX_IRQ4_VBUS_SESSION_END	(1 << 2)
+#define	 AXP2XX_IRQ4_APS_LOW_1		(1 << 1)
+#define	 AXP2XX_IRQ4_APS_LOW_2		(1 << 0)
+
+#define	AXP2XX_IRQ5_ENABLE	0x44
+#define	AXP2XX_IRQ5_STATUS	0x4C
+#define	 AXP2XX_IRQ5_TIMER_EXPIRE	(1 << 7)
+#define	 AXP2XX_IRQ5_PEK_RISE_EDGE	(1 << 6)
+#define	 AXP2XX_IRQ5_PEK_FALL_EDGE	(1 << 5)
+#define	 AXP2XX_IRQ5_GPIO3	(1 << 3)
+#define	 AXP2XX_IRQ5_GPIO2	(1 << 2)
+#define	 AXP2XX_IRQ5_GPIO1	(1 << 1)
+#define	 AXP2XX_IRQ5_GPIO0	(1 << 0)
+
+#define	AXP2XX_IRQ_ACK		0xff
+
+/* GPIOs registers */
+#define	AXP2XX_GPIO_FUNC_MASK		0x7
+
+#define	AXP2XX_GPIO_FUNC_DRVLO		0x0
+#define	AXP2XX_GPIO_FUNC_DRVHI		0x1
+#define	AXP2XX_GPIO_FUNC_INPUT		0x2
+
+#define	AXP2XX_GPIO0_CTRL	0x90
+#define	AXP2XX_GPIO1_CTRL	0x92
+#define	AXP209_GPIO2_CTRL	0x93
+#define	AXP2XX_GPIO_STATUS	0x94
+
+/* Regulators registers */
+#define	AXP209_POWERCTL			0x12
+#define	 AXP209_POWERCTL_LDO3		(1 << 6)
+#define	 AXP209_POWERCTL_DCDC2		(1 << 4)
+#define	 AXP209_POWERCTL_LDO4		(1 << 3)
+#define	 AXP209_POWERCTL_LDO2		(1 << 2)
+#define	 AXP209_POWERCTL_DCDC3		(1 << 1)
+
+#define	AXP221_POWERCTL_1		0x10
+#define	 AXP221_POWERCTL1_ALDO2		(1 << 7)
+#define	 AXP221_POWERCTL1_ALDO1		(1 << 6)
+#define	 AXP221_POWERCTL1_DCDC5		(1 << 5)
+#define	 AXP221_POWERCTL1_DCDC4		(1 << 4)
+#define	 AXP221_POWERCTL1_DCDC3		(1 << 3)
+#define	 AXP221_POWERCTL1_DCDC2		(1 << 2)
+#define	 AXP221_POWERCTL1_DCDC1		(1 << 1)
+#define	 AXP221_POWERCTL1_DC5LDO	(1 << 0)
+
+#define	AXP221_POWERCTL_2		0x12
+#define	 AXP221_POWERCTL2_DC1SW		(1 << 7)
+#define	 AXP221_POWERCTL2_DLDO4		(1 << 6)
+#define	 AXP221_POWERCTL2_DLDO3		(1 << 5)
+#define	 AXP221_POWERCTL2_DLDO2		(1 << 4)
+#define	 AXP221_POWERCTL2_DLDO1		(1 << 3)
+#define	 AXP221_POWERCTL2_ELDO3		(1 << 2)
+#define	 AXP221_POWERCTL2_ELDO2		(1 << 1)
+#define	 AXP221_POWERCTL2_ELDO1		(1 << 0)
+
+#define	AXP221_POWERCTL_3		0x14
+#define	 AXP221_POWERCTL3_ALDO3		(1 << 7)
+
+#define	AXP209_REG_DCDC2_VOLTAGE	0x23
+#define	AXP209_REG_DCDC3_VOLTAGE	0x27
+#define	AXP209_REG_LDO24_VOLTAGE	0x28
+#define	AXP209_REG_LDO3_VOLTAGE		0x29
+
+#define	AXP221_REG_DLDO1_VOLTAGE	0x15
+#define	AXP221_REG_DLDO2_VOLTAGE	0x16
+#define	AXP221_REG_DLDO3_VOLTAGE	0x17
+#define	AXP221_REG_DLDO4_VOLTAGE	0x18
+#define	AXP221_REG_ELDO1_VOLTAGE	0x19
+#define	AXP221_REG_ELDO2_VOLTAGE	0x1A
+#define	AXP221_REG_ELDO3_VOLTAGE	0x1B
+#define	AXP221_REG_DC5LDO_VOLTAGE	0x1C
+#define	AXP221_REG_DCDC1_VOLTAGE	0x21
+#define	AXP221_REG_DCDC2_VOLTAGE	0x22
+#define	AXP221_REG_DCDC3_VOLTAGE	0x23
+#define	AXP221_REG_DCDC4_VOLTAGE	0x24
+#define	AXP221_REG_DCDC5_VOLTAGE	0x25
+#define	AXP221_REG_DCDC23_VRC		0x27
+#define	AXP221_REG_ALDO1_VOLTAGE	0x28
+#define	AXP221_REG_ALDO2_VOLTAGE	0x29
+#define	AXP221_REG_ALDO3_VOLTAGE	0x2A
+
+
+enum axp2xx_sensor {
+	AXP209_ACVOLT,
+	AXP209_ACCURRENT,
+	AXP209_VBUSVOLT,
+	AXP209_VBUSCURRENT,
+	AXP2XX_TEMP,
+	AXP2XX_BATVOLT,
+	AXP2XX_BATCHARGECURRENT,
+	AXP2XX_BATDISCHARGECURRENT,
+};
+
+enum axp2xx_regulators {
+	AXP209_REG_ID_DCDC2,
+	AXP209_REG_ID_DCDC3,
+	AXP209_REG_ID_LDO1,
+	AXP209_REG_ID_LDO2,
+	AXP209_REG_ID_LDO3,
+	/* LDO4 is weird, need to find a correct way to handle it */
+	/* AXP209_REG_ID_LDO4, */
+	AXP209_REG_ID_LDO5,
+	AXP221_REG_ID_DLDO1,
+	AXP221_REG_ID_DLDO2,
+	AXP221_REG_ID_DLDO3,
+	AXP221_REG_ID_DLDO4,
+	AXP221_REG_ID_ELDO1,
+	AXP221_REG_ID_ELDO2,
+	AXP221_REG_ID_ELDO3,
+	AXP221_REG_ID_DC5LDO,
+	AXP221_REG_ID_DCDC1,
+	AXP221_REG_ID_DCDC2,
+	AXP221_REG_ID_DCDC3,
+	AXP221_REG_ID_DCDC4,
+	AXP221_REG_ID_DCDC5,
+	AXP221_REG_ID_ALDO1,
+	AXP221_REG_ID_ALDO2,
+	AXP221_REG_ID_ALDO3,
+	AXP221_REG_ID_DC1SW,
+};
+
+#endif /* _AXP209REG_H_ */


Property changes on: trunk/sys/arm/allwinner/axp209reg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/axp81x.c
===================================================================
--- trunk/sys/arm/allwinner/axp81x.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/axp81x.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,520 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/axp81x.c 299862 2016-05-15 16:43:47Z jmcneill $
+ */
+
+/*
+ * X-Powers AXP813/818 PMU for Allwinner SoCs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/axp81x.c 299862 2016-05-15 16:43:47Z jmcneill $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/eventhandler.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/reboot.h>
+#include <sys/gpio.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/gpio/gpiobusvar.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "iicbus_if.h"
+#include "gpio_if.h"
+
+#define	AXP_ICTYPE		0x03
+#define	AXP_POWERBAT		0x32
+#define	 AXP_POWERBAT_SHUTDOWN	(1 << 7)
+#define	AXP_IRQEN1		0x40
+#define	AXP_IRQEN2		0x41
+#define	AXP_IRQEN3		0x42
+#define	AXP_IRQEN4		0x43
+#define	AXP_IRQEN5		0x44
+#define	 AXP_IRQEN5_POKSIRQ	(1 << 4)
+#define	AXP_IRQEN6		0x45
+#define	AXP_IRQSTAT5		0x4c
+#define	 AXP_IRQSTAT5_POKSIRQ	(1 << 4)
+#define	AXP_GPIO0_CTRL		0x90
+#define	AXP_GPIO1_CTRL		0x92
+#define	 AXP_GPIO_FUNC		(0x7 << 0)
+#define	 AXP_GPIO_FUNC_SHIFT	0
+#define	 AXP_GPIO_FUNC_DRVLO	0
+#define	 AXP_GPIO_FUNC_DRVHI	1
+#define	 AXP_GPIO_FUNC_INPUT	2
+#define	AXP_GPIO_SIGBIT		0x94
+#define	AXP_GPIO_PD		0x97
+
+static const struct {
+	const char *name;
+	uint8_t	ctrl_reg;
+} axp81x_pins[] = {
+	{ "GPIO0", AXP_GPIO0_CTRL },
+	{ "GPIO1", AXP_GPIO1_CTRL },
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "x-powers,axp813",			1 },
+	{ "x-powers,axp818",			1 },
+	{ NULL,					0 }
+};
+
+static struct resource_spec axp81x_spec[] = {
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+struct axp81x_softc {
+	struct resource		*res;
+	uint16_t		addr;
+	void			*ih;
+	device_t		gpiodev;
+	struct mtx		mtx;
+	int			busy;
+};
+
+#define	AXP_LOCK(sc)	mtx_lock(&(sc)->mtx)
+#define	AXP_UNLOCK(sc)	mtx_unlock(&(sc)->mtx)
+
+static int
+axp81x_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
+{
+	struct axp81x_softc *sc;
+	struct iic_msg msg[2];
+
+	sc = device_get_softc(dev);
+
+	msg[0].slave = sc->addr;
+	msg[0].flags = IIC_M_WR;
+	msg[0].len = 1;
+	msg[0].buf = ®
+
+	msg[1].slave = sc->addr;
+	msg[1].flags = IIC_M_RD;
+	msg[1].len = size;
+	msg[1].buf = data;
+
+	return (iicbus_transfer(dev, msg, 2));
+}
+
+static int
+axp81x_write(device_t dev, uint8_t reg, uint8_t val)
+{
+	struct axp81x_softc *sc;
+	struct iic_msg msg[2];
+
+	sc = device_get_softc(dev);
+
+	msg[0].slave = sc->addr;
+	msg[0].flags = IIC_M_WR;
+	msg[0].len = 1;
+	msg[0].buf = ®
+
+	msg[1].slave = sc->addr;
+	msg[1].flags = IIC_M_WR;
+	msg[1].len = 1;
+	msg[1].buf = &val;
+
+	return (iicbus_transfer(dev, msg, 2));
+}
+
+static void
+axp81x_shutdown(void *devp, int howto)
+{
+	device_t dev;
+
+	if ((howto & RB_POWEROFF) == 0)
+		return;
+
+	dev = devp;
+
+	if (bootverbose)
+		device_printf(dev, "Shutdown AXP81x\n");
+
+	axp81x_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN);
+}
+
+static void
+axp81x_intr(void *arg)
+{
+	struct axp81x_softc *sc;
+	device_t dev;
+	uint8_t val;
+	int error;
+
+	dev = arg;
+	sc = device_get_softc(dev);
+
+	error = axp81x_read(dev, AXP_IRQSTAT5, &val, 1);
+	if (error != 0)
+		return;
+
+	if (val != 0) {
+		if ((val & AXP_IRQSTAT5_POKSIRQ) != 0) {
+			if (bootverbose)
+				device_printf(dev, "Power button pressed\n");
+			shutdown_nice(RB_POWEROFF);
+		}
+		/* Acknowledge */
+		axp81x_write(dev, AXP_IRQSTAT5, val);
+	}
+}
+
+static device_t
+axp81x_gpio_get_bus(device_t dev)
+{
+	struct axp81x_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (sc->gpiodev);
+}
+
+static int
+axp81x_gpio_pin_max(device_t dev, int *maxpin)
+{
+	*maxpin = nitems(axp81x_pins) - 1;
+
+	return (0);
+}
+
+static int
+axp81x_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	snprintf(name, GPIOMAXNAME, "%s", axp81x_pins[pin].name);
+
+	return (0);
+}
+
+static int
+axp81x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	*caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+
+	return (0);
+}
+
+static int
+axp81x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct axp81x_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	AXP_LOCK(sc);
+	error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
+		if (func == AXP_GPIO_FUNC_INPUT)
+			*flags = GPIO_PIN_INPUT;
+		else if (func == AXP_GPIO_FUNC_DRVLO ||
+		    func == AXP_GPIO_FUNC_DRVHI)
+			*flags = GPIO_PIN_OUTPUT;
+		else
+			*flags = 0;
+	}
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp81x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	struct axp81x_softc *sc;
+	uint8_t data;
+	int error;
+
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	AXP_LOCK(sc);
+	error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		data &= ~AXP_GPIO_FUNC;
+		if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) {
+			if ((flags & GPIO_PIN_OUTPUT) == 0)
+				data |= AXP_GPIO_FUNC_INPUT;
+		}
+		error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
+	}
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp81x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+	struct axp81x_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	AXP_LOCK(sc);
+	error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
+		switch (func) {
+		case AXP_GPIO_FUNC_DRVLO:
+			*val = 0;
+			break;
+		case AXP_GPIO_FUNC_DRVHI:
+			*val = 1;
+			break;
+		case AXP_GPIO_FUNC_INPUT:
+			error = axp81x_read(dev, AXP_GPIO_SIGBIT, &data, 1);
+			if (error == 0)
+				*val = (data & (1 << pin)) ? 1 : 0;
+			break;
+		default:
+			error = EIO;
+			break;
+		}
+	}
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp81x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
+{
+	struct axp81x_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	AXP_LOCK(sc);
+	error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
+		switch (func) {
+		case AXP_GPIO_FUNC_DRVLO:
+		case AXP_GPIO_FUNC_DRVHI:
+			data &= ~AXP_GPIO_FUNC;
+			data |= (val << AXP_GPIO_FUNC_SHIFT);
+			break;
+		default:
+			error = EIO;
+			break;
+		}
+	}
+	if (error == 0)
+		error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+
+static int
+axp81x_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	struct axp81x_softc *sc;
+	uint8_t data, func;
+	int error;
+
+	if (pin >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	AXP_LOCK(sc);
+	error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
+	if (error == 0) {
+		func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
+		switch (func) {
+		case AXP_GPIO_FUNC_DRVLO:
+			data &= ~AXP_GPIO_FUNC;
+			data |= (AXP_GPIO_FUNC_DRVHI << AXP_GPIO_FUNC_SHIFT);
+			break;
+		case AXP_GPIO_FUNC_DRVHI:
+			data &= ~AXP_GPIO_FUNC;
+			data |= (AXP_GPIO_FUNC_DRVLO << AXP_GPIO_FUNC_SHIFT);
+			break;
+		default:
+			error = EIO;
+			break;
+		}
+	}
+	if (error == 0)
+		error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
+	AXP_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+axp81x_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent,
+    int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+	if (gpios[0] >= nitems(axp81x_pins))
+		return (EINVAL);
+
+	*pin = gpios[0];
+	*flags = gpios[1];
+
+	return (0);
+}
+
+static phandle_t
+axp81x_get_node(device_t dev, device_t bus)
+{
+	return (ofw_bus_get_node(dev));
+}
+
+static int
+axp81x_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "X-Powers AXP81x Power Management Unit");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+axp81x_attach(device_t dev)
+{
+	struct axp81x_softc *sc;
+	uint8_t chip_id;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	sc->addr = iicbus_get_addr(dev);
+	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+	error = bus_alloc_resources(dev, axp81x_spec, &sc->res);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (error);
+	}
+
+	if (bootverbose) {
+		axp81x_read(dev, AXP_ICTYPE, &chip_id, 1);
+		device_printf(dev, "chip ID 0x%02x\n", chip_id);
+	}
+
+	/* Enable IRQ on short power key press */
+	axp81x_write(dev, AXP_IRQEN1, 0);
+	axp81x_write(dev, AXP_IRQEN2, 0);
+	axp81x_write(dev, AXP_IRQEN3, 0);
+	axp81x_write(dev, AXP_IRQEN4, 0);
+	axp81x_write(dev, AXP_IRQEN5, AXP_IRQEN5_POKSIRQ);
+	axp81x_write(dev, AXP_IRQEN6, 0);
+
+	/* Install interrupt handler */
+	error = bus_setup_intr(dev, sc->res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, axp81x_intr, dev, &sc->ih);
+	if (error != 0) {
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (error);
+	}
+
+	EVENTHANDLER_REGISTER(shutdown_final, axp81x_shutdown, dev,
+	    SHUTDOWN_PRI_LAST);
+
+	sc->gpiodev = gpiobus_attach_bus(dev);
+
+	return (0);
+}
+
+static device_method_t axp81x_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		axp81x_probe),
+	DEVMETHOD(device_attach,	axp81x_attach),
+
+	/* GPIO interface */
+	DEVMETHOD(gpio_get_bus,		axp81x_gpio_get_bus),
+	DEVMETHOD(gpio_pin_max,		axp81x_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getname,	axp81x_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_getcaps,	axp81x_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_getflags,	axp81x_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_setflags,	axp81x_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_get,		axp81x_gpio_pin_get),
+	DEVMETHOD(gpio_pin_set,		axp81x_gpio_pin_set),
+	DEVMETHOD(gpio_pin_toggle,	axp81x_gpio_pin_toggle),
+	DEVMETHOD(gpio_map_gpios,	axp81x_gpio_map_gpios),
+
+	/* OFW bus interface */
+	DEVMETHOD(ofw_bus_get_node,	axp81x_get_node),
+
+	DEVMETHOD_END
+};
+
+static driver_t axp81x_driver = {
+	"axp81x_pmu",
+	axp81x_methods,
+	sizeof(struct axp81x_softc),
+};
+
+static devclass_t axp81x_devclass;
+extern devclass_t ofwgpiobus_devclass, gpioc_devclass;
+extern driver_t ofw_gpiobus_driver, gpioc_driver;
+
+DRIVER_MODULE(axp81x, iicbus, axp81x_driver, axp81x_devclass, 0, 0);
+DRIVER_MODULE(ofw_gpiobus, axp81x_pmu, ofw_gpiobus_driver,
+    ofwgpiobus_devclass, 0, 0);
+DRIVER_MODULE(gpioc, axp81x_pmu, gpioc_driver, gpioc_devclass, 0, 0);
+MODULE_VERSION(axp81x, 1);
+MODULE_DEPEND(axp81x, iicbus, 1, 1, 1);


Property changes on: trunk/sys/arm/allwinner/axp81x.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/console.c
===================================================================
--- trunk/sys/arm/allwinner/console.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/console.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -28,7 +28,7 @@
 /* Simple UART console driver for Allwinner A10 */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/console.c 266337 2014-05-17 18:53:36Z ian $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/console.c 263711 2014-03-25 08:31:47Z ganbold $");
 
 #include <sys/types.h>
 #include <sys/param.h>

Deleted: trunk/sys/arm/allwinner/files.a10
===================================================================
--- trunk/sys/arm/allwinner/files.a10	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/files.a10	2020-03-08 17:23:22 UTC (rev 12402)
@@ -1,23 +0,0 @@
-# $FreeBSD: stable/10/sys/arm/allwinner/files.a10 278727 2015-02-13 22:32:02Z ian $
-kern/kern_clocksource.c			standard
-
-arm/arm/bus_space_asm_generic.S		standard
-arm/arm/bus_space_generic.c		standard
-arm/arm/cpufunc_asm_armv5.S		standard
-arm/arm/cpufunc_asm_arm10.S		standard
-arm/arm/cpufunc_asm_arm11.S		standard
-arm/arm/cpufunc_asm_armv7.S		standard
-
-arm/allwinner/a10_clk.c			standard
-arm/allwinner/a10_common.c		standard
-arm/allwinner/a10_gpio.c		optional	gpio
-arm/allwinner/a10_ehci.c		optional	ehci
-arm/allwinner/a10_machdep.c		standard
-arm/allwinner/a10_sramc.c		standard
-arm/allwinner/a10_wdog.c		standard
-arm/allwinner/a20/a20_cpu_cfg.c 	standard
-arm/allwinner/aintc.c			standard
-arm/allwinner/if_emac.c			optional	emac
-arm/allwinner/timer.c			standard
-arm/arm/bus_space_base.c		standard
-#arm/allwinner/console.c		standard

Added: trunk/sys/arm/allwinner/files.allwinner
===================================================================
--- trunk/sys/arm/allwinner/files.allwinner	                        (rev 0)
+++ trunk/sys/arm/allwinner/files.allwinner	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,55 @@
+# $MidnightBSD$
+kern/kern_clocksource.c			standard
+
+arm/allwinner/a10_ahci.c		optional	ahci
+arm/allwinner/a10_codec.c		optional	sound
+arm/allwinner/a10_common.c		standard
+arm/allwinner/a10_dmac.c		standard
+arm/allwinner/a10_ehci.c		optional	ehci
+arm/allwinner/aw_usbphy.c		optional	ehci
+arm/allwinner/a10_gpio.c		optional	gpio
+arm/allwinner/a10_mmc.c			optional	mmc
+arm/allwinner/a10_sramc.c		standard
+arm/allwinner/aw_nmi.c			optional	intrng
+arm/allwinner/aw_if_dwc.c		optional	dwc
+arm/allwinner/aw_rsb.c			optional	rsb
+arm/allwinner/aw_rtc.c			standard
+arm/allwinner/aw_ts.c			standard
+arm/allwinner/aw_wdog.c			standard
+arm/allwinner/aw_machdep.c		standard
+arm/allwinner/aw_mp.c			optional	smp
+arm/allwinner/axp209.c			optional	axp209
+arm/allwinner/axp81x.c			optional	axp81x
+arm/allwinner/if_awg.c			optional	awg
+arm/allwinner/if_emac.c			optional	emac
+arm/allwinner/sunxi_dma_if.m		standard
+dev/iicbus/twsi/a10_twsi.c		optional	twsi
+dev/usb/controller/generic_ohci.c	optional	ohci
+dev/usb/controller/generic_usb_if.m	optional	ohci
+arm/allwinner/aw_sid.c			standard
+arm/allwinner/aw_thermal.c		standard
+#arm/allwinner/console.c		standard
+
+arm/allwinner/a10_fb.c			optional	vt
+arm/allwinner/a10_hdmi.c		optional	hdmi
+arm/allwinner/a10_hdmiaudio.c		optional	hdmi sound
+arm/arm/hdmi_if.m			optional	hdmi
+
+arm/allwinner/aw_reset.c		standard
+arm/allwinner/aw_ccu.c			standard
+arm/allwinner/clk/aw_ahbclk.c		standard
+arm/allwinner/clk/aw_apbclk.c		standard
+arm/allwinner/clk/aw_axiclk.c		standard
+arm/allwinner/clk/aw_codecclk.c		standard
+arm/allwinner/clk/aw_cpuclk.c		standard
+arm/allwinner/clk/aw_cpusclk.c		standard
+arm/allwinner/clk/aw_debeclk.c		standard
+arm/allwinner/clk/aw_gate.c		standard
+arm/allwinner/clk/aw_gmacclk.c		standard
+arm/allwinner/clk/aw_hdmiclk.c		standard
+arm/allwinner/clk/aw_lcdclk.c		standard
+arm/allwinner/clk/aw_modclk.c		standard
+arm/allwinner/clk/aw_mmcclk.c		standard
+arm/allwinner/clk/aw_oscclk.c		standard
+arm/allwinner/clk/aw_pll.c		standard
+arm/allwinner/clk/aw_usbclk.c		standard


Property changes on: trunk/sys/arm/allwinner/files.allwinner
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/files.allwinner_up
===================================================================
--- trunk/sys/arm/allwinner/files.allwinner_up	                        (rev 0)
+++ trunk/sys/arm/allwinner/files.allwinner_up	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,3 @@
+# $MidnightBSD$
+
+arm/allwinner/timer.c			standard


Property changes on: trunk/sys/arm/allwinner/files.allwinner_up
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/h3/files.h3
===================================================================
--- trunk/sys/arm/allwinner/h3/files.h3	                        (rev 0)
+++ trunk/sys/arm/allwinner/h3/files.h3	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,4 @@
+# $MidnightBSD$
+
+arm/allwinner/h3/h3_padconf.c		standard
+arm/allwinner/h3/h3_r_padconf.c		standard


Property changes on: trunk/sys/arm/allwinner/h3/files.h3
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/h3/h3_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/h3/h3_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/h3/h3_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,148 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/h3/h3_padconf.c 299688 2016-05-13 18:20:54Z manu $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#ifdef SOC_ALLWINNER_H3
+
+const static struct allwinner_pins h3_pins[] = {
+	{"PA0",  0, 0,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint", NULL}},
+	{"PA1",  0, 1,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint", NULL}},
+	{"PA2",  0, 2,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint", NULL}},
+	{"PA3",  0, 3,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint", NULL}},
+	{"PA4",  0, 4,  {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint", NULL}},
+	{"PA5",  0, 5,  {"gpio_in", "gpio_out", "uart0", "pwm0", NULL, NULL, "eint", NULL}},
+	{"PA6",  0, 6,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "eint", NULL}},
+	{"PA7",  0, 7,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "eint", NULL}},
+	{"PA8",  0, 8,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "eint", NULL}},
+	{"PA9",  0, 9,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "eint", NULL}},
+	{"PA10", 0, 10, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "eint", NULL}},
+	{"PA11", 0, 11, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "eint", NULL}},
+	{"PA12", 0, 12, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "eint", NULL}},
+	{"PA13", 0, 13, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint", NULL}},
+	{"PA14", 0, 14, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint", NULL}},
+	{"PA15", 0, 15, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint", NULL}},
+	{"PA16", 0, 16, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint", NULL}},
+	{"PA17", 0, 17, {"gpio_in", "gpio_out", "spdif", NULL, NULL, NULL, "eint", NULL}},
+	{"PA18", 0, 18, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "eint", NULL}},
+	{"PA19", 0, 19, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "eint", NULL}},
+	{"PA20", 0, 20, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "eint", NULL}},
+	{"PA21", 0, 21, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "eint", NULL}},
+
+	{"PC0",  2, 0,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC1",  2, 1,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC2",  2, 2,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC3",  2, 3,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
+	{"PC4",  2, 4,  {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}},
+	{"PC5",  2, 5,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC6",  2, 6,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC7",  2, 7,  {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}},
+	{"PC8",  2, 8,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC9",  2, 9,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC10", 2, 10, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC11", 2, 11, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC12", 2, 12, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC13", 2, 13, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC14", 2, 14, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC15", 2, 15, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+	{"PC16", 2, 16, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
+
+	{"PD0",  3, 0,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD1",  3, 1,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD2",  3, 2,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD3",  3, 3,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD4",  3, 4,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD5",  3, 5,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD6",  3, 6,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD7",  3, 7,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD8",  3, 8,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD9",  3, 9,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD10", 3, 10, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD11", 3, 11, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD12", 3, 12, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD13", 3, 13, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD14", 3, 14, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD15", 3, 15, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD16", 3, 16, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+	{"PD17", 3, 17, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
+
+	{"PE0",  4, 0,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE1",  4, 1,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE2",  4, 2,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE3",  4, 3,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE4",  4, 4,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE5",  4, 5,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE6",  4, 6,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE7",  4, 7,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE8",  4, 8,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE9",  4, 9,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
+	{"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}},
+	{"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}},
+	{"PE14", 4, 14, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+	{"PE15", 4, 15, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+
+	{"PF0",  5, 0,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
+	{"PF1",  5, 1,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
+	{"PF2",  5, 2,  {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}},
+	{"PF3",  5, 3,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
+	{"PF4",  5, 4,  {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}},
+	{"PF5",  5, 5,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
+	{"PF6",  5, 6,  {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
+
+	{"PG0",  6, 0,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG1",  6, 1,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG2",  6, 2,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG3",  6, 3,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG4",  6, 4,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG5",  6, 5,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG6",  6, 6,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG7",  6, 7,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG8",  6, 8,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG9",  6, 9,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG10", 6, 10, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG11", 6, 11, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG12", 6, 11, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, NULL, "eint"}},
+	{"PG13", 6, 11, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, NULL, "eint"}},
+};
+
+const struct allwinner_padconf h3_padconf = {
+	.npins = nitems(h3_pins),
+	.pins = h3_pins,
+};
+
+#endif /* SOC_ALLWINNER_H3 */


Property changes on: trunk/sys/arm/allwinner/h3/h3_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/h3/h3_r_padconf.c
===================================================================
--- trunk/sys/arm/allwinner/h3/h3_r_padconf.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/h3/h3_r_padconf.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,61 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu at freebsd.org>
+ * 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 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/h3/h3_r_padconf.c 299688 2016-05-13 18:20:54Z manu $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+
+#include <arm/allwinner/allwinner_pinctrl.h>
+
+#ifdef SOC_ALLWINNER_H3
+
+const static struct allwinner_pins h3_r_pins[] = {
+	{"PL0",  0, 0,  {"gpio_in", "gpio_out", "s_twi", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL1",  0, 1,  {"gpio_in", "gpio_out", "s_twi", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL2",  0, 2,  {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL3",  0, 3,  {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL4",  0, 4,  {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL5",  0, 5,  {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL6",  0, 6,  {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL7",  0, 7,  {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL8",  0, 8,  {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, "eint"}},
+	{"PL9",  0, 9,  {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, "eint"}},
+	{"PL10", 0, 10, {"gpio_in", "gpio_out", "s_pwm", NULL, NULL, NULL, NULL, "eint"}},
+	{"PL11", 0, 11, {"gpio_in", "gpio_out", "s_cir_rx", NULL, NULL, NULL, NULL, "eint"}},
+};
+
+const struct allwinner_padconf h3_r_padconf = {
+	.npins = nitems(h3_r_pins),
+	.pins = h3_r_pins,
+};
+
+#endif /* SOC_ALLWINNER_H3 */


Property changes on: trunk/sys/arm/allwinner/h3/h3_r_padconf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/h3/std.h3
===================================================================
--- trunk/sys/arm/allwinner/h3/std.h3	                        (rev 0)
+++ trunk/sys/arm/allwinner/h3/std.h3	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,15 @@
+# Allwinner H3 common options
+# $MidnightBSD$
+
+cpu		CPU_CORTEXA
+machine 	arm armv6
+makeoptions	CONF_CFLAGS="-march=armv7a"
+
+makeoptions	KERNVIRTADDR=0xc0200000
+options 	KERNVIRTADDR=0xc0200000
+
+options 	IPI_IRQ_START=0
+options 	IPI_IRQ_END=15
+
+files		"../allwinner/files.allwinner"
+files		"../allwinner/h3/files.h3"


Property changes on: trunk/sys/arm/allwinner/h3/std.h3
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/if_awg.c
===================================================================
--- trunk/sys/arm/allwinner/if_awg.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/if_awg.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,1425 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/if_awg.c 329648 2018-02-20 18:12:07Z gonzo $
+ */
+
+/*
+ * Allwinner Gigabit Ethernet MAC (EMAC) controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/if_awg.c 329648 2018-02-20 18:12:07Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/module.h>
+#include <sys/taskqueue.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/if_awgreg.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/regulator/regulator.h>
+
+#include "miibus_if.h"
+
+#define	RD4(sc, reg)		bus_read_4((sc)->res[0], (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res[0], (reg), (val))
+
+#define	AWG_LOCK(sc)		mtx_lock(&(sc)->mtx)
+#define	AWG_UNLOCK(sc)		mtx_unlock(&(sc)->mtx);
+#define	AWG_ASSERT_LOCKED(sc)	mtx_assert(&(sc)->mtx, MA_OWNED)
+#define	AWG_ASSERT_UNLOCKED(sc)	mtx_assert(&(sc)->mtx, MA_NOTOWNED)
+
+#define	DESC_ALIGN		4
+#define	TX_DESC_COUNT		256
+#define	TX_DESC_SIZE		(sizeof(struct emac_desc) * TX_DESC_COUNT)
+#define	RX_DESC_COUNT		256
+#define	RX_DESC_SIZE		(sizeof(struct emac_desc) * RX_DESC_COUNT)
+
+#define	DESC_OFF(n)		((n) * sizeof(struct emac_desc))
+#define	TX_NEXT(n)		(((n) + 1) & (TX_DESC_COUNT - 1))
+#define	TX_SKIP(n, o)		(((n) + (o)) & (TX_DESC_COUNT - 1))
+#define	RX_NEXT(n)		(((n) + 1) & (RX_DESC_COUNT - 1))
+
+#define	TX_MAX_SEGS		20
+
+#define	SOFT_RST_RETRY		1000
+#define	MII_BUSY_RETRY		1000
+#define	MDIO_FREQ		2500000
+
+#define	BURST_LEN_DEFAULT	8
+#define	RX_TX_PRI_DEFAULT	0
+#define	PAUSE_TIME_DEFAULT	0x400
+#define	TX_INTERVAL_DEFAULT	64
+
+/* Burst length of RX and TX DMA transfers */
+static int awg_burst_len = BURST_LEN_DEFAULT;
+TUNABLE_INT("hw.awg.burst_len", &awg_burst_len);
+
+/* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */
+static int awg_rx_tx_pri = RX_TX_PRI_DEFAULT;
+TUNABLE_INT("hw.awg.rx_tx_pri", &awg_rx_tx_pri);
+
+/* Pause time field in the transmitted control frame */
+static int awg_pause_time = PAUSE_TIME_DEFAULT;
+TUNABLE_INT("hw.awg.pause_time", &awg_pause_time);
+
+/* Request a TX interrupt every <n> descriptors */
+static int awg_tx_interval = TX_INTERVAL_DEFAULT;
+TUNABLE_INT("hw.awg.tx_interval", &awg_tx_interval);
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun8i-a83t-emac",		1 },
+	{ NULL,					0 }
+};
+
+struct awg_bufmap {
+	bus_dmamap_t		map;
+	struct mbuf		*mbuf;
+};
+
+struct awg_txring {
+	bus_dma_tag_t		desc_tag;
+	bus_dmamap_t		desc_map;
+	struct emac_desc	*desc_ring;
+	bus_addr_t		desc_ring_paddr;
+	bus_dma_tag_t		buf_tag;
+	struct awg_bufmap	buf_map[TX_DESC_COUNT];
+	u_int			cur, next, queued;
+};
+
+struct awg_rxring {
+	bus_dma_tag_t		desc_tag;
+	bus_dmamap_t		desc_map;
+	struct emac_desc	*desc_ring;
+	bus_addr_t		desc_ring_paddr;
+	bus_dma_tag_t		buf_tag;
+	struct awg_bufmap	buf_map[RX_DESC_COUNT];
+	u_int			cur;
+};
+
+struct awg_softc {
+	struct resource		*res[2];
+	struct mtx		mtx;
+	if_t			ifp;
+	device_t		dev;
+	device_t		miibus;
+	struct callout		stat_ch;
+	struct task		link_task;
+	void			*ih;
+	u_int			mdc_div_ratio_m;
+	int			link;
+	int			if_flags;
+
+	struct awg_txring	tx;
+	struct awg_rxring	rx;
+};
+
+static struct resource_spec awg_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static int
+awg_miibus_readreg(device_t dev, int phy, int reg)
+{
+	struct awg_softc *sc;
+	int retry, val;
+
+	sc = device_get_softc(dev);
+	val = 0;
+
+	WR4(sc, EMAC_MII_CMD,
+	    (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) |
+	    (phy << PHY_ADDR_SHIFT) |
+	    (reg << PHY_REG_ADDR_SHIFT) |
+	    MII_BUSY);
+	for (retry = MII_BUSY_RETRY; retry > 0; retry--) {
+		if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) {
+			val = RD4(sc, EMAC_MII_DATA);
+			break;
+		}
+		DELAY(10);
+	}
+
+	if (retry == 0)
+		device_printf(dev, "phy read timeout, phy=%d reg=%d\n",
+		    phy, reg);
+
+	return (val);
+}
+
+static int
+awg_miibus_writereg(device_t dev, int phy, int reg, int val)
+{
+	struct awg_softc *sc;
+	int retry;
+
+	sc = device_get_softc(dev);
+
+	WR4(sc, EMAC_MII_DATA, val);
+	WR4(sc, EMAC_MII_CMD,
+	    (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) |
+	    (phy << PHY_ADDR_SHIFT) |
+	    (reg << PHY_REG_ADDR_SHIFT) |
+	    MII_WR | MII_BUSY);
+	for (retry = MII_BUSY_RETRY; retry > 0; retry--) {
+		if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0)
+			break;
+		DELAY(10);
+	}
+
+	if (retry == 0)
+		device_printf(dev, "phy write timeout, phy=%d reg=%d\n",
+		    phy, reg);
+
+	return (0);
+}
+
+static void
+awg_update_link_locked(struct awg_softc *sc)
+{
+	struct mii_data *mii;
+	uint32_t val;
+
+	AWG_ASSERT_LOCKED(sc);
+
+	if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0)
+		return;
+	mii = device_get_softc(sc->miibus);
+
+	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+	    (IFM_ACTIVE | IFM_AVALID)) {
+		switch (IFM_SUBTYPE(mii->mii_media_active)) {
+		case IFM_1000_T:
+		case IFM_1000_SX:
+		case IFM_100_TX:
+		case IFM_10_T:
+			sc->link = 1;
+			break;
+		default:
+			sc->link = 0;
+			break;
+		}
+	} else
+		sc->link = 0;
+
+	if (sc->link == 0)
+		return;
+
+	val = RD4(sc, EMAC_BASIC_CTL_0);
+	val &= ~(BASIC_CTL_SPEED | BASIC_CTL_DUPLEX);
+
+	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
+	    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)
+		val |= BASIC_CTL_SPEED_1000 << BASIC_CTL_SPEED_SHIFT;
+	else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
+		val |= BASIC_CTL_SPEED_100 << BASIC_CTL_SPEED_SHIFT;
+	else
+		val |= BASIC_CTL_SPEED_10 << BASIC_CTL_SPEED_SHIFT;
+
+	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
+		val |= BASIC_CTL_DUPLEX;
+
+	WR4(sc, EMAC_BASIC_CTL_0, val);
+
+	val = RD4(sc, EMAC_RX_CTL_0);
+	val &= ~RX_FLOW_CTL_EN;
+	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
+		val |= RX_FLOW_CTL_EN;
+	WR4(sc, EMAC_RX_CTL_0, val);
+
+	val = RD4(sc, EMAC_TX_FLOW_CTL);
+	val &= ~(PAUSE_TIME|TX_FLOW_CTL_EN);
+	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
+		val |= TX_FLOW_CTL_EN;
+	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
+		val |= awg_pause_time << PAUSE_TIME_SHIFT;
+	WR4(sc, EMAC_TX_FLOW_CTL, val);
+}
+
+static void
+awg_link_task(void *arg, int pending)
+{
+	struct awg_softc *sc;
+
+	sc = arg;
+
+	AWG_LOCK(sc);
+	awg_update_link_locked(sc);
+	AWG_UNLOCK(sc);
+}
+
+static void
+awg_miibus_statchg(device_t dev)
+{
+	struct awg_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	taskqueue_enqueue(taskqueue_swi, &sc->link_task);
+}
+
+static void
+awg_media_status(if_t ifp, struct ifmediareq *ifmr)
+{
+	struct awg_softc *sc;
+	struct mii_data *mii;
+
+	sc = if_getsoftc(ifp);
+	mii = device_get_softc(sc->miibus);
+
+	AWG_LOCK(sc);
+	mii_pollstat(mii);
+	ifmr->ifm_active = mii->mii_media_active;
+	ifmr->ifm_status = mii->mii_media_status;
+	AWG_UNLOCK(sc);
+}
+
+static int
+awg_media_change(if_t ifp)
+{
+	struct awg_softc *sc;
+	struct mii_data *mii;
+	int error;
+
+	sc = if_getsoftc(ifp);
+	mii = device_get_softc(sc->miibus);
+
+	AWG_LOCK(sc);
+	error = mii_mediachg(mii);
+	AWG_UNLOCK(sc);
+
+	return (error);
+}
+
+static void
+awg_setup_txdesc(struct awg_softc *sc, int index, int flags, bus_addr_t paddr,
+    u_int len)
+{
+	uint32_t status, size;
+
+	if (paddr == 0 || len == 0) {
+		status = 0;
+		size = 0;
+		--sc->tx.queued;
+	} else {
+		status = TX_DESC_CTL;
+		size = flags | len;
+		if ((index & (awg_tx_interval - 1)) == 0)
+			size |= htole32(TX_INT_CTL);
+		++sc->tx.queued;
+	}
+
+	sc->tx.desc_ring[index].addr = htole32((uint32_t)paddr);
+	sc->tx.desc_ring[index].size = htole32(size);
+	sc->tx.desc_ring[index].status = htole32(status);
+}
+
+static int
+awg_setup_txbuf(struct awg_softc *sc, int index, struct mbuf **mp)
+{
+	bus_dma_segment_t segs[TX_MAX_SEGS];
+	int error, nsegs, cur, i, flags;
+	u_int csum_flags;
+	struct mbuf *m;
+
+	m = *mp;
+	error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag,
+	    sc->tx.buf_map[index].map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+	if (error == EFBIG) {
+		m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS);
+		if (m == NULL) {
+			device_printf(sc->dev, "awg_setup_txbuf: m_collapse failed\n");
+			return (0);
+		}
+		*mp = m;
+		error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag,
+		    sc->tx.buf_map[index].map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+	}
+	if (error != 0) {
+		device_printf(sc->dev, "awg_setup_txbuf: bus_dmamap_load_mbuf_sg failed\n");
+		return (0);
+	}
+
+	bus_dmamap_sync(sc->tx.buf_tag, sc->tx.buf_map[index].map,
+	    BUS_DMASYNC_PREWRITE);
+
+	flags = TX_FIR_DESC;
+	if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) {
+		if ((m->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) != 0)
+			csum_flags = TX_CHECKSUM_CTL_FULL;
+		else
+			csum_flags = TX_CHECKSUM_CTL_IP;
+		flags |= (csum_flags << TX_CHECKSUM_CTL_SHIFT);
+	}
+
+	for (cur = index, i = 0; i < nsegs; i++) {
+		sc->tx.buf_map[cur].mbuf = (i == 0 ? m : NULL);
+		if (i == nsegs - 1)
+			flags |= TX_LAST_DESC;
+		awg_setup_txdesc(sc, cur, flags, segs[i].ds_addr,
+		    segs[i].ds_len);
+		flags &= ~TX_FIR_DESC;
+		cur = TX_NEXT(cur);
+	}
+
+	return (nsegs);
+}
+
+static void
+awg_setup_rxdesc(struct awg_softc *sc, int index, bus_addr_t paddr)
+{
+	uint32_t status, size;
+
+	status = RX_DESC_CTL;
+	size = MCLBYTES - 1;
+
+	sc->rx.desc_ring[index].addr = htole32((uint32_t)paddr);
+	sc->rx.desc_ring[index].size = htole32(size);
+	sc->rx.desc_ring[index].next =
+	    htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(index)));
+	sc->rx.desc_ring[index].status = htole32(status);
+}
+
+static int
+awg_setup_rxbuf(struct awg_softc *sc, int index, struct mbuf *m)
+{
+	bus_dma_segment_t seg;
+	int error, nsegs;
+
+	m_adj(m, ETHER_ALIGN);
+
+	error = bus_dmamap_load_mbuf_sg(sc->rx.buf_tag,
+	    sc->rx.buf_map[index].map, m, &seg, &nsegs, 0);
+	if (error != 0)
+		return (error);
+
+	bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map,
+	    BUS_DMASYNC_PREREAD);
+
+	sc->rx.buf_map[index].mbuf = m;
+	awg_setup_rxdesc(sc, index, seg.ds_addr);
+
+	return (0);
+}
+
+static struct mbuf *
+awg_alloc_mbufcl(struct awg_softc *sc)
+{
+	struct mbuf *m;
+
+	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (m != NULL)
+		m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
+
+	return (m);
+}
+
+static void
+awg_start_locked(struct awg_softc *sc)
+{
+	struct mbuf *m;
+	uint32_t val;
+	if_t ifp;
+	int cnt, nsegs;
+
+	AWG_ASSERT_LOCKED(sc);
+
+	if (!sc->link)
+		return;
+
+	ifp = sc->ifp;
+
+	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
+	    IFF_DRV_RUNNING)
+		return;
+
+	for (cnt = 0; ; cnt++) {
+		if (sc->tx.queued >= TX_DESC_COUNT - TX_MAX_SEGS) {
+			if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
+			break;
+		}
+
+		m = if_dequeue(ifp);
+		if (m == NULL)
+			break;
+
+		nsegs = awg_setup_txbuf(sc, sc->tx.cur, &m);
+		if (nsegs == 0) {
+			if_sendq_prepend(ifp, m);
+			break;
+		}
+		if_bpfmtap(ifp, m);
+		sc->tx.cur = TX_SKIP(sc->tx.cur, nsegs);
+	}
+
+	if (cnt != 0) {
+		bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map,
+		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+		/* Start and run TX DMA */
+		val = RD4(sc, EMAC_TX_CTL_1);
+		WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_START);
+	}
+}
+
+static void
+awg_start(if_t ifp)
+{
+	struct awg_softc *sc;
+
+	sc = if_getsoftc(ifp);
+
+	AWG_LOCK(sc);
+	awg_start_locked(sc);
+	AWG_UNLOCK(sc);
+}
+
+static void
+awg_tick(void *softc)
+{
+	struct awg_softc *sc;
+	struct mii_data *mii;
+	if_t ifp;
+	int link;
+
+	sc = softc;
+	ifp = sc->ifp;
+	mii = device_get_softc(sc->miibus);
+
+	AWG_ASSERT_LOCKED(sc);
+
+	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
+		return;
+
+	link = sc->link;
+	mii_tick(mii);
+	if (sc->link && !link)
+		awg_start_locked(sc);
+
+	callout_reset(&sc->stat_ch, hz, awg_tick, sc);
+}
+
+/* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */
+static uint32_t
+bitrev32(uint32_t x)
+{
+	x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
+	x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
+	x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
+	x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
+
+	return (x >> 16) | (x << 16);
+}
+
+static void
+awg_setup_rxfilter(struct awg_softc *sc)
+{
+	uint32_t val, crc, hashreg, hashbit, hash[2], machi, maclo;
+	int mc_count, mcnt, i;
+	uint8_t *eaddr, *mta;
+	if_t ifp;
+
+	AWG_ASSERT_LOCKED(sc);
+
+	ifp = sc->ifp;
+	val = 0;
+	hash[0] = hash[1] = 0;
+
+	mc_count = if_multiaddr_count(ifp, -1);
+
+	if (if_getflags(ifp) & IFF_PROMISC)
+		val |= DIS_ADDR_FILTER;
+	else if (if_getflags(ifp) & IFF_ALLMULTI) {
+		val |= RX_ALL_MULTICAST;
+		hash[0] = hash[1] = ~0;
+	} else if (mc_count > 0) {
+		val |= HASH_MULTICAST;
+
+		mta = malloc(sizeof(unsigned char) * ETHER_ADDR_LEN * mc_count,
+		    M_DEVBUF, M_NOWAIT);
+		if (mta == NULL) {
+			if_printf(ifp,
+			    "failed to allocate temporary multicast list\n");
+			return;
+		}
+
+		if_multiaddr_array(ifp, mta, &mcnt, mc_count);
+		for (i = 0; i < mcnt; i++) {
+			crc = ether_crc32_le(mta + (i * ETHER_ADDR_LEN),
+			    ETHER_ADDR_LEN) & 0x7f;
+			crc = bitrev32(~crc) >> 26;
+			hashreg = (crc >> 5);
+			hashbit = (crc & 0x1f);
+			hash[hashreg] |= (1 << hashbit);
+		}
+
+		free(mta, M_DEVBUF);
+	}
+
+	/* Write our unicast address */
+	eaddr = IF_LLADDR(ifp);
+	machi = (eaddr[5] << 8) | eaddr[4];
+	maclo = (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) |
+	   (eaddr[0] << 0);
+	WR4(sc, EMAC_ADDR_HIGH(0), machi);
+	WR4(sc, EMAC_ADDR_LOW(0), maclo);
+
+	/* Multicast hash filters */
+	WR4(sc, EMAC_RX_HASH_0, hash[1]);
+	WR4(sc, EMAC_RX_HASH_1, hash[0]);
+
+	/* RX frame filter config */
+	WR4(sc, EMAC_RX_FRM_FLT, val);
+}
+
+static void
+awg_init_locked(struct awg_softc *sc)
+{
+	struct mii_data *mii;
+	uint32_t val;
+	if_t ifp;
+
+	mii = device_get_softc(sc->miibus);
+	ifp = sc->ifp;
+
+	AWG_ASSERT_LOCKED(sc);
+
+	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
+		return;
+
+	awg_setup_rxfilter(sc);
+
+	/* Configure DMA burst length and priorities */
+	val = awg_burst_len << BASIC_CTL_BURST_LEN_SHIFT;
+	if (awg_rx_tx_pri)
+		val |= BASIC_CTL_RX_TX_PRI;
+	WR4(sc, EMAC_BASIC_CTL_1, val);
+
+	/* Enable interrupts */
+	WR4(sc, EMAC_INT_EN, RX_INT_EN | TX_INT_EN | TX_BUF_UA_INT_EN);
+
+	/* Enable transmit DMA */
+	val = RD4(sc, EMAC_TX_CTL_1);
+	WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_EN | TX_MD);
+
+	/* Enable receive DMA */
+	val = RD4(sc, EMAC_RX_CTL_1);
+	WR4(sc, EMAC_RX_CTL_1, val | RX_DMA_EN | RX_MD);
+
+	/* Enable transmitter */
+	val = RD4(sc, EMAC_TX_CTL_0);
+	WR4(sc, EMAC_TX_CTL_0, val | TX_EN);
+
+	/* Enable receiver */
+	val = RD4(sc, EMAC_RX_CTL_0);
+	WR4(sc, EMAC_RX_CTL_0, val | RX_EN | CHECK_CRC);
+
+	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
+
+	mii_mediachg(mii);
+	callout_reset(&sc->stat_ch, hz, awg_tick, sc);
+}
+
+static void
+awg_init(void *softc)
+{
+	struct awg_softc *sc;
+
+	sc = softc;
+
+	AWG_LOCK(sc);
+	awg_init_locked(sc);
+	AWG_UNLOCK(sc);
+}
+
+static void
+awg_stop(struct awg_softc *sc)
+{
+	if_t ifp;
+	uint32_t val;
+
+	AWG_ASSERT_LOCKED(sc);
+
+	ifp = sc->ifp;
+
+	callout_stop(&sc->stat_ch);
+
+	/* Stop transmit DMA and flush data in the TX FIFO */
+	val = RD4(sc, EMAC_TX_CTL_1);
+	val &= ~TX_DMA_EN;
+	val |= FLUSH_TX_FIFO;
+	WR4(sc, EMAC_TX_CTL_1, val);
+
+	/* Disable transmitter */
+	val = RD4(sc, EMAC_TX_CTL_0);
+	WR4(sc, EMAC_TX_CTL_0, val & ~TX_EN);
+
+	/* Disable receiver */
+	val = RD4(sc, EMAC_RX_CTL_0);
+	WR4(sc, EMAC_RX_CTL_0, val & ~RX_EN);
+
+	/* Disable interrupts */
+	WR4(sc, EMAC_INT_EN, 0);
+
+	/* Disable transmit DMA */
+	val = RD4(sc, EMAC_TX_CTL_1);
+	WR4(sc, EMAC_TX_CTL_1, val & ~TX_DMA_EN);
+
+	/* Disable receive DMA */
+	val = RD4(sc, EMAC_RX_CTL_1);
+	WR4(sc, EMAC_RX_CTL_1, val & ~RX_DMA_EN);
+
+	sc->link = 0;
+
+	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+}
+
+static void
+awg_rxintr(struct awg_softc *sc)
+{
+	if_t ifp;
+	struct mbuf *m, *m0;
+	int error, index, len;
+	uint32_t status;
+
+	ifp = sc->ifp;
+
+	bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	for (index = sc->rx.cur; ; index = RX_NEXT(index)) {
+		status = le32toh(sc->rx.desc_ring[index].status);
+		if ((status & RX_DESC_CTL) != 0)
+			break;
+
+		bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map,
+		    BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->rx.buf_tag, sc->rx.buf_map[index].map);
+
+		len = (status & RX_FRM_LEN) >> RX_FRM_LEN_SHIFT;
+		if (len != 0) {
+			m = sc->rx.buf_map[index].mbuf;
+			m->m_pkthdr.rcvif = ifp;
+			m->m_pkthdr.len = len;
+			m->m_len = len;
+			if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+
+			if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0 &&
+			    (status & RX_FRM_TYPE) != 0) {
+				m->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
+				if ((status & RX_HEADER_ERR) == 0)
+					m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+				if ((status & RX_PAYLOAD_ERR) == 0) {
+					m->m_pkthdr.csum_flags |=
+					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+					m->m_pkthdr.csum_data = 0xffff;
+				}
+			}
+
+			AWG_UNLOCK(sc);
+			if_input(ifp, m);
+			AWG_LOCK(sc);
+		}
+
+		if ((m0 = awg_alloc_mbufcl(sc)) != NULL) {
+			error = awg_setup_rxbuf(sc, index, m0);
+			if (error != 0) {
+				/* XXX hole in RX ring */
+			}
+		} else
+			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
+	}
+
+	if (index != sc->rx.cur) {
+		bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map,
+		    BUS_DMASYNC_PREWRITE);
+	}
+
+	sc->rx.cur = index;
+}
+
+static void
+awg_txintr(struct awg_softc *sc)
+{
+	struct awg_bufmap *bmap;
+	struct emac_desc *desc;
+	uint32_t status;
+	if_t ifp;
+	int i;
+
+	AWG_ASSERT_LOCKED(sc);
+
+	bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	ifp = sc->ifp;
+	for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) {
+		desc = &sc->tx.desc_ring[i];
+		status = le32toh(desc->status);
+		if ((status & TX_DESC_CTL) != 0)
+			break;
+		bmap = &sc->tx.buf_map[i];
+		if (bmap->mbuf != NULL) {
+			bus_dmamap_sync(sc->tx.buf_tag, bmap->map,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->tx.buf_tag, bmap->map);
+			m_freem(bmap->mbuf);
+			bmap->mbuf = NULL;
+		}
+		awg_setup_txdesc(sc, i, 0, 0, 0);
+		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
+		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+	}
+
+	sc->tx.next = i;
+
+	bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map,
+	    BUS_DMASYNC_PREWRITE);
+}
+
+static void
+awg_intr(void *arg)
+{
+	struct awg_softc *sc;
+	uint32_t val;
+
+	sc = arg;
+
+	AWG_LOCK(sc);
+	val = RD4(sc, EMAC_INT_STA);
+	WR4(sc, EMAC_INT_STA, val);
+
+	if (val & RX_INT)
+		awg_rxintr(sc);
+
+	if (val & (TX_INT|TX_BUF_UA_INT)) {
+		awg_txintr(sc);
+		if (!if_sendq_empty(sc->ifp))
+			awg_start_locked(sc);
+	}
+
+	AWG_UNLOCK(sc);
+}
+
+static int
+awg_ioctl(if_t ifp, u_long cmd, caddr_t data)
+{
+	struct awg_softc *sc;
+	struct mii_data *mii;
+	struct ifreq *ifr;
+	int flags, mask, error;
+
+	sc = if_getsoftc(ifp);
+	mii = device_get_softc(sc->miibus);
+	ifr = (struct ifreq *)data;
+	error = 0;
+
+	switch (cmd) {
+	case SIOCSIFFLAGS:
+		AWG_LOCK(sc);
+		if (if_getflags(ifp) & IFF_UP) {
+			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
+				flags = if_getflags(ifp) ^ sc->if_flags;
+				if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0)
+					awg_setup_rxfilter(sc);
+			} else
+				awg_init_locked(sc);
+		} else {
+			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
+				awg_stop(sc);
+		}
+		sc->if_flags = if_getflags(ifp);
+		AWG_UNLOCK(sc);
+		break;
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
+			AWG_LOCK(sc);
+			awg_setup_rxfilter(sc);
+			AWG_UNLOCK(sc);
+		}
+		break;
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+		break;
+	case SIOCSIFCAP:
+		mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
+		if (mask & IFCAP_VLAN_MTU)
+			if_togglecapenable(ifp, IFCAP_VLAN_MTU);
+		if (mask & IFCAP_RXCSUM)
+			if_togglecapenable(ifp, IFCAP_RXCSUM);
+		if (mask & IFCAP_TXCSUM)
+			if_togglecapenable(ifp, IFCAP_TXCSUM);
+		if ((if_getcapenable(ifp) & (IFCAP_RXCSUM|IFCAP_TXCSUM)) != 0)
+			if_sethwassistbits(ifp, CSUM_IP, 0);
+		else
+			if_sethwassistbits(ifp, 0, CSUM_IP);
+		break;
+	default:
+		error = ether_ioctl(ifp, cmd, data);
+		break;
+	}
+
+	return (error);
+}
+
+static int
+awg_setup_extres(device_t dev)
+{
+	struct awg_softc *sc;
+	hwreset_t rst_ahb;
+	clk_t clk_ahb, clk_tx, clk_tx_parent;
+	regulator_t reg;
+	const char *tx_parent_name;
+	char *phy_type;
+	phandle_t node;
+	uint64_t freq;
+	int error, div;
+
+	sc = device_get_softc(dev);
+	node = ofw_bus_get_node(dev);
+	rst_ahb = NULL;
+	clk_ahb = NULL;
+	clk_tx = NULL;
+	clk_tx_parent = NULL;
+	reg = NULL;
+	phy_type = NULL;
+
+	/* Get AHB clock and reset resources */
+	error = hwreset_get_by_ofw_name(dev, 0, "ahb", &rst_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot get ahb reset\n");
+		goto fail;
+	}
+	error = clk_get_by_ofw_name(dev, 0, "ahb", &clk_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot get ahb clock\n");
+		goto fail;
+	}
+	
+	/* Configure PHY for MII or RGMII mode */
+	if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type)) {
+		if (bootverbose)
+			device_printf(dev, "PHY type: %s\n", phy_type);
+
+		if (strcmp(phy_type, "rgmii") == 0)
+			tx_parent_name = "emac_int_tx";
+		else
+			tx_parent_name = "mii_phy_tx";
+		OF_prop_free(phy_type);
+
+		/* Get the TX clock */
+		error = clk_get_by_ofw_name(dev, 0, "tx", &clk_tx);
+		if (error != 0) {
+			device_printf(dev, "cannot get tx clock\n");
+			goto fail;
+		}
+
+		/* Find the desired parent clock based on phy-mode property */
+		error = clk_get_by_name(dev, tx_parent_name, &clk_tx_parent);
+		if (error != 0) {
+			device_printf(dev, "cannot get clock '%s'\n",
+			    tx_parent_name);
+			goto fail;
+		}
+
+		/* Set TX clock parent */
+		error = clk_set_parent_by_clk(clk_tx, clk_tx_parent);
+		if (error != 0) {
+			device_printf(dev, "cannot set tx clock parent\n");
+			goto fail;
+		}
+
+		/* Enable TX clock */
+		error = clk_enable(clk_tx);
+		if (error != 0) {
+			device_printf(dev, "cannot enable tx clock\n");
+			goto fail;
+		}
+	}
+
+	/* Enable AHB clock */
+	error = clk_enable(clk_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot enable ahb clock\n");
+		goto fail;
+	}
+
+	/* De-assert reset */
+	error = hwreset_deassert(rst_ahb);
+	if (error != 0) {
+		device_printf(dev, "cannot de-assert ahb reset\n");
+		goto fail;
+	}
+
+	/* Enable PHY regulator if applicable */
+	if (regulator_get_by_ofw_property(dev, 0, "phy-supply", &reg) == 0) {
+		error = regulator_enable(reg);
+		if (error != 0) {
+			device_printf(dev, "cannot enable PHY regulator\n");
+			goto fail;
+		}
+	}
+
+	/* Determine MDC clock divide ratio based on AHB clock */
+	error = clk_get_freq(clk_ahb, &freq);
+	if (error != 0) {
+		device_printf(dev, "cannot get AHB clock frequency\n");
+		goto fail;
+	}
+	div = freq / MDIO_FREQ;
+	if (div <= 16)
+		sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_16;
+	else if (div <= 32)
+		sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_32;
+	else if (div <= 64)
+		sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_64;
+	else if (div <= 128)
+		sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_128;
+	else {
+		device_printf(dev, "cannot determine MDC clock divide ratio\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (bootverbose)
+		device_printf(dev, "AHB frequency %llu Hz, MDC div: 0x%x\n",
+		    freq, sc->mdc_div_ratio_m);
+
+	return (0);
+
+fail:
+	OF_prop_free(phy_type);
+
+	if (reg != NULL)
+		regulator_release(reg);
+	if (clk_tx_parent != NULL)
+		clk_release(clk_tx_parent);
+	if (clk_tx != NULL)
+		clk_release(clk_tx);
+	if (clk_ahb != NULL)
+		clk_release(clk_ahb);
+	if (rst_ahb != NULL)
+		hwreset_release(rst_ahb);
+	return (error);
+}
+
+static void 
+awg_get_eaddr(device_t dev, uint8_t *eaddr)
+{
+	struct awg_softc *sc;
+	uint32_t maclo, machi, rnd;
+
+	sc = device_get_softc(dev);
+
+	machi = RD4(sc, EMAC_ADDR_HIGH(0)) & 0xffff;
+	maclo = RD4(sc, EMAC_ADDR_LOW(0));
+
+	if (maclo == 0xffffffff && machi == 0xffff) {
+		/* MAC address in hardware is invalid, create one */
+		rnd = arc4random();
+		maclo = 0x00f2 | (rnd & 0xffff0000);
+		machi = rnd & 0xffff;
+	}
+
+	eaddr[0] = maclo & 0xff;
+	eaddr[1] = (maclo >> 8) & 0xff;
+	eaddr[2] = (maclo >> 16) & 0xff;
+	eaddr[3] = (maclo >> 24) & 0xff;
+	eaddr[4] = machi & 0xff;
+	eaddr[5] = (machi >> 8) & 0xff;
+}
+
+#ifdef AWG_DEBUG
+static void
+awg_dump_regs(device_t dev)
+{
+	static const struct {
+		const char *name;
+		u_int reg;
+	} regs[] = {
+		{ "BASIC_CTL_0", EMAC_BASIC_CTL_0 },
+		{ "BASIC_CTL_1", EMAC_BASIC_CTL_1 },
+		{ "INT_STA", EMAC_INT_STA },
+		{ "INT_EN", EMAC_INT_EN },
+		{ "TX_CTL_0", EMAC_TX_CTL_0 },
+		{ "TX_CTL_1", EMAC_TX_CTL_1 },
+		{ "TX_FLOW_CTL", EMAC_TX_FLOW_CTL },
+		{ "TX_DMA_LIST", EMAC_TX_DMA_LIST },
+		{ "RX_CTL_0", EMAC_RX_CTL_0 },
+		{ "RX_CTL_1", EMAC_RX_CTL_1 },
+		{ "RX_DMA_LIST", EMAC_RX_DMA_LIST },
+		{ "RX_FRM_FLT", EMAC_RX_FRM_FLT },
+		{ "RX_HASH_0", EMAC_RX_HASH_0 },
+		{ "RX_HASH_1", EMAC_RX_HASH_1 },
+		{ "MII_CMD", EMAC_MII_CMD },
+		{ "ADDR_HIGH0", EMAC_ADDR_HIGH(0) },
+		{ "ADDR_LOW0", EMAC_ADDR_LOW(0) },
+		{ "TX_DMA_STA", EMAC_TX_DMA_STA },
+		{ "TX_DMA_CUR_DESC", EMAC_TX_DMA_CUR_DESC },
+		{ "TX_DMA_CUR_BUF", EMAC_TX_DMA_CUR_BUF },
+		{ "RX_DMA_STA", EMAC_RX_DMA_STA },
+		{ "RX_DMA_CUR_DESC", EMAC_RX_DMA_CUR_DESC },
+		{ "RX_DMA_CUR_BUF", EMAC_RX_DMA_CUR_BUF },
+		{ "RGMII_STA", EMAC_RGMII_STA },
+	};
+	struct awg_softc *sc;
+	unsigned int n;
+
+	sc = device_get_softc(dev);
+
+	for (n = 0; n < nitems(regs); n++)
+		device_printf(dev, "  %-20s %08x\n", regs[n].name,
+		    RD4(sc, regs[n].reg));
+}
+#endif
+
+static int
+awg_reset(device_t dev)
+{
+	struct awg_softc *sc;
+	int retry;
+
+	sc = device_get_softc(dev);
+
+	/* Soft reset all registers and logic */
+	WR4(sc, EMAC_BASIC_CTL_1, BASIC_CTL_SOFT_RST);
+
+	/* Wait for soft reset bit to self-clear */
+	for (retry = SOFT_RST_RETRY; retry > 0; retry--) {
+		if ((RD4(sc, EMAC_BASIC_CTL_1) & BASIC_CTL_SOFT_RST) == 0)
+			break;
+		DELAY(10);
+	}
+	if (retry == 0) {
+		device_printf(dev, "soft reset timed out\n");
+#ifdef AWG_DEBUG
+		awg_dump_regs(dev);
+#endif
+		return (ETIMEDOUT);
+	}
+
+	return (0);
+}
+
+static void
+awg_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	if (error != 0)
+		return;
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+static int
+awg_setup_dma(device_t dev)
+{
+	struct awg_softc *sc;
+	struct mbuf *m;
+	int error, i;
+
+	sc = device_get_softc(dev);
+
+	/* Setup TX ring */
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),	/* Parent tag */
+	    DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    TX_DESC_SIZE, 1,		/* maxsize, nsegs */
+	    TX_DESC_SIZE,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->tx.desc_tag);
+	if (error != 0) {
+		device_printf(dev, "cannot create TX descriptor ring tag\n");
+		return (error);
+	}
+
+	error = bus_dmamem_alloc(sc->tx.desc_tag, (void **)&sc->tx.desc_ring,
+	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->tx.desc_map);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate TX descriptor ring\n");
+		return (error);
+	}
+
+	error = bus_dmamap_load(sc->tx.desc_tag, sc->tx.desc_map,
+	    sc->tx.desc_ring, TX_DESC_SIZE, awg_dmamap_cb,
+	    &sc->tx.desc_ring_paddr, 0);
+	if (error != 0) {
+		device_printf(dev, "cannot load TX descriptor ring\n");
+		return (error);
+	}
+
+	for (i = 0; i < TX_DESC_COUNT; i++)
+		sc->tx.desc_ring[i].next =
+		    htole32(sc->tx.desc_ring_paddr + DESC_OFF(TX_NEXT(i)));
+
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),	/* Parent tag */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES, TX_MAX_SEGS,	/* maxsize, nsegs */
+	    MCLBYTES,			/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->tx.buf_tag);
+	if (error != 0) {
+		device_printf(dev, "cannot create TX buffer tag\n");
+		return (error);
+	}
+
+	sc->tx.queued = TX_DESC_COUNT;
+	for (i = 0; i < TX_DESC_COUNT; i++) {
+		error = bus_dmamap_create(sc->tx.buf_tag, 0,
+		    &sc->tx.buf_map[i].map);
+		if (error != 0) {
+			device_printf(dev, "cannot create TX buffer map\n");
+			return (error);
+		}
+		awg_setup_txdesc(sc, i, 0, 0, 0);
+	}
+
+	/* Setup RX ring */
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),	/* Parent tag */
+	    DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    RX_DESC_SIZE, 1,		/* maxsize, nsegs */
+	    RX_DESC_SIZE,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->rx.desc_tag);
+	if (error != 0) {
+		device_printf(dev, "cannot create RX descriptor ring tag\n");
+		return (error);
+	}
+
+	error = bus_dmamem_alloc(sc->rx.desc_tag, (void **)&sc->rx.desc_ring,
+	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx.desc_map);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate RX descriptor ring\n");
+		return (error);
+	}
+
+	error = bus_dmamap_load(sc->rx.desc_tag, sc->rx.desc_map,
+	    sc->rx.desc_ring, RX_DESC_SIZE, awg_dmamap_cb,
+	    &sc->rx.desc_ring_paddr, 0);
+	if (error != 0) {
+		device_printf(dev, "cannot load RX descriptor ring\n");
+		return (error);
+	}
+
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),	/* Parent tag */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES, 1,		/* maxsize, nsegs */
+	    MCLBYTES,			/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->rx.buf_tag);
+	if (error != 0) {
+		device_printf(dev, "cannot create RX buffer tag\n");
+		return (error);
+	}
+
+	for (i = 0; i < RX_DESC_COUNT; i++) {
+		error = bus_dmamap_create(sc->rx.buf_tag, 0,
+		    &sc->rx.buf_map[i].map);
+		if (error != 0) {
+			device_printf(dev, "cannot create RX buffer map\n");
+			return (error);
+		}
+		if ((m = awg_alloc_mbufcl(sc)) == NULL) {
+			device_printf(dev, "cannot allocate RX mbuf\n");
+			return (ENOMEM);
+		}
+		error = awg_setup_rxbuf(sc, i, m);
+		if (error != 0) {
+			device_printf(dev, "cannot create RX buffer\n");
+			return (error);
+		}
+	}
+	bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map,
+	    BUS_DMASYNC_PREWRITE);
+
+	/* Write transmit and receive descriptor base address registers */
+	WR4(sc, EMAC_TX_DMA_LIST, sc->tx.desc_ring_paddr);
+	WR4(sc, EMAC_RX_DMA_LIST, sc->rx.desc_ring_paddr);
+
+	return (0);
+}
+
+static int
+awg_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Gigabit Ethernet");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+awg_attach(device_t dev)
+{
+	uint8_t eaddr[ETHER_ADDR_LEN];
+	struct awg_softc *sc;
+	phandle_t node;
+	int error;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	node = ofw_bus_get_node(dev);
+
+	if (bus_alloc_resources(dev, awg_spec, sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF);
+	callout_init_mtx(&sc->stat_ch, &sc->mtx, 0);
+	TASK_INIT(&sc->link_task, 0, awg_link_task, sc);
+
+	/* Setup clocks and regulators */
+	error = awg_setup_extres(dev);
+	if (error != 0)
+		return (error);
+
+	/* Read MAC address before resetting the chip */
+	awg_get_eaddr(dev, eaddr);
+
+	/* Soft reset EMAC core */
+	error = awg_reset(dev);
+	if (error != 0)
+		return (error);
+
+	/* Setup DMA descriptors */
+	error = awg_setup_dma(dev);
+	if (error != 0)
+		return (error);
+
+	/* Install interrupt handler */
+	error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, awg_intr, sc, &sc->ih);
+	if (error != 0) {
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (error);
+	}
+
+	/* Setup ethernet interface */
+	sc->ifp = if_alloc(IFT_ETHER);
+	if_setsoftc(sc->ifp, sc);
+	if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev));
+	if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
+	if_setstartfn(sc->ifp, awg_start);
+	if_setioctlfn(sc->ifp, awg_ioctl);
+	if_setinitfn(sc->ifp, awg_init);
+	if_setsendqlen(sc->ifp, TX_DESC_COUNT - 1);
+	if_setsendqready(sc->ifp);
+	if_sethwassist(sc->ifp, CSUM_IP | CSUM_UDP | CSUM_TCP);
+	if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM);
+	if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));
+
+	/* Attach MII driver */
+	error = mii_attach(dev, &sc->miibus, sc->ifp, awg_media_change,
+	    awg_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY,
+	    MIIF_DOPAUSE);
+	if (error != 0) {
+		device_printf(dev, "cannot attach PHY\n");
+		return (error);
+	}
+
+	/* Attach ethernet interface */
+	ether_ifattach(sc->ifp, eaddr);
+
+	return (0);
+}
+
+static device_method_t awg_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		awg_probe),
+	DEVMETHOD(device_attach,	awg_attach),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	awg_miibus_readreg),
+	DEVMETHOD(miibus_writereg,	awg_miibus_writereg),
+	DEVMETHOD(miibus_statchg,	awg_miibus_statchg),
+
+	DEVMETHOD_END
+};
+
+static driver_t awg_driver = {
+	"awg",
+	awg_methods,
+	sizeof(struct awg_softc),
+};
+
+static devclass_t awg_devclass;
+
+DRIVER_MODULE(awg, simplebus, awg_driver, awg_devclass, 0, 0);
+DRIVER_MODULE(miibus, awg, miibus_driver, miibus_devclass, 0, 0);
+
+MODULE_DEPEND(awg, ether, 1, 1, 1);
+MODULE_DEPEND(awg, miibus, 1, 1, 1);


Property changes on: trunk/sys/arm/allwinner/if_awg.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/if_awgreg.h
===================================================================
--- trunk/sys/arm/allwinner/if_awgreg.h	                        (rev 0)
+++ trunk/sys/arm/allwinner/if_awgreg.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,182 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at 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.
+ *
+ * $FreeBSD: stable/11/sys/arm/allwinner/if_awgreg.h 299084 2016-05-04 20:06:20Z jmcneill $
+ */
+
+/*
+ * Allwinner Gigabit Ethernet
+ */
+
+#ifndef __IF_AWGREG_H__
+#define __IF_AWGREG_H__
+
+#define	EMAC_BASIC_CTL_0	0x00
+#define	 BASIC_CTL_SPEED	(0x3 << 2)
+#define	 BASIC_CTL_SPEED_SHIFT	2
+#define	 BASIC_CTL_SPEED_1000	0
+#define	 BASIC_CTL_SPEED_10	2
+#define	 BASIC_CTL_SPEED_100	3
+#define	 BASIC_CTL_LOOPBACK	(1 << 1)
+#define	 BASIC_CTL_DUPLEX	(1 << 0)
+#define	EMAC_BASIC_CTL_1	0x04
+#define	 BASIC_CTL_BURST_LEN	(0x3f << 24)
+#define	 BASIC_CTL_BURST_LEN_SHIFT 24
+#define	 BASIC_CTL_RX_TX_PRI	(1 << 1)
+#define	 BASIC_CTL_SOFT_RST	(1 << 0)
+#define	EMAC_INT_STA		0x08
+#define	 RX_BUF_UA_INT		(1 << 10)
+#define	 RX_INT			(1 << 8)
+#define	 TX_UNDERFLOW_INT	(1 << 4)
+#define	 TX_BUF_UA_INT		(1 << 2)
+#define	 TX_DMA_STOPPED_INT	(1 << 1)
+#define	 TX_INT			(1 << 0)
+#define	EMAC_INT_EN		0x0c
+#define	 RX_BUF_UA_INT_EN	(1 << 10)
+#define	 RX_INT_EN		(1 << 8)
+#define	 TX_UNDERFLOW_INT_EN	(1 << 4)
+#define	 TX_BUF_UA_INT_EN	(1 << 2)
+#define	 TX_DMA_STOPPED_INT_EN	(1 << 1)
+#define	 TX_INT_EN		(1 << 0)
+#define	EMAC_TX_CTL_0		0x10
+#define	 TX_EN			(1 << 31)
+#define	EMAC_TX_CTL_1		0x14
+#define	 TX_DMA_START		(1 << 31)
+#define	 TX_DMA_EN		(1 << 30)
+#define	 TX_MD			(1 << 1)
+#define	 FLUSH_TX_FIFO		(1 << 0)
+#define	EMAC_TX_FLOW_CTL	0x1c
+#define	 PAUSE_TIME		(0xffff << 4)
+#define	 PAUSE_TIME_SHIFT	4
+#define	 TX_FLOW_CTL_EN		(1 << 0)
+#define	EMAC_TX_DMA_LIST	0x20
+#define	EMAC_RX_CTL_0		0x24
+#define	 RX_EN			(1 << 31)
+#define	 JUMBO_FRM_EN		(1 << 29)
+#define	 STRIP_FCS		(1 << 28)
+#define	 CHECK_CRC		(1 << 27)
+#define	 RX_FLOW_CTL_EN		(1 << 16)
+#define	EMAC_RX_CTL_1		0x28
+#define	 RX_DMA_START		(1 << 31)
+#define	 RX_DMA_EN		(1 << 30)
+#define	 RX_MD			(1 << 1)
+#define	EMAC_RX_DMA_LIST	0x34
+#define	EMAC_RX_FRM_FLT		0x38
+#define	 DIS_ADDR_FILTER	(1 << 31)
+#define	 DIS_BROADCAST		(1 << 17)
+#define	 RX_ALL_MULTICAST	(1 << 16)
+#define	 CTL_FRM_FILTER		(0x3 << 12)
+#define	 CTL_FRM_FILTER_SHIFT	12
+#define	 HASH_MULTICAST		(1 << 9)
+#define	 HASH_UNICAST		(1 << 8)
+#define	 SA_FILTER_EN		(1 << 6)
+#define	 SA_INV_FILTER		(1 << 5)
+#define	 DA_INV_FILTER		(1 << 4)
+#define	 FLT_MD			(1 << 1)
+#define	 RX_ALL			(1 << 0)
+#define	EMAC_RX_HASH_0		0x40
+#define	EMAC_RX_HASH_1		0x44
+#define	EMAC_MII_CMD		0x48
+#define	 MDC_DIV_RATIO_M	(0x7 << 20)
+#define	 MDC_DIV_RATIO_M_16	0
+#define	 MDC_DIV_RATIO_M_32	1
+#define	 MDC_DIV_RATIO_M_64	2
+#define	 MDC_DIV_RATIO_M_128	3
+#define	 MDC_DIV_RATIO_M_SHIFT	20
+#define	 PHY_ADDR		(0x1f << 12)
+#define	 PHY_ADDR_SHIFT		12
+#define	 PHY_REG_ADDR		(0x1f << 4)
+#define	 PHY_REG_ADDR_SHIFT	4
+#define	 MII_WR			(1 << 1)
+#define	 MII_BUSY		(1 << 0)
+#define	EMAC_MII_DATA		0x4c
+#define	EMAC_ADDR_HIGH(n)	(0x50 + (n) * 8)
+#define	EMAC_ADDR_LOW(n)	(0x54 + (n) * 8)
+#define	EMAC_TX_DMA_STA		0x80
+#define	EMAC_TX_DMA_CUR_DESC	0x84
+#define	EMAC_TX_DMA_CUR_BUF	0x88
+#define	EMAC_RX_DMA_STA		0xc0
+#define	EMAC_RX_DMA_CUR_DESC	0xc4
+#define	EMAC_RX_DMA_CUR_BUF	0xc8
+#define	EMAC_RGMII_STA		0xd0
+
+struct emac_desc {
+	uint32_t	status;
+/* Transmit */
+#define	TX_DESC_CTL		(1 << 31)
+#define	TX_HEADER_ERR		(1 << 16)
+#define	TX_LENGTH_ERR		(1 << 14)
+#define	TX_PAYLOAD_ERR		(1 << 12)
+#define	TX_CRS_ERR		(1 << 10)
+#define	TX_COL_ERR_0		(1 << 9)
+#define	TX_COL_ERR_1		(1 << 8)
+#define	TX_COL_CNT		(0xf << 3)
+#define	TX_COL_CNT_SHIFT	3
+#define	TX_DEFER_ERR		(1 << 2)
+#define	TX_UNDERFLOW_ERR	(1 << 1)
+#define	TX_DEFER		(1 << 0)
+/* Receive */
+#define	RX_DESC_CTL		(1 << 31)
+#define	RX_DAF_FAIL		(1 << 30)
+#define	RX_FRM_LEN		(0x3fff << 16)
+#define	RX_FRM_LEN_SHIFT	16
+#define	RX_NO_ENOUGH_BUF_ERR	(1 << 14)
+#define	RX_SAF_FAIL		(1 << 13)
+#define	RX_OVERFLOW_ERR		(1 << 11)
+#define	RX_FIR_DESC		(1 << 9)
+#define	RX_LAST_DESC		(1 << 8)
+#define	RX_HEADER_ERR		(1 << 7)
+#define	RX_COL_ERR		(1 << 6)
+#define	RX_FRM_TYPE		(1 << 5)
+#define	RX_LENGTH_ERR		(1 << 4)
+#define	RX_PHY_ERR		(1 << 3)
+#define	RX_CRC_ERR		(1 << 1)
+#define	RX_PAYLOAD_ERR		(1 << 0)
+
+	uint32_t	size;
+/* Transmit */
+#define	TX_INT_CTL		(1 << 31)
+#define	TX_LAST_DESC		(1 << 30)
+#define	TX_FIR_DESC		(1 << 29)
+#define	TX_CHECKSUM_CTL		(0x3 << 27)
+#define	TX_CHECKSUM_CTL_IP	1
+#define	TX_CHECKSUM_CTL_NO_PSE	2
+#define	TX_CHECKSUM_CTL_FULL	3
+#define	TX_CHECKSUM_CTL_SHIFT	27
+#define	TX_CRC_CTL		(1 << 26)
+#define	TX_BUF_SIZE		(0xfff << 0)
+#define	TX_BUF_SIZE_SHIFT	0
+/* Receive */
+#define	RX_INT_CTL		(1 << 31)
+#define	RX_BUF_SIZE		(0xfff << 0)
+#define	RX_BUF_SIZE_SHIFT	0
+
+	uint32_t	addr;
+
+	uint32_t	next;
+} __packed;
+
+#endif /* !__IF_AWGREG_H__ */


Property changes on: trunk/sys/arm/allwinner/if_awgreg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/if_emac.c
===================================================================
--- trunk/sys/arm/allwinner/if_emac.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/if_emac.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -24,13 +24,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: stable/10/sys/arm/allwinner/if_emac.c 266337 2014-05-17 18:53:36Z ian $
+ * $FreeBSD: stable/11/sys/arm/allwinner/if_emac.c 331722 2018-03-29 02:50:57Z eadler $
  */
 
 /* A10/A20 EMAC driver */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/if_emac.c 266337 2014-05-17 18:53:36Z ian $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/if_emac.c 331722 2018-03-29 02:50:57Z eadler $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -78,14 +78,15 @@
 #include <dev/mii/miivar.h>
 
 #include <arm/allwinner/if_emacreg.h>
+#include <arm/allwinner/aw_sid.h>
 
+#include <dev/extres/clk/clk.h>
+
 #include "miibus_if.h"
 
 #include "gpio_if.h"
 
-#include "a10_clk.h"
 #include "a10_sramc.h"
-#include "a10_gpio.h"
 
 struct emac_softc {
 	struct ifnet		*emac_ifp;
@@ -96,6 +97,7 @@
 	struct resource		*emac_res;
 	struct resource		*emac_irq;
 	void			*emac_intrhand;
+	clk_t			emac_clk;
 	int			emac_if_flags;
 	struct mtx		emac_mtx;
 	struct callout		emac_tick_ch;
@@ -102,6 +104,7 @@
 	int			emac_watchdog_timer;
 	int			emac_rx_process_limit;
 	int			emac_link;
+	uint32_t		emac_fifo_mask;
 };
 
 static int	emac_probe(device_t);
@@ -111,7 +114,7 @@
 static int	emac_suspend(device_t);
 static int	emac_resume(device_t);
 
-static void	emac_sys_setup(void);
+static int	emac_sys_setup(struct emac_softc *);
 static void	emac_reset(struct emac_softc *);
 
 static void	emac_init_locked(struct emac_softc *);
@@ -122,7 +125,7 @@
 static int	emac_ioctl(struct ifnet *, u_long, caddr_t);
 
 static void	emac_rxeof(struct emac_softc *, int);
-static void	emac_txeof(struct emac_softc *);
+static void	emac_txeof(struct emac_softc *, uint32_t);
 
 static int	emac_miibus_readreg(device_t, int, int);
 static int	emac_miibus_writereg(device_t, int, int, int);
@@ -139,21 +142,27 @@
 #define	EMAC_WRITE_REG(sc, reg, val)	\
     bus_space_write_4(sc->emac_tag, sc->emac_handle, reg, val)
 
-static void
-emac_sys_setup(void)
+static int
+emac_sys_setup(struct emac_softc *sc)
 {
-	int i;
+	int error;
 
-	a10_clk_emac_activate();
+	/* Activate EMAC clock. */
+	error = clk_get_by_ofw_index(sc->emac_dev, 0, 0, &sc->emac_clk);
+	if (error != 0) {
+		device_printf(sc->emac_dev, "cannot get clock\n");
+		return (error);
+	}
+	error = clk_enable(sc->emac_clk);
+	if (error != 0) {
+		device_printf(sc->emac_dev, "cannot enable clock\n");
+		return (error);
+	}
 
-	/*
-	 * Configure pin mux settings for MII.
-	 * Pins PA0 from PA17.
-	 */
-	for (i = 0; i <= 17; i++)
-		a10_emac_gpio_config(i);
-	/* Map sram */
+	/* Map sram. */
 	a10_map_to_emac();
+
+	return (0);
 }
 
 static void
@@ -160,6 +169,7 @@
 emac_get_hwaddr(struct emac_softc *sc, uint8_t *hwaddr)
 {
 	uint32_t val0, val1, rnd;
+	u_char rootkey[16];
 
 	/*
 	 * Try to get MAC address from running hardware.
@@ -166,6 +176,10 @@
 	 * If there is something non-zero there just use it.
 	 *
 	 * Otherwise set the address to a convenient locally assigned address,
+	 * using the SID rootkey.
+	 * This is was uboot does so we end up with the same mac as if uboot
+	 * did set it.
+	 * If we can't get the root key, generate a random one,
 	 * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally
 	 * assigned bit set, and the broadcast/multicast bit clear.
 	 */
@@ -179,13 +193,23 @@
 		hwaddr[4] = (val0 >> 8) & 0xff;
 		hwaddr[5] = (val0 >> 0) & 0xff;
 	} else {
-		rnd = arc4random() & 0x00ffffff;
-		hwaddr[0] = 'b';
-		hwaddr[1] = 's';
-		hwaddr[2] = 'd';
-		hwaddr[3] = (rnd >> 16) & 0xff;
-		hwaddr[4] = (rnd >> 8) & 0xff;
-		hwaddr[5] = (rnd >> 0) & 0xff;
+		if (aw_sid_get_rootkey(rootkey) == 0) {
+			hwaddr[0] = 0x2;
+			hwaddr[1] = rootkey[3];
+			hwaddr[2] = rootkey[12];
+			hwaddr[3] = rootkey[13];
+			hwaddr[4] = rootkey[14];
+			hwaddr[5] = rootkey[15];
+		}
+		else {
+			rnd = arc4random() & 0x00ffffff;
+			hwaddr[0] = 'b';
+			hwaddr[1] = 's';
+			hwaddr[2] = 'd';
+			hwaddr[3] = (rnd >> 16) & 0xff;
+			hwaddr[4] = (rnd >> 8) & 0xff;
+			hwaddr[5] = (rnd >> 0) & 0xff;
+		}
 	}
 	if (bootverbose)
 		printf("MAC address: %s\n", ether_sprintf(hwaddr));
@@ -254,14 +278,28 @@
 }
 
 static void
-emac_txeof(struct emac_softc *sc)
+emac_drain_rxfifo(struct emac_softc *sc)
 {
+	uint32_t data;
+
+	while (EMAC_READ_REG(sc, EMAC_RX_FBC) > 0)
+		data = EMAC_READ_REG(sc, EMAC_RX_IO_DATA);
+}
+
+static void
+emac_txeof(struct emac_softc *sc, uint32_t status)
+{
 	struct ifnet *ifp;
 
 	EMAC_ASSERT_LOCKED(sc);
 
 	ifp = sc->emac_ifp;
-	ifp->if_opackets++;
+	status &= (EMAC_TX_FIFO0 | EMAC_TX_FIFO1);
+	sc->emac_fifo_mask &= ~status;
+	if (status == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 2);
+	else
+		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
 	/* Unarm watchdog timer if no TX */
@@ -276,7 +314,7 @@
 	uint32_t reg_val, rxcount;
 	int16_t len;
 	uint16_t status;
-	int good_packet, i;
+	int i;
 
 	ifp = sc->emac_ifp;
 	for (; count > 0 &&
@@ -328,25 +366,24 @@
 			return;
 		}
 
-		good_packet = 1;
-
 		/* Get packet size and status */
 		reg_val = EMAC_READ_REG(sc, EMAC_RX_IO_DATA);
 		len = reg_val & 0xffff;
 		status = (reg_val >> 16) & 0xffff;
 
-		if (len < 64) {
-			good_packet = 0;
+		if (len < 64 || (status & EMAC_PKT_OK) == 0) {
 			if (bootverbose)
 				if_printf(ifp,
 				    "bad packet: len = %i status = %i\n",
 				    len, status);
-			ifp->if_ierrors++;
+			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+			emac_drain_rxfifo(sc);
+			continue;
 		}
 #if 0
 		if (status & (EMAC_CRCERR | EMAC_LENERR)) {
 			good_packet = 0;
-			ifp->if_ierrors++;
+			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
 			if (status & EMAC_CRCERR)
 				if_printf(ifp, "crc error\n");
 			if (status & EMAC_LENERR)
@@ -353,63 +390,58 @@
 				if_printf(ifp, "length error\n");
 		}
 #endif
-		if (good_packet) {
-			m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
-			if (m == NULL)
-				return;
-			m->m_len = m->m_pkthdr.len = MCLBYTES;
+		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+		if (m == NULL) {
+			emac_drain_rxfifo(sc);
+			return;
+		}
+		m->m_len = m->m_pkthdr.len = MCLBYTES;
 
-			len -= ETHER_CRC_LEN;
+		/* Copy entire frame to mbuf first. */
+		bus_space_read_multi_4(sc->emac_tag, sc->emac_handle,
+		    EMAC_RX_IO_DATA, mtod(m, uint32_t *), roundup2(len, 4) / 4);
 
-			/* Copy entire frame to mbuf first. */
-			bus_space_read_multi_4(sc->emac_tag, sc->emac_handle,
-			    EMAC_RX_IO_DATA, mtod(m, uint32_t *),
-			    roundup2(len, 4) / 4);
+		m->m_pkthdr.rcvif = ifp;
+		m->m_len = m->m_pkthdr.len = len - ETHER_CRC_LEN;
 
-			m->m_pkthdr.rcvif = ifp;
-			m->m_len = m->m_pkthdr.len = len;
-
-			/*
-			 * Emac controller needs strict aligment, so to avoid
-			 * copying over an entire frame to align, we allocate
-			 * a new mbuf and copy ethernet header + IP header to
-			 * the new mbuf. The new mbuf is prepended into the
-			 * existing mbuf chain.
-			 */
-			if (m->m_len <= (MHLEN - ETHER_HDR_LEN)) {
-				bcopy(m->m_data, m->m_data + ETHER_HDR_LEN,
-				    m->m_len);
-				m->m_data += ETHER_HDR_LEN;
-			} else if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN) &&
-			    m->m_len > (MHLEN - ETHER_HDR_LEN)) {
-				MGETHDR(m0, M_NOWAIT, MT_DATA);
-				if (m0 != NULL) {
-					len = ETHER_HDR_LEN +
-					    m->m_pkthdr.l2hlen;
-					bcopy(m->m_data, m0->m_data, len);
-					m->m_data += len;
-					m->m_len -= len;
-					m0->m_len = len;
-					M_MOVE_PKTHDR(m0, m);
-					m0->m_next = m;
-					m = m0;
-				} else {
-					ifp->if_ierrors++;
-					m_freem(m);
-					m = NULL;
-					continue;
-				}
-			} else if (m->m_len > EMAC_MAC_MAXF) {
-				ifp->if_ierrors++;
+		/*
+		 * Emac controller needs strict aligment, so to avoid
+		 * copying over an entire frame to align, we allocate
+		 * a new mbuf and copy ethernet header + IP header to
+		 * the new mbuf. The new mbuf is prepended into the
+		 * existing mbuf chain.
+		 */
+		if (m->m_len <= (MHLEN - ETHER_HDR_LEN)) {
+			bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
+			m->m_data += ETHER_HDR_LEN;
+		} else if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN) &&
+		    m->m_len > (MHLEN - ETHER_HDR_LEN)) {
+			MGETHDR(m0, M_NOWAIT, MT_DATA);
+			if (m0 != NULL) {
+				len = ETHER_HDR_LEN + m->m_pkthdr.l2hlen;
+				bcopy(m->m_data, m0->m_data, len);
+				m->m_data += len;
+				m->m_len -= len;
+				m0->m_len = len;
+				M_MOVE_PKTHDR(m0, m);
+				m0->m_next = m;
+				m = m0;
+			} else {
+				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
 				m_freem(m);
 				m = NULL;
 				continue;
 			}
-			ifp->if_ipackets++;
-			EMAC_UNLOCK(sc);
-			(*ifp->if_input)(ifp, m);
-			EMAC_LOCK(sc);
+		} else if (m->m_len > EMAC_MAC_MAXF) {
+			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+			m_freem(m);
+			m = NULL;
+			continue;
 		}
+		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+		EMAC_UNLOCK(sc);
+		(*ifp->if_input)(ifp, m);
+		EMAC_LOCK(sc);
 	}
 }
 
@@ -432,7 +464,7 @@
 	} else
 		if_printf(sc->emac_ifp, "watchdog timeout -- resetting\n");
 	
-	ifp->if_oerrors++;
+	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 	emac_init_locked(sc);
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
@@ -583,11 +615,13 @@
 {
 	struct emac_softc *sc;
 	struct mbuf *m, *m0;
-	uint32_t reg_val;
+	uint32_t fifo, reg;
 
 	sc = ifp->if_softc;
 	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
 		return;
+	if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+		return;
 	if (sc->emac_link == 0)
 		return;
 	IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
@@ -595,7 +629,14 @@
 		return;
 
 	/* Select channel */
-	EMAC_WRITE_REG(sc, EMAC_TX_INS, 0);
+	if (sc->emac_fifo_mask & EMAC_TX_FIFO0)
+		fifo = 1;
+	else
+		fifo = 0;
+	sc->emac_fifo_mask |= (1 << fifo);
+	if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+	EMAC_WRITE_REG(sc, EMAC_TX_INS, fifo);
 
 	/*
 	 * Emac controller wants 4 byte aligned TX buffers.
@@ -616,17 +657,17 @@
 	    roundup2(m->m_len, 4) / 4);
 
 	/* Send the data lengh. */
-	EMAC_WRITE_REG(sc, EMAC_TX_PL0, m->m_len);
+	reg = (fifo == 0) ? EMAC_TX_PL0 : EMAC_TX_PL1;
+	EMAC_WRITE_REG(sc, reg, m->m_len);
 
 	/* Start translate from fifo to phy. */
-	reg_val = EMAC_READ_REG(sc, EMAC_TX_CTL0);
-	reg_val |= 1;
-	EMAC_WRITE_REG(sc, EMAC_TX_CTL0, reg_val);
+	reg = (fifo == 0) ? EMAC_TX_CTL0 : EMAC_TX_CTL1;
+	EMAC_WRITE_REG(sc, reg, EMAC_READ_REG(sc, reg) | 1);
 
 	/* Set timeout */
 	sc->emac_watchdog_timer = 5;
 
-	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+	/* Data have been sent to hardware, it is okay to free the mbuf now. */
 	BPF_MTAP(ifp, m);
 	m_freem(m);
 }
@@ -665,9 +706,6 @@
 
 	sc = (struct emac_softc *)arg;
 	EMAC_LOCK(sc);
-	ifp = sc->emac_ifp;
-	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
-		return;
 
 	/* Disable all interrupts */
 	EMAC_WRITE_REG(sc, EMAC_INT_CTL, 0);
@@ -681,18 +719,17 @@
 		emac_rxeof(sc, sc->emac_rx_process_limit);
 
 	/* Transmit Interrupt check */
-	if (reg_val & EMAC_INT_STA_TX){
-		emac_txeof(sc);
+	if (reg_val & EMAC_INT_STA_TX) {
+		emac_txeof(sc, reg_val);
+		ifp = sc->emac_ifp;
 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 			emac_start_locked(ifp);
 	}
 
-	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
-		/* Re-enable interrupt mask */
-		reg_val = EMAC_READ_REG(sc, EMAC_INT_CTL);
-		reg_val |= EMAC_INT_EN;
-		EMAC_WRITE_REG(sc, EMAC_INT_CTL, reg_val);
-	}
+	/* Re-enable interrupt mask */
+	reg_val = EMAC_READ_REG(sc, EMAC_INT_CTL);
+	reg_val |= EMAC_INT_EN;
+	EMAC_WRITE_REG(sc, EMAC_INT_CTL, reg_val);
 	EMAC_UNLOCK(sc);
 }
 
@@ -748,9 +785,12 @@
 emac_probe(device_t dev)
 {
 
-	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-emac"))
+	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-emac"))
+		return (ENXIO);
+
 	device_set_desc(dev, "A10/A20 EMAC ethernet controller");
 	return (BUS_PROBE_DEFAULT);
 }
@@ -779,6 +819,9 @@
 		bus_generic_detach(sc->emac_dev);
 	}
 
+	if (sc->emac_clk != NULL)
+		clk_disable(sc->emac_clk);
+
 	if (sc->emac_res != NULL)
 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->emac_res);
 
@@ -892,7 +935,10 @@
 		}
 	}
 	/* Setup EMAC */
-	emac_sys_setup();
+	error = emac_sys_setup(sc);
+	if (error != 0)
+		goto fail;
+
 	emac_reset(sc);
 
 	ifp = sc->emac_ifp = if_alloc(IFT_ETHER);

Modified: trunk/sys/arm/allwinner/if_emacreg.h
===================================================================
--- trunk/sys/arm/allwinner/if_emacreg.h	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/if_emacreg.h	2020-03-08 17:23:22 UTC (rev 12402)
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: stable/10/sys/arm/allwinner/if_emacreg.h 266337 2014-05-17 18:53:36Z ian $
+ * $FreeBSD: stable/11/sys/arm/allwinner/if_emacreg.h 331722 2018-03-29 02:50:57Z eadler $
  */
 
 #ifndef	__IF_EMACREG_H__
@@ -52,6 +52,8 @@
 #define	EMAC_TX_TSVH0		0x30
 #define	EMAC_TX_TSVL1		0x34
 #define	EMAC_TX_TSVH1		0x38
+#define	EMAC_TX_FIFO0		(1 << 0)
+#define	EMAC_TX_FIFO1		(1 << 1)
 
 #define	EMAC_RX_CTL		0x3C
 #define	EMAC_RX_HASH0		0x40
@@ -62,7 +64,7 @@
 
 #define	EMAC_INT_CTL		0x54
 #define	EMAC_INT_STA		0x58
-#define	EMAC_INT_STA_TX		(0x01 | 0x02)
+#define	EMAC_INT_STA_TX		(EMAC_TX_FIFO0 | EMAC_TX_FIFO1)
 #define	EMAC_INT_STA_RX		0x100
 #define	EMAC_INT_EN		(0xf << 0) | (1 << 8)
 
@@ -224,6 +226,7 @@
 /* Receive status */
 #define	EMAC_CRCERR		(1 << 4)
 #define	EMAC_LENERR		(3 << 5)
+#define	EMAC_PKT_OK		(1 << 7)
 
 #define	EMAC_RX_FLUSH_FIFO	(1 << 3)
 #define	EMAC_PHY_RESET		(1 << 15)

Deleted: trunk/sys/arm/allwinner/std.a10
===================================================================
--- trunk/sys/arm/allwinner/std.a10	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/std.a10	2020-03-08 17:23:22 UTC (rev 12402)
@@ -1,20 +0,0 @@
-# Allwinner A10 common options
-#$FreeBSD: stable/10/sys/arm/allwinner/std.a10 278601 2015-02-11 22:47:48Z ian $
-
-cpu		CPU_CORTEXA
-machine 	arm armv6
-makeoptions	CONF_CFLAGS="-march=armv7a -Wa,-march=armv7a"
-makeoption	ARM_LITTLE_ENDIAN
-
-# Physical memory starts at 0x40200000.  We assume images are loaded at
-# 0x40200000, e.g. from u-boot with 'fatload mmc 0 0x40200000 kernel'
-#
-#
-options		PHYSADDR=0x40000000
-
-makeoptions	KERNPHYSADDR=0x40200000
-options		KERNPHYSADDR=0x40200000
-makeoptions	KERNVIRTADDR=0xc0200000
-options		KERNVIRTADDR=0xc0200000
-
-files		"../allwinner/files.a10"

Added: trunk/sys/arm/allwinner/std.allwinner
===================================================================
--- trunk/sys/arm/allwinner/std.allwinner	                        (rev 0)
+++ trunk/sys/arm/allwinner/std.allwinner	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,15 @@
+# Allwinner common options
+# $MidnightBSD$
+
+cpu		CPU_CORTEXA
+machine 	arm armv6
+makeoptions	CONF_CFLAGS="-march=armv7a"
+
+options 	IPI_IRQ_START=0
+options 	IPI_IRQ_END=15
+
+files		"../allwinner/files.allwinner"
+files		"../allwinner/a20/files.a20"
+files		"../allwinner/a31/files.a31"
+files		"../allwinner/a83t/files.a83t"
+files		"../allwinner/h3/files.h3"


Property changes on: trunk/sys/arm/allwinner/std.allwinner
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/std.allwinner_up
===================================================================
--- trunk/sys/arm/allwinner/std.allwinner_up	                        (rev 0)
+++ trunk/sys/arm/allwinner/std.allwinner_up	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,11 @@
+# Allwinner Uniprocessor common options
+# $MidnightBSD$
+
+cpu		CPU_CORTEXA
+machine 	arm armv6
+makeoptions	CONF_CFLAGS="-march=armv7a"
+
+files		"../allwinner/files.allwinner_up"
+files		"../allwinner/files.allwinner"
+files		"../allwinner/a10/files.a10"
+files		"../allwinner/a13/files.a13"


Property changes on: trunk/sys/arm/allwinner/std.allwinner_up
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: trunk/sys/arm/allwinner/sunxi_dma_if.m
===================================================================
--- trunk/sys/arm/allwinner/sunxi_dma_if.m	                        (rev 0)
+++ trunk/sys/arm/allwinner/sunxi_dma_if.m	2020-03-08 17:23:22 UTC (rev 12402)
@@ -0,0 +1,99 @@
+/* $MidnightBSD$ */
+#-
+# Copyright (c) 2016 Jared D. McNeill <jmcneill at 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 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 AUTHOR 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.
+#
+# $FreeBSD: stable/11/sys/arm/allwinner/sunxi_dma_if.m 295635 2016-02-15 19:56:35Z andrew $
+#
+
+#include <sys/bus.h>
+
+INTERFACE sunxi_dma;
+
+HEADER {
+	#include <machine/bus.h>
+
+	struct sunxi_dma_config {
+		unsigned int dst_width;
+		unsigned int dst_burst_len;
+		unsigned int dst_drqtype;
+		bool dst_noincr;
+		unsigned int dst_blksize;	/* DDMA-only */
+		unsigned int dst_wait_cyc;	/* DDMA-only */
+		unsigned int src_width;
+		unsigned int src_burst_len;
+		unsigned int src_drqtype;
+		bool src_noincr;
+		unsigned int src_blksize;	/* DDMA-only */
+		unsigned int src_wait_cyc;	/* DDMA-only */
+	};
+
+	typedef void (*sunxi_dma_callback)(void *);
+}
+
+#
+# Allocate DMA channel
+#
+METHOD void * alloc {
+	device_t dev;
+	bool dedicated;
+	sunxi_dma_callback callback;
+	void *callback_arg;
+};
+
+#
+# Free DMA channel
+#
+METHOD void free {
+	device_t dev;
+	void *dmachan;
+};
+
+#
+# Set DMA channel configuration
+#
+METHOD int set_config {
+	device_t dev;
+	void *dmachan;
+	const struct sunxi_dma_config *cfg;
+};
+
+#
+# Start DMA channel transfer
+#
+METHOD int transfer {
+	device_t dev;
+	void *dmachan;
+	bus_addr_t src;
+	bus_addr_t dst;
+	size_t nbytes;
+};
+
+#
+# Halt DMA channel transfer
+#
+METHOD void halt {
+	device_t dev;
+	void *dmachan;
+};


Property changes on: trunk/sys/arm/allwinner/sunxi_dma_if.m
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/arm/allwinner/timer.c
===================================================================
--- trunk/sys/arm/allwinner/timer.c	2020-03-08 17:21:06 UTC (rev 12401)
+++ trunk/sys/arm/allwinner/timer.c	2020-03-08 17:23:22 UTC (rev 12402)
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/arm/allwinner/timer.c 277113 2015-01-13 07:45:16Z ganbold $");
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/timer.c 308274 2016-11-04 00:54:21Z manu $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -41,6 +41,7 @@
 #include <machine/bus.h>
 #include <machine/cpu.h>
 #include <machine/intr.h>
+#include <machine/machdep.h>
 
 #include <dev/fdt/fdt_common.h>
 #include <dev/ofw/openfirm.h>
@@ -48,11 +49,10 @@
 #include <dev/ofw/ofw_bus_subr.h>
 
 #include <machine/bus.h>
-#include <machine/fdt.h>
 
 #include <sys/kdb.h>
 
-#include "a20/a20_cpu_cfg.h"
+#include <arm/allwinner/aw_machdep.h>
 
 /**
  * Timer registers addr
@@ -86,7 +86,6 @@
 	uint32_t 	sc_period;
 	uint32_t 	timer0_freq;
 	struct eventtimer et;
-	uint8_t 	sc_timer_type;	/* 0 for A10, 1 for A20 */
 };
 
 int a10_timer_get_timerfreq(struct a10_timer_softc *);
@@ -103,11 +102,12 @@
 
 static uint64_t timer_read_counter64(void);
 
-static int a10_timer_initialized = 0;
 static int a10_timer_hardclock(void *);
 static int a10_timer_probe(device_t);
 static int a10_timer_attach(device_t);
 
+static delay_func a10_timer_delay;
+
 static struct timecounter a10_timer_timecounter = {
 	.tc_name           = "a10_timer timer0",
 	.tc_get_timecount  = a10_timer_get_timecount,
@@ -129,10 +129,6 @@
 {
 	uint32_t lo, hi;
 
-	/* In case of A20 get appropriate counter info */
-	if (a10_timer_sc->sc_timer_type)
-		return (a20_read_counter64());
-
 	/* Latch counter, wait for it to be ready to read. */
 	timer_write_4(a10_timer_sc, CNT64_CTRL_REG, CNT64_RL_EN);
 	while (timer_read_4(a10_timer_sc, CNT64_CTRL_REG) & CNT64_RL_EN)
@@ -148,16 +144,18 @@
 a10_timer_probe(device_t dev)
 {
 	struct a10_timer_softc *sc;
+	u_int soc_family;
 
 	sc = device_get_softc(dev);
 
-	if (ofw_bus_is_compatible(dev, "allwinner,sun4i-timer"))
-		sc->sc_timer_type = 0;
-	else if (ofw_bus_is_compatible(dev, "allwinner,sun7i-timer"))
-		sc->sc_timer_type = 1;
-	else
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-timer"))
 		return (ENXIO);
 
+	soc_family = allwinner_soc_family();
+	if (soc_family != ALLWINNERSOC_SUN4I &&
+	    soc_family != ALLWINNERSOC_SUN5I)
+		return (ENXIO);
+
 	device_set_desc(dev, "Allwinner A10/A20 timer");
 	return (BUS_PROBE_DEFAULT);
 }
@@ -214,8 +212,10 @@
 	sc->et.et_priv = sc;
 	et_register(&sc->et);
 
-	if (device_get_unit(dev) == 0)
+	if (device_get_unit(dev) == 0) {
+		arm_set_delay(a10_timer_delay, sc);
 		a10_timer_sc = sc;
+	}
 
 	a10_timer_timecounter.tc_frequency = sc->timer0_freq;
 	tc_init(&a10_timer_timecounter);
@@ -229,8 +229,6 @@
 		    a10_timer_timecounter.tc_frequency);
 	}
 
-	a10_timer_initialized = 1;
-
 	return (0);
 }
 
@@ -354,25 +352,18 @@
 
 static devclass_t a10_timer_devclass;
 
-DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0);
+EARLY_DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0,
+    BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
 
-void
-DELAY(int usec)
+static void
+a10_timer_delay(int usec, void *arg)
 {
-	uint32_t counter;
+	struct a10_timer_softc *sc = arg;
 	uint64_t end, now;
 
-	if (!a10_timer_initialized) {
-		for (; usec > 0; usec--)
-			for (counter = 50; counter > 0; counter--)
-				cpufunc_nullop();
-		return;
-	}
-
 	now = timer_read_counter64();
-	end = now + (a10_timer_sc->timer0_freq / 1000000) * (usec + 1);
+	end = now + (sc->timer0_freq / 1000000) * (usec + 1);
 
 	while (now < end)
 		now = timer_read_counter64();
 }
-



More information about the Midnightbsd-cvs mailing list