summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-09-16 11:36:12 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-09-16 11:36:12 -0600
commitab5111d3abb2f89af47de1195058a973a942130c (patch)
tree846c252c077c0cf8912bde8a9231bf04b36d9eba
parent7d6066e85556b82dbdafa7bd47b757d0b7d8dba2 (diff)
downloadnuttx-ab5111d3abb2f89af47de1195058a973a942130c.tar.gz
nuttx-ab5111d3abb2f89af47de1195058a973a942130c.tar.bz2
nuttx-ab5111d3abb2f89af47de1195058a973a942130c.zip
SAMA5 EMAC: Incremental progress. Still not code complete
-rw-r--r--nuttx/arch/arm/src/sama5/Kconfig197
-rw-r--r--nuttx/arch/arm/src/sama5/Make.defs9
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_emac.h72
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_gmac.h14
-rw-r--r--nuttx/arch/arm/src/sama5/sam_emac.c1427
-rw-r--r--nuttx/configs/sama5d3x-ek/include/board.h3
-rw-r--r--nuttx/configs/sama5d3x-ek/src/sam_buttons.c5
-rw-r--r--nuttx/configs/sama5d3x-ek/src/sam_ethernet.c18
-rw-r--r--nuttx/configs/sama5d3x-ek/src/sam_usb.c6
9 files changed, 798 insertions, 953 deletions
diff --git a/nuttx/arch/arm/src/sama5/Kconfig b/nuttx/arch/arm/src/sama5/Kconfig
index cfb0f3fe6..fe25d149e 100644
--- a/nuttx/arch/arm/src/sama5/Kconfig
+++ b/nuttx/arch/arm/src/sama5/Kconfig
@@ -14,18 +14,23 @@ choice
config ARCH_CHIP_ATSAMA5D31
bool "Atmel ATSAMA5D31"
select ARCH_CHIP_SAMA5D3
+ select SAMA5_HAVE_EMAC
config ARCH_CHIP_ATSAMA5D33
bool "Atmel ATSAMA5D33"
select ARCH_CHIP_SAMA5D3
+ select SAMA5_HAVE_GMAC
config ARCH_CHIP_ATSAMA5D34
bool "Atmel ATSAMA5D34"
select ARCH_CHIP_SAMA5D3
+ select SAMA5_HAVE_GMAC
config ARCH_CHIP_ATSAMA5D35
bool "Atmel ATSAMA5D35"
select ARCH_CHIP_SAMA5D3
+ select SAMA5_HAVE_EMAC
+ select SAMA5_HAVE_GMAC
endchoice # Atmel AT91SAMA5 Chip Selection
@@ -149,14 +154,16 @@ config SAMA5_UHPHS
config SAMA5_UDPHS
bool "USB Device High Speed (UDPHS)"
default n
+ depends on SAMA5_HAVE_GMAC
config SAMA5_GMAC
bool "Gigabit Ethernet MAC (GMAC)"
default n
config SAMA5_EMAC
- bool "Ethernet MAC (EMAC)"
+ bool "10/100MBps Ethernet MAC (EMAC)"
default n
+ depends on SAMA5_HAVE_EMAC
config SAMA5_LCDC
bool "LCD Controller (LCDC)"
@@ -241,6 +248,194 @@ config SAMA5_PIOE_IRQ
endif # PIO_IRQ
+config SAMA5_HAVE_GMAC
+ bool
+ default n
+
+config SAMA5_HAVE_EMAC
+ bool
+ default n
+
+if SAMA5_EMAC
+
+menu "EMAC device driver options"
+
+config SAMA5_EMAC_NRXBUFFERS
+ int "Number of RX buffers"
+ default 16
+ ---help---
+ EMAC buffer memory is segmented into 128 byte units (not
+ configurable). This setting provides the number of such 128 byte
+ units used for reception. This is also equal to the number of RX
+ descriptors that will be allocate.d The selected value must be an
+ even power of 2.
+
+config SAMA5_EMAC_NTXBUFFERS
+ int "Number of TX buffers"
+ default 1
+ ---help---
+ EMAC buffer memory is segmented into 128 byte units (not
+ configurable). This setting provides the number of such 128 byte
+ units used for transmission. This is also equal to the number of TX
+ descriptors that will be allocated. The selected value must be an
+ even power of 2.
+
+config SAMA5_EMAC_PREALLOCATE
+ bool "Preallocate buffers"
+ default n
+ ---help---
+ Buffer an descriptor many may either be allocated from the memory
+ pool or pre-allocated to lie in .bss. This options selected pre-
+ allocated buffer memory.
+
+config SAMA5_EMAC_NBC
+ bool "Disable Broadcast"
+ default n
+ ---help---
+ Select to disable receipt of broadcast packets.
+
+config SAMA5_EMAC_PHYADDR
+ int "PHY address"
+ default 1
+ ---help---
+ The 5-bit address of the PHY on the board. Default: 1
+
+config SAMA5_EMAC_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
+ SAMA5_EMAC_PHYINIT is defined in the configuration then the board specific logic must
+ provide sam_phyinitialize(); The SAMA5 EMAC driver will call this function
+ one time before it first uses the PHY.
+
+config SAMA5_EMAC_MII
+ bool "Use MII interface"
+ default n
+ ---help---
+ Support Ethernet MII interface (vs RMII).
+
+config SAMA5_EMAC_RMII
+ bool
+ default y if !SAMA5_EMAC_MII
+ default n if SAMA5_EMAC_MII
+
+config SAMA5_EMAC_AUTONEG
+ bool "Use autonegotiation"
+ default y
+ ---help---
+ Use PHY autonegotiation to determine speed and mode
+
+config SAMA5_EMAC_ETHFD
+ bool "Full duplex"
+ default n
+ depends on !SAMA5_EMAC_AUTONEG
+ ---help---
+ If SAMA5_EMAC_AUTONEG is not defined, then this may be defined to select full duplex
+ mode. Default: half-duplex
+
+config SAMA5_EMAC_ETH100MBPS
+ bool "100 Mbps"
+ default n
+ depends on !SAMA5_EMAC_AUTONEG
+ ---help---
+ If SAMA5_EMAC_AUTONEG is not defined, then this may be defined to select 100 MBps
+ speed. Default: 10 Mbps
+
+config SAMA5_EMAC_PHYSR
+ int "PHY Status Register Address (decimal)"
+ depends on SAMA5_EMAC_AUTONEG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. The PHY status register
+ address may diff from PHY to PHY. This configuration sets the address of
+ the PHY status register.
+
+config SAMA5_EMAC_PHYSR_ALTCONFIG
+ bool "PHY Status Alternate Bit Layout"
+ default n
+ depends on SAMA5_EMAC_AUTONEG
+ ---help---
+ Different PHYs present speed and mode information in different ways. Some
+ will present separate information for speed and mode (this is the default).
+ Those PHYs, for example, may provide a 10/100 Mbps indication and a separate
+ full/half duplex indication. This options selects an alternative representation
+ where speed and mode information are combined. This might mean, for example,
+ separate bits for 10HD, 100HD, 10FD and 100FD.
+
+config SAMA5_EMAC_PHYSR_SPEED
+ hex "PHY Speed Mask"
+ depends on SAMA5_EMAC_AUTONEG && !SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This provides bit mask
+ for isolating the 10 or 100MBps speed indication.
+
+config SAMA5_EMAC_PHYSR_100MBPS
+ hex "PHY 100Mbps Speed Value"
+ depends on SAMA5_EMAC_AUTONEG && !SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This provides the value
+ of the speed bit(s) indicating 100MBps speed.
+
+config SAMA5_EMAC_PHYSR_MODE
+ hex "PHY Mode Mask"
+ depends on SAMA5_EMAC_AUTONEG && !SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This provide bit mask
+ for isolating the full or half duplex mode bits.
+
+config SAMA5_EMAC_PHYSR_FULLDUPLEX
+ hex "PHY Full Duplex Mode Value"
+ depends on SAMA5_EMAC_AUTONEG && !SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This provides the
+ value of the mode bits indicating full duplex mode.
+
+config SAMA5_EMAC_PHYSR_ALTMODE
+ hex "PHY Mode Mask"
+ depends on SAMA5_EMAC_AUTONEG && SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This provide bit mask
+ for isolating the speed and full/half duplex mode bits.
+
+config SAMA5_EMAC_PHYSR_10HD
+ hex "10MHz/Half Duplex Value"
+ depends on SAMA5_EMAC_AUTONEG && SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This is the value
+ under the bit mask that represents the 10Mbps, half duplex setting.
+
+config SAMA5_EMAC_PHYSR_100HD
+ hex "100MHz/Half Duplex Value"
+ depends on SAMA5_EMAC_AUTONEG && SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This is the value
+ under the bit mask that represents the 100Mbps, half duplex setting.
+
+config SAMA5_EMAC_PHYSR_10FD
+ hex "10MHz/Full Duplex Value"
+ depends on SAMA5_EMAC_AUTONEG && SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This is the value
+ under the bit mask that represents the 10Mbps, full duplex setting.
+
+config SAMA5_EMAC_PHYSR_100FD
+ hex "100MHz/Full Duplex Value"
+ depends on SAMA5_EMAC_AUTONEG && SAMA5_EMAC_PHYSR_ALTCONFIG
+ ---help---
+ This must be provided if SAMA5_EMAC_AUTONEG is defined. This is the value
+ under the bit mask that represents the 100Mbps, full duplex setting.
+
+config SAMA5_EMAC_REGDEBUG
+ bool "Register-Level Debug"
+ default n
+ depends on DEBUG
+ ---help---
+ Enable very low-level register access debug. Depends on DEBUG.
+
+endmenu # EMAC device driver options
+endif # SAMA5_EMAC
+
if SAMA5_SPI0 || SAMA5_SPI1
menu "SPI device driver options"
diff --git a/nuttx/arch/arm/src/sama5/Make.defs b/nuttx/arch/arm/src/sama5/Make.defs
index 51247113e..dc78b023a 100644
--- a/nuttx/arch/arm/src/sama5/Make.defs
+++ b/nuttx/arch/arm/src/sama5/Make.defs
@@ -140,6 +140,15 @@ endif
endif
endif
+ifeq ($(CONFIG_NET),y)
+ifeq ($(CONFIG_SAMA5_EMAC),y)
+CHIP_CSRCS += sam_emac.c
+endif
+ifeq ($(CONFIG_SAMA5_GMAC),y)
+CHIP_CSRCS += sam_gmac.c
+endif
+endif
+
ifeq ($(CONFIG_SAMA5_TWI0),y)
CHIP_CSRCS += sam_twi.c
else
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_emac.h b/nuttx/arch/arm/src/sama5/chip/sam_emac.h
index 0b2cc8102..6ee32f98d 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_emac.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_emac.h
@@ -236,6 +236,8 @@
#define EMAC_INT_PTZ (1 << 13) /* Bit 13: Pause Time Zero */
#define EMAC_INT_WOL (1 << 14) /* Bit 14: Wake On LAN */
+#define EMAC_INT_ALL (0x00007cff)
+
/* Phy Maintenance Register */
#define EMAC_MAN_DATA_SHIFT (0) /* Bits 0-15: Read/write data */
@@ -256,7 +258,7 @@
# define EMAC_MAN_WRITE (1 << EMAC_MAN_RW_SHIFT)
#define EMAC_MAN_SOF_SHIFT (30) /* Bits 30-31: Start of frame */
#define EMAC_MAN_SOF_MASK (3 << EMAC_MAN_SOF_SHIFT)
-# define EMAC_MAN_SOF_MASK (1 << EMAC_MAN_SOF_SHIFT) /* Must be written b01 */
+# define EMAC_MAN_SOF (1 << EMAC_MAN_SOF_SHIFT) /* Must be written b01 */
/* Pause Time Register */
@@ -387,49 +389,49 @@
/* Receive buffer descriptor: Address word */
-#define RXDESC_ADDR_OWNER (1 << 0) /* Bit 0: 1=Software owns; 0=EMAC owns */
-#define RXDESC_ADDR_WRAP (1 << 1) /* Bit 1: Last descriptor in list */
-#define RXDESC_ADDR_MASK (0xfffffffc) /* Bits 2-31: Aligned buffer address */
+#define EMACRXD_ADDR_OWNER (1 << 0) /* Bit 0: 1=Software owns; 0=EMAC owns */
+#define EMACRXD_ADDR_WRAP (1 << 1) /* Bit 1: Last descriptor in list */
+#define EMACRXD_ADDR_MASK (0xfffffffc) /* Bits 2-31: Aligned buffer address */
/* Receive buffer descriptor: Control word */
-#define RXDESC_CTRL_FRLEN_SHIFT (0) /* Bits 0-11: Length of frame */
-#define RXDESC_CTRL_FRLEN_MASK (0x000007ff << RXDESC_CTRL_FRLEN_SHIFT)
-#define RXDESC_CTRL_BOFFS_SHIFT (12) /* Bits 12-13: Receive buffer offset */
-#define RXDESC_CTRL_BOFFS_MASK (3 << RXDESC_CTRL_BOFFS_SHIFT)
-#define RXDESC_CTRL_SOF (1 << 14) /* Bit 14: Start of frame */
-#define RXDESC_CTRL_EOF (1 << 15) /* Bit 15: End of frame */
-#define RXDESC_CTRL_CFI (1 << 16) /* Bit 16: Concatenation format indicator (CFI) bit */
-#define RXDESC_CTRL_VLPRIO_SHIFT (17) /* Bits 17-19: VLAN priority */
-#define RXDESC_CTRL_VLPRIO_MASK (7 << RXDESC_CTRL_VLANPRIO_SHIFT)
-#define RXDESC_CTRL_PRIODET (1 << 20) /* Bit 20: Priority tag detected */
-#define RXDESC_CTRL_VLANTAG (1 << 21) /* Bit 21: VLAN tag detected */
-#define RXDESC_CTRL_TYPEID (1 << 22) /* Bit 22: Type ID match */
-#define RXDESC_CTRL_ADDR4 (1 << 23) /* Bit 23: Specific address register 4 match */
-#define RXDESC_CTRL_ADDR3 (1 << 24) /* Bit 24: Specific address register 3 match */
-#define RXDESC_CTRL_ADDR2 (1 << 25) /* Bit 25: Specific address register 2 match */
-#define RXDESC_CTRL_ADDR1 (1 << 26) /* Bit 26: Specific address register 1 match */
+#define EMACRXD_CTRL_FRLEN_SHIFT (0) /* Bits 0-11: Length of frame */
+#define EMACRXD_CTRL_FRLEN_MASK (0x000007ff << EMACRXD_CTRL_FRLEN_SHIFT)
+#define EMACRXD_CTRL_BOFFS_SHIFT (12) /* Bits 12-13: Receive buffer offset */
+#define EMACRXD_CTRL_BOFFS_MASK (3 << EMACRXD_CTRL_BOFFS_SHIFT)
+#define EMACRXD_CTRL_SOF (1 << 14) /* Bit 14: Start of frame */
+#define EMACRXD_CTRL_EOF (1 << 15) /* Bit 15: End of frame */
+#define EMACRXD_CTRL_CFI (1 << 16) /* Bit 16: Concatenation format indicator (CFI) bit */
+#define EMACRXD_CTRL_VLPRIO_SHIFT (17) /* Bits 17-19: VLAN priority */
+#define EMACRXD_CTRL_VLPRIO_MASK (7 << EMACRXD_CTRL_VLANPRIO_SHIFT)
+#define EMACRXD_CTRL_PRIODET (1 << 20) /* Bit 20: Priority tag detected */
+#define EMACRXD_CTRL_VLANTAG (1 << 21) /* Bit 21: VLAN tag detected */
+#define EMACRXD_CTRL_TYPEID (1 << 22) /* Bit 22: Type ID match */
+#define EMACRXD_CTRL_ADDR4 (1 << 23) /* Bit 23: Specific address register 4 match */
+#define EMACRXD_CTRL_ADDR3 (1 << 24) /* Bit 24: Specific address register 3 match */
+#define EMACRXD_CTRL_ADDR2 (1 << 25) /* Bit 25: Specific address register 2 match */
+#define EMACRXD_CTRL_ADDR1 (1 << 26) /* Bit 26: Specific address register 1 match */
/* Bit 27: Reserved */
-#define RXDESC_CTRL_EXTADDR (1 << 28) /* Bit 28: External address match */
-#define RXDESC_CTRL_UCAST (1 << 29) /* Bit 29: Unicast hash match */
-#define RXDESC_CTRL_MCAST (1 << 30) /* Bit 30: Multicast hash match */
-#define RXDESC_CTRL_ONES (1 << 31) /* Bit 31: Global all ones broadcast address detected */
+#define EMACRXD_CTRL_EXTADDR (1 << 28) /* Bit 28: External address match */
+#define EMACRXD_CTRL_UCAST (1 << 29) /* Bit 29: Unicast hash match */
+#define EMACRXD_CTRL_MCAST (1 << 30) /* Bit 30: Multicast hash match */
+#define EMACRXD_CTRL_BCAST (1 << 31) /* Bit 31: Global all ones broadcast address detected */
/* Transmit buffer descriptor: Address word (un-aligned, 32-bit address */
/* Transmit buffer descriptor: Control word */
-#define TXDESC_CTRL_BUFLEN_SHIFT (0) /* Bits 0-10: Length of buffer */
-#define TXDESC_CTRL_BUFLEN_MASK (0x000003ff << TXDESC_CTRL_BUFLEN_SHIFT)
+#define EMACTXD_CTRL_BUFLEN_SHIFT (0) /* Bits 0-10: Length of buffer */
+#define EMACTXD_CTRL_BUFLEN_MASK (0x000003ff << EMACTXD_CTRL_BUFLEN_SHIFT)
/* Bits 11-14: Reserved */
-#define TXDESC_CTRL_LAST (1 << 15) /* Bit 15: Last buffer in the current frame */
-#define TXDESC_CTRL_NOCRC (1 << 16) /* Bit 16: No CRC*/
+#define EMACTXD_CTRL_LAST (1 << 15) /* Bit 15: Last buffer in the current frame */
+#define EMACTXD_CTRL_NOCRC (1 << 16) /* Bit 16: No CRC*/
/* Bits 17-26: Reserved */
-#define TXDESC_CTRL_NOBUFFER (1 << 27) /* Bit 27: Buffers exhausted in mid frame*/
-#define TXDESC_CTRL_TXUR (1 << 28) /* Bit 28: Transmit underrun*/
-#define TXDESC_CTRL_TXERR (1 << 29) /* Bit 29: Retry limit exceeded, transmit error detected*/
-#define TXDESC_CTRL_WRAP (1 << 30) /* Bit 30: Last descriptor in descriptor list*/
-#define TXDESC_CTRL_USED (1 << 31) /* Bit 31: Zero for the EMAC to read from buffer*/
+#define EMACTXD_CTRL_NOBUFFER (1 << 27) /* Bit 27: Buffers exhausted in mid frame*/
+#define EMACTXD_CTRL_TXUR (1 << 28) /* Bit 28: Transmit underrun*/
+#define EMACTXD_CTRL_TXERR (1 << 29) /* Bit 29: Retry limit exceeded, transmit error detected*/
+#define EMACTXD_CTRL_WRAP (1 << 30) /* Bit 30: Last descriptor in descriptor list*/
+#define EMACTXD_CTRL_USED (1 << 31) /* Bit 31: Zero for the EMAC to read from buffer*/
/************************************************************************************
* Public Types
@@ -439,7 +441,7 @@
struct emac_rxdesc_s
{
uint32_t addr; /* Buffer address */
- uint32_t ctrl; /* RX controls */
+ uint32_t status; /* RX status and controls */
};
/* Transmit buffer descriptor */
@@ -447,6 +449,6 @@ struct emac_rxdesc_s
struct emac_txdesc_s
{
uint32_t addr; /* Buffer address */
- uint32_t ctrl; /* TX controls */
+ uint32_t status; /* TX status and controls */
};
#endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_EMAC_H */
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_gmac.h b/nuttx/arch/arm/src/sama5/chip/sam_gmac.h
index d33aebabc..283e6885e 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_gmac.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_gmac.h
@@ -148,8 +148,8 @@
#define SAM_GMAC_EFRN_OFFSET 0x01ec /* PTP Event Frame Received Nanoseconds */
#define SAM_GMAC_PEFTS_OFFSET 0x01f0 /* PTP Peer Event Frame Transmitted Seconds */
#define SAM_GMAC_PEFTN_OFFSET 0x01f4 /* PTP Peer Event Frame Transmitted Nanoseconds */
-#define SAM_GMAC_PEFRS_OFFSET 0x01f8 /* PTP Peer Event Frame ReceiveGMAC_PEFRNd Seconds */
-#define SAM_GMAC_PEFRS_OFFSET 0x01fc /* PTP Peer Event Frame Received Nanoseconds */
+#define SAM_GMAC_PEFRS_OFFSET 0x01f8 /* PTP Peer Event Frame Received Seconds */
+#define SAM_GMAC_PEFRN_OFFSET 0x01fc /* PTP Peer Event Frame Received Nanoseconds */
/* 0x0200-0x023c Reserved */
/* 0x0280-0x0298 Reserved */
#define SAM_GMAC_ISRPQ_OFFSET(n) (0x400 + ((n) << 2)) /* n=0..6 */
@@ -344,7 +344,7 @@
#define SAM_GMAC_PEFTS (SAM_GMAC_VBASE+SAM_GMAC_PEFTS_OFFSET)
#define SAM_GMAC_PEFTN (SAM_GMAC_VBASE+SAM_GMAC_PEFTN_OFFSET)
#define SAM_GMAC_PEFRS (SAM_GMAC_VBASE+SAM_GMAC_PEFRS_OFFSET)
-#define SAM_GMAC_PEFRS (SAM_GMAC_VBASE+SAM_GMAC_PEFRS_OFFSET)
+#define SAM_GMAC_PEFRN (SAM_GMAC_VBASE+SAM_GMAC_PEFRN_OFFSET)
#define SAM_GMAC_ISRPQ(n) (SAM_GMAC_VBASE+SAM_GMAC_ISRPQ_OFFSET(n))
#define SAM_GMAC_ISRPQ0 (SAM_GMAC_VBASE+SAM_GMAC_ISRPQ0_OFFSET)
#define SAM_GMAC_ISRPQ1 (SAM_GMAC_VBASE+SAM_GMAC_ISRPQ1_OFFSET)
@@ -628,8 +628,8 @@
#define GMAC_PEFTS_
/* PTP Peer Event Frame Transmitted Nanoseconds */
#define GMAC_PEFTN_
-/* PTP Peer Event Frame ReceiveGMAC_PEFRNd Seconds */
-#define GMAC_PEFRS_
+/* PTP Peer Event Frame Received Seconds */
+#define GMAC_PEFRN_
/* PTP Peer Event Frame Received Nanoseconds */
#define GMAC_PEFRS_
/* Interrupt Status Register Priority Queue 0-6 */
@@ -651,8 +651,4 @@
/* Interrupt Mask Register Priority Queue 0-6 */
#define GMAC_IMRPQ0_
- (1 << nn) /* Bit nn:
-_SHIFT (nn) /* Bits nn-nn:
-_MASK (xx << yy)
-
#endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_GMAC_H */
diff --git a/nuttx/arch/arm/src/sama5/sam_emac.c b/nuttx/arch/arm/src/sama5/sam_emac.c
index a857180b6..a51578f20 100644
--- a/nuttx/arch/arm/src/sama5/sam_emac.c
+++ b/nuttx/arch/arm/src/sama5/sam_emac.c
@@ -51,16 +51,21 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
#include <nuttx/net/mii.h>
-
#include <nuttx/net/uip/uip.h>
#include <nuttx/net/uip/uip-arp.h>
#include <nuttx/net/uip/uip-arch.h>
+#include "up_arch.h"
#include "up_internal.h"
+#include "cache.h"
#include "chip.h"
+#include "chip/sam_pinmap.h"
#include "sam_pio.h"
+#include "sam_periphclks.h"
+#include "sam_memories.h"
#include "sam_ethernet.h"
#include <arch/board/board.h>
@@ -70,94 +75,80 @@
****************************************************************************/
/* Configuration ************************************************************/
-#ifndef CONFIG_SAMA5_PHYADDR
-# error "CONFIG_SAMA5_PHYADDR must be defined in the NuttX configuration"
+/* Number of buffer for RX */
+
+#ifndef CONFIG_SAMA5_EMAC_NRXBUFFERS
+# define CONFIG_SAMA5_EMAC_NRXBUFFERS 16
+#endif
+
+/* Number of buffer for TX */
+
+#ifndef CONFIG_SAMA5_EMAC_NTXBUFFERS
+# define CONFIG_SAMA5_EMAC_NTXBUFFERS 32
#endif
-#if !defined(CONFIG_SAMA5_MII) && !defined(CONFIG_SAMA5_RMII)
-# warning "Neither CONFIG_SAMA5_MII nor CONFIG_SAMA5_RMII defined"
+#undef CONFIG_SAMA5_EMAC_NBC
+
+#ifndef CONFIG_SAMA5_EMAC_PHYADDR
+# error "CONFIG_SAMA5_EMAC_PHYADDR must be defined in the NuttX configuration"
+#endif
+
+#if !defined(CONFIG_SAMA5_EMAC_MII) && !defined(CONFIG_SAMA5_EMAC_RMII)
+# warning "Neither CONFIG_SAMA5_EMAC_MII nor CONFIG_SAMA5_EMAC_RMII defined"
#endif
-#if defined(CONFIG_SAMA5_MII) && defined(CONFIG_SAMA5_RMII)
-# error "Both CONFIG_SAMA5_MII and CONFIG_SAMA5_RMII defined"
+#if defined(CONFIG_SAMA5_EMAC_MII) && defined(CONFIG_SAMA5_EMAC_RMII)
+# error "Both CONFIG_SAMA5_EMAC_MII and CONFIG_SAMA5_EMAC_RMII defined"
#endif
-#ifdef CONFIG_SAMA5_AUTONEG
-# ifndef CONFIG_SAMA5_PHYSR
-# error "CONFIG_SAMA5_PHYSR must be defined in the NuttX configuration"
+#ifdef CONFIG_SAMA5_EMAC_AUTONEG
+# ifndef CONFIG_SAMA5_EMAC_PHYSR
+# error "CONFIG_SAMA5_EMAC_PHYSR must be defined in the NuttX configuration"
# endif
-# ifdef CONFIG_SAMA5_PHYSR_ALTCONFIG
-# ifndef CONFIG_SAMA5_PHYSR_ALTMODE
-# error "CONFIG_SAMA5_PHYSR_ALTMODE must be defined in the NuttX configuration"
+# ifdef CONFIG_SAMA5_EMAC_PHYSR_ALTCONFIG
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_ALTMODE
+# error "CONFIG_SAMA5_EMAC_PHYSR_ALTMODE must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_10HD
-# error "CONFIG_SAMA5_PHYSR_10HD must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_10HD
+# error "CONFIG_SAMA5_EMAC_PHYSR_10HD must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_100HD
-# error "CONFIG_SAMA5_PHYSR_100HD must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_100HD
+# error "CONFIG_SAMA5_EMAC_PHYSR_100HD must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_10FD
-# error "CONFIG_SAMA5_PHYSR_10FD must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_10FD
+# error "CONFIG_SAMA5_EMAC_PHYSR_10FD must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_100FD
-# error "CONFIG_SAMA5_PHYSR_100FD must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_100FD
+# error "CONFIG_SAMA5_EMAC_PHYSR_100FD must be defined in the NuttX configuration"
# endif
# else
-# ifndef CONFIG_SAMA5_PHYSR_SPEED
-# error "CONFIG_SAMA5_PHYSR_SPEED must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_SPEED
+# error "CONFIG_SAMA5_EMAC_PHYSR_SPEED must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_100MBPS
-# error "CONFIG_SAMA5_PHYSR_100MBPS must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_100MBPS
+# error "CONFIG_SAMA5_EMAC_PHYSR_100MBPS must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_MODE
-# error "CONFIG_SAMA5_PHYSR_MODE must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_MODE
+# error "CONFIG_SAMA5_EMAC_PHYSR_MODE must be defined in the NuttX configuration"
# endif
-# ifndef CONFIG_SAMA5_PHYSR_FULLDUPLEX
-# error "CONFIG_SAMA5_PHYSR_FULLDUPLEX must be defined in the NuttX configuration"
+# ifndef CONFIG_SAMA5_EMAC_PHYSR_FULLDUPLEX
+# error "CONFIG_SAMA5_EMAC_PHYSR_FULLDUPLEX must be defined in the NuttX configuration"
# endif
# endif
#endif
-/* Ethernet buffer sizes, number of buffers, and number of descriptors */
+/* EMAC buffer sizes, number of buffers, and number of descriptors */
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER is required"
+#ifdef CONFIG_NET_MULTIBUFFER
+# error CONFIG_NET_MULTIBUFFER must not be set
#endif
-/* 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_EMAC_BUFSIZE ((CONFIG_NET_BUFSIZE + 4 + 15) & ~15)
-
-#ifndef CONFIG_SAMA5_EMAC_BUFSIZE
-# define CONFIG_SAMA5_EMAC_BUFSIZE OPTIMAL_EMAC_BUFSIZE
-#endif
-
-#if CONFIG_SAMA5_EMAC_BUFSIZE > EMAC_TDES1_TBS1_MASK
-# error "CONFIG_SAMA5_EMAC_BUFSIZE is too large"
-#endif
-
-#if (CONFIG_SAMA5_EMAC_BUFSIZE & 15) != 0
-# error "CONFIG_SAMA5_EMAC_BUFSIZE must be aligned"
-#endif
-
-#if CONFIG_SAMA5_EMAC_BUFSIZE != OPTIMAL_EMAC_BUFSIZE
-# warning "You using an incomplete/untested configuration"
-#endif
-
-#ifndef CONFIG_SAMA5_EMAC_NRXDESC
-# define CONFIG_SAMA5_EMAC_NRXDESC 8
-#endif
-#ifndef CONFIG_SAMA5_EMAC_NTXDESC
-# define CONFIG_SAMA5_EMAC_NTXDESC 4
-#endif
+#define EMAC_RX_UNITSIZE 128 /* Fixed size for RX buffer */
+#define EMAC_TX_UNITSIZE 1518 /* Size for ETH frame length */
/* We need at least one more free buffer than transmit buffers */
-#define SAM_EMAC_NFREEBUFFERS (CONFIG_SAMA5_EMAC_NTXDESC+1)
+#define SAM_EMAC_NFREEBUFFERS (CONFIG_SAMA5_EMAC_NTXBUFFERS+1)
/* Extremely detailed register debug that you would normally never want
* enabled.
@@ -197,7 +188,7 @@
/* Interrupt bit sets *******************************************************/
/* Helpers ******************************************************************/
-/* This is a helper pointer for accessing the contents of the Ethernet
+/* This is a helper pointer for accessing the contents of the EMAC
* header
*/
@@ -223,18 +214,18 @@ struct sam_emac_s
/* Used to track transmit and receive descriptors */
+ uint8_t phyaddr; /* PHY address (pre-defined by pins on reset) */
+ uint16_t txhead; /* Circular buffer head index */
+ uint16_t txtail; /* Circualr buffer tail index */
+ uint16_t rxndx; /* RX index for current processing RX descriptor */
+ uint16_t segments; /* RX segment count */
+ uint16_t inflight; /* Number of TX transfers "in_flight" */
+ uint16_t retries; /* PHY retry count */
+
uint8_t *rxbuffer; /* Allocated RX buffers */
uint8_t *txbuffer; /* Allocated TX buffers */
struct emac_rxdesc_s *rxdesc; /* Allocated RX descriptors */
struct emac_txdesc_s *txdesc; /* Allocated TX descriptors */
- struct emac_txdesc_s *txhead; /* Next available TX descriptor */
- struct emac_rxdesc_s *rxhead; /* Next available RX descriptor */
-
- struct emac_txdesc_s *txtail; /* First "in_flight" TX descriptor */
- struct emac_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 */
/* Debug stuff */
@@ -244,16 +235,6 @@ struct sam_emac_s
uint32_t vallast; /* Last value */
int ntimes; /* Number of times */
#endif
-
- /* Descriptor allocations */
-
- struct emac_rxdesc_s rxtable[CONFIG_SAMA5_EMAC_NRXDESC];
- struct emac_txdesc_s txtable[CONFIG_SAMA5_EMAC_NTXDESC];
-
- /* Buffer allocations */
-
- uint8_t rxbuffer[CONFIG_SAMA5_EMAC_NRXDESC*CONFIG_SAMA5_EMAC_BUFSIZE];
- uint8_t alloc[SAM_EMAC_NFREEBUFFERS*CONFIG_SAMA5_EMAC_BUFSIZE];
};
/****************************************************************************
@@ -306,13 +287,6 @@ static void sam_putreg(struct sam_emac_s *priv, uintptr_t addr, uint32_t val);
# define sam_putreg(priv,addr,val) putreg32(val,addr)
#endif
-/* Free buffer management */
-
-static void sam_initbuffer(FAR struct sam_emac_s *priv);
-static inline uint8_t *sam_allocbuffer(FAR struct sam_emac_s *priv);
-static inline void sam_freebuffer(FAR struct sam_emac_s *priv, uint8_t *buffer);
-static inline bool sam_isfreebuffer(FAR struct sam_emac_s *priv);
-
/* Common TX logic */
static int sam_transmit(FAR struct sam_emac_s *priv);
@@ -327,7 +301,7 @@ static int sam_recvframe(FAR struct sam_emac_s *priv);
static void sam_receive(FAR struct sam_emac_s *priv);
static void sam_freeframe(FAR struct sam_emac_s *priv);
static void sam_txdone(FAR struct sam_emac_s *priv);
-static int sam_interrupt(int irq, FAR void *context);
+static int sam_emac_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
@@ -344,11 +318,6 @@ static int sam_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
static int sam_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
#endif
-/* Descriptor Initialization */
-
-static void sam_txdescinit(FAR struct sam_emac_s *priv);
-static void sam_rxdescinit(FAR struct sam_emac_s *priv);
-
/* PHY Initialization */
static int sam_phyread(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t *value);
@@ -356,23 +325,19 @@ static int sam_phywrite(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t valu
#ifdef CONFIG_PHY_DM9161
static inline int sam_dm9161(FAR struct sam_emac_s *priv);
#endif
+static int sam_autonegotiate(struct sam_emac_s *priv);
+static bool sam_linkup(struct sam_emac_s *priv);
static int sam_phyinit(FAR struct sam_emac_s *priv);
/* MAC/DMA Initialization */
-#ifdef CONFIG_SAMA5_MII
-static inline void sam_selectmii(void);
-#endif
-#ifdef CONFIG_SAMA5_RMII
-static inline void sam_selectrmii(void);
-#endif
-static inline void sam_ethgpioconfig(FAR struct sam_emac_s *priv);
-static void sam_ethreset(FAR struct sam_emac_s *priv);
-static int sam_macconfig(FAR struct sam_emac_s *priv);
+static void sam_txreset(struct sam_emac_s *priv);
+static void sam_rxreset(struct sam_emac_s *priv);
+static void sam_emac_reset(FAR struct sam_emac_s *priv);
static void sam_macaddress(FAR struct sam_emac_s *priv);
-static int sam_macenable(FAR struct sam_emac_s *priv);
-static int sam_ethconfig(FAR struct sam_emac_s *priv);
+static int sam_emac_configure(FAR struct sam_emac_s *priv);
static int sam_buffer_initialize(struct sam_emac_s *priv);
+static void sam_buffer_free(struct sam_emac_s *priv);
/****************************************************************************
* Private Functions
@@ -475,121 +440,6 @@ static void sam_putreg(struct twi_dev_s *priv, uintptr_t address,
#endif
/****************************************************************************
- * Function: sam_initbuffer
- *
- * Description:
- * Initialize the free buffer list.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called during early driver initialization before Ethernet interrupts
- * are enabled.
- *
- ****************************************************************************/
-
-static void sam_initbuffer(FAR struct sam_emac_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 < SAM_EMAC_NFREEBUFFERS;
- i++, buffer += CONFIG_SAMA5_EMAC_BUFSIZE)
- {
- sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
- }
-}
-
-/****************************************************************************
- * Function: sam_allocbuffer
- *
- * Description:
- * Allocate one buffer from the free buffer list.
- *
- * 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 *sam_allocbuffer(FAR struct sam_emac_s *priv)
-{
- /* Allocate a buffer by returning the head of the free buffer list */
-
- return (uint8_t *)sq_remfirst(&priv->freeb);
-}
-
-/****************************************************************************
- * Function: sam_freebuffer
- *
- * Description:
- * Return a buffer to the free buffer list.
- *
- * 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 sam_freebuffer(FAR struct sam_emac_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: sam_isfreebuffer
- *
- * Description:
- * Return TRUE if the free buffer list is not empty.
- *
- * 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.
- *
- ****************************************************************************/
-
-static inline bool sam_isfreebuffer(FAR struct sam_emac_s *priv)
-{
- /* Return TRUE if the free buffer list is not empty */
-
- return !sq_empty(&priv->freeb);
-}
-
-/****************************************************************************
* Function: sam_transmit
*
* Description:
@@ -613,137 +463,81 @@ static int sam_transmit(FAR struct sam_emac_s *priv)
{
struct emac_txdesc_s *txdesc;
struct emac_txdesc_s *txfirst;
-
- /* The internal (optimal) uIP buffer size may be configured to be larger
- * than the Ethernet buffer size.
- */
-
-#if OPTIMAL_EMAC_BUFSIZE > CONFIG_SAMA5_EMAC_BUFSIZE
uint8_t *buffer;
int bufcount;
int lastsize;
+ int txndx;
int i;
-#endif
/* Verify that the hardware is ready to send another packet. 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->txhead;
+ txndx = priv->txhead;
+ txdesc = &priv->txdesc[txndx];
txfirst = txdesc;
- nllvdbg("d_len: %d d_buf: %p txhead: %p tdes0: %08x\n",
- priv->dev.d_len, priv->dev.d_buf, txdesc, txdesc->tdes0);
-
- DEBUGASSERT(txdesc && (txdesc->tdes0 & EMAC_TDES0_OWN) == 0);
+ nllvdbg("d_len: %d d_buf: %p txhead: %d\n",
+ priv->dev.d_len, priv->dev.d_buf, txndx);
- /* Is the size to be sent greater than the size of the Ethernet buffer? */
+ /* Now many buffers will be need to send the packet? */
- DEBUGASSERT(priv->dev.d_len > 0 && priv->dev.d_buf != NULL);
-
-#if OPTIMAL_EMAC_BUFSIZE > CONFIG_SAMA5_EMAC_BUFSIZE
- if (priv->dev.d_len > CONFIG_SAMA5_EMAC_BUFSIZE)
- {
- /* Yes... how many buffers will be need to send the packet? */
+ bufcount = (priv->dev.d_len + (CONFIG_NET_BUFSIZE-1)) / CONFIG_NET_BUFSIZE;
+ lastsize = priv->dev.d_len - (bufcount - 1) * CONFIG_NET_BUFSIZE;
- bufcount = (priv->dev.d_len + (CONFIG_SAMA5_EMAC_BUFSIZE-1)) / CONFIG_SAMA5_EMAC_BUFSIZE;
- lastsize = priv->dev.d_len - (bufcount - 1) * CONFIG_SAMA5_EMAC_BUFSIZE;
+ nllvdbg("bufcount: %d lastsize: %d\n", bufcount, lastsize);
- nllvdbg("bufcount: %d lastsize: %d\n", bufcount, lastsize);
+ /* Set the first segment bit in the first TX descriptor */
+#warning Missing logic
- /* Set the first segment bit in the first TX descriptor */
+ /* Set up all but the last TX descriptor */
- txdesc->tdes0 |= EMAC_TDES0_FS;
+ buffer = priv->dev.d_buf;
- /* Set up all but the last TX descriptor */
+ for (i = 0; i < bufcount; i++)
+ {
+ /* Set the Buffer1 address pointer */
+#warning Missing logic
- buffer = priv->dev.d_buf;
+ /* Set the buffer size in all TX descriptors */
- for (i = 0; i < bufcount; i++)
+ if (i == (bufcount-1))
{
- /* This could be a normal event but the design does not handle it */
-
- DEBUGASSERT((txdesc->tdes0 & EMAC_TDES0_OWN) == 0);
-
- /* Set the Buffer1 address pointer */
-
- txdesc->tdes2 = (uint32_t)buffer;
-
- /* Set the buffer size in all TX descriptors */
-
- if (i == (bufcount-1))
- {
- /* This is the last segment. Set the last segment bit in the
- * last TX descriptor and ask for an interrupt when this
- * segment transfer completes.
- */
-
- txdesc->tdes0 |= (EMAC_TDES0_LS | EMAC_TDES0_IC);
-
- /* This segement is, most likely, of fractional buffersize */
-
- txdesc->tdes1 = lastsize;
- buffer += lastsize;
- }
- else
- {
- /* This is not the last segment. We don't want an interrupt
- * when this segment transfer completes.
- */
-
- txdesc->tdes0 &= ~EMAC_TDES0_IC;
-
- /* The size of the transfer is the whole buffer */
-
- txdesc->tdes1 = CONFIG_SAMA5_EMAC_BUFSIZE;
- buffer += CONFIG_SAMA5_EMAC_BUFSIZE;
- }
-
- /* Give the descriptor to DMA */
+ /* This is the last segment. Set the last segment bit in the
+ * last TX descriptor and ask for an interrupt when this
+ * segment transfer completes.
+ */
+#warning Missing logic
- txdesc->tdes0 |= EMAC_TDES0_OWN;
- txdesc = (struct emac_txdesc_s *)txdesc->tdes3;
+ /* This segement is, most likely, of fractional buffersize */
+#warning Missing logic
+ buffer += lastsize;
}
- }
- else
-#endif
- {
- /* The single descriptor is both the first and last segment. And we do
- * want an interrupt when the transfer completes.
- */
-
- txdesc->tdes0 |= (EMAC_TDES0_FS | EMAC_TDES0_LS | EMAC_TDES0_IC);
-
- /* Set frame size */
-
- DEBUGASSERT(priv->dev.d_len <= CONFIG_NET_BUFSIZE);
- txdesc->tdes1 = priv->dev.d_len;
-
- /* Set the Buffer1 address pointer */
-
- txdesc->tdes2 = (uint32_t)priv->dev.d_buf;
-
- /* Set OWN bit of the TX descriptor tdes0. This gives the buffer to
- * Ethernet DMA
- */
+ else
+ {
+ /* This is not the last segment. We don't want an interrupt
+ * when this segment transfer completes.
+ */
+#warning Missing logic
- txdesc->tdes0 |= EMAC_TDES0_OWN;
+ /* The size of the transfer is the whole buffer */
+#warning Missing logic
- /* Point to the next available TX descriptor */
+ }
- txdesc = (struct emac_txdesc_s *)txdesc->tdes3;
+ /* Give the descriptor to DMA */
+#warning Missing logic
}
/* Remember where we left off in the TX descriptor chain */
- priv->txhead = txdesc;
+ priv->txhead = txndx;
/* Detach the buffer from priv->dev structure. That buffer is now
* "in-flight".
*/
- priv->dev.d_buf = NULL;
priv->dev.d_len = 0;
/* If there is no other TX buffer, in flight, then remember the location
@@ -753,14 +547,14 @@ static int sam_transmit(FAR struct sam_emac_s *priv)
if (!priv->txtail)
{
DEBUGASSERT(priv->inflight == 0);
- priv->txtail = txfirst;
+ priv->txtail = txndx;
}
/* Increment the number of TX transfer in-flight */
priv->inflight++;
- nllvdbg("txhead: %p txtail: %p inflight: %d\n",
+ nllvdbg("txhead: %d txtail: %d inflight: %d\n",
priv->txhead, priv->txtail, priv->inflight);
/* If all TX descriptors are in-flight, then we have to disable receive interrupts
@@ -768,7 +562,7 @@ static int sam_transmit(FAR struct sam_emac_s *priv)
* events.
*/
- if (priv->inflight >= CONFIG_SAMA5_EMAC_NTXDESC)
+ if (priv->inflight >= CONFIG_SAMA5_EMAC_NTXBUFFERS)
{
#warning "Missing logic"
}
@@ -827,18 +621,12 @@ static int sam_uiptxpoll(struct uip_driver_s *dev)
sam_transmit(priv);
DEBUGASSERT(dev->d_len == 0 && dev->d_buf == NULL);
- /* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
+ /* Check if the next TX descriptor is owned by the EMAC DMA or CPU. We
* cannot perform the TX poll if we are unable to accept another packet for
* transmission.
- *
- * In a race condition, EMAC_TDES0_OWN may be cleared BUT still not available
- * because sam_freeframe() has not yet run. If sam_freeframe() has run,
- * the buffer1 pointer (tdes2) will be nullified (and inflight should be <
- * CONFIG_SAMA5_EMAC_NTXDESC).
*/
+#warning Missing logic
- if ((priv->txhead->tdes0 & EMAC_TDES0_OWN) != 0 ||
- priv->txhead->tdes2 != 0)
{
/* We have to terminate the poll if we have no more descriptors
* available for another transfer.
@@ -846,21 +634,6 @@ static int sam_uiptxpoll(struct uip_driver_s *dev)
return -EBUSY;
}
-
- /* We have the descriptor, we can continue the poll. Allocate a new
- * buffer for the poll.
- */
-
- dev->d_buf = sam_allocbuffer(priv);
-
- /* We can't continue the poll if we have no buffers */
-
- if (dev->d_buf == NULL)
- {
- /* Terminate the poll. */
-
- return -ENOMEM;
- }
}
/* If zero is returned, the polling will continue until all connections have
@@ -892,43 +665,16 @@ static void sam_dopoll(FAR struct sam_emac_s *priv)
{
FAR struct uip_driver_s *dev = &priv->dev;
- /* Check if the next TX descriptor is owned by the Ethernet DMA or
+ /* Check if the next TX descriptor is owned by the EMAC DMA or
* CPU. We cannot perform the TX poll if we are unable to accept
* another packet for transmission.
- *
- * In a race condition, EMAC_TDES0_OWN may be cleared BUT still not available
- * because sam_freeframe() has not yet run. If sam_freeframe() has run,
- * the buffer1 pointer (tdes2) will be nullified (and inflight should be <
- * CONFIG_SAMA5_EMAC_NTXDESC).
*/
- if ((priv->txhead->tdes0 & EMAC_TDES0_OWN) == 0 &&
- priv->txhead->tdes2 == 0)
+#warning Missing logic
{
- /* If we have the descriptor, then poll uIP for new XMIT data.
- * Allocate a buffer for the poll.
- */
-
- DEBUGASSERT(dev->d_len == 0 && dev->d_buf == NULL);
- dev->d_buf = sam_allocbuffer(priv);
-
- /* We can't poll if we have no buffers */
-
- if (dev->d_buf)
- {
- (void)uip_poll(dev, sam_uiptxpoll);
-
- /* We will, most likely end up with a buffer to be freed. But it
- * might not be the same one that we allocated above.
- */
+ /* If we have the descriptor, then poll uIP for new XMIT data. */
- if (dev->d_buf)
- {
- DEBUGASSERT(dev->d_len == 0);
- sam_freebuffer(priv, dev->d_buf);
- dev->d_buf = NULL;
- }
- }
+ (void)uip_poll(dev, sam_uiptxpoll);
}
}
@@ -963,13 +709,11 @@ static void sam_freesegment(FAR struct sam_emac_s *priv,
rxdesc = rxfirst;
for (i = 0; i < segments; i++)
{
- rxdesc->rdes0 = EMAC_RDES0_OWN;
- rxdesc = (struct emac_rxdesc_s *)rxdesc->rdes3;
+#warning Missing logic
}
/* Reset the segment managment logic */
- priv->rxcurr = NULL;
priv->segments = 0;
/* Check if the RX Buffer unavailable flag is set */
@@ -1002,20 +746,10 @@ static int sam_recvframe(FAR struct sam_emac_s *priv)
struct emac_rxdesc_s *rxdesc;
struct emac_rxdesc_s *rxcurr;
uint8_t *buffer;
+ int rxndx;
int i;
- nllvdbg("rxhead: %p rxcurr: %p segments: %d\n",
- priv->rxhead, priv->rxcurr, priv->segments);
-
- /* Check if there are free buffers. We cannot receive new frames in this
- * design unless there is at least one free buffer.
- */
-
- if (!sam_isfreebuffer(priv))
- {
- nlldbg("No free buffers\n");
- return -ENOMEM;
- }
+ nllvdbg("rxndx: %d segments: %d\n", priv->rxndx, priv->segments);
/* Scan descriptors owned by the CPU. Scan until:
*
@@ -1029,31 +763,23 @@ static int sam_recvframe(FAR struct sam_emac_s *priv)
* transmit logic should also have disabled further RX interrupts.
*/
- rxdesc = priv->rxhead;
- for (i = 0;
- (rxdesc->rdes0 & EMAC_RDES0_OWN) == 0 &&
- i < CONFIG_SAMA5_EMAC_NRXDESC &&
- priv->inflight < CONFIG_SAMA5_EMAC_NTXDESC;
- i++)
+ rxndx = priv->rxndx;
+ rxdesc = &priv->rxdesc[rxndx];
+
+#warning Missing logic
{
/* Check if this is the first segment in the frame */
-
- if ((rxdesc->rdes0 & EMAC_RDES0_FS) != 0 &&
- (rxdesc->rdes0 & EMAC_RDES0_LS) == 0)
- {
- priv->rxcurr = rxdesc;
- priv->segments = 1;
- }
+#warning Missing logic
/* Check if this is an intermediate segment in the frame */
-
- else if (((rxdesc->rdes0 & EMAC_RDES0_LS) == 0)&&
- ((rxdesc->rdes0 & EMAC_RDES0_FS) == 0))
+#warning Missing logic
+ if (true)
{
priv->segments++;
}
/* Otherwise, it is the last segment in the frame */
+#warning Missing logic
else
{
@@ -1067,50 +793,31 @@ static int sam_recvframe(FAR struct sam_emac_s *priv)
}
else
{
- rxcurr = priv->rxcurr;
+ rxcurr = &priv->rxdesc[priv->rxndx];
}
- nllvdbg("rxhead: %p rxcurr: %p segments: %d\n",
- priv->rxhead, priv->rxcurr, priv->segments);
+ nllvdbg("rxndx: %d rxcurr: %p segments: %d\n",
+ priv->rxndx, rxcurr, priv->segments);
/* Check if any errors are reported in the frame */
- if ((rxdesc->rdes0 & EMAC_RDES0_ES) == 0)
+#warning Missing logic
+ if (true)
{
struct uip_driver_s *dev = &priv->dev;
/* Get the Frame Length of the received packet: substruct 4
* bytes of the CRC
*/
-
- dev->d_len = ((rxdesc->rdes0 & EMAC_RDES0_FL_MASK) >> EMAC_RDES0_FL_SHIFT) - 4;
-
- /* Get a buffer from the free list. We don't even check if
- * this is successful because we already assure the free
- * list is not empty above.
- */
-
- buffer = sam_allocbuffer(priv);
-
- /* Take the buffer from the RX descriptor of the first free
- * segment, put it into the uIP device structure, then replace
- * the buffer in the RX descriptor with the newly allocated
- * buffer.
- */
-
- DEBUGASSERT(dev->d_buf == NULL);
- dev->d_buf = (uint8_t*)rxcurr->rdes2;
- rxcurr->rdes2 = (uint32_t)buffer;
+#warning Missing logic
/* Return success, remebering where we should re-start scanning
* and resetting the segment scanning logic
*/
+#warning Missing logic
- priv->rxhead = (struct emac_rxdesc_s*)rxdesc->rdes3;
- sam_freesegment(priv, rxcurr, priv->segments);
-
- nllvdbg("rxhead: %p d_buf: %p d_len: %d\n",
- priv->rxhead, dev->d_buf, dev->d_len);
+ nllvdbg("rxndx: %d d_buf: %p d_len: %d\n",
+ priv->rxndx, dev->d_buf, dev->d_len);
return OK;
}
@@ -1119,25 +826,22 @@ static int sam_recvframe(FAR struct sam_emac_s *priv)
/* Drop the frame that contains the errors, reset the segment
* scanning logic, and continue scanning with the next frame.
*/
-
- nlldbg("DROPPED: RX descriptor errors: %08x\n", rxdesc->rdes0);
+#warning Missing logic
sam_freesegment(priv, rxcurr, priv->segments);
}
}
/* Try the next descriptor */
-
- rxdesc = (struct emac_rxdesc_s*)rxdesc->rdes3;
+#warning Missing logic
}
/* We get here after all of the descriptors have been scanned or when rxdesc points
* to the first descriptor owned by the DMA. Remember where we left off.
*/
- priv->rxhead = rxdesc;
+ priv->rxndx = rxndx;
- nllvdbg("rxhead: %p rxcurr: %p segments: %d\n",
- priv->rxhead, priv->rxcurr, priv->segments);
+ nllvdbg("rxndx: %d segments: %d\n", priv->rxndx, priv->segments);
return -EAGAIN;
}
@@ -1164,7 +868,7 @@ static void sam_receive(FAR struct sam_emac_s *priv)
struct uip_driver_s *dev = &priv->dev;
/* Loop while while sam_recvframe() successfully retrieves valid
- * Ethernet frames.
+ * EMAC frames.
*/
while (sam_recvframe(priv) == OK)
@@ -1224,20 +928,6 @@ static void sam_receive(FAR struct sam_emac_s *priv)
{
nlldbg("DROPPED: Unknown type: %04x\n", BUF->type);
}
-
- /* We are finished with the RX buffer. NOTE: If the buffer is
- * re-used for transmission, the dev->d_buf field will have been
- * nullified.
- */
-
- if (dev->d_buf)
- {
- /* Free the receive packet buffer */
-
- sam_freebuffer(priv, dev->d_buf);
- dev->d_buf = NULL;
- dev->d_len = 0;
- }
}
}
@@ -1261,45 +951,32 @@ static void sam_receive(FAR struct sam_emac_s *priv)
static void sam_freeframe(FAR struct sam_emac_s *priv)
{
struct emac_txdesc_s *txdesc;
+ int txtail;
int i;
- nllvdbg("txhead: %p txtail: %p inflight: %d\n",
+ nllvdbg("txhead: %d txtail: %d inflight: %d\n",
priv->txhead, priv->txtail, priv->inflight);
/* Scan for "in-flight" descriptors owned by the CPU */
- txdesc = priv->txtail;
+ txtail = priv->txtail;
+ txdesc = &priv->txdesc[txtail];
+
if (txdesc)
{
DEBUGASSERT(priv->inflight > 0);
- for (i = 0; (txdesc->tdes0 & EMAC_TDES0_OWN) == 0; i++)
+#warning Missing logic
{
- /* There should be a buffer assigned to all in-flight
- * TX descriptors.
- */
-
- nllvdbg("txtail: %p tdes0: %08x tdes2: %08x tdes3: %08x\n",
- txdesc, txdesc->tdes0, txdesc->tdes2, txdesc->tdes3);
-
- DEBUGASSERT(txdesc->tdes2 != 0);
-
/* Check if this is the first segment of a TX frame. */
+#warning Missing logic
- if ((txdesc->tdes0 & EMAC_TDES0_FS) != 0)
- {
- /* Yes.. Free the buffer */
-
- sam_freebuffer(priv, (uint8_t*)txdesc->tdes2);
- }
-
- /* In any event, make sure that TDES2 is nullified. */
-
- txdesc->tdes2 = 0;
+ /* In any event, make sure that xxx is nullified. */
+#warning Missing logic
/* Check if this is the last segement of a TX frame */
- if ((txdesc->tdes0 & EMAC_TDES0_LS) != 0)
+#warning Missing logic
{
/* Yes.. Decrement the number of frames "in-flight". */
@@ -1314,24 +991,23 @@ static void sam_freeframe(FAR struct sam_emac_s *priv)
if (priv->inflight <= 0)
{
- priv->txtail = NULL;
+ priv->txtail = 0;
priv->inflight = 0;
return;
}
}
/* Try the next descriptor in the TX chain */
-
- txdesc = (struct emac_txdesc_s*)txdesc->tdes3;
+#warning Missing logic
}
/* We get here if (1) there are still frames "in-flight". Remember
* where we left off.
*/
- priv->txtail = txdesc;
+ priv->txtail = txtail;
- nllvdbg("txhead: %p txtail: %p inflight: %d\n",
+ nllvdbg("txhead: %d txtail: %d inflight: %d\n",
priv->txhead, priv->txtail, priv->inflight);
}
}
@@ -1377,7 +1053,7 @@ static void sam_txdone(FAR struct sam_emac_s *priv)
}
/****************************************************************************
- * Function: sam_interrupt
+ * Function: sam_emac_interrupt
*
* Description:
* Hardware interrupt handler
@@ -1393,7 +1069,7 @@ static void sam_txdone(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-static int sam_interrupt(int irq, FAR void *context)
+static int sam_emac_interrupt(int irq, FAR void *context)
{
register FAR struct sam_emac_s *priv = &g_emac;
uint32_t dmasr;
@@ -1521,47 +1197,16 @@ static void sam_polltimer(int argc, uint32_t arg, ...)
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
FAR struct uip_driver_s *dev = &priv->dev;
- /* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
+ /* Check if the next TX descriptor is owned by the EMAC DMA or CPU. We
* cannot perform the timer poll if we are unable to accept another packet
* for transmission. Hmmm.. might be bug here. Does this mean if there is
* a transmit in progress, we will miss TCP time state updates?
- *
- * In a race condition, EMAC_TDES0_OWN may be cleared BUT still not available
- * because sam_freeframe() has not yet run. If sam_freeframe() has run,
- * the buffer1 pointer (tdes2) will be nullified (and inflight should be <
- * CONFIG_SAMA5_EMAC_NTXDESC).
*/
-
- if ((priv->txhead->tdes0 & EMAC_TDES0_OWN) == 0 &&
- priv->txhead->tdes2 == 0)
+#warning Missing logic
{
- /* If we have the descriptor, then perform the timer poll. Allocate a
- * buffer for the poll.
- */
-
- DEBUGASSERT(dev->d_len == 0 && dev->d_buf == NULL);
- dev->d_buf = sam_allocbuffer(priv);
-
- /* We can't poll if we have no buffers */
-
- if (dev->d_buf)
- {
- /* Update TCP timing states and poll uIP for new XMIT data.
- */
+ /* Update TCP timing states and poll uIP for new XMIT data. */
- (void)uip_timer(dev, sam_uiptxpoll, SAM_POLLHSEC);
-
- /* We will, most likely end up with a buffer to be freed. But it
- * might not be the same one that we allocated above.
- */
-
- if (dev->d_buf)
- {
- DEBUGASSERT(dev->d_len == 0);
- sam_freebuffer(priv, dev->d_buf);
- dev->d_buf = NULL;
- }
- }
+ (void)uip_timer(dev, sam_uiptxpoll, SAM_POLLHSEC);
}
/* Setup the watchdog poll timer again */
@@ -1573,7 +1218,7 @@ static void sam_polltimer(int argc, uint32_t arg, ...)
* Function: sam_ifup
*
* Description:
- * NuttX Callback: Bring up the Ethernet interface when an IP address is
+ * NuttX Callback: Bring up the EMAC interface when an IP address is
* provided
*
* Parameters:
@@ -1595,23 +1240,48 @@ static int sam_ifup(struct uip_driver_s *dev)
dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
(dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
- /* Configure the Ethernet interface for DMA operation. */
+ /* Configure the EMAC interface for normal operation. */
+
+ nllvdbg("Initialize the EMAC\n");
+ sam_emac_configure(priv);
+
+ /* Set the MAC address (should have been configured while we were down) */
+
+ sam_macaddress(priv);
+
+ /* Initialize for PHY access */
+
+ ret = sam_phyinit(priv);
+ if (ret < 0)
+ {
+ ndbg("ERROR: sam_phyinit failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Auto Negotiate, working in RMII mode */
- ret = sam_ethconfig(priv);
+ ret = sam_autonegotiate(priv);
if (ret < 0)
{
+ ndbg("ERROR: sam_autonegotiate failed: %d\n", ret);
return ret;
}
+ while (sam_linkup(priv) == 0);
+ nvdbg("Link detected \n");
+
+ /* Enable normal MAC operation */
+
+ nllvdbg("Enable normal operation\n");
+
/* Set and activate a timer process */
(void)wd_start(priv->txpoll, SAM_WDDELAY, sam_polltimer, 1, (uint32_t)priv);
- /* Enable the Ethernet interrupt */
+ /* Enable the EMAC interrupt */
priv->ifup = true;
- up_enable_irq(SAM_IRQ_ETH);
-
+ up_enable_irq(SAM_IRQ_EMAC);
return OK;
}
@@ -1638,10 +1308,10 @@ static int sam_ifdown(struct uip_driver_s *dev)
ndbg("Taking the network down\n");
- /* Disable the Ethernet interrupt */
+ /* Disable the EMAC interrupt */
flags = irqsave();
- up_disable_irq(SAM_IRQ_ETH);
+ up_disable_irq(SAM_IRQ_EMAC);
/* Cancel the TX poll timer and TX timeout timers */
@@ -1653,7 +1323,7 @@ static int sam_ifdown(struct uip_driver_s *dev)
* successfully brings the interface back up.
*/
- sam_ethreset(priv);
+ sam_emac_reset(priv);
/* Mark the device "down" */
@@ -1775,165 +1445,6 @@ static int sam_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
#endif
/****************************************************************************
- * Function: sam_txdescinit
- *
- * Description:
- * Initializes the DMA TX descriptors in chain mode.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-static void sam_txdescinit(FAR struct sam_emac_s *priv)
-{
- struct emac_txdesc_s *txdesc;
- int i;
-
- /* priv->txhead will point to the first, available TX descriptor in the chain.
- * Set the priv->txhead pointer to the first descriptor in the table.
- */
-
- priv->txhead = priv->txtable;
-
- /* priv->txtail will point to the first segment of the oldest pending
- * "in-flight" TX transfer. NULL means that there are no active TX
- * transfers.
- */
-
- priv->txtail = NULL;
- priv->inflight = 0;
-
- /* Initialize each TX descriptor */
-
- for (i = 0; i < CONFIG_SAMA5_EMAC_NTXDESC; i++)
- {
- txdesc = &priv->txtable[i];
-
- /* Set Second Address Chained bit */
-
- txdesc->tdes0 = EMAC_TDES0_TCH;
-
-#ifdef CHECKSUM_BY_HARDWARE
- /* Enable the checksum insertion for the TX frames */
-
- txdesc->tdes0 |= EMAC_TDES0_CIC_ALL;
-#endif
-
- /* Clear Buffer1 address pointer (buffers will be assigned as they
- * are used)
- */
-
- txdesc->tdes2 = 0;
-
- /* Initialize the next descriptor with the Next Descriptor Polling Enable */
-
- if (i < (CONFIG_SAMA5_EMAC_NTXDESC-1))
- {
- /* Set next descriptor address register with next descriptor base
- * address
- */
-
- txdesc->tdes3 = (uint32_t)&priv->txtable[i+1];
- }
- else
- {
- /* For last descriptor, set next descriptor address register equal
- * to the first descriptor base address
- */
-
- txdesc->tdes3 = (uint32_t)priv->txtable;
- }
- }
-
- /* Set Transmit Desciptor List Address Register */
-#warning "Missing logic"
-}
-
-/****************************************************************************
- * Function: sam_rxdescinit
- *
- * Description:
- * Initializes the DMA RX descriptors in chain mode.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-static void sam_rxdescinit(FAR struct sam_emac_s *priv)
-{
- struct emac_rxdesc_s *rxdesc;
- int i;
-
- /* priv->rxhead will point to the first, RX descriptor in the chain.
- * This will be where we receive the first incomplete frame.
- */
-
- priv->rxhead = priv->rxtable;
-
- /* If we accumulate the frame in segments, priv->rxcurr points to the
- * RX descriptor of the first segment in the current TX frame.
- */
-
- priv->rxcurr = NULL;
- priv->segments = 0;
-
- /* Initialize each TX descriptor */
-
- for (i = 0; i < CONFIG_SAMA5_EMAC_NRXDESC; i++)
- {
- rxdesc = &priv->rxtable[i];
-
- /* Set Own bit of the RX descriptor rdes0 */
-
- rxdesc->rdes0 = EMAC_RDES0_OWN;
-
- /* Set Buffer1 size and Second Address Chained bit and enabled DMA
- * RX desc receive interrupt
- */
-
- rxdesc->rdes1 = EMAC_RDES1_RCH | (uint32_t)CONFIG_SAMA5_EMAC_BUFSIZE;
-
- /* Set Buffer1 address pointer */
-
- rxdesc->rdes2 = (uint32_t)&priv->rxbuffer[i*CONFIG_SAMA5_EMAC_BUFSIZE];
-
- /* Initialize the next descriptor with the Next Descriptor Polling Enable */
-
- if (i < (CONFIG_SAMA5_EMAC_NRXDESC-1))
- {
- /* Set next descriptor address register with next descriptor base
- * address
- */
-
- rxdesc->rdes3 = (uint32_t)&priv->rxtable[i+1];
- }
- else
- {
- /* For last descriptor, set next descriptor address register equal
- * to the first descriptor base address
- */
-
- rxdesc->rdes3 = (uint32_t)priv->rxtable;
- }
- }
-
- /* Set Receive Descriptor List Address Register */
-#warning Missing logic
-}
-
-/****************************************************************************
* Function: sam_phyread
*
* Description:
@@ -2054,7 +1565,7 @@ static inline int sam_dm9161(FAR struct sam_emac_s *priv)
* indication that check if the DM9161 PHY CHIP is not ready.
*/
- ret = sam_phyread(CONFIG_SAMA5_PHYADDR, MII_PHYID1, &phyval);
+ ret = sam_phyread(CONFIG_SAMA5_EMAC_PHYADDR, MII_PHYID1, &phyval);
if (ret < 0)
{
ndbg("Failed to read the PHY ID1: %d\n", ret);
@@ -2072,7 +1583,7 @@ static inline int sam_dm9161(FAR struct sam_emac_s *priv)
/* Now check the "DAVICOM Specified Configuration Register (DSCR)", Register 16 */
- ret = sam_phyread(CONFIG_SAMA5_PHYADDR, 16, &phyval);
+ ret = sam_phyread(CONFIG_SAMA5_EMAC_PHYADDR, 16, &phyval);
if (ret < 0)
{
ndbg("Failed to read the PHY Register 0x10: %d\n", ret);
@@ -2125,7 +1636,7 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Put the PHY in reset mode */
- ret = sam_phywrite(CONFIG_SAMA5_PHYADDR, MII_MCR, MII_MCR_RESET);
+ ret = sam_phywrite(CONFIG_SAMA5_EMAC_PHYADDR, MII_MCR, MII_MCR_RESET);
if (ret < 0)
{
ndbg("Failed to reset the PHY: %d\n", ret);
@@ -2135,7 +1646,7 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Perform any necessary, board-specific PHY initialization */
-#ifdef CONFIG_SAMA5_PHYINIT
+#ifdef CONFIG_SAMA5_EMAC_PHYINIT
ret = sam_phy_boardinitialize(EMAC_INTF);
if (ret < 0)
{
@@ -2156,12 +1667,12 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Perform auto-negotion if so configured */
-#ifdef CONFIG_SAMA5_AUTONEG
+#ifdef CONFIG_SAMA5_EMAC_AUTONEG
/* Wait for link status */
for (timeout = 0; timeout < PHY_RETRY_TIMEOUT; timeout++)
{
- ret = sam_phyread(CONFIG_SAMA5_PHYADDR, MII_MSR, &phyval);
+ ret = sam_phyread(CONFIG_SAMA5_EMAC_PHYADDR, MII_MSR, &phyval);
if (ret < 0)
{
ndbg("Failed to read the PHY MSR: %d\n", ret);
@@ -2181,7 +1692,7 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Enable auto-gegotiation */
- ret = sam_phywrite(CONFIG_SAMA5_PHYADDR, MII_MCR, MII_MCR_ANENABLE);
+ ret = sam_phywrite(CONFIG_SAMA5_EMAC_PHYADDR, MII_MCR, MII_MCR_ANENABLE);
if (ret < 0)
{
ndbg("Failed to enable auto-negotiation: %d\n", ret);
@@ -2192,7 +1703,7 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
for (timeout = 0; timeout < PHY_RETRY_TIMEOUT; timeout++)
{
- ret = sam_phyread(CONFIG_SAMA5_PHYADDR, MII_MSR, &phyval);
+ ret = sam_phyread(CONFIG_SAMA5_EMAC_PHYADDR, MII_MSR, &phyval);
if (ret < 0)
{
ndbg("Failed to read the PHY MSR: %d\n", ret);
@@ -2212,7 +1723,7 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Read the result of the auto-negotiation from the PHY-specific register */
- ret = sam_phyread(CONFIG_SAMA5_PHYADDR, CONFIG_SAMA5_PHYSR, &phyval);
+ ret = sam_phyread(CONFIG_SAMA5_EMAC_PHYADDR, CONFIG_SAMA5_EMAC_PHYSR, &phyval);
if (ret < 0)
{
ndbg("Failed to read PHY status register\n");
@@ -2221,34 +1732,34 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Remember the selected speed and duplex modes */
- nvdbg("PHYSR[%d]: %04x\n", CONFIG_SAMA5_PHYSR, phyval);
+ nvdbg("PHYSR[%d]: %04x\n", CONFIG_SAMA5_EMAC_PHYSR, phyval);
/* Different PHYs present speed and mode information in different ways. IF
- * This CONFIG_SAMA5_PHYSR_ALTCONFIG is selected, this indicates that the PHY
+ * This CONFIG_SAMA5_EMAC_PHYSR_ALTCONFIG is selected, this indicates that the PHY
* represents speed and mode information are combined, for example, with
* separate bits for 10HD, 100HD, 10FD and 100FD.
*/
-#ifdef CONFIG_SAMA5_PHYSR_ALTCONFIG
- switch (phyval & CONFIG_SAMA5_PHYSR_ALTMODE)
+#ifdef CONFIG_SAMA5_EMAC_PHYSR_ALTCONFIG
+ switch (phyval & CONFIG_SAMA5_EMAC_PHYSR_ALTMODE)
{
default:
- case CONFIG_SAMA5_PHYSR_10HD:
+ case CONFIG_SAMA5_EMAC_PHYSR_10HD:
priv->fduplex = 0;
priv->mbps100 = 0;
break;
- case CONFIG_SAMA5_PHYSR_100HD:
+ case CONFIG_SAMA5_EMAC_PHYSR_100HD:
priv->fduplex = 0;
priv->mbps100 = 1;
break;
- case CONFIG_SAMA5_PHYSR_10FD:
+ case CONFIG_SAMA5_EMAC_PHYSR_10FD:
priv->fduplex = 1;
priv->mbps100 = 0;
break;
- case CONFIG_SAMA5_PHYSR_100FD:
+ case CONFIG_SAMA5_EMAC_PHYSR_100FD:
priv->fduplex = 1;
priv->mbps100 = 1;
break;
@@ -2261,12 +1772,12 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
*/
#else
- if ((phyval & CONFIG_SAMA5_PHYSR_MODE) == CONFIG_SAMA5_PHYSR_FULLDUPLEX)
+ if ((phyval & CONFIG_SAMA5_EMAC_PHYSR_MODE) == CONFIG_SAMA5_EMAC_PHYSR_FULLDUPLEX)
{
priv->fduplex = 1;
}
- if ((phyval & CONFIG_SAMA5_PHYSR_SPEED) == CONFIG_SAMA5_PHYSR_100MBPS)
+ if ((phyval & CONFIG_SAMA5_EMAC_PHYSR_SPEED) == CONFIG_SAMA5_EMAC_PHYSR_100MBPS)
{
priv->mbps100 = 1;
}
@@ -2275,14 +1786,14 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
#else /* Auto-negotion not selected */
phyval = 0;
-#ifdef CONFIG_SAMA5_ETHFD
+#ifdef CONFIG_SAMA5_EMAC_ETHFD
phyval |= MII_MCR_FULLDPLX;
#endif
-#ifdef CONFIG_SAMA5_ETH100MBPS
+#ifdef CONFIG_SAMA5_EMAC_ETH100MBPS
phyval |= MII_MCR_SPEED100;
#endif
- ret = sam_phywrite(CONFIG_SAMA5_PHYADDR, MII_MCR, phyval);
+ ret = sam_phywrite(CONFIG_SAMA5_EMAC_PHYADDR, MII_MCR, phyval);
if (ret < 0)
{
ndbg("Failed to write the PHY MCR: %d\n", ret);
@@ -2292,10 +1803,10 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
/* Remember the selected speed and duplex modes */
-#ifdef CONFIG_SAMA5_ETHFD
+#ifdef CONFIG_SAMA5_EMAC_ETHFD
priv->fduplex = 1;
#endif
-#ifdef CONFIG_SAMA5_ETH100MBPS
+#ifdef CONFIG_SAMA5_EMAC_ETH100MBPS
priv->mbps100 = 1;
#endif
#endif
@@ -2307,51 +1818,11 @@ static int sam_phyinit(FAR struct sam_emac_s *priv)
return OK;
}
-/************************************************************************************
- * Name: sam_selectmii
- *
- * Description:
- * Selects the MII inteface.
- *
- * Input Parameters:
- * None
- *
- * Returned Value:
- * None
- *
- ************************************************************************************/
-
-#ifdef CONFIG_SAMA5_MII
-static inline void sam_selectmii(void)
-{
-#warning Missing logic
-}
-#endif
-
-/************************************************************************************
- * Name: sam_selectrmii
- *
- * Description:
- * Selects the RMII inteface.
- *
- * Input Parameters:
- * None
- *
- * Returned Value:
- * None
- *
- ************************************************************************************/
-
-static inline void sam_selectrmii(void)
-{
-#warning Missing logic
-}
-
/****************************************************************************
* Function: sam_ethgpioconfig
*
* Description:
- * Configure GPIOs for the Ethernet interface.
+ * Configure GPIOs for the EMAC interface.
*
* Parameters:
* priv - A reference to the private driver state structure
@@ -2383,36 +1854,26 @@ static inline void sam_ethgpioconfig(FAR struct sam_emac_s *priv)
sam_configpio(PIO_EMAC_MDC);
sam_configpio(PIO_EMAC_MDIO);
-#if defined(CONFIG_SAMA5_MII)
-
- /* Select the MII interface */
-
- sam_selectmii();
-
- /* Provide clocking */
+#if defined(CONFIG_SAMA5_EMAC_MII)
+ /* Provide clocking for the MII interface */
#warning Missing logic
# endif
/* Set up the RMII interface. */
-#elif defined(CONFIG_SAMA5_RMII)
-
- /* Select the RMII interface */
-
- sam_selectrmii();
-
- /* Provide clocking */
+#elif defined(CONFIG_SAMA5_EMAC_RMII)
+ /* Provide clocking for the RMII interface */
#warning Missing logic
#endif
}
/****************************************************************************
- * Function: sam_ethreset
+ * Function: sam_txreset
*
* Description:
- * Reset the Ethernet block.
+ * Reset the transmit logic
*
* Parameters:
* priv - A reference to the private driver state structure
@@ -2424,102 +1885,151 @@ static inline void sam_ethgpioconfig(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-static void sam_ethreset(FAR struct sam_emac_s *priv)
+static void sam_txreset(struct sam_emac_s *priv)
{
+ uint8_t *txbuffer = priv->txbuffer;
+ struct emac_txdesc_s *txdesc = priv->txdesc;
+ uintptr_t bufaddr;
+ uint32_t physaddr;
uint32_t regval;
+ int ndx;
- /* Reset the EMAC */
-#warning Missing logic
+ /* Disable TX */
- /* Wait for reset to complete */
-#warning Missing logic
+ regval = sam_getreg(priv, SAM_EMAC_NCR);
+ regval &= ~EMAC_NCR_TE;
+ sam_putreg(priv, SAM_EMAC_NCR, regval);
+
+ /* Configure the TX descriptors. */
+
+ priv->txhead = 0;
+ priv->txtail = 0;
+
+ for (ndx = 0; ndx < CONFIG_SAMA5_EMAC_NTXBUFFERS; ndx++)
+ {
+ bufaddr = (uint32_t)(&(txbuffer[ndx * EMAC_TX_UNITSIZE]));
+ DEBUGASSERT((bufaddr & ~EMACTXD_ADDR_MASK) == 0);
+
+ /* Set the buffer address and mark the descriptor as used */
+
+ physaddr = sam_physramaddr(bufaddr);
+ txdesc[ndx].addr = physaddr;
+ txdesc[ndx].status = EMACTXD_CTRL_USED;
+ }
+
+ /* Mark the final descriptor in the list */
+
+ txdesc[CONFIG_SAMA5_EMAC_NTXBUFFERS - 1].status =
+ EMACTXD_CTRL_USED | EMACTXD_CTRL_WRAP;
+
+ /* Set the Transmit Buffer Queue Pointer Register */
+
+ physaddr = sam_physramaddr((uint32_t)txdesc);
+ sam_putreg(priv, SAM_EMAC_TBQP, physaddr);
}
/****************************************************************************
- * Function: sam_macconfig
+ * Function: sam_rxreset
*
* Description:
- * Configure the Ethernet MAC for DMA operation.
+ * Reset the receive logic
*
* Parameters:
* priv - A reference to the private driver state structure
*
* Returned Value:
- * OK on success; Negated errno on failure.
+ * None.
*
* Assumptions:
*
****************************************************************************/
-static int sam_macconfig(FAR struct sam_emac_s *priv)
+static void sam_rxreset(struct sam_emac_s *priv)
{
+ struct emac_rxdesc_s *rxdesc = priv->rxdesc;
+ uint8_t *rxbuffer = priv->rxbuffer;
+ uint32_t bufaddr;
+ uint32_t physaddr;
uint32_t regval;
+ int ndx;
-#warning Missing logic
+ /* Disable RX */
- if (priv->fduplex)
- {
-#warning Missing logic
- }
+ regval = sam_getreg(priv, SAM_EMAC_NCR);
+ regval &= ~EMAC_NCR_RE;
+ sam_putreg(priv, SAM_EMAC_NCR, regval);
- if (priv->mbps100)
- {
-#warning Missing logic
- }
+ /* Configure the RX descriptors. */
-#warning Missing logic
+ priv->rxndx = 0;
+ for (ndx = 0; ndx < CONFIG_SAMA5_EMAC_NRXBUFFERS; ndx++)
+ {
+ bufaddr = (uintptr_t)(&(rxbuffer[ndx * EMAC_RX_UNITSIZE]));
+ DEBUGASSERT((bufaddr & ~EMACRXD_ADDR_MASK) == 0);
- /* DMA Configuration */
-#warning Missing logic
+ /* Set the buffer address and remove EMACRXD_ADDR_OWNER and
+ * EMACRXD_ADDR_WRAP.
+ */
- return OK;
+ physaddr = sam_physramaddr(bufaddr);
+ rxdesc[ndx].addr = physaddr;
+ rxdesc[ndx].status = 0;
+ }
+
+ /* Mark the final descriptor in the list */
+
+ rxdesc[CONFIG_SAMA5_EMAC_NRXBUFFERS - 1].addr |= EMACRXD_ADDR_WRAP;
+
+ /* Set the Receive Buffer Queue Pointer Register */
+
+ physaddr = sam_physramaddr((uint32_t)rxdesc);
+ sam_putreg(priv, SAM_EMAC_RBQP, physaddr);
}
/****************************************************************************
- * Function: sam_macaddress
+ * Function: sam_emac_reset
*
* Description:
- * Configure the selected MAC address.
+ * Reset the EMAC block.
*
* Parameters:
* priv - A reference to the private driver state structure
*
* Returned Value:
- * OK on success; Negated errno on failure.
+ * None.
*
* Assumptions:
*
****************************************************************************/
-static void sam_macaddress(FAR struct sam_emac_s *priv)
+static void sam_emac_reset(FAR struct sam_emac_s *priv)
{
- FAR struct uip_driver_s *dev = &priv->dev;
uint32_t regval;
- nllvdbg("%s MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->d_ifname,
- dev->d_mac.ether_addr_octet[0], dev->d_mac.ether_addr_octet[1],
- dev->d_mac.ether_addr_octet[2], dev->d_mac.ether_addr_octet[3],
- dev->d_mac.ether_addr_octet[4], dev->d_mac.ether_addr_octet[5]);
+ /* Disable all EMAC interrupts */
- /* Set the MAC address */
+ sam_putreg(priv, SAM_EMAC_IDR, EMAC_INT_ALL);
+
+ /* Reset RX and TX logic */
+
+ sam_rxreset(priv);
+ sam_txreset(priv);
+
+ /* Disable RX, TX, and statistics */
- regval = (uint32_t)dev->d_mac.ether_addr_octet[0] |,
- (uint32_t)dev->d_mac.ether_addr_octet[1] << 8 |,
- (uint32_t)dev->d_mac.ether_addr_octet[2] << 16 |,
- (uint32_t)dev->d_mac.ether_addr_octet[3] << 24 |,
- sam_putreg(priv, SAM_GMAC_SAB1, regval);
+ regval = EMAC_NCR_TE | EMAC_NCR_RE | EMAC_NCR_WESTAT | EMAC_NCR_CLRSTAT;
+ sam_putreg(priv, SAM_EMAC_NCR, regval);
- regval = (uint32_t)dev->d_mac.ether_addr_octet[4] |,
- (uint32_t)dev->d_mac.ether_addr_octet[5] << 8 |,
- sam_putreg(priv, SAM_GMAC_SAT1, regval);
+ /* Disable clocking to the EMAC peripheral */
+
+ sam_emac_disableclk();
}
/****************************************************************************
- * Function: sam_macenable
+ * Function: sam_macaddress
*
* Description:
- * Enable normal MAC operation.
+ * Configure the selected MAC address.
*
* Parameters:
* priv - A reference to the private driver state structure
@@ -2531,40 +2041,35 @@ static void sam_macaddress(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-static int sam_macenable(FAR struct sam_emac_s *priv)
+static void sam_macaddress(FAR struct sam_emac_s *priv)
{
+ FAR struct uip_driver_s *dev = &priv->dev;
uint32_t regval;
- /* Set the MAC address */
-
- sam_macaddress(priv);
-
- /* Enable transmit state machine of the MAC for transmission on the MII */
-#warning Missing logic
-
- /* Flush Transmit FIFO */
-#warning Missing logic
-
- /* Enable receive state machine of the MAC for reception from the MII */
-#warning Missing logic
-
- /* Start DMA transmission */
-#warning Missing logic
+ nllvdbg("%s MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->d_ifname,
+ dev->d_mac.ether_addr_octet[0], dev->d_mac.ether_addr_octet[1],
+ dev->d_mac.ether_addr_octet[2], dev->d_mac.ether_addr_octet[3],
+ dev->d_mac.ether_addr_octet[4], dev->d_mac.ether_addr_octet[5]);
- /* Start DMA reception */
-#warning Missing logic
+ /* Set the MAC address */
- /* Enable Ethernet DMA interrupts */
-#warning Missing logic
+ regval = (uint32_t)dev->d_mac.ether_addr_octet[0] |
+ (uint32_t)dev->d_mac.ether_addr_octet[1] << 8 |
+ (uint32_t)dev->d_mac.ether_addr_octet[2] << 16 |
+ (uint32_t)dev->d_mac.ether_addr_octet[3] << 24;
+ sam_putreg(priv, SAM_EMAC_SA1B, regval);
- return OK;
+ regval = (uint32_t)dev->d_mac.ether_addr_octet[4] |
+ (uint32_t)dev->d_mac.ether_addr_octet[5] << 8;
+ sam_putreg(priv, SAM_EMAC_SA1T, regval);
}
/****************************************************************************
- * Function: sam_ethconfig
+ * Function: sam_emac_configure
*
* Description:
- * Configure the Ethernet interface for DMA operation.
+ * Configure the EMAC interface for DMA operation.
*
* Parameters:
* priv - A reference to the private driver state structure
@@ -2576,60 +2081,86 @@ static int sam_macenable(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-static int sam_ethconfig(FAR struct sam_emac_s *priv)
+static int sam_emac_configure(FAR struct sam_emac_s *priv)
{
- int ret;
+ uint32_t regval;
- /* NOTE: The Ethernet clocks were initialized early in the boot-up
- * sequence in sam_rcc.c.
- */
+ nvdbg("Entry\n");
- /* Reset the Ethernet block */
+ /* Enable clocking to the EMAC peripheral */
- nllvdbg("Reset the Ethernet block\n");
- sam_ethreset(priv);
+ sam_emac_enableclk();
- /* Initialize the PHY */
+ /* Disable TX, RX, interrupts, etc. */
- nllvdbg("Initialize the PHY\n");
- ret = sam_phyinit(priv);
- if (ret < 0)
- {
- return ret;
- }
+ sam_putreg(priv, SAM_EMAC_NCR, 0);
+ sam_putreg(priv, SAM_EMAC_IDR, EMAC_INT_ALL);
- /* Initialize the MAC and DMA */
+ regval = sam_getreg(priv, SAM_EMAC_NCR);
+ regval |= EMAC_NCR_CLRSTAT;
+ sam_putreg(priv, SAM_EMAC_NCR, regval);
- nllvdbg("Initialize the MAC and DMA\n");
- ret = sam_macconfig(priv);
- if (ret < 0)
- {
- return ret;
- }
+ /* Clear all status bits in the receive status register. */
- /* Initialize the free buffer list */
+ regval = (EMAC_RSR_OVR | EMAC_RSR_REC | EMAC_RSR_BNA);
+ sam_putreg(priv, SAM_EMAC_RSR, regval);
- sam_initbuffer(priv);
+ /* Clear all status bits in the transmit status register */
- /* Initialize TX Descriptors list: Chain Mode */
+ regval = (EMAC_TSR_UBR | EMAC_TSR_COL | EMAC_TSR_RLES | EMAC_TSR_BEX |
+ EMAC_TSR_COMP | EMAC_TSR_UND);
+ sam_putreg(priv, SAM_EMAC_TSR, regval);
- sam_txdescinit(priv);
+ /* Clear any pending interrupts */
- /* Initialize RX Descriptors list: Chain Mode */
+ (void)sam_getreg(priv, SAM_EMAC_ISR);
- sam_rxdescinit(priv);
+ /* Enable/disable the copy of data into the buffers, ignore broadcasts.
+ * Don't copy FCS.
+ */
- /* Enable normal MAC operation */
+ regval = sam_getreg(priv, SAM_EMAC_NCFGR);
+ regval |= (EMAC_NCFGR_DRFCS | EMAC_NCFGR_PAE);
- nllvdbg("Enable normal operation\n");
- return sam_macenable(priv);
+#ifdef CONFIG_NET_PROMISCUOUS
+ regval |= EMAC_NCFGR_CAF;
+#else
+ regval &= ~EMAC_NCFGR_CAF;
+#endif
+
+#ifdef CONFIG_SAMA5_EMAC_NBC
+ regval |= EMAC_NCFGR_NBC;
+#else
+ regval &= ~EMAC_NCFGR_NBC;
+#endif
+
+ sam_putreg(priv, SAM_EMAC_NCFGR, regval);
+
+ /* Reset TX and RX */
+
+ sam_rxreset(priv);
+ sam_txreset(priv);
+
+ /* Enable Rx and Tx, plus the stats register. */
+
+ regval = sam_getreg(priv, SAM_EMAC_NCR);
+ regval |= (EMAC_NCR_RE | EMAC_NCR_TE | EMAC_NCR_WESTAT);
+ sam_putreg(priv, SAM_EMAC_NCR, regval);
+
+ /* Setup the interrupts for TX (and errors) */
+
+ regval = (EMAC_INT_RXUBR | EMAC_INT_TUND | EMAC_INT_RLE | EMAC_INT_TXERR |
+ EMAC_INT_TCOMP | EMAC_INT_ROVR | EMAC_INT_HRESP | EMAC_INT_PFR |
+ EMAC_INT_PTZ);
+ sam_putreg(priv, SAM_EMAC_IER, regval);
+ return OK;
}
/****************************************************************************
* Function: sam_buffer_initialize
*
* Description:
- * Allocate alligned TX and RX descriptors and buffers. For the case of
+ * Allocate aligned TX and RX descriptors and buffers. For the case of
* pre-allocated structures, the function degenerates to a few assignements.
*
* Input Parameters:
@@ -2654,54 +2185,105 @@ static int sam_buffer_initialize(struct sam_emac_s *priv)
priv->rxbuffer = g_rxbuffer;
#else
+ size_t allocsize;
+
/* Allocate buffers */
- priv->txdesc = (struct emac_txdesc_s *)
- kmemalign(8, CONFIG_SAMA5_EMAC_NTXBUFFERS * sizeof(struct emac_txdesc_s));
+ allocsize = CONFIG_SAMA5_EMAC_NTXBUFFERS * sizeof(struct emac_txdesc_s);
+ priv->txdesc = (struct emac_txdesc_s *)kmemalign(8, allocsize);
if (!priv->txdesc)
{
nlldbg("ERROR: Failed to allocate TX descriptors\n");
return -ENOMEM;
}
- priv->rxdesc = (struct emac_rxdesc_s *)
- kmemalign(8, CONFIG_SAMA5_EMAC_NRXBUFFERS * sizeof(struct emac_rxdesc_s));
- if (!priv->txdesc)
+ memset(priv->txdesc, 0, allocsize);
+
+ allocsize = CONFIG_SAMA5_EMAC_NRXBUFFERS * sizeof(struct emac_rxdesc_s);
+ priv->rxdesc = (struct emac_rxdesc_s *)kmemalign(8, allocsize);
+ if (!priv->rxdesc)
{
nlldbg("ERROR: Failed to allocate RX descriptors\n");
- kfree(priv->txdesc);
+ sam_buffer_free(priv);
return -ENOMEM;
}
- priv->txbuffer = (uint8_t *)
- kmemalign(8, CONFIG_SAMA5_GMAC_NTXBUFFERS * GMAC_TX_UNITSIZE);
+ memset(priv->rxdesc, 0, allocsize);
+
+ allocsize = CONFIG_SAMA5_EMAC_NTXBUFFERS * EMAC_TX_UNITSIZE;
+ priv->txbuffer = (uint8_t *)kmemalign(8, allocsize);
if (!priv->txbuffer)
{
nlldbg("ERROR: Failed to allocate TX buffer\n");
- kfree(priv->txdesc);
- kfree(priv->rxdesc);
+ sam_buffer_free(priv);
return -ENOMEM;
}
- priv->rxbuffer = (uint8_t *)kmemalign(8, CONFIG_SAMA5_GMAC_NRXBUFFERS * GMAC_RX_UNITSIZE);
+ allocsize = CONFIG_SAMA5_EMAC_NRXBUFFERS * EMAC_RX_UNITSIZE;
+ priv->rxbuffer = (uint8_t *)kmemalign(8, allocsize);
if (!priv->rxbuffer)
{
nlldbg("ERROR: Failed to allocate RX buffer\n");
- kfree(priv->txdesc);
- kfree(priv->rxdesc);
- kfree(priv->rxbuffer);
+ sam_buffer_free(priv);
return -ENOMEM;
}
+
#endif
DEBUGASSERT(((uintptr_t)priv->rxdesc & 7) = 0 &&
((uintptr_t)priv->rxbuffer & 7) = 0 &&
((uintptr_t)priv->txdesc & 7) = 0 &&
- ((uintptr_t)priv->rxbuffer & 7) = 0 &&
+ ((uintptr_t)priv->txbuffer & 7) = 0);
return OK;
}
/****************************************************************************
+ * Function: sam_buffer_free
+ *
+ * Description:
+ * Free aligned TX and RX descriptors and buffers. For the case of
+ * pre-allocated structures, the function does nothing.
+ *
+ * Input Parameters:
+ * priv - The EMAC driver state
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void sam_buffer_free(struct sam_emac_s *priv)
+{
+#ifndef CONFIG_SAMA5_EMAC_PREALLOCATE
+ /* Free allocated buffers */
+
+ if (priv->txdesc)
+ {
+ kfree(priv->txdesc);
+ priv->txdesc = NULL;
+ }
+
+ if (priv->rxdesc)
+ {
+ kfree(priv->rxdesc);
+ priv->rxdesc = NULL;
+ }
+
+ if (priv->txbuffer)
+ {
+ kfree(priv->txbuffer);
+ priv->txbuffer = NULL;
+ }
+
+ if (priv->rxbuffer)
+ {
+ kfree(priv->rxbuffer);
+ priv->rxbuffer = NULL;
+ }
+#endif
+}
+
+/****************************************************************************
* Public Functions
****************************************************************************/
@@ -2724,48 +2306,91 @@ static int sam_buffer_initialize(struct sam_emac_s *priv)
int sam_emac_initialize(void)
{
- struct sam_emac_s *priv;
-
- /* Get the interface structure associated with this interface number. */
-
- priv = &g_emac;
+ struct sam_emac_s *priv = &g_emac;
+ int ret;
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct sam_emac_s));
- priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
- priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
- priv->dev.d_txavail = sam_txavail; /* New TX data callback */
+ priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
+ priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
+ priv->dev.d_txavail = sam_txavail; /* New TX data callback */
#ifdef CONFIG_NET_IGMP
- priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */
- priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */
+ priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */
+ priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */
#endif
priv->dev.d_private = (void*)&g_emac; /* Used to recover private state from dev */
/* Create a watchdog for timing polling for and timing of transmisstions */
- priv->txpoll = wd_create(); /* Create periodic poll timer */
- priv->txtimeout = wd_create(); /* Create TX timeout timer */
+ priv->txpoll = wd_create();
+ if (!priv->txpoll)
+ {
+ ndbg("ERROR: Failed to create periodic poll timer\n");
+ ret = -EAGAIN;
+ goto errout;
+ }
+
+ priv->txtimeout = wd_create(); /* Create TX timeout timer */
+ if (!priv->txpoll)
+ {
+ ndbg("ERROR: Failed to create periodic poll timer\n");
+ ret = -EAGAIN;
+ goto errout_with_txpoll;
+ }
/* Configure PIO pins to support EMAC */
sam_ethgpioconfig(priv);
- /* Attach the IRQ to the driver */
+ /* Allocate buffers */
- if (irq_attach(SAM_IRQ_ETH, sam_interrupt))
+ ret = sam_buffer_initialize(priv);
+ if (ret < 0)
{
- /* We could not attach the ISR to the interrupt */
+ ndbg("ERROR: sam_buffer_initialize failed: %d\n", ret);
+ goto errout_with_txtimeout;
+ }
+
+ /* Attach the IRQ to the driver. It will not be enabled at the AIC until
+ * the interface is in the 'up' state.
+ */
- return -EAGAIN;
+ ret = irq_attach(SAM_IRQ_EMAC, sam_emac_interrupt);
+ if (ret < 0)
+ {
+ ndbg("ERROR: Failed to attach the handler to the IRQ%d\n", SAM_IRQ_EMAC);
+ goto errout_with_buffers;
}
- /* Put the interface in the down state. */
+ /* Enable clocking to the EMAC peripheral (just for sam_ifdown()) */
- sam_ifdown(&priv->dev);
+ sam_emac_enableclk();
+
+ /* Put the interface in the down state (disabling clocking again). */
+
+ ret = sam_ifdown(&priv->dev);
+ if (ret < 0)
+ {
+ ndbg("ERROR: Failed to put the interface in the down state: %d\n", ret);
+ goto errout_with_buffers;
+ }
/* Register the device with the OS so that socket IOCTLs can be performed */
- (void)netdev_register(&priv->dev);
- return OK;
+ ret = netdev_register(&priv->dev);
+ if (ret >= 0)
+ {
+ ndbg("ERROR: netdev_register() failed: %d\n", ret);
+ return ret;
+ }
+
+errout_with_buffers:
+ sam_buffer_free(priv);
+errout_with_txtimeout:
+ wd_delete(priv->txtimeout);
+errout_with_txpoll:
+ wd_delete(priv->txpoll);
+errout:
+ return ret;
}
diff --git a/nuttx/configs/sama5d3x-ek/include/board.h b/nuttx/configs/sama5d3x-ek/include/board.h
index 4a2eeab93..fafb3c639 100644
--- a/nuttx/configs/sama5d3x-ek/include/board.h
+++ b/nuttx/configs/sama5d3x-ek/include/board.h
@@ -191,7 +191,8 @@ void sam_boardinitialize(void);
*
************************************************************************************/
-#if defined(CONFIG_NET) && (defined(CONFIG_SAMA5_EMAC) || defined(CONFIG_SAMA5_GMAC))
+#if defined(CONFIG_NET) && (defined(CONFIG_SAMA5_EMAC) || defined(CONFIG_SAMA5_GMAC)) && \
+ defined(CONFIG_SAMA5_PIOE_IRQ)
xcpt_t sam_phyirq(int intf, xcpt_t irqhandler);
#endif
diff --git a/nuttx/configs/sama5d3x-ek/src/sam_buttons.c b/nuttx/configs/sama5d3x-ek/src/sam_buttons.c
index 2a6de2908..a5770b011 100644
--- a/nuttx/configs/sama5d3x-ek/src/sam_buttons.c
+++ b/nuttx/configs/sama5d3x-ek/src/sam_buttons.c
@@ -151,14 +151,15 @@ xcpt_t up_irqbutton(int id, xcpt_t irqhandler)
/* Get the old button interrupt handler and save the new one */
- oldhandler = *g_irquser1;
- *g_irquser1 = irqhandler;
+ oldhandler = g_irquser1;
+ g_irquser1 = irqhandler;
/* Configure the interrupt */
sam_pioirq(IRQ_USER1);
(void)irq_attach(IRQ_USER1, irqhandler);
sam_pioirqenable(IRQ_USER1);
+ irqrestore(flags);
}
/* Return the old button handler (so that it can be restored) */
diff --git a/nuttx/configs/sama5d3x-ek/src/sam_ethernet.c b/nuttx/configs/sama5d3x-ek/src/sam_ethernet.c
index 54248a3b2..2a72207ce 100644
--- a/nuttx/configs/sama5d3x-ek/src/sam_ethernet.c
+++ b/nuttx/configs/sama5d3x-ek/src/sam_ethernet.c
@@ -47,10 +47,23 @@
#ifdef HAVE_NETWORK
/************************************************************************************
- * Definitions
+ * Pre-processor Definitions
************************************************************************************/
/************************************************************************************
+ * Private Data
+ ************************************************************************************/
+
+#ifdef CONFIG_SAMA5_PIOE_IRQ
+#ifdef CONFIG_SAMA5_EMAC
+static xcpt g_emac_handler;
+#endif
+#ifdef CONFIG_SAMA5_GMAC
+static xcpt g_gmac_handler;
+#endif
+#endif
+
+/************************************************************************************
* Private Functions
************************************************************************************/
@@ -117,6 +130,7 @@ void weak_function sam_netinitialize(void)
*
************************************************************************************/
+#ifdef CONFIG_SAMA5_PIOE_IRQ
xcpt_t sam_phyirq(int intf, xcpt_t irqhandler)
{
irqstate_t flags;
@@ -164,7 +178,9 @@ xcpt_t sam_phyirq(int intf, xcpt_t irqhandler)
/* Return the old button handler (so that it can be restored) */
+ irqrestore(flags);
return oldhandler;
}
+#endif /* CONFIG_SAMA5_PIOE_IRQ */
#endif /* HAVE_NETWORK */
diff --git a/nuttx/configs/sama5d3x-ek/src/sam_usb.c b/nuttx/configs/sama5d3x-ek/src/sam_usb.c
index 2c5b325e9..bbadc788e 100644
--- a/nuttx/configs/sama5d3x-ek/src/sam_usb.c
+++ b/nuttx/configs/sama5d3x-ek/src/sam_usb.c
@@ -90,7 +90,7 @@ static struct usbhost_connection_s *g_ehciconn;
/* Overcurrent interrupt handler */
#if defined(HAVE_USBHOST) && defined(CONFIG_SAMA5_PIOD_IRQ)
-static xcpt_t *g_ochandler;
+static xcpt_t g_ochandler;
#endif
/************************************************************************************
@@ -476,8 +476,8 @@ xcpt_t sam_setup_overcurrent(xcpt_t handler)
/* Get the old button interrupt handler and save the new one */
- oldhandler = *g_ochandler;
- *g_ochandler = handler;
+ oldhandler = g_ochandler;
+ g_ochandler = handler;
/* Configure the interrupt */