Webserver+3d print
Diff: cyclone_tcp/drivers/zynq7000_eth.c
- Revision:
- 0:8918a71cdbe9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cyclone_tcp/drivers/zynq7000_eth.c Sat Feb 04 18:15:49 2017 +0000 @@ -0,0 +1,781 @@ +/** + * @file zynq7000_eth.c + * @brief Zynq-7000 Ethernet MAC controller + * + * @section License + * + * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneTCP Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 1.7.6 + **/ + +//Switch to the appropriate trace level +#define TRACE_LEVEL NIC_TRACE_LEVEL + +//Dependencies +#include <limits.h> +#include "xemacps_hw.h" +#include "xscugic.h" +#include "xil_misc_psreset_api.h" +#include "core/net.h" +#include "drivers/zynq7000_eth.h" +#include "debug.h" + +//Underlying network interface +static NetInterface *nicDriverInterface; + +//GIC instance +extern XScuGic ZYNQ7000_ETH_GIC_INSTANCE; + +//IAR EWARM compiler? +#if defined(__ICCARM__) + +//TX buffer +#pragma data_alignment = 8 +#pragma location = ".ram_no_cache" +static uint8_t txBuffer[ZYNQ7000_ETH_TX_BUFFER_COUNT][ZYNQ7000_ETH_TX_BUFFER_SIZE]; +//RX buffer +#pragma data_alignment = 8 +#pragma location = ".ram_no_cache" +static uint8_t rxBuffer[ZYNQ7000_ETH_RX_BUFFER_COUNT][ZYNQ7000_ETH_RX_BUFFER_SIZE]; +//TX buffer descriptors +#pragma data_alignment = 4 +#pragma location = ".ram_no_cache" +static Zynq7000TxBufferDesc txBufferDesc[ZYNQ7000_ETH_TX_BUFFER_COUNT]; +//RX buffer descriptors +#pragma data_alignment = 4 +#pragma location = ".ram_no_cache" +static Zynq7000RxBufferDesc rxBufferDesc[ZYNQ7000_ETH_RX_BUFFER_COUNT]; + +//Keil MDK-ARM or GCC compiler? +#else + +//TX buffer +static uint8_t txBuffer[ZYNQ7000_ETH_TX_BUFFER_COUNT][ZYNQ7000_ETH_TX_BUFFER_SIZE] + __attribute__((aligned(8), __section__(".ram_no_cache"))); +//RX buffer +static uint8_t rxBuffer[ZYNQ7000_ETH_RX_BUFFER_COUNT][ZYNQ7000_ETH_RX_BUFFER_SIZE] + __attribute__((aligned(8), __section__(".ram_no_cache"))); +//TX buffer descriptors +static Zynq7000TxBufferDesc txBufferDesc[ZYNQ7000_ETH_TX_BUFFER_COUNT] + __attribute__((aligned(4), __section__(".ram_no_cache"))); +//RX buffer descriptors +static Zynq7000RxBufferDesc rxBufferDesc[ZYNQ7000_ETH_RX_BUFFER_COUNT] + __attribute__((aligned(4), __section__(".ram_no_cache"))); + +#endif + +//TX buffer index +static uint_t txBufferIndex; +//RX buffer index +static uint_t rxBufferIndex; + + +/** + * @brief Zynq-7000 Ethernet MAC driver + **/ + +const NicDriver zynq7000EthDriver = +{ + NIC_TYPE_ETHERNET, + ETH_MTU, + zynq7000EthInit, + zynq7000EthTick, + zynq7000EthEnableIrq, + zynq7000EthDisableIrq, + zynq7000EthEventHandler, + zynq7000EthSendPacket, + zynq7000EthSetMulticastFilter, + zynq7000EthUpdateMacConfig, + zynq7000EthWritePhyReg, + zynq7000EthReadPhyReg, + TRUE, + TRUE, + TRUE, + FALSE +}; + + +/** + * @brief Zynq-7000 Ethernet MAC initialization + * @param[in] interface Underlying network interface + * @return Error code + **/ + +error_t zynq7000EthInit(NetInterface *interface) +{ + error_t error; + volatile uint32_t temp; + + //Debug message + TRACE_INFO("Initializing Zynq-7000 Ethernet MAC...\r\n"); + + //Save underlying network interface + nicDriverInterface = interface; + + //Unlock SLCR + XSLCR_UNLOCK = XSLCR_UNLOCK_KEY_VALUE; + + //Configure Ethernet controller reference clock + temp = XSLCR_GEM0_CLK_CTRL_CLKACT_MASK; + temp |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK; + temp |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK; + XSLCR_GEM0_CLK_CTRL = temp; + + //Enable Ethernet controller RX clock + XSLCR_GEM0_RCLK_CTRL = XSLCR_GEM0_RCLK_CTRL_CLKACT_MASK; + + //Lock SLCR + XSLCR_LOCK = XSLCR_LOCK_KEY_VALUE; + + //Clear network control register + XEMACPS_NWCTRL = 0; + //Clear statistics registers + XEMACPS_NWCTRL |= XEMACPS_NWCTRL_STATCLR_MASK; + + //Configure MDC clock speed + XEMACPS_NWCFG = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK) | XEMACPS_NWCFG_MDCCLKDIV_MASK; + //Enable management port (MDC and MDIO) + XEMACPS_NWCTRL |= XEMACPS_NWCTRL_MDEN_MASK; + + //PHY transceiver initialization + error = interface->phyDriver->init(interface); + //Failed to initialize PHY transceiver? + if(error) + return error; + + //Set the MAC address + XEMACPS_LADDR1L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16); + XEMACPS_LADDR1H = interface->macAddr.w[2]; + + //Configure the receive filter + XEMACPS_NWCFG |= XEMACPS_NWCFG_UCASTHASHEN_MASK | XEMACPS_NWCFG_MCASTHASHEN_MASK; + + //Initialize hash table + XEMACPS_HASHL = 0; + XEMACPS_HASHH = 0; + + //Initialize buffer descriptors + zynq7000EthInitBufferDesc(interface); + + //Set RX buffer size + temp = ((ZYNQ7000_ETH_RX_BUFFER_SIZE / 64) << XEMACPS_DMACR_RXBUF_SHIFT) & + XEMACPS_DMACR_RXBUF_MASK; + + //Use full configured addressable space for transmit and receive packet buffers + temp |= XEMACPS_DMACR_TXSIZE_MASK | XEMACPS_DMACR_RXSIZE_MASK; + //Select the burst length for DMA data operations + temp |= XEMACPS_DMACR_INCR16_AHB_BURST; + //Set DMA configuration register + XEMACPS_DMACR = temp; + + //Clear transmit status register + XEMACPS_TXSR = XEMACPS_TXSR_TXCOMPL_MASK | XEMACPS_TXSR_TXGO_MASK | + XEMACPS_TXSR_ERROR_MASK; + + //Clear receive status register + XEMACPS_RXSR = XEMACPS_RXSR_FRAMERX_MASK | XEMACPS_RXSR_ERROR_MASK; + + //First disable all interrupts + XEMACPS_IDR = 0xFFFFFFFF; + + //Only the desired ones are enabled + XEMACPS_IER = XEMACPS_IXR_HRESPNOK_MASK | XEMACPS_IXR_RXOVR_MASK | + XEMACPS_IXR_TXCOMPL_MASK | XEMACPS_IXR_TXEXH_MASK | XEMACPS_IXR_RETRY_MASK | + XEMACPS_IXR_URUN_MASK | XEMACPS_IXR_RXUSED_MASK | XEMACPS_IXR_FRAMERX_MASK; + + //Read interrupt status register to clear any pending interrupt + temp = XEMACPS_ISR; + + //Register interrupt handler + XScuGic_Connect(&ZYNQ7000_ETH_GIC_INSTANCE, XPS_GEM0_INT_ID, + (Xil_InterruptHandler) zynq7000EthIrqHandler, interface); + + //Configure interrupt priority + XScuGic_SetPriorityTriggerType(&ZYNQ7000_ETH_GIC_INSTANCE, + XPS_GEM0_INT_ID, ZYNQ7000_ETH_IRQ_PRIORITY, 1); + + //Enable the transmitter and the receiver + XEMACPS_NWCTRL |= XEMACPS_NWCTRL_TXEN_MASK | XEMACPS_NWCTRL_RXEN_MASK; + + //Accept any packets from the upper layer + osSetEvent(&interface->nicTxEvent); + + //Successful initialization + return NO_ERROR; +} + + +/** + * @brief Initialize buffer descriptors + * @param[in] interface Underlying network interface + **/ + +void zynq7000EthInitBufferDesc(NetInterface *interface) +{ + uint_t i; + uint32_t address; + + //Initialize TX buffer descriptors + for(i = 0; i < ZYNQ7000_ETH_TX_BUFFER_COUNT; i++) + { + //Calculate the address of the current TX buffer + address = (uint32_t) txBuffer[i]; + //Write the address to the descriptor entry + txBufferDesc[i].address = address; + //Initialize status field + txBufferDesc[i].status = XEMACPS_TX_USED; + } + + //Mark the last descriptor entry with the wrap flag + txBufferDesc[i - 1].status |= XEMACPS_TX_WRAP; + //Initialize TX buffer index + txBufferIndex = 0; + + //Initialize RX buffer descriptors + for(i = 0; i < ZYNQ7000_ETH_RX_BUFFER_COUNT; i++) + { + //Calculate the address of the current RX buffer + address = (uint32_t) rxBuffer[i]; + //Write the address to the descriptor entry + rxBufferDesc[i].address = address & XEMACPS_RX_ADDRESS; + //Clear status field + rxBufferDesc[i].status = 0; + } + + //Mark the last descriptor entry with the wrap flag + rxBufferDesc[i - 1].address |= XEMACPS_RX_WRAP; + //Initialize RX buffer index + rxBufferIndex = 0; + + //Start location of the TX descriptor list + XEMACPS_TXQBASE = (uint32_t) txBufferDesc; + //Start location of the RX descriptor list + XEMACPS_RXQBASE = (uint32_t) rxBufferDesc; +} + + +/** + * @brief Zynq-7000 Ethernet MAC timer handler + * + * This routine is periodically called by the TCP/IP stack to + * handle periodic operations such as polling the link state + * + * @param[in] interface Underlying network interface + **/ + +void zynq7000EthTick(NetInterface *interface) +{ + //Handle periodic operations + interface->phyDriver->tick(interface); +} + + +/** + * @brief Enable interrupts + * @param[in] interface Underlying network interface + **/ + +void zynq7000EthEnableIrq(NetInterface *interface) +{ + //Enable Ethernet MAC interrupts + XScuGic_Enable(&ZYNQ7000_ETH_GIC_INSTANCE, XPS_GEM0_INT_ID); + //Enable Ethernet PHY interrupts + interface->phyDriver->enableIrq(interface); +} + + +/** + * @brief Disable interrupts + * @param[in] interface Underlying network interface + **/ + +void zynq7000EthDisableIrq(NetInterface *interface) +{ + //Disable Ethernet MAC interrupts + XScuGic_Disable(&ZYNQ7000_ETH_GIC_INSTANCE, XPS_GEM0_INT_ID); + //Disable Ethernet PHY interrupts + interface->phyDriver->disableIrq(interface); +} + + +/** + * @brief Zynq-7000 Ethernet MAC interrupt service routine + * @param[in] interface Underlying network interface + **/ + +void zynq7000EthIrqHandler(NetInterface *interface) +{ + bool_t flag; + volatile uint32_t isr; + volatile uint32_t tsr; + volatile uint32_t rsr; + + //Enter interrupt service routine + osEnterIsr(); + + //This flag will be set if a higher priority task must be woken + flag = FALSE; + + //Each time the software reads XEMACPS_ISR, it has to check the + //contents of XEMACPS_TXSR, XEMACPS_RXSR + isr = XEMACPS_ISR; + tsr = XEMACPS_TXSR; + rsr = XEMACPS_RXSR; + + //Clear interrupt flags + XEMACPS_ISR = isr; + + //A packet has been transmitted? + if(tsr & (XEMACPS_TXSR_TXCOMPL_MASK | XEMACPS_TXSR_TXGO_MASK | XEMACPS_TXSR_ERROR_MASK)) + { + //Only clear TSR flags that are currently set + XEMACPS_TXSR = tsr; + + //Check whether the TX buffer is available for writing + if(txBufferDesc[txBufferIndex].status & XEMACPS_TX_USED) + { + //Notify the TCP/IP stack that the transmitter is ready to send + flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent); + } + } + + //A packet has been received? + if(rsr & (XEMACPS_RXSR_FRAMERX_MASK | XEMACPS_RXSR_ERROR_MASK)) + { + //Set event flag + nicDriverInterface->nicEvent = TRUE; + //Notify the TCP/IP stack of the event + flag |= osSetEventFromIsr(&netEvent); + } + + //Flush packet if the receive buffer not available + if (isr & XEMACPS_IXR_RXUSED_MASK) + XEMACPS_NWCTRL |= XEMACPS_NWCTRL_FLUSH_DPRAM_MASK; + + //Leave interrupt service routine + osExitIsr(flag); +} + + +/** + * @brief Zynq-7000 Ethernet MAC event handler + * @param[in] interface Underlying network interface + **/ + +void zynq7000EthEventHandler(NetInterface *interface) +{ + error_t error; + uint32_t rsr; + + //Read receive status + rsr = XEMACPS_RXSR; + + //Packet received? + if(rsr & (XEMACPS_RXSR_FRAMERX_MASK | XEMACPS_RXSR_ERROR_MASK)) + { + //Only clear RSR flags that are currently set + XEMACPS_RXSR = rsr; + + //Process all pending packets + do + { + //Read incoming packet + error = zynq7000EthReceivePacket(interface); + + //No more data in the receive buffer? + } while(error != ERROR_BUFFER_EMPTY); + } +} + + +/** + * @brief Send a packet + * @param[in] interface Underlying network interface + * @param[in] buffer Multi-part buffer containing the data to send + * @param[in] offset Offset to the first data byte + * @return Error code + **/ + +error_t zynq7000EthSendPacket(NetInterface *interface, + const NetBuffer *buffer, size_t offset) +{ + static uint8_t temp[ZYNQ7000_ETH_TX_BUFFER_SIZE]; + size_t length; + + //Retrieve the length of the packet + length = netBufferGetLength(buffer) - offset; + + //Check the frame length + if(length > ZYNQ7000_ETH_TX_BUFFER_SIZE) + { + //The transmitter can accept another packet + osSetEvent(&interface->nicTxEvent); + //Report an error + return ERROR_INVALID_LENGTH; + } + + //Make sure the current buffer is available for writing + if(!(txBufferDesc[txBufferIndex].status & XEMACPS_TX_USED)) + return ERROR_FAILURE; + + //Copy user data to the transmit buffer + netBufferRead(temp, buffer, offset, length); + memcpy(txBuffer[txBufferIndex], temp, length); + + //Set the necessary flags in the descriptor entry + if(txBufferIndex < (ZYNQ7000_ETH_TX_BUFFER_COUNT - 1)) + { + //Write the status word + txBufferDesc[txBufferIndex].status = + XEMACPS_TX_LAST | (length & XEMACPS_TX_LENGTH); + + //Point to the next buffer + txBufferIndex++; + } + else + { + //Write the status word + txBufferDesc[txBufferIndex].status = XEMACPS_TX_WRAP | + XEMACPS_TX_LAST | (length & XEMACPS_TX_LENGTH); + + //Wrap around + txBufferIndex = 0; + } + + //Set the STARTTX bit to initiate transmission + XEMACPS_NWCTRL |= XEMACPS_NWCTRL_STARTTX_MASK; + + //Check whether the next buffer is available for writing + if(txBufferDesc[txBufferIndex].status & XEMACPS_TX_USED) + { + //The transmitter can accept another packet + osSetEvent(&interface->nicTxEvent); + } + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Receive a packet + * @param[in] interface Underlying network interface + * @return Error code + **/ + +error_t zynq7000EthReceivePacket(NetInterface *interface) +{ + static uint8_t temp[ETH_MAX_FRAME_SIZE]; + error_t error; + uint_t i; + uint_t j; + uint_t sofIndex; + uint_t eofIndex; + size_t n; + size_t size; + size_t length; + + //Initialize SOF and EOF indices + sofIndex = UINT_MAX; + eofIndex = UINT_MAX; + + //Search for SOF and EOF flags + for(i = 0; i < ZYNQ7000_ETH_RX_BUFFER_COUNT; i++) + { + //Point to the current entry + j = rxBufferIndex + i; + + //Wrap around to the beginning of the buffer if necessary + if(j >= ZYNQ7000_ETH_RX_BUFFER_COUNT) + j -= ZYNQ7000_ETH_RX_BUFFER_COUNT; + + //No more entries to process? + if(!(rxBufferDesc[j].address & XEMACPS_RX_OWNERSHIP)) + { + //Stop processing + break; + } + //A valid SOF has been found? + if(rxBufferDesc[j].status & XEMACPS_RX_SOF) + { + //Save the position of the SOF + sofIndex = i; + } + //A valid EOF has been found? + if((rxBufferDesc[j].status & XEMACPS_RX_EOF) && sofIndex != UINT_MAX) + { + //Save the position of the EOF + eofIndex = i; + //Retrieve the length of the frame + size = rxBufferDesc[j].status & XEMACPS_RX_LENGTH; + //Limit the number of data to read + size = MIN(size, ETH_MAX_FRAME_SIZE); + //Stop processing since we have reached the end of the frame + break; + } + } + + //Determine the number of entries to process + if(eofIndex != UINT_MAX) + j = eofIndex + 1; + else if(sofIndex != UINT_MAX) + j = sofIndex; + else + j = i; + + //Total number of bytes that have been copied from the receive buffer + length = 0; + + //Process incoming frame + for(i = 0; i < j; i++) + { + //Any data to copy from current buffer? + if(eofIndex != UINT_MAX && i >= sofIndex && i <= eofIndex) + { + //Calculate the number of bytes to read at a time + n = MIN(size, ZYNQ7000_ETH_RX_BUFFER_SIZE); + //Copy data from receive buffer + memcpy(temp + length, rxBuffer[rxBufferIndex], n); + //Update byte counters + length += n; + size -= n; + } + + //Mark the current buffer as free + rxBufferDesc[rxBufferIndex].address &= ~XEMACPS_RX_OWNERSHIP; + + //Point to the following entry + rxBufferIndex++; + + //Wrap around to the beginning of the buffer if necessary + if(rxBufferIndex >= ZYNQ7000_ETH_RX_BUFFER_COUNT) + rxBufferIndex = 0; + } + + //Any packet to process? + if(length > 0) + { + //Pass the packet to the upper layer + nicProcessPacket(interface, temp, length); + //Valid packet received + error = NO_ERROR; + } + else + { + //No more data in the receive buffer + error = ERROR_BUFFER_EMPTY; + } + + //Return status code + return error; +} + + +/** + * @brief Configure multicast MAC address filtering + * @param[in] interface Underlying network interface + * @return Error code + **/ + +error_t zynq7000EthSetMulticastFilter(NetInterface *interface) +{ + uint_t i; + uint_t k; + uint8_t *p; + uint32_t hashTable[2]; + MacFilterEntry *entry; + + //Debug message + TRACE_DEBUG("Updating Zynq-7000 hash table...\r\n"); + + //Clear hash table + hashTable[0] = 0; + hashTable[1] = 0; + + //The MAC filter table contains the multicast MAC addresses + //to accept when receiving an Ethernet frame + for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++) + { + //Point to the current entry + entry = &interface->macMulticastFilter[i]; + + //Valid entry? + if(entry->refCount > 0) + { + //Point to the MAC address + p = entry->addr.b; + + //Apply the hash function + k = (p[0] >> 6) ^ p[0]; + k ^= (p[1] >> 4) ^ (p[1] << 2); + k ^= (p[2] >> 2) ^ (p[2] << 4); + k ^= (p[3] >> 6) ^ p[3]; + k ^= (p[4] >> 4) ^ (p[4] << 2); + k ^= (p[5] >> 2) ^ (p[5] << 4); + + //The hash value is reduced to a 6-bit index + k &= 0x3F; + + //Update hash table contents + hashTable[k / 32] |= (1 << (k % 32)); + } + } + + //Write the hash table + XEMACPS_HASHL = hashTable[0]; + XEMACPS_HASHH = hashTable[1]; + + //Debug message + TRACE_DEBUG(" HASHL = %08" PRIX32 "\r\n", XEMACPS_HASHL); + TRACE_DEBUG(" HASHH = %08" PRIX32 "\r\n", XEMACPS_HASHH); + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Adjust MAC configuration parameters for proper operation + * @param[in] interface Underlying network interface + * @return Error code + **/ + +error_t zynq7000EthUpdateMacConfig(NetInterface *interface) +{ + uint32_t config; + uint32_t clockCtrl; + + //Read network configuration register + config = XEMACPS_NWCFG; + + //Read clock control register + clockCtrl = XSLCR_GEM0_CLK_CTRL; + clockCtrl &= ~(XSLCR_GEM0_CLK_CTRL_DIV1_MASK | XSLCR_GEM0_CLK_CTRL_DIV0_MASK); + + //1000BASE-T operation mode? + if(interface->linkSpeed == NIC_LINK_SPEED_1GBPS) + { + //Update network configuration + config |= XEMACPS_NWCFG_1000_MASK; + config &= ~XEMACPS_NWCFG_100_MASK; + + //Update clock configuration + clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK; + clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK; + } + //100BASE-TX operation mode? + else if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS) + { + //Update network configuration + config &= ~XEMACPS_NWCFG_1000_MASK; + config |= XEMACPS_NWCFG_100_MASK; + + //Update clock configuration + clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK; + clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK; + } + //10BASE-T operation mode? + else + { + //Update network configuration + config &= ~XEMACPS_NWCFG_1000_MASK; + config &= ~XEMACPS_NWCFG_100_MASK; + + //Update clock configuration + clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1 << 20) & XSLCR_GEM0_CLK_CTRL_DIV1_MASK; + clockCtrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 << 8) & XSLCR_GEM0_CLK_CTRL_DIV0_MASK; + } + + //Half-duplex or full-duplex mode? + if(interface->duplexMode == NIC_FULL_DUPLEX_MODE) + config |= XEMACPS_NWCFG_FDEN_MASK; + else + config &= ~XEMACPS_NWCFG_FDEN_MASK; + + //Write network configuration register + XEMACPS_NWCFG = config; + + //Unlock SLCR + XSLCR_UNLOCK = XSLCR_UNLOCK_KEY_VALUE; + //Write clock control register + XSLCR_GEM0_CLK_CTRL = clockCtrl; + //Lock SLCR + XSLCR_LOCK = XSLCR_LOCK_KEY_VALUE; + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Write PHY register + * @param[in] phyAddr PHY address + * @param[in] regAddr Register address + * @param[in] data Register value + **/ + +void zynq7000EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data) +{ + uint32_t value; + + //Set up a write operation + value = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_W_MASK; + //PHY address + value |= (phyAddr << 23) & XEMACPS_PHYMNTNC_ADDR_MASK; + //Register address + value |= (regAddr << 18) & XEMACPS_PHYMNTNC_REG_MASK; + //Register value + value |= data & XEMACPS_PHYMNTNC_DATA_MASK; + + //Start a write operation + XEMACPS_PHYMNTNC = value; + //Wait for the write to complete + while(!(XEMACPS_NWSR & XEMACPS_NWSR_MDIOIDLE_MASK)); +} + + +/** + * @brief Read PHY register + * @param[in] phyAddr PHY address + * @param[in] regAddr Register address + * @return Register value + **/ + +uint16_t zynq7000EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr) +{ + uint32_t value; + + //Set up a read operation + value = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_R_MASK; + //PHY address + value |= (phyAddr << 23) & XEMACPS_PHYMNTNC_ADDR_MASK; + //Register address + value |= (regAddr << 18) & XEMACPS_PHYMNTNC_REG_MASK; + + //Start a read operation + XEMACPS_PHYMNTNC = value; + //Wait for the read to complete + while(!(XEMACPS_NWSR & XEMACPS_NWSR_MDIOIDLE_MASK)); + + //Return PHY register contents + return XEMACPS_PHYMNTNC & XEMACPS_PHYMNTNC_DATA_MASK; +} +