]> git.sur5r.net Git - freertos/blob - Demo/Common/drivers/Atmel/at91lib/peripherals/emac/emac.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / Common / drivers / Atmel / at91lib / peripherals / emac / emac.c
1 /* ----------------------------------------------------------------------------\r
2  *         ATMEL Microcontroller Software Support\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2008, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 //-----------------------------------------------------------------------------\r
31 //         Headers\r
32 //-----------------------------------------------------------------------------\r
33 #include <board.h>\r
34 #include "emac.h"\r
35 #include <utility/trace.h>\r
36 #include <utility/assert.h>\r
37 #include <string.h>\r
38 \r
39 //------------------------------------------------------------------------------\r
40 //         Definitions\r
41 //------------------------------------------------------------------------------\r
42 /// The buffer addresses written into the descriptors must be aligned so the\r
43 /// last few bits are zero.  These bits have special meaning for the EMAC\r
44 /// peripheral and cannot be used as part of the address.\r
45 #define EMAC_ADDRESS_MASK   ((unsigned int)0xFFFFFFFC)\r
46 #define EMAC_LENGTH_FRAME   ((unsigned int)0x0FFF)    /// Length of frame mask\r
47 \r
48 // receive buffer descriptor bits\r
49 #define EMAC_RX_OWNERSHIP_BIT   (1UL <<  0)\r
50 #define EMAC_RX_WRAP_BIT        (1UL <<  1)\r
51 #define EMAC_RX_SOF_BIT         (1UL << 14)\r
52 #define EMAC_RX_EOF_BIT         (1UL << 15)\r
53 \r
54 // Transmit buffer descriptor bits\r
55 #define EMAC_TX_LAST_BUFFER_BIT (1UL << 15)\r
56 #define EMAC_TX_WRAP_BIT        (1UL << 30)\r
57 #define EMAC_TX_USED_BIT        (1UL << 31)\r
58 \r
59 //-----------------------------------------------------------------------------\r
60 // Circular buffer management\r
61 //-----------------------------------------------------------------------------\r
62 // Return count in buffer\r
63 #define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))\r
64 \r
65 // Return space available, 0..size-1\r
66 // We always leave one free char as a completely full buffer\r
67 // has head == tail, which is the same as empty\r
68 #define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))\r
69 \r
70 // Return count up to the end of the buffer.\r
71 // Carefully avoid accessing head and tail more than once,\r
72 // so they can change underneath us without returning inconsistent results\r
73 #define CIRC_CNT_TO_END(head,tail,size) \\r
74    ({int end = (size) - (tail); \\r
75      int n = ((head) + end) & ((size)-1); \\r
76      n < end ? n : end;})\r
77 \r
78 // Return space available up to the end of the buffer\r
79 #define CIRC_SPACE_TO_END(head,tail,size) \\r
80    ({int end = (size) - 1 - (head); \\r
81      int n = (end + (tail)) & ((size)-1); \\r
82      n <= end ? n : end+1;})\r
83 \r
84 // Increment head or tail\r
85 #define CIRC_INC(headortail,size) \\r
86         headortail++;             \\r
87         if(headortail >= size) {  \\r
88             headortail = 0;       \\r
89         }\r
90 \r
91 #define CIRC_EMPTY(circ)     ((circ)->head == (circ)->tail)\r
92 #define CIRC_CLEAR(circ)     ((circ)->head = (circ)->tail = 0)\r
93 \r
94 \r
95 //------------------------------------------------------------------------------\r
96 //      Structures\r
97 //------------------------------------------------------------------------------\r
98 #ifdef __ICCARM__          // IAR\r
99 #pragma pack(4)            // IAR\r
100 #define __attribute__(...) // IAR\r
101 #endif                     // IAR\r
102 /// Describes the type and attribute of Receive Transfer descriptor.\r
103 typedef struct _EmacRxTDescriptor {\r
104     unsigned int addr;\r
105     unsigned int status;\r
106 } __attribute__((packed, aligned(8))) EmacRxTDescriptor, *PEmacRxTDescriptor;\r
107 \r
108 /// Describes the type and attribute of Transmit Transfer descriptor.\r
109 typedef struct _EmacTxTDescriptor {\r
110     unsigned int addr;\r
111     unsigned int status;\r
112 } __attribute__((packed, aligned(8))) EmacTxTDescriptor, *PEmacTxTDescriptor;\r
113 #ifdef __ICCARM__          // IAR\r
114 #pragma pack()             // IAR\r
115 #endif                     // IAR\r
116 \r
117 /// Descriptors for RX (required aligned by 8)\r
118 typedef struct {\r
119    volatile EmacRxTDescriptor td[RX_BUFFERS];\r
120    EMAC_RxCallback rxCb; /// Callback function to be invoked once a frame has been received\r
121    unsigned short idx;\r
122 } RxTd;\r
123 \r
124 /// Descriptors for TX (required aligned by 8)\r
125 typedef struct {\r
126    volatile EmacTxTDescriptor td[TX_BUFFERS];\r
127    EMAC_TxCallback txCb[TX_BUFFERS];    /// Callback function to be invoked once TD has been processed\r
128    EMAC_WakeupCallback wakeupCb;        /// Callback function to be invoked once several TD have been released\r
129    unsigned short wakeupThreshold; /// Number of free TD before wakeupCb is invoked\r
130    unsigned short head;            /// Circular buffer head pointer incremented by the upper layer (buffer to be sent)\r
131    unsigned short tail;            /// Circular buffer head pointer incremented by the IT handler (buffer sent)\r
132 } TxTd;\r
133 \r
134 //------------------------------------------------------------------------------\r
135 //         Internal variables\r
136 //------------------------------------------------------------------------------\r
137 // Receive Transfer Descriptor buffer\r
138 #ifdef __ICCARM__          // IAR\r
139 #pragma data_alignment=8   // IAR\r
140 #endif                     // IAR\r
141 static volatile RxTd rxTd;\r
142 // Transmit Transfer Descriptor buffer\r
143 #ifdef __ICCARM__          // IAR\r
144 #pragma data_alignment=8   // IAR\r
145 #endif                     // IAR\r
146 static volatile TxTd txTd;\r
147 /// Send Buffer\r
148 // Section 3.6 of AMBA 2.0 spec states that burst should not cross 1K Boundaries.\r
149 // Receive buffer manager writes are burst of 2 words => 3 lsb bits of the address shall be set to 0\r
150 #ifdef __ICCARM__          // IAR\r
151 #pragma data_alignment=8   // IAR\r
152 #endif                     // IAR\r
153 static volatile unsigned char pTxBuffer[TX_BUFFERS * EMAC_TX_UNITSIZE] __attribute__((aligned(8)));\r
154 \r
155 #ifdef __ICCARM__          // IAR\r
156 #pragma data_alignment=8   // IAR\r
157 #endif                     // IAR\r
158 /// Receive Buffer\r
159 static volatile unsigned char pRxBuffer[RX_BUFFERS * EMAC_RX_UNITSIZE] __attribute__((aligned(8)));\r
160 /// Statistics\r
161 static volatile EmacStats EmacStatistics;\r
162 \r
163 //-----------------------------------------------------------------------------\r
164 //         Internal functions\r
165 //-----------------------------------------------------------------------------\r
166 \r
167 //-----------------------------------------------------------------------------\r
168 /// Wait PHY operation complete.\r
169 /// Return 1 if the operation completed successfully.\r
170 /// May be need to re-implemented to reduce CPU load.\r
171 /// \param retry: the retry times, 0 to wait forever until complete.\r
172 //-----------------------------------------------------------------------------\r
173 static unsigned char EMAC_WaitPhy( unsigned int retry )\r
174 {\r
175     unsigned int retry_count = 0;\r
176 \r
177     while((AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE) == 0) {\r
178 \r
179         // Dead LOOP!\r
180         if (retry == 0) {\r
181 \r
182             continue;\r
183         }\r
184 \r
185         // Timeout check\r
186         retry_count++;\r
187         if(retry_count >= retry) {\r
188 \r
189             trace_LOG(trace_ERROR, "E: Wait PHY time out\n\r");\r
190             return 0;\r
191         }\r
192     }\r
193 \r
194     return 1;\r
195 }\r
196 \r
197 //-----------------------------------------------------------------------------\r
198 //         Exported functions\r
199 //-----------------------------------------------------------------------------\r
200 \r
201 //-----------------------------------------------------------------------------\r
202 //          PHY management functions\r
203 //-----------------------------------------------------------------------------\r
204 \r
205 //-----------------------------------------------------------------------------\r
206 /// Set MDC clock according to current board clock. Per 802.3, MDC should be\r
207 /// less then 2.5MHz.\r
208 /// Return 1 if successfully, 0 if MDC clock not found.\r
209 //-----------------------------------------------------------------------------\r
210 unsigned char EMAC_SetMdcClock( unsigned int mck )\r
211 {\r
212     int clock_dividor;\r
213 \r
214     if (mck <= 20000000) {\r
215         clock_dividor = AT91C_EMAC_CLK_HCLK_8;          /// MDC clock = MCK/8\r
216     }\r
217     else if (mck <= 40000000) {\r
218         clock_dividor = AT91C_EMAC_CLK_HCLK_16;         /// MDC clock = MCK/16\r
219     }\r
220     else if (mck <= 80000000) {\r
221         clock_dividor = AT91C_EMAC_CLK_HCLK_32;         /// MDC clock = MCK/32\r
222     }\r
223     else if (mck <= 160000000) {\r
224         clock_dividor = AT91C_EMAC_CLK_HCLK_64;         /// MDC clock = MCK/64\r
225     }\r
226     else {\r
227         trace_LOG(trace_ERROR, "E: No valid MDC clock.\n\r");\r
228         return 0;\r
229     }\r
230     AT91C_BASE_EMAC->EMAC_NCFGR = (AT91C_BASE_EMAC->EMAC_NCFGR & (~AT91C_EMAC_CLK))\r
231                                  | clock_dividor;\r
232     return 1;\r
233 }\r
234 \r
235 //-----------------------------------------------------------------------------\r
236 /// Enable MDI with PHY\r
237 //-----------------------------------------------------------------------------\r
238 void EMAC_EnableMdio( void )\r
239 {\r
240     AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;\r
241 }\r
242 \r
243 //-----------------------------------------------------------------------------\r
244 /// Enable MDI with PHY\r
245 //-----------------------------------------------------------------------------\r
246 void EMAC_DisableMdio( void )\r
247 {\r
248     AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;\r
249 }\r
250 \r
251 //-----------------------------------------------------------------------------\r
252 /// Enable MII mode for EMAC, called once after autonegotiate\r
253 //-----------------------------------------------------------------------------\r
254 void EMAC_EnableMII( void )\r
255 {\r
256     AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;\r
257 }\r
258 \r
259 //-----------------------------------------------------------------------------\r
260 /// Enable RMII mode for EMAC, called once after autonegotiate\r
261 //-----------------------------------------------------------------------------\r
262 void EMAC_EnableRMII( void )\r
263 {\r
264     AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN | AT91C_EMAC_RMII;\r
265 }\r
266 \r
267 //-----------------------------------------------------------------------------\r
268 /// Read PHY register.\r
269 /// Return 1 if successfully, 0 if timeout.\r
270 /// \param PhyAddress PHY Address\r
271 /// \param Address Register Address\r
272 /// \param pValue Pointer to a 32 bit location to store read data\r
273 /// \param retry The retry times, 0 to wait forever until complete.\r
274 //-----------------------------------------------------------------------------\r
275 unsigned char EMAC_ReadPhy(unsigned char PhyAddress,\r
276                            unsigned char Address,\r
277                            unsigned int *pValue,\r
278                            unsigned int retry)\r
279 {\r
280     AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30))\r
281                               | (AT91C_EMAC_CODE & (2 << 16))\r
282                               | (AT91C_EMAC_RW & (2 << 28))\r
283                               | (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23))\r
284                               | (AT91C_EMAC_REGA & (Address << 18));\r
285 \r
286     if ( EMAC_WaitPhy(retry) == 0 ) {\r
287 \r
288         trace_LOG(trace_ERROR, "TimeOut EMAC_ReadPhy\n\r");\r
289         return 0;\r
290     }\r
291     *pValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );\r
292     return 1;\r
293 }\r
294 \r
295 //-----------------------------------------------------------------------------\r
296 /// Write PHY register\r
297 /// Return 1 if successfully, 0 if timeout.\r
298 /// \param PhyAddress PHY Address\r
299 /// \param Address Register Address\r
300 /// \param Value Data to write ( Actually 16 bit data )\r
301 /// \param retry The retry times, 0 to wait forever until complete.\r
302 //-----------------------------------------------------------------------------\r
303 unsigned char EMAC_WritePhy(unsigned char PhyAddress,\r
304                             unsigned char Address,\r
305                             unsigned int  Value,\r
306                             unsigned int  retry)\r
307 {\r
308     AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30))\r
309                               | (AT91C_EMAC_CODE & (2 << 16))\r
310                               | (AT91C_EMAC_RW & (1 << 28))\r
311                               | (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23))\r
312                               | (AT91C_EMAC_REGA & (Address << 18))\r
313                               | (AT91C_EMAC_DATA & Value) ;\r
314     if ( EMAC_WaitPhy(retry) == 0 ) {\r
315 \r
316         trace_LOG(trace_ERROR, "TimeOut EMAC_WritePhy\n\r");\r
317         return 0;\r
318     }\r
319     return 1;\r
320 }\r
321 \r
322 //-----------------------------------------------------------------------------\r
323 /// Setup the EMAC for the link : speed 100M/10M and Full/Half duplex\r
324 /// \param speed        Link speed, 0 for 10M, 1 for 100M\r
325 /// \param fullduplex   1 for Full Duplex mode\r
326 //-----------------------------------------------------------------------------\r
327 void EMAC_SetLinkSpeed(unsigned char speed, unsigned char fullduplex)\r
328 {\r
329     unsigned int ncfgr;\r
330 \r
331     ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR;\r
332     ncfgr &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);\r
333     if (speed) {\r
334 \r
335         ncfgr |= AT91C_EMAC_SPD;\r
336     }\r
337     if (fullduplex) {\r
338 \r
339         ncfgr |= AT91C_EMAC_FD;\r
340     }\r
341     AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr;\r
342 }\r
343 \r
344 \r
345 \r
346 //-----------------------------------------------------------------------------\r
347 //          EMAC functions\r
348 //-----------------------------------------------------------------------------\r
349 \r
350 //-----------------------------------------------------------------------------\r
351 /// EMAC Interrupt handler\r
352 //-----------------------------------------------------------------------------\r
353 void EMAC_Handler(void)\r
354 {\r
355     volatile EmacTxTDescriptor *pTxTd;\r
356     volatile EMAC_TxCallback   *pTxCb;\r
357     unsigned int isr;\r
358     unsigned int rsr;\r
359     unsigned int tsr;\r
360     unsigned int rxStatusFlag;\r
361     unsigned int txStatusFlag;\r
362 \r
363     //trace_LOG(trace_DEBUG, "EMAC_Handler\n\r");\r
364     isr = AT91C_BASE_EMAC->EMAC_ISR & AT91C_BASE_EMAC->EMAC_IMR;\r
365     rsr = AT91C_BASE_EMAC->EMAC_RSR;\r
366     tsr = AT91C_BASE_EMAC->EMAC_TSR;\r
367 \r
368     // RX packet\r
369     if ((isr & AT91C_EMAC_RCOMP) || (rsr & AT91C_EMAC_REC)) {\r
370         rxStatusFlag = AT91C_EMAC_REC;\r
371 \r
372         // Frame received\r
373         EmacStatistics.rx_packets++;\r
374 \r
375         // Check OVR\r
376         if (rsr & AT91C_EMAC_OVR) {\r
377             rxStatusFlag |= AT91C_EMAC_OVR;\r
378             EmacStatistics.rx_ovrs++;\r
379         }\r
380         // Check BNA\r
381         if (rsr & AT91C_EMAC_BNA) {\r
382             rxStatusFlag |= AT91C_EMAC_BNA;\r
383             EmacStatistics.rx_bnas++;\r
384         }\r
385         // Clear status\r
386         AT91C_BASE_EMAC->EMAC_RSR |= rxStatusFlag;\r
387 \r
388         // Invoke callbacks\r
389         if (rxTd.rxCb) {\r
390             rxTd.rxCb(rxStatusFlag);\r
391         }\r
392     }\r
393 \r
394     // TX packet\r
395     if ((isr & AT91C_EMAC_TCOMP) || (tsr & AT91C_EMAC_COMP)) {\r
396 \r
397         txStatusFlag = AT91C_EMAC_COMP;\r
398         EmacStatistics.tx_comp ++;\r
399 \r
400         // A frame transmitted\r
401         // Check RLE\r
402         if (tsr & AT91C_EMAC_RLES) {\r
403             txStatusFlag |= AT91C_EMAC_RLES;\r
404             EmacStatistics.tx_errors++;\r
405         }\r
406         // Check COL\r
407         if (tsr & AT91C_EMAC_COL) {\r
408             txStatusFlag |= AT91C_EMAC_COL;\r
409             EmacStatistics.collisions++;\r
410         }\r
411         // Check BEX\r
412         if (tsr & AT91C_EMAC_BEX) {\r
413             txStatusFlag |= AT91C_EMAC_BEX;\r
414             EmacStatistics.tx_exausts++;\r
415         }\r
416         // Check UND\r
417         if (tsr & AT91C_EMAC_UND) {\r
418             txStatusFlag |= AT91C_EMAC_UND;\r
419             EmacStatistics.tx_underruns++;\r
420         }\r
421         // Clear status\r
422         AT91C_BASE_EMAC->EMAC_TSR |= txStatusFlag;\r
423 \r
424         // Sanity check: Tx buffers have to be scheduled\r
425         ASSERT(!CIRC_EMPTY(&txTd),\r
426             "-F- EMAC Tx interrupt received meanwhile no TX buffers has been scheduled\n\r");\r
427 \r
428         // Check the buffers\r
429         while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS)) {\r
430             pTxTd = txTd.td + txTd.tail;\r
431             pTxCb = txTd.txCb + txTd.tail;\r
432 \r
433             // Exit if buffer has not been sent yet\r
434             if ((pTxTd->status & EMAC_TX_USED_BIT) == 0) {\r
435                 break;\r
436             }\r
437 \r
438             // Notify upper layer that packet has been sent\r
439             if (*pTxCb) {\r
440                 (*pTxCb)(txStatusFlag);\r
441             }\r
442 \r
443             CIRC_INC( txTd.tail, TX_BUFFERS );\r
444         }\r
445 \r
446         // If a wakeup has been scheduled, notify upper layer that it can send\r
447         // other packets, send will be successfull.\r
448         if( (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) >= txTd.wakeupThreshold)\r
449          &&  txTd.wakeupCb) {\r
450             txTd.wakeupCb();\r
451         }\r
452     }\r
453 }\r
454 \r
455 //-----------------------------------------------------------------------------\r
456 /// Initialize the EMAC with the emac controller address\r
457 /// \param id     HW ID for power management\r
458 /// \param pTxWakeUpfct Thresold TX Wakeup Callback\r
459 /// \param pRxfct       RX Wakeup Callback\r
460 /// \param pMacAddress  Mac Address\r
461 /// \param enableCAF    enable AT91C_EMAC_CAF if needed by application\r
462 /// \param enableNBC    AT91C_EMAC_NBC if needed by application\r
463 //-----------------------------------------------------------------------------\r
464 void EMAC_Init( unsigned char id, const unsigned char *pMacAddress,\r
465                 unsigned char enableCAF, unsigned char enableNBC )\r
466 {\r
467     int Index;\r
468     unsigned int Address;\r
469 \r
470     // Check parameters\r
471     ASSERT(RX_BUFFERS * EMAC_RX_UNITSIZE > EMAC_FRAME_LENTGH_MAX,\r
472            "E: RX buffers too small\n\r");\r
473 \r
474     trace_LOG(trace_DEBUG, "EMAC_Init\n\r");\r
475 \r
476     // Power ON\r
477     AT91C_BASE_PMC->PMC_PCER = 1 << id;\r
478 \r
479     // Disable TX & RX and more\r
480     AT91C_BASE_EMAC->EMAC_NCR = 0;\r
481 \r
482     // disable\r
483     AT91C_BASE_EMAC->EMAC_IDR = ~0;\r
484 \r
485     rxTd.idx = 0;\r
486     CIRC_CLEAR(&txTd);\r
487 \r
488     // Setup the RX descriptors.\r
489     for(Index = 0; Index < RX_BUFFERS; Index++) {\r
490 \r
491         Address = (unsigned int)(&(pRxBuffer[Index * EMAC_RX_UNITSIZE]));\r
492         // Remove EMAC_RX_OWNERSHIP_BIT and EMAC_RX_WRAP_BIT\r
493         rxTd.td[Index].addr = Address & EMAC_ADDRESS_MASK;\r
494         rxTd.td[Index].status = 0;\r
495     }\r
496     rxTd.td[RX_BUFFERS - 1].addr |= EMAC_RX_WRAP_BIT;\r
497 \r
498     // Setup the TX descriptors.\r
499     for(Index = 0; Index < TX_BUFFERS; Index++) {\r
500 \r
501         Address = (unsigned int)(&(pTxBuffer[Index * EMAC_TX_UNITSIZE]));\r
502         txTd.td[Index].addr = Address;\r
503         txTd.td[Index].status = EMAC_TX_USED_BIT;\r
504     }\r
505     txTd.td[TX_BUFFERS - 1].status = EMAC_TX_USED_BIT | EMAC_TX_WRAP_BIT;\r
506 \r
507     // Set the MAC address\r
508     if( pMacAddress != (unsigned char *)0 ) {\r
509         AT91C_BASE_EMAC->EMAC_SA1L = ( ((unsigned int)pMacAddress[3] << 24)\r
510                                      | ((unsigned int)pMacAddress[2] << 16)\r
511                                      | ((unsigned int)pMacAddress[1] << 8 )\r
512                                      |                pMacAddress[0] );\r
513 \r
514         AT91C_BASE_EMAC->EMAC_SA1H = ( ((unsigned int)pMacAddress[5] << 8 )\r
515                                      |                pMacAddress[4] );\r
516     }\r
517     // Now setup the descriptors\r
518     // Receive Buffer Queue Pointer Register\r
519     AT91C_BASE_EMAC->EMAC_RBQP = (unsigned int) (rxTd.td);\r
520     // Transmit Buffer Queue Pointer Register\r
521     AT91C_BASE_EMAC->EMAC_TBQP = (unsigned int) (txTd.td);\r
522 \r
523     AT91C_BASE_EMAC->EMAC_NCR = AT91C_EMAC_CLRSTAT;\r
524 \r
525     // Clear all status bits in the receive status register.\r
526     AT91C_BASE_EMAC->EMAC_RSR = (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);\r
527 \r
528     // Clear all status bits in the transmit status register\r
529     AT91C_BASE_EMAC->EMAC_TSR = ( AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES\r
530                                 | AT91C_EMAC_BEX | AT91C_EMAC_COMP\r
531                                 | AT91C_EMAC_UND );\r
532 \r
533     // Clear interrupts\r
534     AT91C_BASE_EMAC->EMAC_ISR;\r
535 \r
536     // Enable the copy of data into the buffers\r
537     // ignore broadcasts, and don't copy FCS.\r
538     AT91C_BASE_EMAC->EMAC_NCFGR |= (AT91C_EMAC_DRFCS | AT91C_EMAC_PAE);\r
539 \r
540     if( enableCAF == EMAC_CAF_ENABLE ) {\r
541         AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CAF;\r
542     }\r
543     if( enableNBC == EMAC_NBC_ENABLE ) {\r
544         AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_NBC;\r
545     }\r
546 \r
547     // Enable Rx and Tx, plus the stats register.\r
548     AT91C_BASE_EMAC->EMAC_NCR |= (AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT);\r
549 \r
550     // Setup the interrupts for TX (and errors)\r
551     AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RXUBR\r
552                               | AT91C_EMAC_TUNDR\r
553                               | AT91C_EMAC_RLEX\r
554                               | AT91C_EMAC_TXERR\r
555                               | AT91C_EMAC_TCOMP\r
556                               | AT91C_EMAC_ROVR\r
557                               | AT91C_EMAC_HRESP;\r
558 \r
559 }\r
560 \r
561 //-----------------------------------------------------------------------------\r
562 /// Get the statstic information & reset it\r
563 /// \param pStats   Pointer to EmacStats structure to copy the informations\r
564 /// \param reset    Reset the statistics after copy it\r
565 //-----------------------------------------------------------------------------\r
566 void EMAC_GetStatistics(EmacStats *pStats, unsigned char reset)\r
567 {\r
568     unsigned int ncrBackup = 0;\r
569 \r
570     trace_LOG(trace_DEBUG, "EMAC_GetStatistics\n\r");\r
571 \r
572     // Sanity check\r
573     if (pStats == (EmacStats *) 0) {\r
574         return;\r
575     }\r
576 \r
577     ncrBackup = AT91C_BASE_EMAC->EMAC_NCR & (AT91C_EMAC_TE | AT91C_EMAC_RE);\r
578 \r
579     // Disable TX/RX\r
580     AT91C_BASE_EMAC->EMAC_NCR = ncrBackup & ~(AT91C_EMAC_TE | AT91C_EMAC_RE);\r
581 \r
582     // Copy the informations\r
583     memcpy(pStats, (void*)&EmacStatistics, sizeof(EmacStats));\r
584 \r
585     // Reset the statistics\r
586     if (reset) {\r
587         memset((void*)&EmacStatistics, 0x00, sizeof(EmacStats));\r
588         AT91C_BASE_EMAC->EMAC_NCR = ncrBackup | AT91C_EMAC_CLRSTAT;\r
589     }\r
590 \r
591     // restore NCR\r
592     AT91C_BASE_EMAC->EMAC_NCR = ncrBackup;\r
593 }\r
594 \r
595 //-----------------------------------------------------------------------------\r
596 /// Send a packet with EMAC.\r
597 /// If the packet size is larger than transfer buffer size error returned.\r
598 /// \param buffer   The buffer to be send\r
599 /// \param size     The size of buffer to be send\r
600 /// \param fEMAC_TxCallback Threshold Wakeup callback\r
601 /// \param fWakeUpCb   TX Wakeup\r
602 /// \return         OK, Busy or invalid packet\r
603 //-----------------------------------------------------------------------------\r
604 unsigned char EMAC_Send(void *pBuffer,\r
605                         unsigned int size,\r
606                         EMAC_TxCallback fEMAC_TxCallback)\r
607 {\r
608     volatile EmacTxTDescriptor *pTxTd;\r
609     volatile EMAC_TxCallback   *pTxCb;\r
610 \r
611     //trace_LOG(trace_DEBUG, "EMAC_Send\n\r");\r
612 \r
613     // Check parameter\r
614     if (size > EMAC_TX_UNITSIZE) {\r
615 \r
616         trace_LOG(trace_ERROR, "-E- EMAC driver does not split send packets.");\r
617         trace_LOG(trace_ERROR, " It can send %d bytes max in one packet (%u bytes requested)\n\r",\r
618             EMAC_TX_UNITSIZE, size);\r
619         return EMAC_TX_INVALID_PACKET;\r
620     }\r
621 \r
622     // If no free TxTd, buffer can't be sent, schedule the wakeup callback\r
623     if( CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) == 0) {\r
624         return EMAC_TX_BUFFER_BUSY;\r
625 \r
626     }\r
627 \r
628     // Pointers to the current TxTd\r
629     pTxTd = txTd.td + txTd.head;\r
630     pTxCb = txTd.txCb + txTd.head;\r
631 \r
632     // Sanity check\r
633     ASSERT((pTxTd->status & EMAC_TX_USED_BIT) != 0,\r
634         "-F- Buffer is still under EMAC control\n\r");\r
635 \r
636     // Setup/Copy data to transmition buffer\r
637     if (pBuffer && size) {\r
638         // Driver manage the ring buffer\r
639         memcpy((void *)pTxTd->addr, pBuffer, size);\r
640     }\r
641 \r
642     // Tx Callback\r
643     *pTxCb = fEMAC_TxCallback;\r
644 \r
645     // Update TD status\r
646     // The buffer size defined is length of ethernet frame\r
647     // so it's always the last buffer of the frame.\r
648     if (txTd.head == TX_BUFFERS-1) {\r
649         pTxTd->status =\r
650             (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT | EMAC_TX_WRAP_BIT;\r
651     }\r
652     else {\r
653         pTxTd->status = (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT;\r
654     }\r
655 \r
656     CIRC_INC(txTd.head, TX_BUFFERS)\r
657 \r
658     // Tx packets count\r
659     EmacStatistics.tx_packets++;\r
660 \r
661     // Now start to transmit if it is not already done\r
662     AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;\r
663 \r
664     return EMAC_TX_OK;\r
665 }\r
666 \r
667 //-----------------------------------------------------------------------------\r
668 /// Receive a packet with EMAC\r
669 /// If not enough buffer for the packet, the remaining data is lost but right\r
670 /// frame length is returned.\r
671 /// \param pFrame           Buffer to store the frame\r
672 /// \param frameSize        Size of the frame\r
673 /// \param pRcvSize         Received size\r
674 /// \return                 OK, no data, or frame too small\r
675 //-----------------------------------------------------------------------------\r
676 unsigned char EMAC_Poll(unsigned char *pFrame,\r
677                         unsigned int frameSize,\r
678                         unsigned int *pRcvSize)\r
679 {\r
680     unsigned short bufferLength;\r
681     unsigned int   tmpFrameSize=0;\r
682     unsigned char  *pTmpFrame=0;\r
683     unsigned int   tmpIdx = rxTd.idx;\r
684     volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx;\r
685 \r
686     ASSERT(pFrame, "F: EMAC_Poll\n\r");\r
687 \r
688     char isFrame = 0;\r
689     // Set the default return value\r
690     *pRcvSize = 0;\r
691 \r
692     // Process received RxTd\r
693     while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT) {\r
694 \r
695         // A start of frame has been received, discard previous fragments\r
696         if ((pRxTd->status & EMAC_RX_SOF_BIT) == EMAC_RX_SOF_BIT) {\r
697             // Skip previous fragment\r
698             while (tmpIdx != rxTd.idx) {\r
699                 pRxTd = rxTd.td + rxTd.idx;\r
700                 pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);\r
701                 CIRC_INC(rxTd.idx, RX_BUFFERS);\r
702             }\r
703             // Reset the temporary frame pointer\r
704             pTmpFrame = pFrame;\r
705             tmpFrameSize = 0;\r
706             // Start to gather buffers in a frame\r
707             isFrame = 1;\r
708         }\r
709 \r
710         // Increment the pointer\r
711         CIRC_INC(tmpIdx, RX_BUFFERS);\r
712 \r
713         // Copy data in the frame buffer\r
714         if (isFrame) {\r
715             if (tmpIdx == rxTd.idx) {\r
716                 trace_LOG(trace_INFO,\r
717                     "I: no EOF (Invalid of buffers too small)\n\r");\r
718 \r
719                 do {\r
720 \r
721                     pRxTd = rxTd.td + rxTd.idx;\r
722                     pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);\r
723                     CIRC_INC(rxTd.idx, RX_BUFFERS);\r
724                 } while(tmpIdx != rxTd.idx);\r
725                 return EMAC_RX_NO_DATA;\r
726             }\r
727             // Copy the buffer into the application frame\r
728             bufferLength = EMAC_RX_UNITSIZE;\r
729             if ((tmpFrameSize + bufferLength) > frameSize) {\r
730                 bufferLength = frameSize - tmpFrameSize;\r
731             }\r
732 \r
733             memcpy(pTmpFrame, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), bufferLength);\r
734             pTmpFrame += bufferLength;\r
735             tmpFrameSize += bufferLength;\r
736 \r
737             // An end of frame has been received, return the data\r
738             if ((pRxTd->status & EMAC_RX_EOF_BIT) == EMAC_RX_EOF_BIT) {\r
739                 // Frame size from the EMAC\r
740                 *pRcvSize = (pRxTd->status & EMAC_LENGTH_FRAME);\r
741 \r
742                 // Application frame buffer is too small all data have not been copied\r
743                 if (tmpFrameSize < *pRcvSize) {\r
744                     printf("size req %u size allocated %u\n\r", *pRcvSize, frameSize);\r
745 \r
746                     return EMAC_RX_FRAME_SIZE_TOO_SMALL;\r
747                 }\r
748 \r
749                 trace_LOG(trace_INFO, "packet %d-%u (%u)\n\r", rxTd.idx, tmpIdx, *pRcvSize);\r
750                 // All data have been copied in the application frame buffer => release TD\r
751                 while (rxTd.idx != tmpIdx) {\r
752                     pRxTd = rxTd.td + rxTd.idx;\r
753                     pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);\r
754                     CIRC_INC(rxTd.idx, RX_BUFFERS);\r
755                 }\r
756                 EmacStatistics.rx_packets++;\r
757                 return EMAC_RX_OK;\r
758             }\r
759         }\r
760 \r
761         // SOF has not been detected, skip the fragment\r
762         else {\r
763            pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);\r
764            rxTd.idx = tmpIdx;\r
765         }\r
766 \r
767         // Process the next buffer\r
768         pRxTd = rxTd.td + tmpIdx;\r
769     }\r
770 \r
771     //trace_LOG(trace_DEBUG, "E");\r
772     return EMAC_RX_NO_DATA;\r
773 }\r
774 \r
775 //-----------------------------------------------------------------------------\r
776 /// Registers pRxCb callback. Callback will be invoked after the next received\r
777 /// frame.\r
778 /// When EMAC_Poll() returns EMAC_RX_NO_DATA the application task call EMAC_Set_RxCb()\r
779 /// to register pRxCb() callback and enters suspend state. The callback is in charge\r
780 /// to resume the task once a new frame has been received. The next time EMAC_Poll()\r
781 /// is called, it will be successfull.\r
782 /// \param pRxCb            Pointer to callback function\r
783 //-----------------------------------------------------------------------------\r
784 void EMAC_Set_RxCb(EMAC_RxCallback pRxCb)\r
785 {\r
786     rxTd.rxCb = pRxCb;\r
787     AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP;\r
788 }\r
789 \r
790 //-----------------------------------------------------------------------------\r
791 /// Remove the RX callback function.\r
792 /// This function is usually invoked from the RX callback itself. Once the callback\r
793 /// has resumed the application task, there is no need to invoke the callback again.\r
794 //-----------------------------------------------------------------------------\r
795 void EMAC_Clear_RxCb(void)\r
796 {\r
797     AT91C_BASE_EMAC->EMAC_IDR = AT91C_EMAC_RCOMP;\r
798     rxTd.rxCb = (EMAC_RxCallback) 0;\r
799 }\r
800 \r
801 //-----------------------------------------------------------------------------\r
802 /// Registers TX wakeup callback callback. Callback will be invoked once several\r
803 /// transfer descriptors are available.\r
804 /// When EMAC_Send() returns EMAC_TX_BUFFER_BUSY (all TD busy) the application\r
805 /// task calls EMAC_Set_TxWakeUpCb() to register pTxWakeUpCb() callback and\r
806 /// enters suspend state. The callback is in charge to resume the task once\r
807 /// several TD have been released. The next time EMAC_Send() will be called, it\r
808 /// shall be successfull.\r
809 /// \param pTxWakeUpCb   Pointer to callback function\r
810 /// \param threshold     Minimum number of available transfer descriptors before pTxWakeUpCb() is invoked\r
811 /// \return              0= success, 1 = threshold exceeds nuber of transfer descriptors\r
812 //-----------------------------------------------------------------------------\r
813 char EMAC_Set_TxWakeUpCb(EMAC_WakeupCallback pTxWakeUpCb, unsigned short threshold)\r
814 {\r
815     if (threshold <= TX_BUFFERS) {\r
816         txTd.wakeupCb = pTxWakeUpCb;\r
817         txTd.wakeupThreshold = threshold;\r
818         return 0;\r
819     }\r
820     return 1;\r
821 }\r
822 \r
823 //-----------------------------------------------------------------------------\r
824 /// Remove the TX wakeup callback function.\r
825 /// This function is usually invoked from the TX wakeup callback itself. Once the callback\r
826 /// has resumed the application task, there is no need to invoke the callback again.\r
827 //-----------------------------------------------------------------------------\r
828 void EMAC_Clear_TxWakeUpCb(void)\r
829 {\r
830     txTd.wakeupCb = (EMAC_WakeupCallback) 0;\r
831 }\r
832 \r
833 \r