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