2 * FreeRTOS+TCP V2.0.11
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * Handling of Ethernet PHY's
\r
28 * PHY's communicate with an EMAC either through
\r
29 * a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII).
\r
30 * The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports
\r
31 * shall be treated independently.
\r
35 /* Standard includes. */
\r
40 /* FreeRTOS includes. */
\r
41 #include "FreeRTOS.h"
\r
46 /* FreeRTOS+TCP includes. */
\r
47 #include "FreeRTOS_IP.h"
\r
48 #include "FreeRTOS_Sockets.h"
\r
50 #include "phyHandling.h"
\r
52 #define phyMIN_PHY_ADDRESS 0
\r
53 #define phyMAX_PHY_ADDRESS 31
\r
55 #if defined( PHY_LS_HIGH_CHECK_TIME_MS ) || defined( PHY_LS_LOW_CHECK_TIME_MS )
\r
56 #warning please use the new defines with 'ipconfig' prefix
\r
59 #ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS
\r
60 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
61 receiving packets. */
\r
62 #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000
\r
65 #ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS
\r
66 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
67 #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000
\r
70 /* Naming and numbering of basic PHY registers. */
\r
71 #define phyREG_00_BMCR 0x00u /* Basic Mode Control Register. */
\r
72 #define phyREG_01_BMSR 0x01u /* Basic Mode Status Register. */
\r
73 #define phyREG_02_PHYSID1 0x02u /* PHYS ID 1 */
\r
74 #define phyREG_03_PHYSID2 0x03u /* PHYS ID 2 */
\r
75 #define phyREG_04_ADVERTISE 0x04u /* Advertisement control reg */
\r
77 /* Naming and numbering of extended PHY registers. */
\r
78 #define PHYREG_10_PHYSTS 0x10u /* 16 PHY status register Offset */
\r
79 #define phyREG_19_PHYCR 0x19u /* 25 RW PHY Control Register */
\r
80 #define phyREG_1F_PHYSPCS 0x1Fu /* 31 RW PHY Special Control Status */
\r
82 /* Bit fields for 'phyREG_00_BMCR', the 'Basic Mode Control Register'. */
\r
83 #define phyBMCR_FULL_DUPLEX 0x0100u /* Full duplex. */
\r
84 #define phyBMCR_AN_RESTART 0x0200u /* Auto negotiation restart. */
\r
85 #define phyBMCR_ISOLATE 0x0400u /* 1 = Isolates 0 = Normal operation. */
\r
86 #define phyBMCR_AN_ENABLE 0x1000u /* Enable auto negotiation. */
\r
87 #define phyBMCR_SPEED_100 0x2000u /* Select 100Mbps. */
\r
88 #define phyBMCR_RESET 0x8000u /* Reset the PHY. */
\r
90 /* Bit fields for 'phyREG_19_PHYCR', the 'PHY Control Register'. */
\r
91 #define PHYCR_MDIX_EN 0x8000u /* Enable Auto MDIX. */
\r
92 #define PHYCR_MDIX_FORCE 0x4000u /* Force MDIX crossed. */
\r
94 #define phyBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */
\r
96 #define phyBMSR_LINK_STATUS 0x0004u
\r
98 #define phyPHYSTS_LINK_STATUS 0x0001u /* PHY Link mask */
\r
99 #define phyPHYSTS_SPEED_STATUS 0x0002u /* PHY Speed mask */
\r
100 #define phyPHYSTS_DUPLEX_STATUS 0x0004u /* PHY Duplex mask */
\r
102 /* Bit fields for 'phyREG_1F_PHYSPCS
\r
103 001 = 10BASE-T half-duplex
\r
104 101 = 10BASE-T full-duplex
\r
105 010 = 100BASE-TX half-duplex
\r
106 110 = 100BASE-TX full-duplex
\r
108 #define phyPHYSPCS_SPEED_MASK 0x000Cu
\r
109 #define phyPHYSPCS_SPEED_10 0x0004u
\r
110 #define phyPHYSPCS_FULL_DUPLEX 0x0010u
\r
113 * Description of all capabilities that can be advertised to
\r
114 * the peer (usually a switch or router).
\r
116 #define phyADVERTISE_CSMA 0x0001u /* Only selector supported. */
\r
117 #define phyADVERTISE_10HALF 0x0020u /* Try for 10mbps half-duplex. */
\r
118 #define phyADVERTISE_10FULL 0x0040u /* Try for 10mbps full-duplex. */
\r
119 #define phyADVERTISE_100HALF 0x0080u /* Try for 100mbps half-duplex. */
\r
120 #define phyADVERTISE_100FULL 0x0100u /* Try for 100mbps full-duplex. */
\r
122 #define phyADVERTISE_ALL ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \
\r
123 phyADVERTISE_100HALF | phyADVERTISE_100FULL )
\r
125 /* Send a reset commando to a set of PHY-ports. */
\r
126 static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask );
\r
128 static BaseType_t xHas_1F_PHYSPCS( uint32_t ulPhyID )
\r
130 BaseType_t xResult;
\r
134 case PHY_ID_LAN8720:
\r
135 case PHY_ID_LAN8742A:
\r
136 case PHY_ID_KSZ8041:
\r
138 case PHY_ID_KSZ8051: // same ID as 8041
\r
139 case PHY_ID_KSZ8081: // same ID as 8041
\r
141 case PHY_ID_KSZ8081MNXIA:
\r
143 case PHY_ID_KSZ8863:
\r
145 /* Most PHY's have a 1F_PHYSPCS */
\r
148 case PHY_ID_DP83848I:
\r
154 /*-----------------------------------------------------------*/
\r
156 static BaseType_t xHas_19_PHYCR( uint32_t ulPhyID )
\r
158 BaseType_t xResult;
\r
162 case PHY_ID_LAN8742A:
\r
163 case PHY_ID_DP83848I:
\r
167 /* Most PHY's do not have a 19_PHYCR */
\r
173 /*-----------------------------------------------------------*/
\r
175 /* Initialise the struct and assign a PHY-read and -write function. */
\r
176 void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite )
\r
178 memset( ( void * )pxPhyObject, '\0', sizeof( *pxPhyObject ) );
\r
180 pxPhyObject->fnPhyRead = fnPhyRead;
\r
181 pxPhyObject->fnPhyWrite = fnPhyWrite;
\r
183 /*-----------------------------------------------------------*/
\r
185 /* Discover all PHY's connected by polling 32 indexes ( zero-based ) */
\r
186 BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject )
\r
188 BaseType_t xPhyAddress;
\r
190 pxPhyObject->xPortCount = 0;
\r
192 for( xPhyAddress = phyMIN_PHY_ADDRESS; xPhyAddress <= phyMAX_PHY_ADDRESS; xPhyAddress++ )
\r
194 uint32_t ulLowerID;
\r
196 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_03_PHYSID2, &ulLowerID );
\r
197 /* A valid PHY id can not be all zeros or all ones. */
\r
198 if( ( ulLowerID != ( uint16_t )~0u ) && ( ulLowerID != ( uint16_t )0u ) )
\r
200 uint32_t ulUpperID;
\r
203 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_02_PHYSID1, &ulUpperID );
\r
204 ulPhyID = ( ( ( uint32_t ) ulUpperID ) << 16 ) | ( ulLowerID & 0xFFF0 );
\r
206 pxPhyObject->ucPhyIndexes[ pxPhyObject->xPortCount ] = xPhyAddress;
\r
207 pxPhyObject->ulPhyIDs[ pxPhyObject->xPortCount ] = ulPhyID;
\r
209 pxPhyObject->xPortCount++;
\r
211 /* See if there is more storage space. */
\r
212 if( pxPhyObject->xPortCount == ipconfigPHY_MAX_PORTS )
\r
218 if( pxPhyObject->xPortCount > 0 )
\r
220 FreeRTOS_printf( ( "PHY ID %lX\n", pxPhyObject->ulPhyIDs[ 0 ] ) );
\r
223 return pxPhyObject->xPortCount;
\r
225 /*-----------------------------------------------------------*/
\r
227 /* Send a reset commando to a set of PHY-ports. */
\r
228 static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
\r
230 uint32_t ulDoneMask, ulConfig;
\r
231 TickType_t xRemainingTime;
\r
233 BaseType_t xPhyIndex;
\r
235 /* A bit-mask ofPHY ports that are ready. */
\r
238 /* Set the RESET bits high. */
\r
239 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
241 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
243 /* Read Control register. */
\r
244 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
245 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig | phyBMCR_RESET );
\r
248 xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );
\r
249 vTaskSetTimeOutState( &xTimer );
\r
251 /* The reset should last less than a second. */
\r
254 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
256 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
258 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
259 if( ( ulConfig & phyBMCR_RESET ) == 0 )
\r
261 FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", (int)xPhyIndex ) );
\r
262 ulDoneMask |= ( 1ul << xPhyIndex );
\r
265 if( ulDoneMask == ulPhyMask )
\r
269 if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
\r
271 FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
\r
274 /* Block for a while */
\r
275 vTaskDelay( pdMS_TO_TICKS( 50ul ) );
\r
278 /* Clear the reset bits. */
\r
279 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
281 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
283 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
284 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig & ~phyBMCR_RESET );
\r
287 vTaskDelay( pdMS_TO_TICKS( 50ul ) );
\r
291 /*-----------------------------------------------------------*/
\r
293 BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties )
\r
295 uint32_t ulConfig, ulAdvertise;
\r
296 BaseType_t xPhyIndex;
\r
298 if( pxPhyObject->xPortCount < 1 )
\r
300 FreeRTOS_printf( ( "xPhyResetAll: No PHY's detected.\n" ) );
\r
304 /* The expected ID for the 'LAN8742A' is 0x0007c130. */
\r
305 /* The expected ID for the 'LAN8720' is 0x0007c0f0. */
\r
306 /* The expected ID for the 'DP83848I' is 0x20005C90. */
\r
308 /* Set advertise register. */
\r
309 if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )
\r
311 ulAdvertise = phyADVERTISE_CSMA | phyADVERTISE_ALL;
\r
312 /* Reset auto-negotiation capability. */
\r
316 ulAdvertise = phyADVERTISE_CSMA;
\r
318 if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO )
\r
320 if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
\r
322 ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_100FULL;
\r
326 ulAdvertise |= phyADVERTISE_10HALF | phyADVERTISE_100HALF;
\r
329 else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO )
\r
331 if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )
\r
333 ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_10HALF;
\r
337 ulAdvertise |= phyADVERTISE_100FULL | phyADVERTISE_100HALF;
\r
340 else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 )
\r
342 if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
\r
344 ulAdvertise |= phyADVERTISE_100FULL;
\r
348 ulAdvertise |= phyADVERTISE_100HALF;
\r
353 if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
\r
355 ulAdvertise |= phyADVERTISE_10FULL;
\r
359 ulAdvertise |= phyADVERTISE_10HALF;
\r
364 /* Send a reset commando to a set of PHY-ports. */
\r
365 xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) );
\r
367 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
369 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
370 uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
\r
372 /* Write advertise register. */
\r
373 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, ulAdvertise );
\r
376 AN_EN AN1 AN0 Forced Mode
\r
377 0 0 0 10BASE-T, Half-Duplex
\r
378 0 0 1 10BASE-T, Full-Duplex
\r
379 0 1 0 100BASE-TX, Half-Duplex
\r
380 0 1 1 100BASE-TX, Full-Duplex
\r
381 AN_EN AN1 AN0 Advertised Mode
\r
382 1 0 0 10BASE-T, Half/Full-Duplex
\r
383 1 0 1 100BASE-TX, Half/Full-Duplex
\r
384 1 1 0 10BASE-T Half-Duplex
\r
385 100BASE-TX, Half-Duplex
\r
386 1 1 1 10BASE-T, Half/Full-Duplex
\r
387 100BASE-TX, Half/Full-Duplex
\r
390 /* Read Control register. */
\r
391 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
\r
393 ulConfig &= ~( phyBMCR_SPEED_100 | phyBMCR_FULL_DUPLEX );
\r
395 ulConfig |= phyBMCR_AN_ENABLE;
\r
397 if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 ) || ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) )
\r
399 ulConfig |= phyBMCR_SPEED_100;
\r
401 else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )
\r
403 ulConfig &= ~phyBMCR_SPEED_100;
\r
406 if( ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) || ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )
\r
408 ulConfig |= phyBMCR_FULL_DUPLEX;
\r
410 else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_HALF )
\r
412 ulConfig &= ~phyBMCR_FULL_DUPLEX;
\r
415 if( xHas_19_PHYCR( ulPhyID ) )
\r
417 uint32_t ulPhyControl;
\r
418 /* Read PHY Control register. */
\r
419 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_19_PHYCR, &ulPhyControl );
\r
421 /* Clear bits which might get set: */
\r
422 ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
\r
424 if( pxPhyProperties->ucMDI_X == PHY_MDIX_AUTO )
\r
426 ulPhyControl |= PHYCR_MDIX_EN;
\r
428 else if( pxPhyProperties->ucMDI_X == PHY_MDIX_CROSSED )
\r
430 /* Force direct link = Use crossed RJ45 cable. */
\r
431 ulPhyControl &= ~PHYCR_MDIX_FORCE;
\r
435 /* Force crossed link = Use direct RJ45 cable. */
\r
436 ulPhyControl |= PHYCR_MDIX_FORCE;
\r
438 /* update PHY Control Register. */
\r
439 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_19_PHYCR, ulPhyControl );
\r
442 FreeRTOS_printf( ( "+TCP: advertise: %04lX config %04lX\n", ulAdvertise, ulConfig ) );
\r
445 /* Keep these values for later use. */
\r
446 pxPhyObject->ulBCRValue = ulConfig & ~phyBMCR_ISOLATE;
\r
447 pxPhyObject->ulACRValue = ulAdvertise;
\r
451 /*-----------------------------------------------------------*/
\r
453 BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
\r
455 BaseType_t xPhyIndex;
\r
456 uint32_t ulValue, ulBitMask = ( uint32_t )1u;
\r
458 ulValue = ( uint32_t )0u;
\r
460 if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL )
\r
462 ulValue |= phyBMCR_FULL_DUPLEX;
\r
464 if( pxPhyObject->xPhyPreferences.ucSpeed == PHY_SPEED_100 )
\r
466 ulValue |= phyBMCR_SPEED_100;
\r
469 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
471 if( ( ulPhyMask & ulBitMask ) != 0lu )
\r
473 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
475 /* Enable Auto-Negotiation. */
\r
476 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulValue );
\r
481 /*-----------------------------------------------------------*/
\r
483 BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
\r
485 uint32_t xPhyIndex, ulDoneMask, ulBitMask;
\r
486 uint32_t ulPHYLinkStatus, ulRegValue;
\r
487 TickType_t xRemainingTime;
\r
490 if( ulPhyMask == ( uint32_t )0u )
\r
494 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
\r
496 if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu )
\r
498 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
500 /* Enable Auto-Negotiation. */
\r
501 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, pxPhyObject->ulACRValue);
\r
502 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART );
\r
505 xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 3000UL );
\r
506 vTaskSetTimeOutState( &xTimer );
\r
508 /* Wait until the auto-negotiation will be completed */
\r
511 ulBitMask = ( uint32_t )1u;
\r
512 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
514 if( ( ulPhyMask & ulBitMask ) != 0lu )
\r
516 if( ( ulDoneMask & ulBitMask ) == 0lu )
\r
518 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
520 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );
\r
521 if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 )
\r
523 ulDoneMask |= ulBitMask;
\r
528 if( ulPhyMask == ulDoneMask )
\r
532 if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
\r
534 FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
\r
537 vTaskDelay( pdMS_TO_TICKS( 50 ) );
\r
540 if( ulDoneMask != ( uint32_t)0u )
\r
542 ulBitMask = ( uint32_t )1u;
\r
543 pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask );
\r
544 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
546 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
547 uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
\r
549 if( ( ulDoneMask & ulBitMask ) == ( uint32_t )0u )
\r
554 /* Clear the 'phyBMCR_AN_RESTART' bit. */
\r
555 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue );
\r
557 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue);
\r
558 if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 )
\r
560 ulPHYLinkStatus |= phyBMSR_LINK_STATUS;
\r
561 pxPhyObject->ulLinkStatusMask |= ulBitMask;
\r
565 ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS );
\r
568 if( ulPhyID == PHY_ID_KSZ8081MNXIA )
\r
570 uint32_t ulControlStatus;
\r
572 pxPhyObject->fnPhyRead( xPhyAddress, 0x1E, &ulControlStatus);
\r
573 switch( ulControlStatus & 0x07 )
\r
577 // [001] = 10BASE-T half-duplex
\r
578 // [101] = 10BASE-T full-duplex
\r
580 ulRegValue |= phyPHYSTS_SPEED_STATUS;
\r
584 // [010] = 100BASE-TX half-duplex
\r
585 // [110] = 100BASE-TX full-duplex
\r
588 switch( ulControlStatus & 0x07 )
\r
592 // [101] = 10BASE-T full-duplex
\r
593 // [110] = 100BASE-TX full-duplex
\r
595 ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
\r
599 // [001] = 10BASE-T half-duplex
\r
600 // [010] = 100BASE-TX half-duplex
\r
604 else if( xHas_1F_PHYSPCS( ulPhyID ) )
\r
606 /* 31 RW PHY Special Control Status */
\r
607 uint32_t ulControlStatus;
\r
609 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus);
\r
611 if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 )
\r
613 ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
\r
615 if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 )
\r
617 ulRegValue |= phyPHYSTS_SPEED_STATUS;
\r
622 /* Read the result of the auto-negotiation. */
\r
623 pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue);
\r
626 FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",
\r
628 ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half",
\r
629 ( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100,
\r
630 ( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0) ? "high" : "low" ) );
\r
631 if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t )0u )
\r
633 pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;
\r
637 pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF;
\r
640 if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 )
\r
642 pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10;
\r
646 pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;
\r
649 } /* if( ulDoneMask != ( uint32_t)0u ) */
\r
653 /*-----------------------------------------------------------*/
\r
655 BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception )
\r
657 uint32_t ulStatus, ulBitMask = 1u;
\r
658 BaseType_t xPhyIndex;
\r
659 BaseType_t xNeedCheck = pdFALSE;
\r
661 if( xHadReception > 0 )
\r
663 /* A packet was received. No need to check for the PHY status now,
\r
664 but set a timer to check it later on. */
\r
665 vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
\r
666 pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
\r
667 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
669 if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0ul )
\r
671 pxPhyObject->ulLinkStatusMask |= ulBitMask;
\r
672 FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
\r
673 xNeedCheck = pdTRUE;
\r
677 else if( xTaskCheckForTimeOut( &( pxPhyObject->xLinkStatusTimer ), &( pxPhyObject->xLinkStatusRemaining ) ) != pdFALSE )
\r
679 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
\r
681 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
\r
683 if( pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulStatus ) == 0 )
\r
685 if( !!( pxPhyObject->ulLinkStatusMask & ulBitMask ) != !!( ulStatus & phyBMSR_LINK_STATUS ) )
\r
687 if( ( ulStatus & phyBMSR_LINK_STATUS ) != 0 )
\r
689 pxPhyObject->ulLinkStatusMask |= ulBitMask;
\r
693 pxPhyObject->ulLinkStatusMask &= ~( ulBitMask );
\r
695 FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
\r
696 xNeedCheck = pdTRUE;
\r
700 vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
\r
701 if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 )
\r
703 pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
\r
707 pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS );
\r
712 /*-----------------------------------------------------------*/
\r