]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libboard_samv7-ek/source/gmacb_phy.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libboard_samv7-ek / source / gmacb_phy.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2013, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\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
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\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
16  *\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
28  */\r
29 \r
30 /** \file */\r
31 \r
32 /*---------------------------------------------------------------------------\r
33  *         Headers\r
34  *---------------------------------------------------------------------------*/\r
35 \r
36 #include "board.h"\r
37 \r
38 /*---------------------------------------------------------------------------\r
39  *         Definitions\r
40  *---------------------------------------------------------------------------*/\r
41 \r
42 /** Default max retry count */\r
43 #define GMACB_RETRY_MAX            300000\r
44 \r
45 /** Default max retry count */\r
46 #define GACB_RETRY_MAX            1000000\r
47 \r
48 /*---------------------------------------------------------------------------\r
49  *         Local functions\r
50  *---------------------------------------------------------------------------*/\r
51 \r
52 \r
53 /**\r
54  * Wait PHY operation complete.\r
55  * Return 1 if the operation completed successfully.\r
56  * May be need to re-implemented to reduce CPU load.\r
57  * \param retry: the retry times, 0 to wait forever until complete.\r
58  */\r
59 static uint8_t GMACB_WaitPhy( Gmac *pHw, uint32_t retry )\r
60 {\r
61     volatile uint32_t retry_count = 0;\r
62 \r
63     while (!GMAC_IsIdle(pHw))\r
64     {\r
65         if(retry == 0) continue;\r
66         retry_count ++;\r
67         if (retry_count >= retry)\r
68         {\r
69             return 0;\r
70         }\r
71     }\r
72     return 1;\r
73 }\r
74 \r
75 /**\r
76  * Read PHY register.\r
77  * Return 1 if successfully, 0 if timeout.\r
78  * \param pHw HW controller address\r
79  * \param PhyAddress PHY Address\r
80  * \param Address Register Address\r
81  * \param pValue Pointer to a 32 bit location to store read data\r
82  * \param retry The retry times, 0 to wait forever until complete.\r
83  */\r
84 static uint8_t GMACB_ReadPhy(Gmac *pHw,\r
85         uint8_t PhyAddress,\r
86         uint8_t Address,\r
87         uint32_t *pValue,\r
88         uint32_t retry)\r
89 {\r
90     GMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0);\r
91     if ( GMACB_WaitPhy(pHw, retry) == 0 )\r
92     {\r
93         TRACE_ERROR("TimeOut GMACB_ReadPhy\n\r");\r
94         return 0;\r
95     }\r
96     *pValue = GMAC_PHYData(pHw);\r
97     return 1;\r
98 }\r
99 \r
100 /**\r
101  * Write PHY register\r
102  * Return 1 if successfully, 0 if timeout.\r
103  * \param pHw HW controller address\r
104  * \param PhyAddress PHY Address\r
105  * \param Address Register Address\r
106  * \param Value Data to write ( Actually 16 bit data )\r
107  * \param retry The retry times, 0 to wait forever until complete.\r
108  */\r
109 static uint8_t GMACB_WritePhy(Gmac *pHw,\r
110         uint8_t PhyAddress,\r
111         uint8_t Address,\r
112         uint32_t Value,\r
113         uint32_t retry)\r
114 {\r
115     GMAC_PHYMaintain(pHw, PhyAddress, Address, 0, Value);\r
116     if ( GMACB_WaitPhy(pHw, retry) == 0 )\r
117     {\r
118         TRACE_ERROR("TimeOut GMACB_WritePhy\n\r");\r
119         return 0;\r
120     }\r
121     return 1;\r
122 }\r
123 \r
124 /*---------------------------------------------------------------------------\r
125  *         Exported functions\r
126  *---------------------------------------------------------------------------*/\r
127 \r
128 /**\r
129  * \brief Find a valid PHY Address ( from 0 to 31 ).\r
130  * \param pMacb Pointer to the MACB instance\r
131  * \return 0xFF when no valid PHY Address found.\r
132  */\r
133 static uint8_t GMACB_FindValidPhy(GMacb *pMacb)\r
134 {\r
135     sGmacd *pDrv = pMacb->pGmacd;\r
136     Gmac *pHw = pDrv->pHw;\r
137 \r
138     uint32_t  retryMax;\r
139     uint32_t  value=0;\r
140     uint8_t rc;\r
141     uint8_t phyAddress;\r
142     uint8_t cnt;\r
143 \r
144     TRACE_DEBUG("GMACB_FindValidPhy\n\r");\r
145 \r
146     GMAC_EnableMdio(pHw);\r
147     phyAddress = pMacb->phyAddress;\r
148     retryMax = pMacb->retryMax;\r
149 \r
150     /* Check current phyAddress */\r
151     rc = phyAddress;\r
152     if( GMACB_ReadPhy(pHw, phyAddress, GMII_PHYID1R, &value, retryMax) == 0 ) {\r
153         TRACE_ERROR("GMACB PROBLEM\n\r");\r
154     }\r
155     TRACE_DEBUG("_PHYID1  : 0x%X, addr: %d\n\r", value, phyAddress);\r
156 \r
157     /* Find another one */\r
158     if (value != GMII_OUI_MSB) {\r
159 \r
160         rc = 0xFF;\r
161         for(cnt = 0; cnt < 32; cnt ++) {\r
162 \r
163             phyAddress = (phyAddress + 1) & 0x1F;\r
164             if( GMACB_ReadPhy(pHw, phyAddress, GMII_PHYID1R, &value, retryMax) == 0 ) {\r
165                 TRACE_ERROR("MACB PROBLEM\n\r");\r
166             }\r
167             TRACE_DEBUG("_PHYID1  : 0x%X, addr: %d\n\r", value, phyAddress);\r
168             if (value == GMII_OUI_MSB) {\r
169 \r
170                 rc = phyAddress;\r
171                 break;\r
172             }\r
173         }\r
174     }\r
175     if (rc != 0xFF) {\r
176         TRACE_INFO("** Valid PHY Found: %d\n\r", rc);\r
177         GMACB_ReadPhy(pHw, phyAddress, GMII_PHYID1R, &value, retryMax);\r
178         TRACE_DEBUG("_PHYID1R  : 0x%X, addr: %d\n\r", value, phyAddress);\r
179         GMACB_ReadPhy(pHw, phyAddress, GMII_PHYID2R, &value, retryMax);\r
180         TRACE_DEBUG("_EMSR  : 0x%X, addr: %d\n\r", value, phyAddress);\r
181     }\r
182     GMAC_DisableMdio(pHw);\r
183     return rc;\r
184 }\r
185 \r
186 \r
187 /*----------------------------------------------------------------------------\r
188  *        Exported functions\r
189  *----------------------------------------------------------------------------*/\r
190 \r
191 \r
192 /**\r
193  * \brief Dump all the useful registers.\r
194  * \param pMacb          Pointer to the MACB instance\r
195  */\r
196 void GMACB_DumpRegisters(GMacb *pMacb)\r
197 {\r
198     sGmacd *pDrv = pMacb->pGmacd;\r
199     Gmac *pHw = pDrv->pHw;\r
200 \r
201     uint8_t phyAddress;\r
202     uint32_t retryMax;\r
203     uint32_t value;\r
204 \r
205     TRACE_INFO("GMACB_DumpRegisters\n\r");\r
206 \r
207     GMAC_EnableMdio(pHw);\r
208     phyAddress = pMacb->phyAddress;\r
209     retryMax = pMacb->retryMax;\r
210 \r
211     TRACE_INFO("GMII MACB @ %d) Registers:\n\r", phyAddress);\r
212 \r
213     GMACB_ReadPhy(pHw, phyAddress, GMII_BMCR, &value, retryMax);\r
214     TRACE_INFO(" _BMCR     : 0x%X\n\r", value);\r
215     GMACB_ReadPhy(pHw, phyAddress, GMII_BMSR, &value, retryMax);\r
216     TRACE_INFO(" _BMSR     : 0x%X\n\r", value);\r
217     GMACB_ReadPhy(pHw, phyAddress, GMII_PHYID1R, &value, retryMax);\r
218     TRACE_INFO(" _PHYID1     : 0x%X\n\r", value);\r
219     GMACB_ReadPhy(pHw, phyAddress, GMII_PHYID2R, &value, retryMax);\r
220     TRACE_INFO(" _PHYID2     : 0x%X\n\r", value);\r
221     GMACB_ReadPhy(pHw, phyAddress, GMII_ANAR, &value, retryMax);\r
222     TRACE_INFO(" _ANAR     : 0x%X\n\r", value);\r
223     GMACB_ReadPhy(pHw, phyAddress, GMII_ANLPAR, &value, retryMax);\r
224     TRACE_INFO(" _ANLPAR   : 0x%X\n\r", value);\r
225     GMACB_ReadPhy(pHw, phyAddress, GMII_ANER, &value, retryMax);\r
226     TRACE_INFO(" _ANER     : 0x%X\n\r", value);\r
227     GMACB_ReadPhy(pHw, phyAddress, GMII_ANNPR, &value, retryMax);\r
228     TRACE_INFO(" _ANNPR    : 0x%X\n\r", value);\r
229     GMACB_ReadPhy(pHw, phyAddress, GMII_ANLPNPAR, &value, retryMax);\r
230     TRACE_INFO(" _ANLPNPAR : 0x%X\n\r", value);\r
231 \r
232     TRACE_INFO(" \n\r");\r
233 \r
234     GMACB_ReadPhy(pHw, phyAddress, GMII_RXERCR, &value, retryMax);\r
235     TRACE_INFO(" _RXERCR   : 0x%X\n\r", value);\r
236     GMACB_ReadPhy(pHw, phyAddress, GMII_ICSR, &value, retryMax);\r
237     TRACE_INFO(" _ICSR     : 0x%X\n\r", value);\r
238     TRACE_INFO(" \n\r");\r
239 \r
240     GMAC_DisableMdio(pHw);\r
241 }\r
242 \r
243 /**\r
244  * \brief Setup the maximum timeout count of the driver.\r
245  * \param pMacb Pointer to the MACB instance\r
246  * \param toMax Timeout maxmum count.\r
247  */\r
248 void GMACB_SetupTimeout(GMacb *pMacb, uint32_t toMax)\r
249 {\r
250     pMacb->retryMax = toMax;\r
251 }\r
252 \r
253 /**\r
254  * \brief Initialize the MACB instance.\r
255  * \param pMacb Pointer to the MACB instance\r
256  * \param phyAddress   The PHY address used to access the PHY\r
257  */\r
258 void GMACB_Init(GMacb *pMacb, sGmacd *pGmacd, uint8_t phyAddress)\r
259 {\r
260     pMacb->pGmacd = pGmacd;\r
261     pMacb->phyAddress = phyAddress;\r
262     /* Initialize timeout by default */\r
263     pMacb->retryMax = GMACB_RETRY_MAX;\r
264 }\r
265 \r
266 \r
267 /**\r
268  * \brief Issue a SW reset to reset all registers of the PHY.\r
269  * \param pMacb Pointer to the MACB instance\r
270  * \return 1 if successfully, 0 if timeout.\r
271  */\r
272 uint8_t GMACB_ResetPhy(GMacb *pMacb)\r
273 {\r
274     sGmacd *pDrv = pMacb->pGmacd;\r
275     Gmac *pHw = pDrv->pHw;\r
276     uint32_t retryMax;\r
277     uint32_t bmcr = GMII_RESET;\r
278     uint8_t phyAddress;\r
279     uint32_t timeout = 10;\r
280     uint8_t ret = 1;\r
281 \r
282     TRACE_INFO(" GMACB_ResetPhy\n\r");\r
283 \r
284     phyAddress = pMacb->phyAddress;\r
285     retryMax = pMacb->retryMax;\r
286 \r
287     GMAC_EnableMdio(pHw);\r
288     bmcr = GMII_RESET;\r
289     GMACB_WritePhy(pHw, phyAddress, GMII_BMCR, bmcr, retryMax);\r
290 \r
291     do {\r
292         GMACB_ReadPhy(pHw, phyAddress, GMII_BMCR, &bmcr, retryMax);\r
293         timeout--;\r
294     } while ((bmcr & GMII_RESET) && timeout);\r
295 \r
296     GMAC_DisableMdio(pHw);\r
297 \r
298     if (!timeout) {\r
299         ret = 0;\r
300     }\r
301 \r
302     return( ret );\r
303 }\r
304 \r
305 /**\r
306  * \brief Do a HW initialize to the PHY ( via RSTC ) and setup clocks & PIOs\r
307  * This should be called only once to initialize the PHY pre-settings.\r
308  * The PHY address is reset status of CRS,RXD[3:0] (the emacPins' pullups).\r
309  * The COL pin is used to select MII mode on reset (pulled up for Reduced MII)\r
310  * The RXDV pin is used to select test mode on reset (pulled up for test mode)\r
311  * The above pins should be predefined for corresponding settings in resetPins\r
312  * The GMAC peripheral pins are configured after the reset done.\r
313  * \param pMacb Pointer to the MACB instance\r
314  * \param mck         Main clock setting to initialize clock\r
315  * \param resetPins   Pointer to list of PIOs to configure before HW RESET\r
316  *                       (for PHY power on reset configuration latch)\r
317  * \param nbResetPins Number of PIO items that should be configured\r
318  * \param emacPins    Pointer to list of PIOs for the EMAC interface\r
319  * \param nbEmacPins  Number of PIO items that should be configured\r
320  * \return 1 if RESET OK, 0 if timeout.\r
321  */\r
322 uint8_t GMACB_InitPhy(GMacb *pMacb,\r
323         uint32_t mck,\r
324         const Pin *pResetPins,\r
325         uint32_t nbResetPins,\r
326         const Pin *pGmacPins,\r
327         uint32_t nbGmacPins)\r
328 {\r
329     sGmacd *pDrv = pMacb->pGmacd;\r
330     Gmac *pHw = pDrv->pHw;\r
331     uint8_t rc = 1;\r
332     uint8_t phy;\r
333 \r
334     /* Perform RESET */\r
335     TRACE_DEBUG("RESET PHY\n\r");\r
336 \r
337     if (pResetPins) {\r
338         /* Configure PINS */\r
339         PIO_Configure(pResetPins, nbResetPins);\r
340         TRACE_INFO(" Hard Reset of GMACD Phy\n\r");\r
341         PIO_Clear(pResetPins);\r
342         Wait(100);\r
343         PIO_Set(pResetPins);\r
344     }\r
345     /* Configure GMAC runtime pins */\r
346     if (rc) {\r
347 \r
348         PIO_Configure(pGmacPins, nbGmacPins);\r
349         rc = GMAC_SetMdcClock(pHw, mck );\r
350         if (!rc) {\r
351             TRACE_ERROR("No Valid MDC clock\n\r");\r
352             return 0;\r
353         }\r
354 \r
355         /* Check PHY Address */\r
356         phy = GMACB_FindValidPhy(pMacb);\r
357         if (phy == 0xFF) {\r
358             TRACE_ERROR("PHY Access fail\n\r");\r
359             return 0;\r
360         }\r
361         if(phy != pMacb->phyAddress) {\r
362             pMacb->phyAddress = phy;\r
363             GMACB_ResetPhy(pMacb);\r
364         }\r
365     }\r
366     else {\r
367         TRACE_ERROR("PHY Reset Timeout\n\r");\r
368     }\r
369     return rc;\r
370 }\r
371 \r
372 /**\r
373  * \brief Issue a Auto Negotiation of the PHY\r
374  * \param pMacb Pointer to the MACB instance\r
375  * \return 1 if successfully, 0 if timeout.\r
376  */\r
377 uint8_t GMACB_AutoNegotiate(GMacb *pMacb)\r
378 {\r
379     sGmacd *pDrv = pMacb->pGmacd;\r
380     Gmac *pHw = pDrv->pHw;\r
381     uint32_t retryMax;\r
382     uint32_t value;\r
383     uint32_t phyAnar;\r
384     uint32_t phyAnalpar;\r
385     uint32_t retryCount= 0;\r
386     uint8_t phyAddress;\r
387     uint8_t rc = 1;\r
388     uint32_t duplex, speed;\r
389     phyAddress = pMacb->phyAddress;\r
390     retryMax = pMacb->retryMax;\r
391 \r
392     GMAC_EnableMdio(pHw);\r
393 \r
394     if (!GMACB_ReadPhy(pHw,phyAddress, GMII_PHYID1R, &value, retryMax)) \r
395     {\r
396         TRACE_ERROR("Pb GEMAC_ReadPhy Id1\n\r");\r
397         rc = 0;\r
398         goto AutoNegotiateExit;\r
399     }\r
400     TRACE_DEBUG("ReadPhy Id1 0x%X, addresse: %d\n\r", value, phyAddress);\r
401     if (!GMACB_ReadPhy(pHw,phyAddress, GMII_PHYID2R, &phyAnar, retryMax)) \r
402     {\r
403         TRACE_ERROR("Pb GMACB_ReadPhy Id2\n\r");\r
404         rc = 0;\r
405         goto AutoNegotiateExit;\r
406     }\r
407     TRACE_DEBUG("ReadPhy Id2 0x%X\n\r", phyAnar);\r
408 \r
409     if( ( value == GMII_OUI_MSB )\r
410             && ( ((phyAnar)&(~GMII_LSB_MASK)) == GMII_OUI_LSB ) )\r
411     {\r
412         TRACE_DEBUG("Vendor Number Model = 0x%X\n\r", ((phyAnar>>4)&0x3F));\r
413         TRACE_DEBUG("Model Revision Number = 0x%X\n\r", (phyAnar&0xF));\r
414     }\r
415     else \r
416     {\r
417         TRACE_ERROR("Problem OUI value\n\r");\r
418     }\r
419 \r
420     /* Set the Auto_negotiation Advertisement Register, MII advertising for Next page\r
421        100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3 */\r
422     rc  = GMACB_ReadPhy(pHw, phyAddress, GMII_ANAR, &phyAnar, retryMax);\r
423     if (rc == 0) \r
424     {\r
425         goto AutoNegotiateExit;\r
426     }\r
427     phyAnar = GMII_TX_FDX | GMII_TX_HDX |\r
428         GMII_10_FDX | GMII_10_HDX | GMII_AN_IEEE_802_3;\r
429     rc = GMACB_WritePhy(pHw,phyAddress, GMII_ANAR, phyAnar, retryMax);\r
430     if (rc == 0) \r
431     {\r
432         goto AutoNegotiateExit;\r
433     }\r
434 \r
435     /* Read & modify control register */\r
436     rc  = GMACB_ReadPhy(pHw, phyAddress, GMII_BMCR, &value, retryMax);\r
437     if (rc == 0) \r
438     {\r
439         goto AutoNegotiateExit;\r
440     }\r
441 \r
442     /* Check AutoNegotiate complete */\r
443     value |=  GMII_AUTONEG | GMII_RESTART_AUTONEG;\r
444     rc = GMACB_WritePhy(pHw, phyAddress, GMII_BMCR, value, retryMax);\r
445     if (rc == 0) \r
446     {\r
447         goto AutoNegotiateExit;\r
448     }\r
449     TRACE_DEBUG(" _BMCR: 0x%X\n\r", value);\r
450 \r
451     // Check AutoNegotiate complete\r
452     while (1) \r
453     {\r
454         rc  = GMACB_ReadPhy(pHw, phyAddress, GMII_BMSR, &value, retryMax);\r
455         if (rc == 0)\r
456         {\r
457             TRACE_ERROR("rc==0\n\r");\r
458             goto AutoNegotiateExit;\r
459         }\r
460         /* Done successfully */\r
461         if (value & GMII_AUTONEG_COMP) \r
462         {\r
463             printf("AutoNegotiate complete\n\r");\r
464             break;\r
465         }\r
466         /* Timeout check */\r
467         if (retryMax)\r
468         {\r
469             if (++ retryCount >= retryMax)\r
470             {\r
471                 GMACB_DumpRegisters(pMacb);\r
472                 TRACE_ERROR("TimeOut\n\r");\r
473                 rc = 0;\r
474                 goto AutoNegotiateExit; \r
475             }\r
476         }\r
477     }\r
478 \r
479     /*Set local link mode */\r
480     while(1)\r
481     {\r
482         rc  = GMACB_ReadPhy(pHw, phyAddress, GMII_ANLPAR, &phyAnalpar, retryMax);\r
483         if (rc == 0) \r
484         {\r
485             goto AutoNegotiateExit;\r
486         }\r
487         /* Setup the GMAC link speed */\r
488         if ((phyAnar & phyAnalpar) & GMII_TX_FDX) \r
489         {\r
490             /* set RGMII for 1000BaseTX and Full Duplex */\r
491             duplex = GMAC_DUPLEX_FULL;\r
492             speed = GMAC_SPEED_100M;\r
493             break;\r
494         }\r
495         else if ((phyAnar & phyAnalpar) & GMII_10_FDX) \r
496         {\r
497             /* set RGMII for 1000BaseT and Half Duplex*/\r
498             duplex = GMAC_DUPLEX_FULL;\r
499             speed = GMAC_SPEED_10M;\r
500             break;\r
501         }\r
502         else if ((phyAnar & phyAnalpar) & GMII_TX_HDX) \r
503         {\r
504             /* set RGMII for 100BaseTX and half Duplex */\r
505             duplex = GMAC_DUPLEX_HALF;\r
506             speed = GMAC_SPEED_100M;\r
507             break;\r
508         }\r
509         else if ((phyAnar & phyAnalpar) & GMII_10_HDX) \r
510         {\r
511             // set RGMII for 10BaseT and half Duplex\r
512             duplex = GMAC_DUPLEX_HALF;\r
513             speed = GMAC_SPEED_10M;\r
514             break;\r
515         }\r
516     }\r
517     TRACE_INFO("GMAC_EnableRGMII duplex %u, speed %u\n\r",duplex,speed);\r
518 \r
519     GMACB_ReadPhy(pHw,phyAddress, GMII_PC1R, &value, retryMax);\r
520     GMACB_ReadPhy(pHw,phyAddress, GMII_PC2R, &value, retryMax);\r
521     GMACB_ReadPhy(pHw,phyAddress, GMII_ICSR, &value, retryMax);\r
522     /* Setup GMAC mode  */\r
523     GMAC_EnableRGMII(pHw, duplex, speed);\r
524 \r
525 AutoNegotiateExit:\r
526     GMAC_DisableMdio(pHw);\r
527     return rc;\r
528 }\r