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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [lwIP_Demo_Rowley_ARM7/] [EMAC/] [SAM7_EMAC.c] - Blame information for rev 609

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 583 jeremybenn
/*
2
    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
3
 
4
    ***************************************************************************
5
    *                                                                         *
6
    * If you are:                                                             *
7
    *                                                                         *
8
    *    + New to FreeRTOS,                                                   *
9
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
10
    *    + Looking for basic training,                                        *
11
    *    + Wanting to improve your FreeRTOS skills and productivity           *
12
    *                                                                         *
13
    * then take a look at the FreeRTOS books - available as PDF or paperback  *
14
    *                                                                         *
15
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
16
    *                  http://www.FreeRTOS.org/Documentation                  *
17
    *                                                                         *
18
    * A pdf reference manual is also available.  Both are usually delivered   *
19
    * to your inbox within 20 minutes to two hours when purchased between 8am *
20
    * and 8pm GMT (although please allow up to 24 hours in case of            *
21
    * exceptional circumstances).  Thank you for your support!                *
22
    *                                                                         *
23
    ***************************************************************************
24
 
25
    This file is part of the FreeRTOS distribution.
26
 
27
    FreeRTOS is free software; you can redistribute it and/or modify it under
28
    the terms of the GNU General Public License (version 2) as published by the
29
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30
    ***NOTE*** The exception to the GPL is included to allow you to distribute
31
    a combined work that includes FreeRTOS without being obliged to provide the
32
    source code for proprietary components outside of the FreeRTOS kernel.
33
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
36
    more details. You should have received a copy of the GNU General Public
37
    License and the FreeRTOS license exception along with FreeRTOS; if not it
38
    can be viewed here: http://www.freertos.org/a00114.html and also obtained
39
    by writing to Richard Barry, contact details for whom are available on the
40
    FreeRTOS WEB site.
41
 
42
    1 tab == 4 spaces!
43
 
44
    http://www.FreeRTOS.org - Documentation, latest information, license and
45
    contact details.
46
 
47
    http://www.SafeRTOS.com - A version that is certified for use in safety
48
    critical systems.
49
 
50
    http://www.OpenRTOS.com - Commercial support, development, porting,
51
    licensing and training services.
52
*/
53
 
54
/*
55
 * Interrupt driven driver for the EMAC peripheral.  This driver is not
56
 * reentrant, re-entrancy is handled by a semaphore at the network interface
57
 * level.
58
 */
59
 
60
 
61
/*
62
Changes from V3.2.2
63
 
64
        + Corrected the byte order when writing the MAC address to the MAC.
65
        + Support added for MII interfaces.  Previously only RMII was supported.
66
 
67
Changes from V3.2.3
68
 
69
        + The MII interface is now the default.
70
        + Modified the initialisation sequence slightly to allow auto init more
71
          time to complete.
72
 
73
Changes from V4.0.1
74
 
75
        + Made the function vClearEMACTxBuffer() more robust by moving the index
76
          manipulation into the if() statement.  This allows the tx interrupt to
77
          execute even when there is no data to handle.
78
 
79
Changes from V4.0.4
80
 
81
        + Corrected the Rx frame length mask when obtaining the length from the
82
          rx descriptor.
83
*/
84
 
85
 
86
/* Standard includes. */
87
#include <string.h>
88
 
89
/* Scheduler includes. */
90
#include "FreeRTOS.h"
91
#include "semphr.h"
92
#include "task.h"
93
 
94
/* Demo app includes. */
95
#include "SAM7_EMAC.h"
96
 
97
/* Hardware specific includes. */
98
#include "Emac.h"
99
#include "mii.h"
100
#include "AT91SAM7X256.h"
101
 
102
 
103
/* USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0
104
to use an MII interface. */
105
#define USE_RMII_INTERFACE 0
106
 
107
 
108
/* The buffer addresses written into the descriptors must be aligned so the
109
last few bits are zero.  These bits have special meaning for the EMAC
110
peripheral and cannot be used as part of the address. */
111
#define emacADDRESS_MASK                        ( ( unsigned long ) 0xFFFFFFFC )
112
 
113
/* Bit used within the address stored in the descriptor to mark the last
114
descriptor in the array. */
115
#define emacRX_WRAP_BIT                         ( ( unsigned long ) 0x02 )
116
 
117
/* Bit used within the Tx descriptor status to indicate whether the
118
descriptor is under the control of the EMAC or the software. */
119
#define emacTX_BUF_USED                         ( ( unsigned long ) 0x80000000 )
120
 
121
/* A short delay is used to wait for a buffer to become available, should
122
one not be immediately available when trying to transmit a frame. */
123
#define emacBUFFER_WAIT_DELAY           ( 2 )
124
#define emacMAX_WAIT_CYCLES                     ( ( portBASE_TYPE ) ( configTICK_RATE_HZ / 40 ) )
125
 
126
/* The time to block waiting for input. */
127
#define emacBLOCK_TIME_WAITING_FOR_INPUT        ( ( portTickType ) 100 )
128
 
129
/* Peripheral setup for the EMAC. */
130
#define emacPERIPHERAL_A_SETUP          ( ( unsigned long ) AT91C_PB2_ETX0                      ) | \
131
                                                                        ( ( unsigned long ) AT91C_PB12_ETXER            ) | \
132
                                                                        ( ( unsigned long ) AT91C_PB16_ECOL                     ) | \
133
                                                                        ( ( unsigned long ) AT91C_PB11_ETX3                     ) | \
134
                                                                        ( ( unsigned long ) AT91C_PB6_ERX1                      ) | \
135
                                                                        ( ( unsigned long ) AT91C_PB15_ERXDV            ) | \
136
                                                                        ( ( unsigned long ) AT91C_PB13_ERX2                     ) | \
137
                                                                        ( ( unsigned long ) AT91C_PB3_ETX1                      ) | \
138
                                                                        ( ( unsigned long ) AT91C_PB8_EMDC                      ) | \
139
                                                                        ( ( unsigned long ) AT91C_PB5_ERX0                      ) | \
140
                                                                        ( ( unsigned long ) AT91C_PB14_ERX3                     ) | \
141
                                                                        ( ( unsigned long ) AT91C_PB4_ECRS_ECRSDV       ) | \
142
                                                                        ( ( unsigned long ) AT91C_PB1_ETXEN                     ) | \
143
                                                                        ( ( unsigned long ) AT91C_PB10_ETX2                     ) | \
144
                                                                        ( ( unsigned long ) AT91C_PB0_ETXCK_EREFCK      ) | \
145
                                                                        ( ( unsigned long ) AT91C_PB9_EMDIO                     ) | \
146
                                                                        ( ( unsigned long ) AT91C_PB7_ERXER                     ) | \
147
                                                                        ( ( unsigned long ) AT91C_PB17_ERXCK            );
148
 
149
/* Misc defines. */
150
#define emacINTERRUPT_LEVEL                     ( 5 )
151
#define emacNO_DELAY                            ( 0 )
152
#define emacTOTAL_FRAME_HEADER_SIZE     ( 54 )
153
#define emacPHY_INIT_DELAY                      ( 5000 / portTICK_RATE_MS )
154
#define emacRESET_KEY                           ( ( unsigned long ) 0xA5000000 )
155
#define emacRESET_LENGTH                        ( ( unsigned long ) ( 0x01 << 8 ) )
156
 
157
/* The Atmel header file only defines the TX frame length mask. */
158
#define emacRX_LENGTH_FRAME                     ( 0xfff )
159
 
160
/*-----------------------------------------------------------*/
161
 
162
/* Buffer written to by the EMAC DMA.  Must be aligned as described by the
163
comment above the emacADDRESS_MASK definition. */
164
static volatile char pcRxBuffer[ NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
165
 
166
/* Buffer read by the EMAC DMA.  Must be aligned as described by the comment
167
above the emacADDRESS_MASK definition. */
168
static char pcTxBuffer[ NB_TX_BUFFERS * ETH_TX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
169
 
170
/* Descriptors used to communicate between the program and the EMAC peripheral.
171
These descriptors hold the locations and state of the Rx and Tx buffers. */
172
static volatile AT91S_TxTdDescriptor xTxDescriptors[ NB_TX_BUFFERS ];
173
static volatile AT91S_RxTdDescriptor xRxDescriptors[ NB_RX_BUFFERS ];
174
 
175
/* The IP and Ethernet addresses are read from the header files. */
176
const char cMACAddress[ 6 ] = { emacETHADDR0, emacETHADDR1, emacETHADDR2, emacETHADDR3, emacETHADDR4, emacETHADDR5 };
177
const unsigned char ucIPAddress[ 4 ]  = { emacIPADDR0, emacIPADDR1, emacIPADDR2, emacIPADDR3 };
178
 
179
/*-----------------------------------------------------------*/
180
 
181
/* See the header file for descriptions of public functions. */
182
 
183
/*
184
 * Prototype for the EMAC interrupt function.
185
 */
186
void vEMACISR_Wrapper( void ) __attribute__ ((naked));
187
 
188
/*
189
 * Initialise both the Tx and Rx descriptors used by the EMAC.
190
 */
191
static void prvSetupDescriptors(void);
192
 
193
/*
194
 * Write our MAC address into the EMAC.
195
 */
196
static void prvSetupMACAddress( void );
197
 
198
/*
199
 * Configure the EMAC and AIC for EMAC interrupts.
200
 */
201
static void prvSetupEMACInterrupt( void );
202
 
203
/*
204
 * Some initialisation functions taken from the Atmel EMAC sample code.
205
 */
206
static void vReadPHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long *pulValue );
207
static portBASE_TYPE xGetLinkSpeed( void );
208
static portBASE_TYPE prvProbePHY( void );
209
#if USE_RMII_INTERFACE != 1
210
        static void vWritePHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long ulValue);
211
#endif
212
 
213
 
214
/* The semaphore used by the EMAC ISR to wake the EMAC task. */
215
static xSemaphoreHandle xSemaphore = NULL;
216
 
217
/* Holds the index to the next buffer from which data will be read. */
218
static volatile unsigned long ulNextRxBuffer = 0;
219
 
220
/*-----------------------------------------------------------*/
221
 
222
/* See the header file for descriptions of public functions. */
223
long lEMACSend( char *pcFrom, unsigned long ulLength, long lEndOfFrame )
224
{
225
static unsigned portBASE_TYPE uxTxBufferIndex = 0;
226
portBASE_TYPE xWaitCycles = 0;
227
long lReturn = pdPASS;
228
char *pcBuffer;
229
unsigned long ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend;
230
 
231
        /* If the length of data to be transmitted is greater than each individual
232
        transmit buffer then the data will be split into more than one buffer.
233
        Loop until the entire length has been buffered. */
234
        while( ulDataBuffered < ulLength )
235
        {
236
                /* Is a buffer available? */
237
                while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AT91C_TRANSMIT_OK ) )
238
                {
239
                        /* There is no room to write the Tx data to the Tx buffer.  Wait a
240
                        short while, then try again. */
241
                        xWaitCycles++;
242
                        if( xWaitCycles > emacMAX_WAIT_CYCLES )
243
                        {
244
                                /* Give up. */
245
                                lReturn = pdFAIL;
246
                                break;
247
                        }
248
                        else
249
                        {
250
                                vTaskDelay( emacBUFFER_WAIT_DELAY );
251
                        }
252
                }
253
 
254
                /* lReturn will only be pdPASS if a buffer is available. */
255
                if( lReturn == pdPASS )
256
                {
257
                        portENTER_CRITICAL();
258
                        {
259
                                /* Get the address of the buffer from the descriptor, then copy
260
                                the data into the buffer. */
261
                                pcBuffer = ( char * ) xTxDescriptors[ uxTxBufferIndex ].addr;
262
 
263
                                /* How much can we write to the buffer? */
264
                                ulDataRemainingToSend = ulLength - ulDataBuffered;
265
                                if( ulDataRemainingToSend <= ETH_TX_BUFFER_SIZE )
266
                                {
267
                                        /* We can write all the remaining bytes. */
268
                                        ulLengthToSend = ulDataRemainingToSend;
269
                                }
270
                                else
271
                                {
272
                                        /* We can not write more than ETH_TX_BUFFER_SIZE in one go. */
273
                                        ulLengthToSend = ETH_TX_BUFFER_SIZE;
274
                                }
275
 
276
                                /* Copy the data into the buffer. */
277
                                memcpy( ( void * ) pcBuffer, ( void * ) &( pcFrom[ ulDataBuffered ] ), ulLengthToSend );
278
                                ulDataBuffered += ulLengthToSend;
279
 
280
                                /* Is this the last data for the frame? */
281
                                if( lEndOfFrame && ( ulDataBuffered >= ulLength ) )
282
                                {
283
                                        /* No more data remains for this frame so we can start the
284
                                        transmission. */
285
                                        ulLastBuffer = AT91C_LAST_BUFFER;
286
                                }
287
                                else
288
                                {
289
                                        /* More data to come for this frame. */
290
                                        ulLastBuffer = 0;
291
                                }
292
 
293
                                /* Fill out the necessary in the descriptor to get the data sent,
294
                                then move to the next descriptor, wrapping if necessary. */
295
                                if( uxTxBufferIndex >= ( NB_TX_BUFFERS - 1 ) )
296
                                {
297
                                        xTxDescriptors[ uxTxBufferIndex ].U_Status.status =     ( ulLengthToSend & ( unsigned long ) AT91C_LENGTH_FRAME )
298
                                                                                                                                                        | ulLastBuffer
299
                                                                                                                                                        | AT91C_TRANSMIT_WRAP;
300
                                        uxTxBufferIndex = 0;
301
                                }
302
                                else
303
                                {
304
                                        xTxDescriptors[ uxTxBufferIndex ].U_Status.status =     ( ulLengthToSend & ( unsigned long ) AT91C_LENGTH_FRAME )
305
                                                                                                                                                        | ulLastBuffer;
306
                                        uxTxBufferIndex++;
307
                                }
308
 
309
                                /* If this is the last buffer to be sent for this frame we can
310
                                start the transmission. */
311
                                if( ulLastBuffer )
312
                                {
313
                                        AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
314
                                }
315
                        }
316
                        portEXIT_CRITICAL();
317
                }
318
                else
319
                {
320
                        break;
321
                }
322
        }
323
 
324
        return lReturn;
325
}
326
/*-----------------------------------------------------------*/
327
 
328
/* See the header file for descriptions of public functions. */
329
unsigned long ulEMACInputLength( void )
330
{
331
register unsigned long ulIndex, ulLength = 0;
332
 
333
        /* Skip any fragments.  We are looking for the first buffer that contains
334
        data and has the SOF (start of frame) bit set. */
335
        while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_SOF ) )
336
        {
337
                /* Ignoring this buffer.  Mark it as free again. */
338
                xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
339
                ulNextRxBuffer++;
340
                if( ulNextRxBuffer >= NB_RX_BUFFERS )
341
                {
342
                        ulNextRxBuffer = 0;
343
                }
344
        }
345
 
346
        /* We are going to walk through the descriptors that make up this frame,
347
        but don't want to alter ulNextRxBuffer as this would prevent vEMACRead()
348
        from finding the data.  Therefore use a copy of ulNextRxBuffer instead. */
349
        ulIndex = ulNextRxBuffer;
350
 
351
        /* Walk through the descriptors until we find the last buffer for this
352
        frame.  The last buffer will give us the length of the entire frame. */
353
        while( ( xRxDescriptors[ ulIndex ].addr & AT91C_OWNERSHIP_BIT ) && !ulLength )
354
        {
355
                ulLength = xRxDescriptors[ ulIndex ].U_Status.status & emacRX_LENGTH_FRAME;
356
 
357
                /* Increment to the next buffer, wrapping if necessary. */
358
                ulIndex++;
359
                if( ulIndex >= NB_RX_BUFFERS )
360
                {
361
                        ulIndex = 0;
362
                }
363
        }
364
 
365
        return ulLength;
366
}
367
/*-----------------------------------------------------------*/
368
 
369
/* See the header file for descriptions of public functions. */
370
void vEMACRead( char *pcTo, unsigned long ulSectionLength, unsigned long ulTotalFrameLength )
371
{
372
static unsigned long ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFameBytesReadSoFar = 0;
373
static char *pcSource;
374
register unsigned long ulBytesRemainingInBuffer, ulRemainingSectionBytes;
375
 
376
        /* Read ulSectionLength bytes from the Rx buffers.  This is not necessarily any
377
        correspondence between the length of our Rx buffers, and the length of the
378
        data we are returning or the length of the data being requested.  Therefore,
379
        between calls  we have to remember not only which buffer we are currently
380
        processing, but our position within that buffer.  This would be greatly
381
        simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater than
382
        the size of each Rx buffer, and that memory fragmentation did not occur.
383
 
384
        This function should only be called after a call to ulEMACInputLength().
385
        This will ensure ulNextRxBuffer is set to the correct buffer. */
386
 
387
 
388
 
389
        /* vEMACRead is called with pcTo set to NULL to indicate that we are about
390
        to read a new frame.  Any fragments remaining in the frame we were
391
        processing during the last call should be dropped. */
392
        if( pcTo == NULL )
393
        {
394
                /* How many bytes are indicated as being in this buffer?  If none then
395
                the buffer is completely full and the frame is contained within more
396
                than one buffer. */
397
 
398
                /* Reset our state variables ready for the next read from this buffer. */
399
        pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
400
        ulFameBytesReadSoFar = ( unsigned long ) 0;
401
                ulBufferPosition = ( unsigned long ) 0;
402
        }
403
        else
404
        {
405
                /* Loop until we have obtained the required amount of data. */
406
        ulSectionBytesReadSoFar = 0;
407
                while( ulSectionBytesReadSoFar < ulSectionLength )
408
                {
409
                        /* We may have already read some data from this buffer.  How much
410
                        data remains in the buffer? */
411
                        ulBytesRemainingInBuffer = ( ETH_RX_BUFFER_SIZE - ulBufferPosition );
412
 
413
                        /* How many more bytes do we need to read before we have the
414
                        required amount of data? */
415
            ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar;
416
 
417
                        /* Do we want more data than remains in the buffer? */
418
                        if( ulRemainingSectionBytes > ulBytesRemainingInBuffer )
419
                        {
420
                                /* We want more data than remains in the buffer so we can
421
                                write the remains of the buffer to the destination, then move
422
                                onto the next buffer to get the rest. */
423
                                memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer );
424
                                ulSectionBytesReadSoFar += ulBytesRemainingInBuffer;
425
                ulFameBytesReadSoFar += ulBytesRemainingInBuffer;
426
 
427
                                /* Mark the buffer as free again. */
428
                                xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
429
 
430
                                /* Move onto the next buffer. */
431
                                ulNextRxBuffer++;
432
                                if( ulNextRxBuffer >= NB_RX_BUFFERS )
433
                                {
434
                                        ulNextRxBuffer = ( unsigned long ) 0;
435
                                }
436
 
437
                                /* Reset the variables for the new buffer. */
438
                                pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
439
                                ulBufferPosition = ( unsigned long ) 0;
440
                        }
441
                        else
442
                        {
443
                                /* We have enough data in this buffer to send back.  Read out
444
                                enough data and remember how far we read up to. */
445
                                memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes );
446
 
447
                                /* There may be more data in this buffer yet.  Increment our
448
                                position in this buffer past the data we have just read. */
449
                                ulBufferPosition += ulRemainingSectionBytes;
450
                                ulSectionBytesReadSoFar += ulRemainingSectionBytes;
451
                ulFameBytesReadSoFar += ulRemainingSectionBytes;
452
 
453
                                /* Have we now finished with this buffer? */
454
                                if( ( ulBufferPosition >= ETH_RX_BUFFER_SIZE ) || ( ulFameBytesReadSoFar >= ulTotalFrameLength ) )
455
                                {
456
                                        /* Mark the buffer as free again. */
457
                                        xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
458
 
459
                                        /* Move onto the next buffer. */
460
                                        ulNextRxBuffer++;
461
                                        if( ulNextRxBuffer >= NB_RX_BUFFERS )
462
                                        {
463
                                                ulNextRxBuffer = 0;
464
                                        }
465
 
466
                                        pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
467
                                        ulBufferPosition = 0;
468
                                }
469
                        }
470
                }
471
        }
472
}
473
/*-----------------------------------------------------------*/
474
 
475
/* See the header file for descriptions of public functions. */
476
xSemaphoreHandle xEMACInit( void )
477
{
478
        /* Code supplied by Atmel -------------------------------*/
479
 
480
        /* Disable pull up on RXDV => PHY normal mode (not in test mode),
481
        PHY has internal pull down. */
482
        AT91C_BASE_PIOB->PIO_PPUDR = 1 << 15;
483
 
484
        #if USE_RMII_INTERFACE != 1
485
                /* PHY has internal pull down : set MII mode. */
486
                AT91C_BASE_PIOB->PIO_PPUDR = 1 << 16;
487
        #endif
488
 
489
        /* Clear PB18 <=> PHY powerdown. */
490
        AT91C_BASE_PIOB->PIO_PER = 1 << 18;
491
        AT91C_BASE_PIOB->PIO_OER = 1 << 18;
492
        AT91C_BASE_PIOB->PIO_CODR = 1 << 18;
493
 
494
        /* After PHY power up, hardware reset. */
495
        AT91C_BASE_RSTC->RSTC_RMR = emacRESET_KEY | emacRESET_LENGTH;
496
        AT91C_BASE_RSTC->RSTC_RCR = emacRESET_KEY | AT91C_RSTC_EXTRST;
497
 
498
        /* Wait for hardware reset end. */
499
        while( !( AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL ) )
500
        {
501
                __asm volatile ( "NOP" );
502
        }
503
    __asm volatile ( "NOP" );
504
 
505
        /* Setup the pins. */
506
        AT91C_BASE_PIOB->PIO_ASR = emacPERIPHERAL_A_SETUP;
507
        AT91C_BASE_PIOB->PIO_PDR = emacPERIPHERAL_A_SETUP;
508
 
509
        /* Enable com between EMAC PHY.
510
 
511
        Enable management port. */
512
        AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
513
 
514
        /* MDC = MCK/32. */
515
        AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
516
 
517
        /* Wait for PHY auto init end (rather crude delay!). */
518
        vTaskDelay( emacPHY_INIT_DELAY );
519
 
520
        /* PHY configuration. */
521
        #if USE_RMII_INTERFACE != 1
522
        {
523
                unsigned long ulControl;
524
 
525
                /* PHY has internal pull down : disable MII isolate. */
526
                vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
527
                vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
528
                ulControl &= ~BMCR_ISOLATE;
529
                vWritePHY( AT91C_PHY_ADDR, MII_BMCR, ulControl );
530
        }
531
        #endif
532
 
533
        /* Disable management port again. */
534
        AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
535
 
536
        #if USE_RMII_INTERFACE != 1
537
                /* Enable EMAC in MII mode, enable clock ERXCK and ETXCK. */
538
                AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN ;
539
        #else
540
                /* Enable EMAC in RMII mode, enable RMII clock (50MHz from oscillator
541
                on ERFCK). */
542
                AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_RMII | AT91C_EMAC_CLKEN ;
543
        #endif
544
 
545
        /* End of code supplied by Atmel ------------------------*/
546
 
547
        /* Setup the buffers and descriptors. */
548
        prvSetupDescriptors();
549
 
550
        /* Load our MAC address into the EMAC. */
551
        prvSetupMACAddress();
552
 
553
        /* Are we connected? */
554
        if( prvProbePHY() )
555
        {
556
                /* Enable the interrupt! */
557
                portENTER_CRITICAL();
558
                {
559
                        prvSetupEMACInterrupt();
560
                        vPassEMACSemaphore( xSemaphore );
561
                }
562
                portEXIT_CRITICAL();
563
        }
564
 
565
        return xSemaphore;
566
}
567
/*-----------------------------------------------------------*/
568
 
569
/* See the header file for descriptions of public functions. */
570
void vClearEMACTxBuffer( void )
571
{
572
static unsigned portBASE_TYPE uxNextBufferToClear = 0;
573
 
574
        /* Called on Tx interrupt events to reset the AT91C_TRANSMIT_OK bit in each
575
        Tx buffer within the frame just transmitted.  This marks all the buffers
576
        as available again.
577
 
578
        The first buffer in the frame should have the bit set automatically. */
579
        if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AT91C_TRANSMIT_OK )
580
        {
581
                /* Loop through the other buffers in the frame. */
582
                while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AT91C_LAST_BUFFER ) )
583
                {
584
                        uxNextBufferToClear++;
585
 
586
                        if( uxNextBufferToClear >= NB_TX_BUFFERS )
587
                        {
588
                                uxNextBufferToClear = 0;
589
                        }
590
 
591
                        xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AT91C_TRANSMIT_OK;
592
                }
593
 
594
                /* Start with the next buffer the next time a Tx interrupt is called. */
595
                uxNextBufferToClear++;
596
 
597
                /* Do we need to wrap back to the first buffer? */
598
                if( uxNextBufferToClear >= NB_TX_BUFFERS )
599
                {
600
                        uxNextBufferToClear = 0;
601
                }
602
        }
603
}
604
/*-----------------------------------------------------------*/
605
 
606
static void prvSetupDescriptors(void)
607
{
608
unsigned portBASE_TYPE xIndex;
609
unsigned long ulAddress;
610
 
611
        /* Initialise xRxDescriptors descriptor. */
612
        for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex )
613
        {
614
                /* Calculate the address of the nth buffer within the array. */
615
                ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) );
616
 
617
                /* Write the buffer address into the descriptor.  The DMA will place
618
                the data at this address when this descriptor is being used.  Mask off
619
                the bottom bits of the address as these have special meaning. */
620
                xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
621
        }
622
 
623
        /* The last buffer has the wrap bit set so the EMAC knows to wrap back
624
        to the first buffer. */
625
        xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT;
626
 
627
        /* Initialise xTxDescriptors. */
628
        for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex )
629
        {
630
                /* Calculate the address of the nth buffer within the array. */
631
                ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) );
632
 
633
                /* Write the buffer address into the descriptor.  The DMA will read
634
                data from here when the descriptor is being used. */
635
                xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
636
                xTxDescriptors[ xIndex ].U_Status.status = AT91C_TRANSMIT_OK;
637
        }
638
 
639
        /* The last buffer has the wrap bit set so the EMAC knows to wrap back
640
        to the first buffer. */
641
        xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AT91C_TRANSMIT_WRAP | AT91C_TRANSMIT_OK;
642
 
643
        /* Tell the EMAC where to find the descriptors. */
644
        AT91C_BASE_EMAC->EMAC_RBQP = ( unsigned long ) xRxDescriptors;
645
        AT91C_BASE_EMAC->EMAC_TBQP = ( unsigned long ) xTxDescriptors;
646
 
647
        /* Clear all the bits in the receive status register. */
648
        AT91C_BASE_EMAC->EMAC_RSR = ( AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA );
649
 
650
        /* Enable the copy of data into the buffers, ignore broadcasts,
651
        and don't copy FCS. */
652
        AT91C_BASE_EMAC->EMAC_NCFGR |= ( AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS);
653
 
654
        /* Enable Rx and Tx, plus the stats register. */
655
        AT91C_BASE_EMAC->EMAC_NCR |= ( AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT );
656
}
657
/*-----------------------------------------------------------*/
658
 
659
static void prvSetupMACAddress( void )
660
{
661
        /* Must be written SA1L then SA1H. */
662
        AT91C_BASE_EMAC->EMAC_SA1L =    ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) |
663
                                                                        ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) |
664
                                                                        ( ( unsigned long ) cMACAddress[ 1 ] << 8  ) |
665
                                                                        cMACAddress[ 0 ];
666
 
667
        AT91C_BASE_EMAC->EMAC_SA1H =    ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) |
668
                                                                        cMACAddress[ 4 ];
669
}
670
/*-----------------------------------------------------------*/
671
 
672
static void prvSetupEMACInterrupt( void )
673
{
674
        /* Create the semaphore used to trigger the EMAC task. */
675
        vSemaphoreCreateBinary( xSemaphore );
676
        if( xSemaphore )
677
        {
678
                /* We start by 'taking' the semaphore so the ISR can 'give' it when the
679
                first interrupt occurs. */
680
                xSemaphoreTake( xSemaphore, emacNO_DELAY );
681
                portENTER_CRITICAL();
682
                {
683
                        /* We want to interrupt on Rx and Tx events. */
684
                        AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;
685
 
686
                        /* Enable the interrupts in the AIC. */
687
                        AT91F_AIC_ConfigureIt( AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISR_Wrapper );
688
            AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC;
689
                }
690
                portEXIT_CRITICAL();
691
        }
692
}
693
 
694
 
695
 
696
 
697
 
698
/*
699
 * The following functions are initialisation functions taken from the Atmel
700
 * EMAC sample code.
701
 */
702
 
703
 
704
static portBASE_TYPE prvProbePHY( void )
705
{
706
unsigned long ulPHYId1, ulPHYId2, ulStatus;
707
portBASE_TYPE xReturn = pdPASS;
708
 
709
        /* Code supplied by Atmel (reformatted) -----------------*/
710
 
711
        /* Enable management port */
712
        AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
713
        AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
714
 
715
        /* Read the PHY ID. */
716
        vReadPHY( AT91C_PHY_ADDR, MII_PHYSID1, &ulPHYId1 );
717
        vReadPHY(AT91C_PHY_ADDR, MII_PHYSID2, &ulPHYId2 );
718
 
719
        /* AMD AM79C875:
720
                        PHY_ID1 = 0x0022
721
                        PHY_ID2 = 0x5541
722
                        Bits 3:0 Revision Number Four bit manufacturer?s revision number.
723
                                0001 stands for Rev. A, etc.
724
        */
725
        if( ( ( ulPHYId1 << 16 ) | ( ulPHYId2 & 0xfff0 ) ) != MII_DM9161_ID )
726
        {
727
                /* Did not expect this ID. */
728
                xReturn = pdFAIL;
729
        }
730
        else
731
        {
732
                ulStatus = xGetLinkSpeed();
733
 
734
                if( ulStatus != pdPASS )
735
                {
736
                        xReturn = pdFAIL;
737
                }
738
        }
739
 
740
        /* Disable management port */
741
        AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
742
 
743
        /* End of code supplied by Atmel ------------------------*/
744
 
745
        return xReturn;
746
}
747
/*-----------------------------------------------------------*/
748
 
749
static void vReadPHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long *pulValue )
750
{
751
        /* Code supplied by Atmel (reformatted) ----------------------*/
752
 
753
        AT91C_BASE_EMAC->EMAC_MAN =     (AT91C_EMAC_SOF & (0x01<<30))
754
                                                                        | (2 << 16) | (2 << 28)
755
                                                                        | ((ucPHYAddress & 0x1f) << 23)
756
                                                                        | (ucAddress << 18);
757
 
758
        /* Wait until IDLE bit in Network Status register is cleared. */
759
        while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
760
        {
761
                __asm( "NOP" );
762
        }
763
 
764
        *pulValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );
765
 
766
        /* End of code supplied by Atmel ------------------------*/
767
}
768
/*-----------------------------------------------------------*/
769
 
770
#if USE_RMII_INTERFACE != 1
771
static void vWritePHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long ulValue )
772
{
773
        /* Code supplied by Atmel (reformatted) ----------------------*/
774
 
775
        AT91C_BASE_EMAC->EMAC_MAN = (( AT91C_EMAC_SOF & (0x01<<30))
776
                                                                | (2 << 16) | (1 << 28)
777
                                                                | ((ucPHYAddress & 0x1f) << 23)
778
                                                                | (ucAddress << 18))
779
                                                                | (ulValue & 0xffff);
780
 
781
        /* Wait until IDLE bit in Network Status register is cleared */
782
        while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
783
        {
784
                __asm( "NOP" );
785
        };
786
 
787
        /* End of code supplied by Atmel ------------------------*/
788
}
789
#endif
790
/*-----------------------------------------------------------*/
791
 
792
static portBASE_TYPE xGetLinkSpeed( void )
793
{
794
        unsigned long ulBMSR, ulBMCR, ulLPA, ulMACCfg, ulSpeed, ulDuplex;
795
 
796
        /* Code supplied by Atmel (reformatted) -----------------*/
797
 
798
        /* Link status is latched, so read twice to get current value */
799
        vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
800
        vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
801
 
802
        if( !( ulBMSR & BMSR_LSTATUS ) )
803
        {
804
                /* No Link. */
805
                return pdFAIL;
806
        }
807
 
808
        vReadPHY(AT91C_PHY_ADDR, MII_BMCR, &ulBMCR);
809
        if (ulBMCR & BMCR_ANENABLE)
810
        {
811
                /* AutoNegotiation is enabled. */
812
                if (!(ulBMSR & BMSR_ANEGCOMPLETE))
813
                {
814
                        /* Auto-negotitation in progress. */
815
                        return pdFAIL;
816
                }
817
 
818
                vReadPHY(AT91C_PHY_ADDR, MII_LPA, &ulLPA);
819
                if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_100HALF ) )
820
                {
821
                        ulSpeed = SPEED_100;
822
                }
823
                else
824
                {
825
                        ulSpeed = SPEED_10;
826
                }
827
 
828
                if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_10FULL ) )
829
                {
830
                        ulDuplex = DUPLEX_FULL;
831
                }
832
                else
833
                {
834
                        ulDuplex = DUPLEX_HALF;
835
                }
836
        }
837
        else
838
        {
839
                ulSpeed = ( ulBMCR & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10;
840
                ulDuplex = ( ulBMCR & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF;
841
        }
842
 
843
        /* Update the MAC */
844
        ulMACCfg = AT91C_BASE_EMAC->EMAC_NCFGR & ~( AT91C_EMAC_SPD | AT91C_EMAC_FD );
845
        if( ulSpeed == SPEED_100 )
846
        {
847
                if( ulDuplex == DUPLEX_FULL )
848
                {
849
                        /* 100 Full Duplex */
850
                        AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;
851
                }
852
                else
853
                {
854
                        /* 100 Half Duplex */
855
                        AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD;
856
                }
857
        }
858
        else
859
        {
860
                if (ulDuplex == DUPLEX_FULL)
861
                {
862
                        /* 10 Full Duplex */
863
                        AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_FD;
864
                }
865
                else
866
                {                       /* 10 Half Duplex */
867
                        AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg;
868
                }
869
        }
870
 
871
        /* End of code supplied by Atmel ------------------------*/
872
 
873
        return pdPASS;
874
}
875
/*-----------------------------------------------------------*/
876
 
877
void vEMACWaitForInput( void )
878
{
879
        /* Just wait until we are signled from an ISR that data is available, or
880
        we simply time out. */
881
        xSemaphoreTake( xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );
882
}

powered by: WebSVN 2.1.0

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