2 * Handling of Ethernet PHY's
\r
3 * PHY's communicate with an EMAC either through
\r
4 * a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII).
\r
5 * The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports
\r
6 * shall be treated independently.
\r
10 /* Standard includes. */
\r
15 /* FreeRTOS includes. */
\r
16 #include "FreeRTOS.h"
\r
21 /* FreeRTOS+TCP includes. */
\r
22 #include "FreeRTOS_IP.h"
\r
23 #include "FreeRTOS_Sockets.h"
\r
25 #include "phyHandling.h"
\r
27 #define phyMIN_PHY_ADDRESS 0
\r
28 #define phyMAX_PHY_ADDRESS 31
\r
30 #if defined( PHY_LS_HIGH_CHECK_TIME_MS ) || defined( PHY_LS_LOW_CHECK_TIME_MS )
\r
31 #warning please use the new defines with 'ipconfig' prefix
\r
34 #ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS
\r
35 /* Check if the LinkStatus in the PHY is still high after 15 seconds of not
\r
36 receiving packets. */
\r
37 #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000uL
\r
40 #ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS
\r
41 /* Check if the LinkStatus in the PHY is still low every second. */
\r
42 #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000uL
\r
45 /* As the following 3 macro's are OK in most situations, and so they're not
\r
46 included in 'FreeRTOSIPConfigDefaults.h'.
\r
47 Users can change their values in the project's 'FreeRTOSIPConfig.h'. */
\r
48 #ifndef phyPHY_MAX_RESET_TIME_MS
\r
49 #define phyPHY_MAX_RESET_TIME_MS 1000uL
\r
52 #ifndef phyPHY_MAX_NEGOTIATE_TIME_MS
\r
53 #define phyPHY_MAX_NEGOTIATE_TIME_MS 3000uL
\r
56 #ifndef phySHORT_DELAY_MS
\r
57 #define phySHORT_DELAY_MS 50uL
\r
60 /* Naming and numbering of basic PHY registers. */
\r
61 #define phyREG_00_BMCR 0x00u /* Basic Mode Control Register. */
\r
62 #define phyREG_01_BMSR 0x01u /* Basic Mode Status Register. */
\r
63 #define phyREG_02_PHYSID1 0x02u /* PHYS ID 1 */
\r
64 #define phyREG_03_PHYSID2 0x03u /* PHYS ID 2 */
\r
65 #define phyREG_04_ADVERTISE 0x04u /* Advertisement control reg */
\r
67 /* Naming and numbering of extended PHY registers. */
\r
68 #define PHYREG_10_PHYSTS 0x10u /* 16 PHY status register Offset */
\r
69 #define phyREG_19_PHYCR 0x19u /* 25 RW PHY Control Register */
\r
70 #define phyREG_1F_PHYSPCS 0x1Fu /* 31 RW PHY Special Control Status */
\r
72 /* Bit fields for 'phyREG_00_BMCR', the 'Basic Mode Control Register'. */
\r
73 #define phyBMCR_FULL_DUPLEX 0x0100u /* Full duplex. */
\r
74 #define phyBMCR_AN_RESTART 0x0200u /* Auto negotiation restart. */
\r
75 #define phyBMCR_ISOLATE 0x0400u /* 1 = Isolates 0 = Normal operation. */
\r
76 #define phyBMCR_AN_ENABLE 0x1000u /* Enable auto negotiation. */
\r
77 #define phyBMCR_SPEED_100 0x2000u /* Select 100Mbps. */
\r
78 #define phyBMCR_RESET 0x8000u /* Reset the PHY. */
\r
80 /* Bit fields for 'phyREG_19_PHYCR', the 'PHY Control Register'. */
\r
81 #define PHYCR_MDIX_EN 0x8000u /* Enable Auto MDIX. */
\r
82 #define PHYCR_MDIX_FORCE 0x4000u /* Force MDIX crossed. */
\r
84 #define phyBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */
\r
86 #define phyBMSR_LINK_STATUS 0x0004u
\r
88 #define phyPHYSTS_LINK_STATUS 0x0001u /* PHY Link mask */
\r
89 #define phyPHYSTS_SPEED_STATUS 0x0002u /* PHY Speed mask */
\r
90 #define phyPHYSTS_DUPLEX_STATUS 0x0004u /* PHY Duplex mask */
\r
92 /* Bit fields for 'phyREG_1F_PHYSPCS
\r
93 001 = 10BASE-T half-duplex
\r
94 101 = 10BASE-T full-duplex
\r
95 010 = 100BASE-TX half-duplex
\r
96 110 = 100BASE-TX full-duplex
\r
98 #define phyPHYSPCS_SPEED_MASK 0x000Cu
\r
99 #define phyPHYSPCS_SPEED_10 0x0004u
\r
100 #define phyPHYSPCS_FULL_DUPLEX 0x0010u
\r
103 * Description of all capabilities that can be advertised to
\r
104 * the peer (usually a switch or router).
\r
107 #define phyADVERTISE_CSMA 0x0001u /* Supports IEEE 802.3u: Fast Ethernet at 100 Mbit/s */
\r
108 #define phyADVERTISE_10HALF 0x0020u /* Try for 10mbps half-duplex. */
\r
109 #define phyADVERTISE_10FULL 0x0040u /* Try for 10mbps full-duplex. */
\r
110 #define phyADVERTISE_100HALF 0x0080u /* Try for 100mbps half-duplex. */
\r
111 #define phyADVERTISE_100FULL 0x0100u /* Try for 100mbps full-duplex. */
\r
113 #define phyADVERTISE_ALL ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \
\r
114 phyADVERTISE_100HALF | phyADVERTISE_100FULL | \
\r
115 phyADVERTISE_CSMA )
\r
117 /* Send a reset command to a set of PHY-ports. */
\r
118 static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask );
\r
120 static BaseType_t xHas_1F_PHYSPCS( uint32_t ulPhyID )
\r
122 BaseType_t xResult;
\r
126 case PHY_ID_LAN8720:
\r
127 case PHY_ID_LAN8742A:
\r
128 case PHY_ID_KSZ8041:
\r
130 case PHY_ID_KSZ8051: // same ID as 8041
\r
131 case PHY_ID_KSZ8081: // same ID as 8041
\r
133 case PHY_ID_KSZ8081MNXIA:
\r
135 case PHY_ID_KSZ8863:
\r
137 /* Most PHY's have a 1F_PHYSPCS */
\r
140 case PHY_ID_DP83848I:
\r
146 /*-----------------------------------------------------------*/
\r
148 static BaseType_t xHas_19_PHYCR( uint32_t ulPhyID )
\r
150 BaseType_t xResult;
\r
154 case PHY_ID_LAN8742A:
\r
155 case PHY_ID_DP83848I:
\r
159 /* Most PHY's do not have a 19_PHYCR */
\r
165 /*-----------------------------------------------------------*/
\r
167 /* Initialise the struct and assign a PHY-read and -write function. */
\r
168 void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite )
\r
170 memset( ( void * )pxPhyObject, '\0', sizeof( *pxPhyObject ) );
\r
172 pxPhyObject->fnPhyRead = fnPhyRead;
\r
173 pxPhyObject->fnPhyWrite = fnPhyWrite;
\r
175 /*-----------------------------------------------------------*/
\r
177 /* Discover all PHY's connected by polling 32 indexes ( zero-based ) */
\r
178 BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject )
\r
180 BaseType_t xPhyAddress;
\r
182 pxPhyObject->xPortCount = 0;
\r
184 for( xPhyAddress = phyMIN_PHY_ADDRESS; xPhyAddress <= phyMAX_PHY_ADDRESS; xPhyAddress++ )
\r
186 uint32_t ulLowerID;
\r
188 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_03_PHYSID2, &ulLowerID );
\r
189 /* A valid PHY id can not be all zeros or all ones. */
\r
190 if( ( ulLowerID != ( uint16_t )~0u ) && ( ulLowerID != ( uint16_t )0u ) )
\r
192 uint32_t ulUpperID;
\r
195 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_02_PHYSID1, &ulUpperID );
\r
196 ulPhyID = ( ( ( uint32_t ) ulUpperID ) << 16 ) | ( ulLowerID & 0xFFF0 );
\r
198 pxPhyObject->ucPhyIndexes[ pxPhyObject->xPortCount ] = xPhyAddress;
\r
199 pxPhyObject->ulPhyIDs[ pxPhyObject->xPortCount ] = ulPhyID;
\r
201 pxPhyObject->xPortCount++;
\r
203 /* See if there is more storage space. */
\r
204 if( pxPhyObject->xPortCount == ipconfigPHY_MAX_PORTS )
\r
210 if( pxPhyObject->xPortCount > 0 )
\r
212 FreeRTOS_printf( ( "PHY ID %lX\n", pxPhyObject->ulPhyIDs[ 0 ] ) );
\r
215 return pxPhyObject->xPortCount;
\r
217 /*-----------------------------------------------------------*/
\r
219 /* Send a reset command to a set of PHY-ports. */
\r
220 static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
\r
222 uint32_t ulDoneMask, ulConfig;
\r
223 TickType_t xRemainingTime;
\r
225 BaseType_t xPhyIndex;
\r
227 /* A bit-mask of PHY ports that are ready. */
\r
230 /* Set the RESET bits high. */
\r
231 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
233 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
235 /* Read Control register. */
\r
236 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
237 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig | phyBMCR_RESET );
\r
240 xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_RESET_TIME_MS );
\r
241 vTaskSetTimeOutState( &xTimer );
\r
243 /* The reset should last less than a second. */
\r
246 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
248 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
250 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
251 if( ( ulConfig & phyBMCR_RESET ) == 0 )
\r
253 FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", (int)xPhyIndex ) );
\r
254 ulDoneMask |= ( 1ul << xPhyIndex );
\r
257 if( ulDoneMask == ulPhyMask )
\r
261 if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
\r
263 FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
\r
266 /* Block for a while */
\r
267 vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
\r
270 /* Clear the reset bits. */
\r
271 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
273 if( ( ulDoneMask & ( 1ul << xPhyIndex ) ) == 0uL )
\r
275 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
277 /* The reset operation timed out, clear the bit manually. */
\r
278 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
279 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig & ~phyBMCR_RESET );
\r
283 vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
\r
287 /*-----------------------------------------------------------*/
\r
289 BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties )
\r
291 uint32_t ulConfig, ulAdvertise;
\r
292 BaseType_t xPhyIndex;
\r
294 if( pxPhyObject->xPortCount < 1 )
\r
296 FreeRTOS_printf( ( "xPhyConfigure: No PHY's detected.\n" ) );
\r
300 /* The expected ID for the 'LAN8742A' is 0x0007c130. */
\r
301 /* The expected ID for the 'LAN8720' is 0x0007c0f0. */
\r
302 /* The expected ID for the 'DP83848I' is 0x20005C90. */
\r
304 /* Set advertise register. */
\r
305 if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )
\r
307 ulAdvertise = phyADVERTISE_ALL;
\r
308 /* Reset auto-negotiation capability. */
\r
312 /* Always select protocol 802.3u. */
\r
313 ulAdvertise = phyADVERTISE_CSMA;
\r
315 if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO )
\r
317 if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
\r
319 ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_100FULL;
\r
323 ulAdvertise |= phyADVERTISE_10HALF | phyADVERTISE_100HALF;
\r
326 else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO )
\r
328 if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )
\r
330 ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_10HALF;
\r
334 ulAdvertise |= phyADVERTISE_100FULL | phyADVERTISE_100HALF;
\r
337 else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 )
\r
339 if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
\r
341 ulAdvertise |= phyADVERTISE_100FULL;
\r
345 ulAdvertise |= phyADVERTISE_100HALF;
\r
350 if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
\r
352 ulAdvertise |= phyADVERTISE_10FULL;
\r
356 ulAdvertise |= phyADVERTISE_10HALF;
\r
361 /* Send a reset command to a set of PHY-ports. */
\r
362 xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) );
\r
364 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
366 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
367 uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
\r
369 /* Write advertise register. */
\r
370 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, ulAdvertise );
\r
373 AN_EN AN1 AN0 Forced Mode
\r
374 0 0 0 10BASE-T, Half-Duplex
\r
375 0 0 1 10BASE-T, Full-Duplex
\r
376 0 1 0 100BASE-TX, Half-Duplex
\r
377 0 1 1 100BASE-TX, Full-Duplex
\r
378 AN_EN AN1 AN0 Advertised Mode
\r
379 1 0 0 10BASE-T, Half/Full-Duplex
\r
380 1 0 1 100BASE-TX, Half/Full-Duplex
\r
381 1 1 0 10BASE-T Half-Duplex
\r
382 100BASE-TX, Half-Duplex
\r
383 1 1 1 10BASE-T, Half/Full-Duplex
\r
384 100BASE-TX, Half/Full-Duplex
\r
387 /* Read Control register. */
\r
388 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
390 ulConfig &= ~( phyBMCR_SPEED_100 | phyBMCR_FULL_DUPLEX );
\r
392 ulConfig |= phyBMCR_AN_ENABLE;
\r
394 if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 ) || ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) )
\r
396 ulConfig |= phyBMCR_SPEED_100;
\r
398 else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )
\r
400 ulConfig &= ~phyBMCR_SPEED_100;
\r
403 if( ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) || ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )
\r
405 ulConfig |= phyBMCR_FULL_DUPLEX;
\r
407 else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_HALF )
\r
409 ulConfig &= ~phyBMCR_FULL_DUPLEX;
\r
412 if( xHas_19_PHYCR( ulPhyID ) )
\r
414 uint32_t ulPhyControl;
\r
415 /* Read PHY Control register. */
\r
416 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_19_PHYCR, &ulPhyControl );
\r
418 /* Clear bits which might get set: */
\r
419 ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
\r
421 if( pxPhyProperties->ucMDI_X == PHY_MDIX_AUTO )
\r
423 ulPhyControl |= PHYCR_MDIX_EN;
\r
425 else if( pxPhyProperties->ucMDI_X == PHY_MDIX_CROSSED )
\r
427 /* Force direct link = Use crossed RJ45 cable. */
\r
428 ulPhyControl &= ~PHYCR_MDIX_FORCE;
\r
432 /* Force crossed link = Use direct RJ45 cable. */
\r
433 ulPhyControl |= PHYCR_MDIX_FORCE;
\r
435 /* update PHY Control Register. */
\r
436 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_19_PHYCR, ulPhyControl );
\r
439 FreeRTOS_printf( ( "+TCP: advertise: %04lX config %04lX\n", ulAdvertise, ulConfig ) );
\r
442 /* Keep these values for later use. */
\r
443 pxPhyObject->ulBCRValue = ulConfig & ~phyBMCR_ISOLATE;
\r
444 pxPhyObject->ulACRValue = ulAdvertise;
\r
448 /*-----------------------------------------------------------*/
\r
450 /* xPhyFixedValue(): this function is called in case auto-negotiation is disabled.
\r
451 The caller has set the values in 'xPhyPreferences' (ucDuplex and ucSpeed).
\r
452 The PHY register phyREG_00_BMCR will be set for every connected PHY that matches
\r
454 BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
\r
456 BaseType_t xPhyIndex;
\r
457 uint32_t ulValue, ulBitMask = ( uint32_t )1u;
\r
459 ulValue = ( uint32_t )0u;
\r
461 if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL )
\r
463 ulValue |= phyBMCR_FULL_DUPLEX;
\r
465 if( pxPhyObject->xPhyPreferences.ucSpeed == PHY_SPEED_100 )
\r
467 ulValue |= phyBMCR_SPEED_100;
\r
470 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
472 if( ( ulPhyMask & ulBitMask ) != 0lu )
\r
474 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
476 /* Enable Auto-Negotiation. */
\r
477 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulValue );
\r
482 /*-----------------------------------------------------------*/
\r
484 /* xPhyStartAutoNegotiation() is the alternative xPhyFixedValue():
\r
485 It sets the BMCR_AN_RESTART bit and waits for the auto-negotiation completion
\r
486 ( phyBMSR_AN_COMPLETE ). */
\r
487 BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
\r
489 uint32_t xPhyIndex, ulDoneMask, ulBitMask;
\r
490 uint32_t ulPHYLinkStatus, ulRegValue;
\r
491 TickType_t xRemainingTime;
\r
494 if( ulPhyMask == ( uint32_t )0u )
\r
498 for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++ )
\r
500 if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu )
\r
502 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
504 /* Enable Auto-Negotiation. */
\r
505 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, pxPhyObject->ulACRValue);
\r
506 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART );
\r
509 xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_NEGOTIATE_TIME_MS );
\r
510 vTaskSetTimeOutState( &xTimer );
\r
512 /* Wait until the auto-negotiation will be completed */
\r
515 ulBitMask = ( uint32_t )1u;
\r
516 for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
518 if( ( ulPhyMask & ulBitMask ) != 0lu )
\r
520 if( ( ulDoneMask & ulBitMask ) == 0lu )
\r
522 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
524 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );
\r
525 if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 )
\r
527 ulDoneMask |= ulBitMask;
\r
532 if( ulPhyMask == ulDoneMask )
\r
536 if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
\r
538 FreeRTOS_printf( ( "xPhyStartAutoNegotiation: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
\r
541 vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
\r
544 if( ulDoneMask != ( uint32_t)0u )
\r
546 ulBitMask = ( uint32_t )1u;
\r
547 pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask );
\r
548 for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
550 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
551 uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
\r
553 if( ( ulDoneMask & ulBitMask ) == ( uint32_t )0u )
\r
558 /* Clear the 'phyBMCR_AN_RESTART' bit. */
\r
559 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue );
\r
561 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue);
\r
562 if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 )
\r
564 ulPHYLinkStatus |= phyBMSR_LINK_STATUS;
\r
565 pxPhyObject->ulLinkStatusMask |= ulBitMask;
\r
569 ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS );
\r
572 if( ulPhyID == PHY_ID_KSZ8081MNXIA )
\r
574 uint32_t ulControlStatus;
\r
576 pxPhyObject->fnPhyRead( xPhyAddress, 0x1E, &ulControlStatus);
\r
577 switch( ulControlStatus & 0x07 )
\r
581 // [001] = 10BASE-T half-duplex
\r
582 // [101] = 10BASE-T full-duplex
\r
584 ulRegValue |= phyPHYSTS_SPEED_STATUS;
\r
588 // [010] = 100BASE-TX half-duplex
\r
589 // [110] = 100BASE-TX full-duplex
\r
592 switch( ulControlStatus & 0x07 )
\r
596 // [101] = 10BASE-T full-duplex
\r
597 // [110] = 100BASE-TX full-duplex
\r
599 ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
\r
603 // [001] = 10BASE-T half-duplex
\r
604 // [010] = 100BASE-TX half-duplex
\r
608 else if( xHas_1F_PHYSPCS( ulPhyID ) )
\r
610 /* 31 RW PHY Special Control Status */
\r
611 uint32_t ulControlStatus;
\r
613 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus);
\r
615 if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 )
\r
617 ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
\r
619 if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 )
\r
621 ulRegValue |= phyPHYSTS_SPEED_STATUS;
\r
626 /* Read the result of the auto-negotiation. */
\r
627 pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue);
\r
630 FreeRTOS_printf( ( "Autonego ready: %08lx: %s duplex %u mbit %s status\n",
\r
632 ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half",
\r
633 ( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100,
\r
634 ( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0) ? "high" : "low" ) );
\r
635 if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t )0u )
\r
637 pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;
\r
641 pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF;
\r
644 if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 )
\r
646 pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10;
\r
650 pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;
\r
653 } /* if( ulDoneMask != ( uint32_t)0u ) */
\r
657 /*-----------------------------------------------------------*/
\r
659 BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception )
\r
661 uint32_t ulStatus, ulBitMask = 1u;
\r
662 BaseType_t xPhyIndex;
\r
663 BaseType_t xNeedCheck = pdFALSE;
\r
665 if( xHadReception > 0 )
\r
667 /* A packet was received. No need to check for the PHY status now,
\r
668 but set a timer to check it later on. */
\r
669 vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
\r
670 pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
\r
671 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
673 if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0ul )
\r
675 pxPhyObject->ulLinkStatusMask |= ulBitMask;
\r
676 FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
\r
677 xNeedCheck = pdTRUE;
\r
681 else if( xTaskCheckForTimeOut( &( pxPhyObject->xLinkStatusTimer ), &( pxPhyObject->xLinkStatusRemaining ) ) != pdFALSE )
\r
683 /* Frequent checking the PHY Link Status can affect for the performance of Ethernet controller.
\r
684 As long as packets are received, no polling is needed.
\r
685 Otherwise, polling will be done when the 'xLinkStatusTimer' expires. */
\r
686 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
688 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
690 if( pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulStatus ) == 0 )
\r
692 if( !!( pxPhyObject->ulLinkStatusMask & ulBitMask ) != !!( ulStatus & phyBMSR_LINK_STATUS ) )
\r
694 if( ( ulStatus & phyBMSR_LINK_STATUS ) != 0 )
\r
696 pxPhyObject->ulLinkStatusMask |= ulBitMask;
\r
700 pxPhyObject->ulLinkStatusMask &= ~( ulBitMask );
\r
702 FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
\r
703 xNeedCheck = pdTRUE;
\r
707 vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
\r
708 if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 )
\r
710 /* The link status is high, so don't poll the PHY too often. */
\r
711 pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
\r
715 /* The link status is low, polling may be done more frequently. */
\r
716 pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS );
\r
721 /*-----------------------------------------------------------*/
\r