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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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