]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/ColdFire_MCF52233_Eclipse/RTOSDemo/webserver/FEC.c
8aa3414754feff7dd6ff2bce6c953e6f938c984f
[freertos] / FreeRTOS / Demo / ColdFire_MCF52233_Eclipse / RTOSDemo / webserver / FEC.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 /* Kernel includes. */\r
30 #include "FreeRTOS.h"\r
31 #include "semphr.h"\r
32 #include "task.h"\r
33 \r
34 /* Hardware includes. */\r
35 #include "fecbd.h"\r
36 #include "mii.h"\r
37 #include "eth_phy.h"\r
38 #include "eth.h"\r
39 \r
40 /* uIP includes. */\r
41 #include "uip.h"\r
42 #include "uip_arp.h"\r
43 \r
44 /* Delay between polling the PHY to see if a link has been established. */\r
45 #define fecLINK_DELAY                                                   ( 500 / portTICK_RATE_MS )\r
46 \r
47 /* Delay to wait for an MII access. */\r
48 #define fecMII_DELAY                                                    ( 10 / portTICK_RATE_MS )\r
49 #define fecMAX_POLLS                                                    ( 20 )\r
50 \r
51 /* Constants used to delay while waiting for a tx descriptor to be free. */\r
52 #define fecMAX_WAIT_FOR_TX_BUFFER                                               ( 200 / portTICK_RATE_MS )\r
53 \r
54 /* We only use a single Tx descriptor which can lead to Txed packets being sent\r
55 twice (due to a bug in the FEC silicon).  However, in this case the bug is used\r
56 to our advantage in that it means the uip-split mechanism is not required. */\r
57 #define fecNUM_FEC_TX_BUFFERS                                   ( 1 )\r
58 #define fecTX_BUFFER_TO_USE                                             ( 0 )\r
59 /*-----------------------------------------------------------*/\r
60 \r
61 /* The semaphore used to wake the uIP task when data arrives. */\r
62 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;\r
63 \r
64 /* The buffer used by the uIP stack.  In this case the pointer is used to\r
65 point to one of the Rx buffers to effect a zero copy policy. */\r
66 unsigned char *uip_buf;\r
67 \r
68 /* The DMA descriptors.  This is a char array to allow us to align it correctly. */\r
69 static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ];\r
70 static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ];\r
71 static FECBD *xFECTxDescriptors;\r
72 static FECBD *xFECRxDescriptors;\r
73 \r
74 /* The DMA buffers.  These are char arrays to allow them to be aligned correctly. */\r
75 static unsigned char ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];\r
76 static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0;\r
77 \r
78 /*-----------------------------------------------------------*/\r
79 \r
80 /*\r
81  * Enable all the required interrupts in the FEC and in the interrupt controller.\r
82  */\r
83 static void prvEnableFECInterrupts( void );\r
84 \r
85 /*\r
86  * Reset the FEC if we get into an unrecoverable state.\r
87  */\r
88 static void prvResetFEC( portBASE_TYPE xCalledFromISR );\r
89 \r
90 /********************************************************************/\r
91 \r
92 /*\r
93  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
94  *\r
95  * Write a value to a PHY's MII register.\r
96  *\r
97  * Parameters:\r
98  *  ch          FEC channel\r
99  *  phy_addr    Address of the PHY.\r
100  *  reg_addr    Address of the register in the PHY.\r
101  *  data        Data to be written to the PHY register.\r
102  *\r
103  * Return Values:\r
104  *  0 on failure\r
105  *  1 on success.\r
106  *\r
107  * Please refer to your PHY manual for registers and their meanings.\r
108  * mii_write() polls for the FEC's MII interrupt event and clears it.\r
109  * If after a suitable amount of time the event isn't triggered, a\r
110  * value of 0 is returned.\r
111  */\r
112 static int fec_mii_write( int phy_addr, int reg_addr, int data )\r
113 {\r
114 int timeout, iReturn;\r
115 uint32 eimr;\r
116 \r
117     /* Clear the MII interrupt bit */\r
118     MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
119 \r
120     /* Mask the MII interrupt */\r
121     eimr = MCF_FEC_EIMR;\r
122     MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;\r
123 \r
124     /* Write to the MII Management Frame Register to kick-off the MII write */\r
125     MCF_FEC_MMFR = MCF_FEC_MMFR_ST_01 | MCF_FEC_MMFR_OP_WRITE | MCF_FEC_MMFR_PA(phy_addr) | MCF_FEC_MMFR_RA(reg_addr) | MCF_FEC_MMFR_TA_10 | MCF_FEC_MMFR_DATA( data );\r
126 \r
127     /* Poll for the MII interrupt (interrupt should be masked) */\r
128     for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )\r
129     {\r
130         if( MCF_FEC_EIR & MCF_FEC_EIR_MII )\r
131         {\r
132                         break;\r
133         }\r
134         else\r
135         {\r
136                 vTaskDelay( fecMII_DELAY );\r
137         }\r
138     }\r
139 \r
140     if( timeout == fecMAX_POLLS )\r
141     {\r
142         iReturn = 0;\r
143     }\r
144     else\r
145     {\r
146                 iReturn = 1;\r
147     }\r
148 \r
149         /* Clear the MII interrupt bit */\r
150         MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
151 \r
152         /* Restore the EIMR */\r
153         MCF_FEC_EIMR = eimr;\r
154 \r
155     return iReturn;\r
156 }\r
157 \r
158 /********************************************************************/\r
159 /*\r
160  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
161  *\r
162  * Read a value from a PHY's MII register.\r
163  *\r
164  * Parameters:\r
165  *  ch          FEC channel\r
166  *  phy_addr    Address of the PHY.\r
167  *  reg_addr    Address of the register in the PHY.\r
168  *  data        Pointer to storage for the Data to be read\r
169  *              from the PHY register (passed by reference)\r
170  *\r
171  * Return Values:\r
172  *  0 on failure\r
173  *  1 on success.\r
174  *\r
175  * Please refer to your PHY manual for registers and their meanings.\r
176  * mii_read() polls for the FEC's MII interrupt event and clears it.\r
177  * If after a suitable amount of time the event isn't triggered, a\r
178  * value of 0 is returned.\r
179  */\r
180 static int fec_mii_read( int phy_addr, int reg_addr, unsigned short* data )\r
181 {\r
182 int timeout, iReturn;\r
183 uint32 eimr;\r
184 \r
185     /* Clear the MII interrupt bit */\r
186     MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
187 \r
188     /* Mask the MII interrupt */\r
189     eimr = MCF_FEC_EIMR;\r
190     MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;\r
191 \r
192     /* Write to the MII Management Frame Register to kick-off the MII read */\r
193     MCF_FEC_MMFR = MCF_FEC_MMFR_ST_01 | MCF_FEC_MMFR_OP_READ | MCF_FEC_MMFR_PA(phy_addr) | MCF_FEC_MMFR_RA(reg_addr) | MCF_FEC_MMFR_TA_10;\r
194 \r
195     /* Poll for the MII interrupt (interrupt should be masked) */\r
196     for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )\r
197     {\r
198         if (MCF_FEC_EIR & MCF_FEC_EIR_MII)\r
199         {\r
200             break;\r
201         }\r
202         else\r
203         {\r
204                 vTaskDelay( fecMII_DELAY );\r
205         }\r
206     }\r
207 \r
208     if( timeout == fecMAX_POLLS )\r
209     {\r
210         iReturn = 0;\r
211     }\r
212     else\r
213     {\r
214                 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);\r
215                 iReturn = 1;\r
216     }\r
217 \r
218         /* Clear the MII interrupt bit */\r
219         MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
220 \r
221         /* Restore the EIMR */\r
222         MCF_FEC_EIMR = eimr;\r
223 \r
224     return iReturn;\r
225 }\r
226 \r
227 \r
228 /********************************************************************/\r
229 /*\r
230  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
231  *\r
232  * Generate the hash table settings for the given address\r
233  *\r
234  * Parameters:\r
235  *  addr    48-bit (6 byte) Address to generate the hash for\r
236  *\r
237  * Return Value:\r
238  *  The 6 most significant bits of the 32-bit CRC result\r
239  */\r
240 static unsigned char fec_hash_address( const unsigned char* addr )\r
241 {\r
242 unsigned long crc;\r
243 unsigned char byte;\r
244 int i, j;\r
245 \r
246         crc = 0xFFFFFFFF;\r
247         for(i=0; i<6; ++i)\r
248         {\r
249                 byte = addr[i];\r
250                 for(j=0; j<8; ++j)\r
251                 {\r
252                         if((byte & 0x01)^(crc & 0x01))\r
253                         {\r
254                                 crc >>= 1;\r
255                                 crc = crc ^ 0xEDB88320;\r
256                         }\r
257                         else\r
258                         {\r
259                                 crc >>= 1;\r
260                         }\r
261 \r
262                         byte >>= 1;\r
263                 }\r
264         }\r
265 \r
266         return (unsigned char)(crc >> 26);\r
267 }\r
268 \r
269 /********************************************************************/\r
270 /*\r
271  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
272  *\r
273  * Set the Physical (Hardware) Address and the Individual Address\r
274  * Hash in the selected FEC\r
275  *\r
276  * Parameters:\r
277  *  ch  FEC channel\r
278  *  pa  Physical (Hardware) Address for the selected FEC\r
279  */\r
280 static void fec_set_address( const unsigned char *pa )\r
281 {\r
282         unsigned char crc;\r
283 \r
284         /*\r
285         * Set the Physical Address\r
286         */\r
287         /* Set the source address for the controller */\r
288         MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 );\r
289         MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 );\r
290 \r
291         /*\r
292         * Calculate and set the hash for given Physical Address\r
293         * in the  Individual Address Hash registers\r
294         */\r
295         crc = fec_hash_address( pa );\r
296         if( crc >= 32 )\r
297         {\r
298                 MCF_FEC_IAUR |= (unsigned long)(1 << (crc - 32));\r
299         }\r
300         else\r
301         {\r
302                 MCF_FEC_IALR |= (unsigned long)(1 << crc);\r
303         }\r
304 }\r
305 /*-----------------------------------------------------------*/\r
306 \r
307 static void prvInitialiseFECBuffers( void )\r
308 {\r
309 unsigned portBASE_TYPE ux;\r
310 unsigned char *pcBufPointer;\r
311 \r
312         /* Correctly align the Tx descriptor pointer. */\r
313         pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );\r
314         while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )\r
315         {\r
316                 pcBufPointer++;\r
317         }\r
318 \r
319         xFECTxDescriptors = ( FECBD * ) pcBufPointer;\r
320 \r
321         /* Likewise the Rx descriptor pointer. */\r
322         pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );\r
323         while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )\r
324         {\r
325                 pcBufPointer++;\r
326         }\r
327 \r
328         xFECRxDescriptors = ( FECBD * ) pcBufPointer;\r
329 \r
330 \r
331         /* Setup the Tx buffers and descriptors.  There is no separate Tx buffer\r
332         to point to (the Rx buffers are actually used) so the data member is\r
333         set to NULL for now. */\r
334         for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ )\r
335         {\r
336                 xFECTxDescriptors[ ux ].status = TX_BD_TC;\r
337                 xFECTxDescriptors[ ux ].data = NULL;\r
338                 xFECTxDescriptors[ ux ].length = 0;\r
339         }\r
340 \r
341         /* Setup the Rx buffers and descriptors, having first ensured correct\r
342         alignment. */\r
343         pcBufPointer = &( ucFECRxBuffers[ 0 ] );\r
344         while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )\r
345         {\r
346                 pcBufPointer++;\r
347         }\r
348 \r
349         for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )\r
350         {\r
351             xFECRxDescriptors[ ux ].status = RX_BD_E;\r
352             xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;\r
353             xFECRxDescriptors[ ux ].data = pcBufPointer;\r
354             pcBufPointer += configFEC_BUFFER_SIZE;\r
355         }\r
356 \r
357         /* Set the wrap bit in the last descriptors to form a ring. */\r
358         xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;\r
359         xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;\r
360 \r
361         uxNextRxBuffer = 0;\r
362 }\r
363 /*-----------------------------------------------------------*/\r
364 \r
365 void vFECInit( void )\r
366 {\r
367 unsigned short usData;\r
368 struct uip_eth_addr xAddr;\r
369 unsigned portBASE_TYPE ux;\r
370 \r
371 /* The MAC address is set at the foot of FreeRTOSConfig.h. */\r
372 const unsigned char ucMACAddress[6] =\r
373 {\r
374         configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5\r
375 };\r
376 \r
377         /* Create the semaphore used by the ISR to wake the uIP task. */\r
378         vSemaphoreCreateBinary( xFECSemaphore );\r
379 \r
380         /* Create the semaphore used to unblock any tasks that might be waiting\r
381         for a Tx descriptor. */\r
382         vSemaphoreCreateBinary( xTxSemaphore );\r
383 \r
384         /* Initialise all the buffers and descriptors used by the DMA. */\r
385         prvInitialiseFECBuffers();\r
386 \r
387         for( usData = 0; usData < 6; usData++ )\r
388         {\r
389                 xAddr.addr[ usData ] = ucMACAddress[ usData ];\r
390         }\r
391         uip_setethaddr( xAddr );\r
392 \r
393         /* Set the Reset bit and clear the Enable bit */\r
394         MCF_FEC_ECR = MCF_FEC_ECR_RESET;\r
395 \r
396         /* Wait at least 8 clock cycles */\r
397         for( usData = 0; usData < 10; usData++ )\r
398         {\r
399                 asm( "NOP" );\r
400         }\r
401 \r
402         /* Set MII speed to 2.5MHz. */\r
403         MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );\r
404 \r
405         /* Initialize PLDPAR to enable Ethernet LEDs. */\r
406         MCF_GPIO_PLDPAR =  MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED\r
407                                          | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED\r
408                                          | MCF_GPIO_PLDPAR_TXLED_TXLED;\r
409 \r
410         /* Initialize Port TA to enable Axcel control. */\r
411         MCF_GPIO_PTAPAR = 0x00;\r
412         MCF_GPIO_DDRTA  = 0x0F;\r
413         MCF_GPIO_PORTTA = 0x04;\r
414 \r
415         /* Set phy address to zero. */\r
416         MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );\r
417 \r
418         /* Enable EPHY module with PHY clocks disabled.  Do not turn on PHY clocks\r
419         until both FEC and EPHY are completely setup (see Below). */\r
420         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);\r
421 \r
422         /* Enable auto_neg at start-up */\r
423         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));\r
424 \r
425         /* Enable EPHY module. */\r
426         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);\r
427 \r
428         /* Let PHY PLLs be determined by PHY. */\r
429         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0  & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));\r
430 \r
431         /* Settle. */\r
432         vTaskDelay( fecLINK_DELAY );\r
433 \r
434         /* Can we talk to the PHY? */\r
435         do\r
436         {\r
437                 vTaskDelay( fecLINK_DELAY );\r
438                 usData = 0;\r
439                 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );\r
440 \r
441         } while( usData == 0xffff );\r
442 \r
443         do\r
444         {\r
445                 /* Start auto negotiate. */\r
446                 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );\r
447 \r
448                 /* Wait for auto negotiate to complete. */\r
449                 do\r
450                 {\r
451                         ux++;\r
452                         if( ux > 10 )\r
453                         {\r
454                                 /* Hardware bug workaround!  Force 100Mbps half duplex. */\r
455                                 while( !fec_mii_read( configPHY_ADDRESS, 0, &usData ) ){};\r
456                                 usData &= ~0x2000;                                                      /* 10Mbps */\r
457                                 usData &= ~0x0100;                                                      /* Half Duplex */\r
458                                 usData &= ~0x1000;                                                      /* Manual Mode */\r
459                                 while( !fec_mii_write( configPHY_ADDRESS, 0, usData ) ){};\r
460                                 while( !fec_mii_write( configPHY_ADDRESS, 0, (usData|0x0200) )){}; /* Force re-negotiate */\r
461                                 break;\r
462                         }\r
463                         vTaskDelay( fecLINK_DELAY );\r
464                         fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );\r
465 \r
466                 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );\r
467 \r
468         } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );\r
469 \r
470         /* When we get here we have a link - find out what has been negotiated. */\r
471         fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );\r
472 \r
473         if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )\r
474         {\r
475                 /* Speed is 100. */\r
476         }\r
477         else\r
478         {\r
479                 /* Speed is 10. */\r
480         }\r
481 \r
482         if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )\r
483         {\r
484                 MCF_FEC_RCR &= (unsigned long)~MCF_FEC_RCR_DRT;\r
485                 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;\r
486         }\r
487         else\r
488         {\r
489                 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;\r
490                 MCF_FEC_TCR &= (unsigned long)~MCF_FEC_TCR_FDEN;\r
491         }\r
492 \r
493         /* Clear the Individual and Group Address Hash registers */\r
494         MCF_FEC_IALR = 0;\r
495         MCF_FEC_IAUR = 0;\r
496         MCF_FEC_GALR = 0;\r
497         MCF_FEC_GAUR = 0;\r
498 \r
499         /* Set the Physical Address for the selected FEC */\r
500         fec_set_address( ucMACAddress );\r
501 \r
502         /* Set Rx Buffer Size */\r
503         MCF_FEC_EMRBR = (unsigned short)configFEC_BUFFER_SIZE;\r
504 \r
505         /* Point to the start of the circular Rx buffer descriptor queue */\r
506         MCF_FEC_ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] );\r
507 \r
508         /* Point to the start of the circular Tx buffer descriptor queue */\r
509         MCF_FEC_ETSDR = ( volatile unsigned long ) &( xFECTxDescriptors[ 0 ] );\r
510 \r
511         /* Mask all FEC interrupts */\r
512         MCF_FEC_EIMR = ( unsigned long ) -1;\r
513 \r
514         /* Clear all FEC interrupt events */\r
515         MCF_FEC_EIR = ( unsigned long ) -1;\r
516 \r
517         /* Initialize the Receive Control Register */\r
518         MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;\r
519 \r
520         MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;\r
521 \r
522         #if( configUSE_PROMISCUOUS_MODE == 1 )\r
523         {\r
524                 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;\r
525         }\r
526         #endif\r
527 \r
528         prvEnableFECInterrupts();\r
529 \r
530         /* Finally... enable. */\r
531         MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;\r
532         MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
533 }\r
534 /*-----------------------------------------------------------*/\r
535 \r
536 static void prvEnableFECInterrupts( void )\r
537 {\r
538 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;\r
539 unsigned portBASE_TYPE ux;\r
540 \r
541 #if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY\r
542         #error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY\r
543 #endif\r
544 \r
545         /* Set the priority of each of the FEC interrupts. */\r
546         for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )\r
547         {\r
548                 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );\r
549         }\r
550 \r
551         /* Enable the FEC interrupts in the mask register */\r
552         MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );\r
553         MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27\r
554                                                 | MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30\r
555                                                 | MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24\r
556                                                 | MCF_INTC_IMRL_MASKALL );\r
557 \r
558         /* Clear any pending FEC interrupt events */\r
559         MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;\r
560 \r
561         /* Unmask all FEC interrupts */\r
562         MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;\r
563 }\r
564 /*-----------------------------------------------------------*/\r
565 \r
566 static void prvResetFEC( portBASE_TYPE xCalledFromISR )\r
567 {\r
568 portBASE_TYPE x;\r
569 \r
570         /* A critical section is used unless this function is being called from\r
571         an ISR. */\r
572         if( xCalledFromISR == pdFALSE )\r
573         {\r
574                 taskENTER_CRITICAL();\r
575         }\r
576 \r
577         {\r
578                 /* Reset all buffers and descriptors. */\r
579                 prvInitialiseFECBuffers();\r
580 \r
581                 /* Set the Reset bit and clear the Enable bit */\r
582                 MCF_FEC_ECR = MCF_FEC_ECR_RESET;\r
583 \r
584                 /* Wait at least 8 clock cycles */\r
585                 for( x = 0; x < 10; x++ )\r
586                 {\r
587                         asm( "NOP" );\r
588                 }\r
589 \r
590                 /* Re-enable. */\r
591                 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;\r
592                 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
593         }\r
594 \r
595         if( xCalledFromISR == pdFALSE )\r
596         {\r
597                 taskEXIT_CRITICAL();\r
598         }\r
599 }\r
600 /*-----------------------------------------------------------*/\r
601 \r
602 unsigned short usFECGetRxedData( void )\r
603 {\r
604 unsigned short usLen;\r
605 \r
606         /* Obtain the size of the packet and put it into the "len" variable. */\r
607         usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;\r
608 \r
609         if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )\r
610         {\r
611                 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;\r
612         }\r
613         else\r
614         {\r
615                 usLen = 0;\r
616         }\r
617 \r
618         return usLen;\r
619 }\r
620 /*-----------------------------------------------------------*/\r
621 \r
622 void vFECRxProcessingCompleted( void )\r
623 {\r
624         /* Free the descriptor as the buffer it points to is no longer in use. */\r
625         xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;\r
626         MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
627         uxNextRxBuffer++;\r
628         if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )\r
629         {\r
630                 uxNextRxBuffer = 0;\r
631         }\r
632 }\r
633 /*-----------------------------------------------------------*/\r
634 \r
635 void vFECSendData( void )\r
636 {\r
637         /* Ensure no Tx frames are outstanding. */\r
638         if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )\r
639         {\r
640                 /* Get a DMA buffer into which we can write the data to send. */\r
641                 if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )\r
642                 {\r
643                         /*** ERROR didn't expect this.  Sledge hammer error handling. ***/\r
644                         prvResetFEC( pdFALSE );\r
645 \r
646                         /* Make sure we leave the semaphore in the expected state as nothing\r
647                         is being transmitted this will not happen in the Tx ISR. */\r
648                         xSemaphoreGive( xTxSemaphore );\r
649                 }\r
650                 else\r
651                 {\r
652                         /* Setup the buffer descriptor for transmission.  The data being\r
653                         sent is actually stored in one of the Rx descriptor buffers,\r
654                         pointed to by uip_buf. */\r
655                         xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;\r
656                         xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );\r
657                         xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;\r
658 \r
659                         /* Remember which Rx descriptor owns the buffer we are sending. */\r
660                         uxIndexToBufferOwner = uxNextRxBuffer;\r
661 \r
662                         /* We have finished with this Rx descriptor now. */\r
663                         uxNextRxBuffer++;\r
664                         if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )\r
665                         {\r
666                                 uxNextRxBuffer = 0;\r
667                         }\r
668 \r
669                         /* Continue the Tx DMA (in case it was waiting for a new TxBD) */\r
670                         MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;\r
671                 }\r
672         }\r
673         else\r
674         {\r
675                 /* Gave up waiting.  Free the buffer back to the DMA. */\r
676                 vFECRxProcessingCompleted();\r
677         }\r
678 }\r
679 /*-----------------------------------------------------------*/\r
680 \r
681 void vFEC_ISR( void )\r
682 {\r
683 unsigned long ulEvent;\r
684 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;\r
685 \r
686         /* This handler is called in response to any of the many separate FEC\r
687         interrupt. */\r
688 \r
689         /* Find the cause of the interrupt, then clear the interrupt. */\r
690         ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;\r
691         MCF_FEC_EIR = ulEvent;\r
692 \r
693         if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )\r
694         {\r
695                 /* A packet has been received.  Wake the handler task. */\r
696                 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );\r
697         }\r
698 \r
699         if( ulEvent & ( MCF_FEC_EIR_UN | MCF_FEC_EIR_RL | MCF_FEC_EIR_LC | MCF_FEC_EIR_EBERR | MCF_FEC_EIR_BABT | MCF_FEC_EIR_BABR | MCF_FEC_EIR_HBERR ) )\r
700         {\r
701                 /* Sledge hammer error handling. */\r
702                 prvResetFEC( pdTRUE );\r
703         }\r
704 \r
705         if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )\r
706         {\r
707                 /* The buffer being sent is pointed to by an Rx descriptor, now the\r
708                 buffer has been sent we can mark the Rx descriptor as free again. */\r
709                 xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;\r
710                 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
711                 xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );\r
712         }\r
713 \r
714         portEND_SWITCHING_ISR( xHighPriorityTaskWoken );\r
715 }\r
716 /*-----------------------------------------------------------*/\r
717 \r
718 /* Install the many different interrupt vectors, all of which call the same\r
719 handler function. */\r
720 void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }\r
721 void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }\r
722 void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }\r
723 void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }\r
724 void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }\r
725 void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }\r
726 void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }\r
727 void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }\r
728 void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }\r
729 void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }\r
730 void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }\r
731 void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }\r
732 void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }\r
733 \r
734 \r