]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_AVR32_UC3/DRIVERS/MACB/macb.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / lwIP_AVR32_UC3 / DRIVERS / MACB / macb.c
1 /*This file has been prepared for Doxygen automatic documentation generation.*/\r
2 /*! \file *********************************************************************\r
3  *\r
4  * \brief MACB driver for EVK1100 board.\r
5  *\r
6  * This file defines a useful set of functions for the MACB interface on\r
7  * AVR32 devices.\r
8  *\r
9  * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32\r
10  * - Supported devices:  All AVR32 devices with a MACB module can be used.\r
11  * - AppNote:\r
12  *\r
13  * \author               Atmel Corporation: http://www.atmel.com \n\r
14  *                       Support and FAQ: http://support.atmel.no/\r
15  *\r
16  *****************************************************************************/\r
17 \r
18 /* Copyright (c) 2007, Atmel Corporation All rights reserved.\r
19  *\r
20  * Redistribution and use in source and binary forms, with or without\r
21  * modification, are permitted provided that the following conditions are met:\r
22  *\r
23  * 1. Redistributions of source code must retain the above copyright notice,\r
24  * this list of conditions and the following disclaimer.\r
25  *\r
26  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
27  * this list of conditions and the following disclaimer in the documentation\r
28  * and/or other materials provided with the distribution.\r
29  *\r
30  * 3. The name of ATMEL may not be used to endorse or promote products derived\r
31  * from this software without specific prior written permission.\r
32  *\r
33  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
35  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND\r
36  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,\r
37  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
38  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
39  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
40  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
41  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
42  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
43  */\r
44 \r
45 \r
46 #include <stdio.h>\r
47 #include <string.h>\r
48 #include <avr32/io.h>\r
49 \r
50 \r
51 #ifdef FREERTOS_USED\r
52   #include "FreeRTOS.h" \r
53   #include "task.h"\r
54   #include "semphr.h"\r
55 #endif\r
56 #include "macb.h"\r
57 #include "gpio.h"\r
58 #include "conf_eth.h"\r
59 #include "intc.h"\r
60 \r
61 \r
62 /* Size of each receive buffer - DO NOT CHANGE. */\r
63 #define RX_BUFFER_SIZE    128\r
64 \r
65 \r
66 /* The buffer addresses written into the descriptors must be aligned so the\r
67 last few bits are zero.  These bits have special meaning for the MACB\r
68 peripheral and cannot be used as part of the address. */\r
69 #define ADDRESS_MASK      ( ( unsigned long ) 0xFFFFFFFC )\r
70 \r
71 /* Bit used within the address stored in the descriptor to mark the last\r
72 descriptor in the array. */\r
73 #define RX_WRAP_BIT       ( ( unsigned long ) 0x02 )\r
74 \r
75 /* A short delay is used to wait for a buffer to become available, should\r
76 one not be immediately available when trying to transmit a frame. */\r
77 #define BUFFER_WAIT_DELAY   ( 2 )\r
78 \r
79 #ifndef FREERTOS_USED\r
80 #define portENTER_CRITICAL           Disable_global_interrupt \r
81 #define portEXIT_CRITICAL            Enable_global_interrupt\r
82 #define portENTER_SWITCHING_ISR()  \r
83 #define portEXIT_SWITCHING_ISR()  \r
84 #endif \r
85 \r
86 \r
87 /* Buffer written to by the MACB DMA.  Must be aligned as described by the\r
88 comment above the ADDRESS_MASK definition. */\r
89 #if __GNUC__\r
90 static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ] __attribute__ ((aligned (8)));\r
91 #elif __ICCAVR32__\r
92 #pragma data_alignment=8\r
93 static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ];\r
94 #endif\r
95 \r
96 \r
97 /* Buffer read by the MACB DMA.  Must be aligned as described by the comment\r
98 above the ADDRESS_MASK definition. */\r
99 #if __GNUC__\r
100 static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ] __attribute__ ((aligned (8)));\r
101 #elif __ICCAVR32__\r
102 #pragma data_alignment=8\r
103 static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ];\r
104 #endif\r
105 \r
106 /* Descriptors used to communicate between the program and the MACB peripheral.\r
107 These descriptors hold the locations and state of the Rx and Tx buffers. */\r
108 static volatile AVR32_TxTdDescriptor xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS ];\r
109 static volatile AVR32_RxTdDescriptor xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS ];\r
110 \r
111 /* The IP and Ethernet addresses are read from the header files. */\r
112 char cMACAddress[ 6 ] = { ETHERNET_CONF_ETHADDR0,ETHERNET_CONF_ETHADDR1,ETHERNET_CONF_ETHADDR2,ETHERNET_CONF_ETHADDR3,ETHERNET_CONF_ETHADDR4,ETHERNET_CONF_ETHADDR5 };\r
113 \r
114 /*-----------------------------------------------------------*/\r
115 \r
116 /* See the header file for descriptions of public functions. */\r
117 \r
118 /*\r
119  * Prototype for the MACB interrupt function - called by the asm wrapper.\r
120  */\r
121 #ifdef FREERTOS_USED\r
122 #if __GNUC__\r
123 __attribute__((naked))\r
124 #elif __ICCAVR32__\r
125 #pragma shadow_registers = full   // Naked.\r
126 #endif\r
127 #else\r
128 #if __GNUC__\r
129 __attribute__((__interrupt__))\r
130 #elif __ICCAVR32__\r
131 __interrupt\r
132 #endif\r
133 #endif\r
134 void vMACB_ISR( void );\r
135 static long prvMACB_ISR_NonNakedBehaviour( void );\r
136 \r
137 \r
138 #if ETHERNET_CONF_USE_PHY_IT\r
139 #ifdef FREERTOS_USED\r
140 #if __GNUC__\r
141 __attribute__((naked))\r
142 #elif __ICCAVR32__\r
143 #pragma shadow_registers = full   // Naked.\r
144 #endif\r
145 #else\r
146 #if __GNUC__\r
147 __attribute__((__interrupt__))\r
148 #elif __ICCAVR32__\r
149 __interrupt\r
150 #endif\r
151 #endif\r
152 void vPHY_ISR( void );\r
153 static long prvPHY_ISR_NonNakedBehaviour( void );\r
154 #endif\r
155 \r
156 \r
157 /*\r
158  * Initialise both the Tx and Rx descriptors used by the MACB.\r
159  */\r
160 static void prvSetupDescriptors(volatile avr32_macb_t * macb);\r
161 \r
162 /*\r
163  * Write our MAC address into the MACB.  \r
164  */\r
165 static void prvSetupMACAddress( volatile avr32_macb_t * macb );\r
166 \r
167 /*\r
168  * Configure the MACB for interrupts.\r
169  */\r
170 static void prvSetupMACBInterrupt( volatile avr32_macb_t * macb );\r
171 \r
172 /*\r
173  * Some initialisation functions.\r
174  */\r
175 static Bool prvProbePHY( volatile avr32_macb_t * macb );\r
176 static unsigned long ulReadMDIO(volatile avr32_macb_t * macb, unsigned short usAddress); \r
177 static void vWriteMDIO(volatile avr32_macb_t * macb, unsigned short usAddress, unsigned short usValue);\r
178 \r
179 \r
180 #ifdef FREERTOS_USED\r
181 /* The semaphore used by the MACB ISR to wake the MACB task. */\r
182 static xSemaphoreHandle xSemaphore = NULL;\r
183 #else\r
184 static volatile Bool DataToRead = FALSE;\r
185 #endif\r
186 \r
187 /* Holds the index to the next buffer from which data will be read. */\r
188 volatile unsigned long ulNextRxBuffer = 0;\r
189 \r
190 \r
191 long lMACBSend(volatile avr32_macb_t * macb, char *pcFrom, unsigned long ulLength, long lEndOfFrame )\r
192 {\r
193 static unsigned long uxTxBufferIndex = 0;\r
194 char *pcBuffer;\r
195 unsigned long ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend;\r
196 \r
197 \r
198   /* If the length of data to be transmitted is greater than each individual\r
199   transmit buffer then the data will be split into more than one buffer.\r
200   Loop until the entire length has been buffered. */\r
201   while( ulDataBuffered < ulLength )\r
202   {\r
203     // Is a buffer available ?\r
204     while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AVR32_TRANSMIT_OK ) )\r
205     {\r
206       // There is no room to write the Tx data to the Tx buffer.  \r
207       // Wait a short while, then try again.\r
208 #ifdef FREERTOS_USED\r
209       vTaskDelay( BUFFER_WAIT_DELAY );\r
210 #else\r
211       __asm__ __volatile__ ("nop");      \r
212 #endif\r
213     }\r
214   \r
215     portENTER_CRITICAL();\r
216     {\r
217       // Get the address of the buffer from the descriptor, \r
218       // then copy the data into the buffer.\r
219       pcBuffer = ( char * ) xTxDescriptors[ uxTxBufferIndex ].addr;\r
220 \r
221       // How much can we write to the buffer ?\r
222       ulDataRemainingToSend = ulLength - ulDataBuffered;\r
223       if( ulDataRemainingToSend <= ETHERNET_CONF_TX_BUFFER_SIZE )\r
224       {\r
225         // We can write all the remaining bytes.\r
226         ulLengthToSend = ulDataRemainingToSend;\r
227       }\r
228       else\r
229       {\r
230         // We can't write more than ETH_TX_BUFFER_SIZE in one go.\r
231         ulLengthToSend = ETHERNET_CONF_TX_BUFFER_SIZE;\r
232       }\r
233       // Copy the data into the buffer.\r
234       memcpy( ( void * ) pcBuffer, ( void * ) &( pcFrom[ ulDataBuffered ] ), ulLengthToSend );\r
235       ulDataBuffered += ulLengthToSend;\r
236       // Is this the last data for the frame ? \r
237       if( lEndOfFrame && ( ulDataBuffered >= ulLength ) )\r
238       {\r
239         // No more data remains for this frame so we can start the transmission.\r
240         ulLastBuffer = AVR32_LAST_BUFFER;\r
241       }\r
242       else\r
243       {\r
244         // More data to come for this frame.\r
245         ulLastBuffer = 0;\r
246       }\r
247       // Fill out the necessary in the descriptor to get the data sent,\r
248       // then move to the next descriptor, wrapping if necessary.\r
249       if( uxTxBufferIndex >= ( ETHERNET_CONF_NB_TX_BUFFERS - 1 ) )\r
250       {\r
251         xTxDescriptors[ uxTxBufferIndex ].U_Status.status =   ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME )\r
252                                     | ulLastBuffer\r
253                                     | AVR32_TRANSMIT_WRAP;\r
254         uxTxBufferIndex = 0;\r
255       }\r
256       else\r
257       {\r
258         xTxDescriptors[ uxTxBufferIndex ].U_Status.status =   ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME )\r
259                                     | ulLastBuffer;\r
260         uxTxBufferIndex++;\r
261       }\r
262       /* If this is the last buffer to be sent for this frame we can\r
263          start the transmission. */\r
264       if( ulLastBuffer )\r
265       {\r
266         macb->ncr |=  AVR32_MACB_TSTART_MASK;\r
267       }\r
268     }\r
269     portEXIT_CRITICAL();\r
270   }\r
271 \r
272   return PASS;\r
273 }\r
274 \r
275 \r
276 unsigned long ulMACBInputLength( void )\r
277 {\r
278 register unsigned long ulIndex , ulLength = 0;\r
279 unsigned int uiTemp;\r
280 \r
281   // Skip any fragments.  We are looking for the first buffer that contains\r
282   // data and has the SOF (start of frame) bit set.\r
283   while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AVR32_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AVR32_SOF ) )\r
284   {\r
285     // Ignoring this buffer.  Mark it as free again.\r
286     uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;\r
287     xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );\r
288     ulNextRxBuffer++;\r
289     if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )\r
290     {\r
291       ulNextRxBuffer = 0;\r
292     }\r
293   }\r
294 \r
295   // We are going to walk through the descriptors that make up this frame,\r
296   // but don't want to alter ulNextRxBuffer as this would prevent vMACBRead()\r
297   // from finding the data.  Therefore use a copy of ulNextRxBuffer instead. \r
298   ulIndex = ulNextRxBuffer;\r
299 \r
300   // Walk through the descriptors until we find the last buffer for this frame.\r
301   // The last buffer will give us the length of the entire frame.\r
302   while( ( xRxDescriptors[ ulIndex ].addr & AVR32_OWNERSHIP_BIT ) && !ulLength )\r
303   {\r
304     ulLength = xRxDescriptors[ ulIndex ].U_Status.status & AVR32_LENGTH_FRAME;\r
305     // Increment to the next buffer, wrapping if necessary.\r
306     ulIndex++;\r
307     if( ulIndex >= ETHERNET_CONF_NB_RX_BUFFERS )\r
308     {\r
309       ulIndex = 0;\r
310     }\r
311   }\r
312   return ulLength;\r
313 }\r
314 /*-----------------------------------------------------------*/\r
315 \r
316 void vMACBRead( char *pcTo, unsigned long ulSectionLength, unsigned long ulTotalFrameLength )\r
317 {\r
318 static unsigned long ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFameBytesReadSoFar = 0;\r
319 static char *pcSource;\r
320 register unsigned long ulBytesRemainingInBuffer, ulRemainingSectionBytes;\r
321 unsigned int uiTemp;\r
322 \r
323   // Read ulSectionLength bytes from the Rx buffers. \r
324   // This is not necessarily any correspondence between the length of our Rx buffers, \r
325   // and the length of the data we are returning or the length of the data being requested.\r
326   // Therefore, between calls  we have to remember not only which buffer we are currently\r
327   // processing, but our position within that buffer.  \r
328   // This would be greatly simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater \r
329   // than the size of each Rx buffer, and that memory fragmentation did not occur.\r
330   \r
331   // This function should only be called after a call to ulMACBInputLength().\r
332   // This will ensure ulNextRxBuffer is set to the correct buffer. */\r
333 \r
334   // vMACBRead is called with pcTo set to NULL to indicate that we are about\r
335   // to read a new frame.  Any fragments remaining in the frame we were\r
336   // processing during the last call should be dropped.\r
337   if( pcTo == NULL )\r
338   {\r
339     // How many bytes are indicated as being in this buffer?  \r
340     // If none then the buffer is completely full and the frame is contained within more\r
341     // than one buffer.\r
342     // Reset our state variables ready for the next read from this buffer.\r
343     pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );\r
344     ulFameBytesReadSoFar = ( unsigned long ) 0;\r
345     ulBufferPosition = ( unsigned long ) 0;\r
346   }\r
347   else\r
348   {\r
349     // Loop until we have obtained the required amount of data.\r
350     ulSectionBytesReadSoFar = 0;\r
351     while( ulSectionBytesReadSoFar < ulSectionLength )\r
352     {\r
353       // We may have already read some data from this buffer.\r
354       // How much data remains in the buffer?\r
355       ulBytesRemainingInBuffer = ( RX_BUFFER_SIZE - ulBufferPosition );\r
356 \r
357       // How many more bytes do we need to read before we have the\r
358       // required amount of data?\r
359       ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar;\r
360 \r
361       // Do we want more data than remains in the buffer? \r
362       if( ulRemainingSectionBytes > ulBytesRemainingInBuffer )\r
363       {\r
364         // We want more data than remains in the buffer so we can\r
365         // write the remains of the buffer to the destination, then move\r
366         // onto the next buffer to get the rest.\r
367         memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer );\r
368         ulSectionBytesReadSoFar += ulBytesRemainingInBuffer;\r
369         ulFameBytesReadSoFar += ulBytesRemainingInBuffer;\r
370 \r
371         // Mark the buffer as free again.\r
372         uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;\r
373         xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );\r
374         // Move onto the next buffer.\r
375         ulNextRxBuffer++;\r
376        \r
377         if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )\r
378         {\r
379           ulNextRxBuffer = ( unsigned long ) 0;\r
380         }\r
381       \r
382         // Reset the variables for the new buffer.\r
383         pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );\r
384         ulBufferPosition = ( unsigned long ) 0;\r
385       }\r
386       else\r
387       {\r
388         // We have enough data in this buffer to send back.\r
389         // Read out enough data and remember how far we read up to.\r
390         memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes );\r
391 \r
392         // There may be more data in this buffer yet.\r
393         // Increment our position in this buffer past the data we have just read.\r
394         ulBufferPosition += ulRemainingSectionBytes;\r
395         ulSectionBytesReadSoFar += ulRemainingSectionBytes;\r
396         ulFameBytesReadSoFar += ulRemainingSectionBytes;\r
397 \r
398         // Have we now finished with this buffer?\r
399         if( ( ulBufferPosition >= RX_BUFFER_SIZE ) || ( ulFameBytesReadSoFar >= ulTotalFrameLength ) )\r
400         {\r
401           // Mark the buffer as free again.\r
402           uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;\r
403           xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );\r
404           // Move onto the next buffer.\r
405           ulNextRxBuffer++;\r
406          \r
407           if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )\r
408           {\r
409             ulNextRxBuffer = 0;\r
410           }\r
411        \r
412           pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );\r
413           ulBufferPosition = 0;\r
414         }\r
415       }\r
416     }\r
417   }\r
418 }\r
419 /*-----------------------------------------------------------*/\r
420 void vMACBSetMACAddress(const char * MACAddress)\r
421 {\r
422   memcpy(cMACAddress, MACAddress, sizeof(cMACAddress));\r
423 }\r
424 \r
425 Bool xMACBInit( volatile avr32_macb_t * macb )\r
426 {\r
427 volatile unsigned long status;\r
428 \r
429   // set up registers\r
430   macb->ncr = 0;\r
431   macb->tsr = ~0UL;\r
432   macb->rsr = ~0UL;\r
433   macb->idr = ~0UL;\r
434   status = macb->isr;\r
435 \r
436 \r
437 #if ETHERNET_CONF_USE_RMII_INTERFACE\r
438   // RMII used, set 0 to the USRIO Register\r
439   macb->usrio &= ~AVR32_MACB_RMII_MASK;\r
440 #else\r
441   // RMII not used, set 1 to the USRIO Register\r
442   macb->usrio |= AVR32_MACB_RMII_MASK;\r
443 #endif\r
444 \r
445   // Load our MAC address into the MACB. \r
446   prvSetupMACAddress(macb);\r
447 \r
448   // Setup the buffers and descriptors.\r
449   prvSetupDescriptors(macb);\r
450 \r
451 #if ETHERNET_CONF_SYSTEM_CLOCK <= 20000000\r
452   macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV8 << AVR32_MACB_NCFGR_CLK_OFFSET);\r
453 #elif ETHERNET_CONF_SYSTEM_CLOCK <= 40000000\r
454   macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV16 << AVR32_MACB_NCFGR_CLK_OFFSET);\r
455 #elif ETHERNET_CONF_SYSTEM_CLOCK <= 80000000\r
456   macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV32 << AVR32_MACB_NCFGR_CLK_OFFSET;\r
457 #elif ETHERNET_CONF_SYSTEM_CLOCK <= 160000000\r
458   macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV64 << AVR32_MACB_NCFGR_CLK_OFFSET;\r
459 #else\r
460 # error System clock too fast\r
461 #endif\r
462 \r
463   // Are we connected?\r
464   if( prvProbePHY(macb) == TRUE )\r
465   {\r
466     // Enable the interrupt!\r
467     portENTER_CRITICAL();\r
468     {\r
469       prvSetupMACBInterrupt(macb);\r
470     }\r
471     portEXIT_CRITICAL();\r
472     // Enable Rx and Tx, plus the stats register.\r
473     macb->ncr = AVR32_MACB_NCR_TE_MASK | AVR32_MACB_NCR_RE_MASK;\r
474     return (TRUE);\r
475   }\r
476   return (FALSE);\r
477 }\r
478 \r
479 void vDisableMACBOperations(volatile avr32_macb_t * macb)\r
480 {\r
481 #if ETHERNET_CONF_USE_PHY_IT\r
482 volatile avr32_gpio_t *gpio = &AVR32_GPIO;\r
483 volatile avr32_gpio_port_t *gpio_port = &gpio->port[MACB_INTERRUPT_PIN/32];\r
484 \r
485   gpio_port->ierc =  1 << (MACB_INTERRUPT_PIN%32);\r
486 #endif\r
487 \r
488   // write the MACB control register : disable Tx & Rx\r
489   macb->ncr &= ~((1 << AVR32_MACB_RE_OFFSET) | (1 << AVR32_MACB_TE_OFFSET));\r
490   // We no more want to interrupt on Rx and Tx events.\r
491   macb->idr = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;\r
492 }\r
493 \r
494 \r
495 void vClearMACBTxBuffer( void )\r
496 {\r
497 static unsigned long uxNextBufferToClear = 0;\r
498 \r
499   // Called on Tx interrupt events to set the AVR32_TRANSMIT_OK bit in each\r
500   // Tx buffer within the frame just transmitted.  This marks all the buffers\r
501   // as available again.\r
502 \r
503   // The first buffer in the frame should have the bit set automatically. */\r
504   if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_TRANSMIT_OK )\r
505   {\r
506     // Loop through the other buffers in the frame.\r
507     while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_LAST_BUFFER ) )\r
508     {\r
509       uxNextBufferToClear++;\r
510 \r
511       if( uxNextBufferToClear >= ETHERNET_CONF_NB_TX_BUFFERS )\r
512       {\r
513         uxNextBufferToClear = 0;\r
514       }\r
515 \r
516       xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AVR32_TRANSMIT_OK;\r
517     }\r
518 \r
519     // Start with the next buffer the next time a Tx interrupt is called.\r
520     uxNextBufferToClear++;\r
521 \r
522     // Do we need to wrap back to the first buffer? \r
523     if( uxNextBufferToClear >= ETHERNET_CONF_NB_TX_BUFFERS )\r
524     {\r
525       uxNextBufferToClear = 0;\r
526     }\r
527   }\r
528 }\r
529 \r
530 static void prvSetupDescriptors(volatile avr32_macb_t * macb)\r
531 {\r
532 unsigned long xIndex;\r
533 unsigned long ulAddress;\r
534 \r
535   // Initialise xRxDescriptors descriptor.\r
536   for( xIndex = 0; xIndex < ETHERNET_CONF_NB_RX_BUFFERS; ++xIndex )\r
537   {\r
538     // Calculate the address of the nth buffer within the array.\r
539     ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * RX_BUFFER_SIZE ) );\r
540 \r
541     // Write the buffer address into the descriptor.  \r
542     // The DMA will place the data at this address when this descriptor is being used.\r
543     // Mask off the bottom bits of the address as these have special meaning.\r
544     xRxDescriptors[ xIndex ].addr = ulAddress & ADDRESS_MASK;\r
545   }\r
546 \r
547   // The last buffer has the wrap bit set so the MACB knows to wrap back\r
548   // to the first buffer.\r
549   xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS - 1 ].addr |= RX_WRAP_BIT;\r
550 \r
551   // Initialise xTxDescriptors.\r
552   for( xIndex = 0; xIndex < ETHERNET_CONF_NB_TX_BUFFERS; ++xIndex )\r
553   {\r
554     // Calculate the address of the nth buffer within the array.\r
555     ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETHERNET_CONF_TX_BUFFER_SIZE ) );\r
556 \r
557     // Write the buffer address into the descriptor.  \r
558     // The DMA will read data from here when the descriptor is being used.\r
559     xTxDescriptors[ xIndex ].addr = ulAddress & ADDRESS_MASK;\r
560     xTxDescriptors[ xIndex ].U_Status.status = AVR32_TRANSMIT_OK;\r
561   }\r
562 \r
563   // The last buffer has the wrap bit set so the MACB knows to wrap back\r
564   // to the first buffer.\r
565   xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS - 1 ].U_Status.status = AVR32_TRANSMIT_WRAP | AVR32_TRANSMIT_OK;\r
566 \r
567   // Tell the MACB where to find the descriptors.\r
568   macb->rbqp =   ( unsigned long )xRxDescriptors;\r
569   macb->tbqp =   ( unsigned long )xTxDescriptors;\r
570 \r
571   // Enable the copy of data into the buffers, ignore broadcasts,\r
572   // and don't copy FCS.\r
573   macb->ncfgr |= (AVR32_MACB_CAF_MASK |  AVR32_MACB_NBC_MASK | AVR32_MACB_NCFGR_DRFCS_MASK);\r
574 \r
575\r
576 \r
577 static void prvSetupMACAddress( volatile avr32_macb_t * macb )\r
578 {\r
579   // Must be written SA1L then SA1H.\r
580   macb->sa1b =  ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) |\r
581                 ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) |\r
582                 ( ( unsigned long ) cMACAddress[ 1 ] << 8  ) |\r
583                                     cMACAddress[ 0 ];\r
584 \r
585   macb->sa1t =  ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) |\r
586                                     cMACAddress[ 4 ];\r
587 }\r
588 \r
589 static void prvSetupMACBInterrupt( volatile avr32_macb_t * macb )\r
590 {\r
591 #ifdef FREERTOS_USED\r
592   // Create the semaphore used to trigger the MACB task. \r
593   if (xSemaphore == NULL)\r
594   {\r
595     vSemaphoreCreateBinary( xSemaphore );\r
596   }\r
597 #else \r
598   // Create the flag used to trigger the MACB polling task. \r
599   DataToRead = FALSE;\r
600 #endif\r
601 \r
602 \r
603 #ifdef FREERTOS_USED\r
604   if( xSemaphore != NULL)\r
605   {\r
606     // We start by 'taking' the semaphore so the ISR can 'give' it when the\r
607     // first interrupt occurs.\r
608     xSemaphoreTake( xSemaphore, 0 );\r
609 #endif\r
610     // Setup the interrupt for MACB.\r
611     // Register the interrupt handler to the interrupt controller at interrupt level 2\r
612     INTC_register_interrupt((__int_handler)&vMACB_ISR, AVR32_MACB_IRQ, INT2);\r
613 \r
614 #if ETHERNET_CONF_USE_PHY_IT\r
615     /* GPIO enable interrupt upon rising edge */\r
616     gpio_enable_pin_interrupt(MACB_INTERRUPT_PIN, GPIO_FALLING_EDGE);\r
617     // Setup the interrupt for PHY.\r
618     // Register the interrupt handler to the interrupt controller at interrupt level 2\r
619     INTC_register_interrupt((__int_handler)&vPHY_ISR, (AVR32_GPIO_IRQ_0 + (MACB_INTERRUPT_PIN/8)), INT2);\r
620     /* enable interrupts on INT pin */\r
621     vWriteMDIO( macb, PHY_MICR , ( MICR_INTEN | MICR_INTOE ));\r
622     /* enable "link change" interrupt for Phy */\r
623     vWriteMDIO( macb, PHY_MISR , MISR_LINK_INT_EN );\r
624 #endif\r
625 \r
626     // We want to interrupt on Rx and Tx events\r
627     macb->ier = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;\r
628 #ifdef FREERTOS_USED\r
629   }\r
630 #endif\r
631 }\r
632 \r
633 /*! Read a register on MDIO bus (access to the PHY)\r
634  *         This function is looping until PHY gets ready\r
635  *\r
636  * \param macb         Input. instance of the MACB to use\r
637  * \param usAddress    Input. register to set.\r
638  *\r
639  * \return unsigned long data that has been read\r
640  */\r
641 static unsigned long ulReadMDIO(volatile avr32_macb_t * macb, unsigned short usAddress)\r
642 {\r
643 unsigned long value, status;\r
644 \r
645   // initiate transaction : enable management port\r
646   macb->ncr |= AVR32_MACB_NCR_MPE_MASK;\r
647   // Write the PHY configuration frame to the MAN register\r
648   macb->man = (AVR32_MACB_SOF_MASK & (0x01<<AVR32_MACB_SOF_OFFSET))  // SOF\r
649             | (2 << AVR32_MACB_CODE_OFFSET)                          // Code\r
650             | (2 << AVR32_MACB_RW_OFFSET)                            // Read operation\r
651             | ((ETHERNET_CONF_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET)  // Phy Add\r
652             | (usAddress << AVR32_MACB_REGA_OFFSET);                 // Reg Add\r
653   // wait for PHY to be ready\r
654   do {\r
655     status = macb->nsr;\r
656   } while (!(status & AVR32_MACB_NSR_IDLE_MASK));\r
657   // read the register value in maintenance register\r
658   value = macb->man & 0x0000ffff;\r
659   // disable management port\r
660   macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK;\r
661   // return the read value\r
662   return (value);\r
663 }\r
664 \r
665 /*! Write a given value to a register on MDIO bus (access to the PHY)\r
666  *         This function is looping until PHY gets ready\r
667  *\r
668  * \param *macb        Input. instance of the MACB to use\r
669  * \param usAddress    Input. register to set.\r
670  * \param usValue      Input. value to write.\r
671  *\r
672  */\r
673 static void vWriteMDIO(volatile avr32_macb_t * macb, unsigned short usAddress, unsigned short usValue)\r
674 {\r
675 unsigned long status;\r
676 \r
677   // initiate transaction : enable management port\r
678   macb->ncr |= AVR32_MACB_NCR_MPE_MASK;\r
679   // Write the PHY configuration frame to the MAN register\r
680   macb->man = (( AVR32_MACB_SOF_MASK & (0x01<<AVR32_MACB_SOF_OFFSET)) // SOF\r
681              | (2 << AVR32_MACB_CODE_OFFSET)                          // Code\r
682              | (1 << AVR32_MACB_RW_OFFSET)                            // Write operation\r
683              | ((ETHERNET_CONF_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET)  // Phy Add\r
684              | (usAddress << AVR32_MACB_REGA_OFFSET))                 // Reg Add\r
685              | (usValue & 0xffff);                                    // Data\r
686   // wait for PHY to be ready\r
687   do {\r
688     status = macb->nsr;\r
689   } while (!(status & AVR32_MACB_NSR_IDLE_MASK));\r
690   // disable management port\r
691   macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK;\r
692 }\r
693 \r
694 static Bool prvProbePHY( volatile avr32_macb_t * macb )\r
695 {\r
696 volatile unsigned long mii_status, phy_ctrl;\r
697 volatile unsigned long config;\r
698 unsigned long upper, lower, mode, advertise, lpa;\r
699 volatile unsigned long physID;\r
700 \r
701   // Read Phy Identifier register 1 & 2\r
702   lower = ulReadMDIO(macb, PHY_PHYSID2);\r
703   upper = ulReadMDIO(macb, PHY_PHYSID1);\r
704   // get Phy ID, ignore Revision\r
705   physID = ((upper << 16) & 0xFFFF0000) | (lower & 0xFFF0);\r
706   // check if it match config\r
707   if (physID == ETHERNET_CONF_PHY_ID)\r
708   {\r
709     // read RBR\r
710     mode = ulReadMDIO(macb, PHY_RBR);\r
711     // set RMII mode if not done\r
712     if ((mode & RBR_RMII) != RBR_RMII)\r
713     {\r
714       // force RMII flag if strap options are wrong\r
715       mode |= RBR_RMII;\r
716       vWriteMDIO(macb, PHY_RBR, mode);\r
717     }\r
718 \r
719     // set advertise register\r
720 #if ETHERNET_CONF_AN_ENABLE == 1\r
721     advertise = ADVERTISE_CSMA | ADVERTISE_ALL;\r
722 #else\r
723     advertise = ADVERTISE_CSMA;\r
724     #if ETHERNET_CONF_USE_100MB\r
725       #if ETHERNET_CONF_USE_FULL_DUPLEX\r
726         advertise |= ADVERTISE_100FULL;\r
727       #else\r
728         advertise |= ADVERTISE_100HALF;\r
729       #endif\r
730     #else\r
731       #if ETHERNET_CONF_USE_FULL_DUPLEX\r
732         advertise |= ADVERTISE_10FULL;\r
733       #else\r
734         advertise |= ADVERTISE_10HALF;\r
735       #endif\r
736     #endif\r
737 #endif\r
738     // write advertise register\r
739     vWriteMDIO(macb, PHY_ADVERTISE, advertise);\r
740     // read Control register\r
741     config = ulReadMDIO(macb, PHY_BMCR);\r
742     // read Phy Control register\r
743     phy_ctrl = ulReadMDIO(macb, PHY_PHYCR);\r
744 #if ETHERNET_CONF_AN_ENABLE\r
745   #if ETHERNET_CONF_AUTO_CROSS_ENABLE\r
746     // enable Auto MDIX\r
747     phy_ctrl |= PHYCR_MDIX_EN;\r
748   #else\r
749     // disable Auto MDIX\r
750     phy_ctrl &= ~PHYCR_MDIX_EN;\r
751     #if ETHERNET_CONF_CROSSED_LINK\r
752       // force direct link = Use crossed RJ45 cable\r
753       phy_ctrl &= ~PHYCR_MDIX_FORCE;\r
754     #else\r
755       // force crossed link = Use direct RJ45 cable\r
756       phy_ctrl |= PHYCR_MDIX_FORCE;\r
757     #endif\r
758   #endif\r
759   // reset auto-negociation capability\r
760   config |= (BMCR_ANRESTART | BMCR_ANENABLE);\r
761 #else\r
762   // disable Auto MDIX\r
763   phy_ctrl &= ~PHYCR_MDIX_EN;\r
764   #if ETHERNET_CONF_CROSSED_LINK\r
765     // force direct link = Use crossed RJ45 cable\r
766     phy_ctrl &= ~PHYCR_MDIX_FORCE;\r
767   #else\r
768     // force crossed link = Use direct RJ45 cable\r
769     phy_ctrl |= PHYCR_MDIX_FORCE;\r
770   #endif\r
771   // clear AN bit\r
772   config &= ~BMCR_ANENABLE;\r
773 \r
774   #if ETHERNET_CONF_USE_100MB\r
775     config |= BMCR_SPEED100;\r
776   #else\r
777     config &= ~BMCR_SPEED100;\r
778   #endif\r
779   #if ETHERNET_CONF_USE_FULL_DUPLEX\r
780     config |= BMCR_FULLDPLX;\r
781   #else\r
782     config &= ~BMCR_FULLDPLX;\r
783   #endif\r
784 #endif\r
785     // update Phy ctrl register\r
786     vWriteMDIO(macb, PHY_PHYCR, phy_ctrl);\r
787 \r
788     // update ctrl register\r
789     vWriteMDIO(macb, PHY_BMCR, config);\r
790 \r
791     // loop while link status isn't OK\r
792     do {\r
793       mii_status = ulReadMDIO(macb, PHY_BMSR);\r
794     } while (!(mii_status & BMSR_LSTATUS));\r
795 \r
796     // read the LPA configuration of the PHY\r
797     lpa = ulReadMDIO(macb, PHY_LPA);\r
798 \r
799     // read the MACB config register\r
800     config = AVR32_MACB.ncfgr;\r
801 \r
802     // if 100MB needed\r
803     if ((lpa & advertise) & (LPA_100HALF | LPA_100FULL))\r
804     {\r
805       config |= AVR32_MACB_SPD_MASK;\r
806     }\r
807     else\r
808     {\r
809       config &= ~(AVR32_MACB_SPD_MASK);\r
810     }\r
811 \r
812     // if FULL DUPLEX needed\r
813     if ((lpa & advertise) & (LPA_10FULL | LPA_100FULL))\r
814     {\r
815       config |= AVR32_MACB_FD_MASK;\r
816     }\r
817     else\r
818     {\r
819       config &= ~(AVR32_MACB_FD_MASK);\r
820     }\r
821 \r
822     // write the MACB config register\r
823     macb->ncfgr = config;\r
824 \r
825     return TRUE;\r
826   }\r
827   return FALSE;\r
828 }\r
829 \r
830 \r
831 void vMACBWaitForInput( unsigned long ulTimeOut )\r
832 {\r
833 #ifdef FREERTOS_USED\r
834   // Just wait until we are signled from an ISR that data is available, or\r
835   // we simply time out.\r
836   xSemaphoreTake( xSemaphore, ulTimeOut );\r
837 #else\r
838 unsigned long i;\r
839   gpio_clr_gpio_pin(LED0_GPIO);\r
840   i = ulTimeOut * 1000;  \r
841   // wait for an interrupt to occurs\r
842   do\r
843   {\r
844     if ( DataToRead == TRUE )\r
845     {\r
846       // IT occurs, reset interrupt flag\r
847       portENTER_CRITICAL();\r
848       DataToRead = FALSE;    \r
849       portEXIT_CRITICAL();\r
850       break;    \r
851     }\r
852     i--;\r
853   }\r
854   while(i != 0);\r
855   gpio_set_gpio_pin(LED0_GPIO);  \r
856 #endif\r
857 }\r
858 \r
859 \r
860 /*\r
861  * The MACB ISR.  Handles both Tx and Rx complete interrupts.\r
862  */\r
863 #ifdef FREERTOS_USED\r
864 #if __GNUC__\r
865 __attribute__((naked))\r
866 #elif __ICCAVR32__\r
867 #pragma shadow_registers = full   // Naked.\r
868 #endif\r
869 #else\r
870 #if __GNUC__\r
871 __attribute__((__interrupt__))\r
872 #elif __ICCAVR32__\r
873 __interrupt\r
874 #endif\r
875 #endif\r
876 void vMACB_ISR( void )\r
877 {\r
878   // This ISR can cause a context switch, so the first statement must be a\r
879   // call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any\r
880   // variable declarations. \r
881   portENTER_SWITCHING_ISR();\r
882 \r
883   // the return value is used by FreeRTOS to change the context if needed after rete instruction\r
884   // in standalone use, this value should be ignored \r
885   prvMACB_ISR_NonNakedBehaviour();\r
886 \r
887   // Exit the ISR.  If a task was woken by either a character being received\r
888   // or transmitted then a context switch will occur.\r
889   portEXIT_SWITCHING_ISR();\r
890 }\r
891 /*-----------------------------------------------------------*/\r
892 \r
893 #if __GNUC__\r
894 __attribute__((__noinline__))\r
895 #elif __ICCAVR32__\r
896 #pragma optimize = no_inline\r
897 #endif\r
898 static long prvMACB_ISR_NonNakedBehaviour( void )\r
899 {\r
900 \r
901   // Variable definitions can be made now.\r
902   volatile unsigned long ulIntStatus, ulEventStatus;\r
903   long xHigherPriorityTaskWoken = FALSE;\r
904 \r
905   // Find the cause of the interrupt.\r
906   ulIntStatus = AVR32_MACB.isr;\r
907   ulEventStatus = AVR32_MACB.rsr;\r
908 \r
909   if( ( ulIntStatus & AVR32_MACB_IDR_RCOMP_MASK ) || ( ulEventStatus & AVR32_MACB_REC_MASK ) )\r
910   {\r
911     // A frame has been received, signal the IP task so it can process\r
912     // the Rx descriptors.\r
913     portENTER_CRITICAL();\r
914 #ifdef FREERTOS_USED\r
915     xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );\r
916 #else\r
917     DataToRead = TRUE;   \r
918 #endif      \r
919     portEXIT_CRITICAL();\r
920     AVR32_MACB.rsr =  AVR32_MACB_REC_MASK;\r
921     AVR32_MACB.rsr;\r
922   }\r
923 \r
924   if( ulIntStatus & AVR32_MACB_TCOMP_MASK )\r
925   {\r
926     // A frame has been transmitted.  Mark all the buffers used by the\r
927     // frame just transmitted as free again.\r
928     vClearMACBTxBuffer();\r
929     AVR32_MACB.tsr =  AVR32_MACB_TSR_COMP_MASK;\r
930     AVR32_MACB.tsr;\r
931   }\r
932 \r
933   return ( xHigherPriorityTaskWoken );\r
934 }\r
935 \r
936 \r
937 \r
938 #if ETHERNET_CONF_USE_PHY_IT\r
939 /*\r
940  * The PHY ISR.  Handles Phy interrupts.\r
941  */\r
942 #ifdef FREERTOS_USED\r
943 #if __GNUC__\r
944 __attribute__((naked))\r
945 #elif __ICCAVR32__\r
946 #pragma shadow_registers = full   // Naked.\r
947 #endif\r
948 #else\r
949 #if __GNUC__\r
950 __attribute__((__interrupt__))\r
951 #elif __ICCAVR32__\r
952 __interrupt\r
953 #endif\r
954 #endif\r
955 void vPHY_ISR( void )\r
956 {\r
957   // This ISR can cause a context switch, so the first statement must be a\r
958   // call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any\r
959   // variable declarations. \r
960   portENTER_SWITCHING_ISR();\r
961 \r
962   // the return value is used by FreeRTOS to change the context if needed after rete instruction\r
963   // in standalone use, this value should be ignored \r
964   prvPHY_ISR_NonNakedBehaviour();\r
965 \r
966   // Exit the ISR.  If a task was woken by either a character being received\r
967   // or transmitted then a context switch will occur.\r
968   portEXIT_SWITCHING_ISR();\r
969 }\r
970 /*-----------------------------------------------------------*/\r
971 \r
972 #if __GNUC__\r
973 __attribute__((__noinline__))\r
974 #elif __ICCAVR32__\r
975 #pragma optimize = no_inline\r
976 #endif\r
977 static long prvPHY_ISR_NonNakedBehaviour( void )\r
978 {\r
979 \r
980   // Variable definitions can be made now.\r
981   volatile unsigned long ulIntStatus, ulEventStatus;\r
982   long xSwitchRequired = FALSE;\r
983   volatile avr32_gpio_t *gpio = &AVR32_GPIO;\r
984   volatile avr32_gpio_port_t *gpio_port = &gpio->port[MACB_INTERRUPT_PIN/32];\r
985 \r
986   // read Phy Interrupt register Status\r
987   ulIntStatus = ulReadMDIO(&AVR32_MACB, PHY_MISR);\r
988   \r
989   // read Phy status register\r
990   ulEventStatus = ulReadMDIO(&AVR32_MACB, PHY_BMSR);\r
991   // dummy read\r
992   ulEventStatus = ulReadMDIO(&AVR32_MACB, PHY_BMSR);\r
993 \r
994    // clear interrupt flag on GPIO\r
995   gpio_port->ifrc =  1 << (MACB_INTERRUPT_PIN%32);\r
996   \r
997   return ( xSwitchRequired );\r
998 }\r
999 #endif\r