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