OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [CORTEX_AT91SAM3U256_IAR/] [AT91Lib/] [peripherals/] [emac/] [emac.c] - Blame information for rev 580

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.