1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2011, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
32 /*---------------------------------------------------------------------------
\r
34 *---------------------------------------------------------------------------*/
\r
38 /*---------------------------------------------------------------------------
\r
40 *---------------------------------------------------------------------------*/
\r
42 /** Default max retry count */
\r
43 #define MACB_RETRY_MAX 1000000
\r
45 /*---------------------------------------------------------------------------
\r
47 *---------------------------------------------------------------------------*/
\r
50 * Wait PHY operation complete.
\r
51 * Return 1 if the operation completed successfully.
\r
52 * May be need to re-implemented to reduce CPU load.
\r
53 * \param retry: the retry times, 0 to wait forever until complete.
\r
55 static uint8_t EMAC_WaitPhy( Emac *pHw, uint32_t retry )
\r
57 volatile uint32_t retry_count = 0;
\r
59 while (!EMAC_IsIdle(pHw))
\r
61 if(retry == 0) continue;
\r
63 if (retry_count >= retry)
\r
72 * Read PHY register.
\r
73 * Return 1 if successfully, 0 if timeout.
\r
74 * \param pHw HW controller address
\r
75 * \param PhyAddress PHY Address
\r
76 * \param Address Register Address
\r
77 * \param pValue Pointer to a 32 bit location to store read data
\r
78 * \param retry The retry times, 0 to wait forever until complete.
\r
80 static uint8_t EMAC_ReadPhy(Emac *pHw,
\r
86 EMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0);
\r
87 if ( EMAC_WaitPhy(pHw, retry) == 0 )
\r
89 TRACE_ERROR("TimeOut EMAC_ReadPhy\n\r");
\r
92 *pValue = EMAC_PHYData(pHw);
\r
97 * Write PHY register
\r
98 * Return 1 if successfully, 0 if timeout.
\r
99 * \param pHw HW controller address
\r
100 * \param PhyAddress PHY Address
\r
101 * \param Address Register Address
\r
102 * \param Value Data to write ( Actually 16 bit data )
\r
103 * \param retry The retry times, 0 to wait forever until complete.
\r
105 static uint8_t EMAC_WritePhy(Emac *pHw,
\r
106 uint8_t PhyAddress,
\r
111 EMAC_PHYMaintain(pHw, PhyAddress, Address, 0, Value);
\r
112 if ( EMAC_WaitPhy(pHw, retry) == 0 )
\r
114 TRACE_ERROR("TimeOut EMAC_WritePhy\n\r");
\r
120 /*---------------------------------------------------------------------------
\r
121 * Exported functions
\r
122 *---------------------------------------------------------------------------*/
\r
125 * Find a valid PHY Address ( from addrStart to 31 ).
\r
126 * Check BMSR register ( not 0 nor 0xFFFF )
\r
127 * Return 0xFF when no valid PHY Address found.
\r
128 * \param pMacb Pointer to the MACB instance
\r
130 uint8_t MACB_FindValidPhy(Macb *pMacb, uint8_t addrStart)
\r
132 sEmacd *pDrv = pMacb->pEmacd;
\r
133 Emac *pHw = pDrv->pHw;
\r
138 uint8_t phyAddress;
\r
141 TRACE_DEBUG("MACB_FindValidPhy\n\r");
\r
143 EMAC_ManagementEnable(pHw, 1);
\r
145 phyAddress = pMacb->phyAddress;
\r
146 retryMax = pMacb->retryMax;
\r
148 /* Check current phyAddress */
\r
150 if( EMAC_ReadPhy(pHw, phyAddress, MII_PHYID1, &value, retryMax) == 0 )
\r
152 TRACE_ERROR("MACB PROBLEM\n\r");
\r
154 TRACE_DEBUG("_PHYID1 : 0x%X, addr: %d\n\r", value, phyAddress);
\r
156 /* Find another one */
\r
157 if (value != MII_OUI_MSB)
\r
160 for(cnt = 0; cnt < 32; cnt ++)
\r
162 phyAddress = (phyAddress + 1) & 0x1F;
\r
163 if( EMAC_ReadPhy(pHw, phyAddress, MII_PHYID1, &value, retryMax) == 0 )
\r
165 TRACE_ERROR("MACB PROBLEM\n\r");
\r
167 TRACE_DEBUG("_PHYID1 : 0x%X, addr: %d\n\r", value, phyAddress);
\r
168 if (value == MII_OUI_MSB)
\r
176 EMAC_ManagementEnable(pHw, 0);
\r
181 printf("** Valid PHY Found: %d\n\r", rc);
\r
182 EMAC_ReadPhy(pHw, phyAddress, MII_DSCSR, &value, retryMax);
\r
183 TRACE_DEBUG("_DSCSR : 0x%X, addr: %d\n\r", value, phyAddress);
\r
190 * Dump all the useful registers
\r
191 * \param pMacb Pointer to the MACB instance
\r
193 void MACB_DumpRegisters(Macb *pMacb)
\r
195 sEmacd *pDrv = pMacb->pEmacd;
\r
196 Emac *pHw = pDrv->pHw;
\r
198 uint8_t phyAddress;
\r
202 TRACE_INFO("MACB_DumpRegisters\n\r");
\r
204 EMAC_ManagementEnable(pHw, 1);
\r
206 phyAddress = pMacb->phyAddress;
\r
207 retryMax = pMacb->retryMax;
\r
209 TRACE_INFO("%cMII MACB (@%d) Registers:\n\r",
\r
210 pMacb->RMII ? 'R' : ' ',
\r
213 EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &value, retryMax);
\r
214 TRACE_INFO(" _BMCR : 0x%X\n\r", value);
\r
215 EMAC_ReadPhy(pHw, phyAddress, MII_BMSR, &value, retryMax);
\r
216 TRACE_INFO(" _BMSR : 0x%X\n\r", value);
\r
217 EMAC_ReadPhy(pHw, phyAddress, MII_ANAR, &value, retryMax);
\r
218 TRACE_INFO(" _ANAR : 0x%X\n\r", value);
\r
219 EMAC_ReadPhy(pHw, phyAddress, MII_ANLPAR, &value, retryMax);
\r
220 TRACE_INFO(" _ANLPAR : 0x%X\n\r", value);
\r
221 EMAC_ReadPhy(pHw, phyAddress, MII_ANER, &value, retryMax);
\r
222 TRACE_INFO(" _ANER : 0x%X\n\r", value);
\r
223 EMAC_ReadPhy(pHw, phyAddress, MII_DSCR, &value, retryMax);
\r
224 TRACE_INFO(" _DSCR : 0x%X\n\r", value);
\r
225 EMAC_ReadPhy(pHw, phyAddress, MII_DSCSR, &value, retryMax);
\r
226 TRACE_INFO(" _DSCSR : 0x%X\n\r", value);
\r
227 EMAC_ReadPhy(pHw, phyAddress, MII_10BTCSR, &value, retryMax);
\r
228 TRACE_INFO(" _10BTCSR: 0x%X\n\r", value);
\r
229 EMAC_ReadPhy(pHw, phyAddress, MII_PWDOR, &value, retryMax);
\r
230 TRACE_INFO(" _PWDOR : 0x%X\n\r", value);
\r
231 EMAC_ReadPhy(pHw, phyAddress, MII_CONFIGR, &value, retryMax);
\r
232 TRACE_INFO(" _CONFIGR: 0x%X\n\r", value);
\r
233 EMAC_ReadPhy(pHw, phyAddress, MII_MDINTR, &value, retryMax);
\r
234 TRACE_INFO(" _MDINTR : 0x%X\n\r", value);
\r
235 EMAC_ReadPhy(pHw, phyAddress, MII_RECR, &value, retryMax);
\r
236 TRACE_INFO(" _RECR : 0x%X\n\r", value);
\r
237 EMAC_ReadPhy(pHw, phyAddress, MII_DISCR, &value, retryMax);
\r
238 TRACE_INFO(" _DISCR : 0x%X\n\r", value);
\r
239 EMAC_ReadPhy(pHw, phyAddress, MII_RLSR, &value, retryMax);
\r
240 TRACE_INFO(" _RLSR : 0x%X\n\r", value);
\r
242 EMAC_ManagementEnable(pHw, 0);
\r
246 * Setup the maximum timeout count of the driver.
\r
247 * \param pMacb Pointer to the MACB instance
\r
248 * \param toMax Timeout maxmum count.
\r
250 void MACB_SetupTimeout(Macb *pMacb, uint32_t toMax)
\r
252 pMacb->retryMax = toMax;
\r
256 * Initialize the MACB instance
\r
257 * \param pMacb Pointer to the MACB instance
\r
258 * \param pEmac Pointer to the Emac instance for the MACB
\r
259 * \param phyAddress The PHY address used to access the PHY
\r
260 * ( pre-defined by pin status on PHY reset )
\r
262 void MACB_Init(Macb *pMacb, sEmacd *pEmacd, uint8_t phyAddress)
\r
264 pMacb->pEmacd = pEmacd;
\r
265 pMacb->phyAddress = phyAddress;
\r
266 /* Initialize timeout by default */
\r
267 pMacb->retryMax = MACB_RETRY_MAX;
\r
271 * Issue a SW reset to reset all registers of the PHY
\r
272 * Return 1 if successfully, 0 if timeout.
\r
273 * \param pMacb Pointer to the MACB instance
\r
275 uint8_t MACB_ResetPhy(Macb *pMacb)
\r
277 sEmacd *pDrv = pMacb->pEmacd;
\r
278 Emac *pHw = pDrv->pHw;
\r
281 uint32_t bmcr = MII_RESET;
\r
282 uint8_t phyAddress;
\r
283 uint32_t timeout = 10;
\r
286 TRACE_INFO(" MACB_ResetPhy\n\r");
\r
288 phyAddress = pMacb->phyAddress;
\r
289 retryMax = pMacb->retryMax;
\r
291 EMAC_ManagementEnable(pHw, 1);
\r
294 EMAC_WritePhy(pHw, phyAddress, MII_BMCR, bmcr, retryMax);
\r
298 EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &bmcr, retryMax);
\r
300 } while ((bmcr & MII_RESET) && timeout);
\r
302 EMAC_ManagementEnable(pHw, 0);
\r
313 * Do a HW initialize to the PHY ( via RSTC ) and setup clocks & PIOs
\r
314 * This should be called only once to initialize the PHY pre-settings.
\r
315 * The PHY address is reset status of CRS,RXD[3:0] (the emacPins' pullups).
\r
316 * The COL pin is used to select MII mode on reset (pulled up for Reduced MII)
\r
317 * The RXDV pin is used to select test mode on reset (pulled up for test mode)
\r
318 * The above pins should be predefined for corresponding settings in resetPins
\r
319 * The EMAC peripheral pins are configured after the reset done.
\r
320 * Return 1 if RESET OK, 0 if timeout.
\r
321 * \param pMacb Pointer to the MACB instance
\r
322 * \param mck Main clock setting to initialize clock
\r
323 * \param resetPins Pointer to list of PIOs to configure before HW RESET
\r
324 * (for PHY power on reset configuration latch)
\r
325 * \param nbResetPins Number of PIO items that should be configured
\r
326 * \param emacPins Pointer to list of PIOs for the EMAC interface
\r
327 * \param nbEmacPins Number of PIO items that should be configured
\r
330 uint8_t MACB_InitPhy(Macb *pMacb,
\r
332 const Pin *pResetPins,
\r
333 uint32_t nbResetPins,
\r
334 const Pin *pEmacPins,
\r
335 uint32_t nbEmacPins)
\r
337 sEmacd *pDrv = pMacb->pEmacd;
\r
338 Emac *pHw = pDrv->pHw;
\r
343 /* Perform RESET */
\r
344 TRACE_DEBUG("RESET PHY\n\r");
\r
348 /* Configure PINS */
\r
349 PIO_Configure(pResetPins, nbResetPins);
\r
350 /* Execute reset */
\r
351 RSTC_SetExtResetLength(MACB_RESET_LENGTH);
\r
353 /* Get NRST level */
\r
354 /* Wait for end hardware reset */
\r
355 while (!RSTC_GetNrstLevel());
\r
357 /* Configure EMAC runtime pins */
\r
360 PIO_Configure(pEmacPins, nbEmacPins);
\r
361 rc = EMAC_SetClock( pHw, mck );
\r
364 TRACE_ERROR("No Valid MDC clock\n\r");
\r
368 /* Check PHY Address */
\r
369 phy = MACB_FindValidPhy(pMacb, 0);
\r
372 TRACE_ERROR("PHY Access fail\n\r");
\r
375 if(phy != pMacb->phyAddress)
\r
377 pMacb->phyAddress = phy;
\r
378 MACB_ResetPhy(pMacb);
\r
384 TRACE_ERROR("PHY Reset Timeout\n\r");
\r
391 * Issue a Auto Negotiation of the PHY
\r
392 * Return 1 if successfully, 0 if timeout.
\r
393 * \param pMacb Pointer to the MACB instance
\r
395 uint8_t MACB_AutoNegotiate(Macb *pMacb, uint8_t rmiiMode)
\r
397 sEmacd *pDrv = pMacb->pEmacd;
\r
398 Emac *pHw = pDrv->pHw;
\r
403 uint32_t phyAnalpar;
\r
404 uint32_t retryCount= 0;
\r
405 uint8_t phyAddress;
\r
410 pMacb->RMII = rmiiMode;
\r
412 phyAddress = pMacb->phyAddress;
\r
413 retryMax = pMacb->retryMax;
\r
415 EMAC_ManagementEnable(pHw, 1);
\r
417 if (!EMAC_ReadPhy(pHw, phyAddress, MII_PHYID1, &value, retryMax))
\r
419 TRACE_ERROR("Pb EMAC_ReadPhy Id1\n\r");
\r
421 goto AutoNegotiateExit;
\r
423 TRACE_DEBUG("ReadPhy Id1 0x%X, addresse: %d\n\r", value, phyAddress);
\r
424 if (!EMAC_ReadPhy(pHw, phyAddress, MII_PHYID2, &phyAnar, retryMax))
\r
426 TRACE_ERROR("Pb EMAC_ReadPhy Id2\n\r");
\r
428 goto AutoNegotiateExit;
\r
430 TRACE_DEBUG("ReadPhy Id2 0x%X\n\r", phyAnar);
\r
432 if( ( value == MII_OUI_MSB )
\r
433 && ( ((phyAnar>>10)&MII_LSB_MASK) == MII_OUI_LSB ) )
\r
435 TRACE_DEBUG("Vendor Number Model = 0x%X\n\r", ((phyAnar>>4)&0x3F));
\r
436 TRACE_DEBUG("Model Revision Number = 0x%X\n\r", (phyAnar&0x7));
\r
440 TRACE_ERROR("Problem OUI value\n\r");
\r
443 /* Setup control register */
\r
444 rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &value, retryMax);
\r
447 goto AutoNegotiateExit;
\r
450 value &= ~MII_AUTONEG; /* Remove autonegotiation enable */
\r
451 value &= ~(MII_LOOPBACK|MII_POWER_DOWN);
\r
452 value |= MII_ISOLATE; /* Electrically isolate PHY */
\r
453 rc = EMAC_WritePhy(pHw, phyAddress, MII_BMCR, value, retryMax);
\r
456 goto AutoNegotiateExit;
\r
459 /* Set the Auto_negotiation Advertisement Register
\r
460 MII advertising for Next page
\r
461 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3 */
\r
462 phyAnar = MII_TX_FDX | MII_TX_HDX |
\r
463 MII_10_FDX | MII_10_HDX | MII_AN_IEEE_802_3;
\r
464 rc = EMAC_WritePhy(pHw, phyAddress, MII_ANAR, phyAnar, retryMax);
\r
467 goto AutoNegotiateExit;
\r
470 /* Read & modify control register */
\r
471 rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMCR, &value, retryMax);
\r
474 goto AutoNegotiateExit;
\r
477 value |= MII_SPEED_SELECT | MII_AUTONEG | MII_DUPLEX_MODE;
\r
478 rc = EMAC_WritePhy(pHw, phyAddress, MII_BMCR, value, retryMax);
\r
481 goto AutoNegotiateExit;
\r
484 /* Restart Auto_negotiation */
\r
485 value |= MII_RESTART_AUTONEG;
\r
486 value &= ~MII_ISOLATE;
\r
487 rc = EMAC_WritePhy(pHw, phyAddress, MII_BMCR, value, retryMax);
\r
490 goto AutoNegotiateExit;
\r
492 TRACE_DEBUG(" _BMCR: 0x%X\n\r", value);
\r
494 /* Check AutoNegotiate complete */
\r
497 rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMSR, &value, retryMax);
\r
500 TRACE_ERROR("_BMSR Rd err\n\r");
\r
501 goto AutoNegotiateExit;
\r
503 /* Done successfully */
\r
504 if (value & MII_AUTONEG_COMP)
\r
506 printf("AutoNegotiate complete\n\r");
\r
510 /* Timeout check */
\r
513 if (++ retryCount >= retryMax)
\r
515 MACB_DumpRegisters(pMacb);
\r
516 TRACE_ERROR("TimeOut\n\r");
\r
518 goto AutoNegotiateExit;
\r
523 /* Get the AutoNeg Link partner base page */
\r
524 rc = EMAC_ReadPhy(pHw, phyAddress, MII_ANLPAR, &phyAnalpar, retryMax);
\r
527 goto AutoNegotiateExit;
\r
530 /* Setup the EMAC link speed */
\r
531 if ((phyAnar & phyAnalpar) & MII_TX_FDX)
\r
533 /* set MII for 100BaseTX and Full Duplex */
\r
536 else if ((phyAnar & phyAnalpar) & MII_10_FDX)
\r
538 /* set MII for 10BaseT and Full Duplex */
\r
541 else if ((phyAnar & phyAnalpar) & MII_TX_HDX)
\r
543 // set MII for 100BaseTX and half Duplex
\r
546 else if ((phyAnar & phyAnalpar) & MII_10_HDX)
\r
548 // set MII for 10BaseT and half Duplex
\r
551 EMAC_SetSpeed(pHw, bSP);
\r
552 EMAC_FullDuplexEnable(pHw, bFD);
\r
554 EMAC_RMIIEnable(pHw, rmiiMode);
\r
555 EMAC_TransceiverClockEnable(pHw, 1);
\r
558 EMAC_ManagementEnable(pHw, 0);
\r
563 * Get the Link & speed settings, and automatically setup the EMAC with the
\r
565 * Return 1 if link found, 0 if no ethernet link.
\r
566 * \param pMacb Pointer to the MACB instance
\r
567 * \param applySetting Apply the settings to EMAC interface
\r
569 uint8_t MACB_GetLinkSpeed(Macb *pMacb, uint8_t applySetting)
\r
571 sEmacd *pDrv = pMacb->pEmacd;
\r
572 Emac *pHw = pDrv->pHw;
\r
577 uint8_t phyAddress, bSP, bFD;
\r
580 TRACE_DEBUG("MACB_GetLinkSpeed\n\r");
\r
582 EMAC_ManagementEnable(pHw, 1);
\r
584 phyAddress = pMacb->phyAddress;
\r
585 retryMax = pMacb->retryMax;
\r
587 rc = EMAC_ReadPhy(pHw, phyAddress, MII_BMSR, &stat1, retryMax);
\r
590 goto GetLinkSpeedExit;
\r
593 if ((stat1 & MII_LINK_STATUS) == 0)
\r
595 TRACE_ERROR("Pb: LinkStat: 0x%x\n\r", (unsigned int)stat1);
\r
597 goto GetLinkSpeedExit;
\r
600 if (applySetting == 0)
\r
602 TRACE_WARNING("Speed #%d not applied\n\r", applySetting);
\r
604 goto GetLinkSpeedExit;
\r
607 /* Re-configure Link speed */
\r
608 rc = EMAC_ReadPhy(pHw, phyAddress, MII_DSCSR, &stat2, retryMax);
\r
611 TRACE_ERROR("Pb _DSCSR: rc 0x%x\n\r", rc);
\r
612 goto GetLinkSpeedExit;
\r
615 if ((stat1 & MII_100BASE_TX_FD) && (stat2 & MII_100FDX))
\r
617 /* set Emac for 100BaseTX and Full Duplex */
\r
621 if ((stat1 & MII_10BASE_T_FD) && (stat2 & MII_10FDX))
\r
623 /* set MII for 10BaseT and Full Duplex */
\r
627 if ((stat1 & MII_100BASE_T4_HD) && (stat2 & MII_100HDX))
\r
629 /* set MII for 100BaseTX and Half Duplex */
\r
633 if ((stat1 & MII_10BASE_T_HD) && (stat2 & MII_10HDX))
\r
635 /* set MII for 10BaseT and Half Duplex */
\r
638 EMAC_SetSpeed(pHw, bSP);
\r
639 EMAC_FullDuplexEnable(pHw, bFD);
\r
641 /* Start the EMAC transfers */
\r
642 TRACE_DEBUG("MACB_GetLinkSpeed passed\n\r");
\r
645 EMAC_ManagementEnable(pHw, 0);
\r