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