You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/12/23 19:56:38 UTC

[incubator-nuttx] 03/03: arch: imx6: Add imx_enet driver

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit ace6e70f5774ebf04f798b9d209eb947cd0eb3b3
Author: Masayuki Ishikawa <ma...@gmail.com>
AuthorDate: Wed Dec 23 19:27:49 2020 +0900

    arch: imx6: Add imx_enet driver
    
    Summary:
    - This commit adds imx_enet driver derived from imxrt_enet
    
    Impact:
    - imx6 only
    
    Testing:
    - Tested with sabre-6quad:netnsh
    - NOTE: telnetd works with QEMU
---
 arch/arm/src/imx6/Kconfig                          |   40 +
 arch/arm/src/imx6/Make.defs                        |    4 +
 arch/arm/src/imx6/hardware/imx_enet.h              |  701 ++++++
 arch/arm/src/imx6/imx_enet.c                       | 2549 ++++++++++++++++++++
 arch/arm/src/imx6/imx_enet.h                       |  108 +
 .../arm/imx6/sabre-6quad/configs/netnsh/defconfig  |   88 +
 6 files changed, 3490 insertions(+)

diff --git a/arch/arm/src/imx6/Kconfig b/arch/arm/src/imx6/Kconfig
index e9ad1e5..b71c49d 100644
--- a/arch/arm/src/imx6/Kconfig
+++ b/arch/arm/src/imx6/Kconfig
@@ -120,8 +120,47 @@ config IMX6_SPI2
 	default n
 	select SPI
 
+config IMX6_ENET
+	bool "Ethernet"
+	default n
+	select ARCH_HAVE_PHY
+	select ARCH_PHY_INTERRUPT
+	select ARCH_HAVE_NETDEV_STATISTICS
+
 endmenu # iMX Peripheral Selection
 
+menu "Ethernet Configuration"
+	depends on IMX6_ENET
+
+config IMX_ENET_NRXBUFFERS
+	int "Number Rx buffers"
+	default 6
+
+config IMX_ENET_NTXBUFFERS
+	int "Number Tx buffers"
+	default 2
+
+config IMX_ENET_ENHANCEDBD
+	bool # not optional
+	default n
+
+config IMX_ENET_NETHIFS
+	int  # Not optional
+	default 1
+
+config IMX_ENET_PHYINIT
+	bool "Board-specific PHY Initialization"
+	default n
+	---help---
+		Some boards require specialized initialization of the PHY before it
+		can be used.  This may include such things as configuring GPIOs,
+		resetting the PHY, etc.  If CONFIG_IMX_ENET_PHYINIT is defined in
+		the configuration then the board specific logic must provide
+		imx_phy_boardinitialize();  The i.MX6 ENET driver will call this
+		function one time before it first uses the PHY.
+
+endmenu # IMX_ENET
+
 config IMX_DDR_SIZE
 	int "Installed DRAM size (bytes)"
 	default 268435456
@@ -152,4 +191,5 @@ config IMX6_BOOT_SRAM
 	select BOOT_RUNFROMEXTSRAM
 
 endchoice # i.MX6 Boot Configuration
+
 endif # ARCH_CHIP_IMX6
diff --git a/arch/arm/src/imx6/Make.defs b/arch/arm/src/imx6/Make.defs
index eb84c44..bedf7fb 100644
--- a/arch/arm/src/imx6/Make.defs
+++ b/arch/arm/src/imx6/Make.defs
@@ -143,3 +143,7 @@ endif
 ifeq ($(CONFIG_IMX6_ECSPI),y)
 CHIP_CSRCS += imx_ecspi.c
 endif
+
+ifeq ($(CONFIG_IMX6_ENET),y)
+CHIP_CSRCS += imx_enet.c
+endif
diff --git a/arch/arm/src/imx6/hardware/imx_enet.h b/arch/arm/src/imx6/hardware/imx_enet.h
new file mode 100644
index 0000000..34a649c
--- /dev/null
+++ b/arch/arm/src/imx6/hardware/imx_enet.h
@@ -0,0 +1,701 @@
+/************************************************************************************
+ * arch/arm/src/imx6/hardware/imx_enet.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_IMX6_HARDWARE_IMX_ENET_H
+#define __ARCH_ARM_SRC_IMX6_HARDWARE_IMX_ENET_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+#define IMX_ENET_HAS_DBSWAP 1
+
+/* Register Offsets *****************************************************************/
+
+#define IMX_ENET_EIR_OFFSET      0x0004 /* Interrupt Event Register */
+#define IMX_ENET_EIMR_OFFSET     0x0008 /* Interrupt Mask Register */
+#define IMX_ENET_RDAR_OFFSET     0x0010 /* Receive Descriptor Active Register */
+#define IMX_ENET_TDAR_OFFSET     0x0014 /* Transmit Descriptor Active Register */
+#define IMX_ENET_ECR_OFFSET      0x0024 /* Ethernet Control Register */
+#define IMX_ENET_MMFR_OFFSET     0x0040 /* MII Management Frame Register */
+#define IMX_ENET_MSCR_OFFSET     0x0044 /* MII Speed Control Register */
+#define IMX_ENET_MIBC_OFFSET     0x0064 /* MIB Control Register */
+#define IMX_ENET_RCR_OFFSET      0x0084 /* Receive Control Register */
+#define IMX_ENET_TCR_OFFSET      0x00c4 /* Transmit Control Register */
+#define IMX_ENET_PALR_OFFSET     0x00e4 /* Physical Address Lower Register */
+#define IMX_ENET_PAUR_OFFSET     0x00e8 /* Physical Address Upper Register */
+#define IMX_ENET_OPD_OFFSET      0x00ec /* Opcode/Pause Duration Register */
+
+#if 0
+#define IMX_ENET_TXIC_OFFSET     0x00f0 /* Transmit Interrupt Coalescing Register */
+#define IMX_ENET_RXIC_OFFSET     0x0100 /* Receive Interrupt Coalescing Register */
+#endif
+
+#define IMX_ENET_IAUR_OFFSET     0x0118 /* Descriptor Individual Upper Address Register */
+#define IMX_ENET_IALR_OFFSET     0x011c /* Descriptor Individual Lower Address Register */
+#define IMX_ENET_GAUR_OFFSET     0x0120 /* Descriptor Group Upper Address Register */
+#define IMX_ENET_GALR_OFFSET     0x0124 /* Descriptor Group Lower Address Register */
+#define IMX_ENET_TFWR_OFFSET     0x0144 /* Transmit FIFO Watermark Register */
+#define IMX_ENET_RDSR_OFFSET     0x0180 /* Receive Descriptor Ring Start Register */
+#define IMX_ENET_TDSR_OFFSET     0x0184 /* Transmit Buffer Descriptor Ring Start Register */
+#define IMX_ENET_MRBR_OFFSET     0x0188 /* Maximum Receive Buffer Size Register */
+#define IMX_ENET_RSFL_OFFSET     0x0190 /* Receive FIFO Section Full Threshold */
+#define IMX_ENET_RSEM_OFFSET     0x0194 /* Receive FIFO Section Empty Threshold */
+#define IMX_ENET_RAEM_OFFSET     0x0198 /* Receive FIFO Almost Empty Threshold */
+#define IMX_ENET_RAFL_OFFSET     0x019c /* Receive FIFO Almost Full Threshold */
+#define IMX_ENET_TSEM_OFFSET     0x01a0 /* Transmit FIFO Section Empty Threshold */
+#define IMX_ENET_TAEM_OFFSET     0x01a4 /* Transmit FIFO Almost Empty Threshold */
+#define IMX_ENET_TAFL_OFFSET     0x01a8 /* Transmit FIFO Almost Full Threshold */
+#define IMX_ENET_TIPG_OFFSET     0x01ac /* Transmit Inter-Packet Gap */
+#define IMX_ENET_FTRL_OFFSET     0x01b0 /* Frame Truncation Length */
+#define IMX_ENET_TACC_OFFSET     0x01c0 /* Transmit Accelerator Function Configuration */
+#define IMX_ENET_RACC_OFFSET     0x01c4 /* Receive Accelerator Function Configuration */
+
+/* TODO: statistic registers: 0x02xx */
+
+#define IMX_ENET_ATCR_OFFSET     0x0400 /* Timer Control Register */
+#define IMX_ENET_ATVR_OFFSET     0x0404 /* Timer Value Register */
+#define IMX_ENET_ATOFF_OFFSET    0x0408 /* Timer Offset Register */
+#define IMX_ENET_ATPER_OFFSET    0x040c /* Timer Period Register */
+#define IMX_ENET_ATCOR_OFFSET    0x0410 /* Timer Correction Register */
+#define IMX_ENET_ATINC_OFFSET    0x0414 /* Time-Stamping Clock Period Register */
+#define IMX_ENET_ATSTMP_OFFSET   0x0418 /* Timestamp of Last Transmitted Frame */
+
+#define IMX_ENET_TGSR_OFFSET     0x0604 /* Timer Global Status Register */
+#define IMX_ENET_TCSR0_OFFSET    0x0608 /* Timer Control Status Register */
+#define IMX_ENET_TCCR0_OFFSET    0x060c /* Timer Compare Capture Register */
+#define IMX_ENET_TCSR1_OFFSET    0x0610 /* Timer Control Status Register */
+#define IMX_ENET_TCCR1_OFFSET    0x0614 /* Timer Compare Capture Register */
+#define IMX_ENET_TCSR2_OFFSET    0x0618 /* Timer Control Status Register */
+#define IMX_ENET_TCCR2_OFFSET    0x061c /* Timer Compare Capture Register */
+#define IMX_ENET_TCSR3_OFFSET    0x0620 /* Timer Control Status Register */
+#define IMX_ENET_TCCR3_OFFSET    0x0624 /* Timer Compare Capture Register */
+
+/* Register Addresses ***************************************************************/
+
+#define IMX_ENET_EIR             (IMX_ENET_VBASE+IMX_ENET_EIR_OFFSET)
+#define IMX_ENET_EIMR            (IMX_ENET_VBASE+IMX_ENET_EIMR_OFFSET)
+#define IMX_ENET_RDAR            (IMX_ENET_VBASE+IMX_ENET_RDAR_OFFSET)
+#define IMX_ENET_TDAR            (IMX_ENET_VBASE+IMX_ENET_TDAR_OFFSET)
+#define IMX_ENET_ECR             (IMX_ENET_VBASE+IMX_ENET_ECR_OFFSET)
+#define IMX_ENET_MMFR            (IMX_ENET_VBASE+IMX_ENET_MMFR_OFFSET)
+#define IMX_ENET_MSCR            (IMX_ENET_VBASE+IMX_ENET_MSCR_OFFSET)
+#define IMX_ENET_MIBC            (IMX_ENET_VBASE+IMX_ENET_MIBC_OFFSET)
+#define IMX_ENET_RCR             (IMX_ENET_VBASE+IMX_ENET_RCR_OFFSET)
+#define IMX_ENET_TCR             (IMX_ENET_VBASE+IMX_ENET_TCR_OFFSET)
+#define IMX_ENET_PALR            (IMX_ENET_VBASE+IMX_ENET_PALR_OFFSET)
+#define IMX_ENET_PAUR            (IMX_ENET_VBASE+IMX_ENET_PAUR_OFFSET)
+#define IMX_ENET_OPD             (IMX_ENET_VBASE+IMX_ENET_OPD_OFFSET)
+#define IMX_ENET_IAUR            (IMX_ENET_VBASE+IMX_ENET_IAUR_OFFSET)
+#define IMX_ENET_IALR            (IMX_ENET_VBASE+IMX_ENET_IALR_OFFSET)
+#define IMX_ENET_GAUR            (IMX_ENET_VBASE+IMX_ENET_GAUR_OFFSET)
+#define IMX_ENET_GALR            (IMX_ENET_VBASE+IMX_ENET_GALR_OFFSET)
+#define IMX_ENET_TFWR            (IMX_ENET_VBASE+IMX_ENET_TFWR_OFFSET)
+#define IMX_ENET_RDSR            (IMX_ENET_VBASE+IMX_ENET_RDSR_OFFSET)
+#define IMX_ENET_TDSR            (IMX_ENET_VBASE+IMX_ENET_TDSR_OFFSET)
+#define IMX_ENET_MRBR            (IMX_ENET_VBASE+IMX_ENET_MRBR_OFFSET)
+#define IMX_ENET_RSFL            (IMX_ENET_VBASE+IMX_ENET_RSFL_OFFSET)
+#define IMX_ENET_RSEM            (IMX_ENET_VBASE+IMX_ENET_RSEM_OFFSET)
+#define IMX_ENET_RAEM            (IMX_ENET_VBASE+IMX_ENET_RAEM_OFFSET)
+#define IMX_ENET_RAFL            (IMX_ENET_VBASE+IMX_ENET_RAFL_OFFSET)
+#define IMX_ENET_TSEM            (IMX_ENET_VBASE+IMX_ENET_TSEM_OFFSET)
+#define IMX_ENET_TAEM            (IMX_ENET_VBASE+IMX_ENET_TAEM_OFFSET)
+#define IMX_ENET_TAFL            (IMX_ENET_VBASE+IMX_ENET_TAFL_OFFSET)
+#define IMX_ENET_TIPG            (IMX_ENET_VBASE+IMX_ENET_TIPG_OFFSET)
+#define IMX_ENET_FTRL            (IMX_ENET_VBASE+IMX_ENET_FTRL_OFFSET)
+#define IMX_ENET_TACC            (IMX_ENET_VBASE+IMX_ENET_TACC_OFFSET)
+#define IMX_ENET_RACC            (IMX_ENET_VBASE+IMX_ENET_RACC_OFFSET)
+
+#define IMX_ENET_ATCR            (IMX_ENET_VBASE+IMX_ENET_ATCR_OFFSET)
+#define IMX_ENET_ATVR            (IMX_ENET_VBASE+IMX_ENET_ATVR_OFFSET)
+#define IMX_ENET_ATOFF           (IMX_ENET_VBASE+IMX_ENET_ATOFF_OFFSET)
+#define IMX_ENET_ATPER           (IMX_ENET_VBASE+IMX_ENET_ATPER_OFFSET)
+#define IMX_ENET_ATCOR           (IMX_ENET_VBASE+IMX_ENET_ATCOR_OFFSET)
+#define IMX_ENET_ATINC           (IMX_ENET_VBASE+IMX_ENET_ATINC_OFFSET)
+#define IMX_ENET_ATSTMP          (IMX_ENET_VBASE+IMX_ENET_ATSTMP_OFFSET)
+
+#define IMX_ENET_TGSR            (IMX_ENET_VBASE+IMX_ENET_TGSR_OFFSET)
+#define IMX_ENET_TCSR0           (IMX_ENET_VBASE+IMX_ENET_TCSR0_OFFSET)
+#define IMX_ENET_TCCR0           (IMX_ENET_VBASE+IMX_ENET_TCCR0_OFFSET)
+#define IMX_ENET_TCSR1           (IMX_ENET_VBASE+IMX_ENET_TCSR1_OFFSET)
+#define IMX_ENET_TCCR1           (IMX_ENET_VBASE+IMX_ENET_TCCR1_OFFSET)
+#define IMX_ENET_TCSR2           (IMX_ENET_VBASE+IMX_ENET_TCSR2_OFFSET)
+#define IMX_ENET_TCCR2           (IMX_ENET_VBASE+IMX_ENET_TCCR2_OFFSET)
+#define IMX_ENET_TCSR3           (IMX_ENET_VBASE+IMX_ENET_TCSR3_OFFSET)
+#define IMX_ENET_TCCR3           (IMX_ENET_VBASE+IMX_ENET_TCCR3_OFFSET)
+
+/* Register Bit Definitions *********************************************************/
+
+/* Interrupt Event Register, Interrupt Mask Register */
+
+/* Bits 0-14: Reserved */
+#define ENET_INT_TS_TIMER            (1 << 15) /* Bit 15: Timestamp timer */
+#define ENET_INT_TS_AVAIL            (1 << 16) /* Bit 16: Transmit timestamp available */
+#define ENET_INT_WAKEUP              (1 << 17) /* Bit 17: Node wake-up request indication */
+#define ENET_INT_PLR                 (1 << 18) /* Bit 18: Payload receive error */
+#define ENET_INT_UN                  (1 << 19) /* Bit 19: Transmit FIFO underrun */
+#define ENET_INT_RL                  (1 << 20) /* Bit 20: Collision Retry Limit */
+#define ENET_INT_LC                  (1 << 21) /* Bit 21: Late Collision */
+#define ENET_INT_EBERR               (1 << 22) /* Bit 22: Ethernet Bus Error */
+#define ENET_INT_MII                 (1 << 23) /* Bit 23: MII Interrupt */
+#define ENET_INT_RXB                 (1 << 24) /* Bit 24: Receive Buffer Interrupt */
+#define ENET_INT_RXF                 (1 << 25) /* Bit 25: Receive Frame Interrupt */
+#define ENET_INT_TXB                 (1 << 26) /* Bit 26: Transmit Buffer Interrupt */
+#define ENET_INT_TXF                 (1 << 27) /* Bit 27: Transmit Frame Interrupt */
+#define ENET_INT_GRA                 (1 << 28) /* Bit 28: Graceful Stop Complete */
+#define ENET_INT_BABT                (1 << 29) /* Bit 29: Babbling Transmit Error */
+#define ENET_INT_BABR                (1 << 30) /* Bit 30: Babbling Receive Error */
+                                               /* Bit 31: Reserved */
+
+/* Receive Descriptor Active Register */
+
+/* Bits 0-23: Reserved */
+#define ENET_RDAR                    (1 << 24) /* Bit 24: Receive descriptor active */
+                                               /* Bits 25-31: Reserved */
+
+/* Transmit Descriptor Active Register */
+
+/* Bits 0-23: Reserved */
+#define ENET_TDAR                    (1 << 24) /* Bit 24: Transmit descriptor active */
+                                               /* Bits 25-31: Reserved */
+
+/* Ethernet Control Register */
+
+#define ENET_ECR_RESET               (1 << 0)  /* Bit 0:  Ethernet MAC reset */
+#define ENET_ECR_ETHEREN             (1 << 1)  /* Bit 1:  Ethernet enable */
+#define ENET_ECR_MAGICEN             (1 << 2)  /* Bit 2:  Magic packet detection enable */
+#define ENET_ECR_SLEEP               (1 << 3)  /* Bit 3:  Sleep mode enable */
+#define ENET_ECR_EN1588              (1 << 4)  /* Bit 4:  EN1588 enable */
+                                               /* Bit 5: Reserved */
+#define ENET_ECR_DBGEN               (1 << 6)  /* Bit 6:  Debug enable */
+#define ENET_ECR_STOPEN              (1 << 7)  /* Bit 7:  STOPEN Signal Control */
+#ifdef IMX_ENET_HAS_DBSWAP
+#define ENET_ECR_DBSWP               (1 << 8)  /* Bit 8:  Swap bytes */
+#endif
+                                               /* Bits 9-31: Reserved */
+#define ECR_RESV_VAL                 (7 << 28) /* Reserve val to write */
+
+/* MII Management Frame Register */
+
+#define ENET_MMFR_DATA_SHIFT         (0)       /* Bits 0-15: Management frame data */
+#define ENET_MMFR_DATA_MASK          (0xffff << ENET_MMFR_DATA_SHIFT)
+#define ENET_MMFR_TA_SHIFT           (16)      /* Bits 16-17: Turn around */
+#define ENET_MMFR_TA_MASK            (3 << ENET_MMFR_TA_SHIFT)
+#define ENET_MMFR_RA_SHIFT           (18)      /* Bits 18-22: Register address */
+#define ENET_MMFR_RA_MASK            (31 << ENET_MMFR_RA_SHIFT)
+#define ENET_MMFR_PA_SHIFT           (23)      /* Bits 23-27: PHY address */
+#define ENET_MMFR_PA_MASK            (31 << ENET_MMFR_PA_SHIFT)
+#define ENET_MMFR_OP_SHIFT           (28)      /* Bits 28-29: Operation code */
+#define ENET_MMFR_OP_MASK            (3 << ENET_MMFR_OP_SHIFT)
+#define ENET_MMFR_OP_WRNOTMII        (0 << ENET_MMFR_OP_SHIFT) /* Write frame, not MII compliant */
+#define ENET_MMFR_OP_WRMII           (1 << ENET_MMFR_OP_SHIFT) /* Write frame, MII management frame */
+#define ENET_MMFR_OP_RDMII           (2 << ENET_MMFR_OP_SHIFT) /* Read frame, MII management frame */
+#define ENET_MMFR_OP_RdNOTMII        (3 << ENET_MMFR_OP_SHIFT) /* Read frame, not MII compliant */
+#define ENET_MMFR_ST_SHIFT           (30)                      /* Bits 30-31: Start of frame delimiter */
+#define ENET_MMFR_ST_MASK            (3 << ENET_MMFR_ST_SHIFT)
+
+/* MII Speed Control Register */
+
+/* Bit 0: Reserved */
+#define ENET_MSCR_MII_SPEED_SHIFT    (1)       /* Bits 1-6: MII speed */
+#define ENET_MSCR_MII_SPEED_MASK     (63 << ENET_MSCR_MII_SPEED_SHIFT)
+#define ENET_MSCR_DIS_PRE            (1 << 7)  /* Bit 7:  Disable preamble */
+#define ENET_MSCR_HOLDTIME_SHIFT     (8)       /* Bits 8-10: Holdtime on MDIO output */
+#define ENET_MSCR_HOLDTIME_MASK      (7 << ENET_MSCR_HOLDTIME_SHIFT)
+#define ENET_MSCR_HOLDTIME_1CYCLE    (0 << ENET_MSCR_HOLDTIME_SHIFT) /* 1 internal module clock cycle */
+#define ENET_MSCR_HOLDTIME_2CYCLES   (1 << ENET_MSCR_HOLDTIME_SHIFT) /* 2 internal module clock cycles */
+#define ENET_MSCR_HOLDTIME_3CYCLES   (2 << ENET_MSCR_HOLDTIME_SHIFT) /* 3 internal module clock cycles */
+#define ENET_MSCR_HOLDTIME_8CYCLES   (7 << ENET_MSCR_HOLDTIME_SHIFT) /* 8 internal module clock cycles */
+                                                                     /* Bits 11-31: Reserved */
+
+/* MIB Control Register */
+
+/* Bits 0-28: Reserved */
+#define ENET_MIBC_MIB_CLEAR          (1 << 29) /* Bit 29: MIB clear */
+#define ENET_MIBC_MIB_IDLE           (1 << 30) /* Bit 30: MIB idle */
+#define ENET_MIBC_MIB_DIS            (1 << 31) /* Bit 31: Disable MIB logic */
+
+/* Receive Control Register */
+
+#define ENET_RCR_LOOP                (1 << 0)  /* Bit 0:  Internal loopback */
+#define ENET_RCR_DRT                 (1 << 1)  /* Bit 1:  Disable receive on transmit */
+#define ENET_RCR_MII_MODE            (1 << 2)  /* Bit 2:  Media independent interface mode */
+#define ENET_RCR_PROM                (1 << 3)  /* Bit 3:  Promiscuous mode */
+#define ENET_RCR_BC_REJ              (1 << 4)  /* Bit 4:  Broadcast frame reject */
+#define ENET_RCR_FCE                 (1 << 5)  /* Bit 5:  Flow control enable */
+                                               /* Bits 6-7: Reserved */
+#define ENET_RCR_RMII_MODE           (1 << 8)  /* Bit 8: RMII mode enable */
+#define ENET_RCR_RMII_10T            (1 << 9)  /* Bit 9: Enables 10-Mbps mode of the RMII */
+                                               /* Bits 10-11: Reserved */
+#define ENET_RCR_PADEN               (1 << 12) /* Bit 12: Enable frame padding remove on receive */
+#define ENET_RCR_PAUFWD              (1 << 13) /* Bit 13: Terminate/forward pause frames */
+#define ENET_RCR_CRCFWD              (1 << 14) /* Bit 14: Terminate/forward received CRC */
+#define ENET_RCR_CFEN                (1 << 15) /* Bit 15: MAC control frame enable */
+#define ENET_RCR_MAX_FL_SHIFT        (16)      /* Bits 16-29: Maximum frame length */
+#define ENET_RCR_MAX_FL_MASK         (0x3fff << ENET_RCR_MAX_FL_SHIFT)
+#define ENET_RCR_NLC                 (1 << 30) /* Bit 30: Payload length check disable */
+#define ENET_RCR_GRS                 (1 << 31) /* Bit 31: Graceful receive stopped */
+
+/* Transmit Control Register */
+
+#define ENET_TCR_GTS                 (1 << 0)  /* Bit 0:  Graceful transmit stop */
+                                               /* Bit 1: Reserved */
+#define ENET_TCR_ADDINS              (1 << 8)  /* Bit 8:  Set MAC address on transmit */
+#define ENET_TCR_FDEN                (1 << 2)  /* Bit 2:  Full duplex enable */
+#define ENET_TCR_TFC_PAUSE           (1 << 3)  /* Bit 3:  Transmit frame control pause */
+#define ENET_TCR_RFC_PAUSE           (1 << 4)  /* Bit 4:  Receive frame control pause */
+#define ENET_TCR_ADDSEL_SHIFT        (5)       /* Bits 5-7: Source MAC address select on transmit */
+#define ENET_TCR_ADDSEL_MASK         (7 << ENET_TCR_ADDSEL_SHIFT)
+#define ENET_TCR_ADDSEL_PADDR12      (0 << ENET_TCR_ADDSEL_SHIFT) /* Node MAC address programmed on PADDR1/2 registers */
+#define ENET_TCR_CRCFWD              (1 << 9)                     /* Bit 9:  Forward frame from application with CRC */
+                                                                  /* Bits 10-31: Reserved */
+
+/* Physical Address Lower/Upper Register (32-bits of 48-address) */
+
+/* Physical Address Upper Register */
+
+#define ENET_PAUR_TYPE_SHIFT         (0)       /* Bits 0-15: Type field in PAUSE frame */
+#define ENET_PAUR_TYPE_MASK          (0xffff << ENET_PAUR_TYPE_MASK)
+#define ENET_PAUR_PADDR2_SHIFT       (16)      /* Bits 16-31: Bytes 4 and 5 of the 6-byte address */
+#define ENET_PAUR_PADDR2_MASK        (0xffff << ENET_PAUR_PADDR2_SHIFT)
+
+/* Opcode/Pause Duration Register */
+
+#define ENET_OPD_PAUSE_DUR_SHIFT     (0)       /* Bits 0-15: Pause duration */
+#define ENET_OPD_PAUSE_DUR_MASK      (0xffff << ENET_OPD_PAUSE_DUR_SHIFT)
+#define ENET_OPD_OPCODE_SHIFT        (16)      /* Bits 16-31: Opcode field in PAUSE frames */
+#define ENET_OPD_OPCODE_MASK         (0xffff << ENET_OPD_OPCODE_SHIFT)
+
+/* Descriptor Individual Upper/Lower Address Register
+ * (64-bit address in two 32-bit registers)
+ * Descriptor Group Upper/Lower Address Register
+ * (64-bit address in two 32-bit registers)
+ */
+
+#if 0
+/* Transmit Interrupt Coalescing Register */
+
+#define ENET_TXIC_ICTT_SHIFT         (0)       /* Bits 0-15: Interrupt coalescing timer threshold */
+#define ENET_TXIC_ICTT_SHIFT_MASK    (0xffff << ENET_TXIC_ICTT_SHIFT)
+                                               /* Bits 16-19: Reserved */
+#define ENET_TXIC_ICFT_SHIFT         (20)      /* Bits 0-15: Interrupt coalescing timer threshold */
+#define ENET_TXIC_ICFT_SHIFT_MASK    (0xff << ENET_TXIC_ICFT_SHIFT)
+#define ENET_TXIC_ICTT_ICCS          (1 << 30) /* Bit 30: Interrupt Coalescing Timer Clock Source Select */
+#define ENET_TXIC_ICTT_ICEN          (1 << 31) /* Bit 31: Eable/disabel Interrupt Coalescing */
+
+/* Receive Interrupt Coalescing Register */
+
+#define ENET_RXIC_ICTT_SHIFT         (0)       /* Bits 0-15: Interrupt coalescing timer threshold */
+#define ENET_RXIC_ICTT_SHIFT_MASK    (0xffff << ENET_TXIC_ICTT_SHIFT)
+                                               /* Bits 16-19: Reserved */
+#define ENET_RXIC_ICFT_SHIFT         (20)      /* Bits 0-15: Interrupt coalescing timer threshold */
+#define ENET_RXIC_ICFT_SHIFT_MASK    (0xff << ENET_TXIC_ICFT_SHIFT)
+#define ENET_RXIC_ICTT_ICCS          (1 << 30) /* Bit 30: Interrupt Coalescing Timer Clock Source Select */
+#define ENET_RXIC_ICTT_ICEN          (1 << 31) /* Bit 31: Eable/disabel Interrupt Coalescing */
+
+#endif /* if 0 */
+
+/* Transmit FIFO Watermark Register */
+
+#define ENET_TFWR_TFWR_SHIFT         (0)       /* Bits 0-5: Transmit FIFO write */
+                                               /* Bits 6-7: Reserved */
+#define ENET_TFWR_TFWR_MASK          (63 << ENET_TFWR_TFWR_SHIFT)
+#define ENET_TFWR_STRFWD             (1 << 8)  /* Bit 8: Store and forward enable */
+                                               /* Bits 9-31: Reserved */
+
+/* Receive Descriptor Ring Start Register */
+
+/* Bits 0-2: Reserved */
+#define ENET_RDSR_SHIFT              (3)       /* Bits 3-31: Start of the receive buffer descriptor queue */
+#define ENET_RDSR_MASK               (0xfffffff8)
+
+/* Transmit Buffer Descriptor Ring Start Register */
+
+/* Bits 0-2: Reserved */
+#define ENET_TDSR_SHIFT              (3)       /* Bits 3-31: Start of the transmit buffer descriptor queue */
+#define ENET_TDSR_MASK               (0xfffffff8)
+
+/* Maximum Receive Buffer Size Register */
+
+/* Bits 14-31: Reserved */
+#define ENET_MRBR_SHIFT              (4)       /* Bits 4-11: Receive buffer size in bytes */
+#define ENET_MRBR_MASK               (0x7f << ENET_MRBR_SHIFT)
+                                               /* Bits 0-3: Reserved */
+
+/* Receive FIFO Section Full Threshold */
+
+/* Bits 8-31: Reserved */
+#define ENET_RSFL_SHIFT              (0)       /* Bits 0-7: Value of receive FIFO section full threshold */
+#define ENET_RSFL_MASK               (0xff << ENET_RSFL_SHIFT)
+
+/* Receive FIFO Section Empty Threshold */
+
+#define ENET_RSEM_SHIFT              (0)       /* Bits 0-7: Value of the receive FIFO section empty threshold */
+#define ENET_RSEM_MASK               (0xff << ENET_RSEM_SHIFT)
+                                               /* Bits 8-31: Reserved */
+
+/* Receive FIFO Almost Empty Threshold */
+
+#define ENET_RAEM_SHIFT              (0)       /* Bits 0-7: Value of the receive FIFO almost empty threshold */
+#define ENET_RAEM_MASK               (0xff << ENET_RAEM_SHIFT)
+                                               /* Bits 8-31: Reserved */
+
+/* Receive FIFO Almost Full Threshold */
+
+#define ENET_RAFL_SHIFT              (0)       /* Bits 0-7: Value of the receive FIFO almost full threshold */
+#define ENET_RAFL_MASK               (0xff << ENET_RAFL_SHIFT)
+                                               /* Bits 8-31: Reserved */
+
+/* Transmit FIFO Section Empty Threshold */
+
+#define ENET_TSEM_SHIFT              (0)       /* Bits 0-7: Value of the transmit FIFO section empty threshold */
+#define ENET_TSEM_MASK               (0xff << ENET_TSEM_SHIFT)
+                                               /* Bits 8-31: Reserved */
+
+/* Transmit FIFO Almost Empty Threshold */
+
+#define ENET_TAEM_SHIFT              (0)       /* Bits 0-7: Value of the transmit FIFO section empty threshold */
+#define ENET_TAEM_MASK               (0xff << ENET_TAEM_SHIFT)
+                                               /* Bits 8-31: Reserved */
+
+/* Transmit FIFO Almost Full Threshold */
+
+#define ENET_TAFL_SHIFT              (0)       /* Bits 0-7: Value of the transmit FIFO section empty threshold */
+#define ENET_TAFL_MASK               (0xff << ENET_TAFL_SHIFT)
+                                               /* Bits 8-31: Reserved */
+
+/* Transmit Inter-Packet Gap */
+
+#define ENET_TIPG_SHIFT              (0)       /* Bits 0-4: Value of the transmit FIFO section empty threshold */
+#define ENET_TIPG_MASK               (31 << ENET_TIPG_SHIFT)
+                                               /* Bits 5-31: Reserved */
+
+/* Frame Truncation Length */
+
+#define ENET_FTRL_SHIFT              (0)       /* Bits 0-13: Value of the transmit FIFO section empty threshold */
+#define ENET_FTRL_MASK               (0x3fff << ENET_FTRL_SHIFT)
+                                               /* Bits 14-31: Reserved */
+
+/* Transmit Accelerator Function Configuration */
+
+#define ENET_TACC_SHIFT16            (1 << 0)  /* Bit 0:  TX FIFO shift-16 */
+                                               /* Bits 1-2: Reserved */
+#define ENET_TACC_IPCHK              (1 << 3)  /* Bit 3:  Enables insertion of IP header checksum */
+#define ENET_TACC_PROCHK             (1 << 4)  /* Bit 4:  Enables insertion of protocol checksum */
+                                               /* Bits 5-31: Reserved */
+
+/* Receive Accelerator Function Configuration */
+
+#define ENET_RACC_PADREM             (1 << 0)  /* Bit 0: Enable padding removal for short IP frames */
+#define ENET_RACC_IPDIS              (1 << 1)  /* Bit 1: Enable discard of frames with wrong IPv4 header checksum */
+#define ENET_RACC_PRODIS             (1 << 2)  /* Bit 2: Enable discard of frames with wrong protocol checksum */
+                                               /* Bits 3-5: Reserved */
+#define ENET_RACC_LINEDIS            (1 << 6)  /* Bit 6: Enable discard of frames with MAC layer errors */
+#define ENET_RACC_SHIFT16            (1 << 7)  /* Bit 7: RX FIFO shift-16 */
+                                               /* Bits 8-31: Reserved */
+
+/* Timer Control Register */
+
+#define ENET_ATCR_EN                 (1 << 0)  /* Bit 0:  Enable timer */
+                                               /* Bit 1:  Reserved */
+#define ENET_ATCR_OFFEN              (1 << 2)  /* Bit 2:  Enable one-shot offset event */
+#define ENET_ATCR_OFFRST             (1 << 3)  /* Bit 3:  Reset timer on offset event */
+#define ENET_ATCR_PEREN              (1 << 4)  /* Bit 4:  Enable periodical event */
+                                               /* Bits 5-6: Reserved */
+#define ENET_ATCR_PINPER             (1 << 7)  /* Bit 7:  Enables event signal output assertion on period event */
+                                               /* Bit 8:  Reserved */
+#define ENET_ATCR_RESTART            (1 << 9)  /* Bit 9:  Reset timer */
+                                               /* Bit 10: Reserved */
+#define ENET_ATCR_CAPTURE            (1 << 11) /* Bit 11: Capture timer value */
+                                               /* Bit 12: Reserved */
+#define ENET_ATCR_SLAVE              (1 << 13) /* Bit 13: Enable timer slave mode */
+                                               /* Bits 14-31: Reserved */
+
+/* Timer Value Register (32-bit timer value)
+ * Timer Offset Register (32-bit offset value)
+ * Timer Period Register (32-bit timer period)
+ */
+
+/* Timer Correction Register */
+
+#define ENET_ATCOR_MASK              (0x7fffffff) /* Bits 0-3: Correction counter wrap-around value */
+                                                  /* Bit 31: Reserved */
+
+/* Time-Stamping Clock Period Register */
+
+#define ENET_ATINC_INC_SHIFT         (0)       /* Bits 0-6: Clock period of the timestamping clock (ts_clk) in nanoseconds */
+#define ENET_ATINC_INC_MASK          (0x7f << ENET_ATINC_INC_SHIFT)
+                                               /* Bit 7: Reserved */
+#define ENET_ATINC_INC_CORR_SHIFT    (8)       /* Bits 8-14: Correction increment value */
+#define ENET_ATINC_INC_CORR_MASK     (0x7f << ENET_ATINC_INC_CORR_SHIFT)
+                                               /* Bits 15-31: Reserved */
+
+/* Timestamp of Last Transmitted Frame (32-bit timestamp) */
+
+/* Timer Global Status Register */
+
+#define ENET_TGSR_TF0                (1 << 0)  /* Bit 0:  Copy of Timer Flag for channel 0 */
+#define ENET_TGSR_TF1                (1 << 1)  /* Bit 1:  Copy of Timer Flag for channel 1 */
+#define ENET_TGSR_TF2                (1 << 2)  /* Bit 2:  Copy of Timer Flag for channel 2 */
+#define ENET_TGSR_TF3                (1 << 3)  /* Bit 3:  Copy of Timer Flag for channel 3 */
+                                               /* Bits 14-31: Reserved */
+
+/* Timer Control Status Register n */
+
+#define ENET_TCSR_TDRE               (1 << 0)  /* Bit 0:  Timer DMA Request Enable */
+                                               /* Bit 1: Reserved */
+#define ENET_TCSR_TMODE_SHIFT        (2)       /* Bits 2-5: Timer Mode */
+#define ENET_TCSR_TMODE_MASK         (15 << ENET_TCSR_TMODE_SHIFT)
+#define ENET_TCSR_TMODE_DISABLED     (0 << ENET_TCSR_TMODE_SHIFT)  /* Disabled */
+#define ENET_TCSR_TMODE_ICRISING     (1 << ENET_TCSR_TMODE_SHIFT)  /* Input Capture on rising edge */
+#define ENET_TCSR_TMODE_ICFALLLING   (2 << ENET_TCSR_TMODE_SHIFT)  /* Input Capture on falling edge */
+#define ENET_TCSR_TMODE_ICBOTH       (3 << ENET_TCSR_TMODE_SHIFT)  /* Input Capture on both edges */
+#define ENET_TCSR_TMODE_OCSW         (4 << ENET_TCSR_TMODE_SHIFT)  /* Output Compare, S/W only */
+#define ENET_TCSR_TMODE_OCTOGGLE     (5 << ENET_TCSR_TMODE_SHIFT)  /* Output Compare, toggle on compare */
+#define ENET_TCSR_TMODE_OCCLR        (6 << ENET_TCSR_TMODE_SHIFT)  /* Output Compare, clear on compare */
+#define ENET_TCSR_TMODE_OCSET        (7 << ENET_TCSR_TMODE_SHIFT)  /*  Output Compare, set on compare */
+#define ENET_TCSR_TMODE_OCSETCLR     (9 << ENET_TCSR_TMODE_SHIFT)  /* Output Compare, set on compare, clear on overflow */
+#define ENET_TCSR_TMODE_OCCLRSET     (10 << ENET_TCSR_TMODE_SHIFT) /*  Output Compare, clear on compare, set on overflow */
+#define ENET_TCSR_TMODE_PCPULSEL     (14 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, pulse low on compare */
+#define ENET_TCSR_TMODE_PCPULSEH     (15 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, pulse high on compare */
+
+#define ENET_TCSR_TIE                (1 << 6)  /* Bit 6:  Timer interrupt enable */
+#define ENET_TCSR_TF                 (1 << 7)  /* Bit 7:  Timer Flag */
+                                               /* Bits 8-31: Reserved */
+
+/* Timer Compare Capture Register (32-bit compare value) */
+
+/* Buffer Descriptors ***************************************************************/
+
+/* Endian-independent descriptor offsets */
+
+#define DESC_STATUS1_OFFSET          (0)
+#define DESC_LENGTH_OFFSET           (2)
+#define DESC_DATAPTR_OFFSET          (4)
+#define DESC_LEGACY_LEN              (8)
+
+#define DESC_STATUS2_OFFSET          (8)
+#define DESC_LENPROTO_OFFSET         (12)
+#define DESC_CHECKSUM_OFFSET         (14)
+#define DESC_BDU_OFFSET              (16)
+#define DESC_TIMESTAMP_OFFSET        (20)
+#define DESC_ENHANCED_LEN            (32)
+
+/* Legacy/Common TX Buffer Descriptor Bit Definitions.
+ *
+ *   The descriptors are represented by structures  Unfortunately, when the
+ *   structures are overlaid on the data, the bytes are reversed because
+ *   the underlying hardware writes the data in big-endian byte order.
+ */
+
+#ifdef IMX_ENET_HAS_DBSWAP
+# ifndef CONFIG_ENDIAN_BIG
+#  define IMX_USE_DBSWAP
+# endif
+#else
+# ifndef CONFIG_ENDIAN_BIG
+#  define IMX_BUFFERS_SWAP
+# endif
+#endif
+
+#ifndef IMX_BUFFERS_SWAP
+#  define TXDESC_ABC                 (1 << 9)  /* Legacy */
+#  define TXDESC_TC                  (1 << 10) /* Common */
+#  define TXDESC_L                   (1 << 11) /* Common */
+#  define TXDESC_TO2                 (1 << 12) /* Common */
+#  define TXDESC_W                   (1 << 13) /* Common */
+#  define TXDESC_TO1                 (1 << 14) /* Common */
+#  define TXDESC_R                   (1 << 15) /* Common */
+#else
+#  define TXDESC_ABC                 (1 << 1)  /* Legacy */
+#  define TXDESC_TC                  (1 << 2)  /* Common */
+#  define TXDESC_L                   (1 << 3)  /* Common */
+#  define TXDESC_TO2                 (1 << 4)  /* Common */
+#  define TXDESC_W                   (1 << 5)  /* Common */
+#  define TXDESC_TO1                 (1 << 6)  /* Common */
+#  define TXDESC_R                   (1 << 7)  /* Common */
+#endif
+
+/* Enhanced (only) TX Buffer Descriptor Bit Definitions */
+
+#ifndef IMX_BUFFERS_SWAP
+#  define TXDESC_TSE                 (1 << 8)
+#  define TXDESC_OE                  (1 << 9)
+#  define TXDESC_LCE                 (1 << 10)
+#  define TXDESC_FE                  (1 << 11)
+#  define TXDESC_EE                  (1 << 12)
+#  define TXDESC_UE                  (1 << 13)
+#  define TXDESC_TXE                 (1 << 15)
+
+#  define TXDESC_IINS                (1 << 27)
+#  define TXDESC_PINS                (1 << 28)
+#  define TXDESC_TS                  (1 << 29)
+#  define TXDESC_INT                 (1 << 30)
+
+#  define TXDESC_BDU                 (1 << 31)
+#else
+#  define TXDESC_IINS                (1 << 3)
+#  define TXDESC_PINS                (1 << 4)
+#  define TXDESC_TS                  (1 << 5)
+#  define TXDESC_INT                 (1 << 6)
+
+#  define TXDESC_TSE                 (1 << 16)
+#  define TXDESC_OE                  (1 << 17)
+#  define TXDESC_LCE                 (1 << 18)
+#  define TXDESC_FE                  (1 << 19)
+#  define TXDESC_EE                  (1 << 20)
+#  define TXDESC_UE                  (1 << 21)
+#  define TXDESC_TXE                 (1 << 23)
+
+#  define TXDESC_BDU                 (1 << 7)
+#endif
+
+/* Legacy (and Common) RX Buffer Descriptor Bit Definitions */
+
+#ifndef IMX_BUFFERS_SWAP
+#  define RXDESC_TR                  (1 << 0)
+#  define RXDESC_OV                  (1 << 1)
+#  define RXDESC_CR                  (1 << 2)
+#  define RXDESC_NO                  (1 << 4)
+#  define RXDESC_LG                  (1 << 5)
+#  define RXDESC_MC                  (1 << 6)
+#  define RXDESC_BC                  (1 << 7)
+#  define RXDESC_M                   (1 << 8)
+#  define RXDESC_L                   (1 << 11)
+#  define RXDESC_R02                 (1 << 12)
+#  define RXDESC_W                   (1 << 13)
+#  define RXDESC_R01                 (1 << 14)
+#  define RXDESC_E                   (1 << 15)
+#else
+#  define RXDESC_M                   (1 << 0)
+#  define RXDESC_L                   (1 << 3)
+#  define RXDESC_R02                 (1 << 4)
+#  define RXDESC_W                   (1 << 5)
+#  define RXDESC_R01                 (1 << 6)
+#  define RXDESC_E                   (1 << 7)
+#  define RXDESC_TR                  (1 << 8)
+#  define RXDESC_OV                  (1 << 9)
+#  define RXDESC_CR                  (1 << 10)
+#  define RXDESC_NO                  (1 << 12)
+#  define RXDESC_LG                  (1 << 13)
+#  define RXDESC_MC                  (1 << 14)
+#  define RXDESC_BC                  (1 << 15)
+#endif
+
+/* Enhanced (only) TX Buffer Descriptor Bit Definitions */
+
+#ifndef IMX_BUFFERS_SWAP
+#  define RXDESC_FRAG                (1 << 0)
+#  define RXDESC_IPV6                (1 << 1)
+#  define RXDESC_VLAN                (1 << 2)
+#  define RXDESC_PCR                 (1 << 4)
+#  define RXDESC_ICE                 (1 << 5)
+#  define RXDESC_INT                 (1 << 23)
+#  define RXDESC_UC                  (1 << 24)
+#  define RXDESC_CE                  (1 << 25)
+#  define RXDESC_PE                  (1 << 26)
+#  define RXDESC_ME                  (1 << 31)
+
+#  define RXDESC_BDU                 (1 << 31)
+#else
+#  define RXDESC_UC                  (1 << 0)
+#  define RXDESC_CE                  (1 << 1)
+#  define RXDESC_PE                  (1 << 2)
+#  define RXDESC_ME                  (1 << 7)
+#  define RXDESC_INT                 (1 << 15)
+#  define RXDESC_FRAG                (1 << 24)
+#  define RXDESC_IPV6                (1 << 25)
+#  define RXDESC_VLAN                (1 << 26)
+#  define RXDESC_PCR                 (1 << 28)
+#  define RXDESC_ICE                 (1 << 29)
+
+#  define RXDESC_BDU                 (1 << 7)
+#endif
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+/* Buffer Descriptors ***************************************************************/
+
+/* Legacy Buffer Descriptor */
+
+#ifdef CONFIG_ENET_ENHANCEDBD
+#ifdef IMX_USE_DBSWAP
+/* When DBSWP is used to swap the bytes in hardware, it is done 32-bits
+ * at a time.  Therefore, all 16 bit elements need to be swapped to
+ * compensate.
+ */
+
+struct enet_desc_s
+{
+  uint16_t length;      /* Data length */
+  uint16_t status1;     /* Control and status */
+  uint8_t  *data;       /* Buffer address */
+  uint32_t status2;     /* Extended status */
+  uint16_t checksum;    /* Payload checksum */
+  uint16_t lenproto;    /* Header length + Protocol type */
+  uint32_t bdu;         /* BDU */
+  uint32_t timestamp;   /* Time stamp */
+  uint32_t reserved1;   /* unused */
+  uint32_t reserved2;   /* unused */
+};
+#else
+struct enet_desc_s
+{
+  uint16_t status1;     /* Control and status */
+  uint16_t length;      /* Data length */
+  uint8_t  *data;       /* Buffer address */
+  uint32_t status2;     /* Extended status */
+  uint16_t lenproto;    /* Header length + Protocol type */
+  uint16_t checksum;    /* Payload checksum */
+  uint32_t bdu;         /* BDU */
+  uint32_t timestamp;   /* Time stamp */
+  uint32_t reserved1;   /* unused */
+  uint32_t reserved2;   /* unused */
+};
+#endif /* IMX_USE_DBSWAP */
+#else /* CONFIG_ENET_ENHANCEDBD */
+#ifdef IMX_USE_DBSWAP
+struct enet_desc_s
+{
+  uint16_t length;      /* Data length */
+  uint16_t status1;     /* Control and status */
+  uint8_t  *data;       /* Buffer address */
+};
+#else
+struct enet_desc_s
+{
+  uint16_t status1;     /* Control and status */
+  uint16_t length;      /* Data length */
+  uint8_t  *data;       /* Buffer address */
+};
+#endif /* IMX_USE_DBSWAP */
+#endif /* CONFIG_ENET_ENHANCEDBD */
+
+#endif /* __ARCH_ARM_SRC_IMX6_HARDWARE_IMX_ENET_H */
diff --git a/arch/arm/src/imx6/imx_enet.c b/arch/arm/src/imx6/imx_enet.c
new file mode 100644
index 0000000..e460e6e
--- /dev/null
+++ b/arch/arm/src/imx6/imx_enet.c
@@ -0,0 +1,2549 @@
+/****************************************************************************
+ * arch/arm/src/imx6/imx_enet.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/wdog.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/phy.h>
+#include <nuttx/net/netdev.h>
+
+#ifdef CONFIG_NET_PKT
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include "arm_arch.h"
+#include "gic.h"
+#include "chip.h"
+#include "imx_config.h"
+#include "hardware/imx_enet.h"
+#include "hardware/imx_ccm.h"
+#include "hardware/imx_pinmux.h"
+
+#if 0
+#include "imx_periphclks.h"
+#endif
+
+#include "imx_gpio.h"
+#include "imx_enet.h"
+
+#ifdef CONFIG_IMX6_ENET
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+#  error Work queue support is required
+#else
+
+  /* Select work queue.  Always use the LP work queue if available.  If not,
+   * then LPWORK will re-direct to the HP work queue.
+   *
+   * NOTE:  However, the network should NEVER run on the high priority work
+   * queue!  That queue is intended only to service short back end interrupt
+   * processing that never suspends.  Suspending the high priority work queue
+   * may bring the system to its knees!
+   */
+
+#  define ETHWORK LPWORK
+#endif
+
+/* CONFIG_IMX_ENET_NETHIFS determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#if CONFIG_IMX_ENET_NETHIFS != 1
+#  error "CONFIG_IMX_ENET_NETHIFS must be one for now"
+#endif
+
+#if CONFIG_IMX_ENET_NTXBUFFERS < 1
+#  error "Need at least one TX buffer"
+#endif
+
+#if CONFIG_IMX_ENET_NRXBUFFERS < 1
+#  error "Need at least one RX buffer"
+#endif
+
+#define NENET_NBUFFERS \
+  (CONFIG_IMX_ENET_NTXBUFFERS + CONFIG_IMX_ENET_NRXBUFFERS)
+
+/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
+ * second.
+ */
+
+#define IMX_WDDELAY     (1 * CLK_TCK)
+
+/* Align assuming that the D-Cache is enabled (probably 32-bytes).
+ *
+ * REVISIT: The size of descriptors and buffers must also be in even units
+ * of the cache line size  That is because the operations to clean and
+ * invalidate the cache will operate on a full 32-byte cache line.  If
+ * CONFIG_ENET_ENHANCEDBD is selected, then the size of the descriptor is
+ * 32-bytes (and probably already the correct size for the cache line);
+ * otherwise, the size of the descriptors much smaller, only 8 bytes.
+ */
+
+#define ENET_ALIGN        32 /* TODO */
+#define ENET_ALIGN_MASK   (ENET_ALIGN - 1)
+#define ENET_ALIGN_UP(n)  (((n) + ENET_ALIGN_MASK) & ~ENET_ALIGN_MASK)
+
+/* TX timeout = 1 minute */
+
+#define IMX_TXTIMEOUT   (60 * CLK_TCK)
+#define MII_MAXPOLLS      (0x1ffff)
+#define LINK_WAITUS       (500 * 1000)
+#define LINK_NLOOPS       (10)
+
+/* PHY definitions.
+ *
+ * The selected PHY must be selected from the drivers/net/Kconfig PHY menu.
+ * A description of the PHY must be provided here.  That description must
+ * include:
+ *
+ * 1. BOARD_PHY_NAME: A PHY name string (for debug output),
+ * 2. BOARD_PHYID1 and BOARD_PHYID2: The PHYID1 and PHYID2 values (from
+ *    include/nuttx/net/mii.h)
+ * 3. BOARD_PHY_STATUS:  The address of the status register to use when
+ *    querying link status (from include/nuttx/net/mii.h)
+ * 4. BOARD_PHY_ADDRThe PHY broadcast address of 0 is selected.  This
+ *    should be fine as long as there is only a single PHY.
+ * 5. BOARD_PHY_10BASET:  A macro that can convert the status register
+ *    value into a boolean: true=10Base-T, false=Not 10Base-T
+ * 6. BOARD_PHY_100BASET:  A macro that can convert the status register
+ *    value into a boolean: true=100Base-T, false=Not 100Base-T
+ * 7. BOARD_PHY_ISDUPLEX:  A macro that can convert the status register
+ *    value into a boolean: true=duplex mode, false=half-duplex mode
+ *
+ */
+
+/* TODO:
+ * KSZ9021RN gigabit ethernet phy for sabrelite
+ * AR8031 gigabit ethernet phy for sabre-6quad
+ */
+
+#if defined(CONFIG_ETH0_PHY_KSZ8081)
+#  define BOARD_PHY_NAME        "KSZ8081"
+#  define BOARD_PHYID1          MII_PHYID1_KSZ8081
+#  define BOARD_PHYID2          MII_PHYID2_KSZ8081
+#  define BOARD_PHY_STATUS      MII_KSZ8081_PHYCTRL1
+#  define BOARD_PHY_ADDR        (0)
+#  define BOARD_PHY_10BASET(s)  (((s) & MII_PHYCTRL1_MODE_10HDX) != 0)
+#  define BOARD_PHY_100BASET(s) (((s) & MII_PHYCTRL1_MODE_100HDX) != 0)
+#  define BOARD_PHY_ISDUPLEX(s) (((s) & MII_PHYCTRL1_MODE_DUPLEX) != 0)
+#elif defined(CONFIG_ETH0_PHY_LAN8720)
+#  define BOARD_PHY_NAME        "LAN8720"
+#  define BOARD_PHYID1          MII_PHYID1_LAN8720
+#  define BOARD_PHYID2          MII_PHYID2_LAN8720
+#  define BOARD_PHY_STATUS      MII_LAN8720_SCSR
+#  define BOARD_PHY_ADDR        (1)
+#  define BOARD_PHY_10BASET(s)  (((s)&MII_LAN8720_SPSCR_10MBPS) != 0)
+#  define BOARD_PHY_100BASET(s) (((s)&MII_LAN8720_SPSCR_100MBPS) != 0)
+#  define BOARD_PHY_ISDUPLEX(s) (((s)&MII_LAN8720_SPSCR_DUPLEX) != 0)
+#else
+#  error "Unrecognized or missing PHY selection"
+#endif
+
+/* Estimate the MII_SPEED in order to get an MDC close to 2.5MHz,
+ * based on the internal module (ENET) clock:
+ *
+ *   MII_SPEED = ENET_FREQ/5000000 -1
+ *
+ * For example, if ENET_FREQ_MHZ=120 (MHz):
+ *
+ *   MII_SPEED = 120000000/5000000 -1
+ *             = 23
+ */
+
+#define IMX_MII_SPEED  0x38 /* 100Mbs. Revisit and remove hardcoded value */
+#if IMX_MII_SPEED > 63
+#  error "IMX_MII_SPEED is out-of-range"
+#endif
+
+/* Interrupt groups */
+
+#define RX_INTERRUPTS     (ENET_INT_RXF | ENET_INT_RXB)
+#define TX_INTERRUPTS      ENET_INT_TXF
+#define ERROR_INTERRUPTS  (ENET_INT_UN    | ENET_INT_RL   | ENET_INT_LC | \
+                           ENET_INT_EBERR | ENET_INT_BABT | ENET_INT_BABR)
+
+/* The subset of errors that require us to reset the hardware - this list
+ * may need to be revisited if it's found that some error above leads to a
+ * locking up of the Ethernet interface.
+ */
+
+#define CRITICAL_ERROR    (ENET_INT_UN | ENET_INT_RL | ENET_INT_EBERR)
+
+/* This is a helper pointer for accessing
+ * the contents of the Ethernet header
+ */
+
+#define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
+
+#define IMX_BUF_SIZE  ENET_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The imx_driver_s encapsulates all state information for a single hardware
+ * interface
+ */
+
+struct imx_driver_s
+{
+  bool bifup;                  /* true:ifup false:ifdown */
+  uint8_t txtail;              /* The oldest busy TX descriptor */
+  uint8_t txhead;              /* The next TX descriptor to use */
+  uint8_t rxtail;              /* The next RX descriptor to use */
+  uint8_t phyaddr;             /* Selected PHY address */
+  struct wdog_s txpoll;        /* TX poll timer */
+  struct wdog_s txtimeout;     /* TX timeout timer */
+  struct work_s irqwork;       /* For deferring interrupt work to the work queue */
+  struct work_s pollwork;      /* For deferring poll work to the work queue */
+  struct enet_desc_s *txdesc;  /* A pointer to the list of TX descriptor */
+  struct enet_desc_s *rxdesc;  /* A pointer to the list of RX descriptors */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s dev;     /* Interface understood by the network */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct imx_driver_s g_enet[CONFIG_IMX_ENET_NETHIFS];
+
+/* The DMA descriptors.  A unaligned uint8_t is used to allocate the
+ * memory; 16 is added to assure that we can meet the descriptor alignment
+ * requirements.
+ */
+
+static uint8_t g_desc_pool[NENET_NBUFFERS * sizeof(struct enet_desc_s)]
+               __attribute__((aligned(ENET_ALIGN)));
+
+/* The DMA buffers.  Again, A unaligned uint8_t is used to allocate the
+ * memory; 16 is added to assure that we can meet the descriptor alignment
+ * requirements.
+ */
+
+static uint8_t g_buffer_pool[NENET_NBUFFERS * IMX_BUF_SIZE]
+               __attribute__((aligned(ENET_ALIGN)));
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Utility functions */
+
+#ifndef IMXRT_BUFFERS_SWAP
+#  define imx_swap32(value) (value)
+#  define imx_swap16(value) (value)
+#else
+#if 0 /* Use builtins if the compiler supports them */
+static inline uint32_t imx_swap32(uint32_t value);
+static inline uint16_t imx_swap16(uint16_t value);
+#else
+#  define imx_swap32 __builtin_bswap32
+#  define imx_swap16 __builtin_bswap16
+#endif
+#endif
+
+/* Common TX logic */
+
+static bool imx_txringfull(FAR struct imx_driver_s *priv);
+static int  imx_transmit(FAR struct imx_driver_s *priv);
+static int  imx_txpoll(struct net_driver_s *dev);
+
+/* Interrupt handling */
+
+static void imx_dispatch(FAR struct imx_driver_s *priv);
+static void imx_receive(FAR struct imx_driver_s *priv);
+static void imx_txdone(FAR struct imx_driver_s *priv);
+
+static void imx_enet_interrupt_work(FAR void *arg);
+static int  imx_enet_interrupt(int irq, FAR void *context, FAR void *arg);
+
+/* Watchdog timer expirations */
+
+static void imx_txtimeout_work(FAR void *arg);
+static void imx_txtimeout_expiry(wdparm_t arg);
+
+static void imx_poll_work(FAR void *arg);
+static void imx_polltimer_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  imx_ifup(struct net_driver_s *dev);
+static int  imx_ifdown(struct net_driver_s *dev);
+
+static void imx_txavail_work(FAR void *arg);
+static int  imx_txavail(struct net_driver_s *dev);
+
+/* Internal ifup function that allows phy reset to be optional */
+
+static int imx_ifup_action(struct net_driver_s *dev, bool resetphy);
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int  imx_addmac(struct net_driver_s *dev,
+              FAR const uint8_t *mac);
+static int  imx_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int  imx_ioctl(struct net_driver_s *dev, int cmd,
+            unsigned long arg);
+#endif
+
+/* PHY/MII support */
+
+#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
+static int imx_phyintenable(struct imx_driver_s *priv);
+#endif
+static inline void imx_initmii(struct imx_driver_s *priv);
+
+#if 0 /* TODO */
+static int imx_writemii(struct imx_driver_s *priv, uint8_t phyaddr,
+             uint8_t regaddr, uint16_t data);
+static int imx_readmii(struct imx_driver_s *priv, uint8_t phyaddr,
+             uint8_t regaddr, uint16_t *data);
+#endif
+
+static int imx_initphy(struct imx_driver_s *priv, bool renogphy);
+
+/* Initialization */
+
+static void imx_initbuffers(struct imx_driver_s *priv);
+static void imx_reset(struct imx_driver_s *priv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: imx_txringfull
+ *
+ * Description:
+ *   Check if all of the TX descriptors are in use.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   true is the TX ring is full; false if there are free slots at the
+ *   head index.
+ *
+ ****************************************************************************/
+
+static bool imx_txringfull(FAR struct imx_driver_s *priv)
+{
+  uint8_t txnext;
+
+  /* Check if there is room in the hardware to hold another outgoing
+   * packet.  The ring is full if incrementing the head pointer would
+   * collide with the tail pointer.
+   */
+
+  txnext = priv->txhead + 1;
+  if (txnext >= CONFIG_IMX_ENET_NTXBUFFERS)
+    {
+      txnext = 0;
+    }
+
+  return priv->txtail == txnext;
+}
+
+/****************************************************************************
+ * Function: imx_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int imx_transmit(FAR struct imx_driver_s *priv)
+{
+  struct enet_desc_s *txdesc;
+  irqstate_t flags;
+  uint32_t regval;
+  uint8_t *buf;
+
+  /* Since this can be called from imx_receive, it is possible that
+   * the transmit queue is full, so check for that now.  If this is the
+   * case, the outgoing packet will be dropped (e.g. an ARP reply)
+   */
+
+  if (imx_txringfull(priv))
+    {
+      return -EBUSY;
+    }
+
+  /* When we get here the TX descriptor should show that the previous
+   * transfer has  completed.  If we get here, then we are committed to
+   * sending a packet; Higher level logic must have assured that there is
+   * no transmission in progress.
+   */
+
+  txdesc = &priv->txdesc[priv->txhead];
+  priv->txhead++;
+  if (priv->txhead >= CONFIG_IMX_ENET_NTXBUFFERS)
+    {
+      priv->txhead = 0;
+    }
+
+#ifdef CONFIG_DEBUG_ASSERTIONS
+  up_invalidate_dcache((uintptr_t)txdesc,
+                       (uintptr_t)txdesc + sizeof(struct enet_desc_s));
+
+  DEBUGASSERT(priv->txtail != priv->txhead &&
+             (txdesc->status1 & TXDESC_R) == 0);
+#endif
+
+  /* Increment statistics */
+
+  NETDEV_TXPACKETS(&priv->dev);
+
+  /* Setup the buffer descriptor for transmission: address=priv->dev.d_buf,
+   * length=priv->dev.d_len
+   */
+
+  txdesc->length   = imx_swap16(priv->dev.d_len);
+#ifdef CONFIG_IMX_ENETENHANCEDBD
+  txdesc->bdu      = 0x00000000;
+  txdesc->status2  = TXDESC_INT | TXDESC_TS; /* | TXDESC_IINS | TXDESC_PINS; */
+#endif
+  txdesc->status1 |= (TXDESC_R | TXDESC_L | TXDESC_TC);
+
+  buf = (uint8_t *)imx_swap32((uint32_t)priv->dev.d_buf);
+  if (priv->rxdesc[priv->rxtail].data == buf)
+    {
+      struct enet_desc_s *rxdesc = &priv->rxdesc[priv->rxtail];
+
+      /* Data was written into the RX buffer, so swap the TX and RX buffers */
+
+      DEBUGASSERT((rxdesc->status1 & RXDESC_E) == 0);
+      rxdesc->data = txdesc->data;
+      txdesc->data = buf;
+    }
+  else
+    {
+      DEBUGASSERT(txdesc->data == buf);
+    }
+
+  /* Make the following operations atomic */
+
+  flags = spin_lock_irqsave();
+
+  /* Enable TX interrupts */
+
+  regval  = getreg32(IMX_ENET_EIMR);
+  regval |= TX_INTERRUPTS;
+  putreg32(regval, IMX_ENET_EIMR);
+
+  /* Setup the TX timeout watchdog (perhaps restarting the timer) */
+
+  wd_start(&priv->txtimeout, IMX_TXTIMEOUT,
+           imx_txtimeout_expiry, (wdparm_t)priv);
+
+  /* Start the TX transfer (if it was not already waiting for buffers) */
+
+  putreg32(ENET_TDAR, IMX_ENET_TDAR);
+
+  spin_unlock_irqrestore(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Function: imx_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send timesout and the interface is reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int imx_txpoll(struct net_driver_s *dev)
+{
+  FAR struct imx_driver_s *priv =
+    (FAR struct imx_driver_s *)dev->d_private;
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->dev.d_flags))
+#endif
+        {
+          arp_out(&priv->dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->dev))
+        {
+          /* Send the packet */
+
+          imx_transmit(priv);
+          priv->dev.d_buf = (uint8_t *)
+            imx_swap32((uint32_t)priv->txdesc[priv->txhead].data);
+
+          /* Check if there is room in the device to hold another packet. If
+           * not, return a non-zero value to terminate the poll.
+           */
+
+          if (imx_txringfull(priv))
+            {
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return 0;
+}
+
+/****************************************************************************
+ * Function: imx_dispatch
+ *
+ * Description:
+ *   A new Rx packet was received; dispatch that packet to the network layer
+ *   as necessary.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void imx_dispatch(FAR struct imx_driver_s *priv)
+{
+  /* Update statistics */
+
+  NETDEV_RXPACKETS(&priv->dev);
+
+#ifdef CONFIG_NET_PKT
+  /* When packet sockets are enabled, feed the frame into the packet tap */
+
+  pkt_input(&priv->dev);
+#endif
+
+#ifdef CONFIG_NET_IPv4
+  /* Check for an IPv4 packet */
+
+  if (BUF->type == HTONS(ETHTYPE_IP))
+    {
+      ninfo("IPv4 frame\n");
+      NETDEV_RXIPV4(&priv->dev);
+
+      /* Handle ARP on input then give the IPv4 packet to the network
+       * layer
+       */
+
+      arp_ipin(&priv->dev);
+      ipv4_input(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, the field  d_len will set to a value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+          if (IFF_IS_IPv4(priv->dev.d_flags))
+#endif
+            {
+              arp_out(&priv->dev);
+            }
+#ifdef CONFIG_NET_IPv6
+          else
+            {
+              neighbor_out(&priv->dev);
+            }
+#endif
+
+          /* And send the packet */
+
+          imx_transmit(priv);
+        }
+    }
+  else
+#endif
+#ifdef CONFIG_NET_IPv6
+  /* Check for an IPv6 packet */
+
+  if (BUF->type == HTONS(ETHTYPE_IP6))
+    {
+      ninfo("Iv6 frame\n");
+      NETDEV_RXIPV6(&priv->dev);
+
+      /* Give the IPv6 packet to the network layer */
+
+      ipv6_input(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, the field  d_len will set to a value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+          if (IFF_IS_IPv4(priv->dev.d_flags))
+            {
+              arp_out(&priv->dev);
+            }
+          else
+#endif
+#ifdef CONFIG_NET_IPv6
+            {
+              neighbor_out(&priv->dev);
+            }
+#endif
+
+          /* And send the packet */
+
+          imx_transmit(priv);
+        }
+    }
+  else
+#endif
+#ifdef CONFIG_NET_ARP
+  /* Check for an ARP packet */
+
+  if (BUF->type == htons(ETHTYPE_ARP))
+    {
+      NETDEV_RXARP(&priv->dev);
+      arp_arpin(&priv->dev);
+
+      /* If the above function invocation resulted in data that should
+       * be sent out on the network, the field  d_len will set to a
+       * value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          imx_transmit(priv);
+        }
+    }
+#endif
+  else
+    {
+      NETDEV_RXDROPPED(&priv->dev);
+    }
+}
+
+/****************************************************************************
+ * Function: imx_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void imx_receive(FAR struct imx_driver_s *priv)
+{
+  struct enet_desc_s *rxdesc;
+  bool received;
+
+  /* Loop while there are received packets to be processed */
+
+  do
+    {
+      /* Invalidate the Rx descriptor.  Since it has been modified via DMA,
+       * we must assure that we must invalid any cached values and re-read
+       * the descriptor from the memory.
+       */
+
+      rxdesc = &priv->rxdesc[priv->rxtail];
+      up_invalidate_dcache((uintptr_t)rxdesc,
+                           (uintptr_t)rxdesc + sizeof(struct enet_desc_s));
+
+      /* Check if the data buffer associated with the descriptor has
+       * been filled with valid data.
+       */
+
+      received = ((rxdesc->status1 & RXDESC_E) == 0);
+      if (received)
+        {
+          /* Copy the buffer pointer to priv->dev.d_buf.  Set amount of data
+           * in priv->dev.d_len
+           */
+
+          priv->dev.d_len = imx_swap16(rxdesc->length);
+          priv->dev.d_buf = (uint8_t *)imx_swap32((uint32_t)rxdesc->data);
+
+          /* Invalidate the buffer so that the correct packet will be re-read
+           * from memory when the packet content is accessed.
+           */
+
+          up_invalidate_dcache((uintptr_t)priv->dev.d_buf,
+                               (uintptr_t)priv->dev.d_buf + priv->dev.d_len);
+
+          /* Dispatch (or drop) the newly received packet */
+
+          imx_dispatch(priv);
+
+          /* Point the packet buffer back to the next Tx buffer that will be
+           * used during the next write.  If the write queue is full, then
+           * this will point at an active buffer, which must not be written
+           * to.  This is OK because devif_poll won't be called unless the
+           * queue is not full.
+           */
+
+          priv->dev.d_buf = (uint8_t *)
+            imx_swap32((uint32_t)priv->txdesc[priv->txhead].data);
+          rxdesc->status1 |= RXDESC_E;
+
+          /* Update the index to the next descriptor */
+
+          priv->rxtail++;
+          if (priv->rxtail >= CONFIG_IMX_ENET_NRXBUFFERS)
+            {
+              priv->rxtail = 0;
+            }
+
+          /* Indicate that there have been empty receive buffers produced */
+
+          putreg32(ENET_RDAR, IMX_ENET_RDAR);
+        }
+    }
+  while (received);
+}
+
+/****************************************************************************
+ * Function: imx_txdone
+ *
+ * Description:
+ *   An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void imx_txdone(FAR struct imx_driver_s *priv)
+{
+  struct enet_desc_s *txdesc;
+  uint32_t regval;
+  bool txdone;
+
+  /* We are here because a transmission completed, so the watchdog can be
+   * canceled.
+   */
+
+  wd_cancel(&priv->txtimeout);
+
+  /* Verify that the oldest descriptor descriptor completed */
+
+  do
+    {
+      /* Invalidate the Tx descriptor.  Since status information has been
+       * modified via DMA, we must assure that we must invalid any cached
+       * values and re-read the descriptor from the memory.
+       */
+
+      txdesc = &priv->txdesc[priv->txtail];
+      up_invalidate_dcache((uintptr_t)txdesc,
+                           (uintptr_t)txdesc + sizeof(struct enet_desc_s));
+
+      txdone = false;
+      if ((txdesc->status1 & TXDESC_R) == 0 && priv->txtail != priv->txhead)
+        {
+          /* Yes.. bump up the tail pointer, making space for a new TX
+           * descriptor.
+           */
+
+          priv->txtail++;
+          if (priv->txtail >= CONFIG_IMX_ENET_NTXBUFFERS)
+            {
+              priv->txtail = 0;
+            }
+
+          /* Update statistics */
+
+          NETDEV_TXDONE(&priv->dev);
+          txdone = true;
+        }
+    }
+  while (txdone);
+
+  /* Are there other transmissions queued? */
+
+  if (priv->txtail == priv->txhead)
+    {
+      /* No.. Cancel the TX timeout and disable further Tx interrupts. */
+
+      wd_cancel(&priv->txtimeout);
+
+      regval  = getreg32(IMX_ENET_EIMR);
+      regval &= ~TX_INTERRUPTS;
+      putreg32(regval, IMX_ENET_EIMR);
+    }
+
+  /* There should be space for a new TX in any event.  Poll the network for
+   * new XMIT data
+   */
+
+  devif_poll(&priv->dev, imx_txpoll);
+}
+
+/****************************************************************************
+ * Function: imx_enet_interrupt_work
+ *
+ * Description:
+ *   Perform interrupt related work from the worker thread
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() was called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void imx_enet_interrupt_work(FAR void *arg)
+{
+  FAR struct imx_driver_s *priv = (FAR struct imx_driver_s *)arg;
+  uint32_t pending;
+#ifdef CONFIG_NET_MCASTGROUP
+  uint32_t gaurstore;
+  uint32_t galrstore;
+#endif
+
+  /* Process pending Ethernet interrupts */
+
+  net_lock();
+
+  /* Get the set of unmasked, pending interrupt. */
+
+  pending = getreg32(IMX_ENET_EIR) & getreg32(IMX_ENET_EIMR);
+
+  /* Clear the pending interrupts */
+
+  putreg32(pending, IMX_ENET_EIR);
+
+  /* Check for errors */
+
+  if (pending & ERROR_INTERRUPTS)
+    {
+      /* An error has occurred, update statistics */
+
+      NETDEV_ERRORS(&priv->dev);
+
+      nerr("ERROR: Network interface error occurred (0x%08X)\n",
+           (pending & ERROR_INTERRUPTS));
+    }
+
+  if (pending & CRITICAL_ERROR)
+    {
+      nerr("Critical error, restarting Ethernet interface\n");
+
+      /* Bring the Ethernet chip down and back up but with no need to
+       * reset/renegotiate the phy.
+       */
+
+#ifdef CONFIG_NET_MCASTGROUP
+      /* Just before we pull the rug lets make sure we retain the
+       * multicast hash table.
+       */
+
+      gaurstore = getreg32(IMX_ENET_GAUR);
+      galrstore = getreg32(IMX_ENET_GALR);
+#endif
+
+      imx_ifdown(&priv->dev);
+      imx_ifup_action(&priv->dev, false);
+
+#ifdef CONFIG_NET_MCASTGROUP
+      /* Now write the multicast table back */
+
+      putreg32(gaurstore, IMX_ENET_GAUR);
+      putreg32(galrstore, IMX_ENET_GALR);
+#endif
+
+      /* Then poll the network for new XMIT data */
+
+      devif_poll(&priv->dev, imx_txpoll);
+    }
+  else
+    {
+      /* Check for the receipt of a packet */
+
+      if ((pending & ENET_INT_RXF) != 0)
+        {
+          /* A packet has been received, call imx_receive() to handle the
+           * packet.
+           */
+
+          imx_receive(priv);
+        }
+
+      /* Check if a packet transmission has completed */
+
+      if ((pending & ENET_INT_TXF) != 0)
+        {
+          /* Call imx_txdone to handle the end of transfer even.  NOTE
+           * that this may disable further Tx interrupts if there are no
+           * pending transmissions.
+           */
+
+          imx_txdone(priv);
+        }
+    }
+
+  net_unlock();
+
+  /* Re-enable Ethernet interrupts */
+
+#if 0
+  up_enable_irq(IMX_IRQ_ENET0TMR);
+#endif
+  up_enable_irq(IMX_IRQ_ENET0);
+}
+
+/****************************************************************************
+ * Function: imx_enet_interrupt
+ *
+ * Description:
+ *   Three interrupt sources will vector this this function:
+ *   1. Ethernet MAC transmit interrupt handler
+ *   2. Ethernet MAC receive interrupt handler
+ *   3.
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int imx_enet_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+  register FAR struct imx_driver_s *priv = &g_enet[0];
+
+  /* Disable further Ethernet interrupts.  Because Ethernet interrupts are
+   * also disabled if the TX timeout event occurs, there can be no race
+   * condition here.
+   */
+
+  up_disable_irq(IMX_IRQ_ENET0);
+
+  /* Schedule to perform the interrupt processing on the worker thread. */
+
+  work_queue(ETHWORK, &priv->irqwork, imx_enet_interrupt_work, priv, 0);
+  return OK;
+}
+
+/****************************************************************************
+ * Function: imx_txtimeout_work
+ *
+ * Description:
+ *   Perform TX timeout related work from the worker thread
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void imx_txtimeout_work(FAR void *arg)
+{
+  FAR struct imx_driver_s *priv = (FAR struct imx_driver_s *)arg;
+
+  /* Increment statistics and dump debug info */
+
+  net_lock();
+  nerr("Resetting interface\n");
+
+  NETDEV_TXTIMEOUTS(&priv->dev);
+
+  /* Take the interface down and bring it back up.  That is the most
+   * aggressive hardware reset.
+   */
+
+  imx_ifdown(&priv->dev);
+  imx_ifup_action(&priv->dev, false);
+
+  /* Then poll the network for new XMIT data */
+
+  devif_poll(&priv->dev, imx_txpoll);
+  net_unlock();
+}
+
+/****************************************************************************
+ * Function: imx_txtimeout_expiry
+ *
+ * Description:
+ *   Our TX watchdog timed out.  Called from the timer interrupt handler.
+ *   The last TX never completed.  Reset the hardware and start again.
+ *
+ * Input Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void imx_txtimeout_expiry(wdparm_t arg)
+{
+  FAR struct imx_driver_s *priv = (FAR struct imx_driver_s *)arg;
+
+  /* Disable further Ethernet interrupts.  This will prevent some race
+   * conditions with interrupt work.  There is still a potential race
+   * condition with interrupt work that is already queued and in progress.
+   */
+
+  up_disable_irq(IMX_IRQ_ENET0);
+
+  /* Schedule to perform the TX timeout processing on the worker thread,
+   * canceling any pending interrupt work.
+   */
+
+  work_queue(ETHWORK, &priv->irqwork, imx_txtimeout_work, priv, 0);
+}
+
+/****************************************************************************
+ * Function: imx_poll_work
+ *
+ * Description:
+ *   Perform periodic polling from the worker thread
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void imx_poll_work(FAR void *arg)
+{
+  FAR struct imx_driver_s *priv = (FAR struct imx_driver_s *)arg;
+
+  /* Check if there is there is a transmission in progress.
+   * We cannot perform the TX poll if he are unable to accept
+   * another packet for transmission.
+   */
+
+  net_lock();
+  if (!imx_txringfull(priv))
+    {
+      /* If so, update TCP timing states and poll the network for new XMIT
+       * data. Hmmm.. might be bug here.  Does this mean if there is a
+       * transmit in progress, we will missing TCP time state updates?
+       */
+
+      devif_timer(&priv->dev, IMX_WDDELAY, imx_txpoll);
+    }
+
+  /* Setup the watchdog poll timer again in any case */
+
+  wd_start(&priv->txpoll, IMX_WDDELAY,
+           imx_polltimer_expiry, (wdparm_t)priv);
+  net_unlock();
+}
+
+/****************************************************************************
+ * Function: imx_polltimer_expiry
+ *
+ * Description:
+ *   Periodic timer handler.  Called from the timer interrupt handler.
+ *
+ * Input Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void imx_polltimer_expiry(wdparm_t arg)
+{
+  FAR struct imx_driver_s *priv = (FAR struct imx_driver_s *)arg;
+
+  /* Schedule to perform the poll processing on the worker thread. */
+
+  work_queue(ETHWORK, &priv->pollwork, imx_poll_work, priv, 0);
+}
+
+/****************************************************************************
+ * Function: imx_ifup_action
+ *
+ * Description:
+ *   Internal action routine to bring up the Ethernet interface
+ *   which makes the resetting of the phy (which takes considerable time)
+ *   optional.
+ *
+ * Input Parameters:
+ *   dev      - Reference to the NuttX driver state structure
+ *   resetphy - Flag indicating if Phy is to be reset. If not then the
+ *              phy configuration is just re-loaded into the ethernet
+ *              interface
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int imx_ifup_action(struct net_driver_s *dev, bool resetphy)
+{
+  FAR struct imx_driver_s *priv =
+    (FAR struct imx_driver_s *)dev->d_private;
+  uint8_t *mac = dev->d_mac.ether.ether_addr_octet;
+  uint32_t regval;
+  int ret;
+
+  ninfo("Bringing up: %d.%d.%d.%d\n",
+        (int)dev->d_ipaddr & 0xff,
+        (int)(dev->d_ipaddr >> 8) & 0xff,
+        (int)(dev->d_ipaddr >> 16) & 0xff,
+        (int)dev->d_ipaddr >> 24);
+
+  /* Initialize ENET buffers */
+
+  imx_initbuffers(priv);
+
+  /* Configure the MII interface */
+
+  imx_initmii(priv);
+
+  /* Set the MAC address */
+
+  putreg32((mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3],
+           IMX_ENET_PALR);
+  putreg32((mac[4] << 24) | (mac[5] << 16), IMX_ENET_PAUR);
+
+  /* Configure the PHY */
+
+  ret = imx_initphy(priv, resetphy);
+  if (ret < 0)
+    {
+      nerr("ERROR: Failed to configure the PHY: %d\n", ret);
+      return ret;
+    }
+
+  /* Handle promiscuous mode */
+
+#ifdef CONFIG_NET_PROMISCUOUS
+  regval = getreg32(IMX_ENET_RCR);
+  regval |= ENET_RCR_PROM;
+  putreg32(regval, IMX_ENET_RCR);
+#endif
+
+  /* Select legacy of enhanced buffer descriptor format */
+
+#ifdef CONFIG_IMX_ENETENHANCEDBD
+  putreg32(ENET_ECR_EN1588, IMX_ENET_ECR);
+#else
+  putreg32(0, IMX_ENET_ECR);
+#endif
+
+  /* Set the RX buffer size */
+
+  putreg32(IMX_BUF_SIZE, IMX_ENET_MRBR);
+
+  /* Point to the start of the circular RX buffer descriptor queue */
+
+  putreg32((uint32_t)priv->rxdesc, IMX_ENET_RDSR);
+
+  /* Point to the start of the circular TX buffer descriptor queue */
+
+  putreg32((uint32_t)priv->txdesc, IMX_ENET_TDSR);
+
+  /* And enable the MAC itself */
+
+  regval  = getreg32(IMX_ENET_ECR);
+  regval |= ENET_ECR_ETHEREN
+#ifdef IMX_USE_DBSWAP
+         | ENET_ECR_DBSWP
+#endif
+        ;
+  putreg32(regval, IMX_ENET_ECR);
+
+  /* Indicate that there have been empty receive buffers produced */
+
+  putreg32(ENET_RDAR, IMX_ENET_RDAR);
+
+  /* Set and activate a timer process */
+
+  wd_start(&priv->txpoll, IMX_WDDELAY,
+           imx_polltimer_expiry, (wdparm_t)priv);
+
+  /* Clear all pending ENET interrupt */
+
+  putreg32(RX_INTERRUPTS | ERROR_INTERRUPTS | TX_INTERRUPTS, IMX_ENET_EIR);
+
+  /* Enable RX and error interrupts at the controller (TX interrupts are
+   * still disabled).
+   */
+
+  putreg32(RX_INTERRUPTS | ERROR_INTERRUPTS,
+           IMX_ENET_EIMR);
+
+  /* Mark the interrupt "up" and enable interrupts at the NVIC */
+
+  priv->bifup = true;
+
+#if 0
+  up_enable_irq(IMX_IRQ_ENET0TMR);
+#endif
+  up_enable_irq(IMX_IRQ_ENET0);
+  return OK;
+}
+
+/****************************************************************************
+ * Function: imx_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int imx_ifup(struct net_driver_s *dev)
+{
+  /* The externally available ifup action includes resetting the phy */
+
+  return imx_ifup_action(dev, true);
+}
+
+/****************************************************************************
+ * Function: imx_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int imx_ifdown(struct net_driver_s *dev)
+{
+  FAR struct imx_driver_s *priv =
+    (FAR struct imx_driver_s *)dev->d_private;
+  irqstate_t flags;
+
+  ninfo("Taking down: %d.%d.%d.%d\n",
+        (int)(dev->d_ipaddr & 0xff),
+        (int)((dev->d_ipaddr >> 8) & 0xff),
+        (int)((dev->d_ipaddr >> 16) & 0xff),
+        (int)(dev->d_ipaddr >> 24));
+
+  /* Flush and disable the Ethernet interrupts at the NVIC */
+
+  flags = enter_critical_section();
+
+  up_disable_irq(IMX_IRQ_ENET0);
+  putreg32(0, IMX_ENET_EIMR);
+
+  /* Cancel the TX poll timer and TX timeout timers */
+
+  wd_cancel(&priv->txpoll);
+  wd_cancel(&priv->txtimeout);
+
+  /* Put the EMAC in its reset, non-operational state.  This should be
+   * a known configuration that will guarantee the imx_ifup() always
+   * successfully brings the interface back up.
+   */
+
+  imx_reset(priv);
+
+  /* Mark the device "down" */
+
+  priv->bifup = false;
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Function: imx_txavail_work
+ *
+ * Description:
+ *   Perform an out-of-cycle poll on the worker thread.
+ *
+ * Input Parameters:
+ *   arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void imx_txavail_work(FAR void *arg)
+{
+  FAR struct imx_driver_s *priv = (FAR struct imx_driver_s *)arg;
+
+  /* Ignore the notification if the interface is not yet up */
+
+  net_lock();
+  if (priv->bifup)
+    {
+      /* Check if there is room in the hardware to hold another outgoing
+       * packet.
+       */
+
+      if (!imx_txringfull(priv))
+        {
+          /* No, there is space for another transfer.  Poll the network for
+           * new XMIT data.
+           */
+
+          devif_timer(&priv->dev, 0, imx_txpoll);
+        }
+    }
+
+  net_unlock();
+}
+
+/****************************************************************************
+ * Function: imx_txavail
+ *
+ * Description:
+ *   Driver callback invoked when new TX data is available.  This is a
+ *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ *   latency.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int imx_txavail(struct net_driver_s *dev)
+{
+  FAR struct imx_driver_s *priv =
+    (FAR struct imx_driver_s *)dev->d_private;
+
+  /* Is our single work structure available?  It may not be if there are
+   * pending interrupt actions and we will have to ignore the Tx
+   * availability action.
+   */
+
+  if (work_available(&priv->pollwork))
+    {
+      /* Schedule to serialize the poll on the worker thread. */
+
+      work_queue(ETHWORK, &priv->pollwork, imx_txavail_work, priv, 0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: imx_calcethcrc
+ *
+ * Description:
+ *   Function to calculate the CRC used by IMX to check an Ethernet frame
+ *
+ * Input Parameters:
+ *   data   - the data to be checked
+ *   length - length of the data
+ *
+ * Returned Value:
+ *   crc32
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static uint32_t imx_calcethcrc(const uint8_t *data, size_t length)
+{
+  uint32_t crc    = 0xffffffffu;
+  uint32_t count1 = 0;
+  uint32_t count2 = 0;
+
+  /* Calculates the CRC-32 polynomial on the multicast group address. */
+
+  for (count1 = 0; count1 < length; count1++)
+    {
+      uint8_t c = data[count1];
+
+      for (count2 = 0; count2 < 0x08u; count2++)
+        {
+          if ((c ^ crc) & 1U)
+            {
+              crc >>= 1U;
+              c   >>= 1U;
+              crc  ^= 0xedb88320u;
+            }
+          else
+            {
+              crc >>= 1U;
+              c   >>= 1U;
+            }
+        }
+    }
+
+  return crc;
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_enet_hash_index
+ *
+ * Description:
+ *   Function to find the hash index for multicast address filter
+ *
+ * Input Parameters:
+ *   mac  - The MAC address
+ *
+ * Returned Value:
+ *   hash index
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static uint32_t imx_enet_hash_index(const uint8_t *mac)
+{
+  uint32_t crc;
+  uint32_t hashindex;
+
+  ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+  crc = imx_calcethcrc(mac, 6);
+  hashindex = (crc >> 26) & 0x3f;
+
+  return hashindex;
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_addmac
+ *
+ * Description:
+ *   NuttX Callback: Add the specified MAC address to the hardware multicast
+ *   address filtering
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be added
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int imx_addmac(struct net_driver_s *dev, FAR const uint8_t *mac)
+{
+  uint32_t hashindex;
+  uint32_t temp;
+  uint32_t registeraddress;
+
+  hashindex = imx_enet_hash_index(mac);
+
+  /* Add the MAC address to the hardware multicast routing table */
+
+  if (hashindex > 31)
+    {
+      registeraddress = IMX_ENET_GAUR;
+      hashindex      -= 32;
+    }
+  else
+    {
+      registeraddress = IMX_ENET_GALR;
+    }
+
+  temp  = getreg32(registeraddress);
+  temp |= 1 << hashindex;
+  putreg32(temp, registeraddress);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_rmmac
+ *
+ * Description:
+ *   NuttX Callback: Remove the specified MAC address from the hardware
+ *   multicast address filtering
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be removed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int imx_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac)
+{
+  uint32_t hashindex;
+  uint32_t temp;
+  uint32_t registeraddress;
+
+  /* Remove the MAC address from the hardware multicast routing table */
+
+  hashindex = imx_enet_hash_index(mac);
+
+  if (hashindex > 31)
+    {
+      registeraddress = IMX_ENET_GAUR;
+      hashindex      -= 32;
+    }
+  else
+    {
+      registeraddress = IMX_ENET_GALR;
+    }
+
+  temp  = getreg32(registeraddress);
+  temp &= ~(1 << hashindex);
+  putreg32(temp, registeraddress);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_ioctl
+ *
+ * Description:
+ *   PHY ioctl command handler
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   cmd  - ioctl command
+ *   arg  - Argument accompanying the command
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int imx_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
+{
+#ifdef CONFIG_NETDEV_PHY_IOCTL
+  FAR struct imx_driver_s *priv =
+    (FAR struct imx_driver_s *)dev->d_private;
+#endif
+  int ret;
+
+  switch (cmd)
+    {
+#ifdef CONFIG_NETDEV_PHY_IOCTL
+#ifdef CONFIG_ARCH_PHY_INTERRUPT
+      case SIOCMIINOTIFY: /* Set up for PHY event notifications */
+        {
+          struct mii_ioctl_notify_s *req =
+            (struct mii_ioctl_notify_s *)((uintptr_t)arg);
+
+          ret = phy_notify_subscribe(dev->d_ifname, req->pid, &req->event);
+          if (ret == OK)
+            {
+              /* Enable PHY link up/down interrupts */
+
+              ret = imx_phyintenable(priv);
+            }
+        }
+        break;
+#endif
+
+      case SIOCGMIIPHY: /* Get MII PHY address */
+        {
+          struct mii_ioctl_data_s *req =
+            (struct mii_ioctl_data_s *)((uintptr_t)arg);
+          req->phy_id = priv->phyaddr;
+          ret = OK;
+        }
+        break;
+
+      case SIOCGMIIREG: /* Get register from MII PHY */
+        {
+          struct mii_ioctl_data_s *req =
+            (struct mii_ioctl_data_s *)((uintptr_t)arg);
+          ret = imx_readmii(priv, req->phy_id, req->reg_num, &req->val_out);
+        }
+        break;
+
+      case SIOCSMIIREG: /* Set register in MII PHY */
+        {
+          struct mii_ioctl_data_s *req =
+            (struct mii_ioctl_data_s *)((uintptr_t)arg);
+          ret = imx_writemii(priv, req->phy_id, req->reg_num, req->val_in);
+        }
+        break;
+#endif /* CONFIG_NETDEV_PHY_IOCTL */
+
+      default:
+        ret = -ENOTTY;
+        break;
+    }
+
+  return ret;
+}
+#endif /* CONFIG_NETDEV_IOCTL */
+
+/****************************************************************************
+ * Function: imx_phyintenable
+ *
+ * Description:
+ *  Enable link up/down PHY interrupts.  The interrupt protocol is like this:
+ *
+ *  - Interrupt status is cleared when the interrupt is enabled.
+ *  - Interrupt occurs.  Interrupt is disabled (at the processor level) when
+ *    is received.
+ *  - Interrupt status is cleared when the interrupt is re-enabled.
+ *
+ * Input Parameters:
+ *   priv - A reference to the private driver state structure
+ *
+ * Returned Value:
+ *   OK on success; Negated errno (-ETIMEDOUT) on failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
+static int imx_phyintenable(struct imx_driver_s *priv)
+{
+#if defined(CONFIG_ETH0_PHY_KSZ8051) || defined(CONFIG_ETH0_PHY_KSZ8061) || \
+    defined(CONFIG_ETH0_PHY_KSZ8081)
+  uint16_t phyval;
+  int ret;
+
+  /* Read the interrupt status register in order to clear any pending
+   * interrupts
+   */
+
+  ret = imx_readmii(priv, priv->phyaddr, MII_KSZ8081_INT, &phyval);
+  if (ret == OK)
+    {
+      /* Enable link up/down interrupts */
+
+      ret = imx_writemii(priv, priv->phyaddr, MII_KSZ8081_INT,
+                           (MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN));
+    }
+
+  return ret;
+#else
+#  error Unrecognized PHY
+  return -ENOSYS;
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_initmii
+ *
+ * Description:
+ *   Configure the MII interface
+ *
+ * Input Parameters:
+ *   priv - Reference to the private ENET driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void imx_initmii(struct imx_driver_s *priv)
+{
+  /* Speed is based on the peripheral (bus) clock; hold time is 2 module
+   * clock.  This hold time value may need to be increased on some platforms
+   */
+
+  putreg32(ENET_MSCR_HOLDTIME_2CYCLES |
+           IMX_MII_SPEED << ENET_MSCR_MII_SPEED_SHIFT,
+           IMX_ENET_MSCR);
+}
+
+/****************************************************************************
+ * Function: imx_writemii
+ *
+ * Description:
+ *   Write a 16-bit value to a PHY register.
+ *
+ * Input Parameters:
+ *   priv - Reference to the private ENET driver state structure
+ *   phyaddr - The PHY address
+ *   regaddr - The PHY register address
+ *   data    - The data to write to the PHY register
+ *
+ * Returned Value:
+ *   Zero on success, a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#if 0 /* TODO */
+static int imx_writemii(struct imx_driver_s *priv, uint8_t phyaddr,
+                        uint8_t regaddr, uint16_t data)
+{
+  int timeout;
+
+  /* Clear the MII interrupt bit */
+
+  putreg32(ENET_INT_MII, IMX_ENET_EIR);
+
+  /* Initiate the MII Management write */
+
+  putreg32(data |
+           2 << ENET_MMFR_TA_SHIFT |
+           (uint32_t)regaddr << ENET_MMFR_RA_SHIFT |
+           (uint32_t)phyaddr << ENET_MMFR_PA_SHIFT |
+           ENET_MMFR_OP_WRMII |
+           1 << ENET_MMFR_ST_SHIFT,
+           IMX_ENET_MMFR);
+
+  /* Wait for the transfer to complete */
+
+  for (timeout = 0; timeout < MII_MAXPOLLS; timeout++)
+    {
+      if ((getreg32(IMX_ENET_EIR) & ENET_INT_MII) != 0)
+        {
+          break;
+        }
+    }
+
+  /* Check for a timeout */
+
+  if (timeout == MII_MAXPOLLS)
+    {
+      return -ETIMEDOUT;
+    }
+
+  /* Clear the MII interrupt bit */
+
+  putreg32(ENET_INT_MII, IMX_ENET_EIR);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_reademii
+ *
+ * Description:
+ *   Read a 16-bit value from a PHY register.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the private ENET driver state structure
+ *   phyaddr - The PHY address
+ *   regaddr - The PHY register address
+ *   data    - A pointer to the location to return the data
+ *
+ * Returned Value:
+ *   Zero on success, a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#if 0 /* TODO */
+static int imx_readmii(struct imx_driver_s *priv, uint8_t phyaddr,
+                           uint8_t regaddr, uint16_t *data)
+{
+  int timeout;
+
+  /* Clear the MII interrupt bit */
+
+  putreg32(ENET_INT_MII, IMX_ENET_EIR);
+
+  /* Initiate the MII Management read */
+
+  putreg32(2 << ENET_MMFR_TA_SHIFT |
+           (uint32_t)regaddr << ENET_MMFR_RA_SHIFT |
+           (uint32_t)phyaddr << ENET_MMFR_PA_SHIFT |
+           ENET_MMFR_OP_RDMII |
+           1 << ENET_MMFR_ST_SHIFT,
+           IMX_ENET_MMFR);
+
+  /* Wait for the transfer to complete */
+
+  for (timeout = 0; timeout < MII_MAXPOLLS; timeout++)
+    {
+      if ((getreg32(IMX_ENET_EIR) & ENET_INT_MII) != 0)
+        {
+          break;
+        }
+    }
+
+  /* Check for a timeout */
+
+  if (timeout >= MII_MAXPOLLS)
+    {
+      nerr("ERROR: Timed out waiting for transfer to complete\n");
+      return -ETIMEDOUT;
+    }
+
+  /* Clear the MII interrupt bit */
+
+  putreg32(ENET_INT_MII, IMX_ENET_EIR);
+
+  /* And return the MII data */
+
+  *data = (uint16_t)(getreg32(IMX_ENET_MMFR) & ENET_MMFR_DATA_MASK);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: imx_initphy
+ *
+ * Description:
+ *   Configure the PHY
+ *
+ * Input Parameters:
+ *   priv     - Reference to the private ENET driver state structure
+ *   renogphy - Flag indicating if to perform negotiation of the link
+ *
+ * Returned Value:
+ *   Zero (OK) returned on success; a negated errno value is returned on any
+ *   failure;
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static inline int imx_initphy(struct imx_driver_s *priv, bool renogphy)
+{
+#if 0 /* TODO */
+  uint32_t rcr;
+  uint32_t tcr;
+  uint32_t racc;
+  uint16_t phydata;
+  uint8_t phyaddr    = BOARD_PHY_ADDR;
+  int retries;
+  int ret;
+
+  if (renogphy)
+    {
+      /* Loop (potentially infinitely?) until we successfully communicate
+       * with the PHY. This is 'standard stuff' that should work for any PHY
+       * - we are not communicating with it's 'special' registers
+       * at this point.
+       */
+
+      ninfo("%s: Try phyaddr: %u\n", BOARD_PHY_NAME, phyaddr);
+
+      /* Try to read PHYID1 few times using this address */
+
+      retries = 0;
+      do
+        {
+          nxsig_usleep(LINK_WAITUS);
+
+          ninfo("%s: Read PHYID1, retries=%d\n",
+                BOARD_PHY_NAME, retries + 1);
+
+          phydata = 0xffff;
+          ret     = imx_readmii(priv, phyaddr, MII_PHYID1, &phydata);
+        }
+      while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
+
+      if (retries >= 3)
+        {
+          nerr("ERROR: Failed to read %s PHYID1 at address %d\n",
+               BOARD_PHY_NAME, phyaddr);
+          return -ENOENT;
+        }
+
+      ninfo("%s: Using PHY address %u\n", BOARD_PHY_NAME, phyaddr);
+      priv->phyaddr = phyaddr;
+
+      /* Verify PHYID1.  Compare OUI bits 3-18 */
+
+      ninfo("%s: PHYID1: %04x\n", BOARD_PHY_NAME, phydata);
+      if (phydata != BOARD_PHYID1)
+        {
+          nerr("ERROR: PHYID1=%04x incorrect for %s.  Expected %04x\n",
+               phydata, BOARD_PHY_NAME, BOARD_PHYID1);
+          return -ENXIO;
+        }
+
+      /* Read PHYID2 */
+
+      ret = imx_readmii(priv, phyaddr, MII_PHYID2, &phydata);
+      if (ret < 0)
+        {
+          nerr("ERROR: Failed to read %s PHYID2: %d\n", BOARD_PHY_NAME, ret);
+          return ret;
+        }
+
+      ninfo("%s: PHYID2: %04x\n", BOARD_PHY_NAME, phydata);
+
+      /* Verify PHYID2:  Compare OUI bits 19-24 and the 6-bit model number
+       * (ignoring the 4-bit revision number).
+       */
+
+      if ((phydata & 0xfff0) != (BOARD_PHYID2 & 0xfff0))
+        {
+          nerr("ERROR: PHYID2=%04x incorrect for %s.  Expected %04x\n",
+               (phydata & 0xfff0), BOARD_PHY_NAME, (BOARD_PHYID2 & 0xfff0));
+          return -ENXIO;
+        }
+
+#ifdef CONFIG_ETH0_PHY_KSZ8081
+      /* Reset PHY */
+
+      imx_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
+
+      /* Set RMII mode */
+
+      ret = imx_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
+      if (ret < 0)
+        {
+          nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
+          return ret;
+        }
+
+      /* Indicate 50MHz clock */
+
+      imx_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
+                     (phydata | (1 << 7)));
+
+      /* Switch off NAND Tree mode (in case it was set via pinning) */
+
+      ret = imx_readmii(priv, phyaddr, MII_KSZ8081_OMSO, &phydata);
+      if (ret < 0)
+        {
+          nerr("ERROR: Failed to read MII_KSZ8081_OMSO: %d\n", ret);
+          return ret;
+        }
+
+      imx_writemii(priv, phyaddr, MII_KSZ8081_OMSO,
+                     (phydata & ~(1 << 5)));
+
+      /* Set Ethernet led to green = activity and yellow = link and  */
+
+      ret = imx_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
+      if (ret < 0)
+        {
+          nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
+          return ret;
+        }
+
+      imx_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
+                     (phydata | (1 << 4)));
+
+#elif defined (CONFIG_ETH0_PHY_LAN8720)
+      /* Make sure that PHY comes up in correct mode when it's reset */
+
+      imx_writemii(priv, phyaddr, MII_LAN8720_MODES,
+                     MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL |
+                     MII_LAN8720_MODES_PHYAD(BOARD_PHY_ADDR));
+
+      /* ...and reset PHY */
+
+      imx_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
+#endif
+
+      /* Start auto negotiation */
+
+      ninfo("%s: Start Autonegotiation...\n",  BOARD_PHY_NAME);
+      imx_writemii(priv, phyaddr, MII_MCR,
+                     (MII_MCR_ANRESTART | MII_MCR_ANENABLE));
+
+      /* Wait for auto negotiation to complete */
+
+      for (retries = 0; retries < LINK_NLOOPS; retries++)
+        {
+          ret = imx_readmii(priv, phyaddr, MII_MSR, &phydata);
+          if (ret < 0)
+            {
+              nerr("ERROR: Failed to read %s MII_MSR: %d\n",
+                    BOARD_PHY_NAME, ret);
+              return ret;
+            }
+
+          if (phydata & MII_MSR_ANEGCOMPLETE)
+            {
+              break;
+            }
+
+          nxsig_usleep(LINK_WAITUS);
+        }
+
+      if (phydata & MII_MSR_ANEGCOMPLETE)
+        {
+          ninfo("%s: Autonegotiation complete\n",  BOARD_PHY_NAME);
+          ninfo("%s: MII_MSR: %04x\n", BOARD_PHY_NAME, phydata);
+        }
+      else
+        {
+          /* TODO: Autonegotiation has right now failed. Maybe the Eth cable
+           * is not connected.  PHY chip have mechanisms to configure link
+           * OK. We should leave autconf on, and find a way to re-configure
+           * MCU whenever the link is ready.
+           */
+
+          ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?), "
+                "default to 10Mbs mode\n", \
+                BOARD_PHY_NAME, retries);
+
+          /* Stop auto negotiation */
+
+          imx_writemii(priv, phyaddr, MII_MCR, 0);
+        }
+    }
+
+  /* When we get here we have a (negotiated) speed and duplex. This is also
+   * the point we enter if renegotiation is turned off, so have multiple
+   * attempts at reading the status register in case the PHY isn't awake
+   * properly.
+   */
+
+  retries = 0;
+  do
+    {
+      phydata = 0xffff;
+      ret = imx_readmii(priv, phyaddr, BOARD_PHY_STATUS, &phydata);
+    }
+  while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
+
+  /* If we didn't successfully read anything and we haven't tried a physical
+   * renegotiation then lets do that
+   */
+
+  if (retries >= 3)
+    {
+      if (renogphy == false)
+        {
+          /* Give things one more chance with renegotiation turned on */
+
+          return imx_initphy(priv, true);
+        }
+      else
+        {
+          /* That didn't end well, just give up */
+
+          nerr("ERROR: Failed to read %s BOARD_PHY_STATUS[%02x]: %d\n",
+               BOARD_PHY_NAME, BOARD_PHY_STATUS, ret);
+          return ret;
+        }
+    }
+
+  ninfo("%s: BOARD_PHY_STATUS: %04x\n", BOARD_PHY_NAME, phydata);
+
+  /* Set up the transmit and receive control registers based on the
+   * configuration and the auto negotiation results.
+   */
+
+#ifdef CONFIG_IMX_ENETUSEMII
+  rcr = ENET_RCR_CRCFWD |
+        CONFIG_NET_ETH_PKTSIZE << ENET_RCR_MAX_FL_SHIFT |
+        ENET_RCR_MII_MODE;
+#else
+  rcr = ENET_RCR_RMII_MODE | ENET_RCR_CRCFWD |
+        CONFIG_NET_ETH_PKTSIZE << ENET_RCR_MAX_FL_SHIFT |
+        ENET_RCR_MII_MODE;
+#endif
+  tcr = 0;
+
+  putreg32(rcr, IMX_ENET_RCR);
+  putreg32(tcr, IMX_ENET_TCR);
+
+  /* Enable Discard Of Frames With MAC Layer Errors.
+   * Enable Discard Of Frames With Wrong Protocol Checksum.
+   * Bit 1: Enable discard of frames with wrong IPv4 header checksum.
+   */
+
+  racc = ENET_RACC_PRODIS | ENET_RACC_LINEDIS | ENET_RACC_IPDIS;
+  putreg32(racc, IMX_ENET_RACC);
+
+  /* Setup half or full duplex */
+
+  if (BOARD_PHY_ISDUPLEX(phydata))
+    {
+      /* Full duplex */
+
+      ninfo("%s: Full duplex\n",  BOARD_PHY_NAME);
+      tcr |= ENET_TCR_FDEN;
+    }
+  else
+    {
+      /* Half duplex */
+
+      ninfo("%s: Half duplex\n",  BOARD_PHY_NAME);
+      rcr |= ENET_RCR_DRT;
+    }
+
+  if (BOARD_PHY_10BASET(phydata))
+    {
+      /* 10 Mbps */
+
+      ninfo("%s: 10 Base-T\n",  BOARD_PHY_NAME);
+      rcr |= ENET_RCR_RMII_10T;
+    }
+  else if (BOARD_PHY_100BASET(phydata))
+    {
+      /* 100 Mbps */
+
+      ninfo("%s: 100 Base-T\n",  BOARD_PHY_NAME);
+    }
+  else
+    {
+      /* This might happen if Autonegotiation did not complete(?) */
+
+      nerr("ERROR: Neither 10- nor 100-BaseT reported: PHY STATUS=%04x\n",
+           phydata);
+      return -EIO;
+    }
+
+  putreg32(rcr, IMX_ENET_RCR);
+  putreg32(tcr, IMX_ENET_TCR);
+#endif
+  return OK;
+}
+
+/****************************************************************************
+ * Function: imx_initbuffers
+ *
+ * Description:
+ *   Initialize ENET buffers and descriptors
+ *
+ * Input Parameters:
+ *   priv - Reference to the private ENET driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void imx_initbuffers(struct imx_driver_s *priv)
+{
+  uintptr_t addr;
+  int i;
+
+  /* Get an aligned TX descriptor (array) address */
+
+  addr         = (uintptr_t)g_desc_pool;
+  priv->txdesc = (struct enet_desc_s *)addr;
+
+  /* Get an aligned RX descriptor (array) address */
+
+  addr        +=  CONFIG_IMX_ENET_NTXBUFFERS * sizeof(struct enet_desc_s);
+  priv->rxdesc = (struct enet_desc_s *)addr;
+
+  /* Get the beginning of the first aligned buffer */
+
+  addr         = (uintptr_t)g_buffer_pool;
+
+  /* Then fill in the TX descriptors */
+
+  for (i = 0; i < CONFIG_IMX_ENET_NTXBUFFERS; i++)
+    {
+      priv->txdesc[i].status1 = 0;
+      priv->txdesc[i].length  = 0;
+      priv->txdesc[i].data    = (uint8_t *)imx_swap32((uint32_t)addr);
+#ifdef CONFIG_IMX_ENETENHANCEDBD
+      priv->txdesc[i].status2 = TXDESC_IINS | TXDESC_PINS;
+#endif
+      addr                   += IMX_BUF_SIZE;
+    }
+
+  /* Then fill in the RX descriptors */
+
+  for (i = 0; i < CONFIG_IMX_ENET_NRXBUFFERS; i++)
+    {
+      priv->rxdesc[i].status1 = RXDESC_E;
+      priv->rxdesc[i].length  = 0;
+      priv->rxdesc[i].data    = (uint8_t *)imx_swap32((uint32_t)addr);
+#ifdef CONFIG_IMX_ENETENHANCEDBD
+      priv->rxdesc[i].bdu     = 0;
+      priv->rxdesc[i].status2 = RXDESC_INT;
+#endif
+      addr                   += IMX_BUF_SIZE;
+    }
+
+  /* Set the wrap bit in the last descriptors to form a ring */
+
+  priv->txdesc[CONFIG_IMX_ENET_NTXBUFFERS - 1].status1 |= TXDESC_W;
+  priv->rxdesc[CONFIG_IMX_ENET_NRXBUFFERS - 1].status1 |= RXDESC_W;
+
+  /* We start with RX descriptor 0 and with no TX descriptors in use */
+
+  priv->txtail = 0;
+  priv->txhead = 0;
+  priv->rxtail = 0;
+
+  /* Initialize the packet buffer, which is used when sending */
+
+  priv->dev.d_buf =
+    (uint8_t *)imx_swap32((uint32_t)priv->txdesc[priv->txhead].data);
+}
+
+/****************************************************************************
+ * Function: imx_reset
+ *
+ * Description:
+ *   Put the EMAC in the non-operational, reset state
+ *
+ * Input Parameters:
+ *   priv - Reference to the private ENET driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void imx_reset(struct imx_driver_s *priv)
+{
+  unsigned int i;
+
+  /* Set the reset bit and clear the enable bit */
+
+  putreg32(ENET_ECR_RESET, IMX_ENET_ECR);
+
+  /* Wait at least 8 clock cycles */
+
+  for (i = 0; i < 10; i++)
+    {
+      asm volatile ("nop");
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: imx_netinitialize
+ *
+ * Description:
+ *   Initialize the Ethernet controller and driver
+ *
+ * Input Parameters:
+ *   intf - In the case where there are multiple EMACs, this value
+ *          identifies which EMAC is to be initialized.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int imx_netinitialize(int intf)
+{
+  struct imx_driver_s *priv;
+#ifdef CONFIG_NET_ETHERNET
+  uint32_t uidl  = 0;
+  uint32_t uidml = 0;
+  uint8_t *mac;
+#endif
+  int ret;
+
+  /* Get the interface structure associated with this interface number. */
+
+  DEBUGASSERT(intf < CONFIG_IMX_ENET_NETHIFS);
+  priv = &g_enet[intf];
+
+#if 0 /* TODO */
+  uint32_t regval;
+
+  /* Enable ENET1_TX_CLK_DIR (Provides 50MHz clk OUT to PHY) */
+
+  regval = getreg32(IMX_IOMUXC_GPR_GPR1);
+  regval |= GPR_GPR1_ENET1_TX_CLK_OUT_EN;
+  putreg32(regval, IMX_IOMUXC_GPR_GPR1);
+
+  /* Enable the ENET clock.  Clock is on during all modes,
+   * except STOP mode.
+   */
+
+  imx_clockall_enet();
+
+  /* Configure all ENET/MII pins */
+
+  imx_config_gpio(GPIO_ENET_MDIO);
+  imx_config_gpio(GPIO_ENET_MDC);
+  imx_config_gpio(GPIO_ENET_RX_EN);
+  imx_config_gpio(GPIO_ENET_RX_DATA00);
+  imx_config_gpio(GPIO_ENET_RX_DATA01);
+  imx_config_gpio(GPIO_ENET_TX_DATA00);
+  imx_config_gpio(GPIO_ENET_TX_DATA01);
+  imx_config_gpio(GPIO_ENET_TX_CLK);
+  imx_config_gpio(GPIO_ENET_TX_EN);
+#ifdef GPIO_ENET_RX_ER
+  imx_config_gpio(GPIO_ENET_RX_ER);
+#endif
+
+#endif /* TODO */
+
+  /* Attach the Ethernet MAC IEEE 1588 timer interrupt handler */
+
+#if 0
+  if (irq_attach(IMX_IRQ_ENET0TMR, imx_tmrinterrupt, NULL))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach ENET0TMR IRQ\n");
+      return -EAGAIN;
+    }
+#endif
+
+  /* Attach the Ethernet interrupt handler */
+
+  if (irq_attach(IMX_IRQ_ENET0, imx_enet_interrupt, NULL))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach ENET0 IRQ\n");
+      return -EAGAIN;
+    }
+
+  /* Configure as a (high) level interrupt */
+
+  arm_gic_irq_trigger(IMX_IRQ_ENET0, false);
+
+  /* Initialize the driver structure */
+
+  memset(priv, 0, sizeof(struct imx_driver_s));
+  priv->dev.d_ifup    = imx_ifup;     /* I/F up (new IP address) callback */
+  priv->dev.d_ifdown  = imx_ifdown;   /* I/F down callback */
+  priv->dev.d_txavail = imx_txavail;  /* New TX data callback */
+#ifdef CONFIG_NET_MCASTGROUP
+  priv->dev.d_addmac  = imx_addmac;   /* Add multicast MAC address */
+  priv->dev.d_rmmac   = imx_rmmac;    /* Remove multicast MAC address */
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+  priv->dev.d_ioctl   = imx_ioctl;    /* Support PHY ioctl() calls */
+#endif
+  priv->dev.d_private = g_enet;       /* Used to recover private state from dev */
+
+#ifdef CONFIG_NET_ETHERNET
+  /* Determine a semi-unique MAC address from MCU UID
+   * We use UID Low and Mid Low registers to get 64 bits, from which we keep
+   * 48 bits.  We then force unicast and locally administered bits
+   * (b0 and b1, 1st octet)
+   */
+
+  /* hardcoded offset: todo: need proper header file */
+
+#if 0 /* TODO */
+  uidl   = getreg32(IMX_OCOTP_BASE + 0x410);
+  uidml  = getreg32(IMX_OCOTP_BASE + 0x420);
+#endif
+
+  mac    = priv->dev.d_mac.ether.ether_addr_octet;
+
+  uidml |= 0x00000200;
+  uidml &= 0x0000feff;
+
+  mac[0] = (uidml & 0x0000ff00) >> 8;
+  mac[1] = (uidml & 0x000000ff);
+  mac[2] = (uidl &  0xff000000) >> 24;
+  mac[3] = (uidl &  0x00ff0000) >> 16;
+  mac[4] = (uidl &  0x0000ff00) >> 8;
+  mac[5] = (uidl &  0x000000ff);
+#endif
+
+#ifdef CONFIG_IMX_ENET_PHYINIT
+  /* Perform any necessary, one-time, board-specific PHY initialization */
+
+  ret = imx_phy_boardinitialize(0);
+  if (ret < 0)
+    {
+      nerr("ERROR: Failed to initialize the PHY: %d\n", ret);
+      return ret;
+    }
+#endif
+
+  /* Put the interface in the down state.  This usually amounts to resetting
+   * the device and/or calling imx_ifdown().
+   */
+
+  imx_ifdown(&priv->dev);
+
+  /* Register the device with the OS so that socket IOCTLs can be performed */
+
+  netdev_register(&priv->dev, NET_LL_ETHERNET);
+
+  UNUSED(ret);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_netinitialize
+ *
+ * Description:
+ *   Initialize the first network interface.  If there are more than one
+ *   interface in the chip, then board-specific logic will have to provide
+ *   this function to determine which, if any, Ethernet controllers should
+ *   be initialized.
+ *
+ ****************************************************************************/
+
+#if CONFIG_IMX_ENET_NETHIFS == 1 && !defined(CONFIG_NETDEV_LATEINIT)
+void arm_netinitialize(void)
+{
+  imx_netinitialize(0);
+}
+#endif
+
+#endif /* CONFIG_IMX_ENET */
diff --git a/arch/arm/src/imx6/imx_enet.h b/arch/arm/src/imx6/imx_enet.h
new file mode 100644
index 0000000..b8e59e0
--- /dev/null
+++ b/arch/arm/src/imx6/imx_enet.h
@@ -0,0 +1,108 @@
+/************************************************************************************
+ * arch/arm/src/imx6/imx_enet.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_IMX6_IMX_ENET_H
+#define __ARCH_ARM_SRC_IMX6_IMX_ENET_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "hardware/imx_enet.h"
+
+#ifdef CONFIG_IMX_ENET
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/* Definitions for use with imx_phy_boardinitialize */
+
+#define EMAC_INTF 0
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/************************************************************************************
+ * Function: up_netinitialize
+ *
+ * Description:
+ *   Initialize the first network interface.  If there are more than one
+ *   interface in the chip, then board-specific logic will have to provide
+ *   this function to determine which, if any, Ethernet controllers should
+ *   be initialized.  Also prototyped in up_internal.h.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *   Called very early in the initialization sequence.
+ *
+ ************************************************************************************/
+
+void up_netinitialize(void);
+
+/************************************************************************************
+ * Function: imx_phy_boardinitialize
+ *
+ * Description:
+ *   Some boards require specialized initialization of the PHY before it can be
+ *   used.  This may include such things as configuring GPIOs, resetting the PHY,
+ *   etc.  If CONFIG_IMX_ENET_PHYINIT is defined in the configuration then the
+ *   board specific logic must provide imx_phyinitialize();  The i.MX RT Ethernet
+ *   driver will call this function one time before it first uses the PHY.
+ *
+ * Input Parameters:
+ *   intf - Always zero for now.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ************************************************************************************/
+
+#ifdef CONFIG_IMX_ENET_PHYINIT
+int imx_phy_boardinitialize(int intf);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_IMX_ENET */
+#endif /* __ARCH_ARM_SRC_IMX6_IMX_ENET_H */
diff --git a/boards/arm/imx6/sabre-6quad/configs/netnsh/defconfig b/boards/arm/imx6/sabre-6quad/configs/netnsh/defconfig
new file mode 100644
index 0000000..b53d32a
--- /dev/null
+++ b/boards/arm/imx6/sabre-6quad/configs/netnsh/defconfig
@@ -0,0 +1,88 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="sabre-6quad"
+CONFIG_ARCH_BOARD_SABRE_6QUAD=y
+CONFIG_ARCH_BUTTONS=y
+CONFIG_ARCH_CHIP="imx6"
+CONFIG_ARCH_CHIP_IMX6=y
+CONFIG_ARCH_CHIP_IMX6_6QUAD=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_IRQBUTTONS=y
+CONFIG_ARCH_LOWVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARD_LOOPSPERMSEC=99369
+CONFIG_BOOT_RUNFROMSDRAM=y
+CONFIG_BUILTIN=y
+CONFIG_CLOCK_MONOTONIC=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_ERROR=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_NET=y
+CONFIG_DEBUG_NET_ERROR=y
+CONFIG_DEBUG_NET_WARN=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEBUG_WARN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ETH0_PHY_KSZ8081=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IMX6_ENET=y
+CONFIG_IMX6_UART1=y
+CONFIG_IMX_DDR_SIZE=1073741824
+CONFIG_INTELHEX_BINARY=y
+CONFIG_MAX_TASKS=16
+CONFIG_NET=y
+CONFIG_NETDB_DNSCLIENT=y
+CONFIG_NETDB_DNSCLIENT_ENTRIES=4
+CONFIG_NETDB_DNSSERVER_NOADDR=y
+CONFIG_NETINIT_DRIPADDR=0x0a000201
+CONFIG_NETINIT_IPADDR=0x0a00020f
+CONFIG_NETINIT_NOMAC=y
+CONFIG_NETUTILS_DHCPC=y
+CONFIG_NETUTILS_TELNETD=y
+CONFIG_NETUTILS_TFTPC=y
+CONFIG_NETUTILS_WEBCLIENT=y
+CONFIG_NET_BROADCAST=y
+CONFIG_NET_ETH_PKTSIZE=1500
+CONFIG_NET_ICMP=y
+CONFIG_NET_ICMP_SOCKET=y
+CONFIG_NET_MAX_LISTENPORTS=8
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_TCP=y
+CONFIG_NET_UDP=y
+CONFIG_NET_UDP_CHECKSUMS=y
+CONFIG_NFILE_DESCRIPTORS=8
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=1073741824
+CONFIG_RAM_START=0x10000000
+CONFIG_RAM_VSTART=0x10000000
+CONFIG_RAW_BINARY=y
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=192
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=23
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2020
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART1_SERIAL_CONSOLE=y
+CONFIG_USER_ENTRYPOINT="nsh_main"