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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [CORTEX_LPC1768_GCC_Rowley/] [webserver/] [emac.c] - Blame information for rev 581

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 581 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
/* Originally adapted from file written by Andreas Dannenberg.  Supplied with permission. */
55
 
56
/* Kernel includes. */
57
#include "FreeRTOS.h"
58
#include "task.h"
59
#include "semphr.h"
60
 
61
/* Hardware specific includes. */
62
#include "EthDev_LPC17xx.h"
63
 
64
/* Time to wait between each inspection of the link status. */
65
#define emacWAIT_FOR_LINK_TO_ESTABLISH ( 500 / portTICK_RATE_MS )
66
 
67
/* Short delay used in several places during the initialisation process. */
68
#define emacSHORT_DELAY                            ( 2 )
69
 
70
/* Hardware specific bit definitions. */
71
#define emacLINK_ESTABLISHED            ( 0x0001 )
72
#define emacFULL_DUPLEX_ENABLED         ( 0x0004 )
73
#define emac10BASE_T_MODE                       ( 0x0002 )
74
#define emacPINSEL2_VALUE                       ( 0x50150105 )
75
 
76
/* If no buffers are available, then wait this long before looking again.... */
77
#define emacBUFFER_WAIT_DELAY   ( 3 / portTICK_RATE_MS )
78
 
79
/* ...and don't look more than this many times. */
80
#define emacBUFFER_WAIT_ATTEMPTS        ( 30 )
81
 
82
/* Index to the Tx descriptor that is always used first for every Tx.  The second
83
descriptor is then used to re-send in order to speed up the uIP Tx process. */
84
#define emacTX_DESC_INDEX                       ( 0 )
85
 
86
/*-----------------------------------------------------------*/
87
 
88
/*
89
 * Configure both the Rx and Tx descriptors during the init process.
90
 */
91
static void prvInitDescriptors( void );
92
 
93
/*
94
 * Setup the IO and peripherals required for Ethernet communication.
95
 */
96
static void prvSetupEMACHardware( void );
97
 
98
/*
99
 * Control the auto negotiate process.
100
 */
101
static void prvConfigurePHY( void );
102
 
103
/*
104
 * Wait for a link to be established, then setup the PHY according to the link
105
 * parameters.
106
 */
107
static long prvSetupLinkStatus( void );
108
 
109
/*
110
 * Search the pool of buffers to find one that is free.  If a buffer is found
111
 * mark it as in use before returning its address.
112
 */
113
static unsigned char *prvGetNextBuffer( void );
114
 
115
/*
116
 * Return an allocated buffer to the pool of free buffers.
117
 */
118
static void prvReturnBuffer( unsigned char *pucBuffer );
119
 
120
/*
121
 * Send lValue to the lPhyReg within the PHY.
122
 */
123
static long prvWritePHY( long lPhyReg, long lValue );
124
 
125
/*
126
 * Read a value from ucPhyReg within the PHY.  *plStatus will be set to
127
 * pdFALSE if there is an error.
128
 */
129
static unsigned short prvReadPHY( unsigned char ucPhyReg, long *plStatus );
130
 
131
/*-----------------------------------------------------------*/
132
 
133
/* The semaphore used to wake the uIP task when data arrives. */
134
extern xSemaphoreHandle xEMACSemaphore;
135
 
136
/* Each ucBufferInUse index corresponds to a position in the pool of buffers.
137
If the index contains a 1 then the buffer within pool is in use, if it
138
contains a 0 then the buffer is free. */
139
static unsigned char ucBufferInUse[ ETH_NUM_BUFFERS ] = { pdFALSE };
140
 
141
/* The uip_buffer is not a fixed array, but instead gets pointed to the buffers
142
allocated within this file. */
143
unsigned char * uip_buf;
144
 
145
/* Store the length of the data being sent so the data can be sent twice.  The
146
value will be set back to 0 once the data has been sent twice. */
147
static unsigned short usSendLen = 0;
148
 
149
/*-----------------------------------------------------------*/
150
 
151
long lEMACInit( void )
152
{
153
long lReturn = pdPASS;
154
unsigned long ulID1, ulID2;
155
 
156
        /* Reset peripherals, configure port pins and registers. */
157
        prvSetupEMACHardware();
158
 
159
        /* Check the PHY part number is as expected. */
160
        ulID1 = prvReadPHY( PHY_REG_IDR1, &lReturn );
161
        ulID2 = prvReadPHY( PHY_REG_IDR2, &lReturn );
162
        if( ( (ulID1 << 16UL ) | ( ulID2 & 0xFFF0UL ) ) == DP83848C_ID )
163
        {
164
                /* Set the Ethernet MAC Address registers */
165
                EMAC->SA0 = ( configMAC_ADDR0 << 8 ) | configMAC_ADDR1;
166
                EMAC->SA1 = ( configMAC_ADDR2 << 8 ) | configMAC_ADDR3;
167
                EMAC->SA2 = ( configMAC_ADDR4 << 8 ) | configMAC_ADDR5;
168
 
169
                /* Initialize Tx and Rx DMA Descriptors */
170
                prvInitDescriptors();
171
 
172
                /* Receive broadcast and perfect match packets */
173
                EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
174
 
175
                /* Setup the PHY. */
176
                prvConfigurePHY();
177
        }
178
        else
179
        {
180
                lReturn = pdFAIL;
181
        }
182
 
183
        /* Check the link status. */
184
        if( lReturn == pdPASS )
185
        {
186
                lReturn = prvSetupLinkStatus();
187
        }
188
 
189
        if( lReturn == pdPASS )
190
        {
191
                /* Initialise uip_buf to ensure it points somewhere valid. */
192
                uip_buf = prvGetNextBuffer();
193
 
194
                /* Reset all interrupts */
195
                EMAC->IntClear = ( INT_RX_OVERRUN | INT_RX_ERR | INT_RX_FIN | INT_RX_DONE | INT_TX_UNDERRUN | INT_TX_ERR | INT_TX_FIN | INT_TX_DONE | INT_SOFT_INT | INT_WAKEUP );
196
 
197
                /* Enable receive and transmit mode of MAC Ethernet core */
198
                EMAC->Command |= ( CR_RX_EN | CR_TX_EN );
199
                EMAC->MAC1 |= MAC1_REC_EN;
200
        }
201
 
202
        return lReturn;
203
}
204
/*-----------------------------------------------------------*/
205
 
206
static unsigned char *prvGetNextBuffer( void )
207
{
208
long x;
209
unsigned char *pucReturn = NULL;
210
unsigned long ulAttempts = 0;
211
 
212
        while( pucReturn == NULL )
213
        {
214
                /* Look through the buffers to find one that is not in use by
215
                anything else. */
216
                for( x = 0; x < ETH_NUM_BUFFERS; x++ )
217
                {
218
                        if( ucBufferInUse[ x ] == pdFALSE )
219
                        {
220
                                ucBufferInUse[ x ] = pdTRUE;
221
                                pucReturn = ( unsigned char * ) ETH_BUF( x );
222
                                break;
223
                        }
224
                }
225
 
226
                /* Was a buffer found? */
227
                if( pucReturn == NULL )
228
                {
229
                        ulAttempts++;
230
 
231
                        if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
232
                        {
233
                                break;
234
                        }
235
 
236
                        /* Wait then look again. */
237
                        vTaskDelay( emacBUFFER_WAIT_DELAY );
238
                }
239
        }
240
 
241
        return pucReturn;
242
}
243
/*-----------------------------------------------------------*/
244
 
245
static void prvInitDescriptors( void )
246
{
247
long x, lNextBuffer = 0;
248
 
249
        for( x = 0; x < NUM_RX_FRAG; x++ )
250
        {
251
                /* Allocate the next Ethernet buffer to this descriptor. */
252
                RX_DESC_PACKET( x ) = ETH_BUF( lNextBuffer );
253
                RX_DESC_CTRL( x ) = RCTRL_INT | ( ETH_FRAG_SIZE - 1 );
254
                RX_STAT_INFO( x ) = 0;
255
                RX_STAT_HASHCRC( x ) = 0;
256
 
257
                /* The Ethernet buffer is now in use. */
258
                ucBufferInUse[ lNextBuffer ] = pdTRUE;
259
                lNextBuffer++;
260
        }
261
 
262
        /* Set EMAC Receive Descriptor Registers. */
263
        EMAC->RxDescriptor = RX_DESC_BASE;
264
        EMAC->RxStatus = RX_STAT_BASE;
265
        EMAC->RxDescriptorNumber = NUM_RX_FRAG - 1;
266
 
267
        /* Rx Descriptors Point to 0 */
268
        EMAC->RxConsumeIndex = 0;
269
 
270
        /* A buffer is not allocated to the Tx descriptors until they are actually
271
        used. */
272
        for( x = 0; x < NUM_TX_FRAG; x++ )
273
        {
274
                TX_DESC_PACKET( x ) = ( unsigned long ) NULL;
275
                TX_DESC_CTRL( x ) = 0;
276
                TX_STAT_INFO( x ) = 0;
277
        }
278
 
279
        /* Set EMAC Transmit Descriptor Registers. */
280
        EMAC->TxDescriptor = TX_DESC_BASE;
281
        EMAC->TxStatus = TX_STAT_BASE;
282
        EMAC->TxDescriptorNumber = NUM_TX_FRAG - 1;
283
 
284
        /* Tx Descriptors Point to 0 */
285
        EMAC->TxProduceIndex = 0;
286
}
287
/*-----------------------------------------------------------*/
288
 
289
static void prvSetupEMACHardware( void )
290
{
291
unsigned short us;
292
long x, lDummy;
293
 
294
        /* Enable P1 Ethernet Pins. */
295
        PINCON->PINSEL2 = emacPINSEL2_VALUE;
296
        PINCON->PINSEL3 = ( PINCON->PINSEL3 & ~0x0000000F ) | 0x00000005;
297
 
298
        /* Power Up the EMAC controller. */
299
        SC->PCONP |= PCONP_PCENET;
300
        vTaskDelay( emacSHORT_DELAY );
301
 
302
        /* Reset all EMAC internal modules. */
303
        EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
304
        EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
305
 
306
        /* A short delay after reset. */
307
        vTaskDelay( emacSHORT_DELAY );
308
 
309
        /* Initialize MAC control registers. */
310
        EMAC->MAC1 = MAC1_PASS_ALL;
311
        EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
312
        EMAC->MAXF = ETH_MAX_FLEN;
313
        EMAC->CLRT = CLRT_DEF;
314
        EMAC->IPGR = IPGR_DEF;
315
 
316
        /* Enable Reduced MII interface. */
317
        EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;
318
 
319
        /* Reset Reduced MII Logic. */
320
        EMAC->SUPP = SUPP_RES_RMII;
321
        vTaskDelay( emacSHORT_DELAY );
322
        EMAC->SUPP = 0;
323
 
324
        /* Put the PHY in reset mode */
325
        prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );
326
        prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );
327
 
328
        /* Wait for hardware reset to end. */
329
        for( x = 0; x < 100; x++ )
330
        {
331
                vTaskDelay( emacSHORT_DELAY * 5 );
332
                us = prvReadPHY( PHY_REG_BMCR, &lDummy );
333
                if( !( us & MCFG_RES_MII ) )
334
                {
335
                        /* Reset complete */
336
                        break;
337
                }
338
        }
339
}
340
/*-----------------------------------------------------------*/
341
 
342
static void prvConfigurePHY( void )
343
{
344
unsigned short us;
345
long x, lDummy;
346
 
347
        /* Auto negotiate the configuration. */
348
        if( prvWritePHY( PHY_REG_BMCR, PHY_AUTO_NEG ) )
349
        {
350
                vTaskDelay( emacSHORT_DELAY * 5 );
351
 
352
                for( x = 0; x < 10; x++ )
353
                {
354
                        us = prvReadPHY( PHY_REG_BMSR, &lDummy );
355
 
356
                        if( us & PHY_AUTO_NEG_COMPLETE )
357
                        {
358
                                break;
359
                        }
360
 
361
                        vTaskDelay( emacWAIT_FOR_LINK_TO_ESTABLISH );
362
                }
363
        }
364
}
365
/*-----------------------------------------------------------*/
366
 
367
static long prvSetupLinkStatus( void )
368
{
369
long lReturn = pdFAIL, x;
370
unsigned short usLinkStatus;
371
 
372
        /* Wait with timeout for the link to be established. */
373
        for( x = 0; x < 10; x++ )
374
        {
375
                usLinkStatus = prvReadPHY( PHY_REG_STS, &lReturn );
376
                if( usLinkStatus & emacLINK_ESTABLISHED )
377
                {
378
                        /* Link is established. */
379
                        lReturn = pdPASS;
380
                        break;
381
                }
382
 
383
        vTaskDelay( emacWAIT_FOR_LINK_TO_ESTABLISH );
384
        }
385
 
386
        if( lReturn == pdPASS )
387
        {
388
                /* Configure Full/Half Duplex mode. */
389
                if( usLinkStatus & emacFULL_DUPLEX_ENABLED )
390
                {
391
                        /* Full duplex is enabled. */
392
                        EMAC->MAC2 |= MAC2_FULL_DUP;
393
                        EMAC->Command |= CR_FULL_DUP;
394
                        EMAC->IPGT = IPGT_FULL_DUP;
395
                }
396
                else
397
                {
398
                        /* Half duplex mode. */
399
                        EMAC->IPGT = IPGT_HALF_DUP;
400
                }
401
 
402
                /* Configure 100MBit/10MBit mode. */
403
                if( usLinkStatus & emac10BASE_T_MODE )
404
                {
405
                        /* 10MBit mode. */
406
                        EMAC->SUPP = 0;
407
                }
408
                else
409
                {
410
                        /* 100MBit mode. */
411
                        EMAC->SUPP = SUPP_SPEED;
412
                }
413
        }
414
 
415
        return lReturn;
416
}
417
/*-----------------------------------------------------------*/
418
 
419
static void prvReturnBuffer( unsigned char *pucBuffer )
420
{
421
unsigned long ul;
422
 
423
        /* Return a buffer to the pool of free buffers. */
424
        for( ul = 0; ul < ETH_NUM_BUFFERS; ul++ )
425
        {
426
                if( ETH_BUF( ul ) == ( unsigned long ) pucBuffer )
427
                {
428
                        ucBufferInUse[ ul ] = pdFALSE;
429
                        break;
430
                }
431
        }
432
}
433
/*-----------------------------------------------------------*/
434
 
435
unsigned long ulGetEMACRxData( void )
436
{
437
unsigned long ulLen = 0;
438
long lIndex;
439
 
440
        if( EMAC->RxProduceIndex != EMAC->RxConsumeIndex )
441
        {
442
                /* Mark the current buffer as free as uip_buf is going to be set to
443
                the buffer that contains the received data. */
444
                prvReturnBuffer( uip_buf );
445
 
446
                ulLen = ( RX_STAT_INFO( EMAC->RxConsumeIndex ) & RINFO_SIZE ) - 3;
447
                uip_buf = ( unsigned char * ) RX_DESC_PACKET( EMAC->RxConsumeIndex );
448
 
449
                /* Allocate a new buffer to the descriptor. */
450
        RX_DESC_PACKET( EMAC->RxConsumeIndex ) = ( unsigned long ) prvGetNextBuffer();
451
 
452
                /* Move the consume index onto the next position, ensuring it wraps to
453
                the beginning at the appropriate place. */
454
                lIndex = EMAC->RxConsumeIndex;
455
 
456
                lIndex++;
457
                if( lIndex >= NUM_RX_FRAG )
458
                {
459
                        lIndex = 0;
460
                }
461
 
462
                EMAC->RxConsumeIndex = lIndex;
463
        }
464
 
465
        return ulLen;
466
}
467
/*-----------------------------------------------------------*/
468
 
469
void vSendEMACTxData( unsigned short usTxDataLen )
470
{
471
unsigned long ulAttempts = 0UL;
472
 
473
        /* Check to see if the Tx descriptor is free, indicated by its buffer being
474
        NULL. */
475
        while( TX_DESC_PACKET( emacTX_DESC_INDEX ) != ( unsigned long ) NULL )
476
        {
477
                /* Wait for the Tx descriptor to become available. */
478
                vTaskDelay( emacBUFFER_WAIT_DELAY );
479
 
480
                ulAttempts++;
481
                if( ulAttempts > emacBUFFER_WAIT_ATTEMPTS )
482
                {
483
                        /* Something has gone wrong as the Tx descriptor is still in use.
484
                        Clear it down manually, the data it was sending will probably be
485
                        lost. */
486
                        prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );
487
                        break;
488
                }
489
        }
490
 
491
        /* Setup the Tx descriptor for transmission.  Remember the length of the
492
        data being sent so the second descriptor can be used to send it again from
493
        within the ISR. */
494
        usSendLen = usTxDataLen;
495
        TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) uip_buf;
496
        TX_DESC_CTRL( emacTX_DESC_INDEX ) = ( usTxDataLen | TCTRL_LAST | TCTRL_INT );
497
        EMAC->TxProduceIndex = ( emacTX_DESC_INDEX + 1 );
498
 
499
        /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer. */
500
        uip_buf = prvGetNextBuffer();
501
}
502
/*-----------------------------------------------------------*/
503
 
504
static long prvWritePHY( long lPhyReg, long lValue )
505
{
506
const long lMaxTime = 10;
507
long x;
508
 
509
        EMAC->MADR = DP83848C_DEF_ADR | lPhyReg;
510
        EMAC->MWTD = lValue;
511
 
512
        x = 0;
513
        for( x = 0; x < lMaxTime; x++ )
514
        {
515
                if( ( EMAC->MIND & MIND_BUSY ) == 0 )
516
                {
517
                        /* Operation has finished. */
518
                        break;
519
                }
520
 
521
                vTaskDelay( emacSHORT_DELAY );
522
        }
523
 
524
        if( x < lMaxTime )
525
        {
526
                return pdPASS;
527
        }
528
        else
529
        {
530
                return pdFAIL;
531
        }
532
}
533
/*-----------------------------------------------------------*/
534
 
535
static unsigned short prvReadPHY( unsigned char ucPhyReg, long *plStatus )
536
{
537
long x;
538
const long lMaxTime = 10;
539
 
540
        EMAC->MADR = DP83848C_DEF_ADR | ucPhyReg;
541
        EMAC->MCMD = MCMD_READ;
542
 
543
        for( x = 0; x < lMaxTime; x++ )
544
        {
545
                /* Operation has finished. */
546
                if( ( EMAC->MIND & MIND_BUSY ) == 0 )
547
                {
548
                        break;
549
                }
550
 
551
                vTaskDelay( emacSHORT_DELAY );
552
        }
553
 
554
        EMAC->MCMD = 0;
555
 
556
        if( x >= lMaxTime )
557
        {
558
                *plStatus = pdFAIL;
559
        }
560
 
561
        return( EMAC->MRDD );
562
}
563
/*-----------------------------------------------------------*/
564
 
565
void vEMAC_ISR( void )
566
{
567
unsigned long ulStatus;
568
long lHigherPriorityTaskWoken = pdFALSE;
569
 
570
        ulStatus = EMAC->IntStatus;
571
 
572
        /* Clear the interrupt. */
573
        EMAC->IntClear = ulStatus;
574
 
575
        if( ulStatus & INT_RX_DONE )
576
        {
577
                /* Ensure the uIP task is not blocked as data has arrived. */
578
                xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );
579
        }
580
 
581
        if( ulStatus & INT_TX_DONE )
582
        {
583
                if( usSendLen > 0 )
584
                {
585
                        /* Send the data again, using the second descriptor.  As there are
586
                        only two descriptors the index is set back to 0. */
587
                        TX_DESC_PACKET( ( emacTX_DESC_INDEX + 1 ) ) = TX_DESC_PACKET( emacTX_DESC_INDEX );
588
                        TX_DESC_CTRL( ( emacTX_DESC_INDEX + 1 ) ) = ( usSendLen | TCTRL_LAST | TCTRL_INT );
589
                        EMAC->TxProduceIndex = ( emacTX_DESC_INDEX );
590
 
591
                        /* This is the second Tx so set usSendLen to 0 to indicate that the
592
                        Tx descriptors will be free again. */
593
                        usSendLen = 0UL;
594
                }
595
                else
596
                {
597
                        /* The Tx buffer is no longer required. */
598
                        prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );
599
            TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) NULL;
600
                }
601
        }
602
 
603
        portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
604
}

powered by: WebSVN 2.1.0

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