]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/uIP_Demo_IAR_ARM7/EMAC/SAM7_EMAC.c
c1bfde97e23c8f24e7b33521e757285196e5612e
[freertos] / FreeRTOS / Demo / uIP_Demo_IAR_ARM7 / EMAC / SAM7_EMAC.c
1 /*\r
2     FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
12 \r
13         ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18         ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40         the FAQ page "My application does not run, what could be wrong?".  Have you\r
41         defined configASSERT()?\r
42 \r
43         http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44         embedded software for free we request you assist our global community by\r
45         participating in the support forum.\r
46 \r
47         http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48         be as productive as possible as early as possible.  Now you can receive\r
49         FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50         Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /*\r
71  * Basic interrupt driven driver for the EMAC peripheral.  This driver is not\r
72  * reentrant as with uIP the buffers are only ever accessed from a single task.\r
73  *\r
74  * The simple buffer management used within uIP allows the EMAC driver to also\r
75  * be simplistic.  The driver contained within the lwIP demo is more\r
76  * comprehensive.\r
77  */\r
78 \r
79 \r
80 /*\r
81 Changes from V3.2.2\r
82 \r
83         + Corrected the byte order when writing the MAC address to the MAC.\r
84         + Support added for MII interfaces.  Previously only RMII was supported.\r
85 \r
86 Changes from V3.2.3\r
87 \r
88         + The MII interface is now the default.\r
89         + Modified the initialisation sequence slightly to allow auto init more\r
90           time to complete.\r
91 \r
92 Changes from V3.2.4\r
93 \r
94         + Also read the EMAC_RSR register in the EMAC ISR as a work around the \r
95           the EMAC bug that can reset the RX bit in EMAC_ISR register before the\r
96           bit has been read.\r
97 \r
98 Changes from V4.0.4\r
99 \r
100         + Corrected the Rx frame length mask when obtaining the length from the\r
101           rx descriptor.\r
102 \r
103 */\r
104 \r
105 /* Standard includes. */\r
106 #include <string.h>\r
107 \r
108 /* Scheduler includes. */\r
109 #include "FreeRTOS.h"\r
110 #include "semphr.h"\r
111 #include "task.h"\r
112 \r
113 /* uIP includes. */\r
114 #include "uip.h"\r
115 \r
116 /* Hardware specific includes. */\r
117 #include "Emac.h"\r
118 #include "mii.h"\r
119 \r
120 \r
121 /* USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0\r
122 to use an MII interface. */\r
123 #define USE_RMII_INTERFACE 0\r
124 \r
125 /* The buffer addresses written into the descriptors must be aligned so the\r
126 last few bits are zero.  These bits have special meaning for the EMAC\r
127 peripheral and cannot be used as part of the address. */\r
128 #define emacADDRESS_MASK                        ( ( unsigned long ) 0xFFFFFFFC )\r
129 \r
130 /* Bit used within the address stored in the descriptor to mark the last\r
131 descriptor in the array. */\r
132 #define emacRX_WRAP_BIT                         ( ( unsigned long ) 0x02 )\r
133 \r
134 /* Bit used within the Tx descriptor status to indicate whether the\r
135 descriptor is under the control of the EMAC or the software. */\r
136 #define emacTX_BUF_USED                         ( ( unsigned long ) 0x80000000 )\r
137 \r
138 /* A short delay is used to wait for a buffer to become available, should\r
139 one not be immediately available when trying to transmit a frame. */\r
140 #define emacBUFFER_WAIT_DELAY           ( 2 )\r
141 #define emacMAX_WAIT_CYCLES                     ( configTICK_RATE_HZ / 40 )\r
142 \r
143 /* Misc defines. */\r
144 #define emacINTERRUPT_LEVEL                     ( 5 )\r
145 #define emacNO_DELAY                            ( 0 )\r
146 #define emacTOTAL_FRAME_HEADER_SIZE     ( 54 )\r
147 #define emacPHY_INIT_DELAY                      ( 5000 / portTICK_PERIOD_MS )\r
148 #define emacRESET_KEY                           ( ( unsigned long ) 0xA5000000 )\r
149 #define emacRESET_LENGTH                        ( ( unsigned long ) ( 0x01 << 8 ) )\r
150 \r
151 /* The Atmel header file only defines the TX frame length mask. */\r
152 #define emacRX_LENGTH_FRAME                     ( 0xfff )\r
153 \r
154 /*-----------------------------------------------------------*/\r
155 \r
156 /*\r
157  * Prototype for the EMAC interrupt asm wrapper.\r
158  */\r
159 extern void vEMACISREntry( void );\r
160 \r
161 /*\r
162  * Prototype for the EMAC interrupt function - called by the asm wrapper.\r
163  */\r
164 __arm void vEMACISR( void );\r
165 \r
166 /*\r
167  * Initialise both the Tx and Rx descriptors used by the EMAC.\r
168  */\r
169 static void prvSetupDescriptors(void);\r
170 \r
171 /*\r
172  * Write our MAC address into the EMAC.  The MAC address is set as one of the\r
173  * uip options.\r
174  */\r
175 static void prvSetupMACAddress( void );\r
176 \r
177 /*\r
178  * Configure the EMAC and AIC for EMAC interrupts.\r
179  */\r
180 static void prvSetupEMACInterrupt( void );\r
181 \r
182 /*\r
183  * Some initialisation functions taken from the Atmel EMAC sample code.\r
184  */\r
185 static void vReadPHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long *pulValue );\r
186 #if USE_RMII_INTERFACE != 1\r
187         static void vWritePHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long ulValue);\r
188 #endif\r
189 static portBASE_TYPE xGetLinkSpeed( void );\r
190 static portBASE_TYPE prvProbePHY( void );\r
191 \r
192 /*-----------------------------------------------------------*/\r
193 \r
194 /* Buffer written to by the EMAC DMA.  Must be aligned as described by the\r
195 comment above the emacADDRESS_MASK definition. */\r
196 #pragma data_alignment=8\r
197 static volatile char pcRxBuffer[ NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE ];\r
198 \r
199 /* Buffer read by the EMAC DMA.  Must be aligned as described by he comment\r
200 above the emacADDRESS_MASK definition. */\r
201 #pragma data_alignment=8\r
202 static char pcTxBuffer[ NB_TX_BUFFERS * ETH_TX_BUFFER_SIZE ];\r
203 \r
204 /* Descriptors used to communicate between the program and the EMAC peripheral.\r
205 These descriptors hold the locations and state of the Rx and Tx buffers. */\r
206 static volatile AT91S_TxTdDescriptor xTxDescriptors[ NB_TX_BUFFERS ];\r
207 static volatile AT91S_RxTdDescriptor xRxDescriptors[ NB_RX_BUFFERS ];\r
208 \r
209 /* The IP and Ethernet addresses are read from the uIP setup. */\r
210 const char cMACAddress[ 6 ] = { UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 };\r
211 const unsigned char ucIPAddress[ 4 ]  = { UIP_IPADDR0, UIP_IPADDR1, UIP_IPADDR2, UIP_IPADDR3 };\r
212 \r
213 /* The semaphore used by the EMAC ISR to wake the EMAC task. */\r
214 static SemaphoreHandle_t xSemaphore = NULL;\r
215 \r
216 /*-----------------------------------------------------------*/\r
217 \r
218 SemaphoreHandle_t xEMACInit( void )\r
219 {\r
220         /* Code supplied by Atmel (modified) --------------------*/\r
221 \r
222         /* disable pull up on RXDV => PHY normal mode (not in test mode),\r
223         PHY has internal pull down. */\r
224         AT91C_BASE_PIOB->PIO_PPUDR = 1 << 15;\r
225 \r
226         #if USE_RMII_INTERFACE != 1\r
227                 /* PHY has internal pull down : set MII mode. */\r
228                 AT91C_BASE_PIOB->PIO_PPUDR= 1 << 16;\r
229         #endif\r
230 \r
231         /* clear PB18 <=> PHY powerdown. */\r
232         AT91F_PIO_CfgOutput( AT91C_BASE_PIOB, 1 << 18 ) ;\r
233         AT91F_PIO_ClearOutput( AT91C_BASE_PIOB,  1 << 18) ;\r
234 \r
235         /* After PHY power up, hardware reset. */\r
236         AT91C_BASE_RSTC->RSTC_RMR = emacRESET_KEY | emacRESET_LENGTH;\r
237         AT91C_BASE_RSTC->RSTC_RCR = emacRESET_KEY | AT91C_RSTC_EXTRST;\r
238         \r
239         /* Wait for hardware reset end. */\r
240         while( !( AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL ) )\r
241         {\r
242                 __asm( "NOP" );\r
243         }\r
244         __asm( "NOP" );\r
245         \r
246         /* EMAC IO init for EMAC-PHY com. Remove EF100 config. */\r
247         AT91F_EMAC_CfgPIO();\r
248 \r
249         /* Enable com between EMAC PHY.\r
250 \r
251         Enable management port. */\r
252         AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;    \r
253 \r
254         /* MDC = MCK/32. */\r
255         AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;     \r
256 \r
257         /* Wait for PHY auto init end (rather crude delay!). */\r
258         vTaskDelay( emacPHY_INIT_DELAY );\r
259 \r
260         /* PHY configuration. */\r
261         #if USE_RMII_INTERFACE != 1\r
262         {\r
263                 unsigned long ulControl;\r
264 \r
265                 /* PHY has internal pull down : disable MII isolate. */\r
266                 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );\r
267                 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );\r
268                 ulControl &= ~BMCR_ISOLATE;\r
269                 vWritePHY( AT91C_PHY_ADDR, MII_BMCR, ulControl );\r
270         }\r
271         #endif\r
272 \r
273         /* Disable management port again. */\r
274         AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;\r
275 \r
276         #if USE_RMII_INTERFACE != 1\r
277                 /* Enable EMAC in MII mode, enable clock ERXCK and ETXCK. */\r
278                 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN ;\r
279         #else\r
280                 /* Enable EMAC in RMII mode, enable RMII clock (50MHz from oscillator\r
281                 on ERFCK). */\r
282                 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_RMII | AT91C_EMAC_CLKEN ;\r
283         #endif\r
284 \r
285         /* End of code supplied by Atmel ------------------------*/\r
286 \r
287         /* Setup the buffers and descriptors. */\r
288         prvSetupDescriptors();\r
289         \r
290         /* Load our MAC address into the EMAC. */\r
291         prvSetupMACAddress();\r
292 \r
293         /* Try to connect. */\r
294         if( prvProbePHY() )\r
295         {\r
296                 /* Enable the interrupt! */\r
297                 prvSetupEMACInterrupt();\r
298         }\r
299 \r
300         return xSemaphore;\r
301 }\r
302 /*-----------------------------------------------------------*/\r
303 \r
304 long lEMACSend( void )\r
305 {\r
306 static unsigned portBASE_TYPE uxTxBufferIndex = 0;\r
307 portBASE_TYPE xWaitCycles = 0;\r
308 long lReturn = pdPASS;\r
309 char *pcBuffer;\r
310 \r
311         /* Is a buffer available? */\r
312         while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AT91C_TRANSMIT_OK ) )\r
313         {\r
314                 /* There is no room to write the Tx data to the Tx buffer.  Wait a\r
315                 short while, then try again. */\r
316                 xWaitCycles++;\r
317                 if( xWaitCycles > emacMAX_WAIT_CYCLES )\r
318                 {\r
319                         /* Give up. */\r
320                         lReturn = pdFAIL;\r
321                         break;\r
322                 }\r
323                 else\r
324                 {\r
325                         vTaskDelay( emacBUFFER_WAIT_DELAY );\r
326                 }\r
327         }\r
328 \r
329         /* lReturn will only be pdPASS if a buffer is available. */\r
330         if( lReturn == pdPASS )\r
331         {\r
332                 /* Copy the headers into the Tx buffer.  These will be in the uIP buffer. */\r
333                 pcBuffer = ( char * ) xTxDescriptors[ uxTxBufferIndex ].addr;\r
334                 memcpy( ( void * ) pcBuffer, ( void * ) uip_buf, emacTOTAL_FRAME_HEADER_SIZE );\r
335                 if( uip_len > emacTOTAL_FRAME_HEADER_SIZE )\r
336                 {\r
337                         memcpy( ( void * ) &( pcBuffer[ emacTOTAL_FRAME_HEADER_SIZE ] ), ( void * ) uip_appdata, ( uip_len - emacTOTAL_FRAME_HEADER_SIZE ) );\r
338                 }\r
339 \r
340                 /* Send. */     \r
341                 portENTER_CRITICAL();\r
342                 {\r
343                         if( uxTxBufferIndex >= ( NB_TX_BUFFERS - 1 ) )\r
344                         {\r
345                                 /* Fill out the necessary in the descriptor to get the data sent. */\r
346                                 xTxDescriptors[ uxTxBufferIndex ].U_Status.status =     ( uip_len & ( unsigned long ) AT91C_LENGTH_FRAME )\r
347                                                                                                                                                 | AT91C_LAST_BUFFER\r
348                                                                                                                                                 | AT91C_TRANSMIT_WRAP;\r
349                                 uxTxBufferIndex = 0;\r
350                         }\r
351                         else\r
352                         {\r
353                                 /* Fill out the necessary in the descriptor to get the data sent. */\r
354                                 xTxDescriptors[ uxTxBufferIndex ].U_Status.status =     ( uip_len & ( unsigned long ) AT91C_LENGTH_FRAME )\r
355                                                                                                                                                 | AT91C_LAST_BUFFER;\r
356                                 uxTxBufferIndex++;\r
357                         }\r
358         \r
359                         AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;\r
360                 }\r
361                 portEXIT_CRITICAL();\r
362         }\r
363 \r
364         return lReturn;\r
365 }\r
366 /*-----------------------------------------------------------*/\r
367 \r
368 unsigned long ulEMACPoll( void )\r
369 {\r
370 static unsigned portBASE_TYPE ulNextRxBuffer = 0;\r
371 unsigned long ulSectionLength = 0, ulLengthSoFar = 0, ulEOF = pdFALSE;\r
372 char *pcSource;\r
373 \r
374         /* Skip any fragments. */\r
375         while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_SOF ) )\r
376         {\r
377                 /* Mark the buffer as free again. */\r
378                 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );              \r
379                 ulNextRxBuffer++;\r
380                 if( ulNextRxBuffer >= NB_RX_BUFFERS )\r
381                 {\r
382                         ulNextRxBuffer = 0;\r
383                 }\r
384         }\r
385 \r
386         /* Is there a packet ready? */\r
387 \r
388         while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !ulSectionLength )\r
389         {\r
390                 pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );\r
391                 ulSectionLength = xRxDescriptors[ ulNextRxBuffer ].U_Status.status & emacRX_LENGTH_FRAME;\r
392 \r
393                 if( ulSectionLength == 0 )\r
394                 {\r
395                         /* The frame is longer than the buffer pointed to by this\r
396                         descriptor so copy the entire buffer to uIP - then move onto\r
397                         the next descriptor to get the rest of the frame. */\r
398                         if( ( ulLengthSoFar + ETH_RX_BUFFER_SIZE ) <= UIP_BUFSIZE )\r
399                         {\r
400                                 memcpy( &( uip_buf[ ulLengthSoFar ] ), pcSource, ETH_RX_BUFFER_SIZE );\r
401                                 ulLengthSoFar += ETH_RX_BUFFER_SIZE;\r
402                         }                       \r
403                 }\r
404                 else\r
405                 {\r
406                         /* This is the last section of the frame.  Copy the section to\r
407                         uIP. */\r
408                         if( ulSectionLength < UIP_BUFSIZE )\r
409                         {\r
410                                 /* The section length holds the length of the entire frame.\r
411                                 ulLengthSoFar holds the length of the frame sections already\r
412                                 copied to uIP, so the length of the final section is\r
413                                 ulSectionLength - ulLengthSoFar; */\r
414                                 if( ulSectionLength > ulLengthSoFar )\r
415                                 {\r
416                                         memcpy( &( uip_buf[ ulLengthSoFar ] ), pcSource, ( ulSectionLength - ulLengthSoFar ) );\r
417                                 }\r
418                         }                       \r
419 \r
420                         /* Is this the last buffer for the frame?  If not why? */\r
421                         ulEOF = xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_EOF;\r
422                 }\r
423 \r
424                 /* Mark the buffer as free again. */\r
425                 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );\r
426 \r
427                 /* Increment to the next buffer, wrapping if necessary. */\r
428                 ulNextRxBuffer++;\r
429                 if( ulNextRxBuffer >= NB_RX_BUFFERS )\r
430                 {\r
431                         ulNextRxBuffer = 0;\r
432                 }\r
433         }\r
434 \r
435         /* If we obtained data but for some reason did not find the end of the\r
436         frame then discard the data as it must contain an error. */\r
437         if( !ulEOF )\r
438         {\r
439                 ulSectionLength = 0;\r
440         }\r
441 \r
442         return ulSectionLength;\r
443 }\r
444 /*-----------------------------------------------------------*/\r
445 \r
446 static void prvSetupDescriptors(void)\r
447 {\r
448 unsigned portBASE_TYPE xIndex;\r
449 unsigned long ulAddress;\r
450 \r
451         /* Initialise xRxDescriptors descriptor. */\r
452         for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex )\r
453         {\r
454                 /* Calculate the address of the nth buffer within the array. */\r
455                 ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) );\r
456 \r
457                 /* Write the buffer address into the descriptor.  The DMA will place\r
458                 the data at this address when this descriptor is being used.  Mask off\r
459                 the bottom bits of the address as these have special meaning. */\r
460                 xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;\r
461         }       \r
462 \r
463         /* The last buffer has the wrap bit set so the EMAC knows to wrap back\r
464         to the first buffer. */\r
465         xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT;\r
466 \r
467         /* Initialise xTxDescriptors. */\r
468         for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex )\r
469         {\r
470                 /* Calculate the address of the nth buffer within the array. */\r
471                 ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) );\r
472 \r
473                 /* Write the buffer address into the descriptor.  The DMA will read\r
474                 data from here when the descriptor is being used. */\r
475                 xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;\r
476                 xTxDescriptors[ xIndex ].U_Status.status = AT91C_TRANSMIT_OK;\r
477         }       \r
478 \r
479         /* The last buffer has the wrap bit set so the EMAC knows to wrap back\r
480         to the first buffer. */\r
481         xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AT91C_TRANSMIT_WRAP | AT91C_TRANSMIT_OK;\r
482 \r
483         /* Tell the EMAC where to find the descriptors. */\r
484         AT91C_BASE_EMAC->EMAC_RBQP = ( unsigned long ) xRxDescriptors;\r
485         AT91C_BASE_EMAC->EMAC_TBQP = ( unsigned long ) xTxDescriptors;\r
486         \r
487         /* Clear all the bits in the receive status register. */\r
488         AT91C_BASE_EMAC->EMAC_RSR = ( AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA );\r
489 \r
490         /* Enable the copy of data into the buffers, ignore broadcasts,\r
491         and don't copy FCS. */\r
492         AT91C_BASE_EMAC->EMAC_NCFGR |= ( AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS);\r
493 \r
494         /* Enable Rx and Tx, plus the stats register. */\r
495         AT91C_BASE_EMAC->EMAC_NCR |= ( AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT );\r
496 }       \r
497 /*-----------------------------------------------------------*/\r
498 \r
499 static void prvSetupMACAddress( void )\r
500 {\r
501         /* Must be written SA1L then SA1H. */\r
502         AT91C_BASE_EMAC->EMAC_SA1L =    ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) |\r
503                                                                         ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) |\r
504                                                                         ( ( unsigned long ) cMACAddress[ 1 ] << 8  ) |\r
505                                                                         cMACAddress[ 0 ];\r
506 \r
507         AT91C_BASE_EMAC->EMAC_SA1H =    ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) |\r
508                                                                         cMACAddress[ 4 ];\r
509 }\r
510 /*-----------------------------------------------------------*/\r
511 \r
512 static void prvSetupEMACInterrupt( void )\r
513 {\r
514         /* Create the semaphore used to trigger the EMAC task. */\r
515         vSemaphoreCreateBinary( xSemaphore );\r
516         if( xSemaphore )\r
517         {\r
518                 /* We start by 'taking' the semaphore so the ISR can 'give' it when the\r
519                 first interrupt occurs. */\r
520                 xSemaphoreTake( xSemaphore, emacNO_DELAY );\r
521                 portENTER_CRITICAL();\r
522                 {\r
523                         /* We want to interrupt on Rx events. */\r
524                         AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP;\r
525 \r
526                         /* Enable the interrupts in the AIC. */\r
527                         AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISREntry );\r
528                         AT91F_AIC_EnableIt( AT91C_BASE_AIC, AT91C_ID_EMAC );\r
529                 }\r
530                 portEXIT_CRITICAL();\r
531         }\r
532 }\r
533 /*-----------------------------------------------------------*/\r
534 \r
535 __arm void vEMACISR( void )\r
536 {\r
537 volatile unsigned long ulIntStatus, ulRxStatus;\r
538 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
539 \r
540         ulIntStatus = AT91C_BASE_EMAC->EMAC_ISR;\r
541         ulRxStatus = AT91C_BASE_EMAC->EMAC_RSR;\r
542 \r
543         if( ( ulIntStatus & AT91C_EMAC_RCOMP ) || ( ulRxStatus & AT91C_EMAC_REC ) )\r
544         {\r
545                 /* A frame has been received, signal the uIP task so it can process\r
546                 the Rx descriptors. */\r
547                 xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );\r
548                 AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_REC;\r
549         }\r
550 \r
551         /* If a task was woken by either a character being received or a character\r
552         being transmitted then we may need to switch to another task. */\r
553         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
554 \r
555         /* Clear the interrupt. */\r
556         AT91C_BASE_AIC->AIC_EOICR = 0;\r
557 }\r
558 /*-----------------------------------------------------------*/\r
559 \r
560 \r
561 \r
562 /*\r
563  * The following functions are initialisation functions taken from the Atmel\r
564  * EMAC sample code.\r
565  */\r
566 \r
567 static portBASE_TYPE prvProbePHY( void )\r
568 {\r
569 unsigned long ulPHYId1, ulPHYId2, ulStatus;\r
570 portBASE_TYPE xReturn = pdPASS;\r
571         \r
572         /* Code supplied by Atmel (reformatted) -----------------*/\r
573 \r
574         /* Enable management port */\r
575         AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;    \r
576         AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;\r
577 \r
578         /* Read the PHY ID. */\r
579         vReadPHY( AT91C_PHY_ADDR, MII_PHYSID1, &ulPHYId1 );\r
580         vReadPHY( AT91C_PHY_ADDR, MII_PHYSID2, &ulPHYId2 );\r
581 \r
582         /* AMD AM79C875:\r
583                         PHY_ID1 = 0x0022\r
584                         PHY_ID2 = 0x5541\r
585                         Bits 3:0 Revision Number Four bit manufacturer\92s revision number.\r
586                                 0001 stands for Rev. A, etc.\r
587         */\r
588         if( ( ( ulPHYId1 << 16 ) | ( ulPHYId2 & 0xfff0 ) ) != MII_DM9161_ID )\r
589         {\r
590                 /* Did not expect this ID. */\r
591                 xReturn = pdFAIL;\r
592         }\r
593         else\r
594         {\r
595                 ulStatus = xGetLinkSpeed();\r
596 \r
597                 if( ulStatus != pdPASS )\r
598                 {\r
599                         xReturn = pdFAIL;\r
600                 }\r
601         }\r
602 \r
603         /* Disable management port */\r
604         AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;   \r
605 \r
606         /* End of code supplied by Atmel ------------------------*/\r
607 \r
608         return xReturn;\r
609 }\r
610 /*-----------------------------------------------------------*/\r
611 \r
612 static void vReadPHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long *pulValue )\r
613 {\r
614         /* Code supplied by Atmel (reformatted) ----------------------*/\r
615 \r
616         AT91C_BASE_EMAC->EMAC_MAN =     (AT91C_EMAC_SOF & (0x01<<30))\r
617                                                                         | (2 << 16) | (2 << 28)\r
618                                                                         | ((ucPHYAddress & 0x1f) << 23)\r
619                                                                         | (ucAddress << 18);\r
620 \r
621         /* Wait until IDLE bit in Network Status register is cleared. */\r
622         while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )\r
623         {\r
624                 __asm( "NOP" );\r
625         }\r
626 \r
627         *pulValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff ); \r
628 \r
629         /* End of code supplied by Atmel ------------------------*/\r
630 }\r
631 /*-----------------------------------------------------------*/\r
632 \r
633 #if USE_RMII_INTERFACE != 1\r
634 static void vWritePHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long ulValue )\r
635 {\r
636         /* Code supplied by Atmel (reformatted) ----------------------*/\r
637 \r
638         AT91C_BASE_EMAC->EMAC_MAN = (( AT91C_EMAC_SOF & (0x01<<30))\r
639                                                                 | (2 << 16) | (1 << 28)\r
640                                                                 | ((ucPHYAddress & 0x1f) << 23)\r
641                                                                 | (ucAddress << 18))\r
642                                                                 | (ulValue & 0xffff);\r
643 \r
644         /* Wait until IDLE bit in Network Status register is cleared */\r
645         while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )\r
646         {\r
647                 __asm( "NOP" );\r
648         };\r
649 \r
650         /* End of code supplied by Atmel ------------------------*/\r
651 }\r
652 #endif\r
653 /*-----------------------------------------------------------*/\r
654 \r
655 static portBASE_TYPE xGetLinkSpeed( void )\r
656 {\r
657         unsigned long ulBMSR, ulBMCR, ulLPA, ulMACCfg, ulSpeed, ulDuplex;\r
658 \r
659         /* Code supplied by Atmel (reformatted) -----------------*/\r
660 \r
661         /* Link status is latched, so read twice to get current value */\r
662         vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);\r
663         vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);\r
664 \r
665         if( !( ulBMSR & BMSR_LSTATUS ) )\r
666         {       \r
667                 /* No Link. */\r
668                 return pdFAIL;\r
669         }\r
670 \r
671         vReadPHY(AT91C_PHY_ADDR, MII_BMCR, &ulBMCR);\r
672         if (ulBMCR & BMCR_ANENABLE)\r
673         {                               \r
674                 /* AutoNegotiation is enabled. */\r
675                 if (!(ulBMSR & BMSR_ANEGCOMPLETE))\r
676                 {\r
677                         /* Auto-negotiation in progress. */\r
678                         return pdFAIL;                          \r
679                 }               \r
680 \r
681                 vReadPHY(AT91C_PHY_ADDR, MII_LPA, &ulLPA);\r
682                 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_100HALF ) )\r
683                 {\r
684                         ulSpeed = SPEED_100;\r
685                 }\r
686                 else\r
687                 {\r
688                         ulSpeed = SPEED_10;\r
689                 }\r
690 \r
691                 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_10FULL ) )\r
692                 {\r
693                         ulDuplex = DUPLEX_FULL;\r
694                 }\r
695                 else\r
696                 {\r
697                         ulDuplex = DUPLEX_HALF;\r
698                 }\r
699         }\r
700         else\r
701         {\r
702                 ulSpeed = ( ulBMCR & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10;\r
703                 ulDuplex = ( ulBMCR & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF;\r
704         }\r
705 \r
706         /* Update the MAC */\r
707         ulMACCfg = AT91C_BASE_EMAC->EMAC_NCFGR & ~( AT91C_EMAC_SPD | AT91C_EMAC_FD );\r
708         if( ulSpeed == SPEED_100 )\r
709         {\r
710                 if( ulDuplex == DUPLEX_FULL )\r
711                 {\r
712                         /* 100 Full Duplex */\r
713                         AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;\r
714                 }\r
715                 else\r
716                 {                                       \r
717                         /* 100 Half Duplex */\r
718                         AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD;\r
719                 }\r
720         }\r
721         else\r
722         {\r
723                 if (ulDuplex == DUPLEX_FULL)\r
724                 {\r
725                         /* 10 Full Duplex */\r
726                         AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_FD;\r
727                 }\r
728                 else\r
729                 {\r
730                         /* 10 Half Duplex */\r
731                         AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg;\r
732                 }\r
733         }\r
734 \r
735         /* End of code supplied by Atmel ------------------------*/\r
736 \r
737         return pdPASS;\r
738 }\r