Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sama5d2_eth.c Source File

sama5d2_eth.c

Go to the documentation of this file.
00001 /**
00002  * @file sama5d2_eth.c
00003  * @brief SAMA5D2 Ethernet MAC controller
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <limits.h>
00034 #include "chip.h"
00035 #include "peripherals/aic.h"
00036 #include "peripherals/pio.h"
00037 #include "core/net.h"
00038 #include "drivers/sama5d2_eth.h"
00039 #include "debug.h"
00040 
00041 //Underlying network interface
00042 static NetInterface *nicDriverInterface;
00043 
00044 //IAR EWARM compiler?
00045 #if defined(__ICCARM__)
00046 
00047 //TX buffer
00048 #pragma data_alignment = 8
00049 #pragma location = ".region_ddr_nocache"
00050 static uint8_t txBuffer[SAMA5D2_ETH_TX_BUFFER_COUNT][SAMA5D2_ETH_TX_BUFFER_SIZE];
00051 //RX buffer
00052 #pragma data_alignment = 8
00053 #pragma location = ".region_ddr_nocache"
00054 static uint8_t rxBuffer[SAMA5D2_ETH_RX_BUFFER_COUNT][SAMA5D2_ETH_RX_BUFFER_SIZE];
00055 //TX buffer descriptors
00056 #pragma data_alignment = 4
00057 #pragma location = ".region_ddr_nocache"
00058 static Sama5d2TxBufferDesc txBufferDesc[SAMA5D2_ETH_TX_BUFFER_COUNT];
00059 //RX buffer descriptors
00060 #pragma data_alignment = 4
00061 #pragma location = ".region_ddr_nocache"
00062 static Sama5d2RxBufferDesc rxBufferDesc[SAMA5D2_ETH_RX_BUFFER_COUNT];
00063 
00064 //Dummy TX buffer
00065 #pragma data_alignment = 8
00066 #pragma location = ".region_ddr_nocache"
00067 static uint8_t dummyTxBuffer[SAMA5D2_ETH_DUMMY_BUFFER_COUNT][SAMA5D2_ETH_DUMMY_BUFFER_SIZE];
00068 //Dummy RX buffer
00069 #pragma data_alignment = 8
00070 #pragma location = ".region_ddr_nocache"
00071 static uint8_t dummyRxBuffer[SAMA5D2_ETH_DUMMY_BUFFER_COUNT][SAMA5D2_ETH_DUMMY_BUFFER_SIZE];
00072 //Dummy TX buffer descriptors
00073 #pragma data_alignment = 4
00074 #pragma location = ".region_ddr_nocache"
00075 static Sama5d2TxBufferDesc dummyTxBufferDesc[SAMA5D2_ETH_DUMMY_BUFFER_COUNT];
00076 //Dummy RX buffer descriptors
00077 #pragma data_alignment = 4
00078 #pragma location = ".region_ddr_nocache"
00079 static Sama5d2RxBufferDesc dummyRxBufferDesc[SAMA5D2_ETH_DUMMY_BUFFER_COUNT];
00080 
00081 //GCC compiler?
00082 #else
00083 
00084 //TX buffer
00085 static uint8_t txBuffer[SAMA5D2_ETH_TX_BUFFER_COUNT][SAMA5D2_ETH_TX_BUFFER_SIZE]
00086    __attribute__((aligned(8), __section__(".region_ddr_nocache")));
00087 //RX buffer
00088 static uint8_t rxBuffer[SAMA5D2_ETH_RX_BUFFER_COUNT][SAMA5D2_ETH_RX_BUFFER_SIZE]
00089    __attribute__((aligned(8), __section__(".region_ddr_nocache")));
00090 //TX buffer descriptors
00091 static Sama5d2TxBufferDesc txBufferDesc[SAMA5D2_ETH_TX_BUFFER_COUNT]
00092    __attribute__((aligned(4), __section__(".region_ddr_nocache")));
00093 //RX buffer descriptors
00094 static Sama5d2RxBufferDesc rxBufferDesc[SAMA5D2_ETH_RX_BUFFER_COUNT]
00095    __attribute__((aligned(4), __section__(".region_ddr_nocache")));
00096 
00097 //Dummy TX buffer
00098 static uint8_t dummyTxBuffer[SAMA5D2_ETH_DUMMY_BUFFER_COUNT][SAMA5D2_ETH_DUMMY_BUFFER_SIZE]
00099    __attribute__((aligned(8), __section__(".region_ddr_nocache")));
00100 //Dummy RX buffer
00101 static uint8_t dummyRxBuffer[SAMA5D2_ETH_DUMMY_BUFFER_COUNT][SAMA5D2_ETH_DUMMY_BUFFER_SIZE]
00102    __attribute__((aligned(8), __section__(".region_ddr_nocache")));
00103 //Dummy TX buffer descriptors
00104 static Sama5d2TxBufferDesc dummyTxBufferDesc[SAMA5D2_ETH_DUMMY_BUFFER_COUNT]
00105    __attribute__((aligned(4), __section__(".region_ddr_nocache")));
00106 //Dummy RX buffer descriptors
00107 static Sama5d2RxBufferDesc dummyRxBufferDesc[SAMA5D2_ETH_DUMMY_BUFFER_COUNT]
00108    __attribute__((aligned(4), __section__(".region_ddr_nocache")));
00109 
00110 #endif
00111 
00112 //TX buffer index
00113 static uint_t txBufferIndex;
00114 //RX buffer index
00115 static uint_t rxBufferIndex;
00116 
00117 
00118 /**
00119  * @brief SAMA5D2 Ethernet MAC driver
00120  **/
00121 
00122 const NicDriver sama5d2EthDriver =
00123 {
00124    NIC_TYPE_ETHERNET,
00125    ETH_MTU,
00126    sama5d2EthInit,
00127    sama5d2EthTick,
00128    sama5d2EthEnableIrq,
00129    sama5d2EthDisableIrq,
00130    sama5d2EthEventHandler,
00131    sama5d2EthSendPacket,
00132    sama5d2EthSetMulticastFilter,
00133    sama5d2EthUpdateMacConfig,
00134    sama5d2EthWritePhyReg,
00135    sama5d2EthReadPhyReg,
00136    TRUE,
00137    TRUE,
00138    TRUE,
00139    FALSE
00140 };
00141 
00142 
00143 /**
00144  * @brief SAMA5D2 Ethernet MAC initialization
00145  * @param[in] interface Underlying network interface
00146  * @return Error code
00147  **/
00148 
00149 error_t sama5d2EthInit(NetInterface *interface)
00150 {
00151    error_t error;
00152    volatile uint32_t status;
00153 
00154    //Debug message
00155    TRACE_INFO("Initializing SAMA5D2 Ethernet MAC...\r\n");
00156 
00157    //Save underlying network interface
00158    nicDriverInterface = interface;
00159 
00160    //Enable GMAC peripheral clock
00161    PMC->PMC_PCER0 = (1 << ID_GMAC0);
00162 
00163    //GPIO configuration
00164    sama5d2EthInitGpio(interface);
00165 
00166    //Configure MDC clock speed
00167    GMAC0->GMAC_NCFGR = GMAC_NCFGR_CLK_MCK_96;
00168    //Enable management port (MDC and MDIO)
00169    GMAC0->GMAC_NCR |= GMAC_NCR_MPE;
00170 
00171    //PHY transceiver initialization
00172    error = interface->phyDriver->init(interface);
00173    //Failed to initialize PHY transceiver?
00174    if(error)
00175       return error;
00176 
00177    //Set the MAC address
00178    GMAC0->GMAC_SA[0].GMAC_SAB = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
00179    GMAC0->GMAC_SA[0].GMAC_SAT = interface->macAddr.w[2];
00180 
00181    //Configure the receive filter
00182    GMAC0->GMAC_NCFGR |= GMAC_NCFGR_UNIHEN | GMAC_NCFGR_MTIHEN;
00183 
00184    //DMA configuration
00185    GMAC0->GMAC_DCFGR = GMAC_DCFGR_DRBS(SAMA5D2_ETH_RX_BUFFER_SIZE / 64) |
00186       GMAC_DCFGR_TXPBMS | GMAC_DCFGR_RXBMS_FULL | GMAC_DCFGR_FBLDO_INCR4;
00187 
00188    GMAC0->GMAC_RBSRPQ[0] = GMAC_RBSRPQ_RBS(SAMA5D2_ETH_DUMMY_BUFFER_SIZE / 64);
00189    GMAC0->GMAC_RBSRPQ[1] = GMAC_RBSRPQ_RBS(SAMA5D2_ETH_DUMMY_BUFFER_SIZE / 64);
00190 
00191    //Initialize hash table
00192    GMAC0->GMAC_HRB = 0;
00193    GMAC0->GMAC_HRT = 0;
00194 
00195    //Initialize buffer descriptors
00196    sama5d2EthInitBufferDesc(interface);
00197 
00198    //Clear transmit status register
00199    GMAC0->GMAC_TSR = GMAC_TSR_HRESP | GMAC_TSR_TXCOMP | GMAC_TSR_TFC |
00200       GMAC_TSR_TXGO | GMAC_TSR_RLE | GMAC_TSR_COL | GMAC_TSR_UBR;
00201    //Clear receive status register
00202    GMAC0->GMAC_RSR = GMAC_RSR_HNO | GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA;
00203 
00204    //First disable all GMAC interrupts
00205    GMAC0->GMAC_IDR = 0xFFFFFFFF;
00206    GMAC0->GMAC_IDRPQ[0] = 0xFFFFFFFF;
00207    GMAC0->GMAC_IDRPQ[1] = 0xFFFFFFFF;
00208 
00209    //Only the desired ones are enabled
00210    GMAC0->GMAC_IER = GMAC_IER_HRESP | GMAC_IER_ROVR | GMAC_IER_TCOMP | GMAC_IER_TFC |
00211       GMAC_IER_RLEX | GMAC_IER_TUR | GMAC_IER_RXUBR | GMAC_IER_RCOMP;
00212 
00213    //Read GMAC ISR register to clear any pending interrupt
00214    status = GMAC0->GMAC_ISR;
00215 
00216    //Register interrupt handler
00217    aic_set_source_vector(ID_GMAC0, sama5d2EthIrqHandler);
00218 
00219    //Configure interrupt priority
00220    aic_configure(ID_GMAC0, AIC_SMR_SRCTYPE_INT_LEVEL_SENSITIVE |
00221       AIC_SMR_PRIOR(SAMA5D2_ETH_IRQ_PRIORITY));
00222 
00223    //Enable the GMAC to transmit and receive data
00224    GMAC0->GMAC_NCR |= GMAC_NCR_TXEN | GMAC_NCR_RXEN;
00225 
00226    //Accept any packets from the upper layer
00227    osSetEvent(&interface->nicTxEvent);
00228 
00229    //Successful initialization
00230    return NO_ERROR;
00231 }
00232 
00233 
00234 //SAMA5D2-Xplained-Ultra evaluation board?
00235 #if defined(CONFIG_BOARD_SAMA5D2_XPLAINED)
00236 
00237 /**
00238  * @brief GPIO configuration
00239  * @param[in] interface Underlying network interface
00240  **/
00241 
00242 void sama5d2EthInitGpio(NetInterface *interface)
00243 {
00244    struct _pin rmiiPins[] = PINS_GMAC_RMII_IOS3;
00245 
00246    //Configure RMII pins
00247    pio_configure(rmiiPins, arraysize(rmiiPins));
00248 
00249    //Select RMII operation mode
00250    GMAC0->GMAC_UR = GMAC_UR_RMII;
00251 }
00252 
00253 #endif
00254 
00255 
00256 /**
00257  * @brief Initialize buffer descriptors
00258  * @param[in] interface Underlying network interface
00259  **/
00260 
00261 void sama5d2EthInitBufferDesc(NetInterface *interface)
00262 {
00263    uint_t i;
00264    uint32_t address;
00265 
00266    //Initialize TX buffer descriptors
00267    for(i = 0; i < SAMA5D2_ETH_TX_BUFFER_COUNT; i++)
00268    {
00269       //Calculate the address of the current TX buffer
00270       address = (uint32_t) txBuffer[i];
00271       //Write the address to the descriptor entry
00272       txBufferDesc[i].address = address;
00273       //Initialize status field
00274       txBufferDesc[i].status = GMAC_TX_USED;
00275    }
00276 
00277    //Mark the last descriptor entry with the wrap flag
00278    txBufferDesc[i - 1].status |= GMAC_TX_WRAP;
00279    //Initialize TX buffer index
00280    txBufferIndex = 0;
00281 
00282    //Initialize RX buffer descriptors
00283    for(i = 0; i < SAMA5D2_ETH_RX_BUFFER_COUNT; i++)
00284    {
00285       //Calculate the address of the current RX buffer
00286       address = (uint32_t) rxBuffer[i];
00287       //Write the address to the descriptor entry
00288       rxBufferDesc[i].address = address & GMAC_RX_ADDRESS;
00289       //Clear status field
00290       rxBufferDesc[i].status = 0;
00291    }
00292 
00293    //Mark the last descriptor entry with the wrap flag
00294    rxBufferDesc[i - 1].address |= GMAC_RX_WRAP;
00295    //Initialize RX buffer index
00296    rxBufferIndex = 0;
00297 
00298    //Initialize dummy TX buffer descriptors
00299    for(i = 0; i < SAMA5D2_ETH_DUMMY_BUFFER_COUNT; i++)
00300    {
00301       //Calculate the address of the current TX buffer
00302       address = (uint32_t) dummyTxBuffer[i];
00303       //Write the address to the descriptor entry
00304       dummyTxBufferDesc[i].address = address;
00305       //Initialize status field
00306       dummyTxBufferDesc[i].status = GMAC_TX_USED;
00307    }
00308 
00309    //Mark the last descriptor entry with the wrap flag
00310    dummyTxBufferDesc[i - 1].status |= GMAC_TX_WRAP;
00311 
00312    //Initialize dummy RX buffer descriptors
00313    for(i = 0; i < SAMA5D2_ETH_DUMMY_BUFFER_COUNT; i++)
00314    {
00315       //Calculate the address of the current RX buffer
00316       address = (uint32_t) dummyRxBuffer[i];
00317       //Write the address to the descriptor entry
00318       dummyRxBufferDesc[i].address = (address & GMAC_RX_ADDRESS) | GMAC_RX_OWNERSHIP;
00319       //Clear status field
00320       dummyRxBufferDesc[i].status = 0;
00321    }
00322 
00323    //Mark the last descriptor entry with the wrap flag
00324    dummyRxBufferDesc[i - 1].address |= GMAC_RX_WRAP;
00325 
00326    //Start location of the TX descriptor list
00327    GMAC0->GMAC_TBQB = (uint32_t) txBufferDesc;
00328    GMAC0->GMAC_TBQBAPQ[0] = (uint32_t) dummyTxBufferDesc;
00329    GMAC0->GMAC_TBQBAPQ[1] = (uint32_t) dummyTxBufferDesc;
00330 
00331    //Start location of the RX descriptor list
00332    GMAC0->GMAC_RBQB = (uint32_t) rxBufferDesc;
00333    GMAC0->GMAC_RBQBAPQ[0] = (uint32_t) dummyRxBufferDesc;
00334    GMAC0->GMAC_RBQBAPQ[1] = (uint32_t) dummyRxBufferDesc;
00335 }
00336 
00337 
00338 /**
00339  * @brief SAMA5D2 Ethernet MAC timer handler
00340  *
00341  * This routine is periodically called by the TCP/IP stack to
00342  * handle periodic operations such as polling the link state
00343  *
00344  * @param[in] interface Underlying network interface
00345  **/
00346 
00347 void sama5d2EthTick(NetInterface *interface)
00348 {
00349    //Handle periodic operations
00350    interface->phyDriver->tick(interface);
00351 }
00352 
00353 
00354 /**
00355  * @brief Enable interrupts
00356  * @param[in] interface Underlying network interface
00357  **/
00358 
00359 void sama5d2EthEnableIrq(NetInterface *interface)
00360 {
00361    //Enable Ethernet MAC interrupts
00362    aic_enable(ID_GMAC0);
00363    //Enable Ethernet PHY interrupts
00364    interface->phyDriver->enableIrq(interface);
00365 }
00366 
00367 
00368 /**
00369  * @brief Disable interrupts
00370  * @param[in] interface Underlying network interface
00371  **/
00372 
00373 void sama5d2EthDisableIrq(NetInterface *interface)
00374 {
00375    //Disable Ethernet MAC interrupts
00376    aic_disable(ID_GMAC0);
00377    //Disable Ethernet PHY interrupts
00378    interface->phyDriver->disableIrq(interface);
00379 }
00380 
00381 
00382 /**
00383  * @brief SAMA5D2 Ethernet MAC interrupt service routine
00384  **/
00385 
00386 void sama5d2EthIrqHandler(void)
00387 {
00388    bool_t flag;
00389    volatile uint32_t isr;
00390    volatile uint32_t tsr;
00391    volatile uint32_t rsr;
00392 
00393    //Enter interrupt service routine
00394    osEnterIsr();
00395 
00396    //This flag will be set if a higher priority task must be woken
00397    flag = FALSE;
00398 
00399    //Each time the software reads GMAC_ISR, it has to check the
00400    //contents of GMAC_TSR, GMAC_RSR and GMAC_NSR
00401    isr = GMAC0->GMAC_ISRPQ[0];
00402    isr = GMAC0->GMAC_ISRPQ[1];
00403    isr = GMAC0->GMAC_ISR;
00404    tsr = GMAC0->GMAC_TSR;
00405    rsr = GMAC0->GMAC_RSR;
00406 
00407    //A packet has been transmitted?
00408    if(tsr & (GMAC_TSR_HRESP | GMAC_TSR_TXCOMP | GMAC_TSR_TFC |
00409       GMAC_TSR_TXGO | GMAC_TSR_RLE | GMAC_TSR_COL | GMAC_TSR_UBR))
00410    {
00411       //Only clear TSR flags that are currently set
00412       GMAC0->GMAC_TSR = tsr;
00413 
00414       //Check whether the TX buffer is available for writing
00415       if(txBufferDesc[txBufferIndex].status & GMAC_TX_USED)
00416       {
00417          //Notify the TCP/IP stack that the transmitter is ready to send
00418          flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
00419       }
00420    }
00421 
00422    //A packet has been received?
00423    if(rsr & (GMAC_RSR_HNO | GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA))
00424    {
00425       //Set event flag
00426       nicDriverInterface->nicEvent = TRUE;
00427       //Notify the TCP/IP stack of the event
00428       flag |= osSetEventFromIsr(&netEvent);
00429    }
00430 
00431    //Write AIC_EOICR register before exiting
00432    AIC->AIC_EOICR = 0;
00433 
00434    //Leave interrupt service routine
00435    osExitIsr(flag);
00436 }
00437 
00438 
00439 /**
00440  * @brief SAMA5D2 Ethernet MAC event handler
00441  * @param[in] interface Underlying network interface
00442  **/
00443 
00444 void sama5d2EthEventHandler(NetInterface *interface)
00445 {
00446    error_t error;
00447    uint32_t rsr;
00448 
00449    //Read receive status
00450    rsr = GMAC0->GMAC_RSR;
00451 
00452    //Packet received?
00453    if(rsr & (GMAC_RSR_HNO | GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA))
00454    {
00455       //Only clear RSR flags that are currently set
00456       GMAC0->GMAC_RSR = rsr;
00457 
00458       //Process all pending packets
00459       do
00460       {
00461          //Read incoming packet
00462          error = sama5d2EthReceivePacket(interface);
00463 
00464          //No more data in the receive buffer?
00465       } while(error != ERROR_BUFFER_EMPTY);
00466    }
00467 }
00468 
00469 
00470 /**
00471  * @brief Send a packet
00472  * @param[in] interface Underlying network interface
00473  * @param[in] buffer Multi-part buffer containing the data to send
00474  * @param[in] offset Offset to the first data byte
00475  * @return Error code
00476  **/
00477 
00478 error_t sama5d2EthSendPacket(NetInterface *interface,
00479    const NetBuffer *buffer, size_t offset)
00480 {
00481    size_t length;
00482 
00483    //Retrieve the length of the packet
00484    length = netBufferGetLength(buffer) - offset;
00485 
00486    //Check the frame length
00487    if(length > SAMA5D2_ETH_TX_BUFFER_SIZE)
00488    {
00489       //The transmitter can accept another packet
00490       osSetEvent(&interface->nicTxEvent);
00491       //Report an error
00492       return ERROR_INVALID_LENGTH;
00493    }
00494 
00495    //Make sure the current buffer is available for writing
00496    if(!(txBufferDesc[txBufferIndex].status & GMAC_TX_USED))
00497       return ERROR_FAILURE;
00498 
00499    //Copy user data to the transmit buffer
00500    netBufferRead(txBuffer[txBufferIndex], buffer, offset, length);
00501 
00502    //Set the necessary flags in the descriptor entry
00503    if(txBufferIndex < (SAMA5D2_ETH_TX_BUFFER_COUNT - 1))
00504    {
00505       //Write the status word
00506       txBufferDesc[txBufferIndex].status =
00507          GMAC_TX_LAST | (length & GMAC_TX_LENGTH);
00508 
00509       //Point to the next buffer
00510       txBufferIndex++;
00511    }
00512    else
00513    {
00514       //Write the status word
00515       txBufferDesc[txBufferIndex].status = GMAC_TX_WRAP |
00516          GMAC_TX_LAST | (length & GMAC_TX_LENGTH);
00517 
00518       //Wrap around
00519       txBufferIndex = 0;
00520    }
00521 
00522    //Data synchronization barrier
00523    __DSB();
00524 
00525    //Set the TSTART bit to initiate transmission
00526    GMAC0->GMAC_NCR |= GMAC_NCR_TSTART;
00527 
00528    //Check whether the next buffer is available for writing
00529    if(txBufferDesc[txBufferIndex].status & GMAC_TX_USED)
00530    {
00531       //The transmitter can accept another packet
00532       osSetEvent(&interface->nicTxEvent);
00533    }
00534 
00535    //Successful processing
00536    return NO_ERROR;
00537 }
00538 
00539 
00540 /**
00541  * @brief Receive a packet
00542  * @param[in] interface Underlying network interface
00543  * @return Error code
00544  **/
00545 
00546 error_t sama5d2EthReceivePacket(NetInterface *interface)
00547 {
00548    static uint8_t temp[ETH_MAX_FRAME_SIZE];
00549    error_t error;
00550    uint_t i;
00551    uint_t j;
00552    uint_t sofIndex;
00553    uint_t eofIndex;
00554    size_t n;
00555    size_t size;
00556    size_t length;
00557 
00558    //Initialize SOF and EOF indices
00559    sofIndex = UINT_MAX;
00560    eofIndex = UINT_MAX;
00561 
00562    //Search for SOF and EOF flags
00563    for(i = 0; i < SAMA5D2_ETH_RX_BUFFER_COUNT; i++)
00564    {
00565       //Point to the current entry
00566       j = rxBufferIndex + i;
00567 
00568       //Wrap around to the beginning of the buffer if necessary
00569       if(j >= SAMA5D2_ETH_RX_BUFFER_COUNT)
00570          j -= SAMA5D2_ETH_RX_BUFFER_COUNT;
00571 
00572       //No more entries to process?
00573       if(!(rxBufferDesc[j].address & GMAC_RX_OWNERSHIP))
00574       {
00575          //Stop processing
00576          break;
00577       }
00578       //A valid SOF has been found?
00579       if(rxBufferDesc[j].status & GMAC_RX_SOF)
00580       {
00581          //Save the position of the SOF
00582          sofIndex = i;
00583       }
00584       //A valid EOF has been found?
00585       if((rxBufferDesc[j].status & GMAC_RX_EOF) && sofIndex != UINT_MAX)
00586       {
00587          //Save the position of the EOF
00588          eofIndex = i;
00589          //Retrieve the length of the frame
00590          size = rxBufferDesc[j].status & GMAC_RX_LENGTH;
00591          //Limit the number of data to read
00592          size = MIN(size, ETH_MAX_FRAME_SIZE);
00593          //Stop processing since we have reached the end of the frame
00594          break;
00595       }
00596    }
00597 
00598    //Determine the number of entries to process
00599    if(eofIndex != UINT_MAX)
00600       j = eofIndex + 1;
00601    else if(sofIndex != UINT_MAX)
00602       j = sofIndex;
00603    else
00604       j = i;
00605 
00606    //Total number of bytes that have been copied from the receive buffer
00607    length = 0;
00608 
00609    //Process incoming frame
00610    for(i = 0; i < j; i++)
00611    {
00612       //Any data to copy from current buffer?
00613       if(eofIndex != UINT_MAX && i >= sofIndex && i <= eofIndex)
00614       {
00615          //Calculate the number of bytes to read at a time
00616          n = MIN(size, SAMA5D2_ETH_RX_BUFFER_SIZE);
00617          //Copy data from receive buffer
00618          memcpy(temp + length, rxBuffer[rxBufferIndex], n);
00619          //Update byte counters
00620          length += n;
00621          size -= n;
00622       }
00623 
00624       //Mark the current buffer as free
00625       rxBufferDesc[rxBufferIndex].address &= ~GMAC_RX_OWNERSHIP;
00626 
00627       //Point to the following entry
00628       rxBufferIndex++;
00629 
00630       //Wrap around to the beginning of the buffer if necessary
00631       if(rxBufferIndex >= SAMA5D2_ETH_RX_BUFFER_COUNT)
00632          rxBufferIndex = 0;
00633    }
00634 
00635    //Any packet to process?
00636    if(length > 0)
00637    {
00638       //Pass the packet to the upper layer
00639       nicProcessPacket(interface, temp, length);
00640       //Valid packet received
00641       error = NO_ERROR;
00642    }
00643    else
00644    {
00645       //No more data in the receive buffer
00646       error = ERROR_BUFFER_EMPTY;
00647    }
00648 
00649    //Return status code
00650    return error;
00651 }
00652 
00653 
00654 /**
00655  * @brief Configure multicast MAC address filtering
00656  * @param[in] interface Underlying network interface
00657  * @return Error code
00658  **/
00659 
00660 error_t sama5d2EthSetMulticastFilter(NetInterface *interface)
00661 {
00662    uint_t i;
00663    uint_t k;
00664    uint8_t *p;
00665    uint32_t hashTable[2];
00666    MacFilterEntry *entry;
00667 
00668    //Debug message
00669    TRACE_DEBUG("Updating SAMA5D2 hash table...\r\n");
00670 
00671    //Clear hash table
00672    hashTable[0] = 0;
00673    hashTable[1] = 0;
00674 
00675    //The MAC filter table contains the multicast MAC addresses
00676    //to accept when receiving an Ethernet frame
00677    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00678    {
00679       //Point to the current entry
00680       entry = &interface->macMulticastFilter[i];
00681 
00682       //Valid entry?
00683       if(entry->refCount > 0)
00684       {
00685          //Point to the MAC address
00686          p = entry->addr.b;
00687 
00688          //Apply the hash function
00689          k = (p[0] >> 6) ^ p[0];
00690          k ^= (p[1] >> 4) ^ (p[1] << 2);
00691          k ^= (p[2] >> 2) ^ (p[2] << 4);
00692          k ^= (p[3] >> 6) ^ p[3];
00693          k ^= (p[4] >> 4) ^ (p[4] << 2);
00694          k ^= (p[5] >> 2) ^ (p[5] << 4);
00695 
00696          //The hash value is reduced to a 6-bit index
00697          k &= 0x3F;
00698 
00699          //Update hash table contents
00700          hashTable[k / 32] |= (1 << (k % 32));
00701       }
00702    }
00703 
00704    //Write the hash table
00705    GMAC0->GMAC_HRB = hashTable[0];
00706    GMAC0->GMAC_HRT = hashTable[1];
00707 
00708    //Debug message
00709    TRACE_DEBUG("  HRB = %08" PRIX32 "\r\n", GMAC0->GMAC_HRB);
00710    TRACE_DEBUG("  HRT = %08" PRIX32 "\r\n", GMAC0->GMAC_HRT);
00711 
00712    //Successful processing
00713    return NO_ERROR;
00714 }
00715 
00716 
00717 /**
00718  * @brief Adjust MAC configuration parameters for proper operation
00719  * @param[in] interface Underlying network interface
00720  * @return Error code
00721  **/
00722 
00723 error_t sama5d2EthUpdateMacConfig(NetInterface *interface)
00724 {
00725    uint32_t config;
00726 
00727    //Read network configuration register
00728    config = GMAC0->GMAC_NCFGR;
00729 
00730    //10BASE-T or 100BASE-TX operation mode?
00731    if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
00732       config |= GMAC_NCFGR_SPD;
00733    else
00734       config &= ~GMAC_NCFGR_SPD;
00735 
00736    //Half-duplex or full-duplex mode?
00737    if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
00738       config |= GMAC_NCFGR_FD;
00739    else
00740       config &= ~GMAC_NCFGR_FD;
00741 
00742    //Write configuration value back to NCFGR register
00743    GMAC0->GMAC_NCFGR = config;
00744 
00745    //Successful processing
00746    return NO_ERROR;
00747 }
00748 
00749 
00750 /**
00751  * @brief Write PHY register
00752  * @param[in] phyAddr PHY address
00753  * @param[in] regAddr Register address
00754  * @param[in] data Register value
00755  **/
00756 
00757 void sama5d2EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
00758 {
00759    uint32_t value;
00760 
00761    //Set up a write operation
00762    value = GMAC_MAN_CLTTO | GMAC_MAN_OP(1) | GMAC_MAN_WTN(2);
00763    //PHY address
00764    value |= GMAC_MAN_PHYA(phyAddr);
00765    //Register address
00766    value |= GMAC_MAN_REGA(regAddr);
00767    //Register value
00768    value |= GMAC_MAN_DATA(data);
00769 
00770    //Start a write operation
00771    GMAC0->GMAC_MAN = value;
00772    //Wait for the write to complete
00773    while(!(GMAC0->GMAC_NSR & GMAC_NSR_IDLE));
00774 }
00775 
00776 
00777 /**
00778  * @brief Read PHY register
00779  * @param[in] phyAddr PHY address
00780  * @param[in] regAddr Register address
00781  * @return Register value
00782  **/
00783 
00784 uint16_t sama5d2EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
00785 {
00786    uint32_t value;
00787 
00788    //Set up a read operation
00789    value = GMAC_MAN_CLTTO | GMAC_MAN_OP(2) | GMAC_MAN_WTN(2);
00790    //PHY address
00791    value |= GMAC_MAN_PHYA(phyAddr);
00792    //Register address
00793    value |= GMAC_MAN_REGA(regAddr);
00794 
00795    //Start a read operation
00796    GMAC0->GMAC_MAN = value;
00797    //Wait for the read to complete
00798    while(!(GMAC0->GMAC_NSR & GMAC_NSR_IDLE));
00799 
00800    //Return PHY register contents
00801    return GMAC0->GMAC_MAN & GMAC_MAN_DATA_Msk;
00802 }
00803