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 /* FreeRTOS includes. */
29 #include "LPC54018.h"
30 #include "FreeRTOS.h"
31 #include "list.h"
32
33 #include <stdbool.h>
34
35 /* FreeRTOS+TCP includes. */
36 #include "FreeRTOS_IP.h"
37
38 #include "FreeRTOS_IP_Private.h"
39 #include "NetworkBufferManagement.h"
40
41 #include "fsl_enet.h"
42 #include "fsl_phy.h"
43
44 #include "fsl_enet_mdio.h"
45 #include "fsl_phylan8720a.h"
46 #include "fsl_debug_console.h"
47
48 #define PHY_ADDRESS ( 0x00U )
49 /* MDIO operations. */
50 #define EXAMPLE_MDIO_OPS lpc_enet_ops
51 /* PHY operations. */
52 #define EXAMPLE_PHY_OPS phylan8720a_ops
53 #define ENET_RXBD_NUM ( 4 )
54 #define ENET_TXBD_NUM ( 4 )
55 #define ENET_RXBUFF_SIZE ( ENET_FRAME_MAX_FRAMELEN )
56 #define ENET_BuffSizeAlign( n ) ENET_ALIGN( n, ENET_BUFF_ALIGNMENT )
57 #define ENET_ALIGN( x, align ) ( ( unsigned int ) ( ( x ) + ( ( align ) - 1 ) ) & ( unsigned int ) ( ~( unsigned int ) ( ( align ) - 1 ) ) )
58
59 #if defined( __GNUC__ )
60 #ifndef __ALIGN_END
61 #define __ALIGN_END __attribute__( ( aligned( ENET_BUFF_ALIGNMENT ) ) )
62 #endif
63 #ifndef __ALIGN_BEGIN
64 #define __ALIGN_BEGIN
65 #endif
66 #else
67 #ifndef __ALIGN_END
68 #define __ALIGN_END
69 #endif
70 #ifndef __ALIGN_BEGIN
71 #if defined( __CC_ARM ) || defined( __ARMCC_VERSION )
72 #define __ALIGN_BEGIN __attribute__( ( aligned( ENET_BUFF_ALIGNMENT ) ) )
73 #elif defined( __ICCARM__ )
74 #define __ALIGN_BEGIN
75 #endif
76 #endif
77 #endif /* if defined( __GNUC__ ) */
78
79 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
80 * driver will filter incoming packets and only pass the stack those packets it
81 * considers need processing. */
82 #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
83 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
84 #else
85 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
86 #endif
87
88 #ifndef NETWORK_INTERFACE_RX_PRIORITY
89 #define NETWORK_INTERFACE_RX_PRIORITY ( configMAX_PRIORITIES - 1 )
90 #endif
91
92 /*******************************************************************************
93 * Variables
94 ******************************************************************************/
95 #if defined( __ICCARM__ )
96 #pragma data_alignment = ENET_BUFF_ALIGNMENT
97 #endif
98 __ALIGN_BEGIN enet_rx_bd_struct_t g_rxBuffDescrip[ ENET_RXBD_NUM ] __ALIGN_END;
99 #if defined( __ICCARM__ )
100 #pragma data_alignment = ENET_BUFF_ALIGNMENT
101 #endif
102 __ALIGN_BEGIN enet_tx_bd_struct_t g_txBuffDescrip[ ENET_TXBD_NUM ] __ALIGN_END;
103
104 enet_handle_t g_handle = { 0 };
105 /* The MAC address for ENET device. */
106 uint8_t g_macAddr[ 6 ] = { 0xde, 0xad, 0x00, 0xbe, 0xef, 0x01 };
107
108 bool g_linkStatus = false;
109
110 /*! @brief Enet PHY and MDIO interface handler. */
111 static mdio_handle_t mdioHandle = { .ops = &EXAMPLE_MDIO_OPS };
112 static phy_handle_t phyHandle = { .phyAddr = PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &EXAMPLE_PHY_OPS };
113
114 __ALIGN_BEGIN uint32_t receiveBuffer[ ENET_RXBD_NUM ][ ENET_RXBUFF_SIZE / sizeof( uint32_t ) + 1 ] __ALIGN_END;
115 uint32_t rxbuffer[ ENET_RXBD_NUM ];
116
117 TaskHandle_t receiveTaskHandle;
118
ENET_IntCallback(ENET_Type * base,enet_handle_t * handle,enet_event_t event,uint8_t channel,void * param)119 void ENET_IntCallback( ENET_Type * base,
120 enet_handle_t * handle,
121 enet_event_t event,
122 uint8_t channel,
123 void * param )
124 {
125 BaseType_t needsToYield = pdFALSE;
126
127 switch( event )
128 {
129 case kENET_TxIntEvent:
130 break;
131
132 case kENET_RxIntEvent:
133 vTaskNotifyGiveFromISR( receiveTaskHandle, &needsToYield );
134 portEND_SWITCHING_ISR( needsToYield );
135 break;
136
137 default:
138 break;
139 }
140 }
141
prvProcessFrame(int length)142 static void prvProcessFrame( int length )
143 {
144 NetworkBufferDescriptor_t * pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( length, 0 );
145
146 if( pxBufferDescriptor != NULL )
147 {
148 ENET_ReadFrame( ENET, &g_handle, pxBufferDescriptor->pucEthernetBuffer, length, 0 );
149 pxBufferDescriptor->xDataLength = length;
150
151 if( ipCONSIDER_FRAME_FOR_PROCESSING( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer )
152 {
153 IPStackEvent_t xRxEvent;
154 xRxEvent.eEventType = eNetworkRxEvent;
155 xRxEvent.pvData = ( void * ) pxBufferDescriptor;
156
157 if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
158 {
159 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
160 iptraceETHERNET_RX_EVENT_LOST();
161 PRINTF( "RX Event Lost\n" );
162 }
163 }
164 else
165 {
166 PRINTF( "RX Event not to be considered\n" );
167 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
168 /* Not sure if a trace is required. The stack did not want this message */
169 }
170 }
171 else
172 {
173 PRINTF( "RX No Buffer Available\n" );
174 ENET_ReadFrame( ENET, &g_handle, NULL, 0, 0 );
175 /* No buffer available to receive this message */
176 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
177 }
178 }
179
rx_task(void * parameter)180 static void rx_task( void * parameter )
181 {
182 while( pdTRUE )
183 {
184 if( ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( 500 ) ) == pdFALSE ) /* no RX packets for a bit so check for a link */
185 {
186 PHY_GetLinkStatus( &phyHandle, &g_linkStatus );
187 }
188 else
189 {
190 BaseType_t receiving = pdTRUE;
191
192 while( receiving == pdTRUE )
193 {
194 uint32_t length;
195 const status_t status = ENET_GetRxFrameSize( ENET, &g_handle, &length, 0 );
196
197 switch( status )
198 {
199 case kStatus_Success: /* there is a frame. process it */
200
201 if( length )
202 {
203 prvProcessFrame( length );
204 }
205
206 break;
207
208 case kStatus_ENET_RxFrameEmpty: /* Received an empty frame. Ignore it */
209 receiving = pdFALSE;
210 break;
211
212 case kStatus_ENET_RxFrameError: /* Received an error frame. Read & drop it */
213 PRINTF( "RX Receive Error\n" );
214 ENET_ReadFrame( ENET, &g_handle, NULL, 0, 0 );
215 /* Not sure if a trace is required. The MAC had an error and needed to dump bytes */
216 break;
217
218 default:
219 PRINTF( "RX Receive default\n" );
220 break;
221 }
222 }
223 }
224 }
225 }
226
xGetPhyLinkStatus(void)227 BaseType_t xGetPhyLinkStatus( void )
228 {
229 return g_linkStatus ? pdTRUE : pdFALSE;
230 }
231
232
xNetworkInterfaceInitialise(void)233 BaseType_t xNetworkInterfaceInitialise( void )
234 {
235 BaseType_t returnValue = pdFAIL;
236 static enum
237 {
238 initPhy, waitForLink, startReceiver, configurePhy
239 }
240 networkInitialisePhase = initPhy;
241
242 switch( networkInitialisePhase )
243 {
244 default:
245 networkInitialisePhase = initPhy;
246
247 /* fall through */
248 case initPhy:
249 {
250 phy_config_t phyConfig;
251 phyConfig.phyAddr = PHY_ADDRESS;
252 phyConfig.autoNeg = true;
253 mdioHandle.resource.base = ENET;
254
255 status_t status = PHY_Init( &phyHandle, &phyConfig );
256
257 if( status == kStatus_PHY_AutoNegotiateFail )
258 {
259 PRINTF( "\nPHY Auto-negotiation failed. Please check the cable connection and link partner setting.\n" );
260 break;
261 }
262 }
263
264 case startReceiver:
265 networkInitialisePhase = startReceiver;
266
267 if( xTaskCreate( rx_task, "rx_task", 512, NULL, NETWORK_INTERFACE_RX_PRIORITY, &receiveTaskHandle ) != pdPASS )
268 {
269 PRINTF( "Network Receive Task creation failed!.\n" );
270 break;
271 }
272
273 /* fall through */
274 case waitForLink:
275 networkInitialisePhase = waitForLink;
276 {
277 if( !xGetPhyLinkStatus() )
278 {
279 PRINTF( "No Link\n" );
280 break;
281 }
282 }
283
284 /* fall through */
285 case configurePhy:
286 {
287 networkInitialisePhase = configurePhy;
288 enet_config_t config;
289 phy_speed_t speed;
290 phy_duplex_t duplex;
291 PHY_GetLinkSpeedDuplex( &phyHandle, &speed, &duplex );
292 /* Get default configuration 100M RMII. */
293 ENET_GetDefaultConfig( &config );
294
295 /* Use the actual speed and duplex when phy success to finish the autonegotiation. */
296 config.miiSpeed = ( enet_mii_speed_t ) speed;
297 config.miiDuplex = ( enet_mii_duplex_t ) duplex;
298
299 /* Initialize ENET. */
300 uint32_t refClock = 50000000; /* 50MHZ for rmii reference clock. */
301 ENET_Init( ENET, &config, g_macAddr, refClock );
302
303 /* Enable the rx interrupt. */
304 ENET_EnableInterrupts( ENET, ( kENET_DmaRx ) );
305
306 /* Initialize Descriptor. */
307 int bufferIndex;
308
309 for( bufferIndex = 0; bufferIndex < ENET_RXBD_NUM; bufferIndex++ )
310 {
311 rxbuffer[ bufferIndex ] = ( uint32_t ) &receiveBuffer[ bufferIndex ];
312 }
313
314 /* prepare the buffer configuration. */
315 enet_buffer_config_t buffConfig[ 1 ] =
316 {
317 {
318 ENET_RXBD_NUM, ENET_TXBD_NUM,
319 &g_txBuffDescrip[ 0 ], &g_txBuffDescrip[ 0 ],
320 &g_rxBuffDescrip[ 0 ], &g_rxBuffDescrip[ ENET_RXBD_NUM ],
321 &rxbuffer[ 0 ], ENET_BuffSizeAlign( ENET_RXBUFF_SIZE ),
322 }
323 };
324 ENET_DescriptorInit( ENET, &config, &buffConfig[ 0 ] );
325
326 /* Create the handler. */
327 ENET_CreateHandler( ENET, &g_handle, &config, &buffConfig[ 0 ], ENET_IntCallback, NULL );
328 NVIC_SetPriority( 65 - 16, 4 ); /* TODO this is a hack and I would expect a nice ENET API for priority. */
329
330 /* Active TX/RX. */
331 ENET_StartRxTx( ENET, 1, 1 );
332 }
333 returnValue = pdPASS;
334 break;
335 }
336
337 return returnValue;
338 }
339
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t xReleaseAfterSend)340 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
341 BaseType_t xReleaseAfterSend )
342 {
343 BaseType_t response = pdFALSE;
344 status_t status;
345
346 if( xGetPhyLinkStatus() )
347 {
348 status = ENET_SendFrame( ENET, &g_handle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
349
350 switch( status )
351 {
352 default: /* anything not Success will be a failure */
353 case kStatus_ENET_TxFrameBusy:
354 PRINTF( "TX Frame Busy\n" );
355 break;
356
357 case kStatus_Success:
358 iptraceNETWORK_INTERFACE_TRANSMIT();
359 response = pdTRUE;
360 break;
361 }
362 }
363
364 if( xReleaseAfterSend != pdFALSE )
365 {
366 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
367 }
368
369 return response;
370 }
371
372 /* statically allocate the buffers */
373 /* allocating them as uint32_t's to force them into word alignment, a requirement of the DMA. */
374 __ALIGN_BEGIN static uint32_t buffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ ( ipBUFFER_PADDING + ENET_RXBUFF_SIZE ) / sizeof( uint32_t ) + 1 ] __ALIGN_END;
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])375 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
376 {
377 for( int x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
378 {
379 pxNetworkBuffers[ x ].pucEthernetBuffer = ( uint8_t * ) &buffers[ x ][ 0 ] + ipBUFFER_PADDING;
380 buffers[ x ][ 0 ] = ( uint32_t ) &pxNetworkBuffers[ x ];
381 }
382 }
383