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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [RX600_RX62N-RSK_Renesas/] [RTOSDemo/] [webserver/] [EMAC.c] - Blame information for rev 604

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

Line No. Rev Author Line
1 585 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
/* Hardware specific includes. */
55
#include "iodefine.h"
56
#include "typedefine.h"
57
#include "r_ether.h"
58
#include "phy.h"
59
 
60
/* FreeRTOS includes. */
61
#include "FreeRTOS.h"
62
#include "task.h"
63
#include "semphr.h"
64
 
65
/* uIP includes. */
66
#include "net/uip.h"
67
 
68
/* The time to wait between attempts to obtain a free buffer. */
69
#define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_RATE_MS )
70
 
71
/* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
72
up on attempting to obtain a free buffer all together. */
73
#define emacBUFFER_WAIT_ATTEMPTS        ( 30 )
74
 
75
/* The number of Rx descriptors. */
76
#define emacNUM_RX_DESCRIPTORS  8
77
 
78
/* The number of Tx descriptors.  When using uIP there is not point in having
79
more than two. */
80
#define emacNUM_TX_BUFFERS      2
81
 
82
/* The total number of EMAC buffers to allocate. */
83
#define emacNUM_BUFFERS         ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
84
 
85
/* The time to wait for the Tx descriptor to become free. */
86
#define emacTX_WAIT_DELAY_ms ( 10 / portTICK_RATE_MS )
87
 
88
/* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
89
become free. */
90
#define emacTX_WAIT_ATTEMPTS ( 50 )
91
 
92
/* Only Rx end and Tx end interrupts are used by this driver. */
93
#define emacTX_END_INTERRUPT    ( 1UL << 21UL )
94
#define emacRX_END_INTERRUPT    ( 1UL << 18UL )
95
 
96
/*-----------------------------------------------------------*/
97
 
98
/* The buffers and descriptors themselves.  */
99
#pragma section _RX_DESC
100
        volatile ethfifo xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
101
#pragma section _TX_DESC
102
        volatile ethfifo xTxDescriptors[ emacNUM_TX_BUFFERS ];
103
#pragma section _ETHERNET_BUFFERS
104
        struct
105
        {
106
                unsigned long ulAlignmentVariable;
107
                char cBuffer[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
108
        } xEthernetBuffers;
109
#pragma section
110
 
111
 
112
 
113
 
114
/* Used to indicate which buffers are free and which are in use.  If an index
115
contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise
116
the buffer is in use or about to be used. */
117
static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
118
 
119
/*-----------------------------------------------------------*/
120
 
121
/*
122
 * Initialise both the Rx and Tx descriptors.
123
 */
124
static void prvInitialiseDescriptors( void );
125
 
126
/*
127
 * Return a pointer to a free buffer within xEthernetBuffers.
128
 */
129
static unsigned char *prvGetNextBuffer( void );
130
 
131
/*
132
 * Return a buffer to the list of free buffers.
133
 */
134
static void prvReturnBuffer( unsigned char *pucBuffer );
135
 
136
/*
137
 * Examine the status of the next Rx FIFO to see if it contains new data.
138
 */
139
static unsigned long prvCheckRxFifoStatus( void );
140
 
141
/*
142
 * Setup the microcontroller for communication with the PHY.
143
 */
144
static void prvResetMAC( void );
145
 
146
/*
147
 * Configure the Ethernet interface peripherals.
148
 */
149
static void prvConfigureEtherCAndEDMAC( void );
150
 
151
/*
152
 * Something has gone wrong with the descriptor usage.  Reset all the buffers
153
 * and descriptors.
154
 */
155
static void prvResetEverything( void );
156
 
157
/*-----------------------------------------------------------*/
158
 
159
/* Points to the Rx descriptor currently in use. */
160
static ethfifo *pxCurrentRxDesc = NULL;
161
 
162
/* The buffer used by the uIP stack to both receive and send.  This points to
163
one of the Ethernet buffers when its actually in use. */
164
unsigned char *uip_buf = NULL;
165
 
166
/*-----------------------------------------------------------*/
167
 
168
void vInitEmac( void )
169
{
170
        /* Software reset. */
171
        prvResetMAC();
172
 
173
        /* Set the Rx and Tx descriptors into their initial state. */
174
        prvInitialiseDescriptors();
175
 
176
        /* Set the MAC address into the ETHERC */
177
        ETHERC.MAHR =   ( ( unsigned long ) configMAC_ADDR0 << 24UL ) |
178
                                        ( ( unsigned long ) configMAC_ADDR1 << 16UL ) |
179
                                        ( ( unsigned long ) configMAC_ADDR2 << 8UL ) |
180
                                        ( unsigned long ) configMAC_ADDR3;
181
 
182
        ETHERC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |
183
                                                 ( unsigned long ) configMAC_ADDR5;
184
 
185
        /* Perform rest of interface hardware configuration. */
186
        prvConfigureEtherCAndEDMAC();
187
 
188
        /* Nothing received yet, so uip_buf points nowhere. */
189
        uip_buf = NULL;
190
 
191
        /* Initialize the PHY */
192
        phy_init();
193
}
194
/*-----------------------------------------------------------*/
195
 
196
void vEMACWrite( void )
197
{
198
long x;
199
 
200
        /* Wait until the second transmission of the last packet has completed. */
201
        for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
202
        {
203
                if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
204
                {
205
                        /* Descriptor is still active. */
206
                        vTaskDelay( emacTX_WAIT_DELAY_ms );
207
                }
208
                else
209
                {
210
                        break;
211
                }
212
        }
213
 
214
        /* Is the descriptor free after waiting for it? */
215
        if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
216
        {
217
                /* Something has gone wrong. */
218
                prvResetEverything();
219
        }
220
 
221
        /* Setup both descriptors to transmit the frame. */
222
        xTxDescriptors[ 0 ].buf_p = ( char * ) uip_buf;
223
        xTxDescriptors[ 0 ].bufsize = uip_len;
224
        xTxDescriptors[ 1 ].buf_p = ( char * ) uip_buf;
225
        xTxDescriptors[ 1 ].bufsize = uip_len;
226
 
227
        /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer
228
        for use by the stack. */
229
        uip_buf = prvGetNextBuffer();
230
 
231
        /* Clear previous settings and go. */
232
        xTxDescriptors[0].status &= ~( FP1 | FP0 );
233
        xTxDescriptors[0].status |= ( FP1 | FP0 | ACT );
234
        xTxDescriptors[1].status &= ~( FP1 | FP0 );
235
        xTxDescriptors[1].status |= ( FP1 | FP0 | ACT );
236
 
237
        EDMAC.EDTRR.LONG = 0x00000001;
238
}
239
/*-----------------------------------------------------------*/
240
 
241
unsigned long ulEMACRead( void )
242
{
243
unsigned long ulBytesReceived;
244
 
245
        ulBytesReceived = prvCheckRxFifoStatus();
246
 
247
        if( ulBytesReceived > 0 )
248
        {
249
                pxCurrentRxDesc->status &= ~( FP1 | FP0 );
250
                pxCurrentRxDesc->status |= ACT;
251
 
252
                if( EDMAC.EDRRR.LONG == 0x00000000L )
253
                {
254
                        /* Restart Ethernet if it has stopped */
255
                        EDMAC.EDRRR.LONG = 0x00000001L;
256
                }
257
 
258
                /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
259
                the buffer that contains the received data. */
260
                prvReturnBuffer( uip_buf );
261
 
262
                uip_buf = ( void * ) pxCurrentRxDesc->buf_p;
263
 
264
                /* Move onto the next buffer in the ring. */
265
                pxCurrentRxDesc = pxCurrentRxDesc->next;
266
        }
267
 
268
        return ulBytesReceived;
269
}
270
/*-----------------------------------------------------------*/
271
 
272
long lEMACWaitForLink( void )
273
{
274
long lReturn;
275
 
276
        /* Set the link status. */
277
        switch( phy_set_autonegotiate() )
278
        {
279
                /* Half duplex link */
280
                case PHY_LINK_100H:
281
                                                                ETHERC.ECMR.BIT.DM = 0;
282
                                                                ETHERC.ECMR.BIT.RTM = 1;
283
                                                                lReturn = pdPASS;
284
                                                                break;
285
 
286
                case PHY_LINK_10H:
287
                                                                ETHERC.ECMR.BIT.DM = 0;
288
                                                                ETHERC.ECMR.BIT.RTM = 0;
289
                                                                lReturn = pdPASS;
290
                                                                break;
291
 
292
 
293
                /* Full duplex link */
294
                case PHY_LINK_100F:
295
                                                                ETHERC.ECMR.BIT.DM = 1;
296
                                                                ETHERC.ECMR.BIT.RTM = 1;
297
                                                                lReturn = pdPASS;
298
                                                                break;
299
 
300
                case PHY_LINK_10F:
301
                                                                ETHERC.ECMR.BIT.DM = 1;
302
                                                                ETHERC.ECMR.BIT.RTM = 0;
303
                                                                lReturn = pdPASS;
304
                                                                break;
305
 
306
                default:
307
                                                                lReturn = pdFAIL;
308
                                                                break;
309
        }
310
 
311
        if( lReturn == pdPASS )
312
        {
313
                /* Enable receive and transmit. */
314
                ETHERC.ECMR.BIT.RE = 1;
315
                ETHERC.ECMR.BIT.TE = 1;
316
 
317
                /* Enable EDMAC receive */
318
                EDMAC.EDRRR.LONG = 0x1;
319
        }
320
 
321
        return lReturn;
322
}
323
/*-----------------------------------------------------------*/
324
 
325
static void prvInitialiseDescriptors( void )
326
{
327
ethfifo *pxDescriptor;
328
long x;
329
 
330
        for( x = 0; x < emacNUM_BUFFERS; x++ )
331
        {
332
                /* Ensure none of the buffers are shown as in use at the start. */
333
                ucBufferInUse[ x ] = pdFALSE;
334
        }
335
 
336
        /* Initialise the Rx descriptors. */
337
        for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
338
        {
339
                pxDescriptor = &( xRxDescriptors[ x ] );
340
                pxDescriptor->buf_p = &( xEthernetBuffers.cBuffer[ x ][ 0 ] );
341
 
342
                pxDescriptor->bufsize = UIP_BUFSIZE;
343
                pxDescriptor->size = 0;
344
                pxDescriptor->status = ACT;
345
                pxDescriptor->next = &xRxDescriptors[ x + 1 ];
346
 
347
                /* Mark this buffer as in use. */
348
                ucBufferInUse[ x ] = pdTRUE;
349
        }
350
 
351
        /* The last descriptor points back to the start. */
352
        pxDescriptor->status |= DL;
353
        pxDescriptor->next = &xRxDescriptors[ 0 ];
354
 
355
        /* Initialise the Tx descriptors. */
356
        for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
357
        {
358
                pxDescriptor = &( xTxDescriptors[ x ] );
359
 
360
                /* A buffer is not allocated to the Tx descriptor until a send is
361
                actually required. */
362
                pxDescriptor->buf_p = NULL;
363
 
364
                pxDescriptor->bufsize = UIP_BUFSIZE;
365
                pxDescriptor->size = 0;
366
                pxDescriptor->status = 0;
367
                pxDescriptor->next = &xTxDescriptors[ x + 1 ];
368
        }
369
 
370
        /* The last descriptor points back to the start. */
371
        pxDescriptor->status |= DL;
372
        pxDescriptor->next = &( xTxDescriptors[ 0 ] );
373
 
374
        /* Use the first Rx descriptor to start with. */
375
        pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
376
}
377
/*-----------------------------------------------------------*/
378
 
379
static unsigned char *prvGetNextBuffer( void )
380
{
381
long x;
382
unsigned char *pucReturn = NULL;
383
unsigned long ulAttempts = 0;
384
 
385
        while( pucReturn == NULL )
386
        {
387
                /* Look through the buffers to find one that is not in use by
388
                anything else. */
389
                for( x = 0; x < emacNUM_BUFFERS; x++ )
390
                {
391
                        if( ucBufferInUse[ x ] == pdFALSE )
392
                        {
393
                                ucBufferInUse[ x ] = pdTRUE;
394
                                pucReturn = ( unsigned char * ) &( xEthernetBuffers.cBuffer[ x ][ 0 ] );
395
                                break;
396
                        }
397
                }
398
 
399
                /* Was a buffer found? */
400
                if( pucReturn == NULL )
401
                {
402
                        ulAttempts++;
403
 
404
                        if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
405
                        {
406
                                break;
407
                        }
408
 
409
                        /* Wait then look again. */
410
                        vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
411
                }
412
        }
413
 
414
        return pucReturn;
415
}
416
/*-----------------------------------------------------------*/
417
 
418
static void prvReturnBuffer( unsigned char *pucBuffer )
419
{
420
unsigned long ul;
421
 
422
        /* Return a buffer to the pool of free buffers. */
423
        for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
424
        {
425
                if( &( xEthernetBuffers.cBuffer[ ul ][ 0 ] ) == ( void * ) pucBuffer )
426
                {
427
                        ucBufferInUse[ ul ] = pdFALSE;
428
                        break;
429
                }
430
        }
431
}
432
/*-----------------------------------------------------------*/
433
 
434
static void prvResetEverything( void )
435
{
436
        /* Temporary code just to see if this gets called.  This function has not
437
        been implemented. */
438
        portDISABLE_INTERRUPTS();
439
        for( ;; );
440
}
441
/*-----------------------------------------------------------*/
442
 
443
static unsigned long prvCheckRxFifoStatus( void )
444
{
445
unsigned long ulReturn = 0;
446
 
447
        if( ( pxCurrentRxDesc->status & ACT ) != 0 )
448
        {
449
                /* Current descriptor is still active. */
450
        }
451
        else if( ( pxCurrentRxDesc->status & FE ) != 0 )
452
        {
453
                /* Frame error.  Clear the error. */
454
                pxCurrentRxDesc->status &= ~( FP1 | FP0 | FE );
455
                pxCurrentRxDesc->status &= ~( RMAF | RRF | RTLF | RTSF | PRE | CERF );
456
                pxCurrentRxDesc->status |= ACT;
457
                pxCurrentRxDesc = pxCurrentRxDesc->next;
458
 
459
                if( EDMAC.EDRRR.LONG == 0x00000000UL )
460
                {
461
                        /* Restart Ethernet if it has stopped. */
462
                        EDMAC.EDRRR.LONG = 0x00000001UL;
463
                }
464
        }
465
        else
466
        {
467
                /* The descriptor contains a frame.  Because of the size of the buffers
468
                the frame should always be complete. */
469
                if( ( pxCurrentRxDesc->status & FP0 ) == FP0 )
470
                {
471
                        ulReturn = pxCurrentRxDesc->size;
472
                }
473
                else
474
                {
475
                        /* Do not expect to get here. */
476
                        prvResetEverything();
477
                }
478
        }
479
 
480
        return ulReturn;
481
}
482
/*-----------------------------------------------------------*/
483
 
484
static void prvResetMAC( void )
485
{
486
        /* Ensure the EtherC and EDMAC are enabled. */
487
        SYSTEM.MSTPCRB.BIT.MSTPB15 = 0;
488
        vTaskDelay( 100 / portTICK_RATE_MS );
489
 
490
        EDMAC.EDMR.BIT.SWR = 1;
491
 
492
        /* Crude wait for reset to complete. */
493
        vTaskDelay( 500 / portTICK_RATE_MS );
494
}
495
/*-----------------------------------------------------------*/
496
 
497
static void prvConfigureEtherCAndEDMAC( void )
498
{
499
        /* Initialisation code taken from Renesas example project. */
500
 
501
        /* TODO:    Check   bit 5   */
502
        ETHERC.ECSR.LONG = 0x00000037;                          /* Clear all ETHERC statuS BFR, PSRTO, LCHNG, MPD, ICD */
503
 
504
        /* Set the EDMAC interrupt priority. */
505
        _IPR( _ETHER_EINT ) = configKERNEL_INTERRUPT_PRIORITY;
506
 
507
        /* TODO:    Check   bit 5   */
508
        /* Enable interrupts of interest only. */
509
        EDMAC.EESIPR.LONG = emacTX_END_INTERRUPT | emacRX_END_INTERRUPT;
510
        ETHERC.RFLR.LONG = 1518;                                        /* Ether payload is 1500+ CRC */
511
        ETHERC.IPGR.LONG = 0x00000014;                          /* Intergap is 96-bit time */
512
 
513
        /* EDMAC */
514
        EDMAC.EESR.LONG = 0x47FF0F9F;                           /* Clear all ETHERC and EDMAC status bits */
515
        #ifdef __LIT
516
                EDMAC.EDMR.BIT.DE = 1;
517
        #endif
518
        EDMAC.RDLAR = ( void * ) pxCurrentRxDesc;       /* Initialaize Rx Descriptor List Address */
519
        EDMAC.TDLAR = &( xTxDescriptors[ 0 ] );          /* Initialaize Tx Descriptor List Address */
520
        EDMAC.TRSCER.LONG = 0x00000000;                         /* Copy-back status is RFE & TFE only   */
521
        EDMAC.TFTR.LONG = 0x00000000;                           /* Threshold of Tx_FIFO */
522
        EDMAC.FDR.LONG = 0x00000000;                            /* Transmit fifo & receive fifo is 256 bytes */
523
        EDMAC.RMCR.LONG = 0x00000003;                           /* Receive function is normal mode(continued) */
524
 
525
        /* Enable the interrupt... */
526
        _IEN( _ETHER_EINT ) = 1;
527
}
528
/*-----------------------------------------------------------*/
529
 
530
#pragma interrupt ( vEMAC_ISR_Handler( vect = VECT_ETHER_EINT, enable ) )
531
void vEMAC_ISR_Handler( void )
532
{
533
unsigned long ul = EDMAC.EESR.LONG;
534
long lHigherPriorityTaskWoken = pdFALSE;
535
extern xSemaphoreHandle xEMACSemaphore;
536
static long ulTxEndInts = 0;
537
 
538
        /* Has a Tx end occurred? */
539
        if( ul & emacTX_END_INTERRUPT )
540
        {
541
                ++ulTxEndInts;
542
                if( ulTxEndInts >= 2 )
543
                {
544
                        /* Only return the buffer to the pool once both Txes have completed. */
545
                        prvReturnBuffer( ( void * ) xTxDescriptors[ 0 ].buf_p );
546
                        ulTxEndInts = 0;
547
                }
548
                EDMAC.EESR.LONG = emacTX_END_INTERRUPT;
549
        }
550
 
551
        /* Has an Rx end occurred? */
552
        if( ul & emacRX_END_INTERRUPT )
553
        {
554
                /* Make sure the Ethernet task is not blocked waiting for a packet. */
555
                xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );
556
                portYIELD_FROM_ISR( lHigherPriorityTaskWoken );
557
                EDMAC.EESR.LONG = emacRX_END_INTERRUPT;
558
        }
559
}
560
 

powered by: WebSVN 2.1.0

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