Newer
Older
/****************************************************************************
* arch/arm/src/stm32/stm32_eth.c
*
Sebastien Lorquet
committed
* Copyright (C) 2011-2012, 2014, 2016-2018 Gregory Nutt. All rights
* reserved.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
* 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 <errno.h>
Gregory Nutt
committed
#include <arpa/inet.h>
#include <nuttx/arch.h>
Gregory Nutt
committed
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/phy.h>
#include <nuttx/net/mii.h>
Gregory Nutt
committed
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
#if defined(CONFIG_NET_PKT)
# include <nuttx/net/pkt.h>
#include "chip.h"
#include "stm32_gpio.h"
#include "stm32_rcc.h"
#include "stm32_syscfg.h"
#include "stm32_eth.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
committed
#if !defined(CONFIG_SCHED_WORKQUEUE)
Gregory Nutt
committed
# error Work queue support is required
#else
Gregory Nutt
committed
/* Select work queue */
Gregory Nutt
committed
# 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
Gregory Nutt
committed
#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
Gregory Nutt
committed
# 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"
patacongo
committed
# 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
Gregory Nutt
committed
# 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"
patacongo
committed
# endif
# endif
#endif
#ifdef CONFIG_STM32_AUTONEG
# ifndef CONFIG_STM32_PHYSR
# error "CONFIG_STM32_PHYSR must be defined in the NuttX configuration"
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# 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 */
Gregory Nutt
committed
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#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
* 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)
# 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
#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.
*/
Gregory Nutt
committed
#ifndef CONFIG_DEBUG_NET_INFO
# 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)
/* TX timeout = 1 minute */
#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)
Gregory Nutt
committed
#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX)
(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)
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
*
* 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)
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
/* 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
*/
Paul A. Patience
committed
#ifdef CONFIG_STM32_ETH_HWCHECKSUM
# 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)
Gregory Nutt
committed
#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 */
Gregory Nutt
committed
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 */
/* Descriptor allocations */
struct eth_rxdesc_s rxtable[CONFIG_STM32_ETH_NRXDESC];
struct eth_txdesc_s txtable[CONFIG_STM32_ETH_NTXDESC];
/* Buffer allocations */
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);
Gregory Nutt
committed
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);
/* Interrupt handling */
Gregory Nutt
committed
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,
Gregory Nutt
committed
FAR struct eth_rxdesc_s *rxfirst, int segments);
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);
Gregory Nutt
committed
static void stm32_interrupt_work(FAR void *arg);
static int stm32_interrupt(int irq, FAR void *context, FAR void *arg);
/* Watchdog timer expirations */
Gregory Nutt
committed
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, ...);
/* NuttX callback functions */
static int stm32_ifup(struct net_driver_s *dev);
static int stm32_ifdown(struct net_driver_s *dev);
Gregory Nutt
committed
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);
#endif
#ifdef CONFIG_NET_IGMP
static int stm32_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
#ifdef CONFIG_NETDEV_IOCTL
Gregory Nutt
committed
static int stm32_ioctl(struct net_driver_s *dev, int cmd,
unsigned long arg);
Gregory Nutt
committed
#endif
/* Descriptor Initialization */
static void stm32_txdescinit(FAR struct stm32_ethmac_s *priv);
static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv);
/* PHY Initialization */
Gregory Nutt
committed
#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)
Gregory Nutt
committed
static int stm32_phyread(uint16_t phydevaddr, uint16_t phyregaddr,
uint16_t *value);
Gregory Nutt
committed
static int stm32_phywrite(uint16_t phydevaddr, uint16_t phyregaddr,
uint16_t value);
#ifdef CONFIG_ETH0_PHY_DM9161
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 */
patacongo
committed
#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);
Sebastien Lorquet
committed
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
*
****************************************************************************/
Gregory Nutt
committed
#ifdef CONFIG_STM32_ETHMAC_REGDEBUG
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)
{
Gregory Nutt
committed
ninfo("...\n");
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 */
Gregory Nutt
committed
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 */
Gregory Nutt
committed
ninfo("%08x->%08x\n", addr, val);
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
*
****************************************************************************/
Gregory Nutt
committed
#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 */
Gregory Nutt
committed
ninfo("%08x<-%08x\n", addr, val);
/* Write the value */
putreg32(val, addr);
}
#endif
/****************************************************************************
* Name: stm32_checksetup
*
* Description:
* Show the state of critical configuration registers.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
Gregory Nutt
committed
#ifdef CONFIG_STM32_ETHMAC_REGDEBUG
static void stm32_checksetup(void)
{
}
#endif
/****************************************************************************
* Function: stm32_initbuffer
*
* Description:
* Initialize the free buffer list.
*
* 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 */
/* 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.
*
* 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.
*
* 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.
*
* 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.
*
****************************************************************************/