xref: /FreeRTOS-Plus-TCP-v3.1.0/source/portable/NetworkInterface/ATSAME5x/NetworkInterface.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 
29 /* This driver is made to work with Atmel START's ASF4 GMAC driver.
30  * The START generated GMAC initialization code should be commented out,
31  * since this driver will take care of initializing the GMAC peripheral itself.
32  *
33  * Optimal performance is obtained with:
34  * - CRC offloading enabled for both RX and TX
35  * - "Copy all frames" set to zero / off
36  */
37 
38 /* Atmel ASF includes */
39 #include "hal_mac_async.h"
40 #include "hpl_gmac_config.h"
41 /* Include MAC initialization function here: */
42 #include "driver_init.h"
43 
44 /* FreeRTOS includes */
45 #include "FreeRTOS.h"
46 #include "task.h"
47 
48 /* FreeRTOS+TCP includes */
49 #include "FreeRTOS_IP.h"
50 #include "FreeRTOS_IP_Private.h"
51 #include "NetworkBufferManagement.h"
52 #include "phyHandling.h"
53 
54 
55 
56 /***********************************************/
57 /*           Configuration variables           */
58 /***********************************************/
59 
60 /* Check for optimal performance parameters */
61 #if ( CONF_GMAC_NCFGR_RXCOEN == 0 )
62     #warning This driver works best with RX CRC offloading enabled.
63 #endif
64 
65 #if ( CONF_GMAC_DCFGR_TXCOEN == 0 )
66     #warning This driver works best with TX CRC offloading enabled.
67 #endif
68 
69 #if ( CONF_GMAC_NCFGR_CAF != 0 )
70     #warning This driver includes GMAC hardware frame filtering for better performance.
71 #endif
72 
73 
74 /* Make sure someone takes care of the CRC calculation */
75 #if ( ( CONF_GMAC_NCFGR_RXCOEN == 0 ) && ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) )
76     #error Receive CRC offloading should be enabled.
77 #endif
78 #if ( ( CONF_GMAC_DCFGR_TXCOEN == 0 ) && ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) )
79     #error Transmit CRC offloading should be enabled.
80 #endif
81 
82 /* Setup LLMNR specific multicast address. */
83 #if ( defined( ipconfigUSE_LLMNR ) && ( ipconfigUSE_LLMNR == 1 ) )
84     static const uint8_t ucLLMNR_MAC_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
85 #endif
86 
87 /* Receive task refresh time */
88 #define RECEIVE_BLOCK_TIME_MS    100
89 
90 /***********************************************/
91 /*              FreeRTOS variables             */
92 /***********************************************/
93 
94 /* Copied from FreeRTOS_IP.c. Used for ICMP CRC calculation */
95 #define ipCORRECT_CRC    0xffffU
96 
97 /* Also copied from FreeRTOS_IP.c */
98 
99 /** @brief If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
100  * driver will filter incoming packets and only pass the stack those packets it
101  * considers need processing.  In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
102  * be #-defined away.  If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
103  * then the Ethernet driver will pass all received packets to the stack, and the
104  * stack must do the filtering itself.  In this case ipCONSIDER_FRAME_FOR_PROCESSING
105  * needs to call eConsiderFrameForProcessing.
106  */
107 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
108     #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer )    eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
109 #else
110     #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer )    eProcessBuffer
111 #endif
112 
113 /* Ethernet buffers for BufferAllocation_1.c scheme.
114  * Set ipUSE_STATIC_ALLOCATION to 1 if using BufferAllocation_1.c,
115  * otherwise to 0, to save RAM. From Iperf testing, there is no point in using
116  * static allocation with a non zero-copy driver.
117  */
118 #define ipUSE_STATIC_ALLOCATION    0
119 #if ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 ) )
120 
121 /* 1536 bytes is more than needed, 1524 would be enough.
122  * But 1536 is a multiple of 32, which gives a great alignment for cached memories. */
123     #define NETWORK_BUFFER_SIZE    1536
124     static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ NETWORK_BUFFER_SIZE ];
125 #endif /* ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 )) */
126 
127 
128 /* Holds the handle of the task used as a deferred interrupt processor.  The
129  * handle is used so direct notifications can be sent to the task for all EMAC/DMA
130  * related interrupts. */
131 TaskHandle_t xEMACTaskHandle = NULL;
132 
133 /* The PING response queue */
134 #if ( defined( ipconfigSUPPORT_OUTGOING_PINGS ) && ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) )
135     QueueHandle_t xPingReplyQueue = NULL;
136 #endif
137 
138 /* GMAC interrupt callbacks. */
139 void xRxCallback( void );
140 static void prvEMACDeferredInterruptHandlerTask( void * pvParameters );
141 
142 /***********************************************/
143 /*                GMAC variables               */
144 /***********************************************/
145 
146 /* The Ethernet MAC instance created by ASF4 */
147 extern struct mac_async_descriptor ETH_MAC;
148 
149 static void prvGMACInit( void );
150 
151 /* Enable/Disable MDC and MDIO ports for PHY register management. */
152 static inline void prvGMACEnablePHYManagementPort( bool enable );
153 
154 /* GMAC registers configuration functions. */
155 static inline void prvGMACEnable100Mbps( bool enable );
156 static inline void prvGMACEnableFullDuplex( bool enable );
157 
158 
159 /***********************************************/
160 /*                PHY variables                */
161 /***********************************************/
162 
163 /* All PHY handling code has now been separated from the NetworkInterface.c,
164  * see "../Common/phyHandling.c". */
165 static EthernetPhy_t xPhyObject;
166 
167 /* PHY link preferences. */
168 /* Set both speed and Duplex to AUTO, or give them BOTH manual values. */
169 const PhyProperties_t xPHYProperties =
170 {
171     .ucSpeed  = PHY_SPEED_AUTO,
172     .ucDuplex = PHY_DUPLEX_AUTO,
173     .ucMDI_X  = PHY_MDIX_AUTO,
174 };
175 
176 static void prvPHYLinkReset( void );
177 static void prvPHYInit( void );
178 static inline bool bPHYGetLinkStatus( void );
179 
180 /* PHY read and write functions. */
181 static BaseType_t xPHYRead( BaseType_t xAddress,
182                             BaseType_t xRegister,
183                             uint32_t * pulValue );
184 static BaseType_t xPHYWrite( BaseType_t xAddress,
185                              BaseType_t xRegister,
186                              uint32_t pulValue );
187 
188 
189 /*********************************************************************/
190 /*                      FreeRTOS+TCP functions                       */
191 /*********************************************************************/
192 
xNetworkInterfaceInitialise(void)193 BaseType_t xNetworkInterfaceInitialise( void )
194 {
195     /*
196      * Perform the hardware specific network initialization here.  Typically
197      * that will involve using the Ethernet driver library to initialize the
198      * Ethernet (or other network) hardware, initialize DMA descriptors, and
199      * perform a PHY auto-negotiation to obtain a network link. */
200 
201     if( xEMACTaskHandle == NULL )
202     {
203         /* Initialize MAC and PHY */
204         prvGMACInit();
205         prvPHYInit();
206 
207         /* (Re)set PHY link */
208         prvPHYLinkReset();
209 
210         /* Initialize PING capability */
211         #if ( defined( ipconfigSUPPORT_OUTGOING_PINGS ) && ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) )
212             xPingReplyQueue = xQueueCreate( ipconfigPING_QUEUE_SIZE, sizeof( uint16_t ) );
213         #endif
214 
215         /* Create event handler task */
216         xTaskCreate( prvEMACDeferredInterruptHandlerTask, /* Function that implements the task. */
217                      "EMACInt",                           /* Text name for the task. */
218                      256,                                 /* Stack size in words, not bytes. */
219                      ( void * ) 1,                        /* Parameter passed into the task. */
220                      configMAX_PRIORITIES - 1,            /* Priority at which the task is created. */
221                      &xEMACTaskHandle );                  /* Used to pass out the created task's handle. */
222 
223         configASSERT( xEMACTaskHandle );
224     }
225 
226     return bPHYGetLinkStatus();
227 }
228 
229 
prvEMACDeferredInterruptHandlerTask(void * pvParameters)230 static void prvEMACDeferredInterruptHandlerTask( void * pvParameters )
231 {
232     NetworkBufferDescriptor_t * pxBufferDescriptor;
233     size_t xBytesReceived = 0, xBytesRead = 0;
234 
235     uint16_t xICMPChecksumResult = ipCORRECT_CRC;
236     const IPPacket_t * pxIPPacket;
237 
238 
239     /* Used to indicate that xSendEventStructToIPTask() is being called because
240      * of an Ethernet receive event. */
241     IPStackEvent_t xRxEvent;
242 
243     for( ; ; )
244     {
245         /* Wait for the Ethernet MAC interrupt to indicate that another packet
246          * has been received.  The task notification is used in a similar way to a
247          * counting semaphore to count Rx events, but is a lot more efficient than
248          * a semaphore. */
249         ulTaskNotifyTake( pdFALSE, pdMS_TO_TICKS( RECEIVE_BLOCK_TIME_MS ) );
250 
251         /* See how much data was received.  Here it is assumed ReceiveSize() is
252          * a peripheral driver function that returns the number of bytes in the
253          * received Ethernet frame. */
254         xBytesReceived = mac_async_read_len( &ETH_MAC );
255 
256         if( xBytesReceived > 0 )
257         {
258             /* Allocate a network buffer descriptor that points to a buffer
259              * large enough to hold the received frame.  As this is the simple
260              * rather than efficient example the received data will just be copied
261              * into this buffer. */
262             pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( xBytesReceived, 0 );
263 
264             if( pxBufferDescriptor != NULL )
265             {
266                 /* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet
267                  * buffer large enough to hold the received data.  Copy the
268                  * received data into pcNetworkBuffer->pucEthernetBuffer.  Here it
269                  * is assumed ReceiveData() is a peripheral driver function that
270                  * copies the received data into a buffer passed in as the function's
271                  * parameter.  Remember! While is is a simple robust technique -
272                  * it is not efficient.  An example that uses a zero copy technique
273                  * is provided further down this page. */
274                 xBytesRead = mac_async_read( &ETH_MAC, pxBufferDescriptor->pucEthernetBuffer, xBytesReceived );
275                 pxBufferDescriptor->xDataLength = xBytesRead;
276 
277 
278                 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
279                     {
280                         /* the Atmel SAM GMAC peripheral does not support hardware CRC offloading for ICMP packets.
281                          * It must therefore be implemented in software. */
282                         pxIPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( IPPacket_t, pxBufferDescriptor->pucEthernetBuffer );
283 
284                         if( pxIPPacket->xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
285                         {
286                             xICMPChecksumResult = usGenerateProtocolChecksum( pxBufferDescriptor->pucEthernetBuffer, pxBufferDescriptor->xDataLength, pdFALSE );
287                         }
288                         else
289                         {
290                             xICMPChecksumResult = ipCORRECT_CRC; /* Reset the result value in case this is not an ICMP packet. */
291                         }
292                     }
293                 #endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) */
294 
295                 /* See if the data contained in the received Ethernet frame needs
296                 * to be processed.  NOTE! It is preferable to do this in
297                 * the interrupt service routine itself, which would remove the need
298                 * to unblock this task for packets that don't need processing. */
299                 if( ( ipCONSIDER_FRAME_FOR_PROCESSING( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer ) &&
300                     ( xICMPChecksumResult == ipCORRECT_CRC ) )
301                 {
302                     /* The event about to be sent to the TCP/IP is an Rx event. */
303                     xRxEvent.eEventType = eNetworkRxEvent;
304 
305                     /* pvData is used to point to the network buffer descriptor that
306                      * now references the received data. */
307                     xRxEvent.pvData = ( void * ) pxBufferDescriptor;
308 
309                     /* Send the data to the TCP/IP stack. */
310                     if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
311                     {
312                         /* The buffer could not be sent to the IP task so the buffer
313                          * must be released. */
314                         vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
315 
316                         /* Make a call to the standard trace macro to log the
317                          * occurrence. */
318                         iptraceETHERNET_RX_EVENT_LOST();
319                     }
320                     else
321                     {
322                         /* The message was successfully sent to the TCP/IP stack.
323                         * Call the standard trace macro to log the occurrence. */
324                         iptraceNETWORK_INTERFACE_RECEIVE();
325                     }
326                 }
327                 else
328                 {
329                     /* The Ethernet frame can be dropped, but the Ethernet buffer
330                      * must be released. */
331                     vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
332                 }
333             }
334             else
335             {
336                 /* The event was lost because a network buffer was not available.
337                  * Call the standard trace macro to log the occurrence. */
338                 iptraceETHERNET_RX_EVENT_LOST();
339             }
340         }
341 
342         prvGMACEnablePHYManagementPort( true );
343 
344         if( xPhyCheckLinkStatus( &xPhyObject, xBytesReceived ) )
345         {
346             prvPHYLinkReset();
347         }
348 
349         prvGMACEnablePHYManagementPort( false );
350     }
351 }
352 
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t xReleaseAfterSend)353 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
354                                     BaseType_t xReleaseAfterSend )
355 {
356     /* Simple network interfaces (as opposed to more efficient zero copy network
357      * interfaces) just use Ethernet peripheral driver library functions to copy
358      * data from the FreeRTOS+TCP buffer into the peripheral driver's own buffer.
359      * This example assumes SendData() is a peripheral driver library function that
360      * takes a pointer to the start of the data to be sent and the length of the
361      * data to be sent as two separate parameters.  The start of the data is located
362      * by pxDescriptor->pucEthernetBuffer.  The length of the data is located
363      * by pxDescriptor->xDataLength. */
364 
365     if( bPHYGetLinkStatus() )
366     {
367         #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 )
368             {
369                 /* the Atmel SAM GMAC peripheral does not support hardware CRC offloading for ICMP packets.
370                  * It must therefore be implemented in software. */
371                 const IPPacket_t * pxIPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( IPPacket_t, pxDescriptor->pucEthernetBuffer );
372 
373                 if( pxIPPacket->xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
374                 {
375                     ( void ) usGenerateProtocolChecksum( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, pdTRUE );
376                 }
377             }
378         #endif
379 
380         mac_async_write( &ETH_MAC, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
381 
382         /* Call the standard trace macro to log the send event. */
383         iptraceNETWORK_INTERFACE_TRANSMIT();
384     }
385 
386     if( xReleaseAfterSend != pdFALSE )
387     {
388         /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet
389          * buffer.  The Ethernet buffer is therefore no longer needed, and must be
390          * freed for re-use. */
391         vReleaseNetworkBufferAndDescriptor( pxDescriptor );
392     }
393 
394     return pdTRUE;
395 }
396 
xRxCallback(void)397 void xRxCallback( void )
398 {
399     vTaskNotifyGiveFromISR( xEMACTaskHandle, 0 );
400 }
401 
402 #if ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 ) )
403 
404 /* Next provide the vNetworkInterfaceAllocateRAMToBuffers() function, which
405  * simply fills in the pucEthernetBuffer member of each descriptor. */
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])406     void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
407     {
408         BaseType_t x;
409 
410         for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
411         {
412             /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the
413              * beginning of the allocated buffer. */
414             pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] );
415 
416             /* The following line is also required, but will not be required in
417              * future versions. */
418             *( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) &( pxNetworkBuffers[ x ] );
419         }
420     }
421 #endif /* ( defined( ipUSE_STATIC_ALLOCATION ) && ( ipUSE_STATIC_ALLOCATION == 1 )) */
422 
423 
424 /*********************************************************************/
425 /*                          GMAC functions                           */
426 /*********************************************************************/
427 
428 /* Initializes the GMAC peripheral. This function is based on ASF4 GMAC initialization
429  * and uses the Atmel START- generated code, typically located in "driver_init.h".
430  * Make sure the initialization function is not called twice, e.g. comment out the call in "driver_init.c".
431  * It is compatible with modifications made in Atmel START afterwards because the
432  * configuration is saved in "hpl_gmac_config.h". */
prvGMACInit()433 static void prvGMACInit()
434 {
435     /* Call MAC initialization function here: */
436     vGMACInit();
437     prvGMACEnablePHYManagementPort( false );
438     mac_async_disable_irq( &ETH_MAC );
439 
440     /* Set GMAC Filtering for own MAC address */
441     struct mac_async_filter mac_filter;
442     memcpy( mac_filter.mac, ipLOCAL_MAC_ADDRESS, ipMAC_ADDRESS_LENGTH_BYTES );
443     mac_filter.tid_enable = false;
444     mac_async_set_filter( &ETH_MAC, 0, &mac_filter );
445 
446     /* Set GMAC filtering for LLMNR, if defined. */
447     #if ( defined( ipconfigUSE_LLMNR ) && ( ipconfigUSE_LLMNR == 1 ) )
448         {
449             memcpy( mac_filter.mac, ucLLMNR_MAC_address, ipMAC_ADDRESS_LENGTH_BYTES );
450             /* LLMNR requires responders to listen to both TCP and UDP protocols. */
451             mac_filter.tid_enable = false;
452             mac_async_set_filter( &ETH_MAC, 1, &mac_filter );
453         }
454     #endif
455 
456     /* Set GMAC interrupt priority to be compatible with FreeRTOS API */
457     NVIC_SetPriority( GMAC_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY >> ( 8 - configPRIO_BITS ) );
458 
459     /* Register callback(s). Currently only RX callback is implemented, but TX callback can be added the same way. */
460     mac_async_register_callback( &ETH_MAC, MAC_ASYNC_RECEIVE_CB, ( FUNC_PTR ) xRxCallback );
461 
462     /* Start the GMAC. */
463     mac_async_enable( &ETH_MAC );
464     mac_async_enable_irq( &ETH_MAC );
465 }
466 
prvGMACEnablePHYManagementPort(bool enable)467 static inline void prvGMACEnablePHYManagementPort( bool enable )
468 {
469     if( enable )
470     {
471         ( ( Gmac * ) ETH_MAC.dev.hw )->NCR.reg |= GMAC_NCR_MPE;
472     }
473     else
474     {
475         ( ( Gmac * ) ETH_MAC.dev.hw )->NCR.reg &= ~GMAC_NCR_MPE;
476     }
477 }
478 
prvGMACEnable100Mbps(bool enable)479 static inline void prvGMACEnable100Mbps( bool enable )
480 {
481     if( enable )
482     {
483         ( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg |= GMAC_NCFGR_SPD;
484     }
485     else
486     {
487         ( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg &= ~GMAC_NCFGR_SPD;
488     }
489 }
490 
prvGMACEnableFullDuplex(bool enable)491 static inline void prvGMACEnableFullDuplex( bool enable )
492 {
493     if( enable )
494     {
495         ( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg |= GMAC_NCFGR_FD;
496     }
497     else
498     {
499         ( ( Gmac * ) ETH_MAC.dev.hw )->NCFGR.reg &= ~GMAC_NCFGR_FD;
500     }
501 }
502 
503 
504 /*********************************************************************/
505 /*                           PHY functions                           */
506 /*********************************************************************/
507 
508 /* Initializes the PHY hardware. Based on ASF4 generated code. */
prvPHYInit()509 static void prvPHYInit()
510 {
511     prvGMACEnablePHYManagementPort( true );
512 
513     vPhyInitialise( &xPhyObject, &xPHYRead, &xPHYWrite );
514     xPhyDiscover( &xPhyObject );
515     xPhyConfigure( &xPhyObject, &xPHYProperties );
516 
517     prvGMACEnablePHYManagementPort( false );
518 }
519 
520 /* Start a new link negotiation on the PHY and wait until link is up. */
prvPHYLinkReset()521 static void prvPHYLinkReset()
522 {
523     /* Restart an auto-negotiation */
524     prvGMACEnablePHYManagementPort( true );
525 
526     if( ( xPHYProperties.ucDuplex == PHY_DUPLEX_AUTO ) && ( xPHYProperties.ucSpeed == PHY_SPEED_AUTO ) && ( xPHYProperties.ucMDI_X == PHY_MDIX_AUTO ) )
527     {
528         /* Auto-negotiation */
529         xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
530 
531         /* Update the MAC with the auto-negotiation result parameters. */
532         prvGMACEnableFullDuplex( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL );
533         prvGMACEnable100Mbps( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_100 );
534     }
535     else
536     {
537         /* Fixed values */
538         xPhyObject.xPhyPreferences.ucDuplex = xPHYProperties.ucDuplex;
539         xPhyObject.xPhyPreferences.ucSpeed = xPHYProperties.ucSpeed;
540         xPhyObject.xPhyPreferences.ucMDI_X = xPHYProperties.ucMDI_X;
541         xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
542 
543         /* Update the MAC with the auto-negotiation result parameters. */
544         prvGMACEnableFullDuplex( xPHYProperties.ucDuplex == PHY_DUPLEX_FULL );
545         prvGMACEnable100Mbps( xPHYProperties.ucSpeed == PHY_SPEED_100 );
546     }
547 
548     prvGMACEnablePHYManagementPort( false );
549 }
550 
xPHYRead(BaseType_t xAddress,BaseType_t xRegister,uint32_t * pulValue)551 static BaseType_t xPHYRead( BaseType_t xAddress,
552                             BaseType_t xRegister,
553                             uint32_t * pulValue )
554 {
555     prvGMACEnablePHYManagementPort( true );
556     BaseType_t readStatus = mac_async_read_phy_reg( &ETH_MAC, xAddress, xRegister, ( ( uint16_t * ) pulValue ) );
557     prvGMACEnablePHYManagementPort( false );
558     return readStatus;
559 }
560 
xPHYWrite(BaseType_t xAddress,BaseType_t xRegister,uint32_t pulValue)561 static BaseType_t xPHYWrite( BaseType_t xAddress,
562                              BaseType_t xRegister,
563                              uint32_t pulValue )
564 {
565     prvGMACEnablePHYManagementPort( true );
566     BaseType_t writeStatus = mac_async_write_phy_reg( &ETH_MAC, xAddress, xRegister, pulValue );
567     prvGMACEnablePHYManagementPort( false );
568     return writeStatus;
569 }
570 
bPHYGetLinkStatus(void)571 static inline bool bPHYGetLinkStatus( void )
572 {
573     return( xPhyObject.ulLinkStatusMask != 0 );
574 }
575