Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers zynq7000_eth.c Source File

zynq7000_eth.c

Go to the documentation of this file.
00001 /**
00002  * @file zynq7000_eth.c
00003  * @brief Zynq-7000 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 "xemacps_hw.h"
00035 #include "xscugic.h"
00036 #include "xil_misc_psreset_api.h"
00037 #include "core/net.h"
00038 #include "drivers/zynq7000_eth.h"
00039 #include "debug.h"
00040 
00041 //Underlying network interface
00042 static NetInterface *nicDriverInterface;
00043 
00044 //GIC instance
00045 extern XScuGic ZYNQ7000_ETH_GIC_INSTANCE;
00046 
00047 //IAR EWARM compiler?
00048 #if defined(__ICCARM__)
00049 
00050 //TX buffer
00051 #pragma data_alignment = 8
00052 #pragma location = ".ram_no_cache"
00053 static uint8_t txBuffer[ZYNQ7000_ETH_TX_BUFFER_COUNT][ZYNQ7000_ETH_TX_BUFFER_SIZE];
00054 //RX buffer
00055 #pragma data_alignment = 8
00056 #pragma location = ".ram_no_cache"
00057 static uint8_t rxBuffer[ZYNQ7000_ETH_RX_BUFFER_COUNT][ZYNQ7000_ETH_RX_BUFFER_SIZE];
00058 //TX buffer descriptors
00059 #pragma data_alignment = 4
00060 #pragma location = ".ram_no_cache"
00061 static Zynq7000TxBufferDesc txBufferDesc[ZYNQ7000_ETH_TX_BUFFER_COUNT];
00062 //RX buffer descriptors
00063 #pragma data_alignment = 4
00064 #pragma location = ".ram_no_cache"
00065 static Zynq7000RxBufferDesc rxBufferDesc[ZYNQ7000_ETH_RX_BUFFER_COUNT];
00066 
00067 //Keil MDK-ARM or GCC compiler?
00068 #else
00069 
00070 //TX buffer
00071 static uint8_t txBuffer[ZYNQ7000_ETH_TX_BUFFER_COUNT][ZYNQ7000_ETH_TX_BUFFER_SIZE]
00072    __attribute__((aligned(8), __section__(".ram_no_cache")));
00073 //RX buffer
00074 static uint8_t rxBuffer[ZYNQ7000_ETH_RX_BUFFER_COUNT][ZYNQ7000_ETH_RX_BUFFER_SIZE]
00075    __attribute__((aligned(8), __section__(".ram_no_cache")));
00076 //TX buffer descriptors
00077 static Zynq7000TxBufferDesc txBufferDesc[ZYNQ7000_ETH_TX_BUFFER_COUNT]
00078    __attribute__((aligned(4), __section__(".ram_no_cache")));
00079 //RX buffer descriptors
00080 static Zynq7000RxBufferDesc rxBufferDesc[ZYNQ7000_ETH_RX_BUFFER_COUNT]
00081    __attribute__((aligned(4), __section__(".ram_no_cache")));
00082 
00083 #endif
00084 
00085 //TX buffer index
00086 static uint_t txBufferIndex;
00087 //RX buffer index
00088 static uint_t rxBufferIndex;
00089 
00090 
00091 /**
00092  * @brief Zynq-7000 Ethernet MAC driver
00093  **/
00094 
00095 const NicDriver zynq7000EthDriver =
00096 {
00097    NIC_TYPE_ETHERNET,
00098    ETH_MTU,
00099    zynq7000EthInit,
00100    zynq7000EthTick,
00101    zynq7000EthEnableIrq,
00102    zynq7000EthDisableIrq,
00103    zynq7000EthEventHandler,
00104    zynq7000EthSendPacket,
00105    zynq7000EthSetMulticastFilter,
00106    zynq7000EthUpdateMacConfig,
00107    zynq7000EthWritePhyReg,
00108    zynq7000EthReadPhyReg,
00109    TRUE,
00110    TRUE,
00111    TRUE,
00112    FALSE
00113 };
00114 
00115 
00116 /**
00117  * @brief Zynq-7000 Ethernet MAC initialization
00118  * @param[in] interface Underlying network interface
00119  * @return Error code
00120  **/
00121 
00122 error_t zynq7000EthInit(NetInterface *interface)
00123 {
00124    error_t error;
00125    volatile uint32_t temp;
00126 
00127    //Debug message
00128    TRACE_INFO("Initializing Zynq-7000 Ethernet MAC...\r\n");
00129 
00130    //Save underlying network interface
00131    nicDriverInterface = interface;
00132 
00133    //Unlock SLCR
00134    XSLCR_UNLOCK = XSLCR_UNLOCK_KEY_VALUE;
00135 
00136    //Configure Ethernet controller reference clock
00137    temp = XSLCR_GEM0_CLK_CTRL_CLKACT_MASK;
00138    temp |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK;
00139    temp |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK;
00140    XSLCR_GEM0_CLK_CTRL = temp;
00141 
00142    //Enable Ethernet controller RX clock
00143    XSLCR_GEM0_RCLK_CTRL = XSLCR_GEM0_RCLK_CTRL_CLKACT_MASK;
00144 
00145    //Lock SLCR
00146    XSLCR_LOCK = XSLCR_LOCK_KEY_VALUE;
00147 
00148    //Clear network control register
00149    XEMACPS_NWCTRL = 0;
00150    //Clear statistics registers
00151    XEMACPS_NWCTRL |= XEMACPS_NWCTRL_STATCLR_MASK;
00152 
00153    //Configure MDC clock speed
00154    XEMACPS_NWCFG = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK) | XEMACPS_NWCFG_MDCCLKDIV_MASK;
00155    //Enable management port (MDC and MDIO)
00156    XEMACPS_NWCTRL |= XEMACPS_NWCTRL_MDEN_MASK;
00157 
00158    //PHY transceiver initialization
00159    error = interface->phyDriver->init(interface);
00160    //Failed to initialize PHY transceiver?
00161    if(error)
00162       return error;
00163 
00164    //Set the MAC address
00165    XEMACPS_LADDR1L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
00166    XEMACPS_LADDR1H = interface->macAddr.w[2];
00167 
00168    //Configure the receive filter
00169    XEMACPS_NWCFG |= XEMACPS_NWCFG_UCASTHASHEN_MASK | XEMACPS_NWCFG_MCASTHASHEN_MASK;
00170 
00171    //Initialize hash table
00172    XEMACPS_HASHL = 0;
00173    XEMACPS_HASHH = 0;
00174 
00175    //Initialize buffer descriptors
00176    zynq7000EthInitBufferDesc(interface);
00177 
00178    //Set RX buffer size
00179    temp = ((ZYNQ7000_ETH_RX_BUFFER_SIZE / 64) << XEMACPS_DMACR_RXBUF_SHIFT) &
00180       XEMACPS_DMACR_RXBUF_MASK;
00181 
00182    //Use full configured addressable space for transmit and receive packet buffers
00183    temp |= XEMACPS_DMACR_TXSIZE_MASK | XEMACPS_DMACR_RXSIZE_MASK;
00184    //Select the burst length for DMA data operations
00185    temp |= XEMACPS_DMACR_INCR16_AHB_BURST;
00186    //Set DMA configuration register
00187    XEMACPS_DMACR = temp;
00188 
00189    //Clear transmit status register
00190    XEMACPS_TXSR = XEMACPS_TXSR_TXCOMPL_MASK | XEMACPS_TXSR_TXGO_MASK |
00191       XEMACPS_TXSR_ERROR_MASK;
00192 
00193    //Clear receive status register
00194    XEMACPS_RXSR = XEMACPS_RXSR_FRAMERX_MASK | XEMACPS_RXSR_ERROR_MASK;
00195 
00196    //First disable all interrupts
00197    XEMACPS_IDR = 0xFFFFFFFF;
00198 
00199    //Only the desired ones are enabled
00200    XEMACPS_IER = XEMACPS_IXR_HRESPNOK_MASK | XEMACPS_IXR_RXOVR_MASK |
00201       XEMACPS_IXR_TXCOMPL_MASK | XEMACPS_IXR_TXEXH_MASK | XEMACPS_IXR_RETRY_MASK |
00202       XEMACPS_IXR_URUN_MASK | XEMACPS_IXR_RXUSED_MASK | XEMACPS_IXR_FRAMERX_MASK;
00203 
00204    //Read interrupt status register to clear any pending interrupt
00205    temp = XEMACPS_ISR;
00206 
00207    //Register interrupt handler
00208    XScuGic_Connect(&ZYNQ7000_ETH_GIC_INSTANCE, XPS_GEM0_INT_ID,
00209       (Xil_InterruptHandler) zynq7000EthIrqHandler, interface);
00210 
00211    //Configure interrupt priority
00212    XScuGic_SetPriorityTriggerType(&ZYNQ7000_ETH_GIC_INSTANCE,
00213       XPS_GEM0_INT_ID, ZYNQ7000_ETH_IRQ_PRIORITY, 1);
00214 
00215    //Enable the transmitter and the receiver
00216    XEMACPS_NWCTRL |= XEMACPS_NWCTRL_TXEN_MASK | XEMACPS_NWCTRL_RXEN_MASK;
00217 
00218    //Accept any packets from the upper layer
00219    osSetEvent(&interface->nicTxEvent);
00220 
00221    //Successful initialization
00222    return NO_ERROR;
00223 }
00224 
00225 
00226 /**
00227  * @brief Initialize buffer descriptors
00228  * @param[in] interface Underlying network interface
00229  **/
00230 
00231 void zynq7000EthInitBufferDesc(NetInterface *interface)
00232 {
00233    uint_t i;
00234    uint32_t address;
00235 
00236    //Initialize TX buffer descriptors
00237    for(i = 0; i < ZYNQ7000_ETH_TX_BUFFER_COUNT; i++)
00238    {
00239       //Calculate the address of the current TX buffer
00240       address = (uint32_t) txBuffer[i];
00241       //Write the address to the descriptor entry
00242       txBufferDesc[i].address = address;
00243       //Initialize status field
00244       txBufferDesc[i].status = XEMACPS_TX_USED;
00245    }
00246 
00247    //Mark the last descriptor entry with the wrap flag
00248    txBufferDesc[i - 1].status |= XEMACPS_TX_WRAP;
00249    //Initialize TX buffer index
00250    txBufferIndex = 0;
00251 
00252    //Initialize RX buffer descriptors
00253    for(i = 0; i < ZYNQ7000_ETH_RX_BUFFER_COUNT; i++)
00254    {
00255       //Calculate the address of the current RX buffer
00256       address = (uint32_t) rxBuffer[i];
00257       //Write the address to the descriptor entry
00258       rxBufferDesc[i].address = address & XEMACPS_RX_ADDRESS;
00259       //Clear status field
00260       rxBufferDesc[i].status = 0;
00261    }
00262 
00263    //Mark the last descriptor entry with the wrap flag
00264    rxBufferDesc[i - 1].address |= XEMACPS_RX_WRAP;
00265    //Initialize RX buffer index
00266    rxBufferIndex = 0;
00267 
00268    //Start location of the TX descriptor list
00269    XEMACPS_TXQBASE = (uint32_t) txBufferDesc;
00270    //Start location of the RX descriptor list
00271    XEMACPS_RXQBASE = (uint32_t) rxBufferDesc;
00272 }
00273 
00274 
00275 /**
00276  * @brief Zynq-7000 Ethernet MAC timer handler
00277  *
00278  * This routine is periodically called by the TCP/IP stack to
00279  * handle periodic operations such as polling the link state
00280  *
00281  * @param[in] interface Underlying network interface
00282  **/
00283 
00284 void zynq7000EthTick(NetInterface *interface)
00285 {
00286    //Handle periodic operations
00287    interface->phyDriver->tick(interface);
00288 }
00289 
00290 
00291 /**
00292  * @brief Enable interrupts
00293  * @param[in] interface Underlying network interface
00294  **/
00295 
00296 void zynq7000EthEnableIrq(NetInterface *interface)
00297 {
00298    //Enable Ethernet MAC interrupts
00299    XScuGic_Enable(&ZYNQ7000_ETH_GIC_INSTANCE, XPS_GEM0_INT_ID);
00300    //Enable Ethernet PHY interrupts
00301    interface->phyDriver->enableIrq(interface);
00302 }
00303 
00304 
00305 /**
00306  * @brief Disable interrupts
00307  * @param[in] interface Underlying network interface
00308  **/
00309 
00310 void zynq7000EthDisableIrq(NetInterface *interface)
00311 {
00312    //Disable Ethernet MAC interrupts
00313    XScuGic_Disable(&ZYNQ7000_ETH_GIC_INSTANCE, XPS_GEM0_INT_ID);
00314    //Disable Ethernet PHY interrupts
00315    interface->phyDriver->disableIrq(interface);
00316 }
00317 
00318 
00319 /**
00320  * @brief Zynq-7000 Ethernet MAC interrupt service routine
00321  * @param[in] interface Underlying network interface
00322  **/
00323 
00324 void zynq7000EthIrqHandler(NetInterface *interface)
00325 {
00326    bool_t flag;
00327    volatile uint32_t isr;
00328    volatile uint32_t tsr;
00329    volatile uint32_t rsr;
00330 
00331    //Enter interrupt service routine
00332    osEnterIsr();
00333 
00334    //This flag will be set if a higher priority task must be woken
00335    flag = FALSE;
00336 
00337    //Each time the software reads XEMACPS_ISR, it has to check the
00338    //contents of XEMACPS_TXSR, XEMACPS_RXSR
00339    isr = XEMACPS_ISR;
00340    tsr = XEMACPS_TXSR;
00341    rsr = XEMACPS_RXSR;
00342 
00343    //Clear interrupt flags
00344    XEMACPS_ISR = isr;
00345 
00346    //A packet has been transmitted?
00347    if(tsr & (XEMACPS_TXSR_TXCOMPL_MASK | XEMACPS_TXSR_TXGO_MASK | XEMACPS_TXSR_ERROR_MASK))
00348    {
00349       //Only clear TSR flags that are currently set
00350       XEMACPS_TXSR = tsr;
00351 
00352       //Check whether the TX buffer is available for writing
00353       if(txBufferDesc[txBufferIndex].status & XEMACPS_TX_USED)
00354       {
00355          //Notify the TCP/IP stack that the transmitter is ready to send
00356          flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
00357       }
00358    }
00359 
00360    //A packet has been received?
00361    if(rsr & (XEMACPS_RXSR_FRAMERX_MASK | XEMACPS_RXSR_ERROR_MASK))
00362    {
00363       //Set event flag
00364       nicDriverInterface->nicEvent = TRUE;
00365       //Notify the TCP/IP stack of the event
00366       flag |= osSetEventFromIsr(&netEvent);
00367    }
00368 
00369    //Flush packet if the receive buffer not available
00370    if (isr & XEMACPS_IXR_RXUSED_MASK)
00371       XEMACPS_NWCTRL |= XEMACPS_NWCTRL_FLUSH_DPRAM_MASK;
00372 
00373    //Leave interrupt service routine
00374    osExitIsr(flag);
00375 }
00376 
00377 
00378 /**
00379  * @brief Zynq-7000 Ethernet MAC event handler
00380  * @param[in] interface Underlying network interface
00381  **/
00382 
00383 void zynq7000EthEventHandler(NetInterface *interface)
00384 {
00385    error_t error;
00386    uint32_t rsr;
00387 
00388    //Read receive status
00389    rsr = XEMACPS_RXSR;
00390 
00391    //Packet received?
00392    if(rsr & (XEMACPS_RXSR_FRAMERX_MASK | XEMACPS_RXSR_ERROR_MASK))
00393    {
00394       //Only clear RSR flags that are currently set
00395       XEMACPS_RXSR = rsr;
00396 
00397       //Process all pending packets
00398       do
00399       {
00400          //Read incoming packet
00401          error = zynq7000EthReceivePacket(interface);
00402 
00403          //No more data in the receive buffer?
00404       } while(error != ERROR_BUFFER_EMPTY);
00405    }
00406 }
00407 
00408 
00409 /**
00410  * @brief Send a packet
00411  * @param[in] interface Underlying network interface
00412  * @param[in] buffer Multi-part buffer containing the data to send
00413  * @param[in] offset Offset to the first data byte
00414  * @return Error code
00415  **/
00416 
00417 error_t zynq7000EthSendPacket(NetInterface *interface,
00418    const NetBuffer *buffer, size_t offset)
00419 {
00420    static uint8_t temp[ZYNQ7000_ETH_TX_BUFFER_SIZE];
00421    size_t length;
00422 
00423    //Retrieve the length of the packet
00424    length = netBufferGetLength(buffer) - offset;
00425 
00426    //Check the frame length
00427    if(length > ZYNQ7000_ETH_TX_BUFFER_SIZE)
00428    {
00429       //The transmitter can accept another packet
00430       osSetEvent(&interface->nicTxEvent);
00431       //Report an error
00432       return ERROR_INVALID_LENGTH;
00433    }
00434 
00435    //Make sure the current buffer is available for writing
00436    if(!(txBufferDesc[txBufferIndex].status & XEMACPS_TX_USED))
00437       return ERROR_FAILURE;
00438 
00439    //Copy user data to the transmit buffer
00440    netBufferRead(temp, buffer, offset, length);
00441    memcpy(txBuffer[txBufferIndex], temp, length);
00442 
00443    //Set the necessary flags in the descriptor entry
00444    if(txBufferIndex < (ZYNQ7000_ETH_TX_BUFFER_COUNT - 1))
00445    {
00446       //Write the status word
00447       txBufferDesc[txBufferIndex].status =
00448          XEMACPS_TX_LAST | (length & XEMACPS_TX_LENGTH);
00449 
00450       //Point to the next buffer
00451       txBufferIndex++;
00452    }
00453    else
00454    {
00455       //Write the status word
00456       txBufferDesc[txBufferIndex].status = XEMACPS_TX_WRAP |
00457          XEMACPS_TX_LAST | (length & XEMACPS_TX_LENGTH);
00458 
00459       //Wrap around
00460       txBufferIndex = 0;
00461    }
00462 
00463    //Set the STARTTX bit to initiate transmission
00464    XEMACPS_NWCTRL |= XEMACPS_NWCTRL_STARTTX_MASK;
00465 
00466    //Check whether the next buffer is available for writing
00467    if(txBufferDesc[txBufferIndex].status & XEMACPS_TX_USED)
00468    {
00469       //The transmitter can accept another packet
00470       osSetEvent(&interface->nicTxEvent);
00471    }
00472 
00473    //Successful processing
00474    return NO_ERROR;
00475 }
00476 
00477 
00478 /**
00479  * @brief Receive a packet
00480  * @param[in] interface Underlying network interface
00481  * @return Error code
00482  **/
00483 
00484 error_t zynq7000EthReceivePacket(NetInterface *interface)
00485 {
00486    static uint8_t temp[ETH_MAX_FRAME_SIZE];
00487    error_t error;
00488    uint_t i;
00489    uint_t j;
00490    uint_t sofIndex;
00491    uint_t eofIndex;
00492    size_t n;
00493    size_t size;
00494    size_t length;
00495 
00496    //Initialize SOF and EOF indices
00497    sofIndex = UINT_MAX;
00498    eofIndex = UINT_MAX;
00499 
00500    //Search for SOF and EOF flags
00501    for(i = 0; i < ZYNQ7000_ETH_RX_BUFFER_COUNT; i++)
00502    {
00503       //Point to the current entry
00504       j = rxBufferIndex + i;
00505 
00506       //Wrap around to the beginning of the buffer if necessary
00507       if(j >= ZYNQ7000_ETH_RX_BUFFER_COUNT)
00508          j -= ZYNQ7000_ETH_RX_BUFFER_COUNT;
00509 
00510       //No more entries to process?
00511       if(!(rxBufferDesc[j].address & XEMACPS_RX_OWNERSHIP))
00512       {
00513          //Stop processing
00514          break;
00515       }
00516       //A valid SOF has been found?
00517       if(rxBufferDesc[j].status & XEMACPS_RX_SOF)
00518       {
00519          //Save the position of the SOF
00520          sofIndex = i;
00521       }
00522       //A valid EOF has been found?
00523       if((rxBufferDesc[j].status & XEMACPS_RX_EOF) && sofIndex != UINT_MAX)
00524       {
00525          //Save the position of the EOF
00526          eofIndex = i;
00527          //Retrieve the length of the frame
00528          size = rxBufferDesc[j].status & XEMACPS_RX_LENGTH;
00529          //Limit the number of data to read
00530          size = MIN(size, ETH_MAX_FRAME_SIZE);
00531          //Stop processing since we have reached the end of the frame
00532          break;
00533       }
00534    }
00535 
00536    //Determine the number of entries to process
00537    if(eofIndex != UINT_MAX)
00538       j = eofIndex + 1;
00539    else if(sofIndex != UINT_MAX)
00540       j = sofIndex;
00541    else
00542       j = i;
00543 
00544    //Total number of bytes that have been copied from the receive buffer
00545    length = 0;
00546 
00547    //Process incoming frame
00548    for(i = 0; i < j; i++)
00549    {
00550       //Any data to copy from current buffer?
00551       if(eofIndex != UINT_MAX && i >= sofIndex && i <= eofIndex)
00552       {
00553          //Calculate the number of bytes to read at a time
00554          n = MIN(size, ZYNQ7000_ETH_RX_BUFFER_SIZE);
00555          //Copy data from receive buffer
00556          memcpy(temp + length, rxBuffer[rxBufferIndex], n);
00557          //Update byte counters
00558          length += n;
00559          size -= n;
00560       }
00561 
00562       //Mark the current buffer as free
00563       rxBufferDesc[rxBufferIndex].address &= ~XEMACPS_RX_OWNERSHIP;
00564 
00565       //Point to the following entry
00566       rxBufferIndex++;
00567 
00568       //Wrap around to the beginning of the buffer if necessary
00569       if(rxBufferIndex >= ZYNQ7000_ETH_RX_BUFFER_COUNT)
00570          rxBufferIndex = 0;
00571    }
00572 
00573    //Any packet to process?
00574    if(length > 0)
00575    {
00576       //Pass the packet to the upper layer
00577       nicProcessPacket(interface, temp, length);
00578       //Valid packet received
00579       error = NO_ERROR;
00580    }
00581    else
00582    {
00583       //No more data in the receive buffer
00584       error = ERROR_BUFFER_EMPTY;
00585    }
00586 
00587    //Return status code
00588    return error;
00589 }
00590 
00591 
00592 /**
00593  * @brief Configure multicast MAC address filtering
00594  * @param[in] interface Underlying network interface
00595  * @return Error code
00596  **/
00597 
00598 error_t zynq7000EthSetMulticastFilter(NetInterface *interface)
00599 {
00600    uint_t i;
00601    uint_t k;
00602    uint8_t *p;
00603    uint32_t hashTable[2];
00604    MacFilterEntry *entry;
00605 
00606    //Debug message
00607    TRACE_DEBUG("Updating Zynq-7000 hash table...\r\n");
00608 
00609    //Clear hash table
00610    hashTable[0] = 0;
00611    hashTable[1] = 0;
00612 
00613    //The MAC filter table contains the multicast MAC addresses
00614    //to accept when receiving an Ethernet frame
00615    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00616    {
00617       //Point to the current entry
00618       entry = &interface->macMulticastFilter[i];
00619 
00620       //Valid entry?
00621       if(entry->refCount > 0)
00622       {
00623          //Point to the MAC address
00624          p = entry->addr.b;
00625 
00626          //Apply the hash function
00627          k = (p[0] >> 6) ^ p[0];
00628          k ^= (p[1] >> 4) ^ (p[1] << 2);
00629          k ^= (p[2] >> 2) ^ (p[2] << 4);
00630          k ^= (p[3] >> 6) ^ p[3];
00631          k ^= (p[4] >> 4) ^ (p[4] << 2);
00632          k ^= (p[5] >> 2) ^ (p[5] << 4);
00633 
00634          //The hash value is reduced to a 6-bit index
00635          k &= 0x3F;
00636 
00637          //Update hash table contents
00638          hashTable[k / 32] |= (1 << (k % 32));
00639       }
00640    }
00641 
00642    //Write the hash table
00643    XEMACPS_HASHL = hashTable[0];
00644    XEMACPS_HASHH = hashTable[1];
00645 
00646    //Debug message
00647    TRACE_DEBUG("  HASHL = %08" PRIX32 "\r\n", XEMACPS_HASHL);
00648    TRACE_DEBUG("  HASHH = %08" PRIX32 "\r\n", XEMACPS_HASHH);
00649 
00650    //Successful processing
00651    return NO_ERROR;
00652 }
00653 
00654 
00655 /**
00656  * @brief Adjust MAC configuration parameters for proper operation
00657  * @param[in] interface Underlying network interface
00658  * @return Error code
00659  **/
00660 
00661 error_t zynq7000EthUpdateMacConfig(NetInterface *interface)
00662 {
00663    uint32_t config;
00664    uint32_t clockCtrl;
00665 
00666    //Read network configuration register
00667    config = XEMACPS_NWCFG;
00668 
00669    //Read clock control register
00670    clockCtrl = XSLCR_GEM0_CLK_CTRL;
00671    clockCtrl &= ~(XSLCR_GEM0_CLK_CTRL_DIV1_MASK | XSLCR_GEM0_CLK_CTRL_DIV0_MASK);
00672 
00673    //1000BASE-T operation mode?
00674    if(interface->linkSpeed == NIC_LINK_SPEED_1GBPS)
00675    {
00676      //Update network configuration
00677       config |= XEMACPS_NWCFG_1000_MASK;
00678       config &= ~XEMACPS_NWCFG_100_MASK;
00679 
00680       //Update clock configuration
00681       clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK;
00682       clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK;
00683    }
00684    //100BASE-TX operation mode?
00685    else if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
00686    {
00687       //Update network configuration
00688       config &= ~XEMACPS_NWCFG_1000_MASK;
00689       config |= XEMACPS_NWCFG_100_MASK;
00690 
00691       //Update clock configuration
00692       clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK;
00693       clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK;
00694    }
00695    //10BASE-T operation mode?
00696    else
00697    {
00698       //Update network configuration
00699       config &= ~XEMACPS_NWCFG_1000_MASK;
00700       config &= ~XEMACPS_NWCFG_100_MASK;
00701 
00702       //Update clock configuration
00703       clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK;
00704       clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK;
00705    }
00706 
00707    //Half-duplex or full-duplex mode?
00708    if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
00709       config |= XEMACPS_NWCFG_FDEN_MASK;
00710    else
00711       config &= ~XEMACPS_NWCFG_FDEN_MASK;
00712 
00713    //Write network configuration register
00714    XEMACPS_NWCFG = config;
00715 
00716    //Unlock SLCR
00717    XSLCR_UNLOCK = XSLCR_UNLOCK_KEY_VALUE;
00718    //Write clock control register
00719    XSLCR_GEM0_CLK_CTRL = clockCtrl;
00720    //Lock SLCR
00721    XSLCR_LOCK = XSLCR_LOCK_KEY_VALUE;
00722 
00723    //Successful processing
00724    return NO_ERROR;
00725 }
00726 
00727 
00728 /**
00729  * @brief Write PHY register
00730  * @param[in] phyAddr PHY address
00731  * @param[in] regAddr Register address
00732  * @param[in] data Register value
00733  **/
00734 
00735 void zynq7000EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
00736 {
00737    uint32_t value;
00738 
00739    //Set up a write operation
00740    value = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_W_MASK;
00741    //PHY address
00742    value |= (phyAddr << 23) & XEMACPS_PHYMNTNC_ADDR_MASK;
00743    //Register address
00744    value |= (regAddr << 18) & XEMACPS_PHYMNTNC_REG_MASK;
00745    //Register value
00746    value |= data & XEMACPS_PHYMNTNC_DATA_MASK;
00747 
00748    //Start a write operation
00749    XEMACPS_PHYMNTNC = value;
00750    //Wait for the write to complete
00751    while(!(XEMACPS_NWSR & XEMACPS_NWSR_MDIOIDLE_MASK));
00752 }
00753 
00754 
00755 /**
00756  * @brief Read PHY register
00757  * @param[in] phyAddr PHY address
00758  * @param[in] regAddr Register address
00759  * @return Register value
00760  **/
00761 
00762 uint16_t zynq7000EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
00763 {
00764    uint32_t value;
00765 
00766    //Set up a read operation
00767    value = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_R_MASK;
00768    //PHY address
00769    value |= (phyAddr << 23) & XEMACPS_PHYMNTNC_ADDR_MASK;
00770    //Register address
00771    value |= (regAddr << 18) & XEMACPS_PHYMNTNC_REG_MASK;
00772 
00773    //Start a read operation
00774    XEMACPS_PHYMNTNC = value;
00775    //Wait for the read to complete
00776    while(!(XEMACPS_NWSR & XEMACPS_NWSR_MDIOIDLE_MASK));
00777 
00778    //Return PHY register contents
00779    return XEMACPS_PHYMNTNC & XEMACPS_PHYMNTNC_DATA_MASK;
00780 }
00781