From 72b2dafe03e2095ff62690b809b633024bc49fc4 Mon Sep 17 00:00:00 2001 From: aleph Date: Wed, 16 Mar 2011 10:33:22 +0000 Subject: [PATCH] Ethernet driver for SAM3X. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4776 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/cortex-m3/drv/eth_sam3.c | 512 ++++++++++++++++++++++++++++ bertos/cpu/cortex-m3/drv/eth_sam3.h | 208 +++++++++++ bertos/drv/eth.h | 2 +- 3 files changed, 721 insertions(+), 1 deletion(-) create mode 100644 bertos/cpu/cortex-m3/drv/eth_sam3.c create mode 100644 bertos/cpu/cortex-m3/drv/eth_sam3.h diff --git a/bertos/cpu/cortex-m3/drv/eth_sam3.c b/bertos/cpu/cortex-m3/drv/eth_sam3.c new file mode 100644 index 00000000..889a5c1b --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/eth_sam3.c @@ -0,0 +1,512 @@ +/** + * \file + * + * + * \brief EMAC driver for AT91SAM family with Davicom 9161A phy. + * + * \author Daniele Basile + * \author Andrea Righi + * \author Stefano Fedrigo + */ + +#include "cfg/cfg_eth.h" + +#define LOG_LEVEL ETH_LOG_LEVEL +#define LOG_FORMAT ETH_LOG_FORMAT + +#include + +#include +#include +#include +#include + +// TODO: unify includes +//#include +//#include +//#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include "eth_sam3.h" + +#define EMAC_RX_INTS (BV(EMAC_RCOMP) | BV(EMAC_ROVR) | BV(EMAC_RXUBR)) +#define EMAC_TX_INTS (BV(EMAC_TCOMP) | BV(EMAC_TXUBR) | BV(EMAC_RLEX)) + +/* + * MAC address configuration (please change this in your project!). + * + * TODO: make this paramater user-configurable from the Wizard. + */ +const uint8_t mac_addr[] = { 0x00, 0x23, 0x54, 0x6a, 0x77, 0x55 }; + +/* Silent Doxygen bug... */ +#ifndef __doxygen__ +/* + * NOTE: this buffer should be declared as 'volatile' because it is read by the + * hardware. However, this is accessed only via memcpy() that should guarantee + * coherency when copying from/to buffers. + */ +static uint8_t tx_buf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] ALIGNED(8); +static volatile BufDescriptor tx_buf_tab[EMAC_TX_DESCRIPTORS] ALIGNED(8); + +/* + * NOTE: this buffer should be declared as 'volatile' because it is wrote by + * the hardware. However, this is accessed only via memcpy() that should + * guarantee coherency when copying from/to buffers. + */ +static uint8_t rx_buf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] ALIGNED(8); +static volatile BufDescriptor rx_buf_tab[EMAC_RX_DESCRIPTORS] ALIGNED(8); +#endif + +static int tx_buf_idx; +static int tx_buf_offset; +static int rx_buf_idx; + +static Event recv_wait, send_wait; + +static DECLARE_ISR(emac_irqHandler) +{ + /* Read interrupt status and disable interrupts. */ + uint32_t isr = EMAC_ISR; + + kprintf("irq: %x\n", isr); + + /* Receiver interrupt */ + if ((isr & EMAC_RX_INTS)) + { + kprintf("emac: rx %x\n", isr); + if (isr & BV(EMAC_RCOMP)) + event_do(&recv_wait); + EMAC_RSR = EMAC_RX_INTS; + } + /* Transmitter interrupt */ + if (isr & EMAC_TX_INTS) + { + if (isr & BV(EMAC_TCOMP)) + { + kprintf("emac: tcomp\n"); + event_do(&send_wait); + } + if (isr & BV(EMAC_RLEX)) + kprintf("emac: rlex\n"); + EMAC_TSR = EMAC_TX_INTS; + } + //AIC_EOICR = 0; +} + +/* + * \brief Read contents of PHY register. + * + * \param reg PHY register number. + * + * \return Contents of the specified register. + */ +static uint16_t phy_hw_read(reg8_t reg) +{ + // PHY read command. + EMAC_MAN = EMAC_SOF | EMAC_RW_READ | (NIC_PHY_ADDR << EMAC_PHYA_SHIFT) + | ((reg << EMAC_REGA_SHIFT) & EMAC_REGA) | EMAC_CODE; + + // Wait until PHY logic completed. + while (!(EMAC_NSR & BV(EMAC_IDLE))) + cpu_relax(); + + // Get data from PHY maintenance register. + return (uint16_t)(EMAC_MAN & EMAC_DATA); +} + +/* + * \brief Write value to PHY register. + * + * \param reg PHY register number. + * \param val Value to write. + */ +static void phy_hw_write(reg8_t reg, uint16_t val) +{ + // PHY write command. + EMAC_MAN = EMAC_SOF | EMAC_RW_WRITE | (NIC_PHY_ADDR << EMAC_PHYA_SHIFT) + | ((reg << EMAC_REGA_SHIFT) & EMAC_REGA) | EMAC_CODE | val; + + // Wait until PHY logic completed. + while (!(EMAC_NSR & BV(EMAC_IDLE))) + cpu_relax(); +} + +static int emac_reset(void) +{ + uint16_t phy_cr; + + // Enable devices + //PMC_PCER = BV(PIOA_ID); + //PMC_PCER = BV(PIOB_ID); + //PMC_PCER = BV(EMAC_ID); + // TOOD: Implement in sam7x + pmc_periphEnable(PIOA_ID); + pmc_periphEnable(PIOB_ID); + pmc_periphEnable(EMAC_ID); + + // Disable TESTMODE + PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT); +#if CPU_ARM_AT91 + // Disable RMII + PIOB_PUDR = BV(PHY_COL_RMII_BIT); + + // Disable PHY power down. + PIOB_PER = BV(PHY_PWRDN_BIT); + PIOB_OER = BV(PHY_PWRDN_BIT); + PIOB_CODR = BV(PHY_PWRDN_BIT); +#endif + + // Toggle external hardware reset pin. + RSTC_MR = RSTC_KEY | (1 << RSTC_ERSTL_SHIFT) | BV(RSTC_URSTEN); + RSTC_CR = RSTC_KEY | BV(RSTC_EXTRST); + + while ((RSTC_SR & BV(RSTC_NRSTL)) == 0) + cpu_relax(); + + // Configure MII ports. +#if CPU_ARM_AT91 + PIOB_ASR = PHY_MII_PINS; + PIOB_BSR = 0; + PIOB_PDR = PHY_MII_PINS; + // Enable receive and transmit clocks. + EMAC_USRIO = BV(EMAC_CLKEN); +#else + PIO_PERIPH_SEL(PIOB_BASE, PHY_MII_PINS, PIO_PERIPH_A); + PIOB_PDR = PHY_MII_PINS; + // Enable receive, transmit clocks and RMII mode. + EMAC_USRIO = BV(EMAC_CLKEN) | BV(EMAC_RMII); +#endif + + // Enable management port. + EMAC_NCR |= BV(EMAC_MPE); + EMAC_NCFGR |= EMAC_CLK_HCLK_32; + + // Set local MAC address. + EMAC_SA1L = (mac_addr[3] << 24) | (mac_addr[2] << 16) | + (mac_addr[1] << 8) | mac_addr[0]; + EMAC_SA1H = (mac_addr[5] << 8) | mac_addr[4]; + + // Wait for PHY ready + timer_delay(255); + + // Clear MII isolate. + phy_hw_read(NIC_PHY_BMCR); + phy_cr = phy_hw_read(NIC_PHY_BMCR); + + phy_cr &= ~NIC_PHY_BMCR_ISOLATE; + phy_hw_write(NIC_PHY_BMCR, phy_cr); + + phy_cr = phy_hw_read(NIC_PHY_BMCR); + + LOG_INFO("%s: PHY ID %#04x %#04x\n", + __func__, + phy_hw_read(NIC_PHY_ID1), phy_hw_read(NIC_PHY_ID2)); + + // Wait for auto negotiation completed. + phy_hw_read(NIC_PHY_BMSR); + for (;;) + { + if (phy_hw_read(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) + break; + cpu_relax(); + } + + // Disable management port. + EMAC_NCR &= ~BV(EMAC_MPE); + + return 0; +} + +static int emac_start(void) +{ + uint32_t addr; + int i; + + for (i = 0; i < EMAC_RX_DESCRIPTORS; i++) + { + addr = (uint32_t)(rx_buf + (i * EMAC_RX_BUFSIZ)); + rx_buf_tab[i].addr = addr & BUF_ADDRMASK; + } + rx_buf_tab[EMAC_RX_DESCRIPTORS - 1].addr |= RXBUF_WRAP; + + for (i = 0; i < EMAC_TX_DESCRIPTORS; i++) + { + addr = (uint32_t)(tx_buf + (i * EMAC_TX_BUFSIZ)); + tx_buf_tab[i].addr = addr & BUF_ADDRMASK; + tx_buf_tab[i].stat = TXS_USED; + } + tx_buf_tab[EMAC_TX_DESCRIPTORS - 1].stat = TXS_USED | TXS_WRAP; + + /* Tell the EMAC where to find the descriptors. */ + EMAC_RBQP = (uint32_t)rx_buf_tab; + EMAC_TBQP = (uint32_t)tx_buf_tab; + + /* Clear receiver status. */ + EMAC_RSR = BV(EMAC_OVR) | BV(EMAC_REC) | BV(EMAC_BNA); + + /* Copy all frames and discard FCS. */ + EMAC_NCFGR |= BV(EMAC_CAF) | BV(EMAC_DRFCS); + + /* Enable receiver, transmitter and statistics. */ + EMAC_NCR |= BV(EMAC_TE) | BV(EMAC_RE) | BV(EMAC_WESTAT); + + return 0; +} + +ssize_t eth_putFrame(const uint8_t *buf, size_t len) +{ + size_t wr_len; + + if (UNLIKELY(!len)) + return -1; + ASSERT(len <= sizeof(tx_buf)); + + /* Check if the transmit buffer is available */ + while (!(tx_buf_tab[tx_buf_idx].stat & TXS_USED)) + event_wait(&send_wait); + + /* Copy the data into the buffer and prepare descriptor */ + wr_len = MIN(len, (size_t)EMAC_TX_BUFSIZ - tx_buf_offset); + memcpy((uint8_t *)tx_buf_tab[tx_buf_idx].addr + tx_buf_offset, + buf, wr_len); + tx_buf_offset += wr_len; + + return wr_len; +} + +void eth_sendFrame(void) +{ + tx_buf_tab[tx_buf_idx].stat = (tx_buf_offset & TXS_LENGTH_FRAME) | + TXS_LAST_BUFF | + ((tx_buf_idx == EMAC_TX_DESCRIPTORS - 1) ? TXS_WRAP : 0); + EMAC_NCR |= BV(EMAC_TSTART); + + tx_buf_offset = 0; + if (++tx_buf_idx >= EMAC_TX_DESCRIPTORS) + tx_buf_idx = 0; +} + +ssize_t eth_send(const uint8_t *buf, size_t len) + { + if (UNLIKELY(!len)) + return -1; + + len = eth_putFrame(buf, len); + eth_sendFrame(); + + return len; +} + +static void eth_buf_realign(int idx) +{ + /* Empty buffer found. Realign. */ + do { + rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP; + if (++rx_buf_idx >= EMAC_RX_BUFFERS) + rx_buf_idx = 0; + } while (idx != rx_buf_idx); +} + +static size_t __eth_getFrameLen(void) +{ + int idx, n = EMAC_RX_BUFFERS; + +skip: + /* Skip empty buffers */ + while ((n > 0) && !(rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP)) + { + if (++rx_buf_idx >= EMAC_RX_BUFFERS) + rx_buf_idx = 0; + n--; + } + if (UNLIKELY(!n)) + { + LOG_INFO("no frame found\n"); + return 0; + } + /* Search the start of frame and cleanup fragments */ + while ((n > 0) && (rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP) && + !(rx_buf_tab[rx_buf_idx].stat & RXS_SOF)) + { + rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP; + if (++rx_buf_idx >= EMAC_RX_BUFFERS) + rx_buf_idx = 0; + n--; + } + if (UNLIKELY(!n)) + { + LOG_INFO("no SOF found\n"); + return 0; + } + /* Search end of frame to evaluate the total frame size */ + idx = rx_buf_idx; +restart: + while (n > 0) + { + if (UNLIKELY(!(rx_buf_tab[idx].addr & RXBUF_OWNERSHIP))) + { + /* Empty buffer found. Realign. */ + eth_buf_realign(idx); + goto skip; + } + if (rx_buf_tab[idx].stat & RXS_EOF) + return rx_buf_tab[idx].stat & RXS_LENGTH_FRAME; + if (UNLIKELY((idx != rx_buf_idx) && + (rx_buf_tab[idx].stat & RXS_SOF))) + { + /* Another start of frame found. Realign. */ + eth_buf_realign(idx); + goto restart; + } + if (++idx >= EMAC_RX_BUFFERS) + idx = 0; + n--; + } + LOG_INFO("no EOF found\n"); + return 0; +} + +size_t eth_getFrameLen(void) +{ + size_t len; + + /* Check if there is at least one available frame in the buffer */ + while (1) + { + len = __eth_getFrameLen(); + if (LIKELY(len)) + break; + /* Wait for RX interrupt */ + event_wait(&recv_wait); + } + return len; +} + +ssize_t eth_getFrame(uint8_t *buf, size_t len) +{ + uint8_t *addr; + size_t rd_len = 0; + + if (UNLIKELY(!len)) + return -1; + ASSERT(len <= sizeof(rx_buf)); + + /* Copy data from the RX buffer */ + addr = (uint8_t *)(rx_buf_tab[rx_buf_idx].addr & BUF_ADDRMASK); + if (addr + len > &rx_buf[countof(rx_buf)]) + { + size_t count = &rx_buf[countof(rx_buf)] - addr; + + memcpy(buf, addr, count); + memcpy(buf + count, rx_buf, len - count); + } + else + { + memcpy(buf, addr, len); + } + /* Update descriptors */ + while (rd_len < len) + { + if (len - rd_len >= EMAC_RX_BUFSIZ) + rd_len += EMAC_RX_BUFSIZ; + else + rd_len += len - rd_len; + if (UNLIKELY(!(rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP))) + { + LOG_INFO("bad frame found\n"); + return 0; + } + rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP; + if (++rx_buf_idx >= EMAC_RX_DESCRIPTORS) + rx_buf_idx = 0; + } + + return rd_len; +} + +ssize_t eth_recv(uint8_t *buf, size_t len) +{ + if (UNLIKELY(!len)) + return -1; + len = MIN(len, eth_getFrameLen()); + return len ? eth_getFrame(buf, len) : 0; +} + +int eth_init() +{ + cpu_flags_t flags; + + emac_reset(); + emac_start(); + + event_initGeneric(&recv_wait); + event_initGeneric(&send_wait); + + // Register interrupt vector + IRQ_SAVE_DISABLE(flags); + + /* Disable all emac interrupts */ + EMAC_IDR = 0xFFFFFFFF; + +#if CPU_ARM_AT91 + // TODO: define sysirq_set... + /* Set the vector. */ + AIC_SVR(EMAC_ID) = emac_irqHandler; + /* Initialize to edge triggered with defined priority. */ + AIC_SMR(EMAC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED; + /* Clear pending interrupt */ + AIC_ICCR = BV(EMAC_ID); + /* Enable the system IRQ */ + AIC_IECR = BV(EMAC_ID); +#else + sysirq_setHandler(INT_EMAC, emac_irqHandler); +#endif + + /* Enable interrupts */ + EMAC_IER = EMAC_RX_INTS | EMAC_TX_INTS; + + IRQ_RESTORE(flags); + + return 0; +} diff --git a/bertos/cpu/cortex-m3/drv/eth_sam3.h b/bertos/cpu/cortex-m3/drv/eth_sam3.h new file mode 100644 index 00000000..f733df9a --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/eth_sam3.h @@ -0,0 +1,208 @@ +/** + * \file + * + * + * \brief EMAC driver for AT91SAM family with Davicom 9161A phy, interface. + * + * \author Daniele Basile + * \author Andrea Righi + * \author Stefano Fedrigo + */ + +#ifndef ETH_SAM3_H +#define ETH_SAM3_H + +// Settings and definition for DAVICOM 9161A +// \{ +#define NIC_PHY_ADDR 31 + +//Registry definition +#define NIC_PHY_BMCR 0x00 // Basic mode control register. +#define NIC_PHY_BMCR_COLTEST 0x0080 // Collision test. +#define NIC_PHY_BMCR_FDUPLEX 0x0100 // Full duplex mode. +#define NIC_PHY_BMCR_ANEGSTART 0x0200 // Restart auto negotiation. +#define NIC_PHY_BMCR_ISOLATE 0x0400 // Isolate from MII. +#define NIC_PHY_BMCR_PWRDN 0x0800 // Power-down. +#define NIC_PHY_BMCR_ANEGENA 0x1000 // Enable auto negotiation. +#define NIC_PHY_BMCR_100MBPS 0x2000 // Select 100 Mbps. +#define NIC_PHY_BMCR_LOOPBACK 0x4000 // Enable loopback mode. +#define NIC_PHY_BMCR_RESET 0x8000 // Software reset. + +#define NIC_PHY_BMSR 0x01 // Basic mode status register. +#define NIC_PHY_BMSR_ANCOMPL 0x0020 // Auto negotiation complete. +#define NIC_PHY_BMSR_ANEGCAPABLE 0x0008 // Able to do auto-negotiation +#define NIC_PHY_BMSR_LINKSTAT 0x0004 // Link status. + +#define NIC_PHY_ID1 0x02 // PHY identifier register 1. +#define NIC_PHY_ID2 0x03 // PHY identifier register 2. +#define NIC_PHY_ANAR 0x04 // Auto negotiation advertisement register. +#define NIC_PHY_ANLPAR 0x05 // Auto negotiation link partner availability register. +#define NIC_PHY_ANER 0x06 // Auto negotiation expansion register. + +#if CPU_ARM_AT91 + +/* + * Pin definition for DAVICOM 9161A. + * See schematics for AT91SAM7X-EK evalution board. + */ +// All pins in port B +#define PHY_TXCLK_ISOLATE_BIT 0 +#define PHY_REFCLK_XT2_BIT 0 +#define PHY_TXEN_BIT 1 +#define PHY_TXD0_BIT 2 +#define PHY_TXD1_BIT 3 +#define PHY_CRS_AD4_BIT 4 +#define PHY_RXD0_AD0_BIT 5 +#define PHY_RXD1_AD1_BIT 6 +#define PHY_RXER_RXD4_RPTR_BIT 7 +#define PHY_MDC_BIT 8 +#define PHY_MDIO_BIT 9 +#define PHY_TXD2_BIT 10 +#define PHY_TXD3_BIT 11 +#define PHY_TXER_TXD4_BIT 12 +#define PHY_RXD2_AD2_BIT 13 +#define PHY_RXD3_AD3_BIT 14 +#define PHY_RXDV_TESTMODE_BIT 15 +#define PHY_COL_RMII_BIT 16 +#define PHY_RXCLK_10BTSER_BIT 17 +#define PHY_PWRDN_BIT 18 +#define PHY_MDINTR_BIT 26 + +#define PHY_MII_PINS \ + BV(PHY_REFCLK_XT2_BIT) \ + | BV(PHY_TXEN_BIT) \ + | BV(PHY_TXD0_BIT) \ + | BV(PHY_TXD1_BIT) \ + | BV(PHY_CRS_AD4_BIT) \ + | BV(PHY_RXD0_AD0_BIT) \ + | BV(PHY_RXD1_AD1_BIT) \ + | BV(PHY_RXER_RXD4_RPTR_BIT) \ + | BV(PHY_MDC_BIT) \ + | BV(PHY_MDIO_BIT) \ + | BV(PHY_TXD2_BIT) \ + | BV(PHY_TXD3_BIT) \ + | BV(PHY_TXER_TXD4_BIT) \ + | BV(PHY_RXD2_AD2_BIT) \ + | BV(PHY_RXD3_AD3_BIT) \ + | BV(PHY_RXDV_TESTMODE_BIT) \ + | BV(PHY_COL_RMII_BIT) \ + | BV(PHY_RXCLK_10BTSER_BIT) + +#else + +/* + * Pin definition for DAVICOM 9161A. + * See schematics for SAM3X-EK evalution board. + */ +// Port B +#define PHY_TXCLK_ISOLATE_BIT 0 +#define PHY_REFCLK_XT2_BIT 0 +#define PHY_TXEN_BIT 1 +#define PHY_TXD0_BIT 2 +#define PHY_TXD1_BIT 3 +#define PHY_RXDV_TESTMODE_BIT 4 +#define PHY_RXD0_AD0_BIT 5 +#define PHY_RXD1_AD1_BIT 6 +#define PHY_RXER_RXD4_RPTR_BIT 7 +#define PHY_MDC_BIT 8 +#define PHY_MDIO_BIT 9 +// Port A +#define PHY_MDINTR_BIT 5 + +#define PHY_MII_PINS \ + BV(PHY_REFCLK_XT2_BIT) \ + | BV(PHY_TXEN_BIT) \ + | BV(PHY_TXD0_BIT) \ + | BV(PHY_TXD1_BIT) \ + | BV(PHY_RXDV_TESTMODE_BIT) \ + | BV(PHY_RXD0_AD0_BIT) \ + | BV(PHY_RXD1_AD1_BIT) \ + | BV(PHY_RXER_RXD4_RPTR_BIT) \ + | BV(PHY_MDC_BIT) \ + | BV(PHY_MDIO_BIT) + +#endif /* CPU_ARM_AT91 */ +// \} + + +#define EMAC_TX_BUFSIZ 1518 //!!! Don't change this +#define EMAC_TX_BUFFERS 1 //!!! Don't change this +#define EMAC_TX_DESCRIPTORS EMAC_TX_BUFFERS + +#define EMAC_RX_BUFFERS 32 //!!! Don't change this +#define EMAC_RX_BUFSIZ 128 //!!! Don't change this +#define EMAC_RX_DESCRIPTORS EMAC_RX_BUFFERS + +// Flag to manage local tx buffer +#define TXS_USED 0x80000000 //Used buffer. +#define TXS_WRAP 0x40000000 //Last descriptor. +#define TXS_ERROR 0x20000000 //Retry limit exceeded. +#define TXS_UNDERRUN 0x10000000 //Transmit underrun. +#define TXS_NO_BUFFER 0x08000000 //Buffer exhausted. +#define TXS_NO_CRC 0x00010000 //CRC not appended. +#define TXS_LAST_BUFF 0x00008000 //Last buffer of frame. +#define TXS_LENGTH_FRAME 0x000007FF // Length of frame including FCS. + +// Flag to manage local rx buffer +#define RXBUF_OWNERSHIP 0x00000001 +#define RXBUF_WRAP 0x00000002 + +#define BUF_ADDRMASK 0xFFFFFFFC + +#define RXS_BROADCAST_ADDR 0x80000000 // Broadcast address detected. +#define RXS_MULTICAST_HASH 0x40000000 // Multicast hash match. +#define RXS_UNICAST_HASH 0x20000000 // Unicast hash match. +#define RXS_EXTERNAL_ADDR 0x10000000 // External address match. +#define RXS_SA1_ADDR 0x04000000 // Specific address register 1 match. +#define RXS_SA2_ADDR 0x02000000 // Specific address register 2 match. +#define RXS_SA3_ADDR 0x01000000 // Specific address register 3 match. +#define RXS_SA4_ADDR 0x00800000 // Specific address register 4 match. +#define RXS_TYPE_ID 0x00400000 // Type ID match. +#define RXS_VLAN_TAG 0x00200000 // VLAN tag detected. +#define RXS_PRIORITY_TAG 0x00100000 // Priority tag detected. +#define RXS_VLAN_PRIORITY 0x000E0000 // VLAN priority. +#define RXS_CFI_IND 0x00010000 // Concatenation format indicator. +#define RXS_EOF 0x00008000 // End of frame. +#define RXS_SOF 0x00004000 // Start of frame. +#define RXS_RBF_OFFSET 0x00003000 // Receive buffer offset mask. +#define RXS_LENGTH_FRAME 0x000007FF // Length of frame including FCS. + +#define EMAC_RSR_BITS (BV(EMAC_BNA) | BV(EMAC_REC) | BV(EMAC_OVR)) +#define EMAC_TSR_BITS (BV(EMAC_UBR) | BV(EMAC_COL) | BV(EMAC_RLES) | \ + BV(EMAC_BEX) | BV(EMAC_COMP) | BV(EMAC_UND)) + +typedef struct BufDescriptor +{ + volatile uint32_t addr; + volatile uint32_t stat; +} BufDescriptor; + +#endif /* ETH_SAM3_H */ diff --git a/bertos/drv/eth.h b/bertos/drv/eth.h index 2d29ba7a..ff80c95c 100644 --- a/bertos/drv/eth.h +++ b/bertos/drv/eth.h @@ -36,7 +36,7 @@ * * $WIZ$ module_name = "eth" * $WIZ$ module_configuration = "bertos/cfg/cfg_eth.h" - * $WIZ$ module_supports = "at91sam7x" + * $WIZ$ module_supports = "at91sam7x or sam3x" */ #ifndef DRV_ETH_H -- 2.25.1