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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [ARM7_AT91SAM7X256_Eclipse/] [RTOSDemo/] [webserver/] [SAM7_EMAC.c] - Blame information for rev 867

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

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

powered by: WebSVN 2.1.0

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