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( Ð_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( Ð_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( Ð_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( Ð_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( Ð_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( Ð_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( Ð_MAC, MAC_ASYNC_RECEIVE_CB, ( FUNC_PTR ) xRxCallback );
461
462 /* Start the GMAC. */
463 mac_async_enable( Ð_MAC );
464 mac_async_enable_irq( Ð_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( Ð_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( Ð_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