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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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