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