Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Add driver for Allwinner Gigabit Ethernet (EMAC) as...



details:   https://anonhg.NetBSD.org/src/rev/ce140cb1df9e
branches:  trunk
changeset: 825148:ce140cb1df9e
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Jul 01 16:25:15 2017 +0000

description:
Add driver for Allwinner Gigabit Ethernet (EMAC) as found in sun8i and
later family SoCs.

This is a port of my FreeBSD driver which has been confirmed to work on
Allwinner H3, A83T, and A64 SoCs.

diffstat:

 sys/arch/arm/sunxi/files.sunxi    |     7 +-
 sys/arch/arm/sunxi/sun8i_h3_ccu.c |     6 +-
 sys/arch/arm/sunxi/sunxi_emac.c   |  1435 +++++++++++++++++++++++++++++++++++++
 sys/arch/arm/sunxi/sunxi_emac.h   |   184 ++++
 sys/arch/evbarm/conf/SUNXI        |     7 +-
 5 files changed, 1633 insertions(+), 6 deletions(-)

diffs (truncated from 1697 to 300 lines):

diff -r 54a7fc37e6b8 -r ce140cb1df9e sys/arch/arm/sunxi/files.sunxi
--- a/sys/arch/arm/sunxi/files.sunxi    Sat Jul 01 15:54:08 2017 +0000
+++ b/sys/arch/arm/sunxi/files.sunxi    Sat Jul 01 16:25:15 2017 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.sunxi,v 1.5 2017/06/29 19:38:24 jmcneill Exp $
+#      $NetBSD: files.sunxi,v 1.6 2017/07/01 16:25:16 jmcneill Exp $
 #
 # Configuration info for Allwinner sunxi family SoCs
 #
@@ -62,6 +62,11 @@
 attach sunxirtc at fdt with sunxi_rtc
 file   arch/arm/sunxi/sunxi_rtc.c              sunxi_rtc
 
+# EMAC
+device sunxiemac: arp, ether, ifnet, mii
+attach sunxiemac at fdt with sunxi_emac
+file   arch/arm/sunxi/sunxi_emac.c             sunxi_emac
+
 # SOC parameters
 defflag        opt_soc.h                       SOC_SUNXI
 defflag        opt_soc.h                       SOC_SUN8I: SOC_SUNXI
diff -r 54a7fc37e6b8 -r ce140cb1df9e sys/arch/arm/sunxi/sun8i_h3_ccu.c
--- a/sys/arch/arm/sunxi/sun8i_h3_ccu.c Sat Jul 01 15:54:08 2017 +0000
+++ b/sys/arch/arm/sunxi/sun8i_h3_ccu.c Sat Jul 01 16:25:15 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sun8i_h3_ccu.c,v 1.4 2017/06/29 17:08:52 jmcneill Exp $ */
+/* $NetBSD: sun8i_h3_ccu.c,v 1.5 2017/07/01 16:25:16 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: sun8i_h3_ccu.c,v 1.4 2017/06/29 17:08:52 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: sun8i_h3_ccu.c,v 1.5 2017/07/01 16:25:16 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -185,6 +185,8 @@
            BUS_CLK_GATING_REG0, 9),
        SUNXI_CCU_GATE(H3_CLK_BUS_MMC2, "bus-mmc2", "ahb1",
            BUS_CLK_GATING_REG0, 10),
+       SUNXI_CCU_GATE(H3_CLK_BUS_EMAC, "bus-emac", "ahb2",
+           BUS_CLK_GATING_REG0, 17),
        SUNXI_CCU_GATE(H3_CLK_BUS_OTG, "bus-otg", "ahb1",
            BUS_CLK_GATING_REG0, 23),
        SUNXI_CCU_GATE(H3_CLK_BUS_EHCI0, "bus-ehci0", "ahb1",
diff -r 54a7fc37e6b8 -r ce140cb1df9e sys/arch/arm/sunxi/sunxi_emac.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/sunxi/sunxi_emac.c   Sat Jul 01 16:25:15 2017 +0000
@@ -0,0 +1,1435 @@
+/* $NetBSD: sunxi_emac.c,v 1.1 2017/07/01 16:25:16 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2016-2017 Jared McNeill <jmcneill%invisible.ca@localhost>
+ * 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 Gigabit Ethernet MAC (EMAC) controller
+ */
+
+#include "opt_net_mpsafe.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c,v 1.1 2017/07/01 16:25:16 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/callout.h>
+#include <sys/gpio.h>
+#include <sys/cprng.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+#include <net/bpf.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <arm/sunxi/sunxi_emac.h>
+
+#ifdef NET_MPSAFE
+#define        EMAC_MPSAFE             1
+#define        CALLOUT_FLAGS           CALLOUT_MPSAFE
+#define        FDT_INTR_FLAGS          FDT_INTR_MPSAFE
+#else
+#define        CALLOUT_FLAGS           0
+#define        FDT_INTR_FLAGS          0
+#endif
+
+#define        EMAC_IFNAME             "emac%d"
+
+#define        ETHER_ALIGN             2
+
+#define        EMAC_LOCK(sc)           mutex_enter(&(sc)->mtx)
+#define        EMAC_UNLOCK(sc)         mutex_exit(&(sc)->mtx)
+#define        EMAC_ASSERT_LOCKED(sc)  KASSERT(mutex_owned(&(sc)->mtx))
+
+#define        DESC_ALIGN              8
+#define        TX_DESC_COUNT           1024
+#define        TX_DESC_SIZE            (sizeof(struct sunxi_emac_desc) * TX_DESC_COUNT)
+#define        RX_DESC_COUNT           256
+#define        RX_DESC_SIZE            (sizeof(struct sunxi_emac_desc) * RX_DESC_COUNT)
+
+#define        DESC_OFF(n)             ((n) * sizeof(struct sunxi_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             128
+
+#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
+#define        RX_BATCH_DEFAULT        64
+
+/* syscon EMAC clock register */
+#define        EMAC_CLK_EPHY_ADDR      (0x1f << 20)    /* H3 */
+#define        EMAC_CLK_EPHY_ADDR_SHIFT 20
+#define        EMAC_CLK_EPHY_LED_POL   (1 << 17)       /* H3 */
+#define        EMAC_CLK_EPHY_SHUTDOWN  (1 << 16)       /* H3 */
+#define        EMAC_CLK_EPHY_SELECT    (1 << 15)       /* H3 */
+#define        EMAC_CLK_RMII_EN        (1 << 13)
+#define        EMAC_CLK_ETXDC          (0x7 << 10)
+#define        EMAC_CLK_ETXDC_SHIFT    10
+#define        EMAC_CLK_ERXDC          (0x1f << 5)
+#define        EMAC_CLK_ERXDC_SHIFT    5
+#define        EMAC_CLK_PIT            (0x1 << 2)
+#define         EMAC_CLK_PIT_MII       (0 << 2)
+#define         EMAC_CLK_PIT_RGMII     (1 << 2)
+#define        EMAC_CLK_SRC            (0x3 << 0)
+#define         EMAC_CLK_SRC_MII       (0 << 0)
+#define         EMAC_CLK_SRC_EXT_RGMII (1 << 0)
+#define         EMAC_CLK_SRC_RGMII     (2 << 0)
+
+/* Burst length of RX and TX DMA transfers */
+static int sunxi_emac_burst_len = BURST_LEN_DEFAULT;
+
+/* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */
+static int sunxi_emac_rx_tx_pri = RX_TX_PRI_DEFAULT;
+
+/* Pause time field in the transmitted control frame */
+static int sunxi_emac_pause_time = PAUSE_TIME_DEFAULT;
+
+/* Request a TX interrupt every <n> descriptors */
+static int sunxi_emac_tx_interval = TX_INTERVAL_DEFAULT;
+
+/* Maximum number of mbufs to send to if_input */
+static int sunxi_emac_rx_batch = RX_BATCH_DEFAULT;
+
+enum sunxi_emac_type {
+       EMAC_A83T = 1,
+       EMAC_H3,
+};
+
+static const struct of_compat_data compat_data[] = {
+       { "allwinner,sun8i-a83t-emac",  EMAC_A83T },
+       { "allwinner,sun8i-h3-emac",    EMAC_H3 },
+       { NULL }
+};
+
+struct sunxi_emac_bufmap {
+       bus_dmamap_t            map;
+       struct mbuf             *mbuf;
+};
+
+struct sunxi_emac_txring {
+       bus_dma_tag_t           desc_tag;
+       bus_dmamap_t            desc_map;
+       bus_dma_segment_t       desc_dmaseg;
+       struct sunxi_emac_desc  *desc_ring;
+       bus_addr_t              desc_ring_paddr;
+       bus_dma_tag_t           buf_tag;
+       struct sunxi_emac_bufmap buf_map[TX_DESC_COUNT];
+       u_int                   cur, next, queued;
+};
+
+struct sunxi_emac_rxring {
+       bus_dma_tag_t           desc_tag;
+       bus_dmamap_t            desc_map;
+       bus_dma_segment_t       desc_dmaseg;
+       struct sunxi_emac_desc  *desc_ring;
+       bus_addr_t              desc_ring_paddr;
+       bus_dma_tag_t           buf_tag;
+       struct sunxi_emac_bufmap buf_map[RX_DESC_COUNT];
+       u_int                   cur;
+};
+
+enum {
+       _RES_EMAC,
+       _RES_SYSCON,
+       _RES_NITEMS
+};
+
+struct sunxi_emac_softc {
+       device_t                dev;
+       int                     phandle;
+       enum sunxi_emac_type    type;
+       bus_space_tag_t         bst;
+       bus_dma_tag_t           dmat;
+
+       bus_space_handle_t      bsh[_RES_NITEMS];
+       struct clk              *clk_ahb;
+       struct clk              *clk_ephy;
+       struct fdtbus_reset     *rst_ahb;
+       struct fdtbus_reset     *rst_ephy;
+       struct fdtbus_regulator *reg_phy;
+       struct fdtbus_gpio_pin  *pin_reset;
+
+       kmutex_t                mtx;
+       struct ethercom         ec;
+       struct mii_data         mii;
+       callout_t               stat_ch;
+       void                    *ih;
+       u_int                   mdc_div_ratio_m;
+
+       struct sunxi_emac_txring        tx;
+       struct sunxi_emac_rxring        rx;
+};
+
+#define        RD4(sc, reg)                    \
+       bus_space_read_4((sc)->bst, (sc)->bsh[_RES_EMAC], (reg))
+#define        WR4(sc, reg, val)               \
+       bus_space_write_4((sc)->bst, (sc)->bsh[_RES_EMAC], (reg), (val))
+
+#define        SYSCONRD4(sc, reg)              \
+       bus_space_read_4((sc)->bst, (sc)->bsh[_RES_SYSCON], (reg))
+#define        SYSCONWR4(sc, reg, val)         \
+       bus_space_write_4((sc)->bst, (sc)->bsh[_RES_SYSCON], (reg), (val))
+
+static int
+sunxi_emac_mii_readreg(device_t dev, int phy, int reg)
+{
+       struct sunxi_emac_softc *sc = device_private(dev);
+       int retry, val;
+
+       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 void
+sunxi_emac_mii_writereg(device_t dev, int phy, int reg, int val)
+{
+       struct sunxi_emac_softc *sc = device_private(dev);
+       int retry;
+



Home | Main Index | Thread Index | Old Index