Skip to content
stm32_eth.c 118 KiB
Newer Older
/****************************************************************************
 * arch/arm/src/stm32/stm32_eth.c
 *
 *   Copyright (C) 2011-2012, 2014, 2016-2018 Gregory Nutt. All rights
 *     reserved.
 *   Author: Gregory Nutt <gnutt@nuttx.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#if defined(CONFIG_NET) && defined(CONFIG_STM32_ETHMAC)

#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <debug.h>
#include <queue.h>
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/net/phy.h>
#if defined(CONFIG_NET_PKT)
#include "up_internal.h"

#include "stm32_gpio.h"
#include "stm32_rcc.h"
#include "stm32_syscfg.h"
#include <arch/board/board.h>

/* STM32_NETHERNET determines the number of physical interfaces
 * that will be supported.
 */

#if STM32_NETHERNET > 0

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/
/* Configuration ************************************************************/
/* See configs/stm3240g-eval/README.txt for an explanation of the configuration
 * settings.
 */

#if STM32_NETHERNET > 1
#  error "Logic to support multiple Ethernet interfaces is incomplete"
#endif
Gregory Nutt's avatar
Gregory Nutt committed
/* Work queue support is required. */
#if !defined(CONFIG_SCHED_WORKQUEUE)
#  error Work queue support is required

#  if defined(CONFIG_STM32_ETHMAC_HPWORK)
#    define ETHWORK HPWORK
#  elif defined(CONFIG_STM32_ETHMAC_LPWORK)
#    define ETHWORK LPWORK
#  else
#    error Neither CONFIG_STM32_ETHMAC_HPWORK nor CONFIG_STM32_ETHMAC_LPWORK defined
#  endif
#if !defined(CONFIG_STM32_SYSCFG) && !defined(CONFIG_STM32_CONNECTIVITYLINE)
#  error "CONFIG_STM32_SYSCFG must be defined in the NuttX configuration"
#endif

#ifndef CONFIG_STM32_PHYADDR
#  error "CONFIG_STM32_PHYADDR must be defined in the NuttX configuration"
#endif

#if !defined(CONFIG_STM32_MII) && !defined(CONFIG_STM32_RMII)
#  warning "Neither CONFIG_STM32_MII nor CONFIG_STM32_RMII defined"
#endif

#if defined(CONFIG_STM32_MII) && defined(CONFIG_STM32_RMII)
#  error "Both CONFIG_STM32_MII and CONFIG_STM32_RMII defined"
#endif

#ifdef CONFIG_STM32_MII
#  if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX)
#    if !defined(CONFIG_STM32_MII_MCO1) && !defined(CONFIG_STM32_MII_MCO2) && !defined(CONFIG_STM32_MII_EXTCLK)
#      warning "Neither CONFIG_STM32_MII_MCO1, CONFIG_STM32_MII_MCO2, nor CONFIG_STM32_MII_EXTCLK defined"
#    endif
#    if defined(CONFIG_STM32_MII_MCO1) && defined(CONFIG_STM32_MII_MCO2)
#      error "Both CONFIG_STM32_MII_MCO1 and CONFIG_STM32_MII_MCO2 defined"
#    endif
#  elif defined(CONFIG_STM32_CONNECTIVITYLINE)
#    if !defined(CONFIG_STM32_MII_MCO) && !defined(CONFIG_STM32_MII_EXTCLK)
#      warning "Neither CONFIG_STM32_MII_MCO nor CONFIG_STM32_MII_EXTCLK defined"
#    endif
#  endif
#endif

#ifdef CONFIG_STM32_RMII
#  if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX)
#    if !defined(CONFIG_STM32_RMII_MCO1) && !defined(CONFIG_STM32_RMII_MCO2) && !defined(CONFIG_STM32_RMII_EXTCLK)
#      warning "Neither CONFIG_STM32_RMII_MCO1, CONFIG_STM32_RMII_MCO2, nor CONFIG_STM32_RMII_EXTCLK defined"
#    endif
#    if defined(CONFIG_STM32_RMII_MCO1) && defined(CONFIG_STM32_RMII_MCO2)
#      error "Both CONFIG_STM32_RMII_MCO1 and CONFIG_STM32_RMII_MCO2 defined"
#    endif
#  elif defined(CONFIG_STM32_CONNECTIVITYLINE)
#    if !defined(CONFIG_STM32_RMII_MCO) && !defined(CONFIG_STM32_RMII_EXTCLK)
#      warning "Neither CONFIG_STM32_RMII_MCO nor CONFIG_STM32_RMII_EXTCLK defined"
#  endif
#endif

#ifdef CONFIG_STM32_AUTONEG
#  ifndef CONFIG_STM32_PHYSR
#    error "CONFIG_STM32_PHYSR must be defined in the NuttX configuration"
#  ifdef CONFIG_STM32_PHYSR_ALTCONFIG
#    ifndef CONFIG_STM32_PHYSR_ALTMODE
#      error "CONFIG_STM32_PHYSR_ALTMODE must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_10HD
#      error "CONFIG_STM32_PHYSR_10HD must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_100HD
#      error "CONFIG_STM32_PHYSR_100HD must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_10FD
#      error "CONFIG_STM32_PHYSR_10FD must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_100FD
#      error "CONFIG_STM32_PHYSR_100FD must be defined in the NuttX configuration"
#    endif
#  else
#    ifndef CONFIG_STM32_PHYSR_SPEED
#      error "CONFIG_STM32_PHYSR_SPEED must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_100MBPS
#      error "CONFIG_STM32_PHYSR_100MBPS must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_MODE
#      error "CONFIG_STM32_PHYSR_MODE must be defined in the NuttX configuration"
#    endif
#    ifndef CONFIG_STM32_PHYSR_FULLDUPLEX
#      error "CONFIG_STM32_PHYSR_FULLDUPLEX must be defined in the NuttX configuration"
#    endif
/* These definitions are used to enable the PHY interrupts */

#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
#  if defined( CONFIG_ETH0_PHY_AM79C874)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_KS8721)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_KSZ8041)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_KSZ8051)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_KSZ8061)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_KSZ8081)
#    define MII_INT_REG    MII_KSZ8081_INT
#    define MII_INT_SETEN  MII_KSZ80x1_INT_LDEN | MII_KSZ80x1_INT_LUEN
#    define MII_INT_CLREN  0
#  elif defined( CONFIG_ETH0_PHY_KSZ90x1)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_DP83848C)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_LAN8720)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_LAN8740)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_LAN8740A)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_LAN8742A)
#    error missing logic
#  elif defined( CONFIG_ETH0_PHY_DM9161)
#    error missing logic
#  else
#    error unknown PHY
#  endif
#ifdef CONFIG_STM32_ETH_PTP
#  warning "CONFIG_STM32_ETH_PTP is not yet supported"
#endif

/* This driver does not use enhanced descriptors.  Enhanced descriptors must
 * be used, however, if time stamping or and/or IPv4 checksum offload is
 * supported.
#undef CONFIG_STM32_ETH_ENHANCEDDESC
#undef CONFIG_STM32_ETH_HWCHECKSUM
/* Add 4 to the configured buffer size to account for the 2 byte checksum
patacongo's avatar
patacongo committed
 * memory needed at the end of the maximum size packet.  Buffer sizes must
 * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
 * will use the 16-byte alignment in all cases.
#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_MTU + 4 + 15) & ~15)
#ifndef CONFIG_STM32_ETH_BUFSIZE
#  define CONFIG_STM32_ETH_BUFSIZE OPTIMAL_ETH_BUFSIZE

#if CONFIG_STM32_ETH_BUFSIZE > ETH_TDES1_TBS1_MASK
#  error "CONFIG_STM32_ETH_BUFSIZE is too large"
#endif

patacongo's avatar
patacongo committed
#if (CONFIG_STM32_ETH_BUFSIZE & 15) != 0
#  error "CONFIG_STM32_ETH_BUFSIZE must be aligned"
#endif

#if CONFIG_STM32_ETH_BUFSIZE != OPTIMAL_ETH_BUFSIZE
#  warning "You using an incomplete/untested configuration"
#endif

#ifndef CONFIG_STM32_ETH_NRXDESC
#  define CONFIG_STM32_ETH_NRXDESC 8
#ifndef CONFIG_STM32_ETH_NTXDESC
#  define CONFIG_STM32_ETH_NTXDESC 4
/* We need at least one more free buffer than transmit buffers */

#define STM32_ETH_NFREEBUFFERS (CONFIG_STM32_ETH_NTXDESC+1)
/* Extremely detailed register debug that you would normally never want
 * enabled.
 */

#  undef CONFIG_STM32_ETHMAC_REGDEBUG
#endif

/* Clocking *****************************************************************/
/* Set MACMIIAR CR bits depending on HCLK setting */

#if STM32_HCLK_FREQUENCY >= 20000000 && STM32_HCLK_FREQUENCY < 35000000
#  define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_20_35
#elif STM32_HCLK_FREQUENCY >= 35000000 && STM32_HCLK_FREQUENCY < 60000000
#  define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_35_60
#elif STM32_HCLK_FREQUENCY >= 60000000 && STM32_HCLK_FREQUENCY < 100000000
#  define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_60_100
#elif STM32_HCLK_FREQUENCY >= 100000000 && STM32_HCLK_FREQUENCY < 150000000
#  define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_100_150
#elif STM32_HCLK_FREQUENCY >= 150000000 && STM32_HCLK_FREQUENCY <= 180000000
#  define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_150_180
#else
#  error "STM32_HCLK_FREQUENCY not supportable"
/* Timing *******************************************************************/
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
 * second
 */
#define STM32_WDDELAY     (1*CLK_TCK)
#define STM32_TXTIMEOUT   (60*CLK_TCK)

/* PHY reset/configuration delays in milliseconds */

#define PHY_RESET_DELAY   (65)
#define PHY_CONFIG_DELAY  (1000)

/* PHY read/write delays in loop counts */

#define PHY_READ_TIMEOUT  (0x0004ffff)
#define PHY_WRITE_TIMEOUT (0x0004ffff)
#define PHY_RETRY_TIMEOUT (0x0004ffff)

/* Register values **********************************************************/

/* Clear the MACCR bits that will be setup during MAC initialization (or that
 * are cleared unconditionally).  Per the reference manual, all reserved bits
 * must be retained at their reset value.
 *
 * ETH_MACCR_RE    Bit 2:  Receiver enable
 * ETH_MACCR_TE    Bit 3:  Transmitter enable
 * ETH_MACCR_DC    Bit 4:  Deferral check
 * ETH_MACCR_BL    Bits 5-6: Back-off limit
 * ETH_MACCR_APCS  Bit 7:  Automatic pad/CRC stripping
 * ETH_MACCR_RD    Bit 9:  Retry disable
 * ETH_MACCR_IPCO  Bit 10: IPv4 checksum offload
 * ETH_MACCR_DM    Bit 11: Duplex mode
 * ETH_MACCR_LM    Bit 12: Loopback mode
 * ETH_MACCR_ROD   Bit 13: Receive own disable
 * ETH_MACCR_FES   Bit 14: Fast Ethernet speed
 * ETH_MACCR_CSD   Bit 16: Carrier sense disable
 * ETH_MACCR_IFG   Bits 17-19: Interframe gap
 * ETH_MACCR_JD    Bit 22: Jabber disable
 * ETH_MACCR_WD    Bit 23: Watchdog disable
 * ETH_MACCR_CSTF  Bits 25: CRC stripping for Type frames (F2/F4 only)
#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX)
#define MACCR_CLEAR_BITS \
  (ETH_MACCR_RE | ETH_MACCR_TE | ETH_MACCR_DC | ETH_MACCR_BL_MASK | \
   ETH_MACCR_APCS | ETH_MACCR_RD | ETH_MACCR_IPCO | ETH_MACCR_DM | \
   ETH_MACCR_LM | ETH_MACCR_ROD | ETH_MACCR_FES | ETH_MACCR_CSD | \
   ETH_MACCR_IFG_MASK | ETH_MACCR_JD | ETH_MACCR_WD | ETH_MACCR_CSTF)
#else
#define MACCR_CLEAR_BITS \
  (ETH_MACCR_RE | ETH_MACCR_TE | ETH_MACCR_DC | ETH_MACCR_BL_MASK | \
   ETH_MACCR_APCS | ETH_MACCR_RD | ETH_MACCR_IPCO | ETH_MACCR_DM | \
   ETH_MACCR_LM | ETH_MACCR_ROD | ETH_MACCR_FES | ETH_MACCR_CSD | \
   ETH_MACCR_IFG_MASK | ETH_MACCR_JD | ETH_MACCR_WD)
#endif

/* The following bits are set or left zero unconditionally in all modes.
 *
 * ETH_MACCR_RE    Receiver enable                0 (disabled)
 * ETH_MACCR_TE    Transmitter enable             0 (disabled)
 * ETH_MACCR_DC    Deferral check                 0 (disabled)
 * ETH_MACCR_BL    Back-off limit                 0 (10)
 * ETH_MACCR_APCS  Automatic pad/CRC stripping    0 (disabled)
 * ETH_MACCR_RD    Retry disable                  1 (disabled)
 * ETH_MACCR_IPCO  IPv4 checksum offload          Depends on CONFIG_STM32_ETH_HWCHECKSUM
 * ETH_MACCR_LM    Loopback mode                  0 (disabled)
 * ETH_MACCR_ROD   Receive own disable            0 (enabled)
 * ETH_MACCR_CSD   Carrier sense disable          0 (enabled)
 * ETH_MACCR_IFG   Interframe gap                 0 (96 bits)
 * ETH_MACCR_JD    Jabber disable                 0 (enabled)
 * ETH_MACCR_WD    Watchdog disable               0 (enabled)
 * ETH_MACCR_CSTF  CRC stripping for Type frames  0 (disabled, F2/F4 only)
 *
 * The following are set conditioinally based on mode and speed.
 *
 * ETH_MACCR_DM       Duplex mode                    Depends on priv->fduplex
 * ETH_MACCR_FES      Fast Ethernet speed            Depends on priv->mbps100
 */

#ifdef CONFIG_STM32_ETH_HWCHECKSUM
#  define MACCR_SET_BITS \
     (ETH_MACCR_BL_10 | ETH_MACCR_RD | ETH_MACCR_IPCO | ETH_MACCR_IFG(96))
#else
#  define MACCR_SET_BITS \
     (ETH_MACCR_BL_10 | ETH_MACCR_RD | ETH_MACCR_IFG(96))
#endif

/* Clear the MACCR bits that will be setup during MAC initialization (or that
 * are cleared unconditionally).  Per the reference manual, all reserved bits
 * must be retained at their reset value.
 *
 * ETH_MACFFR_PM    Bit 0: Promiscuous mode
 * ETH_MACFFR_HU    Bit 1: Hash unicast
 * ETH_MACFFR_HM    Bit 2: Hash multicast
 * ETH_MACFFR_DAIF  Bit 3: Destination address inverse filtering
 * ETH_MACFFR_PAM   Bit 4: Pass all multicast
 * ETH_MACFFR_BFD   Bit 5: Broadcast frames disable
 * ETH_MACFFR_PCF   Bits 6-7: Pass control frames
 * ETH_MACFFR_SAIF  Bit 8: Source address inverse filtering
 * ETH_MACFFR_SAF   Bit 9: Source address filter
 * ETH_MACFFR_HPF   Bit 10: Hash or perfect filter
 * ETH_MACFFR_RA    Bit 31: Receive all
 */

#define MACFFR_CLEAR_BITS \
  (ETH_MACFFR_PM | ETH_MACFFR_HU | ETH_MACFFR_HM | ETH_MACFFR_DAIF | \
   ETH_MACFFR_PAM | ETH_MACFFR_BFD | ETH_MACFFR_PCF_MASK | ETH_MACFFR_SAIF | \
   ETH_MACFFR_SAF | ETH_MACFFR_HPF | ETH_MACFFR_RA)
/* The following bits are set or left zero unconditionally in all modes.
 *
 * ETH_MACFFR_PM    Promiscuous mode                       0 (disabled)
 * ETH_MACFFR_HU    Hash unicast                           0 (perfect dest filtering)
 * ETH_MACFFR_HM    Hash multicast                         0 (perfect dest filtering)
 * ETH_MACFFR_DAIF  Destination address inverse filtering  0 (normal)
 * ETH_MACFFR_PAM   Pass all multicast                     0 (Depends on HM bit)
 * ETH_MACFFR_BFD   Broadcast frames disable               0 (enabled)
 * ETH_MACFFR_PCF   Pass control frames                    1 (block all but PAUSE)
 * ETH_MACFFR_SAIF  Source address inverse filtering       0 (not used)
 * ETH_MACFFR_SAF   Source address filter                  0 (disabled)
 * ETH_MACFFR_HPF   Hash or perfect filter                 0 (Only matching frames passed)
 * ETH_MACFFR_RA    Receive all                            0 (disabled)
 */

#define MACFFR_SET_BITS (ETH_MACFFR_PCF_PAUSE)

/* Clear the MACFCR bits that will be setup during MAC initialization (or that
 * are cleared unconditionally).  Per the reference manual, all reserved bits
 * must be retained at their reset value.
 *
 * ETH_MACFCR_FCB_BPA Bit 0: Flow control busy/back pressure activate
 * ETH_MACFCR_TFCE    Bit 1: Transmit flow control enable
 * ETH_MACFCR_RFCE    Bit 2: Receive flow control enable
 * ETH_MACFCR_UPFD    Bit 3: Unicast pause frame detect
 * ETH_MACFCR_PLT     Bits 4-5: Pause low threshold
 * ETH_MACFCR_ZQPD    Bit 7: Zero-quanta pause disable
 * ETH_MACFCR_PT      Bits 16-31: Pause time
 */

#define MACFCR_CLEAR_MASK \
  (ETH_MACFCR_FCB_BPA | ETH_MACFCR_TFCE | ETH_MACFCR_RFCE | ETH_MACFCR_UPFD | \
   ETH_MACFCR_PLT_MASK | ETH_MACFCR_ZQPD | ETH_MACFCR_PT_MASK)

/* The following bits are set or left zero unconditionally in all modes.
 *
 * ETH_MACFCR_FCB_BPA Flow control busy/back pressure activate   0 (no pause control frame)
 * ETH_MACFCR_TFCE    Transmit flow control enable               0 (disabled)
 * ETH_MACFCR_RFCE    Receive flow control enable                0 (disabled)
 * ETH_MACFCR_UPFD    Unicast pause frame detect                 0 (disabled)
 * ETH_MACFCR_PLT     Pause low threshold                        0 (pause time - 4)
 * ETH_MACFCR_ZQPD    Zero-quanta pause disable                  1 (disabled)
 * ETH_MACFCR_PT      Pause time                                 0
 */

#define MACFCR_SET_MASK (ETH_MACFCR_PLT_M4 | ETH_MACFCR_ZQPD)

/* Clear the DMAOMR bits that will be setup during MAC initialization (or that
 * are cleared unconditionally).  Per the reference manual, all reserved bits
 * must be retained at their reset value.
 *
 * ETH_DMAOMR_SR     Bit 1:  Start/stop receive
 * TH_DMAOMR_OSF     Bit 2:  Operate on second frame
 * ETH_DMAOMR_RTC    Bits 3-4: Receive threshold control
 * ETH_DMAOMR_FUGF   Bit 6:  Forward undersized good frames
 * ETH_DMAOMR_FEF    Bit 7:  Forward error frames
 * ETH_DMAOMR_ST     Bit 13: Start/stop transmission
 * ETH_DMAOMR_TTC    Bits 14-16: Transmit threshold control
 * ETH_DMAOMR_FTF    Bit 20: Flush transmit FIFO
 * ETH_DMAOMR_TSF    Bit 21: Transmit store and forward
 * ETH_DMAOMR_DFRF   Bit 24: Disable flushing of received frames
 * ETH_DMAOMR_RSF    Bit 25: Receive store and forward
 * TH_DMAOMR_DTCEFD  Bit 26: Dropping of TCP/IP checksum error frames disable
 */

#define DMAOMR_CLEAR_MASK \
  (ETH_DMAOMR_SR | ETH_DMAOMR_OSF | ETH_DMAOMR_RTC_MASK | ETH_DMAOMR_FUGF | \
   ETH_DMAOMR_FEF | ETH_DMAOMR_ST | ETH_DMAOMR_TTC_MASK | ETH_DMAOMR_FTF | \
   ETH_DMAOMR_TSF | ETH_DMAOMR_DFRF | ETH_DMAOMR_RSF | ETH_DMAOMR_DTCEFD)

/* The following bits are set or left zero unconditionally in all modes.
 *
 * ETH_DMAOMR_SR     Start/stop receive                   0 (not running)
 * TH_DMAOMR_OSF     Operate on second frame              1 (enabled)
 * ETH_DMAOMR_RTC    Receive threshold control            0 (64 bytes)
 * ETH_DMAOMR_FUGF   Forward undersized good frames       0 (disabled)
 * ETH_DMAOMR_FEF    Forward error frames                 0 (disabled)
 * ETH_DMAOMR_ST     Start/stop transmission              0 (not running)
 * ETH_DMAOMR_TTC    Transmit threshold control           0 (64 bytes)
 * ETH_DMAOMR_FTF    Flush transmit FIFO                  0 (no flush)
 * ETH_DMAOMR_TSF    Transmit store and forward           Depends on CONFIG_STM32_ETH_HWCHECKSUM
 * ETH_DMAOMR_DFRF   Disable flushing of received frames  0 (enabled)
 * ETH_DMAOMR_RSF    Receive store and forward            Depends on CONFIG_STM32_ETH_HWCHECKSUM
 * TH_DMAOMR_DTCEFD  Dropping of TCP/IP checksum error    Depends on CONFIG_STM32_ETH_HWCHECKSUM
 *                   frames disable
 *
 * When the checksum offload feature is enabled, we need to enable the Store
 * and Forward mode: the store and forward guarantee that a whole frame is
 * stored in the FIFO, so the MAC can insert/verify the checksum, if the
 * checksum is OK the DMA can handle the frame otherwise the frame is dropped
 */
#  define DMAOMR_SET_MASK \
    (ETH_DMAOMR_OSF | ETH_DMAOMR_RTC_64 | ETH_DMAOMR_TTC_64 | \
     ETH_DMAOMR_TSF | ETH_DMAOMR_RSF)
#else
#  define DMAOMR_SET_MASK \
    (ETH_DMAOMR_OSF | ETH_DMAOMR_RTC_64 | ETH_DMAOMR_TTC_64 | \
     ETH_DMAOMR_DTCEFD)
#endif

/* Clear the DMABMR bits that will be setup during MAC initialization (or that
 * are cleared unconditionally).  Per the reference manual, all reserved bits
 * must be retained at their reset value.
 *
 * ETH_DMABMR_SR    Bit 0: Software reset
 * ETH_DMABMR_DA    Bit 1: DMA Arbitration
 * ETH_DMABMR_DSL   Bits 2-6: Descriptor skip length
 * ETH_DMABMR_EDFE  Bit 7: Enhanced descriptor format enable
 * ETH_DMABMR_PBL   Bits 8-13: Programmable burst length
 * ETH_DMABMR_RTPR  Bits 14-15: RX TX priority ratio
 * ETH_DMABMR_FB    Bit 16: Fixed burst
 * ETH_DMABMR_RDP   Bits 17-22: RX DMA PBL
 * ETH_DMABMR_USP   Bit 23: Use separate PBL
 * ETH_DMABMR_FPM   Bit 24: 4xPBL mode
 * ETH_DMABMR_AAB   Bit 25: Address-aligned beats
 * ETH_DMABMR_MB    Bit 26: Mixed burst (F2/F4 only)
#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX)
#define DMABMR_CLEAR_MASK \
  (ETH_DMABMR_SR | ETH_DMABMR_DA | ETH_DMABMR_DSL_MASK | ETH_DMABMR_EDFE | \
   ETH_DMABMR_PBL_MASK | ETH_DMABMR_RTPR_MASK | ETH_DMABMR_FB | ETH_DMABMR_RDP_MASK | \
   ETH_DMABMR_USP | ETH_DMABMR_FPM | ETH_DMABMR_AAB | ETH_DMABMR_MB)
#else
#define DMABMR_CLEAR_MASK \
  (ETH_DMABMR_SR | ETH_DMABMR_DA | ETH_DMABMR_DSL_MASK | ETH_DMABMR_EDFE | \
   ETH_DMABMR_PBL_MASK | ETH_DMABMR_RTPR_MASK | ETH_DMABMR_FB | ETH_DMABMR_RDP_MASK | \
   ETH_DMABMR_USP | ETH_DMABMR_FPM | ETH_DMABMR_AAB)
#endif

/* The following bits are set or left zero unconditionally in all modes.
 *
 *
 * ETH_DMABMR_SR    Software reset                     0 (no reset)
 * ETH_DMABMR_DA    DMA Arbitration                    0 (round robin)
 * ETH_DMABMR_DSL   Descriptor skip length             0
 * ETH_DMABMR_EDFE  Enhanced descriptor format enable  Depends on CONFIG_STM32_ETH_ENHANCEDDESC
 * ETH_DMABMR_PBL   Programmable burst length          32 beats
 * ETH_DMABMR_RTPR  RX TX priority ratio               2:1
 * ETH_DMABMR_FB    Fixed burst                        1 (enabled)
 * ETH_DMABMR_RDP   RX DMA PBL                         32 beats
 * ETH_DMABMR_USP   Use separate PBL                   1 (enabled)
 * ETH_DMABMR_FPM   4xPBL mode                         0 (disabled)
 * ETH_DMABMR_AAB   Address-aligned beats              1 (enabled)
 * ETH_DMABMR_MB    Mixed burst                        0 (disabled, F2/F4 only)
 */

#ifdef CONFIG_STM32_ETH_ENHANCEDDESC
#  define DMABMR_SET_MASK \
     (ETH_DMABMR_DSL(0) | ETH_DMABMR_PBL(32) | ETH_DMABMR_EDFE | ETH_DMABMR_RTPR_2TO1 | \
      ETH_DMABMR_FB | ETH_DMABMR_RDP(32) | ETH_DMABMR_USP | ETH_DMABMR_AAB)
#else
#  define DMABMR_SET_MASK \
     (ETH_DMABMR_DSL(0) | ETH_DMABMR_PBL(32) | ETH_DMABMR_RTPR_2TO1 | ETH_DMABMR_FB | \
      ETH_DMABMR_RDP(32) | ETH_DMABMR_USP | ETH_DMABMR_AAB)
#endif
/* Interrupt bit sets *******************************************************/
/* All interrupts in the normal and abnormal interrupt summary.  Early transmit
 * interrupt (ETI) is excluded from the abnormal set because it causes too
 * many interrupts and is not interesting.
 */

#define ETH_DMAINT_NORMAL \
  (ETH_DMAINT_TI | ETH_DMAINT_TBUI | ETH_DMAINT_RI | ETH_DMAINT_ERI)

#define ETH_DMAINT_ABNORMAL \
  (ETH_DMAINT_TPSI | ETH_DMAINT_TJTI | ETH_DMAINT_ROI | ETH_DMAINT_TUI | \
   ETH_DMAINT_RBUI | ETH_DMAINT_RPSI | ETH_DMAINT_RWTI | /* ETH_DMAINT_ETI | */ \
   ETH_DMAINT_FBEI)

/* Normal receive, transmit, error interrupt enable bit sets */

#define ETH_DMAINT_RECV_ENABLE    (ETH_DMAINT_NIS | ETH_DMAINT_RI)
#define ETH_DMAINT_XMIT_ENABLE    (ETH_DMAINT_NIS | ETH_DMAINT_TI)
#define ETH_DMAINT_XMIT_DISABLE   (ETH_DMAINT_TI)

#ifdef CONFIG_DEBUG_NET
#  define ETH_DMAINT_ERROR_ENABLE (ETH_DMAINT_AIS | ETH_DMAINT_ABNORMAL)
#else
#  define ETH_DMAINT_ERROR_ENABLE (0)
#endif

/* Helpers ******************************************************************/
/* This is a helper pointer for accessing the contents of the Ethernet
 * header
 */
#define BUF ((struct eth_hdr_s *)priv->dev.d_buf)

/****************************************************************************
 * Private Types
 ****************************************************************************/

/* The stm32_ethmac_s encapsulates all state information for a single hardware
 * interface
 */

struct stm32_ethmac_s
{
  uint8_t              ifup    : 1; /* true:ifup false:ifdown */
  uint8_t              mbps100 : 1; /* 100MBps operation (vs 10 MBps) */
  uint8_t              fduplex : 1; /* Full (vs. half) duplex */
  WDOG_ID              txpoll;      /* TX poll timer */
  WDOG_ID              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 */
  /* This holds the information visible to the NuttX network */
  struct net_driver_s  dev;         /* Interface understood by the network */

  /* Used to track transmit and receive descriptors */

  struct eth_txdesc_s *txhead;      /* Next available TX descriptor */
  struct eth_rxdesc_s *rxhead;      /* Next available RX descriptor */

  struct eth_txdesc_s *txtail;      /* First "in_flight" TX descriptor */
  struct eth_rxdesc_s *rxcurr;      /* First RX descriptor of the segment */
  uint16_t             segments;    /* RX segment count */
  uint16_t             inflight;    /* Number of TX transfers "in_flight" */
  sq_queue_t           freeb;       /* The free buffer list */
  struct eth_rxdesc_s rxtable[CONFIG_STM32_ETH_NRXDESC];
  struct eth_txdesc_s txtable[CONFIG_STM32_ETH_NTXDESC];
  uint8_t rxbuffer[CONFIG_STM32_ETH_NRXDESC*CONFIG_STM32_ETH_BUFSIZE];
  uint8_t alloc[STM32_ETH_NFREEBUFFERS*CONFIG_STM32_ETH_BUFSIZE];
};

/****************************************************************************
 * Private Data
 ****************************************************************************/

static struct stm32_ethmac_s g_stm32ethmac[STM32_NETHERNET];

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/
/* Register operations ******************************************************/

#if defined(CONFIG_STM32_ETHMAC_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES)
static uint32_t stm32_getreg(uint32_t addr);
static void stm32_putreg(uint32_t val, uint32_t addr);
static void stm32_checksetup(void);
#else
# define stm32_getreg(addr)      getreg32(addr)
# define stm32_putreg(val,addr)  putreg32(val,addr)
# define stm32_checksetup()
#endif

/* Free buffer management */

static void stm32_initbuffer(FAR struct stm32_ethmac_s *priv);
static inline uint8_t *stm32_allocbuffer(FAR struct stm32_ethmac_s *priv);
static inline void stm32_freebuffer(FAR struct stm32_ethmac_s *priv,
              uint8_t *buffer);
static inline bool stm32_isfreebuffer(FAR struct stm32_ethmac_s *priv);

/* Common TX logic */

static int  stm32_transmit(FAR struct stm32_ethmac_s *priv);
static int  stm32_txpoll(struct net_driver_s *dev);
static void stm32_dopoll(FAR struct stm32_ethmac_s *priv);
static void stm32_enableint(FAR struct stm32_ethmac_s *priv,
              uint32_t ierbit);
static void stm32_disableint(FAR struct stm32_ethmac_s *priv,
              uint32_t ierbit);
static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
static int  stm32_recvframe(FAR struct stm32_ethmac_s *priv);
static void stm32_receive(FAR struct stm32_ethmac_s *priv);
static void stm32_freeframe(FAR struct stm32_ethmac_s *priv);
static void stm32_txdone(FAR struct stm32_ethmac_s *priv);
static void stm32_interrupt_work(FAR void *arg);
static int  stm32_interrupt(int irq, FAR void *context, FAR void *arg);
static void stm32_txtimeout_work(FAR void *arg);
static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...);

static void stm32_poll_work(FAR void *arg);
static void stm32_poll_expiry(int argc, uint32_t arg, ...);
static int  stm32_ifup(struct net_driver_s *dev);
static int  stm32_ifdown(struct net_driver_s *dev);
static void stm32_txavail_work(FAR void *arg);
static int  stm32_txavail(struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static int  stm32_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
static int  stm32_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
static int  stm32_ioctl(struct net_driver_s *dev, int cmd,
              unsigned long arg);
/* Descriptor Initialization */

static void stm32_txdescinit(FAR struct stm32_ethmac_s *priv);
static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv);

/* PHY Initialization */

#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
static int  stm32_phyintenable(FAR struct stm32_ethmac_s *priv);
#endif
#if defined(CONFIG_STM32_AUTONEG) || defined(CONFIG_NETDEV_PHY_IOCTL) || \
    defined(CONFIG_ETH0_PHY_DM9161)
static int  stm32_phyread(uint16_t phydevaddr, uint16_t phyregaddr,
              uint16_t *value);
static int  stm32_phywrite(uint16_t phydevaddr, uint16_t phyregaddr,
              uint16_t value);
static inline int stm32_dm9161(FAR struct stm32_ethmac_s *priv);
#endif
static int  stm32_phyinit(FAR struct stm32_ethmac_s *priv);

/* MAC/DMA Initialization */
#ifdef CONFIG_STM32_MII
static inline void stm32_selectmii(void);
#endif
#ifdef CONFIG_STM32_RMII
static inline void stm32_selectrmii(void);
#endif
static inline void stm32_ethgpioconfig(FAR struct stm32_ethmac_s *priv);
static int  stm32_ethreset(FAR struct stm32_ethmac_s *priv);
static int  stm32_macconfig(FAR struct stm32_ethmac_s *priv);
static void stm32_macaddress(FAR struct stm32_ethmac_s *priv);
#ifdef CONFIG_NET_ICMPv6
static void stm32_ipv6multicast(FAR struct stm32_ethmac_s *priv);
#endif
static int  stm32_macenable(FAR struct stm32_ethmac_s *priv);
static int  stm32_ethconfig(FAR struct stm32_ethmac_s *priv);
/****************************************************************************
 * Private Functions
 ****************************************************************************/
/****************************************************************************
 * Name: stm32_getreg
 *
 * Description:
 *   This function may to used to intercept an monitor all register accesses.
 *   Clearly this is nothing you would want to do unless you are debugging
 *   this driver.
 *
 * Input Parameters:
 *   addr - The register address to read
 *
 * Returned Value:
 *   The value read from the register
 *
 ****************************************************************************/

static uint32_t stm32_getreg(uint32_t addr)
{
  static uint32_t prevaddr = 0;
  static uint32_t preval   = 0;
  static uint32_t count    = 0;

  /* Read the value from the register */

  uint32_t val = getreg32(addr);

  /* Is this the same value that we read from the same register last time?
   * Are we polling the register?  If so, suppress some of the output.
   */

  if (addr == prevaddr && val == preval)
    {
      if (count == 0xffffffff || ++count > 3)
        {
          if (count == 4)
            {
          return val;
        }
    }

  /* No this is a new address or value */

  else
    {
      /* Did we print "..." for the previous value? */
      if (count > 3)
        {
          /* Yes.. then show how many times the value repeated */
          ninfo("[repeats %d more times]\n", count-3);
      /* Save the new address, value, and count */
      prevaddr = addr;
      preval   = val;
      count    = 1;
    }

  /* Show the register value read */

  return val;
}
#endif

/****************************************************************************
 * Name: stm32_putreg
 *
 * Description:
 *   This function may to used to intercept an monitor all register accesses.
 *   Clearly this is nothing you would want to do unless you are debugging
 *   this driver.
 *
 * Input Parameters:
 *   val - The value to write to the register
 *   addr - The register address to read
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

#if defined(CONFIG_STM32_ETHMAC_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES)
static void stm32_putreg(uint32_t val, uint32_t addr)
{
  /* Show the register value being written */


  /* Write the value */

  putreg32(val, addr);
}
#endif

/****************************************************************************
 * Name: stm32_checksetup
 *
 * Description:
 *   Show the state of critical configuration registers.
 *
 * Input Parameters:
 *   None
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void stm32_checksetup(void)
{
}
#endif
/****************************************************************************
 * Function: stm32_initbuffer
 *
 * Description:
 *   Initialize the free buffer list.
 *
 * Input Parameters:
 *   priv  - Reference to the driver state structure
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *   Called during early driver initialization before Ethernet interrupts
 *   are enabled.
 *
 ****************************************************************************/

static void stm32_initbuffer(FAR struct stm32_ethmac_s *priv)
{
  uint8_t *buffer;
  int i;

  /* Initialize the head of the free buffer list */

  sq_init(&priv->freeb);

  /* Add all of the pre-allocated buffers to the free buffer list */

  for (i = 0, buffer = priv->alloc;
       i < STM32_ETH_NFREEBUFFERS;
       i++, buffer += CONFIG_STM32_ETH_BUFSIZE)
    {
      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
    }
}

/****************************************************************************
 * Function: stm32_allocbuffer
 *
 * Description:
 *   Allocate one buffer from the free buffer list.
 *
 * Input Parameters:
 *   priv  - Reference to the driver state structure
 *
 * Returned Value:
 *   Pointer to the allocated buffer on success; NULL 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 inline uint8_t *stm32_allocbuffer(FAR struct stm32_ethmac_s *priv)
{
  /* Allocate a buffer by returning the head of the free buffer list */

  return (uint8_t *)sq_remfirst(&priv->freeb);
}

/****************************************************************************
 * Function: stm32_freebuffer
 *
 * Description:
 *   Return a buffer to the free buffer list.
 *
 * Input Parameters:
 *   priv  - Reference to the driver state structure
 *   buffer - A pointer to the buffer to be freed
 *
 * Returned Value:
 *   None
 *
 * 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 inline void stm32_freebuffer(FAR struct stm32_ethmac_s *priv, uint8_t *buffer)
{
  /* Free the buffer by adding it to to the end of the free buffer list */

  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
}

/****************************************************************************
 * Function: stm32_isfreebuffer
 *
 * Description:
 *   Return TRUE if the free buffer list is not empty.
 *
 * Input Parameters:
 *   priv  - Reference to the driver state structure
 *
 * Returned Value:
 *   True if there are one or more buffers in the free buffer list;
 *   false if the free buffer list is empty
 *
 * Assumptions:
 *   None.
 *
 ****************************************************************************/