]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RX600_RX63N-RSK_Renesas/RTOSDemo/webserver/EMAC.c
Fix spelling issues.
[freertos] / FreeRTOS / Demo / RX600_RX63N-RSK_Renesas / RTOSDemo / webserver / EMAC.c
1 /*\r
2  * FreeRTOS Kernel V10.1.0\r
3  * Copyright (C) 2018 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://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /* Hardware specific includes. */\r
29 #include "platform.h"\r
30 #include "r_ether.h"\r
31 #include "phy.h"\r
32 \r
33 /* FreeRTOS includes. */\r
34 #include "FreeRTOS.h"\r
35 #include "task.h"\r
36 #include "semphr.h"\r
37 \r
38 /* uIP includes. */\r
39 #include "net/uip.h"\r
40 \r
41 /* The time to wait between attempts to obtain a free buffer. */\r
42 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_PERIOD_MS )\r
43 \r
44 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving\r
45 up on attempting to obtain a free buffer all together. */\r
46 #define emacBUFFER_WAIT_ATTEMPTS        ( 30 )\r
47 \r
48 /* The number of Rx descriptors. */\r
49 #define emacNUM_RX_DESCRIPTORS  8\r
50 \r
51 /* The number of Tx descriptors.  When using uIP there is not point in having\r
52 more than two. */\r
53 #define emacNUM_TX_BUFFERS      2\r
54 \r
55 /* The total number of EMAC buffers to allocate. */\r
56 #define emacNUM_BUFFERS         ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )\r
57 \r
58 /* The time to wait for the Tx descriptor to become free. */\r
59 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_PERIOD_MS )\r
60 \r
61 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to\r
62 become free. */\r
63 #define emacTX_WAIT_ATTEMPTS ( 50 )\r
64 \r
65 /* Only Rx end and Tx end interrupts are used by this driver. */\r
66 #define emacTX_END_INTERRUPT    ( 1UL << 21UL )\r
67 #define emacRX_END_INTERRUPT    ( 1UL << 18UL )\r
68 \r
69 /*-----------------------------------------------------------*/\r
70 \r
71 /* The buffers and descriptors themselves.  */\r
72 #pragma section _RX_DESC\r
73         volatile ethfifo xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];\r
74 #pragma section _TX_DESC\r
75         volatile ethfifo xTxDescriptors[ emacNUM_TX_BUFFERS ];\r
76 #pragma section _ETHERNET_BUFFERS\r
77         struct\r
78         {\r
79                 unsigned long ulAlignmentVariable;\r
80                 char cBuffer[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];\r
81         } xEthernetBuffers;\r
82 #pragma section\r
83 \r
84 \r
85 \r
86 \r
87 /* Used to indicate which buffers are free and which are in use.  If an index\r
88 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise \r
89 the buffer is in use or about to be used. */\r
90 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];\r
91 \r
92 /*-----------------------------------------------------------*/\r
93 \r
94 /*\r
95  * Initialise both the Rx and Tx descriptors.\r
96  */\r
97 static void prvInitialiseDescriptors( void );\r
98 \r
99 /*\r
100  * Return a pointer to a free buffer within xEthernetBuffers.\r
101  */\r
102 static unsigned char *prvGetNextBuffer( void );\r
103 \r
104 /*\r
105  * Return a buffer to the list of free buffers.\r
106  */\r
107 static void prvReturnBuffer( unsigned char *pucBuffer );\r
108 \r
109 /*\r
110  * Examine the status of the next Rx FIFO to see if it contains new data.\r
111  */\r
112 static unsigned long prvCheckRxFifoStatus( void );\r
113 \r
114 /*\r
115  * Setup the microcontroller for communication with the PHY.\r
116  */\r
117 static void prvResetMAC( void );\r
118 \r
119 /*\r
120  * Configure the Ethernet interface peripherals.\r
121  */\r
122 static void prvConfigureEtherCAndEDMAC( void );\r
123 \r
124 /*\r
125  * Something has gone wrong with the descriptor usage.  Reset all the buffers\r
126  * and descriptors.\r
127  */\r
128 static void prvResetEverything( void );\r
129 \r
130 /*-----------------------------------------------------------*/\r
131 \r
132 /* Points to the Rx descriptor currently in use. */\r
133 static ethfifo *pxCurrentRxDesc = NULL;\r
134 \r
135 /* The buffer used by the uIP stack to both receive and send.  This points to\r
136 one of the Ethernet buffers when its actually in use. */\r
137 unsigned char *uip_buf = NULL;\r
138 \r
139 /*-----------------------------------------------------------*/\r
140 \r
141 void vInitEmac( void )\r
142 {\r
143         /* Software reset. */\r
144         prvResetMAC();\r
145         \r
146         /* Set the Rx and Tx descriptors into their initial state. */\r
147         prvInitialiseDescriptors();\r
148 \r
149         /* Set the MAC address into the ETHERC */\r
150         ETHERC.MAHR =   ( ( unsigned long ) configMAC_ADDR0 << 24UL ) | \r
151                                         ( ( unsigned long ) configMAC_ADDR1 << 16UL ) | \r
152                                         ( ( unsigned long ) configMAC_ADDR2 << 8UL ) | \r
153                                         ( unsigned long ) configMAC_ADDR3;\r
154                                         \r
155         ETHERC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |\r
156                                                  ( unsigned long ) configMAC_ADDR5;\r
157 \r
158         /* Perform rest of interface hardware configuration. */\r
159         prvConfigureEtherCAndEDMAC();\r
160         \r
161         /* Nothing received yet, so uip_buf points nowhere. */\r
162         uip_buf = NULL;\r
163 \r
164         /* Initialize the PHY */\r
165         phy_init();\r
166 }\r
167 /*-----------------------------------------------------------*/\r
168 \r
169 void vEMACWrite( void )\r
170 {\r
171 long x;\r
172 \r
173         /* Wait until the second transmission of the last packet has completed. */\r
174         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )\r
175         {\r
176                 if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )\r
177                 {\r
178                         /* Descriptor is still active. */\r
179                         vTaskDelay( emacTX_WAIT_DELAY_ms );\r
180                 }\r
181                 else\r
182                 {\r
183                         break;\r
184                 }\r
185         }\r
186         \r
187         /* Is the descriptor free after waiting for it? */\r
188         if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )\r
189         {\r
190                 /* Something has gone wrong. */\r
191                 prvResetEverything();\r
192         }\r
193         \r
194         /* Setup both descriptors to transmit the frame. */\r
195         xTxDescriptors[ 0 ].buf_p = ( char * ) uip_buf;\r
196         xTxDescriptors[ 0 ].bufsize = uip_len;  \r
197         xTxDescriptors[ 1 ].buf_p = ( char * ) uip_buf;\r
198         xTxDescriptors[ 1 ].bufsize = uip_len;\r
199 \r
200         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer\r
201         for use by the stack. */\r
202         uip_buf = prvGetNextBuffer();\r
203 \r
204         /* Clear previous settings and go. */\r
205         xTxDescriptors[0].status &= ~( FP1 | FP0 );\r
206         xTxDescriptors[0].status |= ( FP1 | FP0 | ACT );\r
207         xTxDescriptors[1].status &= ~( FP1 | FP0 );\r
208         xTxDescriptors[1].status |= ( FP1 | FP0 | ACT );\r
209 \r
210         EDMAC.EDTRR.LONG = 0x00000001;\r
211 }\r
212 /*-----------------------------------------------------------*/\r
213 \r
214 unsigned long ulEMACRead( void )\r
215 {\r
216 unsigned long ulBytesReceived;\r
217 \r
218         ulBytesReceived = prvCheckRxFifoStatus();\r
219 \r
220         if( ulBytesReceived > 0 )\r
221         {\r
222                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to\r
223                 the buffer that contains the received data. */\r
224                 prvReturnBuffer( uip_buf );\r
225 \r
226                 /* Point uip_buf to the data about ot be processed. */\r
227                 uip_buf = ( void * ) pxCurrentRxDesc->buf_p;\r
228                 \r
229                 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's\r
230                 old descriptor. */\r
231                 pxCurrentRxDesc->buf_p = prvGetNextBuffer();\r
232 \r
233                 /* Prepare the descriptor to go again. */\r
234                 pxCurrentRxDesc->status &= ~( FP1 | FP0 );\r
235                 pxCurrentRxDesc->status |= ACT;\r
236 \r
237                 /* Move onto the next buffer in the ring. */\r
238                 pxCurrentRxDesc = pxCurrentRxDesc->next;\r
239                 \r
240                 if( EDMAC.EDRRR.LONG == 0x00000000L )\r
241                 {\r
242                         /* Restart Ethernet if it has stopped */\r
243                         EDMAC.EDRRR.LONG = 0x00000001L;\r
244                 }\r
245         }\r
246 \r
247         return ulBytesReceived;\r
248 }\r
249 /*-----------------------------------------------------------*/\r
250 \r
251 long lEMACWaitForLink( void )\r
252 {\r
253 long lReturn;\r
254 \r
255         /* Set the link status. */\r
256         switch( phy_set_autonegotiate() )\r
257         {\r
258                 /* Half duplex link */\r
259                 case PHY_LINK_100H:\r
260                                                                 ETHERC.ECMR.BIT.DM = 0;\r
261                                                                 ETHERC.ECMR.BIT.RTM = 1;\r
262                                                                 lReturn = pdPASS;\r
263                                                                 break;\r
264 \r
265                 case PHY_LINK_10H:\r
266                                                                 ETHERC.ECMR.BIT.DM = 0;\r
267                                                                 ETHERC.ECMR.BIT.RTM = 0;\r
268                                                                 lReturn = pdPASS;\r
269                                                                 break;\r
270 \r
271 \r
272                 /* Full duplex link */\r
273                 case PHY_LINK_100F:\r
274                                                                 ETHERC.ECMR.BIT.DM = 1;\r
275                                                                 ETHERC.ECMR.BIT.RTM = 1;\r
276                                                                 lReturn = pdPASS;\r
277                                                                 break;\r
278                 \r
279                 case PHY_LINK_10F:\r
280                                                                 ETHERC.ECMR.BIT.DM = 1;\r
281                                                                 ETHERC.ECMR.BIT.RTM = 0;\r
282                                                                 lReturn = pdPASS;\r
283                                                                 break;\r
284 \r
285                 default:\r
286                                                                 lReturn = pdFAIL;\r
287                                                                 break;\r
288         }\r
289 \r
290         if( lReturn == pdPASS )\r
291         {\r
292                 /* Enable receive and transmit. */\r
293                 ETHERC.ECMR.BIT.RE = 1;\r
294                 ETHERC.ECMR.BIT.TE = 1;\r
295 \r
296                 /* Enable EDMAC receive */\r
297                 EDMAC.EDRRR.LONG = 0x1;\r
298         }\r
299         \r
300         return lReturn;\r
301 }\r
302 /*-----------------------------------------------------------*/\r
303 \r
304 static void prvInitialiseDescriptors( void )\r
305 {\r
306 ethfifo *pxDescriptor;\r
307 long x;\r
308 \r
309         for( x = 0; x < emacNUM_BUFFERS; x++ )\r
310         {\r
311                 /* Ensure none of the buffers are shown as in use at the start. */\r
312                 ucBufferInUse[ x ] = pdFALSE;\r
313         }\r
314 \r
315         /* Initialise the Rx descriptors. */\r
316         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )\r
317         {\r
318                 pxDescriptor = &( xRxDescriptors[ x ] );\r
319                 pxDescriptor->buf_p = &( xEthernetBuffers.cBuffer[ x ][ 0 ] );\r
320 \r
321                 pxDescriptor->bufsize = UIP_BUFSIZE;\r
322                 pxDescriptor->size = 0;\r
323                 pxDescriptor->status = ACT;\r
324                 pxDescriptor->next = &xRxDescriptors[ x + 1 ];  \r
325                 \r
326                 /* Mark this buffer as in use. */\r
327                 ucBufferInUse[ x ] = pdTRUE;\r
328         }\r
329 \r
330         /* The last descriptor points back to the start. */\r
331         pxDescriptor->status |= DL;\r
332         pxDescriptor->next = &xRxDescriptors[ 0 ];\r
333         \r
334         /* Initialise the Tx descriptors. */\r
335         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )\r
336         {\r
337                 pxDescriptor = &( xTxDescriptors[ x ] );\r
338                 \r
339                 /* A buffer is not allocated to the Tx descriptor until a send is\r
340                 actually required. */\r
341                 pxDescriptor->buf_p = NULL;\r
342 \r
343                 pxDescriptor->bufsize = UIP_BUFSIZE;\r
344                 pxDescriptor->size = 0;\r
345                 pxDescriptor->status = 0;\r
346                 pxDescriptor->next = &xTxDescriptors[ x + 1 ];  \r
347         }\r
348 \r
349         /* The last descriptor points back to the start. */\r
350         pxDescriptor->status |= DL;\r
351         pxDescriptor->next = &( xTxDescriptors[ 0 ] );\r
352         \r
353         /* Use the first Rx descriptor to start with. */\r
354         pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );\r
355 }\r
356 /*-----------------------------------------------------------*/\r
357 \r
358 static unsigned char *prvGetNextBuffer( void )\r
359 {\r
360 long x;\r
361 unsigned char *pucReturn = NULL;\r
362 unsigned long ulAttempts = 0;\r
363 \r
364         while( pucReturn == NULL )\r
365         {\r
366                 /* Look through the buffers to find one that is not in use by\r
367                 anything else. */\r
368                 for( x = 0; x < emacNUM_BUFFERS; x++ )\r
369                 {\r
370                         if( ucBufferInUse[ x ] == pdFALSE )\r
371                         {\r
372                                 ucBufferInUse[ x ] = pdTRUE;\r
373                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers.cBuffer[ x ][ 0 ] );\r
374                                 break;\r
375                         }\r
376                 }\r
377 \r
378                 /* Was a buffer found? */\r
379                 if( pucReturn == NULL )\r
380                 {\r
381                         ulAttempts++;\r
382 \r
383                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
384                         {\r
385                                 break;\r
386                         }\r
387 \r
388                         /* Wait then look again. */\r
389                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );\r
390                 }\r
391         }\r
392 \r
393         return pucReturn;\r
394 }\r
395 /*-----------------------------------------------------------*/\r
396 \r
397 static void prvReturnBuffer( unsigned char *pucBuffer )\r
398 {\r
399 unsigned long ul;\r
400 \r
401         /* Return a buffer to the pool of free buffers. */\r
402         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )\r
403         {\r
404                 if( &( xEthernetBuffers.cBuffer[ ul ][ 0 ] ) == ( void * ) pucBuffer )\r
405                 {\r
406                         ucBufferInUse[ ul ] = pdFALSE;\r
407                         break;\r
408                 }\r
409         }\r
410 }\r
411 /*-----------------------------------------------------------*/\r
412 \r
413 static void prvResetEverything( void )\r
414 {\r
415         /* Temporary code just to see if this gets called.  This function has not\r
416         been implemented. */\r
417         portDISABLE_INTERRUPTS();\r
418         for( ;; );\r
419 }\r
420 /*-----------------------------------------------------------*/\r
421 \r
422 static unsigned long prvCheckRxFifoStatus( void )\r
423 {\r
424 unsigned long ulReturn = 0;\r
425 \r
426         if( ( pxCurrentRxDesc->status & ACT ) != 0 )\r
427         {\r
428                 /* Current descriptor is still active. */\r
429         }\r
430         else if( ( pxCurrentRxDesc->status & FE ) != 0 )\r
431         {\r
432                 /* Frame error.  Clear the error. */\r
433                 pxCurrentRxDesc->status &= ~( FP1 | FP0 | FE );\r
434                 pxCurrentRxDesc->status &= ~( RMAF | RRF | RTLF | RTSF | PRE | CERF );\r
435                 pxCurrentRxDesc->status |= ACT;\r
436                 pxCurrentRxDesc = pxCurrentRxDesc->next;\r
437 \r
438                 if( EDMAC.EDRRR.LONG == 0x00000000UL )\r
439                 {\r
440                         /* Restart Ethernet if it has stopped. */\r
441                         EDMAC.EDRRR.LONG = 0x00000001UL;\r
442                 }       \r
443         }\r
444         else\r
445         {\r
446                 /* The descriptor contains a frame.  Because of the size of the buffers\r
447                 the frame should always be complete. */\r
448                 if( ( pxCurrentRxDesc->status & FP0 ) == FP0 )\r
449                 {\r
450                         ulReturn = pxCurrentRxDesc->size;\r
451                 }\r
452                 else\r
453                 {\r
454                         /* Do not expect to get here. */\r
455                         prvResetEverything();\r
456                 }\r
457         }\r
458         \r
459         return ulReturn;\r
460 }\r
461 /*-----------------------------------------------------------*/\r
462 \r
463 static void prvResetMAC( void )\r
464 {\r
465         /* Ensure the EtherC and EDMAC are enabled. */\r
466         SYSTEM.MSTPCRB.BIT.MSTPB15 = 0;\r
467         vTaskDelay( 100 / portTICK_PERIOD_MS );\r
468         \r
469         EDMAC.EDMR.BIT.SWR = 1; \r
470         \r
471         /* Crude wait for reset to complete. */\r
472         vTaskDelay( 500 / portTICK_PERIOD_MS ); \r
473 }\r
474 /*-----------------------------------------------------------*/\r
475 \r
476 static void prvConfigureEtherCAndEDMAC( void )\r
477 {\r
478         /* Initialisation code taken from Renesas example project. */\r
479         \r
480         /* TODO:    Check   bit 5   */\r
481         ETHERC.ECSR.LONG = 0x00000037;                          /* Clear all ETHERC statuS BFR, PSRTO, LCHNG, MPD, ICD */\r
482 \r
483         /* Set the EDMAC interrupt priority. */\r
484         _IPR( _ETHER_EINT ) = configKERNEL_INTERRUPT_PRIORITY;\r
485 \r
486         /* TODO:    Check   bit 5   */\r
487         /* Enable interrupts of interest only. */\r
488         EDMAC.EESIPR.LONG = emacTX_END_INTERRUPT | emacRX_END_INTERRUPT;\r
489         ETHERC.RFLR.LONG = 1518;                                        /* Ether payload is 1500+ CRC */\r
490         ETHERC.IPGR.LONG = 0x00000014;                          /* Intergap is 96-bit time */\r
491 \r
492         /* EDMAC */\r
493         EDMAC.EESR.LONG = 0x47FF0F9F;                           /* Clear all ETHERC and EDMAC status bits */\r
494         #ifdef __LIT\r
495                 EDMAC.EDMR.BIT.DE = 1;\r
496         #endif\r
497         EDMAC.RDLAR = ( void * ) pxCurrentRxDesc;       /* Initialaize Rx Descriptor List Address */\r
498         EDMAC.TDLAR = &( xTxDescriptors[ 0 ] );         /* Initialaize Tx Descriptor List Address */\r
499         EDMAC.TRSCER.LONG = 0x00000000;                         /* Copy-back status is RFE & TFE only   */\r
500         EDMAC.TFTR.LONG = 0x00000000;                           /* Threshold of Tx_FIFO */\r
501         EDMAC.FDR.LONG = 0x00000000;                            /* Transmit fifo & receive fifo is 256 bytes */\r
502         EDMAC.RMCR.LONG = 0x00000003;                           /* Receive function is normal mode(continued) */\r
503         ETHERC.ECMR.BIT.PRM = 0;                                        /* Ensure promiscuous mode is off. */\r
504                 \r
505         /* Enable the interrupt... */\r
506         _IEN( _ETHER_EINT ) = 1;        \r
507 }\r
508 /*-----------------------------------------------------------*/\r
509 \r
510 #pragma interrupt ( vEMAC_ISR_Handler( vect = VECT_ETHER_EINT, enable ) )\r
511 void vEMAC_ISR_Handler( void )\r
512 {\r
513 unsigned long ul = EDMAC.EESR.LONG;\r
514 long lHigherPriorityTaskWoken = pdFALSE;\r
515 extern QueueHandle_t xEMACEventQueue;\r
516 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
517 \r
518         /* Has a Tx end occurred? */\r
519         if( ul & emacTX_END_INTERRUPT )\r
520         {\r
521                 /* Only return the buffer to the pool once both Txes have completed. */\r
522                 prvReturnBuffer( ( void * ) xTxDescriptors[ 0 ].buf_p );\r
523                 EDMAC.EESR.LONG = emacTX_END_INTERRUPT;\r
524         }\r
525 \r
526         /* Has an Rx end occurred? */\r
527         if( ul & emacRX_END_INTERRUPT )\r
528         {\r
529                 /* Make sure the Ethernet task is not blocked waiting for a packet. */\r
530                 xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );\r
531                 portYIELD_FROM_ISR( lHigherPriorityTaskWoken );\r
532                 EDMAC.EESR.LONG = emacRX_END_INTERRUPT;\r
533         }\r
534 }\r
535 \r