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