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