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