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