/* ---------------------------------------------------------------------------- | |
* SAM Software Package License | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2011, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/** \file */ | |
/*--------------------------------------------------------------------------- | |
* Headers | |
*---------------------------------------------------------------------------*/ | |
#include <board.h> | |
/*--------------------------------------------------------------------------- | |
* Definitions | |
*---------------------------------------------------------------------------*/ | |
/** Default max retry count */ | |
#define MACB_RETRY_MAX 1000000 | |
/*--------------------------------------------------------------------------- | |
* Local functions | |
*---------------------------------------------------------------------------*/ | |
/** | |
* Wait PHY operation complete. | |
* Return 1 if the operation completed successfully. | |
* May be need to re-implemented to reduce CPU load. | |
* \param retry: the retry times, 0 to wait forever until complete. | |
*/ | |
static uint8_t EMAC_WaitPhy( Emac *pHw, uint32_t retry ) | |
{ | |
volatile uint32_t retry_count = 0; | |
while (!EMAC_IsIdle(pHw)) | |
{ | |
if(retry == 0) continue; | |
retry_count ++; | |
if (retry_count >= retry) | |
{ | |
return 0; | |
} | |
} | |
return 1; | |
} | |
/** | |
* Read PHY register. | |
* Return 1 if successfully, 0 if timeout. | |
* \param pHw HW controller address | |
* \param PhyAddress PHY Address | |
* \param Address Register Address | |
* \param pValue Pointer to a 32 bit location to store read data | |
* \param retry The retry times, 0 to wait forever until complete. | |
*/ | |
static uint8_t EMAC_ReadPhy(Emac *pHw, | |
uint8_t PhyAddress, | |
uint8_t Address, | |
uint32_t *pValue, | |
uint32_t retry) | |
{ | |
EMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0); | |
if ( EMAC_WaitPhy(pHw, retry) == 0 ) | |
{ | |
TRACE_ERROR("TimeOut EMAC_ReadPhy\n\r"); | |
return 0; | |
} | |
*pValue = EMAC_PHYData(pHw); | |
return 1; | |
} | |
/** | |
* Write PHY register | |
* Return 1 if successfully, 0 if timeout. | |
* \param pHw HW controller address | |
* \param PhyAddress PHY Address | |
* \param Address Register Address | |
* \param Value Data to write ( Actually 16 bit data ) | |
* \param retry The retry times, 0 to wait forever until complete. | |
*/ | |
static uint8_t EMAC_WritePhy(Emac *pHw, | |
uint8_t PhyAddress, | |
uint8_t Address, | |
uint32_t Value, | |
uint32_t retry) | |
{ | |
EMAC_PHYMaintain(pHw, PhyAddress, Address, 0, Value); | |
if ( EMAC_WaitPhy(pHw, retry) == 0 ) | |
{ | |
TRACE_ERROR("TimeOut EMAC_WritePhy\n\r"); | |
return 0; | |
} | |
return 1; | |
} | |
/*--------------------------------------------------------------------------- | |
* Exported functions | |
*---------------------------------------------------------------------------*/ | |
/** | |
* Find a valid PHY Address ( from addrStart to 31 ). | |
* Check BMSR register ( not 0 nor 0xFFFF ) | |
* Return 0xFF when no valid PHY Address found. | |
* \param pMacb Pointer to the MACB instance | |
*/ | |
uint8_t MACB_FindValidPhy(Macb *pMacb, uint8_t addrStart) | |
{ | |
sEmacd *pDrv = pMacb->pEmacd; | |
Emac *pHw = pDrv->pHw; | |
uint32_t retryMax; | |
uint32_t value=0; | |
uint8_t rc; | |
uint8_t phyAddress; | |
uint8_t cnt; | |
TRACE_DEBUG("MACB_FindValidPhy\n\r"); | |
EMAC_ManagementEnable(pHw, 1); | |
phyAddress = pMacb->phyAddress; | |
retryMax = pMacb->retryMax; | |
/* Check current phyAddress */ | |
rc = phyAddress; | |
if( EMAC_ReadPhy(pHw, phyAddress, MII_PHYID1, &value, retryMax) == 0 ) | |
{ | |
TRACE_ERROR("MACB PROBLEM\n\r"); | |
} | |
TRACE_DEBUG("_PHYID1 : 0x%X, addr: %d\n\r", value, phyAddress); | |
/* Find another one */ | |
if (value != MII_OUI_MSB) | |
{ | |
rc = 0xFF; | |
for(cnt = 0; cnt < 32; cnt ++) | |
{ | |
phyAddress = (phyAddress + 1) & 0x1F; | |
if( EMAC_ReadPhy(pHw, phyAddress, MII_PHYID1, &value, retryMax) == 0 ) | |
{ | |
TRACE_ERROR("MACB PROBLEM\n\r"); | |
} | |
TRACE_DEBUG("_PHYID1 : 0x%X, addr: %d\n\r", value, phyAddress); | |
if (value == MII_OUI_MSB) | |
{ | |
rc = phyAddress; | |
break; | |
} | |
} | |
} | |
EMAC_ManagementEnable(pHw, 0); | |
if (rc != 0xFF) | |
{ | |
printf("** Valid PHY Found: %d\n\r", rc); | |
EMAC_ReadPhy(pHw, phyAddress, MII_DSCSR, &value, retryMax); | |
TRACE_DEBUG("_DSCSR : 0x%X, addr: %d\n\r", value, phyAddress); | |
} | |
return rc; | |
} | |
/** | |
* Dump all the useful registers | |
* \param pMacb Pointer to the MACB instance | |
*/ | |
void MACB_DumpRegisters(Macb *pMacb) | |
{ | |
sEmacd *pDrv = pMacb->pEmacd; | |
Emac *pHw = pDrv->pHw; | |
uint8_t phyAddress; | |
uint32_t retryMax; | |
uint32_t value; | |
TRACE_INFO("MACB_DumpRegisters\n\r"); | |
EMAC_ManagementEnable(pHw, 1); | |
phyAddress = pMacb->phyAddress; | |
retryMax = pMacb->retryMax; | |
TRACE_INFO("%cMII MACB (@%d) Registers:\n\r", | |
pMacb->RMII ? 'R' : ' ', | |
phyAddress); | |
EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &value, retryMax); | |
TRACE_INFO(" _BMCR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_BMSR, &value, retryMax); | |
TRACE_INFO(" _BMSR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_ANAR, &value, retryMax); | |
TRACE_INFO(" _ANAR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_ANLPAR, &value, retryMax); | |
TRACE_INFO(" _ANLPAR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_ANER, &value, retryMax); | |
TRACE_INFO(" _ANER : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_DSCR, &value, retryMax); | |
TRACE_INFO(" _DSCR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_DSCSR, &value, retryMax); | |
TRACE_INFO(" _DSCSR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_10BTCSR, &value, retryMax); | |
TRACE_INFO(" _10BTCSR: 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_PWDOR, &value, retryMax); | |
TRACE_INFO(" _PWDOR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_CONFIGR, &value, retryMax); | |
TRACE_INFO(" _CONFIGR: 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_MDINTR, &value, retryMax); | |
TRACE_INFO(" _MDINTR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_RECR, &value, retryMax); | |
TRACE_INFO(" _RECR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_DISCR, &value, retryMax); | |
TRACE_INFO(" _DISCR : 0x%X\n\r", value); | |
EMAC_ReadPhy(pHw, phyAddress, MII_RLSR, &value, retryMax); | |
TRACE_INFO(" _RLSR : 0x%X\n\r", value); | |
EMAC_ManagementEnable(pHw, 0); | |
} | |
/** | |
* Setup the maximum timeout count of the driver. | |
* \param pMacb Pointer to the MACB instance | |
* \param toMax Timeout maxmum count. | |
*/ | |
void MACB_SetupTimeout(Macb *pMacb, uint32_t toMax) | |
{ | |
pMacb->retryMax = toMax; | |
} | |
/** | |
* Initialize the MACB instance | |
* \param pMacb Pointer to the MACB instance | |
* \param pEmac Pointer to the Emac instance for the MACB | |
* \param phyAddress The PHY address used to access the PHY | |
* ( pre-defined by pin status on PHY reset ) | |
*/ | |
void MACB_Init(Macb *pMacb, sEmacd *pEmacd, uint8_t phyAddress) | |
{ | |
pMacb->pEmacd = pEmacd; | |
pMacb->phyAddress = phyAddress; | |
/* Initialize timeout by default */ | |
pMacb->retryMax = MACB_RETRY_MAX; | |
} | |
/** | |
* Issue a SW reset to reset all registers of the PHY | |
* Return 1 if successfully, 0 if timeout. | |
* \param pMacb Pointer to the MACB instance | |
*/ | |
uint8_t MACB_ResetPhy(Macb *pMacb) | |
{ | |
sEmacd *pDrv = pMacb->pEmacd; | |
Emac *pHw = pDrv->pHw; | |
uint32_t retryMax; | |
uint32_t bmcr = MII_RESET; | |
uint8_t phyAddress; | |
uint32_t timeout = 10; | |
uint8_t ret = 1; | |
TRACE_INFO(" MACB_ResetPhy\n\r"); | |
phyAddress = pMacb->phyAddress; | |
retryMax = pMacb->retryMax; | |
EMAC_ManagementEnable(pHw, 1); | |
bmcr = MII_RESET; | |
EMAC_WritePhy(pHw, phyAddress, MII_BMCR, bmcr, retryMax); | |
do | |
{ | |
EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &bmcr, retryMax); | |
timeout--; | |
} while ((bmcr & MII_RESET) && timeout); | |
EMAC_ManagementEnable(pHw, 0); | |
if (!timeout) | |
{ | |
ret = 0; | |
} | |
return( ret ); | |
} | |
/** | |
* Do a HW initialize to the PHY ( via RSTC ) and setup clocks & PIOs | |
* This should be called only once to initialize the PHY pre-settings. | |
* The PHY address is reset status of CRS,RXD[3:0] (the emacPins' pullups). | |
* The COL pin is used to select MII mode on reset (pulled up for Reduced MII) | |
* The RXDV pin is used to select test mode on reset (pulled up for test mode) | |
* The above pins should be predefined for corresponding settings in resetPins | |
* The EMAC peripheral pins are configured after the reset done. | |
* Return 1 if RESET OK, 0 if timeout. | |
* \param pMacb Pointer to the MACB instance | |
* \param mck Main clock setting to initialize clock | |
* \param resetPins Pointer to list of PIOs to configure before HW RESET | |
* (for PHY power on reset configuration latch) | |
* \param nbResetPins Number of PIO items that should be configured | |
* \param emacPins Pointer to list of PIOs for the EMAC interface | |
* \param nbEmacPins Number of PIO items that should be configured | |
*/ | |
uint8_t MACB_InitPhy(Macb *pMacb, | |
uint32_t mck, | |
const Pin *pResetPins, | |
uint32_t nbResetPins, | |
const Pin *pEmacPins, | |
uint32_t nbEmacPins) | |
{ | |
sEmacd *pDrv = pMacb->pEmacd; | |
Emac *pHw = pDrv->pHw; | |
uint8_t rc = 1; | |
uint8_t phy; | |
/* Perform RESET */ | |
TRACE_DEBUG("RESET PHY\n\r"); | |
if (pResetPins) | |
{ | |
/* Configure PINS */ | |
PIO_Configure(pResetPins, nbResetPins); | |
/* Execute reset */ | |
RSTC_SetExtResetLength(MACB_RESET_LENGTH); | |
RSTC_ExtReset(); | |
/* Get NRST level */ | |
/* Wait for end hardware reset */ | |
while (!RSTC_GetNrstLevel()); | |
} | |
/* Configure EMAC runtime pins */ | |
if (rc) | |
{ | |
PIO_Configure(pEmacPins, nbEmacPins); | |
rc = EMAC_SetClock( pHw, mck ); | |
if (!rc) | |
{ | |
TRACE_ERROR("No Valid MDC clock\n\r"); | |
return 0; | |
} | |
/* Check PHY Address */ | |
phy = MACB_FindValidPhy(pMacb, 0); | |
if (phy == 0xFF) | |
{ | |
TRACE_ERROR("PHY Access fail\n\r"); | |
return 0; | |
} | |
if(phy != pMacb->phyAddress) | |
{ | |
pMacb->phyAddress = phy; | |
MACB_ResetPhy(pMacb); | |
} | |
} | |
else | |
{ | |
TRACE_ERROR("PHY Reset Timeout\n\r"); | |
} | |
return rc; | |
} | |
/** | |
* Issue a Auto Negotiation of the PHY | |
* Return 1 if successfully, 0 if timeout. | |
* \param pMacb Pointer to the MACB instance | |
*/ | |
uint8_t MACB_AutoNegotiate(Macb *pMacb, uint8_t rmiiMode) | |
{ | |
sEmacd *pDrv = pMacb->pEmacd; | |
Emac *pHw = pDrv->pHw; | |
uint32_t retryMax; | |
uint32_t value; | |
uint32_t phyAnar; | |
uint32_t phyAnalpar; | |
uint32_t retryCount= 0; | |
uint8_t phyAddress; | |
uint8_t bFD = 0; | |
uint8_t bSP = 0; | |
uint8_t rc = 1; | |
pMacb->RMII = rmiiMode; | |
phyAddress = pMacb->phyAddress; | |
retryMax = pMacb->retryMax; | |
EMAC_ManagementEnable(pHw, 1); | |
if (!EMAC_ReadPhy(pHw, phyAddress, MII_PHYID1, &value, retryMax)) | |
{ | |
TRACE_ERROR("Pb EMAC_ReadPhy Id1\n\r"); | |
rc = 0; | |
goto AutoNegotiateExit; | |
} | |
TRACE_DEBUG("ReadPhy Id1 0x%X, addresse: %d\n\r", value, phyAddress); | |
if (!EMAC_ReadPhy(pHw, phyAddress, MII_PHYID2, &phyAnar, retryMax)) | |
{ | |
TRACE_ERROR("Pb EMAC_ReadPhy Id2\n\r"); | |
rc = 0; | |
goto AutoNegotiateExit; | |
} | |
TRACE_DEBUG("ReadPhy Id2 0x%X\n\r", phyAnar); | |
if( ( value == MII_OUI_MSB ) | |
&& ( ((phyAnar>>10)&MII_LSB_MASK) == MII_OUI_LSB ) ) | |
{ | |
TRACE_DEBUG("Vendor Number Model = 0x%X\n\r", ((phyAnar>>4)&0x3F)); | |
TRACE_DEBUG("Model Revision Number = 0x%X\n\r", (phyAnar&0x7)); | |
} | |
else | |
{ | |
TRACE_ERROR("Problem OUI value\n\r"); | |
} | |
/* Setup control register */ | |
rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &value, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
value &= ~MII_AUTONEG; /* Remove autonegotiation enable */ | |
value &= ~(MII_LOOPBACK|MII_POWER_DOWN); | |
value |= MII_ISOLATE; /* Electrically isolate PHY */ | |
rc = EMAC_WritePhy(pHw, phyAddress, MII_BMCR, value, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
/* Set the Auto_negotiation Advertisement Register | |
MII advertising for Next page | |
100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3 */ | |
phyAnar = MII_TX_FDX | MII_TX_HDX | | |
MII_10_FDX | MII_10_HDX | MII_AN_IEEE_802_3; | |
rc = EMAC_WritePhy(pHw, phyAddress, MII_ANAR, phyAnar, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
/* Read & modify control register */ | |
rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &value, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
value |= MII_SPEED_SELECT | MII_AUTONEG | MII_DUPLEX_MODE; | |
rc = EMAC_WritePhy(pHw, phyAddress, MII_BMCR, value, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
/* Restart Auto_negotiation */ | |
value |= MII_RESTART_AUTONEG; | |
value &= ~MII_ISOLATE; | |
rc = EMAC_WritePhy(pHw, phyAddress, MII_BMCR, value, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
TRACE_DEBUG(" _BMCR: 0x%X\n\r", value); | |
/* Check AutoNegotiate complete */ | |
while (1) | |
{ | |
rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMSR, &value, retryMax); | |
if (rc == 0) | |
{ | |
TRACE_ERROR("_BMSR Rd err\n\r"); | |
goto AutoNegotiateExit; | |
} | |
/* Done successfully */ | |
if (value & MII_AUTONEG_COMP) | |
{ | |
printf("AutoNegotiate complete\n\r"); | |
break; | |
} | |
/* Timeout check */ | |
if (retryMax) | |
{ | |
if (++ retryCount >= retryMax) | |
{ | |
MACB_DumpRegisters(pMacb); | |
TRACE_ERROR("TimeOut\n\r"); | |
rc = 0; | |
goto AutoNegotiateExit; | |
} | |
} | |
} | |
/* Get the AutoNeg Link partner base page */ | |
rc = EMAC_ReadPhy(pHw, phyAddress, MII_ANLPAR, &phyAnalpar, retryMax); | |
if (rc == 0) | |
{ | |
goto AutoNegotiateExit; | |
} | |
/* Setup the EMAC link speed */ | |
if ((phyAnar & phyAnalpar) & MII_TX_FDX) | |
{ | |
/* set MII for 100BaseTX and Full Duplex */ | |
bSP = 1; bFD = 1; | |
} | |
else if ((phyAnar & phyAnalpar) & MII_10_FDX) | |
{ | |
/* set MII for 10BaseT and Full Duplex */ | |
bSP = 0; bFD = 1; | |
} | |
else if ((phyAnar & phyAnalpar) & MII_TX_HDX) | |
{ | |
// set MII for 100BaseTX and half Duplex | |
bSP = 1; bFD = 0; | |
} | |
else if ((phyAnar & phyAnalpar) & MII_10_HDX) | |
{ | |
// set MII for 10BaseT and half Duplex | |
bSP = 0; bFD = 0; | |
} | |
EMAC_SetSpeed(pHw, bSP); | |
EMAC_FullDuplexEnable(pHw, bFD); | |
EMAC_RMIIEnable(pHw, rmiiMode); | |
EMAC_TransceiverClockEnable(pHw, 1); | |
AutoNegotiateExit: | |
EMAC_ManagementEnable(pHw, 0); | |
return rc; | |
} | |
/** | |
* Get the Link & speed settings, and automatically setup the EMAC with the | |
* settings. | |
* Return 1 if link found, 0 if no ethernet link. | |
* \param pMacb Pointer to the MACB instance | |
* \param applySetting Apply the settings to EMAC interface | |
*/ | |
uint8_t MACB_GetLinkSpeed(Macb *pMacb, uint8_t applySetting) | |
{ | |
sEmacd *pDrv = pMacb->pEmacd; | |
Emac *pHw = pDrv->pHw; | |
uint32_t retryMax; | |
uint32_t stat1; | |
uint32_t stat2; | |
uint8_t phyAddress, bSP, bFD; | |
uint8_t rc = 1; | |
TRACE_DEBUG("MACB_GetLinkSpeed\n\r"); | |
bSP = 0; bFD = 0; | |
EMAC_ManagementEnable(pHw, 1); | |
phyAddress = pMacb->phyAddress; | |
retryMax = pMacb->retryMax; | |
rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMSR, &stat1, retryMax); | |
if (rc == 0) | |
{ | |
goto GetLinkSpeedExit; | |
} | |
if ((stat1 & MII_LINK_STATUS) == 0) | |
{ | |
TRACE_ERROR("Pb: LinkStat: 0x%x\n\r", (unsigned int)stat1); | |
rc = 0; | |
goto GetLinkSpeedExit; | |
} | |
if (applySetting == 0) | |
{ | |
TRACE_WARNING("Speed #%d not applied\n\r", applySetting); | |
bSP = 0; bFD = 0; | |
goto GetLinkSpeedExit; | |
} | |
/* Re-configure Link speed */ | |
rc = EMAC_ReadPhy(pHw, phyAddress, MII_DSCSR, &stat2, retryMax); | |
if (rc == 0) | |
{ | |
TRACE_ERROR("Pb _DSCSR: rc 0x%x\n\r", rc); | |
goto GetLinkSpeedExit; | |
} | |
if ((stat1 & MII_100BASE_TX_FD) && (stat2 & MII_100FDX)) | |
{ | |
/* set Emac for 100BaseTX and Full Duplex */ | |
bSP = 1; bFD = 1; | |
} | |
if ((stat1 & MII_10BASE_T_FD) && (stat2 & MII_10FDX)) | |
{ | |
/* set MII for 10BaseT and Full Duplex */ | |
bSP= 0; bFD = 1; | |
} | |
if ((stat1 & MII_100BASE_T4_HD) && (stat2 & MII_100HDX)) | |
{ | |
/* set MII for 100BaseTX and Half Duplex */ | |
bSP = 1; bFD = 0; | |
} | |
if ((stat1 & MII_10BASE_T_HD) && (stat2 & MII_10HDX)) | |
{ | |
/* set MII for 10BaseT and Half Duplex */ | |
bSP = 0; bFD = 0; | |
} | |
EMAC_SetSpeed(pHw, bSP); | |
EMAC_FullDuplexEnable(pHw, bFD); | |
/* Start the EMAC transfers */ | |
TRACE_DEBUG("MACB_GetLinkSpeed passed\n\r"); | |
GetLinkSpeedExit: | |
EMAC_ManagementEnable(pHw, 0); | |
return rc; | |
} | |