Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers a2fxxxm3_eth.c Source File

a2fxxxm3_eth.c

Go to the documentation of this file.
00001 /**
00002  * @file a2fxxxm3_eth.c
00003  * @brief SmartFusion (A2FxxxM3) 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 "a2fxxxm3.h"
00034 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_regs.h"
00035 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_desc.h"
00036 #include "core/net.h"
00037 #include "drivers/a2fxxxm3_eth.h"
00038 #include "debug.h"
00039 
00040 //Underlying network interface
00041 static NetInterface *nicDriverInterface;
00042 
00043 //IAR EWARM compiler?
00044 #if defined(__ICCARM__)
00045 
00046 //Transmit buffer
00047 #pragma data_alignment = 4
00048 static uint8_t txBuffer[A2FXXXM3_ETH_TX_BUFFER_COUNT][A2FXXXM3_ETH_TX_BUFFER_SIZE];
00049 //Receive buffer
00050 #pragma data_alignment = 4
00051 static uint8_t rxBuffer[A2FXXXM3_ETH_RX_BUFFER_COUNT][A2FXXXM3_ETH_RX_BUFFER_SIZE];
00052 //Transmit DMA descriptors
00053 #pragma data_alignment = 4
00054 static A2fxxxm3TxDmaDesc txDmaDesc[A2FXXXM3_ETH_TX_BUFFER_COUNT];
00055 //Receive DMA descriptors
00056 #pragma data_alignment = 4
00057 static A2fxxxm3RxDmaDesc rxDmaDesc[A2FXXXM3_ETH_RX_BUFFER_COUNT];
00058 
00059 //Keil MDK-ARM or GCC compiler?
00060 #else
00061 
00062 //Transmit buffer
00063 static uint8_t txBuffer[A2FXXXM3_ETH_TX_BUFFER_COUNT][A2FXXXM3_ETH_TX_BUFFER_SIZE]
00064    __attribute__((aligned(4)));
00065 //Receive buffer
00066 static uint8_t rxBuffer[A2FXXXM3_ETH_RX_BUFFER_COUNT][A2FXXXM3_ETH_RX_BUFFER_SIZE]
00067    __attribute__((aligned(4)));
00068 //Transmit DMA descriptors
00069 static A2fxxxm3TxDmaDesc txDmaDesc[A2FXXXM3_ETH_TX_BUFFER_COUNT]
00070    __attribute__((aligned(4)));
00071 //Receive DMA descriptors
00072 static A2fxxxm3RxDmaDesc rxDmaDesc[A2FXXXM3_ETH_RX_BUFFER_COUNT]
00073    __attribute__((aligned(4)));
00074 
00075 #endif
00076 
00077 //Pointer to the current TX DMA descriptor
00078 static A2fxxxm3TxDmaDesc *txCurDmaDesc;
00079 //Pointer to the current RX DMA descriptor
00080 static A2fxxxm3RxDmaDesc *rxCurDmaDesc;
00081 
00082 
00083 /**
00084  * @brief A2FxxxM3 Ethernet MAC driver
00085  **/
00086 
00087 const NicDriver a2fxxxm3EthDriver =
00088 {
00089    NIC_TYPE_ETHERNET,
00090    ETH_MTU,
00091    a2fxxxm3EthInit,
00092    a2fxxxm3EthTick,
00093    a2fxxxm3EthEnableIrq,
00094    a2fxxxm3EthDisableIrq,
00095    a2fxxxm3EthEventHandler,
00096    a2fxxxm3EthSendPacket,
00097    a2fxxxm3EthSetMulticastFilter,
00098    a2fxxxm3EthUpdateMacConfig,
00099    a2fxxxm3EthWritePhyReg,
00100    a2fxxxm3EthReadPhyReg,
00101    TRUE,
00102    TRUE,
00103    TRUE,
00104    FALSE
00105 };
00106 
00107 
00108 /**
00109  * @brief A2FxxxM3 Ethernet MAC initialization
00110  * @param[in] interface Underlying network interface
00111  * @return Error code
00112  **/
00113 
00114 error_t a2fxxxm3EthInit(NetInterface *interface)
00115 {
00116    error_t error;
00117 
00118    //Debug message
00119    TRACE_INFO("Initializing A2FxxxM3 Ethernet MAC...\r\n");
00120 
00121    //Save underlying network interface
00122    nicDriverInterface = interface;
00123 
00124    //Perform a software reset
00125    MAC->CSR0 |= CSR0_SWR_MASK;
00126    //Wait for the reset to complete
00127    while(MAC->CSR0 & CSR0_SWR_MASK);
00128 
00129    //PHY transceiver initialization
00130    error = interface->phyDriver->init(interface);
00131    //Failed to initialize PHY transceiver?
00132    if(error)
00133       return error;
00134 
00135    //Enable store and forward mode
00136    MAC->CSR6 |= CSR6_SF_MASK;
00137 
00138    //Initialize DMA descriptor lists
00139    a2fxxxm3EthInitDmaDesc(interface);
00140 
00141    //Enable the desired Ethernet interrupts
00142    MAC->CSR7 |= CSR7_NIE_MASK | CSR7_RIE_MASK | CSR7_TIE_MASK;
00143 
00144    //Set priority grouping (5 bits for pre-emption priority, no bits for subpriority)
00145    NVIC_SetPriorityGrouping(A2FXXXM3_ETH_IRQ_PRIORITY_GROUPING);
00146 
00147    //Configure Ethernet interrupt priority
00148    NVIC_SetPriority(EthernetMAC_IRQn, NVIC_EncodePriority(A2FXXXM3_ETH_IRQ_PRIORITY_GROUPING,
00149       A2FXXXM3_ETH_IRQ_GROUP_PRIORITY, A2FXXXM3_ETH_IRQ_SUB_PRIORITY));
00150 
00151    //Enable transmission and reception
00152    MAC->CSR6 |= CSR6_ST_MASK | CSR6_SR_MASK;
00153 
00154    //Set MAC address
00155    error = a2fxxxm3EthSendSetup(interface);
00156    //Any error to report?
00157    if(error)
00158       return error;
00159 
00160    //Accept any packets from the upper layer
00161    osSetEvent(&interface->nicTxEvent);
00162 
00163    //Successful initialization
00164    return NO_ERROR;
00165 }
00166 
00167 
00168 /**
00169  * @brief Initialize DMA descriptor lists
00170  * @param[in] interface Underlying network interface
00171  **/
00172 
00173 void a2fxxxm3EthInitDmaDesc(NetInterface *interface)
00174 {
00175    uint_t i;
00176 
00177    //Initialize TX DMA descriptor list
00178    for(i = 0; i < A2FXXXM3_ETH_TX_BUFFER_COUNT; i++)
00179    {
00180       //The descriptor is initially owned by the user
00181       txDmaDesc[i].tdes0 = 0;
00182       //Use chain structure rather than ring structure
00183       txDmaDesc[i].tdes1 = TDES1_TCH;
00184       //Transmit buffer address
00185       txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
00186       //Next descriptor address
00187       txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
00188    }
00189 
00190    //The last descriptor is chained to the first entry
00191    txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
00192    //Point to the very first descriptor
00193    txCurDmaDesc = &txDmaDesc[0];
00194 
00195    //Initialize RX DMA descriptor list
00196    for(i = 0; i < A2FXXXM3_ETH_RX_BUFFER_COUNT; i++)
00197    {
00198       //The descriptor is initially owned by the DMA
00199       rxDmaDesc[i].rdes0 = RDES0_OWN;
00200       //Use chain structure rather than ring structure
00201       rxDmaDesc[i].rdes1 = RDES1_RCH | (A2FXXXM3_ETH_RX_BUFFER_SIZE & RDES1_RBS1_MASK);
00202       //Receive buffer address
00203       rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
00204       //Next descriptor address
00205       rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
00206    }
00207 
00208    //The last descriptor is chained to the first entry
00209    rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
00210    //Point to the very first descriptor
00211    rxCurDmaDesc = &rxDmaDesc[0];
00212 
00213    //Start location of the TX descriptor list
00214    MAC->CSR4 = (uint32_t) txDmaDesc;
00215    //Start location of the RX descriptor list
00216    MAC->CSR3 = (uint32_t) rxDmaDesc;
00217 }
00218 
00219 
00220 /**
00221  * @brief A2FxxxM3 Ethernet MAC timer handler
00222  *
00223  * This routine is periodically called by the TCP/IP stack to
00224  * handle periodic operations such as polling the link state
00225  *
00226  * @param[in] interface Underlying network interface
00227  **/
00228 
00229 void a2fxxxm3EthTick(NetInterface *interface)
00230 {
00231    //Handle periodic operations
00232    interface->phyDriver->tick(interface);
00233 }
00234 
00235 
00236 /**
00237  * @brief Enable interrupts
00238  * @param[in] interface Underlying network interface
00239  **/
00240 
00241 void a2fxxxm3EthEnableIrq(NetInterface *interface)
00242 {
00243    //Enable Ethernet MAC interrupts
00244    NVIC_EnableIRQ(EthernetMAC_IRQn);
00245    //Enable Ethernet PHY interrupts
00246    interface->phyDriver->enableIrq(interface);
00247 }
00248 
00249 
00250 /**
00251  * @brief Disable interrupts
00252  * @param[in] interface Underlying network interface
00253  **/
00254 
00255 void a2fxxxm3EthDisableIrq(NetInterface *interface)
00256 {
00257    //Disable Ethernet MAC interrupts
00258    NVIC_DisableIRQ(EthernetMAC_IRQn);
00259    //Disable Ethernet PHY interrupts
00260    interface->phyDriver->disableIrq(interface);
00261 }
00262 
00263 
00264 /**
00265  * @brief A2FxxxM3 Ethernet MAC interrupt service routine
00266  **/
00267 
00268 void EthernetMAC_IRQHandler(void)
00269 {
00270    bool_t flag;
00271    uint32_t status;
00272 
00273    //Enter interrupt service routine
00274    osEnterIsr();
00275 
00276    //This flag will be set if a higher priority task must be woken
00277    flag = FALSE;
00278 
00279    //Read interrupt status register
00280    status = MAC->CSR5;
00281 
00282    //A packet has been transmitted?
00283    if(status & CSR5_TI_MASK)
00284    {
00285       //Clear TI interrupt flag
00286       MAC->CSR5 = CSR5_TI_MASK;
00287 
00288       //Check whether the TX buffer is available for writing
00289       if(!(txCurDmaDesc->tdes0 & TDES0_OWN))
00290       {
00291          //Notify the TCP/IP stack that the transmitter is ready to send
00292          flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
00293       }
00294    }
00295 
00296    //A packet has been received?
00297    if(status & CSR5_RI_MASK)
00298    {
00299       //Disable RIE interrupt
00300       MAC->CSR7 &= ~CSR7_RIE_MASK;
00301 
00302       //Set event flag
00303       nicDriverInterface->nicEvent = TRUE;
00304       //Notify the TCP/IP stack of the event
00305       flag |= osSetEventFromIsr(&netEvent);
00306    }
00307 
00308    //Clear NIS interrupt flag
00309    MAC->CSR5 = CSR5_NIS_MASK;
00310 
00311    //Leave interrupt service routine
00312    osExitIsr(flag);
00313 }
00314 
00315 
00316 /**
00317  * @brief A2FxxxM3 Ethernet MAC event handler
00318  * @param[in] interface Underlying network interface
00319  **/
00320 
00321 void a2fxxxm3EthEventHandler(NetInterface *interface)
00322 {
00323    error_t error;
00324 
00325    //Packet received?
00326    if(MAC->CSR5 & CSR5_RI_MASK)
00327    {
00328       //Clear interrupt flag
00329       MAC->CSR5 = CSR5_RI_MASK;
00330 
00331       //Process all pending packets
00332       do
00333       {
00334          //Read incoming packet
00335          error = a2fxxxm3EthReceivePacket(interface);
00336 
00337          //No more data in the receive buffer?
00338       } while(error != ERROR_BUFFER_EMPTY);
00339    }
00340 
00341    //Re-enable Ethernet interrupts
00342    MAC->CSR7 |= CSR7_NIE_MASK | CSR7_RIE_MASK | CSR7_TIE_MASK;
00343 }
00344 
00345 
00346 /**
00347  * @brief Send a setup frame
00348  * @param[in] interface Underlying network interface
00349  * @return Error code
00350  **/
00351 
00352 error_t a2fxxxm3EthSendSetup(NetInterface *interface)
00353 {
00354    A2fxxxm3HashTableSetupFrame *setupFrame;
00355 
00356    //Make sure the current buffer is available for writing
00357    if(txCurDmaDesc->tdes0 & TDES0_OWN)
00358       return ERROR_FAILURE;
00359 
00360    //Point to the buffer where to format the setup frame
00361    setupFrame = (A2fxxxm3HashTableSetupFrame *) txCurDmaDesc->tdes2;
00362 
00363    //Clear contents
00364    memset(setupFrame, 0, sizeof(A2fxxxm3HashTableSetupFrame));
00365 
00366    //Set MAC address
00367    setupFrame->physicalAddr[0] = interface->macAddr.w[0];
00368    setupFrame->physicalAddr[1] = interface->macAddr.w[1];
00369    setupFrame->physicalAddr[2] = interface->macAddr.w[2];
00370 
00371    //Write the number of bytes to send
00372    txCurDmaDesc->tdes1 = sizeof(A2fxxxm3HashTableSetupFrame) & TDES1_TBS1_MASK;
00373    //The SET flag indicates that this is a setup frame descriptor
00374    txCurDmaDesc->tdes1 |= TDES1_SET | TDES1_TCH | TDES1_FT0;
00375    //Give the ownership of the descriptor to the DMA
00376    txCurDmaDesc->tdes0 |= TDES0_OWN;
00377 
00378    //Instruct the DMA to poll the transmit descriptor list
00379    MAC->CSR1 = 1;
00380 
00381    //Point to the next descriptor in the list
00382    txCurDmaDesc = (A2fxxxm3TxDmaDesc *) txCurDmaDesc->tdes3;
00383 
00384    //Data successfully written
00385    return NO_ERROR;
00386 }
00387 
00388 
00389 /**
00390  * @brief Send a packet
00391  * @param[in] interface Underlying network interface
00392  * @param[in] buffer Multi-part buffer containing the data to send
00393  * @param[in] offset Offset to the first data byte
00394  * @return Error code
00395  **/
00396 
00397 error_t a2fxxxm3EthSendPacket(NetInterface *interface,
00398    const NetBuffer *buffer, size_t offset)
00399 {
00400    size_t length;
00401 
00402    //Retrieve the length of the packet
00403    length = netBufferGetLength(buffer) - offset;
00404 
00405    //Check the frame length
00406    if(length > A2FXXXM3_ETH_TX_BUFFER_SIZE)
00407    {
00408       //The transmitter can accept another packet
00409       osSetEvent(&interface->nicTxEvent);
00410       //Report an error
00411       return ERROR_INVALID_LENGTH;
00412    }
00413 
00414    //Make sure the current buffer is available for writing
00415    if(txCurDmaDesc->tdes0 & TDES0_OWN)
00416       return ERROR_FAILURE;
00417 
00418    //Copy user data to the transmit buffer
00419    netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
00420 
00421    //Write the number of bytes to send
00422    txCurDmaDesc->tdes1 = length & TDES1_TBS1_MASK;
00423    //Set LS and FS flags as the data fits in a single buffer
00424    txCurDmaDesc->tdes1 |= TDES1_IC | TDES1_LS | TDES1_FS | TDES1_TCH;
00425    //Give the ownership of the descriptor to the DMA
00426    txCurDmaDesc->tdes0 |= TDES0_OWN;
00427 
00428    //Instruct the DMA to poll the transmit descriptor list
00429    MAC->CSR1 = 1;
00430 
00431    //Point to the next descriptor in the list
00432    txCurDmaDesc = (A2fxxxm3TxDmaDesc *) txCurDmaDesc->tdes3;
00433 
00434    //Check whether the next buffer is available for writing
00435    if(!(txCurDmaDesc->tdes0 & TDES0_OWN))
00436    {
00437       //The transmitter can accept another packet
00438       osSetEvent(&interface->nicTxEvent);
00439    }
00440 
00441    //Data successfully written
00442    return NO_ERROR;
00443 }
00444 
00445 
00446 /**
00447  * @brief Receive a packet
00448  * @param[in] interface Underlying network interface
00449  * @return Error code
00450  **/
00451 
00452 error_t a2fxxxm3EthReceivePacket(NetInterface *interface)
00453 {
00454    error_t error;
00455    size_t n;
00456 
00457    //The current buffer is available for reading?
00458    if(!(rxCurDmaDesc->rdes0 & RDES0_OWN))
00459    {
00460       //FS and LS flags should be set
00461       if((rxCurDmaDesc->rdes0 & RDES0_FS) && (rxCurDmaDesc->rdes0 & RDES0_LS))
00462       {
00463          //Make sure no error occurred
00464          if(!(rxCurDmaDesc->rdes0 & RDES0_ES))
00465          {
00466             //Retrieve the length of the frame
00467             n = (rxCurDmaDesc->rdes0 >> RDES0_FL_OFFSET) & RDES0_FL_MASK;
00468             //Limit the number of data to read
00469             n = MIN(n, A2FXXXM3_ETH_RX_BUFFER_SIZE);
00470 
00471             //Pass the packet to the upper layer
00472             nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n);
00473 
00474             //Valid packet received
00475             error = NO_ERROR;
00476          }
00477          else
00478          {
00479             //The received packet contains an error
00480             error = ERROR_INVALID_PACKET;
00481          }
00482       }
00483       else
00484       {
00485          //The packet is not valid
00486          error = ERROR_INVALID_PACKET;
00487       }
00488 
00489       //Give the ownership of the descriptor back to the DMA
00490       rxCurDmaDesc->rdes0 = RDES0_OWN;
00491       //Point to the next descriptor in the list
00492       rxCurDmaDesc = (A2fxxxm3RxDmaDesc *) rxCurDmaDesc->rdes3;
00493    }
00494    else
00495    {
00496       //No more data in the receive buffer
00497       error = ERROR_BUFFER_EMPTY;
00498    }
00499 
00500    //Instruct the DMA to poll the receive descriptor list
00501    MAC->CSR2 = 1;
00502 
00503    //Return status code
00504    return error;
00505 }
00506 
00507 
00508 /**
00509  * @brief Configure multicast MAC address filtering
00510  * @param[in] interface Underlying network interface
00511  * @return Error code
00512  **/
00513 
00514 error_t a2fxxxm3EthSetMulticastFilter(NetInterface *interface)
00515 {
00516    uint_t i;
00517    bool_t acceptMulticast;
00518 
00519    //This flag will be set if multicast addresses should be accepted
00520    acceptMulticast = FALSE;
00521 
00522    //The MAC filter table contains the multicast MAC addresses
00523    //to accept when receiving an Ethernet frame
00524    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00525    {
00526       //Valid entry?
00527       if(interface->macMulticastFilter[i].refCount > 0)
00528       {
00529          //Accept multicast addresses
00530          acceptMulticast = TRUE;
00531          //We are done
00532          break;
00533       }
00534    }
00535 
00536    //Enable the reception of multicast frames if necessary
00537    if(acceptMulticast)
00538       MAC->CSR6 |= CSR6_PM_MASK;
00539    else
00540       MAC->CSR6 &= ~CSR6_PM_MASK;
00541 
00542    //Successful processing
00543    return NO_ERROR;
00544 }
00545 
00546 
00547 /**
00548  * @brief Adjust MAC configuration parameters for proper operation
00549  * @param[in] interface Underlying network interface
00550  * @return Error code
00551  **/
00552 
00553 error_t a2fxxxm3EthUpdateMacConfig(NetInterface *interface)
00554 {
00555    //Stop transmission
00556    while(((MAC->CSR5 & CSR5_TS_MASK) >> CSR5_TS_SHIFT) != CSR5_TS_STOPPED)
00557       MAC->CSR6 &= ~CSR6_ST_MASK;
00558 
00559    //Stop reception
00560    while(((MAC->CSR5 & CSR5_RS_MASK) >> CSR5_RS_SHIFT) != CSR5_RS_STOPPED)
00561       MAC->CSR6 &= ~CSR6_SR_MASK;
00562 
00563    //10BASE-T or 100BASE-TX operation mode?
00564    if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
00565       MAC->CSR6 |= CSR6_TTM_MASK;
00566    else
00567       MAC->CSR6 &= ~CSR6_TTM_MASK;
00568 
00569    //Half-duplex or full-duplex mode?
00570    if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
00571       MAC->CSR6 |= CSR6_FD_MASK;
00572    else
00573       MAC->CSR6 &= ~CSR6_FD_MASK;
00574 
00575    //Restart transmission and reception
00576    MAC->CSR6 |= CSR6_ST_MASK | CSR6_SR_MASK;
00577 
00578    //Successful processing
00579    return NO_ERROR;
00580 }
00581 
00582 
00583 /**
00584  * @brief Write PHY register
00585  * @param[in] phyAddr PHY address
00586  * @param[in] regAddr Register address
00587  * @param[in] data Register value
00588  **/
00589 
00590 void a2fxxxm3EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
00591 {
00592    //Synchronization pattern
00593    a2fxxxm3EthWriteSmi(SMI_SYNC, 32);
00594    //Start of frame
00595    a2fxxxm3EthWriteSmi(SMI_START, 2);
00596    //Set up a write operation
00597    a2fxxxm3EthWriteSmi(SMI_WRITE, 2);
00598    //Write PHY address
00599    a2fxxxm3EthWriteSmi(phyAddr, 5);
00600    //Write register address
00601    a2fxxxm3EthWriteSmi(regAddr, 5);
00602    //Turnaround
00603    a2fxxxm3EthWriteSmi(SMI_TA, 2);
00604    //Write register value
00605    a2fxxxm3EthWriteSmi(data, 16);
00606    //Release MDIO
00607    a2fxxxm3EthReadSmi(1);
00608 }
00609 
00610 
00611 /**
00612  * @brief Read PHY register
00613  * @param[in] phyAddr PHY address
00614  * @param[in] regAddr Register address
00615  * @return Register value
00616  **/
00617 
00618 uint16_t a2fxxxm3EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
00619 {
00620    uint16_t data;
00621 
00622    //Synchronization pattern
00623    a2fxxxm3EthWriteSmi(SMI_SYNC, 32);
00624    //Start of frame
00625    a2fxxxm3EthWriteSmi(SMI_START, 2);
00626    //Set up a read operation
00627    a2fxxxm3EthWriteSmi(SMI_READ, 2);
00628    //Write PHY address
00629    a2fxxxm3EthWriteSmi(phyAddr, 5);
00630    //Write register address
00631    a2fxxxm3EthWriteSmi(regAddr, 5);
00632    //Turnaround to avoid contention
00633    a2fxxxm3EthReadSmi(1);
00634    //Read register value
00635    data = a2fxxxm3EthReadSmi(16);
00636    //Force the PHY to release the MDIO pin
00637    a2fxxxm3EthReadSmi(1);
00638 
00639    //Return PHY register contents
00640    return data;
00641 }
00642 
00643 
00644 /**
00645  * @brief SMI write operation
00646  * @param[in] data Raw data to be written
00647  * @param[in] length Number of bits to be written
00648  **/
00649 
00650 void a2fxxxm3EthWriteSmi(uint32_t data, uint_t length)
00651 {
00652    //Skip the most significant bits since they are meaningless
00653    data <<= 32 - length;
00654 
00655    //Configure MDIO as an output
00656    MAC->CSR9 |= CSR9_MDEN_MASK;
00657 
00658    //Write the specified number of bits
00659    while(length--)
00660    {
00661       //Write MDIO
00662       if(data & 0x80000000)
00663          MAC->CSR9 |= CSR9_MDO_MASK;
00664       else
00665          MAC->CSR9 &= ~CSR9_MDO_MASK;
00666 
00667       //Assert MDC
00668       usleep(1);
00669       MAC->CSR9 |= CSR9_MDC_MASK;
00670       //Deassert MDC
00671       usleep(1);
00672       MAC->CSR9 &= ~CSR9_MDC_MASK;
00673 
00674       //Rotate data
00675       data <<= 1;
00676    }
00677 }
00678 
00679 
00680 /**
00681  * @brief SMI read operation
00682  * @param[in] length Number of bits to be read
00683  * @return Data resulting from the MDIO read operation
00684  **/
00685 
00686 uint32_t a2fxxxm3EthReadSmi(uint_t length)
00687 {
00688    uint32_t data = 0;
00689 
00690    //Configure MDIO as an input
00691    MAC->CSR9 &= ~CSR9_MDEN_MASK;
00692 
00693    //Read the specified number of bits
00694    while(length--)
00695    {
00696       //Rotate data
00697       data <<= 1;
00698 
00699       //Assert MDC
00700       MAC->CSR9 |= CSR9_MDC_MASK;
00701       usleep(1);
00702       //Deassert MDC
00703       MAC->CSR9 &= ~CSR9_MDC_MASK;
00704       usleep(1);
00705 
00706       //Check MDIO state
00707       if(MAC->CSR9 & CSR9_MDI_MASK)
00708          data |= 0x00000001;
00709    }
00710 
00711    //Return the received data
00712    return data;
00713 }
00714 
00715 
00716 /**
00717  * @brief CRC calculation
00718  * @param[in] data Pointer to the data over which to calculate the CRC
00719  * @param[in] length Number of bytes to process
00720  * @return Resulting CRC value
00721  **/
00722 
00723 uint32_t a2fxxxm3EthCalcCrc(const void *data, size_t length)
00724 {
00725    uint_t i;
00726    uint_t j;
00727 
00728    //Point to the data over which to calculate the CRC
00729    const uint8_t *p = (uint8_t *) data;
00730    //CRC preset value
00731    uint32_t crc = 0xFFFFFFFF;
00732 
00733    //Loop through data
00734    for(i = 0; i < length; i++)
00735    {
00736       //Update CRC value
00737       crc ^= p[i];
00738 
00739       //The message is processed bit by bit
00740       for(j = 0; j < 8; j++)
00741       {
00742          //Update CRC value
00743          if(crc & 0x00000001)
00744             crc = (crc >> 1) ^ 0xEDB88320;
00745          else
00746             crc = crc >> 1;
00747       }
00748    }
00749 
00750    //Return CRC value
00751    return crc;
00752 }
00753