]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c
Sync FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP with the version in GitHub at (23665258ca...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / Common / phyHandling.c
1 /*\r
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
7  * \r
8  */\r
9 \r
10 /* Standard includes. */\r
11 #include <stdint.h>\r
12 #include <stdio.h>\r
13 #include <stdlib.h>\r
14 \r
15 /* FreeRTOS includes. */\r
16 #include "FreeRTOS.h"\r
17 #include "task.h"\r
18 #include "queue.h"\r
19 #include "semphr.h"\r
20 \r
21 /* FreeRTOS+TCP includes. */\r
22 #include "FreeRTOS_IP.h"\r
23 #include "FreeRTOS_Sockets.h"\r
24 \r
25 #include "phyHandling.h"\r
26 \r
27 #define phyMIN_PHY_ADDRESS              0\r
28 #define phyMAX_PHY_ADDRESS              31\r
29 \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
32 #endif\r
33 \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
38 #endif\r
39 \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
43 #endif\r
44 \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
50 #endif\r
51 \r
52 #ifndef phyPHY_MAX_NEGOTIATE_TIME_MS\r
53         #define phyPHY_MAX_NEGOTIATE_TIME_MS            3000uL\r
54 #endif\r
55 \r
56 #ifndef phySHORT_DELAY_MS\r
57         #define phySHORT_DELAY_MS                                       50uL\r
58 #endif\r
59 \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
66 \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
71 \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
79 \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
83 \r
84 #define phyBMSR_AN_COMPLETE                     0x0020u /* Auto-Negotiation process completed */\r
85 \r
86 #define phyBMSR_LINK_STATUS                     0x0004u\r
87 \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
91 \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
97 */\r
98 #define phyPHYSPCS_SPEED_MASK           0x000Cu\r
99 #define phyPHYSPCS_SPEED_10                     0x0004u\r
100 #define phyPHYSPCS_FULL_DUPLEX          0x0010u\r
101 \r
102 /*\r
103  * Description of all capabilities that can be advertised to\r
104  * the peer (usually a switch or router).\r
105  */\r
106 \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
112 \r
113 #define phyADVERTISE_ALL                        ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \\r
114                                                                           phyADVERTISE_100HALF | phyADVERTISE_100FULL | \\r
115                                                                           phyADVERTISE_CSMA )\r
116 \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
119 \r
120 static BaseType_t xHas_1F_PHYSPCS( uint32_t ulPhyID )\r
121 {\r
122 BaseType_t xResult;\r
123 \r
124         switch( ulPhyID )\r
125         {\r
126                 case PHY_ID_LAN8720:\r
127                 case PHY_ID_LAN8742A:\r
128                 case PHY_ID_KSZ8041:\r
129 /*\r
130                 case PHY_ID_KSZ8051: // same ID as 8041\r
131                 case PHY_ID_KSZ8081: // same ID as 8041\r
132 */\r
133                 case PHY_ID_KSZ8081MNXIA:\r
134 \r
135                 case PHY_ID_KSZ8863:\r
136                 default:\r
137                         /* Most PHY's have a 1F_PHYSPCS */\r
138                         xResult = pdTRUE;\r
139                         break;\r
140                 case PHY_ID_DP83848I:\r
141                         xResult = pdFALSE;\r
142                         break;\r
143         }\r
144         return xResult;\r
145 }\r
146 /*-----------------------------------------------------------*/\r
147 \r
148 static BaseType_t xHas_19_PHYCR( uint32_t ulPhyID )\r
149 {\r
150 BaseType_t xResult;\r
151 \r
152         switch( ulPhyID )\r
153         {\r
154                 case PHY_ID_LAN8742A:\r
155                 case PHY_ID_DP83848I:\r
156                         xResult = pdTRUE;\r
157                         break;\r
158                 default:\r
159                         /* Most PHY's do not have a 19_PHYCR */\r
160                         xResult = pdFALSE;\r
161                         break;\r
162         }\r
163         return xResult;\r
164 }\r
165 /*-----------------------------------------------------------*/\r
166 \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
169 {\r
170         memset( ( void * )pxPhyObject, '\0', sizeof( *pxPhyObject ) );\r
171 \r
172         pxPhyObject->fnPhyRead = fnPhyRead;\r
173         pxPhyObject->fnPhyWrite = fnPhyWrite;\r
174 }\r
175 /*-----------------------------------------------------------*/\r
176 \r
177 /* Discover all PHY's connected by polling 32 indexes ( zero-based ) */\r
178 BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject )\r
179 {\r
180 BaseType_t xPhyAddress;\r
181 \r
182         pxPhyObject->xPortCount = 0;\r
183 \r
184         for( xPhyAddress = phyMIN_PHY_ADDRESS; xPhyAddress <= phyMAX_PHY_ADDRESS; xPhyAddress++ )\r
185         {\r
186         uint32_t ulLowerID;\r
187 \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
191                 {\r
192                 uint32_t ulUpperID;\r
193                 uint32_t ulPhyID;\r
194 \r
195                         pxPhyObject->fnPhyRead( xPhyAddress, phyREG_02_PHYSID1, &ulUpperID );\r
196                         ulPhyID = ( ( ( uint32_t ) ulUpperID ) << 16 ) | ( ulLowerID & 0xFFF0 );\r
197 \r
198                         pxPhyObject->ucPhyIndexes[ pxPhyObject->xPortCount ] = xPhyAddress;\r
199                         pxPhyObject->ulPhyIDs[ pxPhyObject->xPortCount ] = ulPhyID;\r
200 \r
201                         pxPhyObject->xPortCount++;\r
202 \r
203                         /* See if there is more storage space. */\r
204                         if( pxPhyObject->xPortCount == ipconfigPHY_MAX_PORTS )\r
205                         {\r
206                                 break;\r
207                         }\r
208                 }\r
209         }\r
210         if( pxPhyObject->xPortCount > 0 )\r
211         {\r
212                 FreeRTOS_printf( ( "PHY ID %lX\n", pxPhyObject->ulPhyIDs[ 0 ] ) );\r
213         }\r
214 \r
215         return pxPhyObject->xPortCount;\r
216 }\r
217 /*-----------------------------------------------------------*/\r
218 \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
221 {\r
222 uint32_t ulDoneMask, ulConfig;\r
223 TickType_t xRemainingTime;\r
224 TimeOut_t xTimer;\r
225 BaseType_t xPhyIndex;\r
226 \r
227         /* A bit-mask of PHY ports that are ready. */\r
228         ulDoneMask = 0ul;\r
229 \r
230         /* Set the RESET bits high. */\r
231         for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )\r
232         {\r
233         BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
234 \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
238         }\r
239 \r
240         xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_RESET_TIME_MS );\r
241         vTaskSetTimeOutState( &xTimer );\r
242 \r
243         /* The reset should last less than a second. */\r
244         for( ;; )\r
245         {\r
246                 for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )\r
247                 {\r
248                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
249 \r
250                         pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );\r
251                         if( ( ulConfig & phyBMCR_RESET ) == 0 )\r
252                         {\r
253                                 FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", (int)xPhyIndex ) );\r
254                                 ulDoneMask |= ( 1ul << xPhyIndex );\r
255                         }\r
256                 }\r
257                 if( ulDoneMask == ulPhyMask )\r
258                 {\r
259                         break;\r
260                 }\r
261                 if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )\r
262                 {\r
263                         FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );\r
264                         break;\r
265                 }\r
266                 /* Block for a while */\r
267                 vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );\r
268         }\r
269 \r
270         /* Clear the reset bits. */\r
271         for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )\r
272         {\r
273                 if( ( ulDoneMask & ( 1ul << xPhyIndex ) ) == 0uL )\r
274                 {\r
275                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
276 \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
280                 }\r
281         }\r
282 \r
283         vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );\r
284 \r
285         return ulDoneMask;\r
286 }\r
287 /*-----------------------------------------------------------*/\r
288 \r
289 BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties )\r
290 {\r
291 uint32_t ulConfig, ulAdvertise;\r
292 BaseType_t xPhyIndex;\r
293 \r
294         if( pxPhyObject->xPortCount < 1 )\r
295         {\r
296                 FreeRTOS_printf( ( "xPhyConfigure: No PHY's detected.\n" ) );\r
297                 return -1;\r
298         }\r
299 \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
303 \r
304     /* Set advertise register. */\r
305         if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )\r
306         {\r
307                 ulAdvertise = phyADVERTISE_ALL;\r
308                 /* Reset auto-negotiation capability. */\r
309         }\r
310         else\r
311         {\r
312                 /* Always select protocol 802.3u. */\r
313                 ulAdvertise = phyADVERTISE_CSMA;\r
314 \r
315                 if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO )\r
316                 {\r
317                         if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )\r
318                         {\r
319                                 ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_100FULL;\r
320                         }\r
321                         else\r
322                         {\r
323                                 ulAdvertise |= phyADVERTISE_10HALF | phyADVERTISE_100HALF;\r
324                         }\r
325                 }\r
326                 else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO )\r
327                 {\r
328                         if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )\r
329                         {\r
330                                 ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_10HALF;\r
331                         }\r
332                         else\r
333                         {\r
334                                 ulAdvertise |= phyADVERTISE_100FULL | phyADVERTISE_100HALF;\r
335                         }\r
336                 }\r
337                 else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 )\r
338                 {\r
339                         if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )\r
340                         {\r
341                                 ulAdvertise |= phyADVERTISE_100FULL;\r
342                         }\r
343                         else\r
344                         {\r
345                                 ulAdvertise |= phyADVERTISE_100HALF;\r
346                         }\r
347                 }\r
348                 else\r
349                 {\r
350                         if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )\r
351                         {\r
352                                 ulAdvertise |= phyADVERTISE_10FULL;\r
353                         }\r
354                         else\r
355                         {\r
356                                 ulAdvertise |= phyADVERTISE_10HALF;\r
357                         }\r
358                 }\r
359         }\r
360 \r
361         /* Send a reset command to a set of PHY-ports. */\r
362         xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) );\r
363 \r
364         for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )\r
365         {\r
366         BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
367         uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];\r
368 \r
369                 /* Write advertise register. */\r
370                 pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, ulAdvertise );\r
371 \r
372                 /*\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
385                 */\r
386 \r
387                 /* Read Control register. */\r
388                 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );\r
389 \r
390                 ulConfig &= ~( phyBMCR_SPEED_100 | phyBMCR_FULL_DUPLEX );\r
391 \r
392                 ulConfig |= phyBMCR_AN_ENABLE;\r
393 \r
394                 if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 ) || ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) )\r
395                 {\r
396                         ulConfig |= phyBMCR_SPEED_100;\r
397                 }\r
398                 else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )\r
399                 {\r
400                         ulConfig &= ~phyBMCR_SPEED_100;\r
401                 }\r
402 \r
403                 if( ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) || ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )\r
404                 {\r
405                         ulConfig |= phyBMCR_FULL_DUPLEX;\r
406                 }\r
407                 else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_HALF )\r
408                 {\r
409                         ulConfig &= ~phyBMCR_FULL_DUPLEX;\r
410                 }\r
411 \r
412                 if( xHas_19_PHYCR( ulPhyID ) )\r
413                 {\r
414                 uint32_t ulPhyControl;\r
415                         /* Read PHY Control register. */\r
416                         pxPhyObject->fnPhyRead( xPhyAddress, phyREG_19_PHYCR, &ulPhyControl );\r
417 \r
418                         /* Clear bits which might get set: */\r
419                         ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );\r
420 \r
421                         if( pxPhyProperties->ucMDI_X == PHY_MDIX_AUTO )\r
422                         {\r
423                                 ulPhyControl |= PHYCR_MDIX_EN;\r
424                         }\r
425                         else if( pxPhyProperties->ucMDI_X == PHY_MDIX_CROSSED )\r
426                         {\r
427                                 /* Force direct link = Use crossed RJ45 cable. */\r
428                                 ulPhyControl &= ~PHYCR_MDIX_FORCE;\r
429                         }\r
430                         else\r
431                         {\r
432                                 /* Force crossed link = Use direct RJ45 cable. */\r
433                                 ulPhyControl |= PHYCR_MDIX_FORCE;\r
434                         }\r
435                         /* update PHY Control Register. */\r
436                         pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_19_PHYCR, ulPhyControl );\r
437                 }\r
438 \r
439                 FreeRTOS_printf( ( "+TCP: advertise: %04lX config %04lX\n", ulAdvertise, ulConfig ) );\r
440         }\r
441 \r
442         /* Keep these values for later use. */\r
443         pxPhyObject->ulBCRValue = ulConfig & ~phyBMCR_ISOLATE;\r
444         pxPhyObject->ulACRValue = ulAdvertise;\r
445 \r
446         return 0;\r
447 }\r
448 /*-----------------------------------------------------------*/\r
449 \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
453 with ulPhyMask. */\r
454 BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )\r
455 {\r
456 BaseType_t xPhyIndex;\r
457 uint32_t ulValue, ulBitMask = ( uint32_t )1u;\r
458 \r
459         ulValue = ( uint32_t )0u;\r
460 \r
461         if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL )\r
462         {\r
463                 ulValue |= phyBMCR_FULL_DUPLEX;\r
464         }\r
465         if( pxPhyObject->xPhyPreferences.ucSpeed == PHY_SPEED_100 )\r
466         {\r
467                 ulValue |= phyBMCR_SPEED_100;\r
468         }\r
469 \r
470         for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )\r
471         {\r
472                 if( ( ulPhyMask & ulBitMask ) != 0lu )\r
473                 {\r
474                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
475 \r
476                         /* Enable Auto-Negotiation. */\r
477                         pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulValue );\r
478                 }\r
479         }\r
480         return 0;\r
481 }\r
482 /*-----------------------------------------------------------*/\r
483 \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
488 {\r
489 uint32_t xPhyIndex, ulDoneMask, ulBitMask;\r
490 uint32_t ulPHYLinkStatus, ulRegValue;\r
491 TickType_t xRemainingTime;\r
492 TimeOut_t xTimer;\r
493 \r
494         if( ulPhyMask == ( uint32_t )0u )\r
495         {\r
496                 return 0;\r
497         }\r
498         for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++ )\r
499         {\r
500                 if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu )\r
501                 {\r
502                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
503 \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
507                 }\r
508         }\r
509         xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_NEGOTIATE_TIME_MS );\r
510         vTaskSetTimeOutState( &xTimer );\r
511         ulDoneMask = 0;\r
512         /* Wait until the auto-negotiation will be completed */\r
513         for( ;; )\r
514         {\r
515                 ulBitMask = ( uint32_t )1u;\r
516                 for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )\r
517                 {\r
518                         if( ( ulPhyMask & ulBitMask ) != 0lu )\r
519                         {\r
520                                 if( ( ulDoneMask & ulBitMask ) == 0lu )\r
521                                 {\r
522                                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
523 \r
524                                         pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );\r
525                                         if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 )\r
526                                         {\r
527                                                 ulDoneMask |= ulBitMask;\r
528                                         }\r
529                                 }\r
530                         }\r
531                 }\r
532                 if( ulPhyMask == ulDoneMask )\r
533                 {\r
534                         break;\r
535                 }\r
536                 if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )\r
537                 {\r
538                         FreeRTOS_printf( ( "xPhyStartAutoNegotiation: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );\r
539                         break;\r
540                 }\r
541                 vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );\r
542         }\r
543 \r
544         if( ulDoneMask != ( uint32_t)0u )\r
545         {\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
549                 {\r
550                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
551                 uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];\r
552 \r
553                         if( ( ulDoneMask & ulBitMask ) == ( uint32_t )0u )\r
554                         {\r
555                                 continue;\r
556                         }\r
557 \r
558                         /* Clear the 'phyBMCR_AN_RESTART'  bit. */\r
559                         pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue );\r
560 \r
561                         pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue);\r
562                         if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 )\r
563                         {\r
564                                 ulPHYLinkStatus |= phyBMSR_LINK_STATUS;\r
565                                 pxPhyObject->ulLinkStatusMask |= ulBitMask;\r
566                         }\r
567                         else\r
568                         {\r
569                                 ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS );\r
570                         }\r
571 \r
572                         if( ulPhyID == PHY_ID_KSZ8081MNXIA )\r
573                         {\r
574                         uint32_t ulControlStatus;\r
575 \r
576                                 pxPhyObject->fnPhyRead( xPhyAddress, 0x1E, &ulControlStatus);\r
577                                 switch( ulControlStatus & 0x07 )\r
578                                 {\r
579                                 case 0x01:\r
580                                 case 0x05:\r
581 //      [001] = 10BASE-T half-duplex\r
582 //      [101] = 10BASE-T full-duplex\r
583                                         /* 10 Mbps. */\r
584                                         ulRegValue |= phyPHYSTS_SPEED_STATUS;\r
585                                         break;\r
586                                 case 0x02:\r
587                                 case 0x06:\r
588 //      [010] = 100BASE-TX half-duplex\r
589 //      [110] = 100BASE-TX full-duplex\r
590                                         break;\r
591                                 }\r
592                                 switch( ulControlStatus & 0x07 )\r
593                                 {\r
594                                 case 0x05:\r
595                                 case 0x06:\r
596 //      [101] = 10BASE-T full-duplex\r
597 //      [110] = 100BASE-TX full-duplex\r
598                                         /* Full duplex. */\r
599                                         ulRegValue |= phyPHYSTS_DUPLEX_STATUS;\r
600                                         break;\r
601                                 case 0x01:\r
602                                 case 0x02:\r
603 //      [001] = 10BASE-T half-duplex\r
604 //      [010] = 100BASE-TX half-duplex\r
605                                         break;\r
606                                 }\r
607                         }\r
608                         else if( xHas_1F_PHYSPCS( ulPhyID ) )\r
609                         {\r
610                         /* 31 RW PHY Special Control Status */\r
611                         uint32_t ulControlStatus;\r
612 \r
613                                 pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus);\r
614                                 ulRegValue = 0;\r
615                                 if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 )\r
616                                 {\r
617                                         ulRegValue |= phyPHYSTS_DUPLEX_STATUS;\r
618                                 }\r
619                                 if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 )\r
620                                 {\r
621                                         ulRegValue |= phyPHYSTS_SPEED_STATUS;\r
622                                 }\r
623                         }\r
624                         else\r
625                         {\r
626                                 /* Read the result of the auto-negotiation. */\r
627                                 pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue);\r
628                         }\r
629 \r
630                         FreeRTOS_printf( ( "Autonego ready: %08lx: %s duplex %u mbit %s status\n",\r
631                                 ulRegValue,\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
636                         {\r
637                                 pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;\r
638                         }\r
639                         else\r
640                         {\r
641                                 pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF;\r
642                         }\r
643 \r
644                         if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 )\r
645                         {\r
646                                 pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10;\r
647                         }\r
648                         else\r
649                         {\r
650                                 pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;\r
651                         }\r
652                 }\r
653         }       /* if( ulDoneMask != ( uint32_t)0u ) */\r
654 \r
655         return 0;\r
656 }\r
657 /*-----------------------------------------------------------*/\r
658 \r
659 BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception )\r
660 {\r
661 uint32_t ulStatus, ulBitMask = 1u;\r
662 BaseType_t xPhyIndex;\r
663 BaseType_t xNeedCheck = pdFALSE;\r
664 \r
665         if( xHadReception > 0 )\r
666         {\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
672                 {\r
673                         if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0ul )\r
674                         {\r
675                                 pxPhyObject->ulLinkStatusMask |= ulBitMask;\r
676                                 FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );\r
677                                 xNeedCheck = pdTRUE;\r
678                         }\r
679                 }\r
680         }\r
681         else if( xTaskCheckForTimeOut( &( pxPhyObject->xLinkStatusTimer ), &( pxPhyObject->xLinkStatusRemaining ) ) != pdFALSE )\r
682         {\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
687                 {\r
688                 BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];\r
689 \r
690                         if( pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulStatus ) == 0 )\r
691                         {\r
692                                 if( !!( pxPhyObject->ulLinkStatusMask & ulBitMask ) != !!( ulStatus & phyBMSR_LINK_STATUS ) )\r
693                                 {\r
694                                         if( ( ulStatus & phyBMSR_LINK_STATUS ) != 0 )\r
695                                         {\r
696                                                 pxPhyObject->ulLinkStatusMask |= ulBitMask;\r
697                                         }\r
698                                         else\r
699                                         {\r
700                                                 pxPhyObject->ulLinkStatusMask &= ~( ulBitMask );\r
701                                         }\r
702                                         FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );\r
703                                         xNeedCheck = pdTRUE;\r
704                                 }\r
705                         }\r
706                 }\r
707                 vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );\r
708                 if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 )\r
709                 {\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
712                 }\r
713                 else\r
714                 {\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
717                 }\r
718         }\r
719         return xNeedCheck;\r
720 }\r
721 /*-----------------------------------------------------------*/\r