[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, ®) != 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, ®) != 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, ®) != 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", ®) == 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, ®) == 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, ®, 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, ®, 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, ®, 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, ®, 1);
+ if (reg) {
+ axp2xx_write(sc->dev, AXP2XX_IRQ4_STATUS, AXP2XX_IRQ_ACK);
+ }
+
+ axp2xx_read(sc->dev, AXP2XX_IRQ5_STATUS, ®, 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, ®, 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, ®defs[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", ®) == 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