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